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