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