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