phenotype of chromosome + * @since 4.0 + */ +public abstract class AbstractGeneticAlgorithm
{ + + /** the crossover policy used by the algorithm. */ + private final CrossoverPolicy
crossoverPolicy; + + /** the mutation policy used by the algorithm. */ + private final MutationPolicy
mutationPolicy; + + /** the selection policy used by the algorithm. */ + private final SelectionPolicy
selectionPolicy; + + /** + * the number of generations evolved to reach {@link StoppingCondition} in the + * last run. + */ + private int generationsEvolved; + + /** The elitism rate having default value of .25. */ + private double elitismRate = .25; + + /** + * constructor. + * @param crossoverPolicy The {@link CrossoverPolicy} + * @param mutationPolicy The {@link MutationPolicy} + * @param selectionPolicy The {@link SelectionPolicy} + */ + protected AbstractGeneticAlgorithm(final CrossoverPolicy
crossoverPolicy, final MutationPolicy
mutationPolicy, + final SelectionPolicy
selectionPolicy) { + this.crossoverPolicy = crossoverPolicy; + this.mutationPolicy = mutationPolicy; + this.selectionPolicy = selectionPolicy; + } + + /** + * constructor. + * @param crossoverPolicy The {@link CrossoverPolicy} + * @param mutationPolicy The {@link MutationPolicy} + * @param selectionPolicy The {@link SelectionPolicy} + * @param elitismRate The elitism rate + */ + protected AbstractGeneticAlgorithm(final CrossoverPolicy
crossoverPolicy, final MutationPolicy
mutationPolicy, + final SelectionPolicy
selectionPolicy, double elitismRate) { + this.crossoverPolicy = crossoverPolicy; + this.mutationPolicy = mutationPolicy; + this.selectionPolicy = selectionPolicy; + this.elitismRate = elitismRate; + } + + /** + * Returns the crossover policy. + * @return crossover policy + */ + public CrossoverPolicy
getCrossoverPolicy() { + return crossoverPolicy; + } + + /** + * Returns the mutation policy. + * @return mutation policy + */ + public MutationPolicy
getMutationPolicy() { + return mutationPolicy; + } + + /** + * Returns the selection policy. + * @return selection policy + */ + public SelectionPolicy
getSelectionPolicy() { + return selectionPolicy; + } + + /** + * Returns the number of generations evolved to reach {@link StoppingCondition} + * in the last run. + * + * @return number of generations evolved + * @since 2.1 + */ + public int getGenerationsEvolved() { + return generationsEvolved; + } + + /** + * Evolve the given population. Evolution stops when the stopping condition is + * satisfied. Updates the {@link #getGenerationsEvolved() generationsEvolved} + * property with the number of generations evolved before the StoppingCondition + * is satisfied. + * + * @param initial the initial, seed population. + * @param condition the stopping condition used to stop evolution. + * @return the population that satisfies the stopping condition. + */ + public Population
evolve(final Population
initial, final StoppingCondition
condition) { + Population
current = initial; + // check if stopping condition is satisfied otherwise produce the next + // generation of population. + while (!condition.isSatisfied(current)) { + // notify interested listener + ConvergenceListenerRegistry.
getInstance().notifyAll(generationsEvolved, current); + + current = nextGeneration(current); + this.generationsEvolved++; + } + + return current; + } + + /** + * Evolve the given population into the next generation. + *
current
+ * generation, using its nextGeneration methodcurrent
,nextGeneration(Population
current); + + /** + * Returns the elitism rate. + * @return elitism rate + */ + public double getElitismRate() { + return elitismRate; + } + +} diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/GeneticAlgorithm.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/GeneticAlgorithm.java new file mode 100644 index 0000000000..3f97072ca9 --- /dev/null +++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/GeneticAlgorithm.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.commons.math4.ga; + +import org.apache.commons.math4.ga.chromosome.ChromosomePair; +import org.apache.commons.math4.ga.crossover.CrossoverPolicy; +import org.apache.commons.math4.ga.exception.GeneticException; +import org.apache.commons.math4.ga.mutation.MutationPolicy; +import org.apache.commons.math4.ga.population.Population; +import org.apache.commons.math4.ga.selection.SelectionPolicy; +import org.apache.commons.math4.ga.utils.Constants; + +/** + * Implementation of a genetic algorithm. All factors that govern the operation + * of the algorithm can be configured for a specific problem. + * + * @param
phenotype of chromosome + * @since 4.0 + */ +public class GeneticAlgorithm
extends AbstractGeneticAlgorithm
{ + + /** the rate of crossover for the algorithm. */ + private final double crossoverRate; + + /** the rate of mutation for the algorithm. */ + private final double mutationRate; + + /** + * Create a new genetic algorithm. + * @param crossoverPolicy The {@link CrossoverPolicy} + * @param crossoverRate The crossover rate as a percentage (0-1 inclusive) + * @param mutationPolicy The {@link MutationPolicy} + * @param mutationRate The mutation rate as a percentage (0-1 inclusive) + * @param selectionPolicy The {@link SelectionPolicy} + */ + public GeneticAlgorithm(final CrossoverPolicy
crossoverPolicy, final double crossoverRate, + final MutationPolicy
mutationPolicy, final double mutationRate, + final SelectionPolicy
selectionPolicy) { + super(crossoverPolicy, mutationPolicy, selectionPolicy); + + checkValidity(crossoverRate, mutationRate); + this.crossoverRate = crossoverRate; + this.mutationRate = mutationRate; + } + + /** + * Create a new genetic algorithm. + * @param crossoverPolicy The {@link CrossoverPolicy} + * @param crossoverRate The crossover rate as a percentage (0-1 inclusive) + * @param mutationPolicy The {@link MutationPolicy} + * @param mutationRate The mutation rate as a percentage (0-1 inclusive) + * @param selectionPolicy The {@link SelectionPolicy} + * @param elitismRate The rate of elitism + */ + public GeneticAlgorithm(final CrossoverPolicy
crossoverPolicy, final double crossoverRate, + final MutationPolicy
mutationPolicy, final double mutationRate, final SelectionPolicy
selectionPolicy, + final double elitismRate) { + super(crossoverPolicy, mutationPolicy, selectionPolicy, elitismRate); + + checkValidity(crossoverRate, mutationRate); + this.crossoverRate = crossoverRate; + this.mutationRate = mutationRate; + } + + private void checkValidity(final double crossoverRateInput, final double inputMutationRate) { + if (crossoverRateInput < 0 || crossoverRateInput > 1) { + throw new GeneticException(GeneticException.OUT_OF_RANGE, crossoverRateInput, Constants.CROSSOVER_RATE, 0, + 1); + } + if (inputMutationRate < 0 || inputMutationRate > 1) { + throw new GeneticException(GeneticException.OUT_OF_RANGE, inputMutationRate, Constants.MUTATION_RATE, 0, 1); + } + } + + /** + * Evolve the given population into the next generation. + *
current
+ * generation, using its nextGeneration methodcurrent
nextGeneration(final Population
current) { + final Population
nextGeneration = current.nextGeneration(getElitismRate()); + + while (nextGeneration.getPopulationSize() < nextGeneration.getPopulationLimit() - 1) { + // select parent chromosomes + ChromosomePair
pair = getSelectionPolicy().select(current); + + // apply crossover policy to create two offspring + pair = getCrossoverPolicy().crossover(pair.getFirst(), pair.getSecond(), crossoverRate); + + // apply mutation policy to the chromosomes + pair = new ChromosomePair<>(getMutationPolicy().mutate(pair.getFirst(), mutationRate), + getMutationPolicy().mutate(pair.getSecond(), mutationRate)); + + // add the chromosomes to the population + nextGeneration.addChromosome(pair.getFirst()); + nextGeneration.addChromosome(pair.getSecond()); + } + + return nextGeneration; + } + + /** + * Returns the crossover rate. + * @return crossover rate + */ + public double getCrossoverRate() { + return crossoverRate; + } + + /** + * Returns the mutation rate. + * @return mutation rate + */ + public double getMutationRate() { + return mutationRate; + } + +} diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractChromosome.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractChromosome.java new file mode 100644 index 0000000000..a3f5abc3fd --- /dev/null +++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractChromosome.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.commons.math4.ga.chromosome; + +import org.apache.commons.math4.ga.decoder.Decoder; +import org.apache.commons.math4.ga.fitness.FitnessFunction; +import org.apache.commons.math4.ga.utils.ValidationUtils; + +/** + * Individual in a population. Chromosomes are compared based on their fitness. + *
+ * The chromosomes are IMMUTABLE, and so their fitness is also immutable and + * therefore it can be cached. + * + * @param
The phenotype of chromosome. The type should override hashCode() + * and equals() methods. + * @since 4.0 + */ +public abstract class AbstractChromosome
implements Chromosome
{ + + /** Value assigned when no fitness has been computed yet. */ + private static final double NO_FITNESS = Double.NEGATIVE_INFINITY; + + /** Cached value of the fitness of this chromosome. */ + private double fitness = NO_FITNESS; + + /** Fitness function to evaluate fitness of chromosome. **/ + private final FitnessFunction
fitnessFunction; + + /** decoder to deode the chromosome's genotype representation. **/ + private final Decoder
decoder; + + /** + * constructor. + * @param fitnessFunction The {@link FitnessFunction} + * @param decoder The {@link Decoder} + */ + protected AbstractChromosome(final FitnessFunction
fitnessFunction, final Decoder
decoder) { + ValidationUtils.checkForNull("fitness-function", fitnessFunction); + ValidationUtils.checkForNull("decoder", decoder); + this.fitnessFunction = fitnessFunction; + this.decoder = decoder; + } + + /** + * returns fitness function. + * @return fitnessFunction + */ + protected FitnessFunction
getFitnessFunction() { + return fitnessFunction; + } + + /** + * Returns the decoder instance. + * @return decoder + */ + protected Decoder
getDecoder() { + return decoder; + } + + /** + * Access the fitness of this chromosome. The bigger the fitness, the better the + * chromosome. + *
+ * Computation of fitness is usually very time-consuming task, therefore the + * fitness is cached. + * @return the fitness + */ + @Override + public double evaluate() { + if (this.fitness == NO_FITNESS) { + // no cache - compute the fitness + this.fitness = fitnessFunction.compute(decode()); + } + return this.fitness; + } + + /** + * Decodes the chromosome genotype and returns the phenotype. + * @return phenotype + */ + @Override + public P decode() { + return this.decoder.decode(this); + } + + /** + * Compares two chromosomes based on their fitness. The bigger the fitness, the + * better the chromosome. + * @param another another chromosome to compare + * @return + *
another
is better than this
another
is worse than this
another) {
+ return Double.compare(evaluate(), another.evaluate());
+ }
+
+ /**
+ * Returns true
iff another
has the same
+ * representation and therefore the same fitness. By default, it returns false
+ * -- override it in your implementation if you need it.
+ * @param another chromosome to compare
+ * @return true if another
is equivalent to this chromosome
+ */
+ public boolean isSame(final AbstractChromosome
another) {
+ final P decodedChromosome = decode();
+ final P otherDecodedChromosome = another.decode();
+ return decodedChromosome.equals(otherDecodedChromosome);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return String.format("(f=%s %s)", evaluate(), decode());
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractListChromosome.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractListChromosome.java
new file mode 100644
index 0000000000..df3003ce96
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractListChromosome.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.chromosome;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math4.ga.decoder.AbstractListChromosomeDecoder;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+import org.apache.commons.math4.ga.utils.ValidationUtils;
+
+/**
+ * This class represents an abstract chromosome containing an immutable list of
+ * allele/genes.
+ * @param phenotype of chromosome
+ * @since 2.0
+ */
+public abstract class AbstractListChromosome {
+
+ /** List of allele/genes. */
+ private final List fitnessFunction,
+ final AbstractListChromosomeDecoder fitnessFunction,
+ AbstractListChromosomeDecoder fitnessFunction, final AbstractListChromosomeDecoder
+ * Usually, this method just calls a constructor of the class.
+ *
+ * @param chromosomeRepresentation the inner array representation of the new
+ * chromosome.
+ * @return new instance extended from FixedLengthChromosome with the given
+ * arrayRepresentation
+ */
+ public abstract AbstractListChromosome phenotype of chromosome
+ * @since 2.0
+ */
+public class BinaryChromosome extends IntegralValuedChromosome {
+
+ /**
+ * constructor.
+ * @param representation Internal representation of chromosome.
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link AbstractListChromosomeDecoder}
+ */
+ public BinaryChromosome(List fitnessFunction,
+ AbstractListChromosomeDecoder fitnessFunction,
+ AbstractListChromosomeDecoder newChromosome(List phenotype fo chromosome
+ * @param length length of chromosome
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link AbstractListChromosomeDecoder}
+ * @return a binary chromosome
+ */
+ public static BinaryChromosome randomChromosome(int length, FitnessFunction fitnessFunction,
+ AbstractListChromosomeDecoder phenotype of chromosome
+ * @since 4.0
+ */
+public interface Chromosome extends Comparable
+ * Computation of fitness is usually very time-consuming task, therefore the
+ * fitness is cached.
+ * @return the fitness
+ */
+ double evaluate();
+
+ /**
+ * Decodes the chromosome genotype and returns the phenotype.
+ * @return phenotype
+ */
+ P decode();
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/ChromosomePair.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/ChromosomePair.java
new file mode 100644
index 0000000000..1157a00822
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/ChromosomePair.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.chromosome;
+
+/**
+ * A pair of {@link Chromosome} objects.
+ * @param phenotype of chromosome
+ * @since 2.0
+ */
+public class ChromosomePair {
+
+ /** the first chromosome in the pair. */
+ private final Chromosome first;
+
+ /** the second chromosome in the pair. */
+ private final Chromosome second;
+
+ /**
+ * Create a chromosome pair.
+ * @param c1 the first chromosome.
+ * @param c2 the second chromosome.
+ */
+ public ChromosomePair(final Chromosome c1, final Chromosome c2) {
+ super();
+ first = c1;
+ second = c2;
+ }
+
+ /**
+ * Access the first chromosome.
+ *
+ * @return the first chromosome.
+ */
+ public Chromosome getFirst() {
+ return first;
+ }
+
+ /**
+ * Access the second chromosome.
+ *
+ * @return the second chromosome.
+ */
+ public Chromosome getSecond() {
+ return second;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return String.format("(%s,%s)", getFirst(), getSecond());
+ }
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/IntegralValuedChromosome.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/IntegralValuedChromosome.java
new file mode 100644
index 0000000000..91c08c7e18
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/IntegralValuedChromosome.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.chromosome;
+
+import java.util.List;
+
+import org.apache.commons.math4.ga.decoder.AbstractListChromosomeDecoder;
+import org.apache.commons.math4.ga.exception.GeneticException;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.apache.commons.math4.ga.utils.ValidationUtils;
+
+/**
+ * Chromosome represented by a list of integral values. The acceptable integral
+ * values should belong to the range min(inclusive) to max(exclusive).
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public class IntegralValuedChromosome extends AbstractListChromosome fitnessFunction,
+ AbstractListChromosomeDecoder fitnessFunction,
+ AbstractListChromosomeDecoder newChromosome(List phenotype fo chromosome
+ * @param length length of chromosome
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link AbstractListChromosomeDecoder}
+ * @param min minimum inclusive value of allele
+ * @param max maximum exclusive value of allele
+ * @return an integral-valued chromosome
+ */
+ public static IntegralValuedChromosome randomChromosome(int length, FitnessFunction fitnessFunction,
+ AbstractListChromosomeDecoder
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public class RealValuedChromosome extends AbstractListChromosome fitnessFunction,
+ AbstractListChromosomeDecoder fitnessFunction,
+ AbstractListChromosomeDecoder fitnessFunction,
+ AbstractListChromosomeDecoder fitnessFunction,
+ AbstractListChromosomeDecoder newChromosome(List phenotype of chromosome
+ * @param length length of chromosome genotype
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link AbstractListChromosomeDecoder}
+ * @param min minimum inclusive value generated as allele
+ * @param max maximum exclusive value generated as allele
+ * @return A real-valued chromosome
+ */
+ public static RealValuedChromosome randomChromosome(int length, FitnessFunction fitnessFunction,
+ AbstractListChromosomeDecoder
+ * The first time {@link #isSatisfied(Population)} is invoked, the end time of
+ * the evolution is determined based on the provided phenotype of chromosome
+ * @since 3.1
+ */
+public class FixedElapsedTime implements StoppingCondition {
+
+ /** Maximum allowed time period (in nanoseconds). */
+ private final long maxTimePeriod;
+
+ /** The predetermined termination time (stopping condition). */
+ private long endTime = -1;
+
+ /**
+ * Create a new {@link FixedElapsedTime} instance.
+ *
+ * @param maxTime maximum number of seconds generations are allowed to evolve
+ */
+ public FixedElapsedTime(final long maxTime) {
+ this(maxTime, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Create a new {@link FixedElapsedTime} instance.
+ *
+ * @param maxTime maximum time generations are allowed to evolve
+ * @param unit {@link TimeUnit} of the maxTime argument
+ */
+ public FixedElapsedTime(final long maxTime, final TimeUnit unit) {
+ if (maxTime < 0) {
+ throw new GeneticException(GeneticException.TOO_SMALL, maxTime, 0);
+ }
+ maxTimePeriod = unit.toNanos(maxTime);
+ }
+
+ /**
+ * Determine whether or not the maximum allowed time has passed. The termination
+ * time is determined after the first generation.
+ *
+ * @return population) {
+ if (endTime < 0) {
+ endTime = System.nanoTime() + maxTimePeriod;
+ }
+
+ return System.nanoTime() >= endTime;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/FixedGenerationCount.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/FixedGenerationCount.java
new file mode 100644
index 0000000000..c1f1503ac9
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/FixedGenerationCount.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.convergencecond;
+
+import org.apache.commons.math4.ga.exception.GeneticException;
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Stops after a fixed number of generations.
+ *
+ * Each time {@link #isSatisfied(Population)} is invoked, a generation counter
+ * is incremented. Once the counter reaches the configured
+ * {@code maxGenerations} value, {@link #isSatisfied(Population)} returns true.
+ *
+ * @param phenotype of chromosome
+ * @since 2.0
+ */
+public class FixedGenerationCount implements StoppingCondition {
+ /** Number of generations that have passed. */
+ private int numGenerations;
+
+ /** Maximum number of generations (stopping criteria). */
+ private final int maxGenerations;
+
+ /**
+ * Create a new FixedGenerationCount instance.
+ *
+ * @param maxGenerations number of generations to evolve
+ */
+ public FixedGenerationCount(final int maxGenerations) {
+ if (maxGenerations <= 0) {
+ throw new GeneticException(GeneticException.TOO_SMALL, maxGenerations, 1);
+ }
+ this.maxGenerations = maxGenerations;
+ }
+
+ /**
+ * Determine whether or not the given number of generations have passed.
+ * Increments the number of generations counter if the maximum has not been
+ * reached.
+ *
+ * @return population) {
+ if (this.numGenerations < this.maxGenerations) {
+ numGenerations++;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns the number of generations that have already passed.
+ * @return the number of generations that have passed
+ */
+ public int getNumGenerations() {
+ return numGenerations;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/StoppingCondition.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/StoppingCondition.java
new file mode 100644
index 0000000000..1e85c9b329
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/StoppingCondition.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.convergencecond;
+
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Algorithm used to determine when to stop evolution.
+ *
+ * @param phenotype of chromosome
+ * @since 2.0
+ */
+public interface StoppingCondition {
+
+ /**
+ * Determine whether or not the given population satisfies the stopping
+ * condition.
+ * @param population population of chromosome
+ *
+ * @return population);
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/UnchangedBestFitness.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/UnchangedBestFitness.java
new file mode 100644
index 0000000000..f41ad54ac4
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/UnchangedBestFitness.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.convergencecond;
+
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * This class represents a stopping condition based on best fitness value.
+ * Convergence will be stopped once best fitness remains unchanged for
+ * predefined number of generations.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public class UnchangedBestFitness implements StoppingCondition {
+
+ /** best fitness of previous generation. **/
+ private double lastBestFitness = Double.MIN_VALUE;
+
+ /**
+ * The configured number of generations for which optimization process will
+ * continue with unchanged best fitness value.
+ **/
+ private final int maxGenerationsWithUnchangedBestFitness;
+
+ /** Number of generations the best fitness value has not been changed. **/
+ private int generationsHavingUnchangedBestFitness;
+
+ /**
+ * constructor.
+ * @param maxGenerationsWithUnchangedAverageFitness maximum number of
+ * generations with unchanged
+ * best fitness
+ */
+ public UnchangedBestFitness(final int maxGenerationsWithUnchangedAverageFitness) {
+ this.maxGenerationsWithUnchangedBestFitness = maxGenerationsWithUnchangedAverageFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isSatisfied(Population population) {
+ final double currentBestFitness = population.getFittestChromosome().evaluate();
+
+ if (lastBestFitness == currentBestFitness) {
+ generationsHavingUnchangedBestFitness++;
+ if (generationsHavingUnchangedBestFitness == maxGenerationsWithUnchangedBestFitness) {
+ return true;
+ }
+ } else {
+ this.generationsHavingUnchangedBestFitness = 0;
+ lastBestFitness = currentBestFitness;
+ }
+
+ return false;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/UnchangedMeanFitness.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/UnchangedMeanFitness.java
new file mode 100644
index 0000000000..21255b2333
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/UnchangedMeanFitness.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.convergencecond;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * This class represents a stopping condition based on mean fitness value.
+ * Convergence will be stopped once mean fitness remains unchanged for
+ * predefined number of generations.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public class UnchangedMeanFitness implements StoppingCondition {
+
+ /** Mean fitness of previous generation. **/
+ private double lastMeanFitness = Double.MIN_VALUE;
+
+ /**
+ * The configured number of generations for which optimization process will
+ * continue with unchanged best fitness value.
+ **/
+ private final int maxGenerationsWithUnchangedMeanFitness;
+
+ /** Number of generations the mean fitness value has not been changed. **/
+ private int generationsHavingUnchangedMeanFitness;
+
+ /**
+ * constructor.
+ * @param maxGenerationsWithUnchangedMeanFitness maximum number of generations
+ * with unchanged mean fitness
+ */
+ public UnchangedMeanFitness(final int maxGenerationsWithUnchangedMeanFitness) {
+ this.maxGenerationsWithUnchangedMeanFitness = maxGenerationsWithUnchangedMeanFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isSatisfied(Population population) {
+
+ final double currentMeanFitness = calculateMeanFitness(population);
+
+ if (lastMeanFitness == currentMeanFitness) {
+ generationsHavingUnchangedMeanFitness++;
+ if (generationsHavingUnchangedMeanFitness == maxGenerationsWithUnchangedMeanFitness) {
+ return true;
+ }
+ } else {
+ this.generationsHavingUnchangedMeanFitness = 0;
+ lastMeanFitness = currentMeanFitness;
+ }
+
+ return false;
+ }
+
+ /**
+ * calculates mean fitness of the population.
+ * @param population
+ * @return mean fitness
+ */
+ private double calculateMeanFitness(Population population) {
+ double totalFitness = 0.0;
+ for (Chromosome chromosome : population) {
+ totalFitness += chromosome.evaluate();
+ }
+ return totalFitness / population.getPopulationSize();
+ }
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/package-info.java
new file mode 100644
index 0000000000..df73f6996a
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergencecond/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/**
+ * This package provides Genetic Algorithms components and implementations.
+ */
+package org.apache.commons.math4.ga.convergencecond;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicy.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicy.java
new file mode 100644
index 0000000000..e254a621b4
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicy.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.crossover;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.utils.RandomGenerator;
+
+/**
+ * An abstraction to represent the base crossover policy.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractChromosomeCrossoverPolicy implements CrossoverPolicy {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ChromosomePair crossover(final Chromosome first, final Chromosome second,
+ final double crossoverRate) {
+ if (RandomGenerator.getRandomGenerator().nextDouble() < crossoverRate) {
+ return crossover(first, second);
+ } else {
+ return new ChromosomePair<>(first, second);
+ }
+ }
+
+ /**
+ * Performs crossover of two chromosomes.
+ * @param first The first parent chromosome participating in crossover
+ * @param second The second parent chromosome participating in crossover
+ * @return chromosome pair
+ */
+ protected abstract ChromosomePair crossover(Chromosome first, Chromosome second);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractListChromosomeCrossoverPolicy.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractListChromosomeCrossoverPolicy.java
new file mode 100644
index 0000000000..6136282e3e
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractListChromosomeCrossoverPolicy.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.crossover;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.exception.GeneticException;
+
+/**
+ * An abstraction of crossover policy for list chromosomes.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractListChromosomeCrossoverPolicy {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public ChromosomePair crossover(final Chromosome first, final Chromosome second) {
+ // check for validity.
+ checkValidity(first, second);
+
+ final AbstractListChromosome first, final Chromosome second) {
+ if (!(first instanceof AbstractListChromosome, ?> && second instanceof AbstractListChromosome, ?>)) {
+ throw new GeneticException(GeneticException.INVALID_FIXED_LENGTH_CHROMOSOME);
+ }
+ final AbstractListChromosome mate(AbstractListChromosome phenotype of chromosome
+ * @since 2.0
+ */
+public interface CrossoverPolicy {
+
+ /**
+ * Perform a crossover operation on the given chromosomes.
+ *
+ * @param first the first chromosome.
+ * @param second the second chromosome.
+ * @param crossoverRate the probability of crossover
+ * @return the pair of new chromosomes that resulted from the crossover.
+ */
+ ChromosomePair crossover(Chromosome first, Chromosome second, double crossoverRate);
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/CycleCrossover.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/CycleCrossover.java
new file mode 100644
index 0000000000..c0a1678e8b
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/CycleCrossover.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.crossover;
+
+import java.util.ArrayList;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.utils.RandomGenerator;
+
+/**
+ * Cycle Crossover [CX] builds offspring from ordered chromosomes by
+ * identifying cycles between two parent chromosomes. To form the children, the
+ * cycles are copied from the respective parents.
+ *
+ * To form a cycle the following procedure is applied:
+ * phenotype of chromosome
+ * @since 3.1
+ */
+public class CycleCrossover mate(final AbstractListChromosome phenotype of chromosome
+ * @since 3.1
+ */
+public class NPointCrossover
+ * Note: the number of crossover points must be <
+ * mate(final AbstractListChromosome phenotype of chromosome
+ * @since 2.0
+ *
+ */
+public class OnePointCrossover mate(final AbstractListChromosome
+ * This policy works by applying the following rules:
+ *
+ * Example (random sublist from index 3 to 7, underlined):
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @see
+ * Order 1 Crossover Operator
+ *
+ * @param phenotype of chromosome
+ * @since 3.1
+ */
+public class OrderedCrossover mate(final AbstractListChromosome
+ * This crossover policy evaluates each gene of the parent chromosomes by
+ * choosing a uniform random number {@code p} in the range [0, 1]. If {@code p}
+ * < {@code ratio}, the parent genes are swapped. This means with a ratio of
+ * 0.7, 30% of the genes from the first parent and 70% from the second parent
+ * will be selected for the first offspring (and vice versa for the second
+ * offspring).
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @see Crossover
+ * techniques (Wikipedia)
+ * @see Crossover
+ * (Obitko.com)
+ * @see Uniform
+ * crossover
+ * @param phenotype of chromosome
+ * @since 3.1
+ */
+public class UniformCrossover mate(final AbstractListChromosome phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractListChromosomeDecoder {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public P decode(Chromosome chromosome) {
+ checkValidity(chromosome);
+
+ return decode((AbstractListChromosome chromosome) {
+ if (!AbstractListChromosome.class.isAssignableFrom(chromosome.getClass())) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, chromosome.getClass().getSimpleName());
+ }
+ }
+
+ /**
+ * Decodes the chromosome genotype and returns the phenotype.
+ * @param chromosome The list chromosome to decode
+ * @return decoded phenotype of chromosome
+ */
+ protected abstract P decode(AbstractListChromosome phenotype of chromosome
+ * @since 4.0
+ */
+public interface Decoder {
+
+ /**
+ * Converts genotype to phenotype.
+ * @param chromosome The {@link Chromosome}
+ * @return phenotype The phenotype of chromosome
+ */
+ P decode(Chromosome chromosome);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/RandomKeyDecoder.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/RandomKeyDecoder.java
new file mode 100644
index 0000000000..8a096828e2
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/RandomKeyDecoder.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.decoder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.ValidationUtils;
+
+/**
+ * A concrete implementation of RandomKey decoder. This class is responsible for
+ * decoding permutation chromosome encoded with random key.
+ * @param type of the permutation element
+ * @since 4.0
+ */
+public final class RandomKeyDecoder extends AbstractListChromosomeDecoder phenotype of chromosome
+ * @since 4.0
+ */
+public interface FitnessFunction {
+
+ /**
+ * computes the fitness value of the input chromosome's phenotype.
+ * @param decodedChromosome chromosome decoded as phenotype
+ * @return fitness value
+ */
+ double compute(P decodedChromosome);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/fitness/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/fitness/package-info.java
new file mode 100644
index 0000000000..5b6d4c5203
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/fitness/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/**
+ * This package provides Genetic Algorithms components and implementations.
+ */
+package org.apache.commons.math4.ga.fitness;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/ConvergenceListener.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/ConvergenceListener.java
new file mode 100644
index 0000000000..f99d585687
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/ConvergenceListener.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.listener;
+
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * This interface represents a convergence listener. Any implementation of the
+ * same will be notified about the population statics.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public interface ConvergenceListener {
+
+ /**
+ * Notifies about the population statistics.
+ * @param generation current generation
+ * @param population population of chromosome
+ */
+ void notify(int generation, Population population);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/ConvergenceListenerRegistry.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/ConvergenceListenerRegistry.java
new file mode 100644
index 0000000000..033060e57b
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/ConvergenceListenerRegistry.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.listener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.utils.ValidationUtils;
+
+/**
+ * This class is the default implementation of ConvergenceListenerRegistry. It
+ * will be responsible for registering the interested listeners and notifying
+ * all when required.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public final class ConvergenceListenerRegistry {
+
+ /**
+ * The instance of the singleton class.
+ */
+ @SuppressWarnings("rawtypes")
+ private static final ConvergenceListenerRegistry INSTANCE = new ConvergenceListenerRegistry<>();
+
+ /**
+ * List of registered listeners.
+ */
+ private final List convergenceListener) {
+ this.listeners.add(convergenceListener);
+ }
+
+ /**
+ * Notifies all registered ConvergenceListeners about the population statistics.
+ * @param generation current generation
+ * @param population population of chromosomes
+ */
+ public void notifyAll(int generation, Population population) {
+ for (ConvergenceListener convergenceListener : listeners) {
+ convergenceListener.notify(generation, population);
+ }
+ }
+
+ /**
+ * Add instance of convergence listener.
+ * @param convergenceListeners list of {@link ConvergenceListener}
+ */
+ public void addConvergenceListeners(List convergenceListener : convergenceListeners) {
+ addConvergenceListener(convergenceListener);
+ }
+ }
+
+ /**
+ * Returns instance of this class.
+ * @param The phenotype of chromosome
+ * @return instance
+ */
+ @SuppressWarnings("unchecked")
+ public static ConvergenceListenerRegistry getInstance() {
+ return INSTANCE;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/PopulationStatisticsLogger.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/PopulationStatisticsLogger.java
new file mode 100644
index 0000000000..ec76df3817
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/PopulationStatisticsLogger.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.listener;
+
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+import org.apache.commons.math4.ga.stats.internal.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.utils.ConsoleLogger;
+
+/**
+ * Logs population statistics during the convergence process.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public final class PopulationStatisticsLogger implements ConvergenceListener {
+
+ /** instance of consolelogger. **/
+ private ConsoleLogger consoleLogger;
+
+ public PopulationStatisticsLogger(String encoding) {
+ this.consoleLogger = ConsoleLogger.getInstance(encoding);
+ }
+
+ /**
+ * Logs the population statistics to console during the process of convergence.
+ */
+ @Override
+ public void notify(int generation, Population population) {
+ final PopulationStatisticalSummary populationStatisticalSummary = new PopulationStatisticalSummaryImpl<>(
+ population);
+ consoleLogger.log(
+ "Population statistics for generation %d ::: Mean Fitness: %f, Max Fitness: %f, Fitness Variance: %f",
+ generation, populationStatisticalSummary.getMeanFitness(), populationStatisticalSummary.getMaxFitness(),
+ populationStatisticalSummary.getFitnessVariance());
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/package-info.java
new file mode 100644
index 0000000000..f2e0d4a83b
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/**
+ * This package provides Genetic Algorithms components and implementations.
+ */
+package org.apache.commons.math4.ga.listener;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/AbstractListChromosomeMutationPolicy.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/AbstractListChromosomeMutationPolicy.java
new file mode 100644
index 0000000000..a38c348ec5
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/AbstractListChromosomeMutationPolicy.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.commons.math4.ga.mutation;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.utils.RandomGenerator;
+
+/**
+ * This abstraction represents an abstract mutation policy for ListChromosomes.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractListChromosomeMutationPolicy {
+
+ /**
+ * Mutate the given chromosome. Randomly changes few genes depending on mutation
+ * rate.
+ * @param original the original chromosome.
+ * @param mutationRate the rate of mutation per gene
+ * @return the mutated chromosome.
+ */
+ @Override
+ public Chromosome mutate(Chromosome original, double mutationRate) {
+ // check for validity.
+ checkValidity(original);
+
+ @SuppressWarnings("unchecked")
+ final AbstractListChromosome original);
+
+ /**
+ * Selects and returns mutable gene indexes based on mutation rate.
+ * @param length no of alleles/genes in chromosome
+ * @param mutationRate mutation rate of the allele/gene
+ * @return mutable gene indexes
+ */
+ protected Set phenotype of chromosome
+ * @since 4.0
+ */
+public class BinaryMutation extends IntegralValuedMutation {
+
+ public BinaryMutation() {
+ super(0, 2);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void checkValidity(Chromosome original) {
+ super.checkValidity(original);
+ if (!BinaryChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, original.getClass().getSimpleName());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Integer mutateGene(Integer originalValue) {
+ return originalValue == 0 ? 1 : 0;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/IntegralValuedMutation.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/IntegralValuedMutation.java
new file mode 100644
index 0000000000..5ae9d794e4
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/IntegralValuedMutation.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.mutation;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.chromosome.IntegralValuedChromosome;
+import org.apache.commons.math4.ga.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomGenerator;
+import org.apache.commons.math4.ga.utils.ValidationUtils;
+
+/**
+ * Mutation for {@link IntegralValuedChromosome}. Randomly changes few genes.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public class IntegralValuedMutation extends AbstractListChromosomeMutationPolicy original) {
+ if (!IntegralValuedChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, original.getClass().getSimpleName());
+ }
+ IntegralValuedChromosome chromosome = (IntegralValuedChromosome ) original;
+ if (chromosome.getMin() != this.min || chromosome.getMax() != this.max) {
+ throw new GeneticException(GeneticException.ILLEGAL_RANGE, this.min, this.max, chromosome.getMin(),
+ chromosome.getMax());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Integer mutateGene(Integer originalValue) {
+ return min + RandomGenerator.getRandomGenerator().nextInt(max - min);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/MutationPolicy.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/MutationPolicy.java
new file mode 100644
index 0000000000..66bdbc3516
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/MutationPolicy.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.mutation;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+
+/**
+ * Algorithm used to mutate a chromosome.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public interface MutationPolicy {
+
+ /**
+ * Mutate the given chromosome.
+ * @param original the original chromosome.
+ * @param mutationRate The probability of mutation
+ * @return the mutated chromosome.
+ */
+ Chromosome mutate(Chromosome original, double mutationRate);
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/RealValuedMutation.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/RealValuedMutation.java
new file mode 100644
index 0000000000..c999dde8d3
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/RealValuedMutation.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.mutation;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.chromosome.RealValuedChromosome;
+import org.apache.commons.math4.ga.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomGenerator;
+import org.apache.commons.math4.ga.utils.ValidationUtils;
+
+/**
+ * This class mutates real-valued chromosome.
+ * @param phenotype of chromosome
+ * @since 4.0
+ */
+public class RealValuedMutation extends AbstractListChromosomeMutationPolicy original) {
+ if (!RealValuedChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, original.getClass().getSimpleName());
+ }
+ RealValuedChromosome chromosome = (RealValuedChromosome ) original;
+ if (chromosome.getMin() != this.min || chromosome.getMax() != this.max) {
+ throw new GeneticException(GeneticException.ILLEGAL_RANGE, this.min, this.max, chromosome.getMin(),
+ chromosome.getMax());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Double mutateGene(Double originalValue) {
+ return min + RandomGenerator.getRandomGenerator().nextDouble() * (max - min);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/package-info.java
new file mode 100644
index 0000000000..30c90e46cb
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/**
+ * This package provides Genetic Algorithms components and implementations.
+ */
+package org.apache.commons.math4.ga.mutation;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/package-info.java
new file mode 100644
index 0000000000..40fa263981
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/**
+ * This package provides Genetic Algorithms components and implementations.
+ */
+package org.apache.commons.math4.ga;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/ListPopulation.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/ListPopulation.java
new file mode 100644
index 0000000000..15518bb0db
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/ListPopulation.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.commons.math4.ga.population;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.Constants;
+import org.apache.commons.math4.ga.utils.ValidationUtils;
+
+/**
+ * Population of chromosomes represented by a {@link List}.
+ *
+ * @param phenotype of chromosome
+ * @since 2.0
+ */
+public class ListPopulation implements Population {
+
+ /** List of chromosomes. */
+ private final List
+ * Note: the chromosomes of the specified list are added to the population.
+ *
+ * @param chromosomes list of chromosomes to be added to the population
+ * @param populationLimit maximal size of the population
+ */
+ public ListPopulation(final Listthis
is, with a
+ * given arrayRepresentation
. This is needed in crossover and
+ * mutation operators, where we need a new instance of the same class, but with
+ * different array representation.
+ * representation
can represent a valid chromosome.
+ */
+ private void checkValidity() {
+ ValidationUtils.checkForMinMax(min, max);
+ for (int i : getRepresentation()) {
+ if (i < min || i >= max) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, i);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IntegralValuedChromosomerepresentation
can represent a valid chromosome.
+ */
+ private void checkValidity() {
+ ValidationUtils.checkForMinMax(min, max);
+ for (double i : getRepresentation()) {
+ if (i < min || i >= max) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, i);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public RealValuedChromosomemaxTime
value.
+ * Once the elapsed time reaches the configured maxTime
value,
+ * {@link #isSatisfied(Population)} returns true.
+ *
+ * @param true
IFF the maximum allowed time period has elapsed
+ */
+ @Override
+ public boolean isSatisfied(Populationtrue
IFF the maximum number of generations has been
+ * exceeded
+ */
+ @Override
+ public boolean isSatisfied(Populationtrue
if this stopping condition is met by the given
+ * population, false
otherwise.
+ */
+ boolean isSatisfied(Population
+ *
+ * The indices that form a cycle are then used to form the children in
+ * alternating order, i.e. in cycle 1, the genes of parent 1 are copied to child
+ * 1, while in cycle 2 the genes of parent 1 are copied to child 2, and so forth
+ * ...
+ *
+ * Example (zero-start cycle):
+ *
+ * p1 = (8 4 7 3 6 2 5 1 9 0) X c1 = (8 1 2 3 4 5 6 7 9 0)
+ * p2 = (0 1 2 3 4 5 6 7 8 9) X c2 = (0 4 7 3 6 2 5 1 8 9)
+ *
+ * cycle 1: 8 0 9
+ * cycle 2: 4 1 7 2 5 6
+ * cycle 3: 3
+ *
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @see
+ * Cycle Crossover Operator
+ * @param
+ * -C- denotes a crossover point
+ * -C- -C- -C- -C-
+ * p1 = (1 0 | 1 0 0 1 | 0 1 1) X p2 = (0 1 | 1 0 1 0 | 1 1 1)
+ * \----/ \-------/ \-----/ \----/ \--------/ \-----/
+ * || (*) || || (**) ||
+ * VV (**) VV VV (*) VV
+ * /----\ /--------\ /-----\ /----\ /--------\ /-----\
+ * c1 = (1 0 | 1 0 1 0 | 0 1 1) X c2 = (0 1 | 1 0 0 1 | 0 1 1)
+ *
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @param chromosome length - 1
. This condition can only be checked at
+ * runtime, as the chromosome length is not known in advance.
+ *
+ * @param crossoverPoints the number of crossover points
+ */
+ public NPointCrossover(final int crossoverPoints) {
+ if (crossoverPoints <= 0) {
+ throw new GeneticException(GeneticException.NOT_STRICTLY_POSITIVE, crossoverPoints);
+ }
+ this.crossoverPoints = crossoverPoints;
+ }
+
+ /**
+ * Returns the number of crossover points used by this {@link CrossoverPolicy}.
+ *
+ * @return the number of crossover points
+ */
+ public int getCrossoverPoints() {
+ return crossoverPoints;
+ }
+
+ /**
+ * Performs a N-point crossover. N random crossover points are selected and are
+ * used to divide the parent chromosomes into segments. The segments are copied
+ * in alternate order from the two parents to the corresponding child
+ * chromosomes.
+ *
+ * Example (2-point crossover):
+ *
+ * -C- denotes a crossover point
+ * -C- -C- -C- -C-
+ * p1 = (1 0 | 1 0 0 1 | 0 1 1) X p2 = (0 1 | 1 0 1 0 | 1 1 1)
+ * \----/ \-------/ \-----/ \----/ \--------/ \-----/
+ * || (*) || || (**) ||
+ * VV (**) VV VV (*) VV
+ * /----\ /--------\ /-----\ /----\ /--------\ /-----\
+ * c1 = (1 0 | 1 0 1 0 | 0 1 1) X c2 = (0 1 | 1 0 0 1 | 0 1 1)
+ *
+ *
+ * @param first first parent (p1)
+ * @param second second parent (p2)
+ * @return pair of two children (c1,c2)
+ */
+ @Override
+ protected ChromosomePair
+ * -C- denotes a crossover point
+ * -C- -C-
+ * p1 = (1 0 1 0 0 1 | 0 1 1) X p2 = (0 1 1 0 1 0 | 1 1 1)
+ * \------------/ \-----/ \------------/ \-----/
+ * || (*) || (**)
+ * VV (**) VV (*)
+ * /------------\ /-----\ /------------\ /-----\
+ * c1 = (1 0 1 0 0 1 | 1 1 1) X c2 = (0 1 1 0 1 0 | 0 1 1)
+ *
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @param
+ * -C- denotes a crossover point
+ * -C- -C-
+ * p1 = (1 0 1 0 0 1 | 0 1 1) X p2 = (0 1 1 0 1 0 | 1 1 1)
+ * \------------/ \-----/ \------------/ \-----/
+ * || (*) || (**)
+ * VV (**) VV (*)
+ * /------------\ /-----\ /------------\ /-----\
+ * c1 = (1 0 1 0 0 1 | 1 1 1) X c2 = (0 1 1 0 1 0 | 0 1 1)
+ *
+ *
+ * @param first first parent (p1)
+ * @param second second parent (p2)
+ * @return pair of two children (c1,c2)
+ */
+ @Override
+ protected ChromosomePair
+ *
+ *
+ * p1 = (8 4 7 3 6 2 5 1 9 0) X c1 = (0 4 7 3 6 2 5 1 8 9)
+ * --------- ---------
+ * p2 = (0 1 2 3 4 5 6 7 8 9) X c2 = (8 1 2 3 4 5 6 7 9 0)
+ *
+ *