Genotype.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 org.jenetics.internal.util.object.Verify;
import static org.jenetics.internal.util.object.eq;

import java.util.Iterator;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
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.cast;
import org.jenetics.internal.util.jaxb;
import org.jenetics.internal.util.model.ModelType;
import org.jenetics.internal.util.model.ValueType;

import org.jenetics.util.Array;
import org.jenetics.util.Factory;
import org.jenetics.util.Function;
import org.jenetics.util.ISeq;
import org.jenetics.util.Seq;
import org.jenetics.util.Verifiable;

/**
 * The central class the GA is working with, is the {@code Genotype}. It is the
 * structural representative of an individual. This class is the encoded problem
 * solution with one to many {@link Chromosome}.
 * <p><div align="center">
 * <img src="doc-files/Genotype.svg" width="400" height="252" >
 * </p></div>
 * The chromosomes of a genotype doesn't have to have necessarily the same size.
 * It is only required that all genes are from the same type and the genes within
 * a chromosome have the same constraints; e. g. the same min- and max values
 * for number genes.
 *
 * [code]
 * final Genotype〈DoubleGene〉 genotype = Genotype.of(
 *     DoubleChromosome.of(0.0, 1.0, 8),
 *     DoubleChromosome.of(1.0, 2.0, 10),
 *     DoubleChromosome.of(0.0, 10.0, 9),
 *     DoubleChromosome.of(0.1, 0.9, 5)
 * );
 * [/code]
 * The code snippet above creates a genotype with the same structure as shown in
 * the figure above. In this example the {@link DoubleGene} has been chosen as
 * gene type.
 *
 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
 * @since 1.0
 * @version 1.6 &mdash; <em>$Date: 2014-03-04 $</em>
 */
