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