Phenotype.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-4.1.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  * @implSpec
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.0
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      @throws NullPointerException if one of the arguments is {@code null}.
091      @throws IllegalArgumentException if the given {@code generation} is
092      *         {@code < 0}.
093      */
094     private Phenotype(
095         final Genotype<G> genotype,
096         final long generation,
097         final Function<? super Genotype<G>, ? extends C> function,
098         final Function<? super C, ? extends C> scaler
099     ) {
100         _genotype = requireNonNull(genotype, "Genotype");
101         _function = requireNonNull(function, "Fitness function");
102         _scaler = requireNonNull(scaler, "Fitness scaler");
103         if (generation < 0) {
104             throw new IllegalArgumentException(format(
105                 "Generation must not < 0 and was %s.", generation
106             ));
107         }
108         _generation = generation;
109 
110         _rawFitness = Lazy.of(() -> _function.apply(_genotype));
111         _fitness = Lazy.of(() -> _scaler.apply(_rawFitness.get()));
112     }
113 
114     /**
115      * This method returns a copy of the {@code Genotype}, to guarantee a
116      * immutable class.
117      *
118      @return the cloned {@code Genotype} of this {@code Phenotype}.
119      @throws NullPointerException if one of the arguments is {@code null}.
120      */
121     public Genotype<G> getGenotype() {
122         return _genotype;
123     }
124 
125     /**
126      * Evaluates the (raw) fitness values and caches it so the fitness calculation
127      * is performed only once.
128      *
129      @return this phenotype, for method chaining.
130      */
131     public Phenotype<G, C> evaluate() {
132         getFitness();
133         return this;
134     }
135 
136     /**
137      * This method simply calls the {@link #evaluate()} method. The purpose of
138      * this method is to have a simple way for concurrent fitness calculation
139      * for expensive fitness values.
140      */
141     @Override
142     public void run() {
143         evaluate();
144     }
145 
146     /**
147      * Return the fitness function used by this phenotype to calculate the
148      * (raw) fitness value.
149      *
150      @return the fitness function.
151      */
152     public Function<? super Genotype<G>, ? extends C> getFitnessFunction() {
153         return _function;
154     }
155 
156     /**
157      * Return the fitness scaler used by this phenotype to scale the <i>raw</i>
158      * fitness.
159      *
160      @return the fitness scaler.
161      */
162     public Function<? super C, ? extends C> getFitnessScaler() {
163         return _scaler;
164     }
165 
166     /**
167      * Return the fitness value of this {@code Phenotype}.
168      *
169      @return The fitness value of this {@code Phenotype}.
170      */
171     public C getFitness() {
172         return _fitness.get();
173     }
174 
175     /**
176      * Return the raw fitness (before scaling) of the phenotype.
177      *
178      @return The raw fitness (before scaling) of the phenotype.
179      */
180     public C getRawFitness() {
181         return _rawFitness.get();
182     }
183 
184     /**
185      * Return the generation this {@link Phenotype} was created.
186      *
187      @return The generation this {@link Phenotype} was created.
188      */
189     public long getGeneration() {
190         return _generation;
191     }
192 
193     /**
194      * Return the age of this phenotype depending on the given current generation.
195      *
196      @param currentGeneration the current generation evaluated by the GA.
197      @return the age of this phenotype:
198      *          {@code currentGeneration - this.getGeneration()}.
199      */
200     public long getAge(final long currentGeneration) {
201         return currentGeneration - _generation;
202     }
203 
204     /**
205      * Test whether this phenotype is valid. The phenotype is valid if its
206      {@link Genotype} is valid.
207      *
208      @return true if this phenotype is valid, false otherwise.
209      */
210     @Override
211     public boolean isValid() {
212         return _genotype.isValid();
213     }
214 
215     @Override
216     public int compareTo(final Phenotype<G, C> pt) {
217         return getFitness().compareTo(pt.getFitness());
218     }
219 
220     @Override
221     public int hashCode() {
222         int hash = 17;
223         hash += 31*_generation + 37;
224         hash += 31*Objects.hashCode(getFitness()) 37;
225         hash += 31*Objects.hashCode(getRawFitness()) 37;
226         hash += 31*_genotype.hashCode() 37;
227         return hash;
228     }
229 
230     @Override
231     public boolean equals(final Object obj) {
232         return obj == this ||
233             obj instanceof Phenotype<?, ?> &&
234             Objects.equals(getFitness()((Phenotype<?, ?>obj).getFitness()) &&
235             Objects.equals(getRawFitness()((Phenotype<?, ?>)obj).getRawFitness()) &&
236             Objects.equals(_genotype, ((Phenotype<?, ?>)obj)._genotype&&
237             _generation == ((Phenotype<?, ?>)obj)._generation;
238     }
239 
240     @Override
241     public String toString() {
242         return _genotype + " --> " + getFitness();
243     }
244 
245     /**
246      * Create a new {@code Phenotype} with a different {@code Genotype} but the
247      * same {@code generation}, fitness {@code function} and fitness
248      * {@code scaler}.
249      *
250      @since 3.1
251      *
252      @param genotype the new genotype
253      @return a new {@code phenotype} with replaced {@code genotype}
254      @throws NullPointerException if the given {@code genotype} is {@code null}.
255      */
256     public Phenotype<G, C> newInstance(final Genotype<G> genotype) {
257         return of(genotype, _generation, _function, _scaler);
258     }
259 
260     /**
261      * Factory method for creating a new {@link Phenotype} with the same
262      {@link Function} and age as this {@link Phenotype}.
263      *
264      @since 3.5
265      *
266      @param genotype the new genotype of the new phenotype.
267      @param generation date of birth (generation) of the new phenotype.
268      @return New {@link Phenotype} with the same fitness {@link Function}.
269      @throws NullPointerException if the {@code genotype} is {@code null}.
270      */
271     public Phenotype<G, C> newInstance(
272         final Genotype<G> genotype,
273         final long generation
274     ) {
275         return of(genotype, generation, _function, _scaler);
276     }
277 
278     /**
279      * Return a new phenotype with the the genotype of this and with new
280      * fitness function, fitness scaler and generation.
281      *
282      @param generation the generation of the new phenotype.
283      @param function the (new) fitness scaler of the created phenotype.
284      @param scaler the (new) fitness scaler of the created phenotype
285      @return a new phenotype with the given values.
286      @throws NullPointerException if one of the values is {@code null}.
287      @throws IllegalArgumentException if the given {@code generation} is
288      *         {@code < 0}.
289      */
290     public Phenotype<G, C> newInstance(
291         final long generation,
292         final Function<? super Genotype<G>, ? extends C> function,
293         final Function<? super C, ? extends C> scaler
294     ) {
295         return of(_genotype, generation, function, scaler);
296     }
297 
298     /**
299      * Return a new phenotype with the the genotype of this and with new
300      * fitness function and generation.
301      *
302      @param generation the generation of the new phenotype.
303      @param function the (new) fitness scaler of the created phenotype.
304      @return a new phenotype with the given values.
305      @throws NullPointerException if one of the values is {@code null}.
306      @throws IllegalArgumentException if the given {@code generation} is
307      *         {@code < 0}.
308      */
309     public Phenotype<G, C> newInstance(
310         final long generation,
311         final Function<? super Genotype<G>, ? extends C> function
312     ) {
313         return of(_genotype, generation, function, a -> a);
314     }
315 
316     /**
317      * The {@code Genotype} is copied to guarantee an immutable class. Only
318      * the age of the {@code Phenotype} can be incremented.
319      *
320      @param <G> the gene type of the chromosome
321      @param <C> the fitness value type
322      @param genotype the genotype of this phenotype.
323      @param generation the current generation of the generated phenotype.
324      @param function the fitness function of this phenotype.
325      @return a new phenotype from the given parameters
326      @throws NullPointerException if one of the arguments is {@code null}.
327      @throws IllegalArgumentException if the given {@code generation} is
328      *         {@code < 0}.
329      */
330     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
331     Phenotype<G, C> of(
332         final Genotype<G> genotype,
333         final long generation,
334         final Function<? super Genotype<G>, C> function
335     ) {
336         return Phenotype.<G, C>of(
337             genotype,
338             generation,
339             function,
340             function instanceof Serializable
341                 (Function<? super C, ? extends C> & Serializable)a -> a
342                 : a -> a
343         );
344     }
345 
346     /**
347      * Create a new phenotype from the given arguments.
348      *
349      @param <G> the gene type of the chromosome
350      @param <C> the fitness value type
351      @param genotype the genotype of this phenotype.
352      @param generation the current generation of the generated phenotype.
353      @param function the fitness function of this phenotype.
354      @param scaler the fitness scaler.
355      @return a new phenotype object
356      @throws NullPointerException if one of the arguments is {@code null}.
357      @throws IllegalArgumentException if the given {@code generation} is
358      *         {@code < 0}.
359      */
360     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
361     Phenotype<G, C> of(
362         final Genotype<G> genotype,
363         final long generation,
364         final Function<? super Genotype<G>, ? extends C> function,
365         final Function<? super C, ? extends C> scaler
366     ) {
367         return new Phenotype<>(
368             genotype,
369             generation,
370             function,
371             scaler
372         );
373     }
374 
375 
376     /* *************************************************************************
377      *  Java object serialization
378      * ************************************************************************/
379 
380     private void writeObject(final ObjectOutputStream out)
381         throws IOException
382     {
383         out.defaultWriteObject();
384         out.writeLong(getGeneration());
385         out.writeObject(getGenotype());
386         out.writeObject(getFitness());
387         out.writeObject(getRawFitness());
388     }
389 
390     @SuppressWarnings("unchecked")
391     private void readObject(final ObjectInputStream in)
392         throws IOException, ClassNotFoundException
393     {
394         in.defaultReadObject();
395         reflect.setField(this, "_generation", in.readLong());
396         reflect.setField(this, "_genotype", in.readObject());
397         reflect.setField(this, "_fitness", Lazy.ofValue(in.readObject()));
398         reflect.setField(this, "_rawFitness", Lazy.ofValue(in.readObject()));
399 
400         reflect.setField(this, "_function", Function.identity());
401         reflect.setField(this, "_scaler", Function.identity());
402     }
403 
404 }