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