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