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