001 /*
002 * Java Genetic Algorithm Library (jenetics-3.8.0).
003 * Copyright (c) 2007-2017 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
042 import org.jenetics.util.Factory;
043 import org.jenetics.util.ISeq;
044 import org.jenetics.util.MSeq;
045 import org.jenetics.util.Seq;
046 import org.jenetics.util.Verifiable;
047
048 /**
049 * The central class the GA is working with, is the {@code Genotype}. It is the
050 * structural representative of an individual. This class is the encoded problem
051 * solution with one to many {@link Chromosome}.
052 * <p>
053 * <img alt="Genotype" src="doc-files/Genotype.svg" width="400" height="252" >
054 * </p>
055 * The chromosomes of a genotype doesn't have to have necessarily the same size.
056 * It is only required that all genes are from the same type and the genes within
057 * a chromosome have the same constraints; e. g. the same min- and max values
058 * for number genes.
059 *
060 * <pre>{@code
061 * final Genotype<DoubleGene> genotype = Genotype.of(
062 * DoubleChromosome.of(0.0, 1.0, 8),
063 * DoubleChromosome.of(1.0, 2.0, 10),
064 * DoubleChromosome.of(0.0, 10.0, 9),
065 * DoubleChromosome.of(0.1, 0.9, 5)
066 * );
067 * }</pre>
068 * The code snippet above creates a genotype with the same structure as shown in
069 * the figure above. In this example the {@link DoubleGene} has been chosen as
070 * gene type.
071 *
072 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
073 * @since 1.0
074 * @version 3.0
075 */
076 @XmlJavaTypeAdapter(Genotype.Model.Adapter.class)
077 public final class Genotype<G extends Gene<?, G>>
078 implements
079 Factory<Genotype<G>>,
080 Iterable<Chromosome<G>>,
081 Verifiable,
082 Serializable
083 {
084 private static final long serialVersionUID = 3L;
085
086 private final ISeq<Chromosome<G>> _chromosomes;
087 private final int _ngenes;
088
089 //Caching isValid value.
090 private volatile Boolean _valid = null;
091
092 private Genotype(
093 final ISeq<? extends Chromosome<G>> chromosomes,
094 final int ngenes
095 ) {
096 if (chromosomes.isEmpty()) {
097 throw new IllegalArgumentException("No chromosomes given.");
098 }
099
100 _chromosomes = ISeq.upcast(chromosomes);
101 _ngenes = ngenes;
102 }
103
104 /**
105 * Create a new Genotype from a given sequence of {@code Chromosomes}.
106 *
107 * @param chromosomes The {@code Chromosome} array the {@code Genotype}
108 * consists of.
109 * @throws NullPointerException if {@code chromosomes} is null or one of its
110 * element.
111 * @throws IllegalArgumentException if {@code chromosome.length == 0}.
112 */
113 Genotype(final ISeq<? extends Chromosome<G>> chromosomes) {
114 this(chromosomes, ngenes(chromosomes));
115 }
116
117 private static int ngenes(final Seq<? extends Chromosome<?>> chromosomes) {
118 return chromosomes.stream()
119 .mapToInt(c -> c.length())
120 .sum();
121 }
122
123 /**
124 * Return the chromosome at the given index. It is guaranteed, that the
125 * returned chromosome is not null.
126 *
127 * @param index Chromosome index.
128 * @return The Chromosome.
129 * @throws IndexOutOfBoundsException if
130 * {@code (index < 0 || index >= _length)}.
131 */
132 public Chromosome<G> getChromosome(final int index) {
133 assert _chromosomes != null;
134 assert _chromosomes.get(index) != null;
135
136 return _chromosomes.get(index);
137 }
138
139 /**
140 * Return the first chromosome. This is a shortcut for
141 * <pre>{@code
142 * final Genotype<DoubleGene>; gt = ...
143 * final Chromosome<DoubleGene> chromosome = gt.getChromosome(0);
144 * }</pre>
145 *
146 * @return The first chromosome.
147 */
148 public Chromosome<G> getChromosome() {
149 assert _chromosomes != null;
150 assert _chromosomes.get(0) != null;
151
152 return _chromosomes.get(0);
153 }
154
155 /**
156 * Return the first {@link Gene} of the first {@link Chromosome} of this
157 * {@code Genotype}. This is a shortcut for
158 * <pre>{@code
159 * final Genotype<DoubleGene> gt = ...
160 * final DoubleGene gene = gt.getChromosome(0).getGene(0);
161 * }</pre>
162 *
163 * @return the first {@link Gene} of the first {@link Chromosome} of this
164 * {@code Genotype}.
165 */
166 public G getGene() {
167 assert _chromosomes != null;
168 assert _chromosomes.get(0) != null;
169
170 return _chromosomes.get(0).getGene();
171 }
172
173 /**
174 * Return the gene from the given chromosome- and gene index. This is a
175 * shortcut for {@code gt.getChromosome(chromosomeIndex).getGene(geneIndex)}.
176 *
177 * @since 3.0
178 *
179 * @param chromosomeIndex the chromosome index
180 * @param geneIndex the gene index within the chromosome
181 * @return the gene with the given indexes
182 * @throws IndexOutOfBoundsException if the given indexes are not within the
183 * allowed range
184 */
185 public G get(final int chromosomeIndex, final int geneIndex) {
186 return getChromosome(chromosomeIndex).getGene(geneIndex);
187 }
188
189 public ISeq<Chromosome<G>> toSeq() {
190 return _chromosomes;
191 }
192
193 @Override
194 public Iterator<Chromosome<G>> iterator() {
195 return _chromosomes.iterator();
196 }
197
198 /**
199 * Returns a sequential {@code Stream} of chromosomes with this genotype as
200 * its source.
201 *
202 * @since 3.4
203 *
204 * @return a sequential {@code Stream} of chromosomes
205 */
206 public Stream<Chromosome<G>> stream() {
207 return _chromosomes.stream();
208 }
209
210 /**
211 * Getting the number of chromosomes of this genotype.
212 *
213 * @return number of chromosomes.
214 */
215 public int length() {
216 return _chromosomes.length();
217 }
218
219 /**
220 * Return the number of genes this genotype consists of. This is the sum of
221 * the number of genes of the genotype chromosomes.
222 *
223 * @return Return the number of genes this genotype consists of.
224 */
225 public int getNumberOfGenes() {
226 return _ngenes;
227 }
228
229 /**
230 * Test if this genotype is valid. A genotype is valid if all its
231 * {@link Chromosome}s are valid.
232 *
233 * @return true if this genotype is valid, false otherwise.
234 */
235 @Override
236 public boolean isValid() {
237 Boolean valid = _valid;
238 if (valid == null) {
239 valid = _chromosomes.forAll(Verifiable::isValid);
240 _valid = valid;
241 }
242
243 return _valid;
244 }
245
246 /**
247 * Return a new, random genotype by creating new, random chromosomes (calling
248 * the {@link Chromosome#newInstance()} method) from the chromosomes of this
249 * genotype.
250 */
251 @Override
252 public Genotype<G> newInstance() {
253 return new Genotype<>(_chromosomes.map(Factory::newInstance), _ngenes);
254 }
255
256 Genotype<G> newInstance(final ISeq<Chromosome<G>> chromosomes) {
257 return new Genotype<>(chromosomes, _ngenes);
258 }
259
260 @Override
261 public int hashCode() {
262 return Hash.of(getClass()).and(_chromosomes).value();
263 }
264
265 @Override
266 public boolean equals(final Object obj) {
267 return obj instanceof Genotype<?> &&
268 eq(_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 * JAXB object serialization
348 * ************************************************************************/
349
350 @XmlRootElement(name = "genotype")
351 @XmlType(name = "org.jenetics.Genotype")
352 @XmlAccessorType(XmlAccessType.FIELD)
353 @SuppressWarnings({"unchecked", "rawtypes"})
354 static final class Model {
355
356 @XmlAttribute(name = "length", required = true)
357 public int length;
358
359 @XmlAttribute(name = "ngenes", required = true)
360 public int ngenes;
361
362 @XmlElement(name = "chromosome", required = true, nillable = false)
363 public List chromosomes;
364
365 public static final class Adapter
366 extends XmlAdapter<Model, Genotype>
367 {
368 @Override
369 public Model marshal(final Genotype gt) throws Exception {
370 final Model model = new Model();
371 model.length = gt.length();
372 model.ngenes = gt.getNumberOfGenes();
373 model.chromosomes = gt.toSeq()
374 .map(jaxb.Marshaller(gt.getChromosome()))
375 .asList();
376
377 return model;
378 }
379
380 @Override
381 public Genotype unmarshal(final Model model) throws Exception {
382 final ISeq chs = (ISeq)model.chromosomes.stream()
383 .map(jaxb.Unmarshaller(model.chromosomes.get(0)))
384 .collect(toISeq());
385
386 return new Genotype(chs, model.ngenes);
387 }
388 }
389
390 public static final Adapter ADAPTER = new Adapter();
391 }
392 }
|