CharacterChromosome.java
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 &mdash; <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 }