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 java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 import static org.jenetics.internal.util.Equality.eq;
025
026 import java.io.Serializable;
027 import java.util.function.Function;
028
029 import javax.xml.bind.annotation.XmlAccessType;
030 import javax.xml.bind.annotation.XmlAccessorType;
031 import javax.xml.bind.annotation.XmlAttribute;
032 import javax.xml.bind.annotation.XmlElement;
033 import javax.xml.bind.annotation.XmlRootElement;
034 import javax.xml.bind.annotation.XmlType;
035 import javax.xml.bind.annotation.adapters.XmlAdapter;
036 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
037
038 import org.jenetics.internal.util.Hash;
039 import org.jenetics.internal.util.jaxb;
040
041 import org.jenetics.util.Verifiable;
042
043 /**
044 * The {@code Phenotype} consists of a {@link Genotype} plus a fitness
045 * {@link Function}, where the fitness {@link Function} represents the
046 * environment where the {@link Genotype} lives.
047 * This class implements the {@link Comparable} interface, to define a natural
048 * order between two {@code Phenotype}s. The natural order of the
049 * {@code Phenotypes} is defined by its fitness value (given by the
050 * fitness {@link Function}. The {@code Phenotype} is immutable and therefore
051 * can't be changed after creation.
052 * <p>
053 * The evaluation of the fitness function is performed lazily. Either by calling
054 * one of the fitness accessors ({@link #getFitness()} or {@link #getRawFitness()})
055 * of through the <i>evaluation</i> methods {@link #run()} or {@link #evaluate()}.
056 * Since the {@code Phenotype} implements the {@link Runnable} interface, it is
057 * easily possible to perform the fitness function evaluation concurrently, by
058 * putting it into an {@link java.util.concurrent.ExecutorService}.
059 *
060 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
061 * @since 1.0
062 * @version 3.1
063 */
064 @XmlJavaTypeAdapter(Phenotype.Model.Adapter.class)
065 public final class Phenotype<
066 G extends Gene<?, G>,
067 C extends Comparable<? super C>
068 >
069 implements
070 Comparable<Phenotype<G, C>>,
071 Verifiable,
072 Serializable,
073 Runnable
074 {
075 private static final long serialVersionUID = 4L;
076
077 private final Genotype<G> _genotype;
078
079 private final Function<? super Genotype<G>, ? extends C> _function;
080 private final Function<? super C, ? extends C> _scaler;
081
082 private final long _generation;
083
084 // Storing the fitness value for lazy evaluation.
085 private transient volatile boolean _evaluated = false;
086 private C _rawFitness = null;
087 private C _fitness = null;
088
089 /**
090 * Create a new phenotype from the given arguments.
091 *
092 * @param genotype the genotype of this phenotype.
093 * @param generation the current generation of the generated phenotype.
094 * @param function the fitness function of this phenotype.
095 * @param scaler the fitness scaler.
096 * @throws NullPointerException if one of the arguments is {@code null}.
097 * @throws IllegalArgumentException if the given {@code generation} is
098 * {@code < 0}.
099 */
100 private Phenotype(
101 final Genotype<G> genotype,
102 final long generation,
103 final Function<? super Genotype<G>, ? extends C> function,
104 final Function<? super C, ? extends C> scaler
105 ) {
106 _genotype = requireNonNull(genotype, "Genotype");
107 _function = requireNonNull(function, "Fitness function");
108 _scaler = requireNonNull(scaler, "Fitness scaler");
109 if (generation < 0) {
110 throw new IllegalArgumentException(format(
111 "Generation must not < 0 and was %s.", generation
112 ));
113 }
114 _generation = generation;
115 }
116
117 /**
118 * This method returns a copy of the {@code Genotype}, to guarantee a
119 * immutable class.
120 *
121 * @return the cloned {@code Genotype} of this {@code Phenotype}.
122 * @throws NullPointerException if one of the arguments is {@code null}.
123 */
124 public Genotype<G> getGenotype() {
125 return _genotype;
126 }
127
128 /**
129 * Evaluates the (raw) fitness values and caches it so the fitness calculation
130 * is performed only once.
131 *
132 * @return this phenotype, for method chaining.
133 */
134 public Phenotype<G, C> evaluate() {
135 if (!_evaluated) {
136 eval();
137 }
138 return this;
139 }
140
141 private synchronized void eval() {
142 if (!_evaluated) {
143 if (_rawFitness == null) _rawFitness = _function.apply(_genotype);
144 if (_fitness == null) _fitness = _scaler.apply(_rawFitness);
145 _evaluated = true;
146 }
147 }
148
149 /**
150 * This method simply calls the {@link #evaluate()} method. The purpose of
151 * this method is to have a simple way for concurrent fitness calculation
152 * for expensive fitness values.
153 */
154 @Override
155 public void run() {
156 evaluate();
157 }
158
159 /**
160 * Return the fitness function used by this phenotype to calculate the
161 * (raw) fitness value.
162 *
163 * @return the fitness function.
164 */
165 public Function<? super Genotype<G>, ? extends C> getFitnessFunction() {
166 return _function;
167 }
168
169 /**
170 * Return the fitness scaler used by this phenotype to scale the <i>raw</i>
171 * fitness.
172 *
173 * @return the fitness scaler.
174 */
175 public Function<? super C, ? extends C> getFitnessScaler() {
176 return _scaler;
177 }
178
179 /**
180 * Return the fitness value of this {@code Phenotype}.
181 *
182 * @return The fitness value of this {@code Phenotype}.
183 */
184 public C getFitness() {
185 evaluate();
186 return _fitness;
187 }
188
189 /**
190 * Return the raw fitness (before scaling) of the phenotype.
191 *
192 * @return The raw fitness (before scaling) of the phenotype.
193 */
194 public C getRawFitness() {
195 evaluate();
196 return _rawFitness;
197 }
198
199 /**
200 * Return the generation this {@link Phenotype} was created.
201 *
202 * @return The generation this {@link Phenotype} was created.
203 */
204 public long getGeneration() {
205 return _generation;
206 }
207
208 /**
209 * Return the age of this phenotype depending on the given current generation.
210 *
211 * @param currentGeneration the current generation evaluated by the GA.
212 * @return the age of this phenotype:
213 * {@code currentGeneration - this.getGeneration()}.
214 */
215 public long getAge(final long currentGeneration) {
216 return currentGeneration - _generation;
217 }
218
219 /**
220 * Test whether this phenotype is valid. The phenotype is valid if its
221 * {@link Genotype} is valid.
222 *
223 * @return true if this phenotype is valid, false otherwise.
224 */
225 @Override
226 public boolean isValid() {
227 return _genotype.isValid();
228 }
229
230 @Override
231 public int compareTo(final Phenotype<G, C> pt) {
232 return getFitness().compareTo(pt.getFitness());
233 }
234
235 @Override
236 public int hashCode() {
237 return Hash.of(getClass())
238 .and(_generation)
239 .and(getFitness())
240 .and(getRawFitness())
241 .and(_genotype).value();
242 }
243
244 @Override
245 public boolean equals(final Object obj) {
246 return obj instanceof Phenotype<?, ?> &&
247 eq(getFitness(), ((Phenotype<?, ?>)obj).getFitness()) &&
248 eq(getRawFitness(), ((Phenotype<?, ?>)obj).getRawFitness()) &&
249 eq(_genotype, ((Phenotype<?, ?>)obj)._genotype) &&
250 eq(_generation, ((Phenotype<?, ?>)obj)._generation);
251 }
252
253 @Override
254 public String toString() {
255 return _genotype + " --> " + getFitness();
256 }
257
258 /**
259 * Create a new {@code Phenotype} with a different {@code Genotype} but the
260 * same {@code generation}, fitness {@code function} and fitness
261 * {@code scaler}.
262 *
263 * @since 3.1
264 *
265 * @param genotype the new genotype
266 * @return a new {@code phenotype} with replaced {@code genotype}
267 * @throws NullPointerException if the given {@code genotype} is {@code null}.
268 */
269 public Phenotype<G, C> newInstance(final Genotype<G> genotype) {
270 return of(genotype, _generation, _function, _scaler);
271 }
272
273 /**
274 * Factory method for creating a new {@link Phenotype} with the same
275 * {@link Function} and age as this {@link Phenotype}.
276 *
277 * @since 3.5
278 *
279 * @param genotype the new genotype of the new phenotype.
280 * @param generation date of birth (generation) of the new phenotype.
281 * @return New {@link Phenotype} with the same fitness {@link Function}.
282 * @throws NullPointerException if the {@code genotype} is {@code null}.
283 */
284 public Phenotype<G, C> newInstance(
285 final Genotype<G> genotype,
286 final long generation
287 ) {
288 return of(genotype, generation, _function, _scaler);
289 }
290
291 /**
292 * Return a new phenotype with the the genotype of this and with new
293 * fitness function, fitness scaler and generation.
294 *
295 * @param generation the generation of the new phenotype.
296 * @param function the (new) fitness scaler of the created phenotype.
297 * @param scaler the (new) fitness scaler of the created phenotype
298 * @return a new phenotype with the given values.
299 * @throws NullPointerException if one of the values is {@code null}.
300 * @throws IllegalArgumentException if the given {@code generation} is
301 * {@code < 0}.
302 */
303 public Phenotype<G, C> newInstance(
304 final long generation,
305 final Function<? super Genotype<G>, ? extends C> function,
306 final Function<? super C, ? extends C> scaler
307 ) {
308 return of(_genotype, generation, function, scaler);
309 }
310
311 /**
312 * Return a new phenotype with the the genotype of this and with new
313 * fitness function and generation.
314 *
315 * @param generation the generation of the new phenotype.
316 * @param function the (new) fitness scaler of the created phenotype.
317 * @return a new phenotype with the given values.
318 * @throws NullPointerException if one of the values is {@code null}.
319 * @throws IllegalArgumentException if the given {@code generation} is
320 * {@code < 0}.
321 */
322 public Phenotype<G, C> newInstance(
323 final long generation,
324 final Function<? super Genotype<G>, ? extends C> function
325 ) {
326 return of(_genotype, generation, function, a -> a);
327 }
328
329 /**
330 * The {@code Genotype} is copied to guarantee an immutable class. Only
331 * the age of the {@code Phenotype} can be incremented.
332 *
333 * @param <G> the gene type of the chromosome
334 * @param <C> the fitness value type
335 * @param genotype the genotype of this phenotype.
336 * @param generation the current generation of the generated phenotype.
337 * @param function the fitness function of this phenotype.
338 * @return a new phenotype from the given parameters
339 * @throws NullPointerException if one of the arguments is {@code null}.
340 * @throws IllegalArgumentException if the given {@code generation} is
341 * {@code < 0}.
342 */
343 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
344 Phenotype<G, C> of(
345 final Genotype<G> genotype,
346 final long generation,
347 final Function<? super Genotype<G>, C> function
348 ) {
349 return of(
350 genotype,
351 generation,
352 function,
353 function instanceof Serializable
354 ? (Function<? super C, ? extends C> & Serializable)a -> a
355 : a -> a
356 );
357 }
358
359 /**
360 * Create a new phenotype from the given arguments.
361 *
362 * @param <G> the gene type of the chromosome
363 * @param <C> the fitness value type
364 * @param genotype the genotype of this phenotype.
365 * @param generation the current generation of the generated phenotype.
366 * @param function the fitness function of this phenotype.
367 * @param scaler the fitness scaler.
368 * @return a new phenotype object
369 * @throws NullPointerException if one of the arguments is {@code null}.
370 * @throws IllegalArgumentException if the given {@code generation} is
371 * {@code < 0}.
372 */
373 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
374 Phenotype<G, C> of(
375 final Genotype<G> genotype,
376 final long generation,
377 final Function<? super Genotype<G>, ? extends C> function,
378 final Function<? super C, ? extends C> scaler
379 ) {
380 return new Phenotype<>(
381 genotype,
382 generation,
383 function,
384 scaler
385 );
386 }
387
388 /* *************************************************************************
389 * JAXB object serialization
390 * ************************************************************************/
391
392 @XmlRootElement(name = "phenotype")
393 @XmlType(name = "org.jenetics.Phenotype")
394 @XmlAccessorType(XmlAccessType.FIELD)
395 @SuppressWarnings({ "unchecked", "rawtypes" })
396 final static class Model {
397
398 @XmlAttribute(name = "generation", required = true)
399 public long generation;
400
401 @XmlElement(name = "genotype", required = true, nillable = false)
402 public Genotype.Model genotype;
403
404 @XmlElement(name = "fitness", required = true, nillable = false)
405 public Object fitness;
406
407 @XmlElement(name = "raw-fitness", required = true, nillable = false)
408 public Object rawFitness;
409
410 public final static class Adapter
411 extends XmlAdapter<Model, Phenotype>
412 {
413 @Override
414 public Model marshal(final Phenotype pt) throws Exception {
415 final Model m = new Model();
416 m.generation = pt.getGeneration();
417 m.genotype = Genotype.Model.ADAPTER.marshal(pt.getGenotype());
418 m.fitness = jaxb.marshal(pt.getFitness());
419 m.rawFitness = jaxb.marshal(pt.getRawFitness());
420 return m;
421 }
422
423 @Override
424 public Phenotype unmarshal(final Model m) throws Exception {
425 final Phenotype pt = new Phenotype(
426 Genotype.Model.ADAPTER.unmarshal(m.genotype),
427 m.generation,
428 Function.identity(),
429 Function.identity()
430 );
431 pt._fitness = (Comparable)m.fitness;
432 pt._rawFitness = (Comparable)m.rawFitness;
433 return pt;
434 }
435 }
436 }
437
438 }
|