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 G extends Gene<?, G>,
064 C 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 }
|