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::isValid) ? 1 : 0);
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(1 + 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 out) throws 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 }
|