001 /*
002 * Java Genetic Algorithm Library (jenetics-3.0.0).
003 * Copyright (c) 2007-2014 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.Serializable;
027 import java.util.function.Function;
028
029 import javax.xml.bind.annotation.XmlAccessType;
030 import javax.xml.bind.annotation.XmlAccessorType;
031 import javax.xml.bind.annotation.XmlAttribute;
032 import javax.xml.bind.annotation.XmlElement;
033 import javax.xml.bind.annotation.XmlRootElement;
034 import javax.xml.bind.annotation.XmlType;
035 import javax.xml.bind.annotation.adapters.XmlAdapter;
036 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
037
038 import org.jenetics.internal.util.Equality;
039 import org.jenetics.internal.util.Hash;
040 import org.jenetics.internal.util.jaxb;
041
042 import org.jenetics.util.Verifiable;
043
044 /**
045 * The {@code Phenotype} consists of a {@link Genotype} plus a fitness
046 * {@link Function}, where the fitness {@link Function} represents the
047 * environment where the {@link Genotype} lives.
048 * This class implements the {@link Comparable} interface, to define a natural
049 * order between two {@code Phenotype}s. The natural order of the
050 * {@code Phenotypes} is defined by its fitness value (given by the
051 * fitness {@link Function}. The {@code Phenotype} is immutable and therefore
052 * can't be changed after creation.
053 *
054 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
055 * @since 1.0
056 * @version 2.0 — <em>$Date: 2014-12-28 $</em>
057 */
058 @XmlJavaTypeAdapter(Phenotype.Model.Adapter.class)
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 = 4L;
070
071 private final Genotype<G> _genotype;
072
073 private final Function<? super Genotype<G>, ? extends C> _function;
074 private final Function<? super C, ? extends C> _scaler;
075
076 private final long _generation;
077
078 // Storing the fitness value for lazy evaluation.
079 private C _rawFitness = null;
080 private C _fitness = null;
081
082 /**
083 * Create a new phenotype from the given arguments.
084 *
085 * @param genotype the genotype of this phenotype.
086 * @param generation the current generation of the generated phenotype.
087 * @param function the fitness function of this phenotype.
088 * @param scaler the fitness scaler.
089 * @throws NullPointerException if one of the arguments is {@code null}.
090 * @throws IllegalArgumentException if the given {@code generation} is
091 * {@code < 0}.
092 */
093 private Phenotype(
094 final Genotype<G> genotype,
095 final long generation,
096 final Function<? super Genotype<G>, ? extends C> function,
097 final Function<? super C, ? extends C> scaler
098 ) {
099 _genotype = requireNonNull(genotype, "Genotype");
100 _function = requireNonNull(function, "Fitness function");
101 _scaler = requireNonNull(scaler, "Fitness scaler");
102 if (generation < 0) {
103 throw new IllegalArgumentException(format(
104 "Generation must not < 0 and was %s.", generation
105 ));
106 }
107 _generation = generation;
108 }
109
110 /**
111 * This method returns a copy of the {@code Genotype}, to guarantee a
112 * immutable class.
113 *
114 * @return the cloned {@code Genotype} of this {@code Phenotype}.
115 * @throws NullPointerException if one of the arguments is {@code null}.
116 */
117 public Genotype<G> getGenotype() {
118 return _genotype;
119 }
120
121 /**
122 * Evaluates the (raw) fitness values and caches it so the fitness calculation
123 * is performed only once.
124 *
125 * @return this phenotype, for method chaining.
126 */
127 public Phenotype<G, C> evaluate() {
128 if (_rawFitness == null) {
129 _rawFitness = _function.apply(_genotype);
130 _fitness = _scaler.apply(_rawFitness);
131 }
132 return this;
133 }
134
135 /**
136 * This method simply calls the {@link #evaluate()} method. The purpose of
137 * this method is to have a simple way for concurrent fitness calculation
138 * for expensive fitness values.
139 */
140 @Override
141 public void run() {
142 evaluate();
143 }
144
145 /**
146 * Return the fitness function used by this phenotype to calculate the
147 * (raw) fitness value.
148 *
149 * @return the fitness function.
150 */
151 public Function<? super Genotype<G>, ? extends C> getFitnessFunction() {
152 return _function;
153 }
154
155 /**
156 * Return the fitness scaler used by this phenotype to scale the <i>raw</i>
157 * fitness.
158 *
159 * @return the fitness scaler.
160 */
161 public Function<? super C, ? extends C> getFitnessScaler() {
162 return _scaler;
163 }
164
165 /**
166 * Return the fitness value of this {@code Phenotype}.
167 *
168 * @return The fitness value of this {@code Phenotype}.
169 */
170 public C getFitness() {
171 evaluate();
172 return _fitness;
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 evaluate();
182 return _rawFitness;
183 }
184
185 /**
186 * Return the generation this {@link Phenotype} was created.
187 *
188 * @return The generation this {@link Phenotype} was created.
189 */
190 public long getGeneration() {
191 return _generation;
192 }
193
194 /**
195 * Return the age of this phenotype depending on the given current generation.
196 *
197 * @param currentGeneration the current generation evaluated by the GA.
198 * @return the age of this phenotype:
199 * {@code currentGeneration - this.getGeneration()}.
200 */
201 public long getAge(final long currentGeneration) {
202 return currentGeneration - _generation;
203 }
204
205 /**
206 * Test whether this phenotype is valid. The phenotype is valid if its
207 * {@link Genotype} is valid.
208 *
209 * @return true if this phenotype is valid, false otherwise.
210 */
211 @Override
212 public boolean isValid() {
213 return _genotype.isValid();
214 }
215
216 @Override
217 public int compareTo(final Phenotype<G, C> pt) {
218 return getFitness().compareTo(pt.getFitness());
219 }
220
221 @Override
222 public int hashCode() {
223 return Hash.of(getClass())
224 .and(_generation)
225 .and(getFitness())
226 .and(getRawFitness())
227 .and(_genotype).value();
228 }
229
230 @Override
231 public boolean equals(final Object obj) {
232 return Equality.of(this, obj).test(pt ->
233 eq(getFitness(), pt.getFitness()) &&
234 eq(getRawFitness(), pt.getRawFitness()) &&
235 eq(_genotype, pt._genotype) &&
236 eq(_generation, pt._generation)
237 );
238 }
239
240 @Override
241 public String toString() {
242 return _genotype.toString() + " --> " + getFitness();
243 }
244
245 /**
246 * Factory method for creating a new {@link Phenotype} with the same
247 * {@link Function} and age as this {@link Phenotype}.
248 *
249 * @param genotype the new genotype of the new phenotype.
250 * @param generation date of birth (generation) of the new phenotype.
251 * @return New {@link Phenotype} with the same fitness {@link Function}.
252 * @throws NullPointerException if the {@code genotype} is {@code null}.
253 */
254 Phenotype<G, C> newInstance(
255 final Genotype<G> genotype,
256 final long generation
257 ) {
258 return of(genotype, generation, _function, _scaler);
259 }
260
261 /**
262 * Return a new phenotype with the the genotype of this and with new
263 * fitness function, fitness scaler and generation.
264 *
265 * @param generation the generation of the new phenotype.
266 * @param function the (new) fitness scaler of the created phenotype.
267 * @param scaler the (new) fitness scaler of the created phenotype
268 * @return a new phenotype with the given values.
269 * @throws NullPointerException if one of the values is {@code null}.
270 * @throws IllegalArgumentException if the given {@code generation} is
271 * {@code < 0}.
272 */
273 public Phenotype<G, C> newInstance(
274 final long generation,
275 final Function<? super Genotype<G>, ? extends C> function,
276 final Function<? super C, ? extends C> scaler
277 ) {
278 return of(_genotype, generation, function, scaler);
279 }
280
281 /**
282 * Return a new phenotype with the the genotype of this and with new
283 * fitness function and generation.
284 *
285 * @param generation the generation of the new phenotype.
286 * @param function the (new) fitness scaler of the created phenotype.
287 * @return a new phenotype with the given values.
288 * @throws NullPointerException if one of the values is {@code null}.
289 * @throws IllegalArgumentException if the given {@code generation} is
290 * {@code < 0}.
291 */
292 public Phenotype<G, C> newInstance(
293 final long generation,
294 final Function<? super Genotype<G>, ? extends C> function
295 ) {
296 return of(_genotype, generation, function, a -> a);
297 }
298
299 /**
300 * The {@code Genotype} is copied to guarantee an immutable class. Only
301 * the age of the {@code Phenotype} can be incremented.
302 *
303 * @param <G> the gene type of the chromosome
304 * @param <C> the fitness value type
305 * @param genotype the genotype of this phenotype.
306 * @param generation the current generation of the generated phenotype.
307 * @param function the fitness function of this phenotype.
308 * @return a new phenotype from the given parameters
309 * @throws NullPointerException if one of the arguments is {@code null}.
310 * @throws IllegalArgumentException if the given {@code generation} is
311 * {@code < 0}.
312 */
313 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
314 Phenotype<G, C> of(
315 final Genotype<G> genotype,
316 final long generation,
317 final Function<? super Genotype<G>, C> function
318 ) {
319 return of(
320 genotype,
321 generation,
322 function,
323 function instanceof Serializable ?
324 (Function<? super C, ? extends C> & Serializable)a -> a :
325 a -> a
326 );
327 }
328
329 /**
330 * Create a new phenotype from the given arguments.
331 *
332 * @param <G> the gene type of the chromosome
333 * @param <C> the fitness value type
334 * @param genotype the genotype of this phenotype.
335 * @param generation the current generation of the generated phenotype.
336 * @param function the fitness function of this phenotype.
337 * @param scaler the fitness scaler.
338 * @return a new phenotype object
339 * @throws NullPointerException if one of the arguments is {@code null}.
340 * @throws IllegalArgumentException if the given {@code generation} is
341 * {@code < 0}.
342 */
343 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
344 Phenotype<G, C> of(
345 final Genotype<G> genotype,
346 final long generation,
347 final Function<? super Genotype<G>, ? extends C> function,
348 final Function<? super C, ? extends C> scaler
349 ) {
350 return new Phenotype<>(
351 genotype,
352 generation,
353 function,
354 scaler
355 );
356 }
357
358 /* *************************************************************************
359 * JAXB object serialization
360 * ************************************************************************/
361
362 @XmlRootElement(name = "phenotype")
363 @XmlType(name = "org.jenetics.Phenotype")
364 @XmlAccessorType(XmlAccessType.FIELD)
365 @SuppressWarnings({ "unchecked", "rawtypes" })
366 final static class Model {
367
368 @XmlAttribute(name = "generation", required = true)
369 public long generation;
370
371 @XmlElement(name = "genotype", required = true, nillable = false)
372 public Genotype.Model genotype;
373
374 @XmlElement(name = "fitness", required = true, nillable = false)
375 public Object fitness;
376
377 @XmlElement(name = "raw-fitness", required = true, nillable = false)
378 public Object rawFitness;
379
380 public final static class Adapter
381 extends XmlAdapter<Model, Phenotype>
382 {
383 @Override
384 public Model marshal(final Phenotype pt) throws Exception {
385 final Model m = new Model();
386 m.generation = pt.getGeneration();
387 m.genotype = Genotype.Model.ADAPTER.marshal(pt.getGenotype());
388 m.fitness = jaxb.marshal(pt.getFitness());
389 m.rawFitness = jaxb.marshal(pt.getRawFitness());
390 return m;
391 }
392
393 @Override
394 public Phenotype unmarshal(final Model m) throws Exception {
395 final Phenotype pt = new Phenotype(
396 Genotype.Model.ADAPTER.unmarshal(m.genotype),
397 m.generation,
398 Function.identity(),
399 Function.identity()
400 );
401 pt._fitness = (Comparable)m.fitness;
402 pt._rawFitness = (Comparable)m.rawFitness;
403 return pt;
404 }
405 }
406 }
407
408 }
|