CharacterChromosome.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-1.5.0).
003  * Copyright (c) 2007-2013 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 java.lang.String.format;
023 import static org.jenetics.util.object.eq;
024 import static org.jenetics.util.object.hashCodeOf;
025 
026 import java.io.IOException;
027 import java.io.ObjectInputStream;
028 import java.io.ObjectOutputStream;
029 
030 import javolution.text.CharArray;
031 import javolution.xml.XMLFormat;
032 import javolution.xml.XMLSerializable;
033 import javolution.xml.stream.XMLStreamException;
034 
035 import org.jenetics.util.Array;
036 import org.jenetics.util.CharSeq;
037 import org.jenetics.util.Factory;
038 import org.jenetics.util.Function;
039 import org.jenetics.util.ISeq;
040 
041 /**
042  * CharacterChromosome which represents character sequences.
043  *
044  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
045  @since 1.0
046  @version 1.0 &mdash; <em>$Date: 2013-12-05 $</em>
047  */
048 public class CharacterChromosome
049     extends
050         AbstractChromosome<CharacterGene>
051     implements
052         CharSequence,
053         XMLSerializable
054 {
055     private static final long serialVersionUID = 1L;
056 
057     private transient CharSeq _validCharacters;
058 
059     /**
060      * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
061      * char set as valid characters.
062      *
063      @param length the {@code length} of the new chromosome.
064      @throws IllegalArgumentException if the {@code length} is smaller than
065      *         one.
066      */
067     public CharacterChromosome(final int length) {
068         super(
069             new Array<CharacterGene>(length).fill(
070                 CharacterGene.valueOf(CharacterGene.DEFAULT_CHARACTERS)
071             ).toISeq()
072         );
073         _validCharacters = CharacterGene.DEFAULT_CHARACTERS;
074         _valid = true;
075     }
076 
077     /**
078      * Create a new chromosome with the {@code validCharacters} char set as
079      * valid characters.
080      *
081      @param validCharacters the valid characters for this chromosome.
082      @param length the length of the new chromosome.
083      @throws NullPointerException if the {@code validCharacters} is
084      *         {@code null}.
085      @throws IllegalArgumentException if the {@code length} is smaller than
086      *         one.
087      */
088     public CharacterChromosome(final CharSeq validCharacters, final int length) {
089         super(
090             new Array<CharacterGene>(length).fill(
091                 CharacterGene.valueOf(validCharacters)
092             ).toISeq()
093         );
094         _validCharacters = validCharacters;
095         _valid = true;
096     }
097 
098     /**
099      * Create a new chromosome from the given {@code genes} array. The genes
100      * array is copied, so changes to the given genes array doesn't effect the
101      * genes of this chromosome.
102      *
103      @param genes the genes that form the chromosome.
104      @throws NullPointerException if the given gene array is {@code null}.
105      @throws IllegalArgumentException if the length of the gene array is
106      *         smaller than one.
107      */
108     public CharacterChromosome(final ISeq<CharacterGene> genes) {
109         super(genes);
110         _validCharacters = genes.get(0).getValidCharacters();
111     }
112 
113     /**
114      * Create a new chromosome from the given genes (given as string).
115      *
116      @param genes the character genes.
117      @param validCharacters the valid characters.
118      @throws IllegalArgumentException if not all genes are in the set of valid
119      *         characters or the genes string is empty.
120      */
121     public CharacterChromosome(final String genes, final CharSeq validCharacters) {
122         super(
123             new Array<CharacterGene>(genes.length()).fill(new Factory<CharacterGene>() {
124                 private int _index = 0;
125                 @Override
126                 public CharacterGene newInstance() {
127                     final char c = genes.charAt(_index++);
128                     if (!validCharacters.contains(c)) {
129                         throw new IllegalArgumentException(format(
130                                 "Character '%s' not in valid characters %s",
131                                 c, validCharacters
132                             ));
133                     }
134                     return CharacterGene.valueOf(c, validCharacters);
135                 }
136             }).toISeq()
137         );
138 
139         _validCharacters = validCharacters;
140     }
141 
142     /**
143      * Create a new chromosome from the given genes (given as string).
144      *
145      @param genes the character genes.
146      @throws IllegalArgumentException if not all genes are in the set of valid
147      *         characters or the genes is an empty string.
148      */
149     public CharacterChromosome(final String genes) {
150         this(genes, CharacterGene.DEFAULT_CHARACTERS);
151     }
152 
153     /**
154      * Return a more specific view of this chromosome factory.
155      *
156      @return a more specific view of this chromosome factory.
157      *
158      @deprecated No longer needed after adding new factory methods to the
159      *            {@link Array} class.
160      */
161     @Deprecated
162     @SuppressWarnings("unchecked")
163     public Factory<CharacterChromosome> asFactory() {
164         return (Factory<CharacterChromosome>)(Object)this;
165     }
166 
167     @Override
168     public char charAt(final int index) {
169         return getGene(index).getAllele();
170     }
171 
172     @Override
173     public CharacterChromosome subSequence(final int start, final int end) {
174         return new CharacterChromosome(_genes.subSeq(start, end));
175     }
176 
177     /**
178      @throws NullPointerException if the given gene array is {@code null}.
179      */
180     @Override
181     public CharacterChromosome newInstance(final ISeq<CharacterGene> genes) {
182         return new CharacterChromosome(genes);
183     }
184 
185     /**
186      * Create a new, <em>random</em> chromosome.
187      */
188     @Override
189     public CharacterChromosome newInstance() {
190         return new CharacterChromosome(_validCharacters, length());
191     }
192 
193     @Override
194     public int hashCode() {
195         return hashCodeOf(getClass()).
196                 and(super.hashCode()).
197                 and(_validCharacters).value();
198     }
199 
200     @Override
201     public boolean equals(final Object obj) {
202         if (obj == this) {
203             return true;
204         }
205         if (obj == null || getClass() != obj.getClass()) {
206             return false;
207         }
208 
209         final CharacterChromosome cc = (CharacterChromosome)obj;
210         return super.equals(obj&& eq(_validCharacters, cc._validCharacters);
211     }
212 
213     @Override
214     public String toString() {
215         final StringBuilder out = new StringBuilder();
216         for (CharacterGene gene : this) {
217             out.append(gene);
218         }
219         return out.toString();
220     }
221 
222 
223     /* *************************************************************************
224      *  Property access methods
225      * ************************************************************************/
226 
227     /**
228      * Return a {@link Function} which returns the gene array from this
229      {@link Chromosome}.
230      */
231     public static final Function<Chromosome<CharacterGene>, ISeq<CharacterGene>>
232         Genes = AbstractChromosome.genes();
233 
234     /**
235      * Return a {@link Function} which returns the first {@link Gene} from this
236      {@link Chromosome}.
237      */
238     public static final Function<Chromosome<CharacterGene>, CharacterGene>
239         Gene = AbstractChromosome.gene();
240 
241     /**
242      * Return a {@link Function} which returns the {@link Gene} with the given
243      * {@code index} from this {@link Chromosome}.
244      */
245     public static final Function<Chromosome<CharacterGene>, CharacterGene>
246     Gene(final int index)
247     {
248         return AbstractChromosome.gene(index);
249     }
250 
251     /* *************************************************************************
252      *  XML object serialization
253      * ************************************************************************/
254 
255     static final XMLFormat<CharacterChromosome>
256     XML = new XMLFormat<CharacterChromosome>(CharacterChromosome.class)
257     {
258         private static final String LENGTH = "length";
259         private static final String VALID_CHARS = "valid-characters";
260 
261         @Override
262         public CharacterChromosome newInstance(
263             final Class<CharacterChromosome> cls, final InputElement xml
264         )
265             throws XMLStreamException
266         {
267             final int length = xml.getAttribute(LENGTH, 0);
268             final CharSeq validCharacters = new CharSeq(xml.getAttribute(
269                     VALID_CHARS, CharacterGene.DEFAULT_CHARACTERS.toString()
270                 ));
271 
272             final Array<CharacterGene> array = new Array<>(length);
273             final CharArray values = xml.getText();
274             for (int i = 0; i < length; ++i) {
275                 array.set(i, CharacterGene.valueOf(values.charAt(i), validCharacters));
276             }
277             return new CharacterChromosome(array.toISeq());
278         }
279         @Override
280         public void write(final CharacterChromosome chromosome, final OutputElement xml)
281             throws XMLStreamException
282         {
283             xml.setAttribute(LENGTH, chromosome.length());
284             xml.setAttribute(VALID_CHARS, chromosome._validCharacters.toString());
285             final StringBuilder out = new StringBuilder(chromosome.length());
286             for (CharacterGene gene : chromosome) {
287                 out.append(gene.getAllele().charValue());
288             }
289             xml.addText(out.toString());
290         }
291         @Override
292         public void read(final InputElement element, final CharacterChromosome chromosome) {
293         }
294 
295     };
296 
297     /* *************************************************************************
298      *  Java object serialization
299      * ************************************************************************/
300 
301     private void writeObject(final ObjectOutputStream out)
302         throws IOException
303     {
304         out.defaultWriteObject();
305 
306         out.writeInt(length());
307         out.writeObject(_validCharacters);
308 
309         for (CharacterGene gene : _genes) {
310             out.writeChar(gene.getAllele().charValue());
311         }
312     }
313 
314     private void readObject(final ObjectInputStream in)
315         throws IOException, ClassNotFoundException
316     {
317         in.defaultReadObject();
318 
319         final int length = in.readInt();
320         _validCharacters = (CharSeq)in.readObject();
321 
322         final Array<CharacterGene> genes = new Array<>(length);
323         for (int i = 0; i < length; ++i) {
324             final CharacterGene gene = CharacterGene.valueOf(
325                 in.readChar(),
326                 _validCharacters
327             );
328             genes.set(i, gene);
329         }
330 
331         _genes = genes.toISeq();
332     }
333 
334 }
335 
336