Genotype.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.2.0).
003  * Copyright (c) 2007-2020 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@gmail.com)
019  */
020 package io.jenetics;
021 
022 import static io.jenetics.internal.util.Hashes.hash;
023 import static io.jenetics.internal.util.SerialIO.readInt;
024 import static io.jenetics.internal.util.SerialIO.writeInt;
025 
026 import java.io.IOException;
027 import java.io.InvalidObjectException;
028 import java.io.ObjectInput;
029 import java.io.ObjectInputStream;
030 import java.io.ObjectOutput;
031 import java.io.Serializable;
032 import java.util.Objects;
033 
034 import io.jenetics.util.BaseSeq;
035 import io.jenetics.util.Factory;
036 import io.jenetics.util.ISeq;
037 import io.jenetics.util.MSeq;
038 import io.jenetics.util.Verifiable;
039 
040 /**
041  * The central class the GA is working with, is the {@code Genotype}. It is the
042  * structural representative of an individual. This class is the encoded problem
043  * solution with one to many {@link Chromosome}.
044  <p>
045  <img alt="Genotype" src="doc-files/Genotype.svg" width="400" height="252" >
046  </p>
047  * The chromosomes of a genotype doesn't have to have necessarily the same size.
048  * It is only required that all genes are from the same type and the genes within
049  * a chromosome have the same constraints; e. g. the same min- and max values
050  * for number genes.
051  *
052  <pre>{@code
053  * final Genotype<DoubleGene> genotype = Genotype.of(
054  *     DoubleChromosome.of(0.0, 1.0, 8),
055  *     DoubleChromosome.of(1.0, 2.0, 10),
056  *     DoubleChromosome.of(0.0, 10.0, 9),
057  *     DoubleChromosome.of(0.1, 0.9, 5)
058  * );
059  * }</pre>
060  * The code snippet above creates a genotype with the same structure as shown in
061  * the figure above. In this example the {@link DoubleGene} has been chosen as
062  * gene type.
063  *
064  @see Chromosome
065  @see Phenotype
066  *
067  * @implNote
068  * This class is immutable and thread-safe.
069  *
070  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
071  @since 1.0
072  @version 5.2
073  */
074 public final class Genotype<G extends Gene<?, G>>
075     implements
076         BaseSeq<Chromosome<G>>,
077         Factory<Genotype<G>>,
078         Verifiable,
079         Serializable
080 {
081     private static final long serialVersionUID = 3L;
082 
083     private final ISeq<Chromosome<G>> _chromosomes;
084 
085     //Caching isValid value.
086     private byte _valid = -1;
087 
088     /**
089      * Create a new Genotype from a given sequence of {@code Chromosomes}.
090      *
091      @param chromosomes The {@code Chromosome} array the {@code Genotype}
092      *         consists of.
093      @throws NullPointerException if {@code chromosomes} is null or one of its
094      *         element.
095      @throws IllegalArgumentException if {@code chromosome.length == 0}.
096      */
097     Genotype(final ISeq<? extends Chromosome<G>> chromosomes) {
098         if (chromosomes.isEmpty()) {
099             throw new IllegalArgumentException("No chromosomes given.");
100         }
101 
102         _chromosomes = ISeq.upcast(chromosomes);
103     }
104 
105     /**
106      * Return the chromosome at the given index. It is guaranteed, that the
107      * returned chromosome is not null.
108      *
109      @since 4.0
110      *
111      @param index the chromosome index
112      @return the chromosome with the given index
113      @throws IndexOutOfBoundsException if
114      *         {@code (index < 0 || index >= _length)}.
115      */
116     @Override
117     public Chromosome<G> get(final int index) {
118         return _chromosomes.get(index);
119     }
120 
121     /**
122      * Getting the number of chromosomes of this genotype.
123      *
124      @return number of chromosomes.
125      */
126     @Override
127     public int length() {
128         return _chromosomes.length();
129     }
130 
131     /**
132      * Return the first chromosome. This is an alias for
133      <pre>{@code
134      * final Genotype<DoubleGene>; gt = ...
135      * final Chromosome<DoubleGene> chromosome = gt.get(0);
136      * }</pre>
137      *
138      @since 5.2
139      *
140      @return The first chromosome.
141      */
142     public Chromosome<G> chromosome() {
143         return get(0);
144     }
145 
146     /**
147      * Return the first {@link Gene} of the first {@link Chromosome} of this
148      * {@code Genotype}. This is an alias for
149      <pre>{@code
150      * final Genotype<DoubleGene> gt = ...
151      * final DoubleGene gene = gt.get(0).get(0);
152      * }</pre>
153      *
154      @since 5.2
155      *
156      @return the first {@link Gene} of the first {@link Chromosome} of this
157      *         {@code Genotype}.
158      */
159     public G gene() {
160         return get(0).get(0);
161     }
162 
163     /**
164      * Return the chromosome at the given index. It is guaranteed, that the
165      * returned chromosome is not null.
166      *
167      @param index Chromosome index.
168      @return The Chromosome.
169      @throws IndexOutOfBoundsException if
170      *         {@code (index < 0 || index >= _length)}.
171      @deprecated Use the getter, {@link #get(int)}, from the {@link BaseSeq}
172      *             interface.
173      */
174     @Deprecated
175     public Chromosome<G> getChromosome(final int index) {
176         assert _chromosomes != null;
177         assert _chromosomes.get(index!= null;
178 
179         return _chromosomes.get(index);
180     }
181 
182     /**
183      * Return the first chromosome. This is a shortcut for
184      <pre>{@code
185      * final Genotype<DoubleGene>; gt = ...
186      * final Chromosome<DoubleGene> chromosome = gt.get(0);
187      * }</pre>
188      *
189      @return The first chromosome.
190      @deprecated Use {@link #chromosome()} instead
191      */
192     @Deprecated
193     public Chromosome<G> getChromosome() {
194         assert _chromosomes != null;
195         assert _chromosomes.get(0!= null;
196 
197         return _chromosomes.get(0);
198     }
199 
200     /**
201      * Return the first {@link Gene} of the first {@link Chromosome} of this
202      * {@code Genotype}. This is a shortcut for
203      <pre>{@code
204      * final Genotype<DoubleGene> gt = ...
205      * final DoubleGene gene = gt.get(0).get(0);
206      * }</pre>
207      *
208      @return the first {@link Gene} of the first {@link Chromosome} of this
209      *         {@code Genotype}.
210      @deprecated Use {@link #gene()} instead
211      */
212     @Deprecated
213     public G getGene() {
214         assert _chromosomes != null;
215         assert _chromosomes.get(0!= null;
216 
217         return _chromosomes.get(0).gene();
218     }
219 
220     /**
221      * Return the gene from the given chromosome- and gene index. This is a
222      * shortcut for {@code gt.getChromosome(chromosomeIndex).getGene(geneIndex)}.
223      *
224      @since 3.0
225      *
226      @param chromosomeIndex the chromosome index
227      @param geneIndex the gene index within the chromosome
228      @return the gene with the given indexes
229      @throws IndexOutOfBoundsException if the given indexes are not within the
230      *         allowed range
231      @deprecated Use {@code get(chromosomeIndex).get(geneIndex)} instead
232      */
233     @Deprecated
234     public G get(final int chromosomeIndex, final int geneIndex) {
235         return get(chromosomeIndex).get(geneIndex);
236     }
237 
238     /**
239      * Return an immutable chromosome sequence.
240      *
241      @deprecated Since the genotype itself extends the {@link BaseSeq}, it
242      *             is no longer necessary to get a sequence with genes. If it is
243      *             necessary to create an {@link ISeq} from a genotype, use
244      *             {@code ISeq.of(genotype)} instead. This method will be
245      *             removed in the next major release.
246      @return an immutable chromosome sequence
247      */
248     @Deprecated
249     public ISeq<Chromosome<G>> toSeq() {
250         return _chromosomes;
251     }
252 
253 
254     /**
255      * Return the number of genes this genotype consists of. This is the sum of
256      * the number of genes of the genotype chromosomes.
257      *
258      @return Return the number of genes this genotype consists of.
259      */
260     public int geneCount() {
261         int count = 0;
262         for (Chromosome<?> chromosome : this) {
263             count += chromosome.length();
264         }
265         return count;
266     }
267 
268     /**
269      * Test if this genotype is valid. A genotype is valid if all its
270      {@link Chromosome}s are valid.
271      *
272      @return true if this genotype is valid, false otherwise.
273      */
274     @Override
275     public boolean isValid() {
276         byte valid = _valid;
277         if (valid == -1) {
278             valid = (byte)(_chromosomes.forAll(Verifiable::isValid0);
279             _valid = valid;
280         }
281 
282         return _valid == 1;
283     }
284 
285     /**
286      * Return a new, random genotype by creating new, random chromosomes (calling
287      * the {@link Chromosome#newInstance()} method) from the chromosomes of this
288      * genotype.
289      */
290     @Override
291     public Genotype<G> newInstance() {
292         return new Genotype<>(_chromosomes.map(Factory::newInstance));
293     }
294 
295     @Override
296     public int hashCode() {
297         return hash(_chromosomes);
298     }
299 
300     @Override
301     public boolean equals(final Object obj) {
302         return obj == this ||
303             obj instanceof Genotype &&
304             Objects.equals(_chromosomes, ((Genotype)obj)._chromosomes);
305     }
306 
307     @Override
308     public String toString() {
309         return _chromosomes.toString();
310     }
311 
312     /**
313      * Create a new {@code Genotype} from a given array of {@code Chromosomes}.
314      *
315      @since 3.0
316      *
317      @param <G> the gene type
318      @param first the first {@code Chromosome} of the {@code Genotype}
319      @param rest the rest of the genotypes chromosomes.
320      @return a new {@code Genotype} from the given chromosomes
321      @throws NullPointerException if {@code chromosomes} is {@code null} or
322      *         one of its element.
323      */
324     @SafeVarargs
325     public static <G extends Gene<?, G>> Genotype<G> of(
326         final Chromosome<G> first,
327         final Chromosome<G>... rest
328     ) {
329         final MSeq<Chromosome<G>> seq = MSeq.ofLength(+ rest.length);
330         seq.set(0, first);
331         for (int i = 0; i < rest.length; ++i) {
332             seq.set(i + 1, rest[i]);
333         }
334         return new Genotype<>(seq.toISeq());
335     }
336 
337     /**
338      * Create a new {@code Genotype} which consists of {@code n} chromosomes,
339      * which are created by the given {@code factory}. This method can be used
340      * for easily creating a <i>gene matrix</i>. The following example will
341      * create a 10x5 {@code DoubleGene} <i>matrix</i>.
342      *
343      <pre>{@code
344      * final Genotype<DoubleGene> gt = Genotype
345      *     .of(DoubleChromosome.of(0.0, 1.0, 10), 5);
346      * }</pre>
347      *
348      @since 3.0
349      *
350      @param <G> the gene type
351      @param factory the factory which creates the chromosomes this genotype
352      *        consists of
353      @param n the number of chromosomes this genotype consists of
354      @return new {@code Genotype} containing {@code n} chromosomes
355      @throws IllegalArgumentException if {@code n < 1}.
356      @throws NullPointerException if the {@code factory} is {@code null}.
357      */
358     public static <G extends Gene<?, G>> Genotype<G>
359     of(final Factory<? extends Chromosome<G>> factory, final int n) {
360         final ISeq<Chromosome<G>> ch = ISeq.of(factory::newInstance, n);
361         return new Genotype<>(ch);
362     }
363 
364     /**
365      * Create a new {@code Genotype} from a given array of {@code chromosomes}.
366      *
367      @since 3.0
368      *
369      @param <G> the gene type
370      @param chromosomes the {@code Chromosome}s the returned genotype consists
371      *        of
372      @return a new {@code Genotype} from the given chromosomes
373      @throws NullPointerException if {@code chromosomes} is {@code null} or
374      *         one of its element.
375      @throws IllegalArgumentException if {@code chromosome.length() < 1}.
376      */
377     public static <G extends Gene<?, G>> Genotype<G>
378     of(final Iterable<? extends Chromosome<G>> chromosomes) {
379         return new Genotype<>(ISeq.of(chromosomes));
380     }
381 
382 
383     /* *************************************************************************
384      *  Java object serialization
385      * ************************************************************************/
386 
387     private Object writeReplace() {
388         return new Serial(Serial.GENOTYPE, this);
389     }
390 
391     private void readObject(final ObjectInputStream stream)
392         throws InvalidObjectException
393     {
394         throw new InvalidObjectException("Serialization proxy required.");
395     }
396 
397     void write(final ObjectOutput outthrows IOException {
398         writeInt(_chromosomes.length(), out);
399         for (Chromosome<G> ch : _chromosomes) {
400             out.writeObject(ch);
401         }
402     }
403 
404     @SuppressWarnings({"unchecked""rawtypes"})
405     static Object read(final ObjectInput in)
406         throws IOException, ClassNotFoundException
407     {
408         final int length = readInt(in);
409         final MSeq chromosomes = MSeq.ofLength(length);
410         for (int i = 0; i < length; ++i) {
411             chromosomes.set(i, in.readObject());
412         }
413 
414         return new Genotype(chromosomes.asISeq());
415     }
416 
417 }