001 /*
002 * Java Genetic Algorithm Library (jenetics-1.6.0).
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
029 import javax.xml.bind.annotation.XmlAccessType;
030 import javax.xml.bind.annotation.XmlAccessorType;
031 import javax.xml.bind.annotation.XmlAttribute;
032 import javax.xml.bind.annotation.XmlRootElement;
033 import javax.xml.bind.annotation.XmlType;
034 import javax.xml.bind.annotation.XmlValue;
035 import javax.xml.bind.annotation.adapters.XmlAdapter;
036
037 import javolution.text.CharArray;
038 import javolution.xml.XMLFormat;
039 import javolution.xml.XMLSerializable;
040 import javolution.xml.stream.XMLStreamException;
041
042 import org.jenetics.internal.util.HashBuilder;
043 import org.jenetics.internal.util.model.ModelType;
044 import org.jenetics.internal.util.model.ValueType;
045
046 import org.jenetics.util.Array;
047 import org.jenetics.util.CharSeq;
048 import org.jenetics.util.Factory;
049 import org.jenetics.util.Function;
050 import org.jenetics.util.ISeq;
051
052 /**
053 * CharacterChromosome which represents character sequences.
054 *
055 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
056 * @since 1.0
057 * @version 1.6 — <em>$Date: 2014-03-04 $</em>
058 */
059 public class CharacterChromosome
060 extends
061 AbstractChromosome<CharacterGene>
062 implements
063 CharSequence,
064 XMLSerializable
065 {
066 private static final long serialVersionUID = 1L;
067
068 private transient CharSeq _validCharacters;
069
070 /**
071 * Create a new chromosome from the given {@code genes} array. The genes
072 * array is copied, so changes to the given genes array doesn't effect the
073 * genes of this chromosome.
074 *
075 * @param genes the genes that form the chromosome.
076 * @throws NullPointerException if the given gene array is {@code null}.
077 * @throws IllegalArgumentException if the length of the gene array is
078 * smaller than one.
079 *
080 * @deprecated Visibility will be changed to {@code protected}.
081 */
082 @Deprecated
083 public CharacterChromosome(final ISeq<CharacterGene> genes) {
084 super(genes);
085 _validCharacters = genes.get(0).getValidCharacters();
086 }
087
088 /**
089 * Create a new chromosome with the {@code validCharacters} char set as
090 * valid characters.
091 *
092 * @param validCharacters the valid characters for this chromosome.
093 * @param length the length of the new chromosome.
094 * @throws NullPointerException if the {@code validCharacters} is
095 * {@code null}.
096 * @throws IllegalArgumentException if the {@code length} is smaller than
097 * one.
098 */
099 public CharacterChromosome(final CharSeq validCharacters, final int length) {
100 this(CharacterGene.seq(validCharacters, length));
101 _valid = true;
102 }
103
104 /**
105 * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
106 * char set as valid characters.
107 *
108 * @param length the {@code length} of the new chromosome.
109 * @throws IllegalArgumentException if the {@code length} is smaller than
110 * one.
111 *
112 * @deprecated Use {@link #of(int)} instead.
113 */
114 @Deprecated
115 public CharacterChromosome(final int length) {
116 this(DEFAULT_CHARACTERS, length);
117 }
118
119 /**
120 * Create a new chromosome from the given genes (given as string).
121 *
122 * @param genes the character genes.
123 * @param validCharacters the valid characters.
124 * @throws IllegalArgumentException if the genes string is empty.
125 *
126 * @deprecated Use {@link #of(String, org.jenetics.util.CharSeq)} instead.
127 */
128 @Deprecated
129 public CharacterChromosome(final String genes, final CharSeq validCharacters) {
130 super(
131 new Array<CharacterGene>(genes.length()).fill(new Factory<CharacterGene>() {
132 private int _index = 0;
133 @Override public CharacterGene newInstance() {
134 return CharacterGene.of(
135 genes.charAt(_index++), validCharacters
136 );
137 }
138 }).toISeq()
139 );
140
141 _validCharacters = validCharacters;
142 }
143
144 /**
145 * Create a new chromosome from the given genes (given as string).
146 *
147 * @param genes the character genes.
148 * @throws IllegalArgumentException if the genes string is empty.
149 *
150 * @deprecated Use {@link #of(String)} instead.
151 */
152 @Deprecated
153 public CharacterChromosome(final String genes) {
154 this(genes, DEFAULT_CHARACTERS);
155 }
156
157 /**
158 * Return a more specific view of this chromosome factory.
159 *
160 * @return a more specific view of this chromosome factory.
161 *
162 * @deprecated No longer needed after adding new factory methods to the
163 * {@link Array} class.
164 */
165 @Deprecated
166 @SuppressWarnings("unchecked")
167 public Factory<CharacterChromosome> asFactory() {
168 return (Factory<CharacterChromosome>)(Object)this;
169 }
170
171 @Override
172 public char charAt(final int index) {
173 return getGene(index).getAllele();
174 }
175
176 @Override
177 public CharacterChromosome subSequence(final int start, final int end) {
178 return new CharacterChromosome(_genes.subSeq(start, end));
179 }
180
181 /**
182 * @throws NullPointerException if the given gene array is {@code null}.
183 */
184 @Override
185 public CharacterChromosome newInstance(final ISeq<CharacterGene> genes) {
186 return new CharacterChromosome(genes);
187 }
188
189 /**
190 * Create a new, <em>random</em> chromosome.
191 */
192 @Override
193 public CharacterChromosome newInstance() {
194 return new CharacterChromosome(_validCharacters, length());
195 }
196
197 @Override
198 public int hashCode() {
199 return HashBuilder.of(getClass()).
200 and(super.hashCode()).
201 and(_validCharacters).value();
202 }
203
204 @Override
205 public boolean equals(final Object obj) {
206 if (obj == this) {
207 return true;
208 }
209 if (obj == null || getClass() != obj.getClass()) {
210 return false;
211 }
212
213 final CharacterChromosome cc = (CharacterChromosome)obj;
214 return super.equals(obj) && eq(_validCharacters, cc._validCharacters);
215 }
216
217 @Override
218 public String toString() {
219 final StringBuilder out = new StringBuilder();
220 for (CharacterGene gene : this) {
221 out.append(gene);
222 }
223 return out.toString();
224 }
225
226
227 /**
228 * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
229 * char set as valid characters.
230 *
231 * @param length the {@code length} of the new chromosome.
232 * @throws IllegalArgumentException if the {@code length} is smaller than
233 * one.
234 */
235 public static CharacterChromosome of(final int length) {
236 return new CharacterChromosome(
237 CharacterGene.seq(DEFAULT_CHARACTERS, length)
238 );
239 }
240
241 /**
242 * Create a new chromosome from the given genes (given as string).
243 *
244 * @param alleles the character genes.
245 * @param validChars the valid characters.
246 * @throws IllegalArgumentException if the genes string is empty.
247 */
248 public static CharacterChromosome of(
249 final String alleles,
250 final CharSeq validChars
251 ) {
252 final Array<CharacterGene> genes = new Array<>(alleles.length());
253 genes.fill(GeneFactory(alleles, validChars));
254 return new CharacterChromosome(genes.toISeq());
255 }
256
257 private static Factory<CharacterGene>
258 GeneFactory(final String alleles, final CharSeq validChars) {
259 return new Factory<CharacterGene>() {
260 private int _index = 0;
261 @Override
262 public CharacterGene newInstance() {
263 return CharacterGene.of(
264 alleles.charAt(_index++), validChars
265 );
266 }
267 };
268 }
269
270 /**
271 * Create a new chromosome from the given genes (given as string).
272 *
273 * @param alleles the character genes.
274 * @throws IllegalArgumentException if the genes string is empty.
275 */
276 public static CharacterChromosome of(final String alleles) {
277 return of(alleles, DEFAULT_CHARACTERS);
278 }
279
280 /* *************************************************************************
281 * Property access methods
282 * ************************************************************************/
283
284 /**
285 * Return a {@link Function} which returns the gene array from this
286 * {@link Chromosome}.
287 */
288 public static final Function<Chromosome<CharacterGene>, ISeq<CharacterGene>>
289 Genes = AbstractChromosome.genes();
290
291 /**
292 * Return a {@link Function} which returns the first {@link Gene} from this
293 * {@link Chromosome}.
294 */
295 public static final Function<Chromosome<CharacterGene>, CharacterGene>
296 Gene = AbstractChromosome.gene();
297
298 /**
299 * Return a {@link Function} which returns the {@link Gene} with the given
300 * {@code index} from this {@link Chromosome}.
301 */
302 public static Function<Chromosome<CharacterGene>, CharacterGene>
303 Gene(final int index)
304 {
305 return AbstractChromosome.gene(index);
306 }
307
308
309 /* *************************************************************************
310 * Java object serialization
311 * ************************************************************************/
312
313 private void writeObject(final ObjectOutputStream out)
314 throws IOException
315 {
316 out.defaultWriteObject();
317
318 out.writeInt(length());
319 out.writeObject(_validCharacters);
320
321 for (CharacterGene gene : _genes) {
322 out.writeChar(gene.getAllele().charValue());
323 }
324 }
325
326 private void readObject(final ObjectInputStream in)
327 throws IOException, ClassNotFoundException
328 {
329 in.defaultReadObject();
330
331 final int length = in.readInt();
332 _validCharacters = (CharSeq)in.readObject();
333
334 final Array<CharacterGene> genes = new Array<>(length);
335 for (int i = 0; i < length; ++i) {
336 final CharacterGene gene = CharacterGene.of(
337 in.readChar(),
338 _validCharacters
339 );
340 genes.set(i, gene);
341 }
342
343 _genes = genes.toISeq();
344 }
345
346 /* *************************************************************************
347 * XML object serialization
348 * ************************************************************************/
349
350 static final XMLFormat<CharacterChromosome>
351 XML = new XMLFormat<CharacterChromosome>(CharacterChromosome.class)
352 {
353 private static final String LENGTH = "length";
354 private static final String VALID_CHARS = "valid-characters";
355
356 @Override
357 public CharacterChromosome newInstance(
358 final Class<CharacterChromosome> cls, final InputElement xml
359 )
360 throws XMLStreamException
361 {
362 final int length = xml.getAttribute(LENGTH, 0);
363 final CharSeq validCharacters = new CharSeq(xml.getAttribute(
364 VALID_CHARS, CharacterGene.DEFAULT_CHARACTERS.toString()
365 ));
366
367 final Array<CharacterGene> array = new Array<>(length);
368 final CharArray values = xml.getText();
369 for (int i = 0; i < length; ++i) {
370 array.set(i, CharacterGene.of(values.charAt(i), validCharacters));
371 }
372 return new CharacterChromosome(array.toISeq());
373 }
374 @Override
375 public void write(final CharacterChromosome chromosome, final OutputElement xml)
376 throws XMLStreamException
377 {
378 xml.setAttribute(LENGTH, chromosome.length());
379 xml.setAttribute(VALID_CHARS, chromosome._validCharacters.toString());
380 final StringBuilder out = new StringBuilder(chromosome.length());
381 for (CharacterGene gene : chromosome) {
382 out.append(gene.getAllele().charValue());
383 }
384 xml.addText(out.toString());
385 }
386 @Override
387 public void read(final InputElement element, final CharacterChromosome chromosome) {
388 }
389
390 };
391
392 /* *************************************************************************
393 * JAXB object serialization
394 * ************************************************************************/
395
396 @XmlRootElement(name = "org.jenetics.CharacterChromosome")
397 @XmlType(name = "org.jenetics.CharacterChromosome")
398 @XmlAccessorType(XmlAccessType.FIELD)
399 final static class Model {
400
401 @XmlAttribute
402 public int length;
403
404 @XmlAttribute(name = "valid-characters")
405 public String validCharacters;
406
407 @XmlValue
408 public String genes;
409
410 @ValueType(CharacterChromosome.class)
411 @ModelType(Model.class)
412 public final static class Adapter
413 extends XmlAdapter<Model, CharacterChromosome>
414 {
415 @Override
416 public Model marshal(final CharacterChromosome value) {
417 final Model m = new Model();
418 m.length = value.length();
419 m.validCharacters = value._validCharacters.toString();
420 m.genes = value.toString();
421 return m;
422 }
423
424 @Override
425 public CharacterChromosome unmarshal(final Model m) {
426 return CharacterChromosome.of(
427 m.genes,
428 new CharSeq(m.validCharacters)
429 );
430 }
431 }
432 }
433 }
|