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 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 * @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 }
|