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