@XmlJavaTypeAdapter(Genotype.Model.Adapter.class)
public final class Genotype<G extends Gene<?, G>>
	implements
		Factory<Genotype<G>>,
		Iterable<Chromosome<G>>,
		Verifiable,
		XMLSerializable,
		Realtime,
		Immutable
{
	private static final long serialVersionUID = 2L;

	private final ISeq<Chromosome<G>> _chromosomes;
	private final int _ngenes;

	//Caching isValid value.
	private volatile Boolean _valid = null;

	private Genotype(
		final ISeq<? extends Chromosome<G>> chromosomes,
		final int ngenes
	) {
		if (chromosomes.length() == 0) {
			throw new IllegalArgumentException("No chromosomes given.");
		}

		_chromosomes = cast.apply(chromosomes);
		_ngenes = ngenes;
	}

	/**
	 * Create a new Genotype from a given sequence of {@code Chromosomes}.
	 *
	 * @param chromosomes The {@code Chromosome} array the {@code Genotype}
	 *         consists of.
	 * @throws NullPointerException if {@code chromosomes} is null or one of its
	 *         element.
	 * @throws IllegalArgumentException if {@code chromosome.length == 0}.
	 */
	public Genotype(final ISeq<? extends Chromosome<G>> chromosomes) {
		this(chromosomes, ngenes(chromosomes));
	}

	private static int ngenes(final Seq<? extends Chromosome<?>> chromosomes) {
		int ngenes = 0;
		for (int i = chromosomes.length(); --i >= 0;) {
			ngenes += chromosomes.get(i).length();
		}
		return ngenes;
	}

	/**
	 * Return the chromosome at the given index. It is guaranteed, that the
	 * returned chromosome is not null.
	 *
	 * @param index Chromosome index.
	 * @return The Chromosome.
	 * @throws IndexOutOfBoundsException if (index < 0 || index >= _length).
	 */
	public Chromosome<G> getChromosome(final int index) {
		assert(_chromosomes != null);
		assert(_chromosomes.get(index) != null);

		return _chromosomes.get(index);
	}

	/**
	 * Return the first chromosome. This is a shortcut for
	 * [code]
	 * final Genotype〈DoubleGene〉 gt = ...
	 * final Chromosome〈DoubleGene〉 chromosome = gt.getChromosome(0);
	 * [/code]
	 *
	 * @return The first chromosome.
	 */
	public Chromosome<G> getChromosome() {
		assert(_chromosomes != null);
		assert(_chromosomes.get(0) != null);

		return _chromosomes.get(0);
	}

	/**
	 * Return the first {@link Gene} of the first {@link Chromosome} of this
	 * {@code Genotype}. This is a shortcut for
	 * [code]
	 * final Genotype〈DoubleGene〉 gt = ...
	 * final DoubleGene gene = gt.getChromosome(0).getGene(0);
	 * [/code]
	 *
	 * @return the first {@link Gene} of the first {@link Chromosome} of this
	 *         {@code Genotype}.
	 */
	public G getGene() {
		assert(_chromosomes != null);
		assert(_chromosomes.get(0) != null);

		return _chromosomes.get(0).getGene();
	}


	public ISeq<Chromosome<G>> toSeq() {
		return _chromosomes;
	}

	@Override
	public Iterator<Chromosome<G>> iterator() {
		return _chromosomes.iterator();
	}

	/**
	 * Getting the number of chromosomes of this genotype.
	 *
	 * @return number of chromosomes.
	 */
	public int length() {
		return _chromosomes.length();
	}

	/**
	 * Return the number of genes this genotype consists of. This is the sum of
	 * the number of genes of the genotype chromosomes.
	 *
	 * @return Return the number of genes this genotype consists of.
	 */
	public int getNumberOfGenes() {
		return _ngenes;
	}

	/**
	 * Test if this genotype is valid. A genotype is valid if all its
	 * {@link Chromosome}s are valid.
	 *
	 * @return true if this genotype is valid, false otherwise.
	 */
	@Override
	public boolean isValid() {
		if (_valid == null) {
			_valid = _chromosomes.forAll(Verify);
		}
		return _valid;
	}

	/**
	 * Return a new, random genotype by creating new, random chromosomes (calling
	 * the {@link Chromosome#newInstance()} method) from the chromosomes of this
	 * genotype.
	 */
	@Override
	public Genotype<G> newInstance() {
		final Array<Chromosome<G>> chromosomes = new Array<>(length());
		for (int i = 0; i < length(); ++i) {
			chromosomes.set(i, _chromosomes.get(i).newInstance());
		}

		return new Genotype<>(chromosomes.toISeq(), _ngenes);
	}

	Genotype<G> newInstance(final ISeq<Chromosome<G>> chromosomes) {
		return new Genotype<>(chromosomes, _ngenes);
	}

	@Override
	public int hashCode() {
		return HashBuilder.of(getClass()).and(_chromosomes).value();
	}

	@Override
	public boolean equals(final Object o) {
		if (o == this) {
			return true;
		}
		if (!(o instanceof Genotype<?>)) {
			return false;
		}

		final Genotype<?> gt = (Genotype<?>)o;
		return eq(_chromosomes, gt._chromosomes);
	}

	@Override
	public Text toText() {
		return new Text(_chromosomes.toString());
	}

	@Override
	public String toString() {
		return _chromosomes.toString();
	}


	/* *************************************************************************
	 *  Property access methods
	 * ************************************************************************/

	/**
	 * Return a converter which access the chromosome array of this genotype.
	 */
	public static <T extends Gene<?, T>>
	Function<Genotype<T>, ISeq<Chromosome<T>>> Chromosomes()
	{
		return new Function<Genotype<T>, ISeq<Chromosome<T>>>() {
			@Override public ISeq<Chromosome<T>> apply(final Genotype<T> value) {
				return value.toSeq();
			}
		};
	}

	/**
	 * Return a converter which access the chromosome with the given index of
	 * this genotype.
	 */
	public static <T extends Gene<?, T>>
	Function<Genotype<T>, Chromosome<T>> Chromosome(final int index)
	{
		return new Function<Genotype<T>, Chromosome<T>>() {
			@Override public Chromosome<T> apply(final Genotype<T> value) {
				return value.getChromosome(index);
			}
		};
	}

	/**
	 * Return a converter which access the first chromosome of this genotype.
	 */
	public static <T extends Gene<?, T>>
	Function<Genotype<T>, Chromosome<T>> Chromosome()
	{
		return new Function<Genotype<T>, Chromosome<T>>() {
			@Override public Chromosome<T> apply(final Genotype<T> value) {
				return value.getChromosome();
			}
		};
	}

	/**
	 * @deprecated Use {@link #Genotype(org.jenetics.util.ISeq)} instead.
	 */
	@Deprecated
	public static <G extends Gene<?, G>> Genotype<G> valueOf(
		final ISeq<? extends Chromosome<G>> chromosomes
	) {
		return new Genotype<>(chromosomes);
	}

	/**
	 * @deprecated Use {@link #of(Chromosome[])} instead.
	 */
	@Deprecated
	@SafeVarargs
	public static <G extends Gene<?, G>> Genotype<G> valueOf(
		final Chromosome<G>... chromosomes
	) {
		return of(chromosomes);
	}

	/**
	 * Create a new Genotype from a given array of {@code Chromosomes}.
	 *
	 * @param chromosomes The {@code Chromosome} array the {@code Genotype}
	 *         consists of.
	 * @throws NullPointerException if {@code chromosomes} is null or one of its
	 *         element.
	 * @throws IllegalArgumentException if {@code chromosome.length == 0}.
	 */
	@SafeVarargs
	public static <G extends Gene<?, G>> Genotype<G> of(
		final Chromosome<G>... chromosomes
	) {
		return new Genotype<>(Array.of(chromosomes).toISeq());
	}

	/* *************************************************************************
	 *  XML object serialization
	 * ************************************************************************/

	@SuppressWarnings({ "unchecked", "rawtypes"})
	static final XMLFormat<Genotype>
	XML = new XMLFormat<Genotype>(Genotype.class)
	{
		private static final String LENGTH = "length";
		private static final String NGENES = "ngenes";

		@Override
		public Genotype newInstance(
			final Class<Genotype> cls, final InputElement xml
		)
			throws XMLStreamException
		{
			final int length = xml.getAttribute(LENGTH, 0);
			final int ngenes = xml.getAttribute(NGENES, 0);
			final Array<Chromosome> chromosomes = new Array<>(length);
			for (int i = 0; i < length; ++i) {
				final Chromosome<?> c = xml.getNext();
				chromosomes.set(i, c);
			}

			return new Genotype(chromosomes.toISeq(), ngenes);
		}
		@Override
		public void write(final Genotype gt, final OutputElement xml)
			throws XMLStreamException
		{
			xml.setAttribute(LENGTH, gt.length());
			xml.setAttribute(NGENES, gt.getNumberOfGenes());
			for (int i = 0; i < gt.length(); ++i) {
				xml.add(gt._chromosomes.get(i));
			}
		}
		@Override
		public void read(final InputElement xml, final Genotype gt) {
		}
	};

	/* *************************************************************************
	 *  JAXB object serialization
	 * ************************************************************************/

	@XmlRootElement(name = "org.jenetics.Genotype")
	@XmlType(name = "org.jenetics.Genotype")
	@XmlAccessorType(XmlAccessType.FIELD)
	@SuppressWarnings({"unchecked", "rawtypes"})
	static final class Model {

		@XmlAttribute
		public int length;

		@XmlAttribute
		public int ngenes;

		@XmlAnyElement
		public List<Object> chromosomes;

		@ValueType(Genotype.class)
		@ModelType(Model.class)
		public static final class Adapter
			extends XmlAdapter<Model, Genotype>
		{
			@Override
			public Model marshal(final Genotype gt) throws Exception {
				final Model model = new Model();
				model.length = gt.length();
				model.ngenes = gt.getNumberOfGenes();
				model.chromosomes = gt.toSeq()
					.map(jaxb.Marshaller(gt.getChromosome())).asList();

				return model;
			}

			@Override
			public Genotype unmarshal(final Model model) throws Exception {
				final ISeq chs = Array.of(model.chromosomes)
					.map(jaxb.Unmarshaller).toISeq();

				return new Genotype(chs, model.ngenes);
			}
		}

		public static final Adapter Adapter = new Adapter();
	}
}