Phenotype.java
/*
* Java Genetic Algorithm Library (@__identifier__@).
* Copyright (c) @__year__@ Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
*/
package org.jenetics;
import static java.util.Objects.requireNonNull;
import static org.jenetics.internal.util.object.eq;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javolution.lang.Immutable;
import javolution.lang.Realtime;
import javolution.text.Text;
import javolution.xml.XMLFormat;
import javolution.xml.XMLSerializable;
import javolution.xml.stream.XMLStreamException;
import org.jenetics.internal.util.HashBuilder;
import org.jenetics.internal.util.jaxb;
import org.jenetics.internal.util.model.ModelType;
import org.jenetics.internal.util.model.ValueType;
import org.jenetics.util.Function;
import org.jenetics.util.Verifiable;
import org.jenetics.util.functions;
/**
* The {@code Phenotype} consists of a {@link Genotype} plus a fitness
* {@link Function}, where the fitness {@link Function} represents the
* environment where the {@link Genotype} lives.
* This class implements the {@link Comparable} interface, to define a natural
* order between two {@code Phenotype}s. The natural order of the
* {@code Phenotypes} is defined by its fitness value (given by the
* fitness {@link Function}. The {@code Phenotype} is immutable and therefore
* can't be changed after creation.
*
* @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
* @since 1.0
* @version 1.6 — <em>$Date: 2014-03-04 $</em>
*/
@XmlJavaTypeAdapter(Phenotype.Model.Adapter.class)
public final class Phenotype<
G extends Gene<?, G>,
C extends Comparable<? super C>
>
implements
Comparable<Phenotype<G, C>>,
Immutable,
Verifiable,
XMLSerializable,
Realtime,
Runnable
{
private static final long serialVersionUID = 1L;
private final Genotype<G> _genotype;
private transient final
Function<? super Genotype<G>, ? extends C> _fitnessFunction;
private transient final
Function<? super C, ? extends C> _fitnessScaler;
private final int _generation;
//Storing the fitness value for lazy evaluation.
private C _rawFitness = null;
private C _fitness = null;
/**
* Create a new phenotype from the given arguments.
*
* @param genotype the genotype of this phenotype.
* @param fitnessFunction the fitness function of this phenotype.
* @param fitnessScaler the fitness scaler.
* @param generation the current generation of the generated phenotype.
* @throws NullPointerException if one of the arguments is {@code null}.
* @throws IllegalArgumentException if the given {@code generation} is < 0.
*/
public Phenotype(
final Genotype<G> genotype,
final Function<? super Genotype<G>, ? extends C> fitnessFunction,
final Function<? super C, ? extends C> fitnessScaler,
final int generation
) {
_genotype = requireNonNull(genotype, "Genotype");
_fitnessFunction = requireNonNull(fitnessFunction, "Fitness function");
_fitnessScaler = requireNonNull(fitnessScaler, "Fitness scaler");
if (generation < 0) {
throw new IllegalArgumentException(
"Generation must not < 0: " + generation
);
}
_generation = generation;
}
/**
* This method returns a copy of the {@code Genotype}, to guarantee a
* immutable class.
*
* @return the cloned {@code Genotype} of this {@code Phenotype}.
* @throws NullPointerException if one of the arguments is {@code null}.
*/
public Genotype<G> getGenotype() {
return _genotype;
}
/**
* Evaluates the (raw) fitness values and caches it so the fitness calculation
* is performed only once.
*
* @return this phenotype, for method chaining.
*/
public Phenotype<G, C> evaluate() {
if (_rawFitness == null) {
_rawFitness = _fitnessFunction.apply(_genotype);
_fitness = _fitnessScaler.apply(_rawFitness);
}
return this;
}
/**
* This method simply calls the {@link #evaluate()} method. The purpose of
* this method is to have a simple way for concurrent fitness calculation
* for expensive fitness values.
*/
@Override
public void run() {
evaluate();
}
/**
* Return the fitness function used by this phenotype to calculate the
* (raw) fitness value.
*
* @return the fitness function.
*/
public Function<? super Genotype<G>, ? extends C> getFitnessFunction() {
return _fitnessFunction;
}
/**
* Return the fitness scaler used by this phenotype to scale the <i>raw</i>
* fitness.
*
* @return the fitness scaler.
*/
public Function<? super C, ? extends C> getFitnessScaler() {
return _fitnessScaler;
}
/**
* Return the fitness value of this {@code Phenotype}.
*
* @return The fitness value of this {@code Phenotype}.
*/
public C getFitness() {
evaluate();
return _fitness;
}
/**
* Return the raw fitness (before scaling) of the phenotype.
*
* @return The raw fitness (before scaling) of the phenotype.
*/
public C getRawFitness() {
evaluate();
return _rawFitness;
}
/**
* Return the generation this {@link Phenotype} was created.
*
* @return The generation this {@link Phenotype} was created.
*/
public int getGeneration() {
return _generation;
}
/**
* Return the age of this phenotype depending on the given current generation.
*
* @param currentGeneration the current generation evaluated by the GA.
* @return the age of this phenotype:
* {@code currentGeneration - this.getGeneration()}.
*/
public int getAge(final int currentGeneration) {
return currentGeneration - _generation;
}
/**
* Test whether this phenotype is valid. The phenotype is valid if its
* {@link Genotype} is valid.
*
* @return true if this phenotype is valid, false otherwise.
*/
@Override
public boolean isValid() {
return _genotype.isValid();
}
@Override
public int compareTo(final Phenotype<G, C> pt) {
return getFitness().compareTo(pt.getFitness());
}
@Override
public int hashCode() {
return HashBuilder.of(getClass()).
and(_generation).
and(getFitness()).
and(getRawFitness()).
and(_genotype).value();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Phenotype<?, ?>)) {
return false;
}
final Phenotype<?, ?> pt = (Phenotype<?, ?>)obj;
return eq(getFitness(), pt.getFitness()) &&
eq(getRawFitness(), pt.getRawFitness()) &&
eq(_genotype, pt._genotype) &&
eq(_generation, pt._generation);
}
@Override
public Text toText() {
return _genotype.toText();
}
@Override
public String toString() {
return toText().toString() + " --> " + getFitness();
}
/**
* Factory method for creating a new {@link Phenotype} with the same
* {@link Function} and age as this {@link Phenotype}.
*
* @param genotype the new genotype of the new phenotype.
* @param generation date of birth (generation) of the new phenotype.
* @return New {@link Phenotype} with the same fitness {@link Function}.
* @throws NullPointerException if the {@code genotype} is {@code null}.
*/
Phenotype<G, C> newInstance(final Genotype<G> genotype, final int generation) {
requireNonNull(genotype, "Genotype");
return Phenotype.of(
genotype, _fitnessFunction, _fitnessScaler, generation
);
}
/**
* Return a new phenotype with the the genotype of this and with new
* fitness function, fitness scaler and generation.
*
* @param function the (new) fitness scaler of the created phenotype.
* @param scaler the (new) fitness scaler of the created phenotype
* @param generation the generation of the new phenotype.
* @return a new phenotype with the given values.
* @throws NullPointerException if one of the values is {@code null}.
* @throws IllegalArgumentException if the given {@code generation} is < 0.
*/
public Phenotype<G, C> newInstance(
final Function<? super Genotype<G>, ? extends C> function,
final Function<? super C, ? extends C> scaler,
final int generation
) {
return of(_genotype, function, scaler, generation);
}
/**
* Return a new phenotype with the the genotype of this and with new
* fitness function and generation.
*
* @param function the (new) fitness scaler of the created phenotype.
* @param generation the generation of the new phenotype.
* @return a new phenotype with the given values.
* @throws NullPointerException if one of the values is {@code null}.
* @throws IllegalArgumentException if the given {@code generation} is < 0.
*/
public Phenotype<G, C> newInstance(
final Function<? super Genotype<G>, ? extends C> function,
final int generation
) {
return of(_genotype, function, functions.<C>Identity(), generation);
}
/* *************************************************************************
* Property access methods
* ************************************************************************/
/**
* Create a {@link Function} which return the phenotype age when calling
* {@code converter.convert(phenotype)}.
*
* @param currentGeneration the current generation.
* @return an age {@link Function}.
*/
public static Function<Phenotype<?, ?>, Integer>
Age(final int currentGeneration)
{
return new Function<Phenotype<?, ?>, Integer>() {
@Override public Integer apply(final Phenotype<?, ?> value) {
return value.getAge(currentGeneration);
}
};
}
/**
* Create a {@link Function} which return the phenotype generation when
* calling {@code converter.convert(phenotype)}.
*
* @return a generation {@link Function}.
*/
public static Function<Phenotype<?, ?>, Integer> Generation() {
return new Function<Phenotype<?, ?>, Integer>() {
@Override public Integer apply(final Phenotype<?, ?> value) {
return value.getGeneration();
}
};
}
/**
* Create a {@link Function} which return the phenotype fitness when
* calling {@code converter.convert(phenotype)}.
*
* @param <C> the fitness value type.
* @return a fitness {@link Function}.
*/
public static <C extends Comparable<? super C>>
Function<Phenotype<?, C>, C> Fitness()
{
return new Function<Phenotype<?, C>, C>() {
@Override public C apply(final Phenotype<?, C> value) {
return value.getFitness();
}
};
}
/**
* Create a {@link Function} which return the phenotype raw fitness when
* calling {@code converter.convert(phenotype)}.
*
* @param <C> the fitness value type.
* @return a raw fitness {@link Function}.
*
* @deprecated Fixing typo, use {@link #RawFitness()} instead.
*/
@Deprecated
public static <C extends Comparable<? super C>>
Function<Phenotype<?, C>, C> RawFitnees()
{
return RawFitness();
}
/**
* Create a {@link Function} which return the phenotype raw fitness when
* calling {@code converter.convert(phenotype)}.
*
* @param <C> the fitness value type.
* @return a raw fitness {@link Function}.
*/
public static <C extends Comparable<? super C>>
Function<Phenotype<?, C>, C> RawFitness()
{
return new Function<Phenotype<?, C>, C>() {
@Override public C apply(final Phenotype<?, C> value) {
return value.getRawFitness();
}
};
}
/**
* Create a {@link Function} which return the phenotype genotype when
* calling {@code converter.convert(phenotype)}.
*
* @param <G> the gene type.
* @return a genotype {@link Function}.
*/
public static <G extends Gene<?, G>>
Function<Phenotype<G, ?>, Genotype<G>> Genotype()
{
return new Function<Phenotype<G, ?>, Genotype<G>>() {
@Override public Genotype<G> apply(final Phenotype<G, ?> value) {
return value.getGenotype();
}
};
}
/**
* @deprecated Use {@link #of(Genotype, org.jenetics.util.Function, org.jenetics.util.Function, int)}
* instead.
*/
@Deprecated
public static <G extends Gene<?, G>, C extends Comparable<? super C>>
Phenotype<G, C> valueOf(
final Genotype<G> genotype,
final Function<Genotype<G>, C> fitnessFunction,
final int generation
) {
return of(genotype, fitnessFunction, generation);
}
/**
* The {@code Genotype} is copied to guarantee an immutable class. Only
* the age of the {@code Phenotype} can be incremented.
*
* @param genotype the genotype of this phenotype.
* @param fitnessFunction the fitness function of this phenotype.
* @param generation the current generation of the generated phenotype.
* @throws NullPointerException if one of the arguments is {@code null}.
* @throws IllegalArgumentException if the given {@code generation} is < 0.
*/
public static <G extends Gene<?, G>, C extends Comparable<? super C>>
Phenotype<G, C> of(
final Genotype<G> genotype,
final Function<? super Genotype<G>, C> fitnessFunction,
final int generation
) {
return of(genotype, fitnessFunction, functions.<C>Identity(), generation);
}
/**
* @deprecated Use {@link #of(Genotype, org.jenetics.util.Function, org.jenetics.util.Function, int)}
* instead
*/
@Deprecated
public static <G extends Gene<?, G>, C extends Comparable<? super C>>
Phenotype<G, C> valueOf(
final Genotype<G> genotype,
final Function<? super Genotype<G>, ? extends C> fitnessFunction,
final Function<? super C, ? extends C> fitnessScaler,
final int generation
) {
return of(genotype, fitnessFunction, fitnessScaler, generation);
}
/**
* Create a new phenotype from the given arguments.
*
* @param genotype the genotype of this phenotype.
* @param fitnessFunction the fitness function of this phenotype.
* @param fitnessScaler the fitness scaler.
* @param generation the current generation of the generated phenotype.
* @return a new phenotype object
* @throws NullPointerException if one of the arguments is {@code null}.
* @throws IllegalArgumentException if the given {@code generation} is < 0.
*/
public static <G extends Gene<?, G>, C extends Comparable<? super C>>
Phenotype<G, C> of(
final Genotype<G> genotype,
final Function<? super Genotype<G>, ? extends C> fitnessFunction,
final Function<? super C, ? extends C> fitnessScaler,
final int generation
) {
return new Phenotype<>(
genotype,
fitnessFunction,
fitnessScaler,
generation
);
}
/* *************************************************************************
* XML object serialization
* ************************************************************************/
@SuppressWarnings({ "unchecked", "rawtypes" })
static final XMLFormat<Phenotype>
XML = new XMLFormat<Phenotype>(Phenotype.class)
{
private static final String GENERATION = "generation";
private static final String FITNESS = "fitness";
private static final String RAW_FITNESS = "raw-fitness";
@Override
public Phenotype newInstance(
final Class<Phenotype> cls, final InputElement xml
)
throws XMLStreamException
{
final int generation = xml.getAttribute(GENERATION, 0);
final Genotype genotype = xml.getNext();
final Phenotype pt = new Phenotype(
genotype, functions.Identity(), functions.Identity(), generation
);
pt._fitness = xml.get(FITNESS);
pt._rawFitness = xml.get(RAW_FITNESS);
return pt;
}
@Override
public void write(final Phenotype pt, final OutputElement xml)
throws XMLStreamException
{
xml.setAttribute(GENERATION, pt._generation);
xml.add(pt._genotype);
xml.add(pt.getFitness(), FITNESS);
xml.add(pt.getRawFitness(), RAW_FITNESS);
}
@Override
public void read(final InputElement xml, final Phenotype gt) {
}
};
/* *************************************************************************
* JAXB object serialization
* ************************************************************************/
@XmlRootElement(name = "org.jenetics.Phenotype")
@XmlType(name = "org.jenetics.Phenotype")
@XmlAccessorType(XmlAccessType.FIELD)
@SuppressWarnings({ "unchecked", "rawtypes" })
final static class Model {
@XmlAttribute
public int generation;
@XmlElement(name = "org.jenetics.Genotype")
public Genotype.Model genotype;
@XmlJavaTypeAdapter(jaxb.JavolutionElementAdapter.class)
@XmlElement(name = "fitness")
public Object fitness;
@XmlJavaTypeAdapter(jaxb.JavolutionElementAdapter.class)
@XmlElement(name = "raw-fitness")
public Object rawFitness;
@ValueType(Phenotype.class)
@ModelType(Model.class)
public final static class Adapter
extends XmlAdapter<Model, Phenotype>
{
@Override
public Model marshal(final Phenotype pt) throws Exception {
final Model m = new Model();
m.generation = pt.getGeneration();
m.genotype = Genotype.Model.Adapter.marshal(pt.getGenotype());
m.fitness = jaxb.marshal(pt.getFitness());
m.rawFitness = jaxb.marshal(pt.getRawFitness());
return m;
}
@Override
public Phenotype unmarshal(final Model m) throws Exception {
final Phenotype pt = new Phenotype(
Genotype.Model.Adapter.unmarshal(m.genotype),
functions.Identity(),
functions.Identity(),
m.generation
);
pt._fitness = (Comparable)m.fitness;
pt._rawFitness = (Comparable)m.rawFitness;
return pt;
}
}
}
}