001 /*
002 * Java Genetic Algorithm Library (jenetics-2.0.2).
003 * Copyright (c) 2007-2014 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019 */
020 package org.jenetics;
021
022 import static org.jenetics.CharacterGene.DEFAULT_CHARACTERS;
023 import static org.jenetics.internal.util.object.eq;
024
025 import java.io.IOException;
026 import java.io.ObjectInputStream;
027 import java.io.ObjectOutputStream;
028 import java.io.Serializable;
029
030 import javax.xml.bind.annotation.XmlAccessType;
031 import javax.xml.bind.annotation.XmlAccessorType;
032 import javax.xml.bind.annotation.XmlAttribute;
033 import javax.xml.bind.annotation.XmlElement;
034 import javax.xml.bind.annotation.XmlRootElement;
035 import javax.xml.bind.annotation.XmlType;
036 import javax.xml.bind.annotation.adapters.XmlAdapter;
037 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
038
039 import org.jenetics.internal.util.HashBuilder;
040
041 import org.jenetics.util.Array;
042 import org.jenetics.util.CharSeq;
043 import org.jenetics.util.Factory;
044 import org.jenetics.util.Function;
045 import org.jenetics.util.ISeq;
046
047 /**
048 * CharacterChromosome which represents character sequences.
049 *
050 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
051 * @since 1.0
052 * @version 2.0 — <em>$Date: 2014-03-30 $</em>
053 */
054 @XmlJavaTypeAdapter(CharacterChromosome.Model.Adapter.class)
055 public class CharacterChromosome
056 extends
057 AbstractChromosome<CharacterGene>
058 implements
059 CharSequence,
060 Serializable
061 {
062 private static final long serialVersionUID = 2L;
063
064 private transient CharSeq _validCharacters;
065
066 /**
067 * Create a new chromosome from the given {@code genes} array. The genes
068 * array is copied, so changes to the given genes array doesn't effect the
069 * genes of this chromosome.
070 *
071 * @param genes the genes that form the chromosome.
072 * @throws NullPointerException if the given gene array is {@code null}.
073 * @throws IllegalArgumentException if the length of the gene array is
074 * smaller than one.
075 */
076 protected CharacterChromosome(final ISeq<CharacterGene> genes) {
077 super(genes);
078 _validCharacters = genes.get(0).getValidCharacters();
079 }
080
081 /**
082 * Create a new chromosome with the {@code validCharacters} char set as
083 * valid characters.
084 *
085 * @param validCharacters the valid characters for this chromosome.
086 * @param length the length of the new chromosome.
087 * @throws NullPointerException if the {@code validCharacters} is
088 * {@code null}.
089 * @throws IllegalArgumentException if the {@code length} is smaller than
090 * one.
091 */
092 public CharacterChromosome(final CharSeq validCharacters, final int length) {
093 this(CharacterGene.seq(validCharacters, length));
094 _valid = true;
095 }
096
097 @Override
098 public char charAt(final int index) {
099 return getGene(index).getAllele();
100 }
101
102 @Override
103 public CharacterChromosome subSequence(final int start, final int end) {
104 return new CharacterChromosome(_genes.subSeq(start, end));
105 }
106
107 /**
108 * @throws NullPointerException if the given gene array is {@code null}.
109 */
110 @Override
111 public CharacterChromosome newInstance(final ISeq<CharacterGene> genes) {
112 return new CharacterChromosome(genes);
113 }
114
115 /**
116 * Create a new, <em>random</em> chromosome.
117 */
118 @Override
119 public CharacterChromosome newInstance() {
120 return new CharacterChromosome(_validCharacters, length());
121 }
122
123 @Override
124 public int hashCode() {
125 return HashBuilder.of(getClass()).
126 and(super.hashCode()).
127 and(_validCharacters).value();
128 }
129
130 @Override
131 public boolean equals(final Object obj) {
132 if (obj == this) {
133 return true;
134 }
135 if (obj == null || getClass() != obj.getClass()) {
136 return false;
137 }
138
139 final CharacterChromosome cc = (CharacterChromosome)obj;
140 return super.equals(obj) && eq(_validCharacters, cc._validCharacters);
141 }
142
143 @Override
144 public String toString() {
145 final StringBuilder out = new StringBuilder();
146 for (CharacterGene gene : this) {
147 out.append(gene);
148 }
149 return out.toString();
150 }
151
152
153 /**
154 * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
155 * char set as valid characters.
156 *
157 * @param length the {@code length} of the new chromosome.
158 * @return a new {@code CharacterChromosome} with the given parameter
159 * @throws IllegalArgumentException if the {@code length} is smaller than
160 * one.
161 */
162 public static CharacterChromosome of(final int length) {
163 return new CharacterChromosome(
164 CharacterGene.seq(DEFAULT_CHARACTERS, length)
165 );
166 }
167
168 /**
169 * Create a new chromosome from the given genes (given as string).
170 *
171 * @param alleles the character genes.
172 * @param validChars the valid characters.
173 * @return a new {@code CharacterChromosome} with the given parameter
174 * @throws IllegalArgumentException if the genes string is empty.
175 */
176 public static CharacterChromosome of(
177 final String alleles,
178 final CharSeq validChars
179 ) {
180 final Array<CharacterGene> genes = new Array<>(alleles.length());
181 genes.fill(GeneFactory(alleles, validChars));
182 return new CharacterChromosome(genes.toISeq());
183 }
184
185 private static Factory<CharacterGene>
186 GeneFactory(final String alleles, final CharSeq validChars) {
187 return new Factory<CharacterGene>() {
188 private int _index = 0;
189 @Override
190 public CharacterGene newInstance() {
191 return CharacterGene.of(
192 alleles.charAt(_index++), validChars
193 );
194 }
195 };
196 }
197
198 /**
199 * Create a new chromosome from the given genes (given as string).
200 *
201 * @param alleles the character genes.
202 * @return a new {@code CharacterChromosome} with the given parameter
203 * @throws IllegalArgumentException if the genes string is empty.
204 */
205 public static CharacterChromosome of(final String alleles) {
206 return of(alleles, DEFAULT_CHARACTERS);
207 }
208
209 /* *************************************************************************
210 * Property access methods
211 * ************************************************************************/
212
213 /**
214 * Return a {@link Function} which returns the gene array from this
215 * {@link Chromosome}.
216 */
217 public static final Function<Chromosome<CharacterGene>, ISeq<CharacterGene>>
218 Genes = AbstractChromosome.genes();
219
220 /**
221 * Return a {@link Function} which returns the first {@link Gene} from this
222 * {@link Chromosome}.
223 */
224 public static final Function<Chromosome<CharacterGene>, CharacterGene>
225 Gene = AbstractChromosome.gene();
226
227 /**
228 * Return a {@link Function} which returns the {@link Gene} with the given
229 * {@code index} from this {@link Chromosome}.
230 *
231 * @param index the gene index within the chromosome
232 * @return a function witch returns the gene at the given index
233 */
234 public static Function<Chromosome<CharacterGene>, CharacterGene>
235 Gene(final int index)
236 {
237 return AbstractChromosome.gene(index);
238 }
239
240
241 /* *************************************************************************
242 * Java object serialization
243 * ************************************************************************/
244
245 private void writeObject(final ObjectOutputStream out)
246 throws IOException
247 {
248 out.defaultWriteObject();
249
250 out.writeInt(length());
251 out.writeObject(_validCharacters);
252
253 for (CharacterGene gene : _genes) {
254 out.writeChar(gene.getAllele().charValue());
255 }
256 }
257
258 private void readObject(final ObjectInputStream in)
259 throws IOException, ClassNotFoundException
260 {
261 in.defaultReadObject();
262
263 final int length = in.readInt();
264 _validCharacters = (CharSeq)in.readObject();
265
266 final Array<CharacterGene> genes = new Array<>(length);
267 for (int i = 0; i < length; ++i) {
268 final CharacterGene gene = CharacterGene.of(
269 in.readChar(),
270 _validCharacters
271 );
272 genes.set(i, gene);
273 }
274
275 _genes = genes.toISeq();
276 }
277
278 /* *************************************************************************
279 * JAXB object serialization
280 * ************************************************************************/
281
282 @XmlRootElement(name = "character-chromosome")
283 @XmlType(name = "org.jenetics.CharacterChromosome")
284 @XmlAccessorType(XmlAccessType.FIELD)
285 final static class Model {
286
287 @XmlAttribute(name = "length", required = true)
288 public int length;
289
290 @XmlElement(name = "valid-alleles", required = true, nillable = false)
291 public String validCharacters;
292
293 @XmlElement(name = "alleles", required = true, nillable = false)
294 public String genes;
295
296 public final static class Adapter
297 extends XmlAdapter<Model, CharacterChromosome>
298 {
299 @Override
300 public Model marshal(final CharacterChromosome value) {
301 final Model m = new Model();
302 m.length = value.length();
303 m.validCharacters = value._validCharacters.toString();
304 m.genes = value.toString();
305 return m;
306 }
307
308 @Override
309 public CharacterChromosome unmarshal(final Model m) {
310 return CharacterChromosome.of(
311 m.genes,
312 new CharSeq(m.validCharacters)
313 );
314 }
315 }
316 }
317 }
|