Genotype.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.util.Objects.requireNonNull;
023 import static org.jenetics.util.object.Verify;
024 import static org.jenetics.util.object.eq;
025 import static org.jenetics.util.object.hashCodeOf;
026 
027 import java.util.Iterator;
028 
029 import javolution.lang.Immutable;
030 import javolution.lang.Realtime;
031 import javolution.text.Text;
032 import javolution.xml.XMLFormat;
033 import javolution.xml.XMLSerializable;
034 import javolution.xml.stream.XMLStreamException;
035 
036 import org.jenetics.util.Array;
037 import org.jenetics.util.Factory;
038 import org.jenetics.util.Function;
039 import org.jenetics.util.ISeq;
040 import org.jenetics.util.Seq;
041 import org.jenetics.util.Verifiable;
042 
043 /**
044  * The central class the GA is working with, is the {@code Genotype}. It is the
045  * structural representative of an individual. This class is the encoded problem
046  * solution with one to many {@link Chromosome}.
047  <p><div align="center">
048  <img src="doc-files/Genotype.svg" width="400" height="252" >
049  </p></div>
050  * The chromosomes of a genotype doesn't have to have necessarily the same size.
051  * It is only required that all genes are from the same type and the genes within
052  * a chromosome have the same constraints; e. g. the same min- and max values
053  * for number genes.
054  *
055  * [code]
056  * final Genotype〈Float64Gene〉 genotype = Genotype.valueOf(
057  *     new Float64Chromosome(0.0, 1.0, 8),
058  *     new Float64Chromosome(1.0, 2.0, 10),
059  *     new Float64Chromosome(0.0, 10.0, 9),
060  *     new Float64Chromosome(0.1, 0.9, 5)
061  * );
062  * [/code]
063  * The code snippet above creates a genotype with the same structure as shown in
064  * the figure above. In this example the {@link Float64Gene} has been chosen as
065  * gene type.
066  *
067  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
068  @since 1.0
069  @version 1.0 &mdash; <em>$Date: 2013-11-28 $</em>
070  */
071 public final class Genotype<G extends Gene<?, G>>
072     implements
073         Factory<Genotype<G>>,
074         Iterable<Chromosome<G>>,
075         Verifiable,
076         XMLSerializable,
077         Realtime,
078         Immutable
079 {
080     private static final long serialVersionUID = 2L;
081 
082     private final ISeq<Chromosome<G>> _chromosomes;
083     private final int _ngenes;
084 
085     //Caching isValid value.
086     private volatile Boolean _valid = null;
087 
088     private Genotype(final ISeq<Chromosome<G>> chromosomes, final int ngenes) {
089         _chromosomes = chromosomes;
090         _ngenes = ngenes;
091     }
092 
093     private static int ngenes(final Seq<? extends Chromosome<?>> chromosomes) {
094         int ngenes = 0;
095         for (int i = chromosomes.length(); --i >= 0;) {
096             ngenes += chromosomes.get(i).length();
097         }
098         return ngenes;
099     }
100 
101     /**
102      * Return the chromosome at the given index. It is guaranteed, that the
103      * returned chromosome is not null.
104      *
105      @param index Chromosome index.
106      @return The Chromosome.
107      @throws IndexOutOfBoundsException if (index < 0 || index >= _length).
108      */
109     public Chromosome<G> getChromosome(final int index) {
110         assert(_chromosomes != null);
111         assert(_chromosomes.get(index!= null);
112 
113         return _chromosomes.get(index);
114     }
115 
116     /**
117      * Return the first chromosome. This is a shortcut for
118      * [code]
119      * final Genotype〈Float64Gene〉 gt = ...
120      * final Chromosome〈Float64Gene〉 chromosome = gt.getChromosome(0);
121      * [/code]
122      *
123      @return The first chromosome.
124      */
125     public Chromosome<G> getChromosome() {
126         assert(_chromosomes != null);
127         assert(_chromosomes.get(0!= null);
128 
129         return _chromosomes.get(0);
130     }
131 
132     /**
133      * Return the first {@link Gene} of the first {@link Chromosome} of this
134      * {@code Genotype}. This is a shortcut for
135      * [code]
136      * final Genotype〈Float64Gene〉 gt = ...
137      * final Float64Gene gene = gt.getChromosome(0).getGene(0);
138      * [/code]
139      *
140      @return the first {@link Gene} of the first {@link Chromosome} of this
141      *         {@code Genotype}.
142      */
143     public G getGene() {
144         assert(_chromosomes != null);
145         assert(_chromosomes.get(0!= null);
146 
147         return _chromosomes.get(0).getGene();
148     }
149 
150 
151     public ISeq<Chromosome<G>> toSeq() {
152         return _chromosomes;
153     }
154 
155     @Override
156     public Iterator<Chromosome<G>> iterator() {
157         return _chromosomes.iterator();
158     }
159 
160     /**
161      * Getting the number of chromosomes of this genotype.
162      *
163      @return number of chromosomes.
164      */
165     public int length() {
166         return _chromosomes.length();
167     }
168 
169     /**
170      * Return the number of genes this genotype consists of. This is the sum of
171      * the number of genes of the genotype chromosomes.
172      *
173      @return Return the number of genes this genotype consists of.
174      */
175     public int getNumberOfGenes() {
176         return _ngenes;
177     }
178 
179     /**
180      * Test if this genotype is valid. A genotype is valid if all its
181      {@link Chromosome}s are valid.
182      *
183      @return true if this genotype is valid, false otherwise.
184      */
185     @Override
186     public boolean isValid() {
187         if (_valid == null) {
188             _valid = _chromosomes.forAll(Verify);
189         }
190         return _valid;
191     }
192 
193     /**
194      * Return a new, random genotype by creating new, random chromosomes (calling
195      * the {@link Chromosome#newInstance()} method) from the chromosomes of this
196      * genotype.
197      */
198     @Override
199     public Genotype<G> newInstance() {
200         final Array<Chromosome<G>> chromosomes = new Array<>(length());
201         for (int i = 0; i < length(); ++i) {
202             chromosomes.set(i, _chromosomes.get(i).newInstance());
203         }
204 
205         return new Genotype<>(chromosomes.toISeq(), _ngenes);
206     }
207 
208     Genotype<G> newInstance(final ISeq<Chromosome<G>> chromosomes) {
209         return new Genotype<>(chromosomes, _ngenes);
210     }
211 
212     @Override
213     public int hashCode() {
214         return hashCodeOf(getClass()).and(_chromosomes).value();
215     }
216 
217     @Override
218     public boolean equals(final Object o) {
219         if (o == this) {
220             return true;
221         }
222         if (!(instanceof Genotype<?>)) {
223             return false;
224         }
225 
226         final Genotype<?> gt = (Genotype<?>)o;
227         return eq(_chromosomes, gt._chromosomes);
228     }
229 
230     @Override
231     public Text toText() {
232         return new Text(_chromosomes.toString());
233     }
234 
235     @Override
236     public String toString() {
237         return _chromosomes.toString();
238     }
239 
240 
241     /* *************************************************************************
242      *  Property access methods
243      * ************************************************************************/
244 
245     /**
246      * Return a converter which access the chromosome array of this genotype.
247      */
248     public static <T extends Gene<?, T>>
249     Function<Genotype<T>, ISeq<Chromosome<T>>> Chromosomes()
250     {
251         return new Function<Genotype<T>, ISeq<Chromosome<T>>>() {
252             @Override public ISeq<Chromosome<T>> apply(final Genotype<T> value) {
253                 return value.toSeq();
254             }
255         };
256     }
257 
258     /**
259      * Return a converter which access the chromosome with the given index of
260      * this genotype.
261      */
262     public static <T extends Gene<?, T>>
263     Function<Genotype<T>, Chromosome<T>> Chromosome(final int index)
264     {
265         return new Function<Genotype<T>, Chromosome<T>>() {
266             @Override public Chromosome<T> apply(final Genotype<T> value) {
267                 return value.getChromosome(index);
268             }
269         };
270     }
271 
272     /**
273      * Return a converter which access the first chromosome of this genotype.
274      */
275     public static <T extends Gene<?, T>>
276     Function<Genotype<T>, Chromosome<T>> Chromosome()
277     {
278         return new Function<Genotype<T>, Chromosome<T>>() {
279             @Override public Chromosome<T> apply(final Genotype<T> value) {
280                 return value.getChromosome();
281             }
282         };
283     }
284 
285 
286     /**
287      * Create a new Genotype from a given array of {@code Chromosomes}.
288      *
289      @param chromosomes The {@code Chromosome} array the {@code Genotype}
290      *         consists of.
291      @throws NullPointerException if {@code chromosomes} is null or one of its
292      *         element.
293      @throws IllegalArgumentException if {@code chromosome.length == 0}.
294      */
295     public static <G extends Gene<?, G>> Genotype<G> valueOf(
296         final ISeq<? extends Chromosome<G>> chromosomes
297     ) {
298         requireNonNull(chromosomes, "Chromosomes");
299         if (chromosomes.length() == 0) {
300             throw new IllegalArgumentException("Chromosomes must be given.");
301         }
302 
303         @SuppressWarnings("unchecked")
304         ISeq<Chromosome<G>> c = (ISeq<Chromosome<G>>)chromosomes;
305         return new Genotype<>(c, ngenes(chromosomes));
306     }
307 
308     /**
309      * Create a new Genotype from a given array of {@code Chromosomes}.
310      *
311      @param chromosomes The {@code Chromosome} array the {@code Genotype}
312      *         consists of.
313      @throws NullPointerException if {@code chromosomes} is null or one of its
314      *         element.
315      @throws IllegalArgumentException if {@code chromosome.length == 0}.
316      */
317     @SafeVarargs
318     public static <G extends Gene<?, G>> Genotype<G> valueOf(
319         final Chromosome<G>... chromosomes
320     ) {
321         return valueOf(Array.valueOf(chromosomes).toISeq());
322     }
323 
324     /* *************************************************************************
325      *  XML object serialization
326      * ************************************************************************/
327 
328     @SuppressWarnings({ "unchecked""rawtypes"})
329     static final XMLFormat<Genotype>
330     XML = new XMLFormat<Genotype>(Genotype.class)
331     {
332         private static final String LENGTH = "length";
333         private static final String NGENES = "ngenes";
334 
335         @Override
336         public Genotype newInstance(
337             final Class<Genotype> cls, final InputElement xml
338         )
339             throws XMLStreamException
340         {
341             final int length = xml.getAttribute(LENGTH, 0);
342             final int ngenes = xml.getAttribute(NGENES, 0);
343             final Array<Chromosome> chromosomes = new Array<>(length);
344             for (int i = 0; i < length; ++i) {
345                 final Chromosome<?> c = xml.getNext();
346                 chromosomes.set(i, c);
347             }
348 
349             return new Genotype(chromosomes.toISeq(), ngenes);
350         }
351         @Override
352         public void write(final Genotype gt, final OutputElement xml)
353             throws XMLStreamException
354         {
355             xml.setAttribute(LENGTH, gt.length());
356             xml.setAttribute(NGENES, gt.getNumberOfGenes());
357             for (int i = 0; i < gt.length(); ++i) {
358                 xml.add(gt._chromosomes.get(i));
359             }
360         }
361         @Override
362         public void read(final InputElement xml, final Genotype gt) {
363         }
364     };
365 }
366 
367 
368 
369