Phenotype.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.2.0).
003  * Copyright (c) 2007-2020 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 import static io.jenetics.internal.util.SerialIO.readLong;
026 import static io.jenetics.internal.util.SerialIO.writeLong;
027 
028 import java.io.IOException;
029 import java.io.InvalidObjectException;
030 import java.io.ObjectInput;
031 import java.io.ObjectInputStream;
032 import java.io.ObjectOutput;
033 import java.io.Serializable;
034 import java.util.NoSuchElementException;
035 import java.util.Objects;
036 import java.util.Optional;
037 import java.util.function.Function;
038 
039 import io.jenetics.util.Verifiable;
040 
041 /**
042  * The {@code Phenotype} consists of a {@link Genotype}, the current generation
043  * and an optional fitness value. Once the fitness has been evaluated, a new
044  * {@code Phenotype} instance, with the calculated fitness, can be created with
045  * the {@link #withFitness(Comparable)}.
046  *
047  @see Genotype
048  *
049  * @implNote
050  * This class is immutable and thread-safe.
051  *
052  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
053  @since 1.0
054  @version 5.2
055  */
056 public final class Phenotype<
057     extends Gene<?, G>,
058     extends Comparable<? super C>
059 >
060     implements
061         Comparable<Phenotype<G, C>>,
062         Verifiable,
063         Serializable
064 {
065     private static final long serialVersionUID = 6L;
066 
067     private final Genotype<G> _genotype;
068     private final long _generation;
069     private final C _fitness;
070 
071     /**
072      * Create a new phenotype from the given arguments.
073      *
074      @param genotype the genotype of this phenotype.
075      @param generation the current generation of the generated phenotype.
076      @param fitness the known fitness of the phenotype, maybe {@code null}
077      @throws NullPointerException if the genotype is {@code null}.
078      @throws IllegalArgumentException if the given {@code generation} is
079      *         {@code < 0}.
080      */
081     private Phenotype(
082         final Genotype<G> genotype,
083         final long generation,
084         final C fitness
085     ) {
086         if (generation < 0) {
087             throw new IllegalArgumentException(format(
088                 "Generation must not < 0 and was %s.", generation
089             ));
090         }
091 
092         _genotype = requireNonNull(genotype, "Genotype");
093         _generation = generation;
094         _fitness = fitness;
095     }
096 
097     /**
098      * Applies the given fitness function to the underlying genotype and return
099      * a new phenotype with the (newly) evaluated fitness function, if not
100      * already evaluated. If the fitness value is already set {@code this}
101      * phenotype is returned.
102      *
103      @since 5.0
104      *
105      @param ff the fitness function
106      @return a evaluated phenotype or {@code this} if the fitness value is
107      *         already set
108      @throws NullPointerException if the given fitness function is {@code null}
109      */
110     public Phenotype<G, C>
111     eval(final Function<? super Genotype<G>, ? extends C> ff) {
112         requireNonNull(ff);
113         return _fitness == null ? withFitness(ff.apply(_genotype)) this;
114     }
115 
116     /**
117      * This method returns a copy of the {@code Genotype}, to guarantee a
118      * immutable class.
119      *
120      @return the cloned {@code Genotype} of this {@code Phenotype}.
121      @throws NullPointerException if one of the arguments is {@code null}.
122      */
123     public Genotype<G> genotype() {
124         return _genotype;
125     }
126 
127     /**
128      * This method returns a copy of the {@code Genotype}, to guarantee a
129      * immutable class.
130      *
131      @return the cloned {@code Genotype} of this {@code Phenotype}.
132      @throws NullPointerException if one of the arguments is {@code null}.
133      @deprecated Use {@link #genotype()} instead
134      */
135     @Deprecated
136     public Genotype<G> getGenotype() {
137         return _genotype;
138     }
139 
140     /**
141      * A phenotype instance can be created with or without fitness value.
142      * Initially, the phenotype is created without fitness value. The
143      * fitness evaluation strategy is responsible for creating phenotypes with
144      * fitness value assigned.
145      *
146      @since 4.2
147      *
148      @see #nonEvaluated()
149      *
150      @return {@code true} is this phenotype has an fitness value assigned,
151      *         {@code false} otherwise
152      */
153     public boolean isEvaluated() {
154         return _fitness != null;
155     }
156 
157     /**
158      * A phenotype instance can be created with or without fitness value.
159      * Initially, the phenotype is created without fitness value. The
160      * fitness evaluation strategy is responsible for creating phenotypes with
161      * fitness value assigned.
162      *
163      @since 5.0
164      *
165      @see #isEvaluated()
166      *
167      @return {@code false} is this phenotype has an fitness value assigned,
168      *         {@code true} otherwise
169      */
170     public boolean nonEvaluated() {
171         return _fitness == null;
172     }
173 
174     /**
175      * Return the fitness value of this {@code Phenotype}.
176      *
177      @see #fitnessOptional()
178      *
179      @return The fitness value of this {@code Phenotype}.
180      @throws NoSuchElementException if {@link #isEvaluated()} returns
181      *         {@code false}
182      */
183     public C fitness() {
184         if (_fitness == null) {
185             throw new NoSuchElementException(
186                 "Phenotype has no assigned fitness value."
187             );
188         }
189 
190         return _fitness;
191     }
192 
193     /**
194      * Return the fitness value of this {@code Phenotype}.
195      *
196      @see #fitnessOptional()
197      *
198      @return The fitness value of this {@code Phenotype}.
199      @throws NoSuchElementException if {@link #isEvaluated()} returns
200      *         {@code false}
201      @deprecated Use {@link #fitness()} instead
202      */
203     @Deprecated
204     public C getFitness() {
205         return fitness();
206     }
207 
208     /**
209      * Return the fitness value of {@code this} phenotype, or
210      {@link Optional#empty()} if not evaluated yet.
211      *
212      @since 5.0
213      *
214      @see #fitness()
215      *
216      @return the fitness value
217      */
218     public Optional<C> fitnessOptional() {
219         return Optional.ofNullable(_fitness);
220     }
221 
222     /**
223      * Return the generation this {@link Phenotype} was created.
224      *
225      @see #age(long)
226      *
227      @return The generation this {@link Phenotype} was created.
228      */
229     public long generation() {
230         return _generation;
231     }
232 
233     /**
234      * Return the generation this {@link Phenotype} was created.
235      *
236      @see #age(long)
237      *
238      @return The generation this {@link Phenotype} was created.
239      @deprecated Use {@link #generation()} instead
240      */
241     @Deprecated
242     public long getGeneration() {
243         return _generation;
244     }
245 
246     /**
247      * Return the age of this phenotype depending on the given current generation.
248      *
249      @see #generation()
250      *
251      @param currentGeneration the current generation evaluated by the GA.
252      @return the age of this phenotype:
253      *          {@code currentGeneration - this.getGeneration()}.
254      */
255     public long age(final long currentGeneration) {
256         return currentGeneration - _generation;
257     }
258 
259     /**
260      * Return the age of this phenotype depending on the given current generation.
261      *
262      @see #generation()
263      *
264      @param currentGeneration the current generation evaluated by the GA.
265      @return the age of this phenotype:
266      *          {@code currentGeneration - this.getGeneration()}.
267      @deprecated Use {@link #age(long)} instead
268      */
269     @Deprecated
270     public long getAge(final long currentGeneration) {
271         return age(currentGeneration);
272     }
273 
274     /**
275      * Test whether this phenotype is valid. The phenotype is valid if its
276      {@link Genotype} is valid.
277      *
278      @return true if this phenotype is valid, false otherwise.
279      */
280     @Override
281     public boolean isValid() {
282         return _genotype.isValid();
283     }
284 
285     @Override
286     public int compareTo(final Phenotype<G, C> pt) {
287         if (isEvaluated()) {
288             return pt.isEvaluated() ? fitness().compareTo(pt.fitness()) 1;
289         else {
290             return pt.isEvaluated() ? -0;
291         }
292     }
293 
294     @Override
295     public int hashCode() {
296         return hash(_generation, hash(_fitness, hash(_genotype)));
297     }
298 
299     @Override
300     public boolean equals(final Object obj) {
301         return obj == this ||
302             obj instanceof Phenotype &&
303             _generation == ((Phenotype)obj)._generation &&
304             Objects.equals(_fitness, ((Phenotype)obj)._fitness&&
305             Objects.equals(_genotype, ((Phenotype)obj)._genotype);
306     }
307 
308     @Override
309     public String toString() {
310         return _genotype + " -> " + _fitness;
311     }
312 
313     /**
314      * Return a new {@code Phenotype} object with the given <em>raw</em> fitness
315      * value. The returned phenotype is automatically <em>evaluated</em>:
316      * {@code isEvaluated() == true}
317      *
318      @since 4.2
319      *
320      @param fitness the phenotypes fitness value
321      @throws NullPointerException if the given {@code fitness} value is
322      *         {@code null}
323      @return a new phenotype with the given fitness value
324      */
325     public Phenotype<G, C> withFitness(final C fitness) {
326         return Phenotype.of(
327             _genotype,
328             _generation,
329             requireNonNull(fitness)
330         );
331     }
332 
333     /**
334      * Return a new {@code Phenotype} object with the given generation.
335      *
336      @since 5.0
337      *
338      @param generation the generation of the newly created phenotype
339      @return a new phenotype with the given generation
340      */
341     public Phenotype<G, C> withGeneration(final long generation) {
342         return Phenotype.of(
343             _genotype,
344             generation,
345             _fitness
346         );
347     }
348 
349 
350     /* *************************************************************************
351      *  Static factory methods.
352      * ************************************************************************/
353 
354     /**
355      * Create a new phenotype from the given arguments. The phenotype is created
356      * with a non assigned fitness function and the call of {@link #isEvaluated()}
357      * will return {@code false}.
358      *
359      @param <G> the gene type of the chromosome
360      @param <C> the fitness value type
361      @param genotype the genotype of this phenotype.
362      @param generation the current generation of the generated phenotype.
363      @return a new phenotype object
364      @throws NullPointerException if one of the arguments is {@code null}.
365      @throws IllegalArgumentException if the given {@code generation} is
366      *         {@code < 0}.
367      */
368     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
369     Phenotype<G, C> of(final Genotype<G> genotype, final long generation) {
370         return new Phenotype<>(
371             genotype,
372             generation,
373             null
374         );
375     }
376 
377     /**
378      * Create a new phenotype from the given arguments.
379      *
380      @param <G> the gene type of the chromosome
381      @param <C> the fitness value type
382      @param genotype the genotype of this phenotype.
383      @param generation the current generation of the generated phenotype.
384      @param fitness the known fitness of the phenotype.
385      @return a new phenotype object
386      @throws NullPointerException if one of the arguments is {@code null}.
387      @throws IllegalArgumentException if the given {@code generation} is
388      *         {@code < 0}.
389      */
390     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
391     Phenotype<G, C> of(
392         final Genotype<G> genotype,
393         final long generation,
394         final C fitness
395     ) {
396         return new Phenotype<>(
397             genotype,
398             generation,
399             requireNonNull(fitness)
400         );
401     }
402 
403 
404     /* *************************************************************************
405      *  Java object serialization
406      * ************************************************************************/
407 
408     private Object writeReplace() {
409         return new Serial(Serial.PHENOTYPE, this);
410     }
411 
412     private void readObject(final ObjectInputStream stream)
413         throws InvalidObjectException
414     {
415         throw new InvalidObjectException("Serialization proxy required.");
416     }
417 
418     void write(final ObjectOutput outthrows IOException {
419         writeLong(_generation, out);
420         out.writeObject(_genotype);
421         out.writeObject(_fitness);
422     }
423 
424     @SuppressWarnings({"unchecked""rawtypes"})
425     static Object read(final ObjectInput in)
426         throws IOException, ClassNotFoundException
427     {
428         final long generation = readLong(in);
429         final Genotype genotype = (Genotype)in.readObject();
430         final Comparable fitness = (Comparable)in.readObject();
431 
432         return new Phenotype(
433             genotype,
434             generation,
435             fitness
436         );
437     }
438 
439 }