You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2022/01/25 13:29:12 UTC
[commons-math] 02/06: MATH-1563: Introducing new implementation of GA functionality (WIP).
This is an automated email from the ASF dual-hosted git repository.
erans pushed a commit to branch feature__MATH-1563__genetic_algorithm
in repository https://gitbox.apache.org/repos/asf/commons-math.git
commit 5d71c14523ed9a033abeeca6b00db4759189adf7
Author: avbasak1 <av...@in.ibm.com>
AuthorDate: Sun Jan 2 18:54:37 2022 +0530
MATH-1563: Introducing new implementation of GA functionality (WIP).
---
.../examples-ga/examples-ga-math-functions/pom.xml | 47 ++++
.../mathfunctions/dimension2/Dim2GraphPlotter.java | 145 ++++++++++
.../dimension2/Dimension2Coordinate.java | 64 +++++
.../dimension2/Dimension2Decoder.java | 49 ++++
.../dimension2/Dimension2FitnessFunction.java | 40 +++
.../Dimension2FunctionAdaptiveOptimizer.java | 114 ++++++++
.../dimension2/Dimension2FunctionOptimizer.java | 114 ++++++++
.../legacy/Dimension2FunctionOptimizerLegacy.java | 103 +++++++
.../dimension2/legacy/LegacyBinaryChromosome.java | 65 +++++
.../dimension2/legacy/UnchangedBestFitness.java | 67 +++++
.../dimension2/legacy/package-info.java | 20 ++
.../ga/mathfunctions/dimension2/package-info.java | 20 ++
.../mathfunctions/dimensionN/DimNGraphPlotter.java | 145 ++++++++++
.../dimensionN/DimensionNCoordinate.java | 54 ++++
.../dimensionN/DimensionNDecoder.java | 52 ++++
.../dimensionN/DimensionNFitnessFunction.java | 42 +++
.../DimensionNFunctionAdaptiveOptimizer.java | 114 ++++++++
.../dimensionN/DimensionNFunctionOptimizer.java | 113 ++++++++
.../ga/mathfunctions/dimensionN/package-info.java | 20 ++
.../examples/ga/mathfunctions/utils/Constants.java | 55 ++++
.../ga/mathfunctions/utils/package-info.java | 20 ++
.../examples-ga/examples-ga-tsp/pom.xml | 52 ++++
.../math4/examples/ga/tsp/TSPFitnessFunction.java | 52 ++++
.../math4/examples/ga/tsp/TSPOptimizer.java | 116 ++++++++
.../math4/examples/ga/tsp/commons/City.java | 77 ++++++
.../examples/ga/tsp/commons/DistanceMatrix.java | 71 +++++
.../examples/ga/tsp/commons/package-info.java | 20 ++
.../examples/ga/tsp/legacy/TSPChromosome.java | 76 ++++++
.../examples/ga/tsp/legacy/TSPOptimizerLegacy.java | 99 +++++++
.../ga/tsp/legacy/UnchangedBestFitness.java | 67 +++++
.../math4/examples/ga/tsp/legacy/package-info.java | 20 ++
.../math4/examples/ga/tsp/package-info.java | 20 ++
.../math4/examples/ga/tsp/utils/Constants.java | 65 +++++
.../math4/examples/ga/tsp/utils/GraphPlotter.java | 146 ++++++++++
.../math4/examples/ga/tsp/utils/package-info.java | 20 ++
commons-math-examples/examples-ga/pom.xml | 56 ++++
commons-math-examples/pom.xml | 1 +
commons-math-ga/pom.xml | 54 ++++
.../commons/math4/ga/AbstractGeneticAlgorithm.java | 180 ++++++++++++
.../commons/math4/ga/AdaptiveGeneticAlgorithm.java | 164 +++++++++++
.../apache/commons/math4/ga/GeneticAlgorithm.java | 171 ++++++++++++
.../math4/ga/chromosome/AbstractChromosome.java | 148 ++++++++++
.../ga/chromosome/AbstractListChromosome.java | 125 +++++++++
.../math4/ga/chromosome/BinaryChromosome.java | 303 +++++++++++++++++++++
.../commons/math4/ga/chromosome/Chromosome.java | 48 ++++
.../math4/ga/chromosome/ChromosomePair.java | 66 +++++
.../ga/chromosome/IntegralValuedChromosome.java | 136 +++++++++
.../math4/ga/chromosome/RealValuedChromosome.java | 160 +++++++++++
.../commons/math4/ga/chromosome/package-info.java | 20 ++
.../math4/ga/convergence/FixedElapsedTime.java | 80 ++++++
.../math4/ga/convergence/FixedGenerationCount.java | 76 ++++++
.../math4/ga/convergence/StoppingCondition.java | 38 +++
.../math4/ga/convergence/UnchangedBestFitness.java | 72 +++++
.../math4/ga/convergence/UnchangedMeanFitness.java | 85 ++++++
.../commons/math4/ga/convergence/package-info.java | 20 ++
.../AbstractChromosomeCrossoverPolicy.java | 53 ++++
.../AbstractListChromosomeCrossoverPolicy.java | 76 ++++++
.../math4/ga/crossover/CrossoverPolicy.java | 39 +++
.../commons/math4/ga/crossover/CycleCrossover.java | 168 ++++++++++++
.../math4/ga/crossover/NPointCrossover.java | 154 +++++++++++
.../ga/crossover/OnePointBinaryCrossover.java | 115 ++++++++
.../math4/ga/crossover/OnePointCrossover.java | 102 +++++++
.../math4/ga/crossover/OrderedCrossover.java | 131 +++++++++
.../math4/ga/crossover/UniformCrossover.java | 123 +++++++++
.../commons/math4/ga/crossover/package-info.java | 20 ++
...nearAverageRankBasedCrossoverRateGenerator.java | 58 ++++
...nearMaximumRankBasedCrossoverRateGenerator.java | 58 ++++
.../ConstantCrossoverRateGenerator.java | 50 ++++
.../rategenerator/CrossoverRateGenerator.java | 42 +++
.../ga/crossover/rategenerator/package-info.java | 20 ++
.../ga/decoder/AbstractListChromosomeDecoder.java | 59 ++++
.../apache/commons/math4/ga/decoder/Decoder.java | 35 +++
.../commons/math4/ga/decoder/RandomKeyDecoder.java | 75 +++++
.../decoder/TransparentListChromosomeDecoder.java | 39 +++
.../commons/math4/ga/decoder/package-info.java | 20 ++
.../commons/math4/ga/fitness/FitnessFunction.java | 34 +++
.../commons/math4/ga/fitness/package-info.java | 20 ++
.../ga/internal/exception/GeneticException.java | 120 ++++++++
.../math4/ga/internal/exception/package-info.java | 20 ++
.../stats/PopulationStatisticalSummaryImpl.java | 177 ++++++++++++
.../math4/ga/internal/stats/package-info.java | 20 ++
.../math4/ga/listener/ConvergenceListener.java | 37 +++
.../ga/listener/ConvergenceListenerRegistry.java | 91 +++++++
.../ga/listener/PopulationStatisticsLogger.java | 49 ++++
.../commons/math4/ga/listener/package-info.java | 20 ++
.../AbstractListChromosomeMutationPolicy.java | 101 +++++++
.../commons/math4/ga/mutation/BinaryMutation.java | 135 +++++++++
.../math4/ga/mutation/IntegralValuedMutation.java | 88 ++++++
.../commons/math4/ga/mutation/MutationPolicy.java | 36 +++
.../math4/ga/mutation/RealValuedMutation.java | 97 +++++++
.../commons/math4/ga/mutation/package-info.java | 20 ++
.../AdaptiveLinearMutationRateGenerator.java | 54 ++++
.../ConstantMutationRateGenerator.java | 47 ++++
.../rategenerator/MutationRateGenerator.java | 38 +++
.../ga/mutation/rategenerator/package-info.java | 20 ++
.../org/apache/commons/math4/ga/package-info.java | 20 ++
.../math4/ga/population/ListPopulation.java | 220 +++++++++++++++
.../commons/math4/ga/population/Population.java | 59 ++++
.../commons/math4/ga/population/package-info.java | 20 ++
.../math4/ga/selection/SelectionPolicy.java | 35 +++
.../math4/ga/selection/TournamentSelection.java | 108 ++++++++
.../commons/math4/ga/selection/package-info.java | 20 ++
.../ga/stats/PopulationStatisticalSummary.java | 67 +++++
.../commons/math4/ga/stats/package-info.java | 20 ++
.../ga/utils/ChromosomeRepresentationUtils.java | 211 ++++++++++++++
.../math4/ga/utils/RandomProviderManager.java | 47 ++++
.../commons/math4/ga/utils/package-info.java | 20 ++
.../math4/ga/GeneticAlgorithmTestBinaryOneMax.java | 187 +++++++++++++
.../math4/ga/GeneticAlgorithmTestPermutations.java | 144 ++++++++++
.../ga/chromosome/AbstractChromosomeTest.java | 65 +++++
.../math4/ga/chromosome/BinaryChromosomeTest.java | 92 +++++++
.../math4/ga/chromosome/ChromosomePairTest.java | 38 +++
.../chromosome/IntegralValuedChromosomeTest.java | 93 +++++++
.../ga/chromosome/RealValuedChromosomeTest.java | 75 +++++
.../ga/convergencecond/FixedElapsedTimeTest.java | 59 ++++
.../convergencecond/FixedGenerationCountTest.java | 48 ++++
.../convergencecond/UnchangedBestFitnessTest.java | 68 +++++
.../convergencecond/UnchangedMeanFitnessTest.java | 68 +++++
.../AbstractChromosomeCrossoverPolicyTest.java | 45 +++
.../AbstractListChromosomeCrossoverPolicyTest.java | 77 ++++++
.../math4/ga/crossover/CycleCrossoverTest.java | 115 ++++++++
.../math4/ga/crossover/NPointCrossoverTest.java | 127 +++++++++
.../ga/crossover/OnePointBinaryCrossoverTest.java | 73 +++++
.../math4/ga/crossover/OnePointCrossoverTest.java | 66 +++++
.../math4/ga/crossover/OrderedCrossoverTest.java | 63 +++++
.../math4/ga/crossover/UniformCrossoverTest.java | 113 ++++++++
...MaximumRankBasedCrossoverRateGeneratorTest.java | 68 +++++
.../decoder/AbstractListChromosomeDecoderTest.java | 44 +++
.../math4/ga/decoder/RandomKeyDecoderTest.java | 58 ++++
.../TransparentListChromosomeDecoderTest.java | 39 +++
.../commons/math4/ga/dummy/DummyChromosome.java | 27 ++
.../math4/ga/dummy/DummyListChromosome.java | 47 ++++
.../math4/ga/dummy/DummyListChromosomeDecoder.java | 41 +++
.../math4/ga/exception/GeneticExceptionTest.java | 39 +++
.../listener/ConvergenceListenerRegistryTest.java | 107 ++++++++
.../listener/PopulationStatisticsLoggerTest.java | 45 +++
.../AbstractListChromosomeMutationPolicyTest.java | 44 +++
.../math4/ga/mutation/BinaryMutationTest.java | 90 ++++++
.../ga/mutation/IntegralValuedMutationTest.java | 85 ++++++
.../math4/ga/mutation/RealValuedMutationTest.java | 85 ++++++
.../AdaptiveLinearMutationRateGeneratorTest.java | 61 +++++
.../ConstantMutationRateGeneratorTest.java | 45 +++
.../math4/ga/population/ListPopulationTest.java | 202 ++++++++++++++
.../ga/selection/TournamentSelectionTest.java | 109 ++++++++
.../utils/ChromosomeRepresentationUtilsTest.java | 163 +++++++++++
pom.xml | 1 +
.../resources/spotbugs/spotbugs-exclude-filter.xml | 6 +
147 files changed, 10897 insertions(+)
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/pom.xml b/commons-math-examples/examples-ga/examples-ga-math-functions/pom.xml
new file mode 100644
index 0000000..d09ca3f
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>examples-ga</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>examples-ga-math-functions</artifactId>
+
+ <properties>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+
+ <!-- OSGi -->
+ <commons.osgi.symbolicName>org.apache.commons.math4.examples.ga.mathfunctions</commons.osgi.symbolicName>
+ <commons.osgi.export>org.apache.commons.math4.examples.ga.mathfunctions</commons.osgi.export>
+ <!-- Java 9+ -->
+ <commons.automatic.module.name>org.apache.commons.math4.examples.ga.mathfunctions</commons.automatic.module.name>
+ <!-- Workaround to avoid duplicating config files. -->
+ <math.parent.dir>${basedir}/../../..</math.parent.dir>
+
+ <uberjar.name>examples-ga-mathfunctions</uberjar.name>
+ <project.mainClass>org.apache.commons.math4.examples.ga.mathfunctions.Dimension2FunctionOptimizer</project.mainClass>
+ <slf4jVersion>1.7.32</slf4jVersion>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4jVersion}</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dim2GraphPlotter.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dim2GraphPlotter.java
new file mode 100644
index 0000000..eca37e8
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dim2GraphPlotter.java
@@ -0,0 +1,145 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2;
+
+import java.awt.BorderLayout;
+import java.util.List;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import org.apache.commons.math4.ga.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.listener.ConvergenceListener;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+/**
+ * This class represents the graph plotter during optimization.
+ */
+public class Dim2GraphPlotter extends JFrame implements ConvergenceListener<Dimension2Coordinate> {
+
+ /**
+ * Generated serialversionId.
+ */
+ private static final long serialVersionUID = -5683904006424006584L;
+
+ /** collection of 2-D series. **/
+ private final XYSeriesCollection dataset = new XYSeriesCollection();
+
+ /**
+ * constructor.
+ * @param plotSubject subject of plot
+ * @param xAxisLabel x axis label
+ * @param yAxisLabel y axis label
+ */
+ public Dim2GraphPlotter(String plotSubject, String xAxisLabel, String yAxisLabel) {
+ super(plotSubject);
+
+ final JPanel chartPanel = createChartPanel(plotSubject, xAxisLabel, yAxisLabel);
+ add(chartPanel, BorderLayout.CENTER);
+
+ setSize(640, 480);
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setLocationRelativeTo(null);
+
+ setVisible(true);
+ }
+
+ /**
+ * Adds data point to graph.
+ * @param graphName name of graph
+ * @param generation generation, to be plotted along x axis
+ * @param value value, to be plotted along y axis
+ */
+ private void addDataPoint(String graphName, int generation, double value) {
+ XYSeries series = null;
+
+ if (!containsGraph(graphName)) {
+ series = new XYSeries(graphName);
+ dataset.addSeries(series);
+ } else {
+ series = dataset.getSeries(graphName);
+ }
+ series.add(generation, value);
+
+ setVisible(true);
+ }
+
+ /**
+ * Checks if the graph with the given name already exists.
+ * @param graphName name of the graph
+ * @return true/false
+ */
+ @SuppressWarnings("unchecked")
+ private boolean containsGraph(String graphName) {
+ final List<XYSeries> seriesList = dataset.getSeries();
+ if (seriesList == null || seriesList.isEmpty()) {
+ return false;
+ }
+ for (XYSeries series : seriesList) {
+ if (series.getKey().compareTo(graphName) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates chart panel.
+ * @param chartTitle chart title
+ * @param xAxisLabel x axis label
+ * @param yAxisLabel y axis label
+ * @return panel
+ */
+ private JPanel createChartPanel(String chartTitle, String xAxisLabel, String yAxisLabel) {
+
+ final boolean showLegend = true;
+ final boolean createURL = false;
+ final boolean createTooltip = false;
+
+ final JFreeChart chart = ChartFactory.createXYLineChart(chartTitle, xAxisLabel, yAxisLabel, dataset,
+ PlotOrientation.VERTICAL, showLegend, createTooltip, createURL);
+ final XYPlot plot = chart.getXYPlot();
+ final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
+
+ plot.setRenderer(renderer);
+
+ return new ChartPanel(chart);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void notify(int generation, Population<Dimension2Coordinate> population) {
+ PopulationStatisticalSummary<Dimension2Coordinate> populationStatisticalSummary =
+ new PopulationStatisticalSummaryImpl<>(population);
+ this.addDataPoint("Average", generation, populationStatisticalSummary.getMeanFitness());
+ this.addDataPoint("Best", generation, populationStatisticalSummary.getMaxFitness());
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2Coordinate.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2Coordinate.java
new file mode 100644
index 0000000..307f1ef
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2Coordinate.java
@@ -0,0 +1,64 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2;
+
+/**
+ * This class represents the coordinate of the problem domain i.e. the phenotype of chromosome.
+ */
+public class Dimension2Coordinate {
+
+ /** coordinate of first dimension. **/
+ private final double x;
+
+ /** coordinate of second dimension. **/
+ private final double y;
+
+ /**
+ * constructor.
+ * @param x coordinate of first dimension
+ * @param y coordinate of second dimension
+ */
+ public Dimension2Coordinate(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * returns the coordinate of first dimension.
+ * @return coordinate of first dimension
+ */
+ public double getX() {
+ return x;
+ }
+
+ /**
+ * returns the coordinate of second dimension.
+ * @return coordinate of second dimension
+ */
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * Returns a string representation of coordinate.
+ */
+ @Override
+ public String toString() {
+ return "Coordinate [x=" + x + ", y=" + y + "]";
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2Decoder.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2Decoder.java
new file mode 100644
index 0000000..e8394d1
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2Decoder.java
@@ -0,0 +1,49 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2;
+
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.decoder.Decoder;
+
+/**
+ * Decoder to convert chromosome's binary genotype to phenotype
+ * {@link Dimension2Coordinate}.
+ */
+public class Dimension2Decoder implements Decoder<Dimension2Coordinate> {
+
+ /**
+ * Decode the binary representation of chromosome to
+ * {@link Dimension2Coordinate}.
+ * @param chromosome The {@link Chromosome}
+ */
+ @Override
+ public Dimension2Coordinate decode(Chromosome<Dimension2Coordinate> chromosome) {
+ final BinaryChromosome<Dimension2Coordinate> binaryChromosome =
+ (BinaryChromosome<Dimension2Coordinate>) chromosome;
+ final long alleles = binaryChromosome.getRepresentation()[0];
+
+ long mask1 = ~(Long.MAX_VALUE << 12);
+ long mask2 = ~(Long.MAX_VALUE << 24) ^ mask1;
+
+ final double x = (alleles & mask1) / 100d;
+ final double y = ((alleles & mask2) >> 12) / 100d;
+
+ return new Dimension2Coordinate(x, y);
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FitnessFunction.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FitnessFunction.java
new file mode 100644
index 0000000..33e8f73
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FitnessFunction.java
@@ -0,0 +1,40 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2;
+
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+
+/**
+ * This class represents the mathematical fitness function for optimizing a 2
+ * dimension mathematical function.
+ */
+public class Dimension2FitnessFunction implements FitnessFunction<Dimension2Coordinate> {
+
+ /**
+ * Computes the fitness value based on the decoded chromosome.
+ * @param coordinate The {@link Dimension2Coordinate}
+ * @return the fitness value
+ */
+ @Override
+ public double compute(Dimension2Coordinate coordinate) {
+ return -Math.pow(Math.pow(coordinate.getX(), 2) + Math.pow(coordinate.getY(), 2), .25) *
+ (Math.pow(Math.sin(50 * Math.pow(Math.pow(coordinate.getX(), 2) + Math.pow(coordinate.getY(), 2), .1)),
+ 2) + 1);
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FunctionAdaptiveOptimizer.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FunctionAdaptiveOptimizer.java
new file mode 100644
index 0000000..6579dda
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FunctionAdaptiveOptimizer.java
@@ -0,0 +1,114 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2;
+
+import org.apache.commons.math4.examples.ga.mathfunctions.utils.Constants;
+import org.apache.commons.math4.ga.AdaptiveGeneticAlgorithm;
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.convergence.UnchangedBestFitness;
+import org.apache.commons.math4.ga.crossover.OnePointBinaryCrossover;
+import org.apache.commons.math4.ga.crossover.rategenerator.ConstantCrossoverRateGenerator;
+import org.apache.commons.math4.ga.listener.ConvergenceListenerRegistry;
+import org.apache.commons.math4.ga.listener.PopulationStatisticsLogger;
+import org.apache.commons.math4.ga.mutation.BinaryMutation;
+import org.apache.commons.math4.ga.mutation.rategenerator.AdaptiveLinearMutationRateGenerator;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.TournamentSelection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents an optimizer for a 2-dimensional math function using
+ * genetic algorithm.
+ */
+public class Dimension2FunctionAdaptiveOptimizer {
+
+ /** number of dimension. **/
+ private static final int DIMENSION = 2;
+
+ /** size of tournament. **/
+ private static final int TOURNAMENT_SIZE = 3;
+
+ /** instance of logger. **/
+ private Logger logger = LoggerFactory.getLogger(Dimension2FunctionAdaptiveOptimizer.class);
+
+ /**
+ * Optimizes the 2-dimension fitness function.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+ final Population<Dimension2Coordinate> initPopulation = getInitialPopulation();
+
+ final Dimension2FunctionAdaptiveOptimizer optimizer = new Dimension2FunctionAdaptiveOptimizer();
+
+ final ConvergenceListenerRegistry<Dimension2Coordinate> convergenceListenerRegistry =
+ ConvergenceListenerRegistry.getInstance();
+ convergenceListenerRegistry.addConvergenceListener(new PopulationStatisticsLogger<Dimension2Coordinate>());
+ convergenceListenerRegistry
+ .addConvergenceListener(new Dim2GraphPlotter("Adaptive Convergence Stats", "generation", "fitness"));
+
+ optimizer.optimize(initPopulation);
+ }
+
+ private void optimize(Population<Dimension2Coordinate> initial) {
+
+ // initialize a new genetic algorithm
+ final AdaptiveGeneticAlgorithm<Dimension2Coordinate> ga = new AdaptiveGeneticAlgorithm<>(
+ new OnePointBinaryCrossover<Dimension2Coordinate>(), new ConstantCrossoverRateGenerator<>(1),
+ new BinaryMutation<Dimension2Coordinate>(),
+ new AdaptiveLinearMutationRateGenerator<>(Constants.AVERAGE_MUTATION_RATE / 2,
+ Constants.AVERAGE_MUTATION_RATE * 2),
+ new TournamentSelection<>(TOURNAMENT_SIZE));
+
+ // stopping condition
+ final StoppingCondition<Dimension2Coordinate> stopCond = new UnchangedBestFitness<>(
+ Constants.GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS);
+
+ // run the algorithm
+ final Population<Dimension2Coordinate> finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ final Chromosome<Dimension2Coordinate> bestFinal = finalPopulation.getFittestChromosome();
+
+ logger.info("*********************************************");
+ logger.info("***********Optimization Result***************");
+
+ logger.info(bestFinal.toString());
+
+ }
+
+ /**
+ * Generates an initial population.
+ * @return initial population
+ */
+ private static Population<Dimension2Coordinate> getInitialPopulation() {
+ final Population<Dimension2Coordinate> population = new ListPopulation<>(
+ DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION);
+ final Dimension2FitnessFunction fitnessFunction = new Dimension2FitnessFunction();
+ final Dimension2Decoder decoder = new Dimension2Decoder();
+ for (int i = 0; i < DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION; i++) {
+ population.addChromosome(BinaryChromosome.<Dimension2Coordinate>randomChromosome(
+ DIMENSION * Constants.CHROMOSOME_LENGTH_PER_DIMENSION, fitnessFunction, decoder));
+ }
+ return population;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FunctionOptimizer.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FunctionOptimizer.java
new file mode 100644
index 0000000..1d6a3fa
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/Dimension2FunctionOptimizer.java
@@ -0,0 +1,114 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2;
+
+import org.apache.commons.math4.examples.ga.mathfunctions.utils.Constants;
+import org.apache.commons.math4.ga.GeneticAlgorithm;
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.convergence.UnchangedBestFitness;
+import org.apache.commons.math4.ga.crossover.OnePointBinaryCrossover;
+import org.apache.commons.math4.ga.listener.ConvergenceListenerRegistry;
+import org.apache.commons.math4.ga.listener.PopulationStatisticsLogger;
+import org.apache.commons.math4.ga.mutation.BinaryMutation;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.TournamentSelection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents an optimizer for a 2-dimensional math function using
+ * genetic algorithm.
+ */
+public class Dimension2FunctionOptimizer {
+
+ /** number of dimension. **/
+ private static final int DIMENSION = 2;
+
+ /** size of tournament. **/
+ private static final int TOURNAMENT_SIZE = 3;
+
+ /** instance of logger. **/
+ private Logger logger = LoggerFactory.getLogger(Dimension2FunctionAdaptiveOptimizer.class);
+
+ /**
+ * Optimizes the 2-dimension fitness function.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+ final Population<Dimension2Coordinate> initPopulation = getInitialPopulation();
+
+ final Dimension2FunctionOptimizer optimizer = new Dimension2FunctionOptimizer();
+
+ final ConvergenceListenerRegistry<Dimension2Coordinate> convergenceListenerRegistry =
+ ConvergenceListenerRegistry.getInstance();
+ convergenceListenerRegistry.addConvergenceListener(new PopulationStatisticsLogger<Dimension2Coordinate>());
+ convergenceListenerRegistry
+ .addConvergenceListener(new Dim2GraphPlotter("Convergence Stats", "generation", "fitness"));
+
+ optimizer.optimize(initPopulation);
+ }
+
+ /**
+ * Optimizes the population.
+ * @param initial The {@link Population}
+ */
+ public void optimize(Population<Dimension2Coordinate> initial) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm<Dimension2Coordinate> ga = new GeneticAlgorithm<>(
+ new OnePointBinaryCrossover<Dimension2Coordinate>(), Constants.CROSSOVER_RATE,
+ new BinaryMutation<Dimension2Coordinate>(), Constants.AVERAGE_MUTATION_RATE,
+ new TournamentSelection<Dimension2Coordinate>(TOURNAMENT_SIZE), Constants.ELITISM_RATE);
+
+ // stopping condition
+ final StoppingCondition<Dimension2Coordinate> stopCond = new UnchangedBestFitness<>(
+ Constants.GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS);
+
+ // run the algorithm
+ final Population<Dimension2Coordinate> finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ final Chromosome<Dimension2Coordinate> bestFinal = finalPopulation.getFittestChromosome();
+
+ logger.info("*********************************************");
+ logger.info("***********Optimization Result***************");
+
+ logger.info(bestFinal.toString());
+
+ }
+
+ /**
+ * Generates an initial population.
+ * @return initial population
+ */
+ private static Population<Dimension2Coordinate> getInitialPopulation() {
+ final Population<Dimension2Coordinate> population = new ListPopulation<>(
+ DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION);
+ final Dimension2FitnessFunction fitnessFunction = new Dimension2FitnessFunction();
+ final Dimension2Decoder decoder = new Dimension2Decoder();
+ for (int i = 0; i < DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION; i++) {
+ population.addChromosome(BinaryChromosome.<Dimension2Coordinate>randomChromosome(
+ DIMENSION * Constants.CHROMOSOME_LENGTH_PER_DIMENSION, fitnessFunction, decoder));
+ }
+ return population;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/Dimension2FunctionOptimizerLegacy.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/Dimension2FunctionOptimizerLegacy.java
new file mode 100644
index 0000000..b523d41
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/Dimension2FunctionOptimizerLegacy.java
@@ -0,0 +1,103 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2.legacy;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import org.apache.commons.math3.genetics.BinaryChromosome;
+import org.apache.commons.math3.genetics.BinaryMutation;
+import org.apache.commons.math3.genetics.Chromosome;
+import org.apache.commons.math3.genetics.ElitisticListPopulation;
+import org.apache.commons.math3.genetics.GeneticAlgorithm;
+import org.apache.commons.math3.genetics.OnePointCrossover;
+import org.apache.commons.math3.genetics.Population;
+import org.apache.commons.math3.genetics.StoppingCondition;
+import org.apache.commons.math3.genetics.TournamentSelection;
+import org.apache.commons.math4.examples.ga.mathfunctions.utils.Constants;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+
+/**
+ * This class represents an optimizer for a 2-dimensional math function using
+ * the legacy genetic algorithm.
+ */
+public class Dimension2FunctionOptimizerLegacy {
+
+ /** number of dimension. **/
+ private static final int DIMENSION = 2;
+
+ /** size of tournament. **/
+ private static final int TOURNAMENT_SIZE = 3;
+
+ /**
+ * Optimizes the 2-dimensional fitness function.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+ final Population initPopulation = getInitialPopulation();
+ final Dimension2FunctionOptimizerLegacy simulation = new Dimension2FunctionOptimizerLegacy();
+
+ simulation.optimize(initPopulation);
+ }
+
+ /**
+ * Optimizes the initial population using legacy genetic algorithm.
+ * @param initial initial {@link Population}
+ */
+ public void optimize(Population initial) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm geneticAlgorithm = new GeneticAlgorithm(new OnePointCrossover<>(),
+ Constants.CROSSOVER_RATE, new BinaryMutation(), Constants.AVERAGE_MUTATION_RATE,
+ new TournamentSelection(TOURNAMENT_SIZE));
+
+ // stopping condition
+ final StoppingCondition stopCond = new UnchangedBestFitness(
+ Constants.GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS);
+
+ // run the algorithm
+ final Population finalPopulation = geneticAlgorithm.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ final Chromosome bestFinal = finalPopulation.getFittestChromosome();
+
+ try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out, Constants.ENCODING))) {
+ writer.write("*********************************************");
+ writer.newLine();
+ writer.write("***********Optimization Result***************");
+ writer.write(bestFinal.toString());
+ } catch (IOException e) {
+ throw new GeneticException(e);
+ }
+ }
+
+ /**
+ * Generates the initial population.
+ * @return initial population
+ */
+ private static Population getInitialPopulation() {
+ final Population population = new ElitisticListPopulation(Constants.POPULATION_SIZE_PER_DIMENSION,
+ Constants.ELITISM_RATE);
+ for (int i = 0; i < Constants.POPULATION_SIZE_PER_DIMENSION; i++) {
+ population.addChromosome(new LegacyBinaryChromosome(BinaryChromosome
+ .randomBinaryRepresentation(DIMENSION * Constants.CHROMOSOME_LENGTH_PER_DIMENSION)));
+ }
+ return population;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/LegacyBinaryChromosome.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/LegacyBinaryChromosome.java
new file mode 100644
index 0000000..66c4615
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/LegacyBinaryChromosome.java
@@ -0,0 +1,65 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2.legacy;
+
+import java.util.List;
+
+import org.apache.commons.math3.genetics.AbstractListChromosome;
+import org.apache.commons.math3.genetics.BinaryChromosome;
+
+/**
+ * A representation of concrete binary chromosome.
+ */
+public class LegacyBinaryChromosome extends BinaryChromosome {
+
+ /**
+ * constructor.
+ * @param representation the internal representation
+ */
+ public LegacyBinaryChromosome(List<Integer> representation) {
+ super(representation);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double fitness() {
+ final List<Integer> alleles = getRepresentation();
+
+ final StringBuilder allelesStr = new StringBuilder();
+ for (Integer allele : alleles) {
+ allelesStr.append(Integer.toBinaryString(allele));
+ }
+
+ final double x = Integer.parseInt(allelesStr.substring(0, 12), 2) / 100.0;
+ final double y = Integer.parseInt(allelesStr.substring(12, 24), 2) / 100.0;
+
+ return -Math.pow(Math.pow(x, 2) + Math.pow(y, 2), .25) *
+ (Math.pow(Math.sin(50 * Math.pow(Math.pow(x, 2) + Math.pow(y, 2), .1)), 2) + 1);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AbstractListChromosome<Integer> newFixedLengthChromosome(List<Integer> chromosomeRepresentation) {
+ return new LegacyBinaryChromosome(chromosomeRepresentation);
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/UnchangedBestFitness.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/UnchangedBestFitness.java
new file mode 100644
index 0000000..8800f39
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/UnchangedBestFitness.java
@@ -0,0 +1,67 @@
+/*
+ * 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.examples.ga.mathfunctions.dimension2.legacy;
+
+import org.apache.commons.math3.genetics.Population;
+import org.apache.commons.math3.genetics.StoppingCondition;
+
+/**
+ * This class represents the stopping condition based on unchanged best fitness.
+ */
+public class UnchangedBestFitness implements StoppingCondition {
+
+ /** last best fitness. **/
+ private double lastBestFitness = Double.MIN_VALUE;
+
+ /** maximum number of generations evolved with unchanged best fitness. **/
+ private final int maxGenerationsWithUnchangedBestFitness;
+
+ /** generations having unchanged best fitness. **/
+ private int generationsHavingUnchangedBestFitness;
+
+ /**
+ * constructor.
+ * @param maxGenerationsWithUnchangedAverageFitness maximum number of
+ * generations evolved with
+ * unchanged best fitness
+ */
+ public UnchangedBestFitness(final int maxGenerationsWithUnchangedAverageFitness) {
+ this.maxGenerationsWithUnchangedBestFitness = maxGenerationsWithUnchangedAverageFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isSatisfied(Population population) {
+ final double currentBestFitness = population.getFittestChromosome().getFitness();
+
+ if (lastBestFitness == currentBestFitness) {
+ this.generationsHavingUnchangedBestFitness++;
+ if (generationsHavingUnchangedBestFitness == maxGenerationsWithUnchangedBestFitness) {
+ return true;
+ }
+ } else {
+ this.generationsHavingUnchangedBestFitness = 0;
+ lastBestFitness = currentBestFitness;
+ }
+
+ return false;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/package-info.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/package-info.java
new file mode 100644
index 0000000..7965791
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/legacy/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.examples.ga.mathfunctions.dimension2.legacy;
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/package-info.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/package-info.java
new file mode 100644
index 0000000..432651f
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimension2/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.examples.ga.mathfunctions.dimension2;
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimNGraphPlotter.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimNGraphPlotter.java
new file mode 100644
index 0000000..52571e3
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimNGraphPlotter.java
@@ -0,0 +1,145 @@
+/*
+ * 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.examples.ga.mathfunctions.dimensionN;
+
+import java.awt.BorderLayout;
+import java.util.List;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import org.apache.commons.math4.ga.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.listener.ConvergenceListener;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+/**
+ * This class represents the graph plotter during optimization.
+ */
+public class DimNGraphPlotter extends JFrame implements ConvergenceListener<DimensionNCoordinate> {
+
+ /**
+ * Generated serialversionId.
+ */
+ private static final long serialVersionUID = -5683904006424006584L;
+
+ /** collection of 2-D series. **/
+ private final XYSeriesCollection dataset = new XYSeriesCollection();
+
+ /**
+ * constructor.
+ * @param plotSubject subject of plot
+ * @param xAxisLabel x axis label
+ * @param yAxisLabel y axis label
+ */
+ public DimNGraphPlotter(String plotSubject, String xAxisLabel, String yAxisLabel) {
+ super(plotSubject);
+
+ final JPanel chartPanel = createChartPanel(plotSubject, xAxisLabel, yAxisLabel);
+ add(chartPanel, BorderLayout.CENTER);
+
+ setSize(640, 480);
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setLocationRelativeTo(null);
+
+ setVisible(true);
+ }
+
+ /**
+ * Adds data point to graph.
+ * @param graphName name of graph
+ * @param generation generation, to be plotted along x axis
+ * @param value value, to be plotted along y axis
+ */
+ private void addDataPoint(String graphName, int generation, double value) {
+ XYSeries series = null;
+
+ if (!containsGraph(graphName)) {
+ series = new XYSeries(graphName);
+ dataset.addSeries(series);
+ } else {
+ series = dataset.getSeries(graphName);
+ }
+ series.add(generation, value);
+
+ setVisible(true);
+ }
+
+ /**
+ * Checks if the graph with the given name already exists.
+ * @param graphName name of the graph
+ * @return true/false
+ */
+ @SuppressWarnings("unchecked")
+ private boolean containsGraph(String graphName) {
+ final List<XYSeries> seriesList = dataset.getSeries();
+ if (seriesList == null || seriesList.isEmpty()) {
+ return false;
+ }
+ for (XYSeries series : seriesList) {
+ if (series.getKey().compareTo(graphName) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates chart panel.
+ * @param chartTitle chart title
+ * @param xAxisLabel x axis label
+ * @param yAxisLabel y axis label
+ * @return panel
+ */
+ private JPanel createChartPanel(String chartTitle, String xAxisLabel, String yAxisLabel) {
+
+ final boolean showLegend = true;
+ final boolean createURL = false;
+ final boolean createTooltip = false;
+
+ final JFreeChart chart = ChartFactory.createXYLineChart(chartTitle, xAxisLabel, yAxisLabel, dataset,
+ PlotOrientation.VERTICAL, showLegend, createTooltip, createURL);
+ final XYPlot plot = chart.getXYPlot();
+ final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
+
+ plot.setRenderer(renderer);
+
+ return new ChartPanel(chart);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void notify(int generation, Population<DimensionNCoordinate> population) {
+ PopulationStatisticalSummary<DimensionNCoordinate> populationStatisticalSummary =
+ new PopulationStatisticalSummaryImpl<>(population);
+ this.addDataPoint("Average", generation, populationStatisticalSummary.getMeanFitness());
+ this.addDataPoint("Best", generation, populationStatisticalSummary.getMaxFitness());
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNCoordinate.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNCoordinate.java
new file mode 100644
index 0000000..98a31bc
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNCoordinate.java
@@ -0,0 +1,54 @@
+/*
+ * 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.examples.ga.mathfunctions.dimensionN;
+
+import java.util.List;
+
+/**
+ * This class represents the coordinate of the problem domain i.e. the phenotype
+ * of chromosome.
+ */
+public class DimensionNCoordinate {
+
+ /** coordinate of all dimensions. **/
+ private final List<Double> values;
+
+ /**
+ * constructor.
+ * @param values coordinates of all dimensions.
+ */
+ public DimensionNCoordinate(List<Double> values) {
+ this.values = values;
+ }
+
+ /**
+ * Returns the values of all coordinates.
+ * @return values of coordinates
+ */
+ public List<Double> getValues() {
+ return values;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "Coordinate [values=" + values + "]";
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNDecoder.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNDecoder.java
new file mode 100644
index 0000000..9579815
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNDecoder.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.examples.ga.mathfunctions.dimensionN;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.decoder.Decoder;
+
+/**
+ * Decoder to convert chromosome's binary genotype to phenotype
+ * {@link DimensionNCoordinate}.
+ */
+public class DimensionNDecoder implements Decoder<DimensionNCoordinate> {
+
+ /**
+ * decode the binary representation of chromosome to
+ * {@link DimensionNCoordinate}.
+ * @param chromosome The {@link Chromosome}
+ */
+ @Override
+ public DimensionNCoordinate decode(Chromosome<DimensionNCoordinate> chromosome) {
+ final BinaryChromosome<DimensionNCoordinate> binaryChromosome =
+ (BinaryChromosome<DimensionNCoordinate>) chromosome;
+ final long length = binaryChromosome.getLength();
+ final List<Double> coordinates = new ArrayList<>();
+
+ for (int i = 0; i < length; i += 12) {
+ final String dimensionStrValue = binaryChromosome.getStringRepresentation(i, i + 12);
+ coordinates.add(Integer.parseUnsignedInt(dimensionStrValue, 2) / 100d);
+ }
+
+ return new DimensionNCoordinate(coordinates);
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFitnessFunction.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFitnessFunction.java
new file mode 100644
index 0000000..1c0d7db
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFitnessFunction.java
@@ -0,0 +1,42 @@
+/*
+ * 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.examples.ga.mathfunctions.dimensionN;
+
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+
+/**
+ * This class represents the mathematical fitness function for optimizing a 2
+ * dimension mathematical function.
+ */
+public class DimensionNFitnessFunction implements FitnessFunction<DimensionNCoordinate> {
+
+ /**
+ * Computes the fitness value based on the decoded chromosome.
+ * @param coordinate The {@link DimensionNCoordinate}
+ * @return the fitness value
+ */
+ @Override
+ public double compute(DimensionNCoordinate coordinate) {
+ double sumOfSquare = 0.0;
+ for (Double value : coordinate.getValues()) {
+ sumOfSquare += Math.pow(value, 2);
+ }
+ return -Math.pow(sumOfSquare, .25) * (Math.pow(Math.sin(50 * Math.pow(sumOfSquare, .1)), 2) + 1);
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFunctionAdaptiveOptimizer.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFunctionAdaptiveOptimizer.java
new file mode 100644
index 0000000..dee317a
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFunctionAdaptiveOptimizer.java
@@ -0,0 +1,114 @@
+/*
+ * 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.examples.ga.mathfunctions.dimensionN;
+
+import org.apache.commons.math4.examples.ga.mathfunctions.utils.Constants;
+import org.apache.commons.math4.ga.AbstractGeneticAlgorithm;
+import org.apache.commons.math4.ga.AdaptiveGeneticAlgorithm;
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.convergence.UnchangedBestFitness;
+import org.apache.commons.math4.ga.crossover.OnePointBinaryCrossover;
+import org.apache.commons.math4.ga.crossover.rategenerator.AdaptiveLinearMaximumRankBasedCrossoverRateGenerator;
+import org.apache.commons.math4.ga.listener.ConvergenceListenerRegistry;
+import org.apache.commons.math4.ga.listener.PopulationStatisticsLogger;
+import org.apache.commons.math4.ga.mutation.BinaryMutation;
+import org.apache.commons.math4.ga.mutation.rategenerator.AdaptiveLinearMutationRateGenerator;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.TournamentSelection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents an optimizer for a 2-dimensional math function using
+ * genetic algorithm.
+ */
+public class DimensionNFunctionAdaptiveOptimizer {
+
+ /** number of dimension. **/
+ private static final int DIMENSION = 10;
+
+ /** size of tournament. **/
+ private static final int TOURNAMENT_SIZE = 4;
+
+ /** instance of logger. **/
+ private Logger logger = LoggerFactory.getLogger(DimensionNFunctionOptimizer.class);
+
+ /**
+ * Optimizes the 2-dimension fitness function.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+ final Population<DimensionNCoordinate> initPopulation = getInitialPopulation();
+
+ final DimensionNFunctionAdaptiveOptimizer optimizer = new DimensionNFunctionAdaptiveOptimizer();
+
+ final ConvergenceListenerRegistry<DimensionNCoordinate> convergenceListenerRegistry =
+ ConvergenceListenerRegistry.getInstance();
+ convergenceListenerRegistry.addConvergenceListener(new PopulationStatisticsLogger<DimensionNCoordinate>());
+ convergenceListenerRegistry
+ .addConvergenceListener(new DimNGraphPlotter("Adaptive Convergence Stats", "generation", "fitness"));
+
+ optimizer.optimize(initPopulation);
+ }
+
+ private void optimize(Population<DimensionNCoordinate> initial) {
+
+ // initialize a new genetic algorithm
+ final AbstractGeneticAlgorithm<DimensionNCoordinate> ga = new AdaptiveGeneticAlgorithm<DimensionNCoordinate>(
+ new OnePointBinaryCrossover<DimensionNCoordinate>(),
+ new AdaptiveLinearMaximumRankBasedCrossoverRateGenerator<>(Constants.CROSSOVER_RATE / 2,
+ Constants.CROSSOVER_RATE),
+ new BinaryMutation<>(), new AdaptiveLinearMutationRateGenerator<>(0, Constants.AVERAGE_MUTATION_RATE),
+ new TournamentSelection<>(TOURNAMENT_SIZE), Constants.ELITISM_RATE);
+
+ // stopping condition
+ final StoppingCondition<DimensionNCoordinate> stopCond = new UnchangedBestFitness<>(
+ Constants.GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS);
+
+ // run the algorithm
+ final Population<DimensionNCoordinate> finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ final Chromosome<DimensionNCoordinate> bestFinal = finalPopulation.getFittestChromosome();
+
+ logger.info("*********************************************");
+ logger.info("***********Optimization Result***************");
+ logger.info(bestFinal.toString());
+
+ }
+
+ /**
+ * Generates an initial population.
+ * @return initial population
+ */
+ private static Population<DimensionNCoordinate> getInitialPopulation() {
+ final Population<DimensionNCoordinate> population = new ListPopulation<>(
+ DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION);
+ final DimensionNFitnessFunction fitnessFunction = new DimensionNFitnessFunction();
+ final DimensionNDecoder decoder = new DimensionNDecoder();
+ for (int i = 0; i < DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION; i++) {
+ population.addChromosome(BinaryChromosome.<DimensionNCoordinate>randomChromosome(
+ DIMENSION * Constants.CHROMOSOME_LENGTH_PER_DIMENSION, fitnessFunction, decoder));
+ }
+ return population;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFunctionOptimizer.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFunctionOptimizer.java
new file mode 100644
index 0000000..5791b05
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/DimensionNFunctionOptimizer.java
@@ -0,0 +1,113 @@
+/*
+ * 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.examples.ga.mathfunctions.dimensionN;
+
+import org.apache.commons.math4.examples.ga.mathfunctions.utils.Constants;
+import org.apache.commons.math4.ga.GeneticAlgorithm;
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.convergence.UnchangedBestFitness;
+import org.apache.commons.math4.ga.crossover.OnePointBinaryCrossover;
+import org.apache.commons.math4.ga.listener.ConvergenceListenerRegistry;
+import org.apache.commons.math4.ga.listener.PopulationStatisticsLogger;
+import org.apache.commons.math4.ga.mutation.BinaryMutation;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.TournamentSelection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents an optimizer for a 2-dimensional math function using
+ * genetic algorithm.
+ */
+public class DimensionNFunctionOptimizer {
+
+ /** number of dimension. **/
+ private static final int DIMENSION = 10;
+
+ /** size of tournament. **/
+ private static final int TOURNAMENT_SIZE = 4;
+
+ /** instance of logger. **/
+ private Logger logger = LoggerFactory.getLogger(DimensionNFunctionOptimizer.class);
+
+ /**
+ * Optimizes the 2-dimension fitness function.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+ final Population<DimensionNCoordinate> initPopulation = getInitialPopulation();
+
+ final DimensionNFunctionOptimizer optimizer = new DimensionNFunctionOptimizer();
+
+ final ConvergenceListenerRegistry<DimensionNCoordinate> convergenceListenerRegistry =
+ ConvergenceListenerRegistry.getInstance();
+ convergenceListenerRegistry.addConvergenceListener(new PopulationStatisticsLogger<DimensionNCoordinate>());
+ convergenceListenerRegistry
+ .addConvergenceListener(new DimNGraphPlotter("Convergence Stats", "generation", "fitness"));
+
+ optimizer.optimize(initPopulation);
+ }
+
+ /**
+ * Optimizes the population.
+ * @param initial The {@link Population}
+ */
+ public void optimize(Population<DimensionNCoordinate> initial) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm<DimensionNCoordinate> ga = new GeneticAlgorithm<>(
+ new OnePointBinaryCrossover<DimensionNCoordinate>(), Constants.CROSSOVER_RATE,
+ new BinaryMutation<DimensionNCoordinate>(), Constants.AVERAGE_MUTATION_RATE,
+ new TournamentSelection<>(TOURNAMENT_SIZE), Constants.ELITISM_RATE);
+
+ // stopping condition
+ final StoppingCondition<DimensionNCoordinate> stopCond = new UnchangedBestFitness<>(
+ Constants.GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS);
+
+ // run the algorithm
+ final Population<DimensionNCoordinate> finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ final Chromosome<DimensionNCoordinate> bestFinal = finalPopulation.getFittestChromosome();
+
+ logger.info("*********************************************");
+ logger.info("***********Optimization Result***************");
+ logger.info(bestFinal.toString());
+
+ }
+
+ /**
+ * Generates an initial population.
+ * @return initial population
+ */
+ private static Population<DimensionNCoordinate> getInitialPopulation() {
+ final Population<DimensionNCoordinate> population = new ListPopulation<>(
+ DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION);
+ final DimensionNFitnessFunction fitnessFunction = new DimensionNFitnessFunction();
+ final DimensionNDecoder decoder = new DimensionNDecoder();
+ for (int i = 0; i < DIMENSION * Constants.POPULATION_SIZE_PER_DIMENSION; i++) {
+ population.addChromosome(BinaryChromosome.<DimensionNCoordinate>randomChromosome(
+ DIMENSION * Constants.CHROMOSOME_LENGTH_PER_DIMENSION, fitnessFunction, decoder));
+ }
+ return population;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/package-info.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/package-info.java
new file mode 100644
index 0000000..6a15fed
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/dimensionN/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.examples.ga.mathfunctions.dimensionN;
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/utils/Constants.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/utils/Constants.java
new file mode 100644
index 0000000..1389c75
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/utils/Constants.java
@@ -0,0 +1,55 @@
+/*
+ * 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.examples.ga.mathfunctions.utils;
+
+/**
+ * This abstraction maintains constants used by this module.
+ */
+public final class Constants {
+
+ /** size of population. **/
+ public static final int POPULATION_SIZE_PER_DIMENSION = 10;
+
+ /** size of tournament. **/
+ public static final int TOURNAMENT_SIZE_PER_DIMENSION = 2;
+
+ /** length of chromosome. **/
+ public static final int CHROMOSOME_LENGTH_PER_DIMENSION = 12;
+
+ /** rate of crossover. **/
+ public static final double CROSSOVER_RATE = 1.0;
+
+ /** rate of elitism. **/
+ public static final double ELITISM_RATE = 0.25;
+
+ /** rate of mutation. **/
+ public static final double AVERAGE_MUTATION_RATE = 0.05;
+
+ /** number of generations with unchanged best fitness. **/
+ public static final int GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS = 50;
+
+ /** encoding for console logger. **/
+ public static final String ENCODING = "UTF-8";
+
+ /**
+ * constructor.
+ */
+ private Constants() {
+
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/utils/package-info.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/utils/package-info.java
new file mode 100644
index 0000000..360a1c3
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/utils/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.examples.ga.mathfunctions.utils;
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/pom.xml b/commons-math-examples/examples-ga/examples-ga-tsp/pom.xml
new file mode 100644
index 0000000..b4a7811
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>examples-ga</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>examples-ga-tsp</artifactId>
+
+ <properties>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+
+ <!-- OSGi -->
+ <commons.osgi.symbolicName>org.apache.commons.math4.examples.ga.tsp</commons.osgi.symbolicName>
+ <commons.osgi.export>org.apache.commons.math4.examples.ga.tsp</commons.osgi.export>
+ <!-- Java 9+ -->
+ <commons.automatic.module.name>org.apache.commons.math4.examples.ga.tsp</commons.automatic.module.name>
+ <!-- Workaround to avoid duplicating config files. -->
+ <math.parent.dir>${basedir}/../../..</math.parent.dir>
+
+ <uberjar.name>examples-ga-mathfunctions</uberjar.name>
+ <project.mainClass>org.apache.commons.math4.examples.ga.tsp.TSPOptimizer</project.mainClass>
+ <slf4jVersion>1.7.32</slf4jVersion>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-csv</artifactId>
+ <version>1.9.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4jVersion}</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/TSPFitnessFunction.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/TSPFitnessFunction.java
new file mode 100644
index 0000000..9b06312
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/TSPFitnessFunction.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.examples.ga.tsp;
+
+import java.util.List;
+
+
+import org.apache.commons.math4.examples.ga.tsp.commons.City;
+import org.apache.commons.math4.examples.ga.tsp.commons.DistanceMatrix;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+
+/**
+ * This class represents the fitness function for tsp.
+ */
+public class TSPFitnessFunction implements FitnessFunction<List<City>> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double compute(List<City> cities) {
+ double totalDistance = 0.0;
+ int index1 = 0;
+ int index2 = 0;
+ for (int i = 0; i < cities.size(); i++) {
+ index1 = i;
+ index2 = (i == cities.size() - 1) ? 0 : i + 1;
+ totalDistance += calculateNodeDistance(cities.get(index1), cities.get(index2));
+ }
+ return -totalDistance;
+ }
+
+ private double calculateNodeDistance(City node1, City node2) {
+ final DistanceMatrix distanceMatrix = DistanceMatrix.getInstance();
+ return distanceMatrix.getDistance(node1, node2);
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/TSPOptimizer.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/TSPOptimizer.java
new file mode 100644
index 0000000..21833ef
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/TSPOptimizer.java
@@ -0,0 +1,116 @@
+/*
+ * 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.examples.ga.tsp;
+
+import java.util.List;
+
+import org.apache.commons.math4.examples.ga.tsp.commons.City;
+import org.apache.commons.math4.examples.ga.tsp.utils.Constants;
+import org.apache.commons.math4.examples.ga.tsp.utils.GraphPlotter;
+import org.apache.commons.math4.ga.GeneticAlgorithm;
+import org.apache.commons.math4.ga.chromosome.RealValuedChromosome;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.convergence.UnchangedBestFitness;
+import org.apache.commons.math4.ga.crossover.OnePointCrossover;
+import org.apache.commons.math4.ga.decoder.RandomKeyDecoder;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.listener.ConvergenceListenerRegistry;
+import org.apache.commons.math4.ga.listener.PopulationStatisticsLogger;
+import org.apache.commons.math4.ga.mutation.RealValuedMutation;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.TournamentSelection;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents the optimizer for traveling salesman problem.
+ */
+public class TSPOptimizer {
+
+ /** instance of logger. **/
+ private Logger logger = LoggerFactory.getLogger(TSPOptimizer.class);
+
+ /**
+ * Main method to initiate the optimization process.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+ try {
+ final Population<List<City>> initPopulation = getInitialPopulation(Constants.CITIES);
+
+ final TSPOptimizer optimizer = new TSPOptimizer();
+
+ final ConvergenceListenerRegistry<List<City>> convergenceListenerRegistry = ConvergenceListenerRegistry
+ .getInstance();
+ convergenceListenerRegistry.addConvergenceListener(new PopulationStatisticsLogger<>());
+ convergenceListenerRegistry
+ .addConvergenceListener(new GraphPlotter("Convergence", "generation", "total-distance"));
+
+ optimizer.optimizeSGA(initPopulation, Constants.CITIES);
+
+ Thread.sleep(5000);
+
+ } catch (InterruptedException e) {
+ throw new GeneticException(e);
+ }
+ }
+
+ /**
+ * Optimizes the tsp problem.
+ * @param initial initial population
+ * @param cities cities
+ */
+ public void optimizeSGA(Population<List<City>> initial, List<City> cities) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm<List<City>> ga = new GeneticAlgorithm<>(new OnePointCrossover<Integer, List<City>>(),
+ Constants.CROSSOVER_RATE, new RealValuedMutation<List<City>>(), Constants.AVERAGE_MUTATION_RATE,
+ new TournamentSelection<List<City>>(Constants.TOURNAMENT_SIZE));
+
+ // stopping condition
+ final StoppingCondition<List<City>> stopCond = new UnchangedBestFitness<>(
+ Constants.GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS);
+
+ // run the algorithm
+ final Population<List<City>> finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ final RealValuedChromosome<List<City>> bestFinal = (RealValuedChromosome<List<City>>) finalPopulation
+ .getFittestChromosome();
+
+ logger.info("*********************************************");
+ logger.info("***********Optimization Result***************");
+
+ logger.info(bestFinal.decode().toString());
+
+ }
+
+ private static Population<List<City>> getInitialPopulation(List<City> cities) {
+ final Population<List<City>> simulationPopulation = new ListPopulation<>(Constants.POPULATION_SIZE);
+
+ for (int i = 0; i < Constants.POPULATION_SIZE; i++) {
+ simulationPopulation.addChromosome(new RealValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomPermutation(Constants.CHROMOSOME_LENGTH),
+ new TSPFitnessFunction(), new RandomKeyDecoder<City>(cities)));
+ }
+
+ return simulationPopulation;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/City.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/City.java
new file mode 100644
index 0000000..7a6d8d1
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/City.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.examples.ga.tsp.commons;
+
+/**
+ * This class represents a city with location coordinate.
+ */
+public final class City {
+
+ /** index of city. **/
+ private final int index;
+
+ /** x coordinate. **/
+ private final double x;
+
+ /** y coordinate. **/
+ private final double y;
+
+ /**
+ * constructor.
+ * @param index index of city
+ * @param x x coordinate
+ * @param y y coordinate
+ */
+ public City(int index, double x, double y) {
+ this.index = index;
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Returns city index.
+ * @return city index
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Returns x coordinate.
+ * @return x coordinate
+ */
+ public double getX() {
+ return x;
+ }
+
+ /**
+ * Returns y coordinate.
+ * @return y coordinate
+ */
+ public double getY() {
+ return y;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "Node [index=" + index + ", x=" + x + ", y=" + y + "]";
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/DistanceMatrix.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/DistanceMatrix.java
new file mode 100644
index 0000000..175c7c6
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/DistanceMatrix.java
@@ -0,0 +1,71 @@
+/*
+ * 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.examples.ga.tsp.commons;
+
+import java.util.List;
+
+import org.apache.commons.math4.examples.ga.tsp.utils.Constants;
+
+/**
+ * This class represents the distance matrix between cities.
+ */
+public final class DistanceMatrix {
+
+ /** instance of the class. **/
+ private static final DistanceMatrix INSTANCE = new DistanceMatrix();
+
+ /** distances between cities. **/
+ private double[][] distances;
+
+ private DistanceMatrix() {
+ initialize(Constants.CITIES);
+ }
+
+ /**
+ * Returns distances between two cities.
+ * @param city1 first city
+ * @param city2 second city
+ * @return distance
+ */
+ public double getDistance(City city1, City city2) {
+ return distances[city1.getIndex() - 1][city2.getIndex() - 1];
+ }
+
+ /**
+ * Initializes the distance matrix.
+ * @param cities list of cities
+ */
+ private void initialize(List<City> cities) {
+ final int len = cities.size();
+ this.distances = new double[len][len];
+ for (int i = 0; i < len; i++) {
+ for (int j = 0; j < len; j++) {
+ distances[i][j] = Math.pow(Math.pow(cities.get(i).getX() - cities.get(j).getX(), 2) +
+ Math.pow(cities.get(i).getY() - cities.get(j).getY(), 2), .5);
+ }
+ }
+ }
+
+ /**
+ * Returns the instance of this class.
+ * @return instance
+ */
+ public static DistanceMatrix getInstance() {
+ return INSTANCE;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/package-info.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/package-info.java
new file mode 100644
index 0000000..e0422fd
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/commons/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.examples.ga.tsp.commons;
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/TSPChromosome.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/TSPChromosome.java
new file mode 100644
index 0000000..9a42d39
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/TSPChromosome.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.examples.ga.tsp.legacy;
+
+import java.util.List;
+
+import org.apache.commons.math3.genetics.RandomKey;
+import org.apache.commons.math4.examples.ga.tsp.commons.City;
+import org.apache.commons.math4.examples.ga.tsp.commons.DistanceMatrix;
+
+/**
+ * This class represents chromosome for tsp problem.
+ */
+public class TSPChromosome extends RandomKey<City> {
+
+ /** list of cities. **/
+ private final List<City> cities;
+
+ /**
+ * constructor.
+ * @param representation internal representation of chromosome
+ * @param cities list of cities
+ */
+ public TSPChromosome(List<Double> representation, List<City> cities) {
+ super(representation);
+ this.cities = cities;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double fitness() {
+ final List<City> permutatedNodes = decode(cities);
+ return -calculateTotalDistance(permutatedNodes);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public TSPChromosome newFixedLengthChromosome(List<Double> representation) {
+ return new TSPChromosome(representation, cities);
+ }
+
+ private double calculateTotalDistance(List<City> permutedCities) {
+ double totalDistance = 0.0;
+ int index1 = 0;
+ int index2 = 0;
+ for (int i = 0; i < permutedCities.size(); i++) {
+ index1 = i;
+ index2 = (i == permutedCities.size() - 1) ? 0 : i + 1;
+ totalDistance += calculateNodeDistance(permutedCities.get(index1), permutedCities.get(index2));
+ }
+ return totalDistance;
+ }
+
+ private double calculateNodeDistance(City node1, City node2) {
+ return DistanceMatrix.getInstance().getDistance(node1, node2);
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/TSPOptimizerLegacy.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/TSPOptimizerLegacy.java
new file mode 100644
index 0000000..81ae597
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/TSPOptimizerLegacy.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.examples.ga.tsp.legacy;
+
+import java.io.BufferedWriter;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.List;
+
+import org.apache.commons.math3.genetics.ElitisticListPopulation;
+import org.apache.commons.math3.genetics.GeneticAlgorithm;
+import org.apache.commons.math3.genetics.OnePointCrossover;
+import org.apache.commons.math3.genetics.Population;
+import org.apache.commons.math3.genetics.RandomKey;
+import org.apache.commons.math3.genetics.RandomKeyMutation;
+import org.apache.commons.math3.genetics.StoppingCondition;
+import org.apache.commons.math3.genetics.TournamentSelection;
+import org.apache.commons.math4.examples.ga.tsp.commons.City;
+import org.apache.commons.math4.examples.ga.tsp.utils.Constants;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+
+/**
+ * This class represents the tsp optimizer based on legacy implementation of
+ * Genetic Algorithm.
+ */
+public class TSPOptimizerLegacy {
+
+ /**
+ * MainThread.sleep(5000) method to initiate optimization.
+ * @param args arguments
+ */
+ public static void main(String[] args) {
+
+ final Population initPopulation = getInitialPopulation(Constants.CITIES);
+ final TSPOptimizerLegacy optimizer = new TSPOptimizerLegacy();
+
+ optimizer.optimize(initPopulation, Constants.CITIES);
+
+ }
+
+ /**
+ * Optimizes the tsp problem using legacy GA.
+ * @param initial initial population
+ * @param cities cities
+ */
+ public void optimize(Population initial, List<City> cities) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm ga = new GeneticAlgorithm(new OnePointCrossover<Integer>(), Constants.CROSSOVER_RATE,
+ new RandomKeyMutation(), Constants.AVERAGE_MUTATION_RATE,
+ new TournamentSelection(Constants.TOURNAMENT_SIZE));
+
+ // stopping condition
+ final StoppingCondition stopCond = new UnchangedBestFitness(
+ Constants.GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS);
+
+ // run the algorithm
+ final Population finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ @SuppressWarnings("unchecked")
+ final RandomKey<City> bestFinal = (RandomKey<City>) finalPopulation.getFittestChromosome();
+
+ try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out, Constants.ENCODING))) {
+ writer.write("*********************************************");
+ writer.newLine();
+ writer.write("***********Optimization Result***************");
+ writer.write(bestFinal.toString());
+ } catch (IOException e) {
+ throw new GeneticException(e);
+ }
+ }
+
+ private static Population getInitialPopulation(List<City> cities) {
+ final Population simulationPopulation = new ElitisticListPopulation(Constants.POPULATION_SIZE, .25);
+
+ for (int i = 0; i < Constants.POPULATION_SIZE; i++) {
+ simulationPopulation.addChromosome(new TSPChromosome(RandomKey.randomPermutation(cities.size()), cities));
+ }
+
+ return simulationPopulation;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/UnchangedBestFitness.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/UnchangedBestFitness.java
new file mode 100644
index 0000000..44fe93a
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/UnchangedBestFitness.java
@@ -0,0 +1,67 @@
+/*
+ * 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.examples.ga.tsp.legacy;
+
+import org.apache.commons.math3.genetics.Population;
+import org.apache.commons.math3.genetics.StoppingCondition;
+
+/**
+ * This class represents the stopping condition based on unchanged best fitness.
+ */
+public class UnchangedBestFitness implements StoppingCondition {
+
+ /** last best fitness. **/
+ private double lastBestFitness = Double.MIN_VALUE;
+
+ /** maximum number of generations evolved with unchanged best fitness. **/
+ private final int maxGenerationsWithUnchangedBestFitness;
+
+ /** generations having unchanged best fitness. **/
+ private int generationsHavingUnchangedBestFitness;
+
+ /**
+ * constructor.
+ * @param maxGenerationsWithUnchangedAverageFitness maximum number of
+ * generations evolved with
+ * unchanged best fitness
+ */
+ public UnchangedBestFitness(final int maxGenerationsWithUnchangedAverageFitness) {
+ this.maxGenerationsWithUnchangedBestFitness = maxGenerationsWithUnchangedAverageFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isSatisfied(Population population) {
+ final double currentBestFitness = population.getFittestChromosome().getFitness();
+
+ if (lastBestFitness == currentBestFitness) {
+ this.generationsHavingUnchangedBestFitness++;
+ if (generationsHavingUnchangedBestFitness == maxGenerationsWithUnchangedBestFitness) {
+ return true;
+ }
+ } else {
+ this.generationsHavingUnchangedBestFitness = 0;
+ lastBestFitness = currentBestFitness;
+ }
+
+ return false;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/package-info.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/package-info.java
new file mode 100644
index 0000000..d46c6fd
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/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.examples.ga.tsp.legacy;
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/package-info.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/package-info.java
new file mode 100644
index 0000000..938b8f9
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/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.examples.ga.tsp;
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/Constants.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/Constants.java
new file mode 100644
index 0000000..c41cc31
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/Constants.java
@@ -0,0 +1,65 @@
+/*
+ * 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.examples.ga.tsp.utils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math4.examples.ga.tsp.commons.City;
+
+/**
+ * This class contains all required constants for this example.
+ */
+public final class Constants {
+
+ /** size of population. **/
+ public static final int POPULATION_SIZE = 100;
+
+ /** size of tournament. **/
+ public static final int TOURNAMENT_SIZE = 5;
+
+ /** length of chromosome. **/
+ public static final int CHROMOSOME_LENGTH = 14;
+
+ /** rate of crossover. **/
+ public static final double CROSSOVER_RATE = 1.0;
+
+ /** rate of elitism. **/
+ public static final double ELITISM_RATE = 0.25;
+
+ /** rate of mutation. **/
+ public static final double AVERAGE_MUTATION_RATE = 0.05;
+
+ /** maximum number of generations with unchanged best fitness. **/
+ public static final int GENERATION_COUNT_WITH_UNCHANGED_BEST_FUTNESS = 50;
+
+ /** list of cities. **/
+ public static final List<City> CITIES = Collections.unmodifiableList(
+ Arrays.asList(new City[] {new City(1, 0, 0), new City(2, 1, 0), new City(3, 2, 0), new City(4, 3, 0),
+ new City(5, 3, 1), new City(6, 3, 2), new City(7, 3, 3), new City(8, 2, 3), new City(9, 1, 3),
+ new City(10, 0, 3), new City(11, 1, 2), new City(12, 2, 2), new City(13, 2, 1), new City(14, 1, 1)}));
+
+ /** encoding for console logger. **/
+ public static final String ENCODING = "UTF-8";
+
+ private Constants() {
+
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/GraphPlotter.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/GraphPlotter.java
new file mode 100644
index 0000000..701380b
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/GraphPlotter.java
@@ -0,0 +1,146 @@
+/*
+ * 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.examples.ga.tsp.utils;
+
+import java.awt.BorderLayout;
+
+import java.util.List;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import org.apache.commons.math4.examples.ga.tsp.commons.City;
+import org.apache.commons.math4.ga.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.listener.ConvergenceListener;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+/**
+ * This class represents the graph plotter during optimization.
+ */
+public class GraphPlotter extends JFrame implements ConvergenceListener<List<City>> {
+
+ /**
+ * Generated serialversionId.
+ */
+ private static final long serialVersionUID = -5683904006424006584L;
+
+ /** collection of 2-D series. **/
+ private final XYSeriesCollection dataset = new XYSeriesCollection();
+
+ /**
+ * constructor.
+ * @param plotSubject subject of plot
+ * @param xAxisLabel x axis label
+ * @param yAxisLabel y axis label
+ */
+ public GraphPlotter(String plotSubject, String xAxisLabel, String yAxisLabel) {
+ super(plotSubject);
+
+ final JPanel chartPanel = createChartPanel(plotSubject, xAxisLabel, yAxisLabel);
+ add(chartPanel, BorderLayout.CENTER);
+
+ setSize(640, 480);
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setLocationRelativeTo(null);
+
+ setVisible(true);
+ }
+
+ /**
+ * Adds data point to graph.
+ * @param graphName name of graph
+ * @param generation generation, to be plotted along x axis
+ * @param value value, to be plotted along y axis
+ */
+ private void addDataPoint(String graphName, int generation, double value) {
+ XYSeries series = null;
+
+ if (!containsGraph(graphName)) {
+ series = new XYSeries(graphName);
+ dataset.addSeries(series);
+ } else {
+ series = dataset.getSeries(graphName);
+ }
+ series.add(generation, value);
+
+ setVisible(true);
+ }
+
+ /**
+ * Checks if the graph with the given name already exists.
+ * @param graphName name of the graph
+ * @return true/false
+ */
+ @SuppressWarnings("unchecked")
+ private boolean containsGraph(String graphName) {
+ final List<XYSeries> seriesList = dataset.getSeries();
+ if (seriesList == null || seriesList.isEmpty()) {
+ return false;
+ }
+ for (XYSeries series : seriesList) {
+ if (series.getKey().compareTo(graphName) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates chart panel.
+ * @param chartTitle chart title
+ * @param xAxisLabel x axis label
+ * @param yAxisLabel y axis label
+ * @return panel
+ */
+ private JPanel createChartPanel(String chartTitle, String xAxisLabel, String yAxisLabel) {
+
+ final boolean showLegend = true;
+ final boolean createURL = false;
+ final boolean createTooltip = false;
+
+ final JFreeChart chart = ChartFactory.createXYLineChart(chartTitle, xAxisLabel, yAxisLabel, dataset,
+ PlotOrientation.VERTICAL, showLegend, createTooltip, createURL);
+ final XYPlot plot = chart.getXYPlot();
+ final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
+
+ plot.setRenderer(renderer);
+
+ return new ChartPanel(chart);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void notify(int generation, Population<List<City>> population) {
+ PopulationStatisticalSummary<List<City>> populationStatisticalSummary = new PopulationStatisticalSummaryImpl<>(
+ population);
+ this.addDataPoint("Average", generation, populationStatisticalSummary.getMeanFitness());
+ this.addDataPoint("Best", generation, populationStatisticalSummary.getMaxFitness());
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/package-info.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/package-info.java
new file mode 100644
index 0000000..5caadde
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/utils/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.examples.ga.tsp.utils;
diff --git a/commons-math-examples/examples-ga/pom.xml b/commons-math-examples/examples-ga/pom.xml
new file mode 100644
index 0000000..8432483
--- /dev/null
+++ b/commons-math-examples/examples-ga/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math-examples</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>examples-ga</artifactId>
+ <packaging>pom</packaging>
+ <name>examples-genetic-algorithm</name>
+
+ <properties>
+ <!-- Workaround to avoid duplicating config files. -->
+ <math.parent.dir>${basedir}/../..</math.parent.dir>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math-ga</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math3</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jfree</groupId>
+ <artifactId>jfreechart</artifactId>
+ <version>1.5.3</version>
+ </dependency>
+ </dependencies>
+ <modules>
+ <module>examples-ga-math-functions</module>
+ <module>examples-ga-tsp</module>
+ </modules>
+</project>
\ No newline at end of file
diff --git a/commons-math-examples/pom.xml b/commons-math-examples/pom.xml
index ccef4d6..cc1f917 100644
--- a/commons-math-examples/pom.xml
+++ b/commons-math-examples/pom.xml
@@ -168,6 +168,7 @@
<modules>
<module>examples-sofm</module>
<module>examples-kmeans</module>
+ <module>examples-ga</module>
</modules>
</project>
diff --git a/commons-math-ga/pom.xml b/commons-math-ga/pom.xml
new file mode 100644
index 0000000..a2a3689
--- /dev/null
+++ b/commons-math-ga/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math-parent</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>commons-math-ga</artifactId>
+ <name>genetic algorithm</name>
+
+ <description />
+
+ <properties>
+ <!-- The Java Module System Name -->
+ <commons.module.name>org.apache.commons.math4.ga</commons.module.name>
+ <!-- This value must reflect the current name of the base package. -->
+ <commons.osgi.symbolicName>org.apache.commons.math4.ga</commons.osgi.symbolicName>
+ <!-- OSGi -->
+ <commons.osgi.export>org.apache.commons.math4.ga</commons.osgi.export>
+ <!-- Workaround to avoid duplicating config files. -->
+ <math.parent.dir>${basedir}/..</math.parent.dir>
+ <slf4jVersion>1.7.32</slf4jVersion>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-numbers-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-rng-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${slf4jVersion}</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/AbstractGeneticAlgorithm.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/AbstractGeneticAlgorithm.java
new file mode 100644
index 0000000..7f9359f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/AbstractGeneticAlgorithm.java
@@ -0,0 +1,180 @@
+/*
+ * 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.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.crossover.CrossoverPolicy;
+import org.apache.commons.math4.ga.listener.ConvergenceListenerRegistry;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents an abstraction for all Genetic algorithm implementation
+ * comprising the basic properties and operations.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractGeneticAlgorithm<P> {
+
+ /** instance of logger. **/
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGeneticAlgorithm.class);
+
+ /** the crossover policy used by the algorithm. */
+ private final CrossoverPolicy<P> crossoverPolicy;
+
+ /** the mutation policy used by the algorithm. */
+ private final MutationPolicy<P> mutationPolicy;
+
+ /** the selection policy used by the algorithm. */
+ private final SelectionPolicy<P> 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;
+
+ /**
+ * @param crossoverPolicy The {@link CrossoverPolicy}
+ * @param mutationPolicy The {@link MutationPolicy}
+ * @param selectionPolicy The {@link SelectionPolicy}
+ */
+ protected AbstractGeneticAlgorithm(final CrossoverPolicy<P> crossoverPolicy,
+ final MutationPolicy<P> mutationPolicy,
+ final SelectionPolicy<P> selectionPolicy) {
+ this.crossoverPolicy = crossoverPolicy;
+ this.mutationPolicy = mutationPolicy;
+ this.selectionPolicy = selectionPolicy;
+ }
+
+ /**
+ * @param crossoverPolicy The {@link CrossoverPolicy}
+ * @param mutationPolicy The {@link MutationPolicy}
+ * @param selectionPolicy The {@link SelectionPolicy}
+ * @param elitismRate The elitism rate
+ */
+ protected AbstractGeneticAlgorithm(final CrossoverPolicy<P> crossoverPolicy,
+ final MutationPolicy<P> mutationPolicy,
+ final SelectionPolicy<P> selectionPolicy,
+ double elitismRate) {
+ this.crossoverPolicy = crossoverPolicy;
+ this.mutationPolicy = mutationPolicy;
+ this.selectionPolicy = selectionPolicy;
+ this.elitismRate = elitismRate;
+ }
+
+ /**
+ * Returns the crossover policy.
+ * @return crossover policy
+ */
+ public CrossoverPolicy<P> getCrossoverPolicy() {
+ return crossoverPolicy;
+ }
+
+ /**
+ * Returns the mutation policy.
+ * @return mutation policy
+ */
+ public MutationPolicy<P> getMutationPolicy() {
+ return mutationPolicy;
+ }
+
+ /**
+ * Returns the selection policy.
+ * @return selection policy
+ */
+ public SelectionPolicy<P> 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<P> evolve(final Population<P> initial, final StoppingCondition<P> condition) {
+ Population<P> current = initial;
+
+ LOGGER.info("Starting evolution process.");
+ // check if stopping condition is satisfied otherwise produce the next
+ // generation of population.
+ while (!condition.isSatisfied(current)) {
+ // notify interested listener
+ ConvergenceListenerRegistry.<P>getInstance().notifyAll(generationsEvolved, current);
+
+ current = nextGeneration(current);
+ this.generationsEvolved++;
+ }
+ LOGGER.info("Population convergence achieved after generations: " + generationsEvolved);
+
+ return current;
+ }
+
+ /**
+ * Evolve the given population into the next generation.
+ * <ol>
+ * <li>Get nextGeneration population to fill from <code>current</code>
+ * generation, using its nextGeneration method</li>
+ * <li>Loop until new generation is filled:
+ * <ul>
+ * <li>Apply configured SelectionPolicy to select a pair of parents from
+ * <code>current</code>,</li>
+ * <li>apply configured {@link CrossoverPolicy} to parents,</li>
+ * <li>apply configured {@link MutationPolicy} to each of the offspring</li>
+ * <li>Add offspring individually to nextGeneration, space permitting</li>
+ * </ul>
+ * </li>
+ * <li>Return nextGeneration</li>
+ * </ol>
+ *
+ * @param current the current population
+ * @return the population for the next generation.
+ */
+ protected abstract Population<P> nextGeneration(Population<P> 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/AdaptiveGeneticAlgorithm.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/AdaptiveGeneticAlgorithm.java
new file mode 100644
index 0000000..07e8913
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/AdaptiveGeneticAlgorithm.java
@@ -0,0 +1,164 @@
+/*
+ * 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.Chromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.crossover.CrossoverPolicy;
+import org.apache.commons.math4.ga.crossover.rategenerator.CrossoverRateGenerator;
+import org.apache.commons.math4.ga.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.mutation.MutationPolicy;
+import org.apache.commons.math4.ga.mutation.rategenerator.MutationRateGenerator;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.SelectionPolicy;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An implementation of Genetic Algorithm. The probability of crossover and
+ * mutation is generated in an adaptive way. This implementation allows
+ * configuration of dynamic crossover and mutation rate generator along with
+ * crossover policy, mutation policy, selection policy and optionally elitism
+ * rate.
+ * @param <P> phenotype of chromosome
+ */
+public class AdaptiveGeneticAlgorithm<P> extends AbstractGeneticAlgorithm<P> {
+
+ /** instance of logger. **/
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGeneticAlgorithm.class);
+
+ /** The crossover rate generator. **/
+ private final CrossoverRateGenerator<P> crossoverRateGenerator;
+
+ /** The mutation rate generator. **/
+ private final MutationRateGenerator<P> mutationRateGenerator;
+
+ /**
+ * @param crossoverPolicy crossover policy
+ * @param crossoverProbabilityGenerator crossover probability generator
+ * @param mutationPolicy mutation policy
+ * @param mutationProbabilityGenerator mutation probability generator
+ * @param selectionPolicy selection policy
+ */
+ public AdaptiveGeneticAlgorithm(CrossoverPolicy<P> crossoverPolicy,
+ CrossoverRateGenerator<P> crossoverProbabilityGenerator,
+ MutationPolicy<P> mutationPolicy,
+ MutationRateGenerator<P> mutationProbabilityGenerator,
+ SelectionPolicy<P> selectionPolicy) {
+ super(crossoverPolicy, mutationPolicy, selectionPolicy);
+ this.crossoverRateGenerator = crossoverProbabilityGenerator;
+ this.mutationRateGenerator = mutationProbabilityGenerator;
+ }
+
+ /**
+ * @param crossoverPolicy crossover policy
+ * @param crossoverProbabilityGenerator crossover probability generator
+ * @param mutationPolicy mutation policy
+ * @param mutationProbabilityGenerator mutation probability generator
+ * @param selectionPolicy selection policy
+ * @param elitismRate elitism rate
+ */
+ public AdaptiveGeneticAlgorithm(CrossoverPolicy<P> crossoverPolicy,
+ CrossoverRateGenerator<P> crossoverProbabilityGenerator,
+ MutationPolicy<P> mutationPolicy,
+ MutationRateGenerator<P> mutationProbabilityGenerator,
+ SelectionPolicy<P> selectionPolicy,
+ double elitismRate) {
+ super(crossoverPolicy, mutationPolicy, selectionPolicy, elitismRate);
+ this.crossoverRateGenerator = crossoverProbabilityGenerator;
+ this.mutationRateGenerator = mutationProbabilityGenerator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Population<P> nextGeneration(Population<P> current) {
+
+ LOGGER.debug("Reproducing next generation.");
+
+ // compute statistics of current generation chromosomes.
+ PopulationStatisticalSummary<P> populationStats = new PopulationStatisticalSummaryImpl<>(current);
+
+ // Initialize the next generation with elit chromosomes from previous
+ // generation.
+ final Population<P> nextGeneration = current.nextGeneration(getElitismRate());
+
+ LOGGER.debug(
+ "No of Elite chromosomes selected from previous generation: " + nextGeneration.getPopulationSize());
+
+ final int maxOffspringCount = nextGeneration.getPopulationLimit() - nextGeneration.getPopulationSize();
+
+ // Initialize an empty population for offsprings.
+ final Population<P> offspringPopulation = current.nextGeneration(0);
+
+ // perform crossover and generate new offsprings
+ while (offspringPopulation.getPopulationSize() < maxOffspringCount) {
+
+ // select parent chromosomes
+ ChromosomePair<P> pair = getSelectionPolicy().select(current);
+ LOGGER.debug("Selected Chromosomes: \r\n" + pair.toString());
+
+ final double crossoverRate = crossoverRateGenerator.generate(pair.getFirst(), pair.getSecond(),
+ populationStats, getGenerationsEvolved());
+ // apply crossover policy to create two offspring
+ pair = getCrossoverPolicy().crossover(pair.getFirst(), pair.getSecond(), crossoverRate);
+ LOGGER.debug("Offsprings after Crossover: \r\n" + pair.toString());
+
+ // add the first chromosome to the population
+ offspringPopulation.addChromosome(pair.getFirst());
+ // is there still a place for the second chromosome?
+ if (offspringPopulation.getPopulationSize() < maxOffspringCount) {
+ // add the second chromosome to the population
+ offspringPopulation.addChromosome(pair.getSecond());
+ }
+ }
+ LOGGER.debug("Performing adaptive mutation of offsprings.");
+
+ // recompute the statistics of the offspring population.
+ populationStats = new PopulationStatisticalSummaryImpl<>(offspringPopulation);
+
+ // apply mutation policy to the offspring chromosomes and add the mutated
+ // chromosomes to next generation.
+ for (Chromosome<P> chromosome : offspringPopulation) {
+ nextGeneration.addChromosome(getMutationPolicy().mutate(chromosome,
+ mutationRateGenerator.generate(chromosome, populationStats, getGenerationsEvolved())));
+ }
+ LOGGER.debug("New Generation: \r\n" + nextGeneration.toString());
+
+ return nextGeneration;
+ }
+
+ /**
+ * Returns crossover probability generator.
+ * @return crossover probability generator
+ */
+ public CrossoverRateGenerator<P> getCrossoverProbabilityGenerator() {
+ return crossoverRateGenerator;
+ }
+
+ /**
+ * Returns mutation probability generator.
+ * @return mutation probability generator
+ */
+ public MutationRateGenerator<P> getMutationProbabilityGenerator() {
+ return mutationRateGenerator;
+ }
+
+}
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 0000000..94e320d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/GeneticAlgorithm.java
@@ -0,0 +1,171 @@
+/*
+ * 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.internal.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of a genetic algorithm. All factors that govern the operation
+ * of the algorithm can be configured for a specific problem.
+ *
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class GeneticAlgorithm<P> extends AbstractGeneticAlgorithm<P> {
+
+ /** instance of logger. **/
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGeneticAlgorithm.class);
+
+ /** crossover rate string. **/
+ private static final String CROSSOVER_RATE = "CROSSOVER_RATE";
+
+ /** mutation rate string. **/
+ private static final String MUTATION_RATE = "MUTATION_RATE";
+
+ /** 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<P> crossoverPolicy,
+ final double crossoverRate,
+ final MutationPolicy<P> mutationPolicy,
+ final double mutationRate,
+ final SelectionPolicy<P> 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<P> crossoverPolicy,
+ final double crossoverRate,
+ final MutationPolicy<P> mutationPolicy,
+ final double mutationRate,
+ final SelectionPolicy<P> 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, CROSSOVER_RATE, 0, 1);
+ }
+ if (inputMutationRate < 0 || inputMutationRate > 1) {
+ throw new GeneticException(GeneticException.OUT_OF_RANGE, inputMutationRate, MUTATION_RATE, 0, 1);
+ }
+ }
+
+ /**
+ * Evolve the given population into the next generation.
+ * <ol>
+ * <li>Get nextGeneration population to fill from <code>current</code>
+ * generation, using its nextGeneration method</li>
+ * <li>Loop until new generation is filled:
+ * <ul>
+ * <li>Apply configured SelectionPolicy to select a pair of parents from
+ * <code>current</code></li>
+ * <li>With probability = {@link #getCrossoverRate()}, apply configured
+ * {@link CrossoverPolicy} to parents</li>
+ * <li>With probability = {@link #getMutationRate()}, apply configured
+ * {@link MutationPolicy} to each of the offspring</li>
+ * <li>Add offspring individually to nextGeneration, space permitting</li>
+ * </ul>
+ * </li>
+ * <li>Return nextGeneration</li>
+ * </ol>
+ *
+ * @param current the current population.
+ * @return the population for the next generation.
+ */
+ @Override
+ protected Population<P> nextGeneration(final Population<P> current) {
+
+ LOGGER.debug("Reproducing next generation.");
+ final Population<P> nextGeneration = current.nextGeneration(getElitismRate());
+
+ while (nextGeneration.getPopulationSize() < nextGeneration.getPopulationLimit() - 1) {
+
+ // select parent chromosomes
+ ChromosomePair<P> pair = getSelectionPolicy().select(current);
+ LOGGER.debug("Selected Chromosomes: \r\n" + pair.toString());
+
+ // apply crossover policy to create two offspring
+ pair = getCrossoverPolicy().crossover(pair.getFirst(), pair.getSecond(), crossoverRate);
+ LOGGER.debug("Offsprings after Crossover: \r\n" + pair.toString());
+
+ // apply mutation policy to the chromosomes
+ pair = new ChromosomePair<>(getMutationPolicy().mutate(pair.getFirst(), mutationRate),
+ getMutationPolicy().mutate(pair.getSecond(), mutationRate));
+ LOGGER.debug("Offsprings after Mutation: \r\n" + pair.toString());
+
+ // add the chromosomes to the population
+ nextGeneration.addChromosome(pair.getFirst());
+ nextGeneration.addChromosome(pair.getSecond());
+ }
+ LOGGER.debug("New Generation : \r\n" + nextGeneration.toString());
+
+ 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 0000000..4f61ace
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractChromosome.java
@@ -0,0 +1,148 @@
+/*
+ * 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.Objects;
+import java.util.UUID;
+
+import org.apache.commons.math4.ga.decoder.Decoder;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+
+/**
+ * Individual in a population. Chromosomes are compared based on their fitness.
+ * <p>
+ * The chromosomes are IMMUTABLE, and so their fitness is also immutable and
+ * therefore it can be cached.
+ *
+ * @param <P> The phenotype of chromosome. The type should override hashCode()
+ * and equals() methods.
+ * @since 4.0
+ */
+public abstract class AbstractChromosome<P> implements Chromosome<P> {
+
+ /** 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<P> fitnessFunction;
+
+ /** decoder to deode the chromosome's genotype representation. **/
+ private final Decoder<P> decoder;
+
+ /** Id of chromosome. **/
+ private final String id;
+
+ /**
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link Decoder}
+ */
+ protected AbstractChromosome(final FitnessFunction<P> fitnessFunction, final Decoder<P> decoder) {
+ this.fitnessFunction = Objects.requireNonNull(fitnessFunction);
+ this.decoder = Objects.requireNonNull(decoder);
+ this.id = UUID.randomUUID().toString();
+ }
+
+ /**
+ * returns fitness function.
+ * @return fitnessFunction
+ */
+ protected FitnessFunction<P> getFitnessFunction() {
+ return fitnessFunction;
+ }
+
+ /**
+ * Returns the decoder instance.
+ * @return decoder
+ */
+ public Decoder<P> getDecoder() {
+ return decoder;
+ }
+
+ /**
+ * Returns id of chromosome.
+ * @return id
+ */
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Access the fitness of this chromosome. The bigger the fitness, the better the
+ * chromosome.
+ * <p>
+ * 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
+ * <ul>
+ * <li>-1 if <code>another</code> is better than <code>this</code></li>
+ * <li>1 if <code>another</code> is worse than <code>this</code></li>
+ * <li>0 if the two chromosomes have the same fitness</li>
+ * </ul>
+ */
+ @Override
+ public int compareTo(final Chromosome<P> another) {
+ return Double.compare(evaluate(), another.evaluate());
+ }
+
+ /**
+ * Returns <code>true</code> iff <code>another</code> 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 <code>another</code> is equivalent to this chromosome
+ */
+ public boolean isSame(final AbstractChromosome<P> 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 0000000..9e1676d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractListChromosome.java
@@ -0,0 +1,125 @@
+/*
+ * 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 java.util.Objects;
+
+import org.apache.commons.math4.ga.decoder.AbstractListChromosomeDecoder;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+
+/**
+ * This class represents an abstract chromosome containing an immutable list of
+ * allele/genes.
+ * @param <T> type of the allele/gene in the representation list. T should be
+ * immutable.
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ */
+public abstract class AbstractListChromosome<T, P> extends AbstractChromosome<P> {
+
+ /** List of allele/genes. */
+ private final List<T> representation;
+
+ /**
+ * @param representation The representation of chromosome genotype as
+ * {@link List} of generic T
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder An instance of {@link AbstractListChromosomeDecoder},
+ * to decode list chromosome.
+ */
+ protected AbstractListChromosome(final List<T> representation,
+ final FitnessFunction<P> fitnessFunction,
+ final AbstractListChromosomeDecoder<T, P> decoder) {
+ this(representation, true, fitnessFunction, decoder);
+ }
+
+ /**
+ * @param representation The representation of chromosome genotype as an array
+ * of generic T
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder An instance of {@link AbstractListChromosomeDecoder},
+ * to decode list chromosome.
+ */
+ protected AbstractListChromosome(final T[] representation,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<T, P> decoder) {
+ this(Arrays.asList(representation), fitnessFunction, decoder);
+ }
+
+ /**
+ * @param representation Internal representation of chromosome genotype as an
+ * array of generic T
+ * @param copyList if {@code true}, the representation will be copied,
+ * otherwise it will be referenced.
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The instance of {@link AbstractListChromosomeDecoder}
+ */
+ protected AbstractListChromosome(final List<T> representation,
+ final boolean copyList,
+ final FitnessFunction<P> fitnessFunction,
+ final AbstractListChromosomeDecoder<T, P> decoder) {
+ super(fitnessFunction, decoder);
+ Objects.requireNonNull(representation);
+ this.representation = Collections.unmodifiableList(copyList ? new ArrayList<>(representation) : representation);
+ }
+
+ /**
+ * Returns the (immutable) inner representation of the chromosome.
+ * @return the representation of the chromosome
+ */
+ public List<T> getRepresentation() {
+ return representation;
+ }
+
+ /**
+ * Returns the length of the chromosome.
+ * @return the length of the chromosome
+ */
+ public int getLength() {
+ return getRepresentation().size();
+ }
+
+ /**
+ * returns the decoder.
+ * @return decoder
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public AbstractListChromosomeDecoder<T, P> getDecoder() {
+ return (AbstractListChromosomeDecoder<T, P>) super.getDecoder();
+ }
+
+ /**
+ * Creates a new instance of the same class as <code>this</code> is, with a
+ * given <code>arrayRepresentation</code>. This is needed in crossover and
+ * mutation operators, where we need a new instance of the same class, but with
+ * different array representation.
+ * <p>
+ * 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<T, P> newChromosome(List<T> chromosomeRepresentation);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/BinaryChromosome.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/BinaryChromosome.java
new file mode 100644
index 0000000..a9ef839
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/BinaryChromosome.java
@@ -0,0 +1,303 @@
+/*
+ * 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 java.util.Objects;
+
+import org.apache.commons.math4.ga.decoder.Decoder;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+
+/**
+ * BinaryChromosome represented by a vector of 0s and 1s.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class BinaryChromosome<P> extends AbstractChromosome<P> {
+
+ /**
+ * maximum allowed length of binary chromosome.
+ */
+ public static final long MAX_LENGTH = Integer.MAX_VALUE;
+
+ /**
+ * length of binary chromosome.
+ */
+ private final long length;
+
+ /**
+ * binary representation of chromosome.
+ */
+ private final long[] representation;
+
+ /**
+ * @param representation Internal representation of chromosome.
+ * @param length length of chromosome
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link Decoder}
+ */
+ public BinaryChromosome(List<Long> representation,
+ long length,
+ FitnessFunction<P> fitnessFunction,
+ Decoder<P> decoder) {
+ super(fitnessFunction, decoder);
+ Objects.requireNonNull(representation);
+ checkMaximumLength(length);
+ this.length = length;
+ this.representation = new long[representation.size()];
+ for (int i = 0; i < representation.size(); i++) {
+ this.representation[i] = representation.get(i);
+ }
+ }
+
+ /**
+ * @param representation Internal representation of chromosome.
+ * @param length length of chromosome
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link Decoder}
+ */
+ public BinaryChromosome(Long[] representation,
+ long length,
+ FitnessFunction<P> fitnessFunction,
+ Decoder<P> decoder) {
+ super(fitnessFunction, decoder);
+ Objects.requireNonNull(representation);
+ checkMaximumLength(length);
+ this.length = length;
+ this.representation = new long[representation.length];
+ for (int i = 0; i < representation.length; i++) {
+ this.representation[i] = representation[i];
+ }
+ }
+
+ /**
+ * @param inputRepresentation Internal representation of chromosome.
+ * @param length length of chromosome
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link Decoder}
+ */
+ public BinaryChromosome(long[] inputRepresentation,
+ long length,
+ FitnessFunction<P> fitnessFunction,
+ Decoder<P> decoder) {
+ super(fitnessFunction, decoder);
+ Objects.requireNonNull(inputRepresentation);
+ checkMaximumLength(length);
+ if (length <= (inputRepresentation.length - 1) * Long.SIZE || length > inputRepresentation.length * Long.SIZE) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT,
+ "provided length does not match expected representation");
+ }
+ this.length = length;
+ this.representation = new long[inputRepresentation.length];
+ System.arraycopy(inputRepresentation, 0, representation, 0, inputRepresentation.length);
+ }
+
+ /**
+ * @param representation Internal representation of chromosome.
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link Decoder}
+ */
+ public BinaryChromosome(String representation, FitnessFunction<P> fitnessFunction, Decoder<P> decoder) {
+ super(fitnessFunction, decoder);
+ Objects.requireNonNull(representation);
+ this.length = representation.length();
+ this.representation = encode(representation);
+ }
+
+ /**
+ * Checks the input chromosome length against predefined maximum length.
+ * @param chromosomeLength input chromsome length
+ */
+ protected void checkMaximumLength(long chromosomeLength) {
+ if (chromosomeLength > MAX_LENGTH) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT,
+ "length exceeded the max length " + MAX_LENGTH);
+ }
+ }
+
+ /**
+ * Validates the string representation.
+ * @param stringRepresentation binary string representation of chromosome
+ */
+ private void validateStringRepresentation(String stringRepresentation) {
+ char allele = '\0';
+ final int chromosomeLength = stringRepresentation.length();
+ for (int i = 0; i < chromosomeLength; i++) {
+ if ((allele = stringRepresentation.charAt(i)) != '0' && allele != '1') {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT,
+ "Only 0 or 1 are acceptable as characters.");
+ }
+ }
+ }
+
+ /**
+ * encodes the binary string representation as an array of long.
+ * @param stringRepresentation binary string
+ * @return encoded representation
+ */
+ private long[] encode(String stringRepresentation) {
+ validateStringRepresentation(stringRepresentation);
+ final int chromosomeLength = stringRepresentation.length();
+ final int arraySize = (int) Math.ceil(chromosomeLength / (double) Long.SIZE);
+ final long[] encodedRepresentation = new long[arraySize];
+ final int offset = (int) (chromosomeLength % Long.SIZE == 0 ? 0 : Long.SIZE - chromosomeLength % Long.SIZE);
+ encodedRepresentation[0] = Long.parseUnsignedLong(stringRepresentation.substring(0, Long.SIZE - offset), 2);
+ for (int i = Long.SIZE - offset, j = 1; i < chromosomeLength; i += Long.SIZE, j++) {
+ encodedRepresentation[j] = Long.parseUnsignedLong(stringRepresentation.substring(i, i + Long.SIZE), 2);
+ }
+ return encodedRepresentation;
+ }
+
+ /**
+ * Returns the chromosome length.
+ * @return length
+ */
+ public long getLength() {
+ return length;
+ }
+
+ /**
+ * Returns the binary representation.
+ * @return representation
+ */
+ public long[] getRepresentation() {
+ final long[] clonedRepresentation = new long[representation.length];
+ System.arraycopy(representation, 0, clonedRepresentation, 0, representation.length);
+ return clonedRepresentation;
+ }
+
+ /**
+ * Returns the binary string representation of the chromosome.
+ * @return the string representation
+ */
+ public String getStringRepresentation() {
+ if (length > Integer.MAX_VALUE) {
+ throw new GeneticException(GeneticException.LENGTH_TOO_LARGE, length);
+ }
+ return getStringRepresentation(0, length);
+ }
+
+ /**
+ * Returns the binary string representation of the chromosome alleles from
+ * start(inclusive) to end(exclusive) index.
+ * @param start start allele/gene index(inclusive)
+ * @param end end allele/gene index(exclusive)
+ * @return the string representation
+ */
+ public String getStringRepresentation(long start, long end) {
+ if (start >= end) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT,
+ "start " + start + " is greater than end " + end);
+ }
+ if (end - start > Integer.MAX_VALUE) {
+ throw new GeneticException(GeneticException.LENGTH_TOO_LARGE, end - start);
+ }
+ final int offset = (int) (length % Long.SIZE == 0 ? 0 : Long.SIZE - length % Long.SIZE);
+ final long offsettedStart = offset + start;
+ final long offsettedEnd = offset + end;
+ final int startAlleleBlockIndex = (int) (offsettedStart / Long.SIZE);
+ final int endAlleleBlockIndex = (int) (offsettedEnd / Long.SIZE);
+ final int startAlleleElementIndex = (int) (offsettedStart % Long.SIZE);
+ final int endAlleleElementIndex = (int) (offsettedEnd % Long.SIZE);
+
+ if (startAlleleBlockIndex == endAlleleBlockIndex) {
+ return getAlleleBlockString(startAlleleBlockIndex).substring(startAlleleElementIndex,
+ endAlleleElementIndex);
+ } else {
+ final StringBuilder allelesStrRepresentation = new StringBuilder();
+
+ // extract string representation of first allele block.
+ allelesStrRepresentation
+ .append(getAlleleBlockString(startAlleleBlockIndex).substring(startAlleleElementIndex));
+
+ // extract string representation of all allele blocks except first and last.
+ for (int i = startAlleleBlockIndex + 1; i < endAlleleBlockIndex; i++) {
+ allelesStrRepresentation.append(getAlleleBlockString(i));
+ }
+
+ // extract string representation from last allele block if end allele index !=
+ // 0.
+ if (endAlleleElementIndex != 0) {
+ allelesStrRepresentation
+ .append(getAlleleBlockString(endAlleleBlockIndex).substring(0, endAlleleElementIndex));
+ }
+
+ return allelesStrRepresentation.toString();
+ }
+ }
+
+ /**
+ * Returns the allele block as binary string representation.
+ * @param alleleBlockIndex index of allele block i.e. array element
+ * @return the string representation
+ */
+ private String getAlleleBlockString(final int alleleBlockIndex) {
+ return prepareZeroPrefix(representation[alleleBlockIndex] == 0 ? Long.SIZE - 1 :
+ Long.numberOfLeadingZeros(representation[alleleBlockIndex])) +
+ Long.toUnsignedString(representation[alleleBlockIndex], 2);
+ }
+
+ /**
+ * Prepares zero prefix for binary chromosome.
+ * @param count number of zeros
+ * @return prefix
+ */
+ private String prepareZeroPrefix(int count) {
+ final StringBuilder zeroPrefix = new StringBuilder();
+ for (int i = 0; i < count; i++) {
+ zeroPrefix.append('0');
+ }
+ return zeroPrefix.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public FitnessFunction<P> getFitnessFunction() {
+ return super.getFitnessFunction();
+ }
+
+ /**
+ * Creates a new chromosome with provided parameters.
+ * @param chromosomeRepresentation the representation
+ * @param chromosomeLength length of chromosome
+ * @return chromosome
+ */
+ public BinaryChromosome<P> newChromosome(long[] chromosomeRepresentation, long chromosomeLength) {
+ return new BinaryChromosome<P>(chromosomeRepresentation, chromosomeLength, getFitnessFunction(), getDecoder());
+ }
+
+ /**
+ * Creates an instance of Binary Chromosome with random binary representation.
+ * @param <P> phenotype fo chromosome
+ * @param length length of chromosome
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link Decoder}
+ * @return a binary chromosome
+ */
+ public static <P> BinaryChromosome<P> randomChromosome(int length,
+ FitnessFunction<P> fitnessFunction,
+ Decoder<P> decoder) {
+ return new BinaryChromosome<P>(ChromosomeRepresentationUtils.randomBinaryRepresentation(length), length,
+ fitnessFunction, decoder);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/Chromosome.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/Chromosome.java
new file mode 100644
index 0000000..b29461c
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/Chromosome.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+/**
+ * This abstraction represents a chromosome.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public interface Chromosome<P> extends Comparable<Chromosome<P>> {
+
+ /**
+ * Access the fitness of this chromosome. The bigger the fitness, the better the
+ * chromosome.
+ * <p>
+ * 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();
+
+ /**
+ * Returns unique Id of chromosome.
+ * @return id
+ */
+ String getId();
+}
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 0000000..1157a00
--- /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 <P> phenotype of chromosome
+ * @since 2.0
+ */
+public class ChromosomePair<P> {
+
+ /** the first chromosome in the pair. */
+ private final Chromosome<P> first;
+
+ /** the second chromosome in the pair. */
+ private final Chromosome<P> second;
+
+ /**
+ * Create a chromosome pair.
+ * @param c1 the first chromosome.
+ * @param c2 the second chromosome.
+ */
+ public ChromosomePair(final Chromosome<P> c1, final Chromosome<P> c2) {
+ super();
+ first = c1;
+ second = c2;
+ }
+
+ /**
+ * Access the first chromosome.
+ *
+ * @return the first chromosome.
+ */
+ public Chromosome<P> getFirst() {
+ return first;
+ }
+
+ /**
+ * Access the second chromosome.
+ *
+ * @return the second chromosome.
+ */
+ public Chromosome<P> 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 0000000..91fcfd2
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/IntegralValuedChromosome.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 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.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+
+/**
+ * Chromosome represented by a list of integral values. The acceptable integral
+ * values should belong to the range min(inclusive) to max(exclusive).
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class IntegralValuedChromosome<P> extends AbstractListChromosome<Integer, P> {
+
+ /** minimum acceptable value of allele. **/
+ private final int min;
+
+ /** maximum acceptable value of allele. **/
+ private final int max;
+
+ /**
+ * @param representation Internal representation 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
+ */
+ public IntegralValuedChromosome(List<Integer> representation,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Integer, P> decoder,
+ int min,
+ int max) {
+ super(representation, fitnessFunction, decoder);
+ this.min = min;
+ this.max = max;
+ checkValidity();
+ }
+
+ /**
+ * @param representation Internal representation 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
+ */
+ public IntegralValuedChromosome(Integer[] representation,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Integer, P> decoder,
+ int min,
+ int max) {
+ super(representation, fitnessFunction, decoder);
+ this.min = min;
+ this.max = max;
+ checkValidity();
+ }
+
+ /**
+ * Returns the minimum acceptable value of allele.
+ * @return minimum value
+ */
+ public int getMin() {
+ return min;
+ }
+
+ /**
+ * Returns the maximum acceptable value of allele.
+ * @return maximum value
+ */
+ public int getMax() {
+ return max;
+ }
+
+ /**
+ * Asserts that <code>representation</code> can represent a valid chromosome.
+ */
+ private void checkValidity() {
+ if (min >= max) {
+ throw new GeneticException(GeneticException.TOO_LARGE, min, max);
+ }
+ for (int i : getRepresentation()) {
+ if (i < min || i >= max) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, i);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IntegralValuedChromosome<P> newChromosome(List<Integer> chromosomeRepresentation) {
+ return new IntegralValuedChromosome<>(chromosomeRepresentation, getFitnessFunction(), getDecoder(), this.min,
+ this.max);
+ }
+
+ /**
+ * Creates an instance of Integral valued Chromosome with random binary
+ * representation.
+ * @param <P> 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 <P> IntegralValuedChromosome<P> randomChromosome(int length,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Integer, P> decoder,
+ int min,
+ int max) {
+ return new IntegralValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomIntegralRepresentation(length, min, max), fitnessFunction, decoder,
+ min, max);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/RealValuedChromosome.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/RealValuedChromosome.java
new file mode 100644
index 0000000..603a1e2
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/RealValuedChromosome.java
@@ -0,0 +1,160 @@
+/*
+ * 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.Arrays;
+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.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+
+/**
+ * DoubleEncodedChromosome is used for representing chromosome encoded as
+ * Double. It is a vector of a fixed length of real numbers.The acceptable real
+ * values should belong to the range min(inclusive) to max(exclusive).
+ * <p>
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class RealValuedChromosome<P> extends AbstractListChromosome<Double, P> {
+
+ /** minimum acceptable value of allele. **/
+ private final double min;
+
+ /** maximum acceptable value of allele. **/
+ private final double max;
+
+ /**
+ * @param representation an array of real values
+ * @param fitnessFunction the fitness function
+ * @param decoder the {@link AbstractListChromosomeDecoder}
+ */
+ public RealValuedChromosome(final List<Double> representation,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Double, P> decoder) {
+ super(representation, fitnessFunction, decoder);
+ this.min = 0;
+ this.max = 1d;
+ checkValidity();
+ }
+
+ /**
+ * @param representation an array of real values
+ * @param fitnessFunction the fitness function
+ * @param decoder the {@link AbstractListChromosomeDecoder}
+ * @param min minimum inclusive value of allele
+ * @param max maximum exclusive value of allele
+ */
+ public RealValuedChromosome(final List<Double> representation,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Double, P> decoder,
+ double min,
+ double max) {
+ super(representation, fitnessFunction, decoder);
+ this.min = min;
+ this.max = max;
+ checkValidity();
+ }
+
+ /**
+ * @param representation Internal representation of chromosome as genotype
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link AbstractListChromosomeDecoder}
+ */
+ public RealValuedChromosome(final Double[] representation,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Double, P> decoder) {
+ this(Arrays.asList(representation), fitnessFunction, decoder);
+ }
+
+ /**
+ * @param representation Internal representation of chromosome as genotype
+ * @param fitnessFunction The {@link FitnessFunction}
+ * @param decoder The {@link AbstractListChromosomeDecoder}
+ * @param min minimum inclusive value of allele
+ * @param max maximum exclusive value of allele
+ */
+ public RealValuedChromosome(final Double[] representation,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Double, P> decoder,
+ double min,
+ double max) {
+ this(Arrays.asList(representation), fitnessFunction, decoder, min, max);
+ }
+
+ /**
+ * Return the minimum allele value.
+ * @return minimum
+ */
+ public double getMin() {
+ return min;
+ }
+
+ /**
+ * Returns the maximum allele value.
+ * @return maximum
+ */
+ public double getMax() {
+ return max;
+ }
+
+ /**
+ * Asserts that <code>representation</code> can represent a valid chromosome.
+ */
+ private void checkValidity() {
+ if (min >= max) {
+ throw new GeneticException(GeneticException.TOO_LARGE, min, max);
+ }
+ for (double i : getRepresentation()) {
+ if (i < min || i >= max) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, i);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public RealValuedChromosome<P> newChromosome(List<Double> chromosomeRepresentation) {
+ return new RealValuedChromosome<>(chromosomeRepresentation, getFitnessFunction(), getDecoder(), this.min,
+ this.max);
+ }
+
+ /**
+ * Creates an instance of RealValued chromosome with randomly generated
+ * representation.
+ * @param <P> 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 <P> RealValuedChromosome<P> randomChromosome(int length,
+ FitnessFunction<P> fitnessFunction,
+ AbstractListChromosomeDecoder<Double, P> decoder,
+ double min,
+ double max) {
+ return new RealValuedChromosome<>(ChromosomeRepresentationUtils.randomDoubleRepresentation(length, min, max),
+ fitnessFunction, decoder, min, max);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/package-info.java
new file mode 100644
index 0000000..196ddd9
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/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.chromosome;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/FixedElapsedTime.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/FixedElapsedTime.java
new file mode 100644
index 0000000..8fda02b
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/FixedElapsedTime.java
@@ -0,0 +1,80 @@
+/*
+ * 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.convergence;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Stops after a fixed amount of time has elapsed.
+ * <p>
+ * The first time {@link #isSatisfied(Population)} is invoked, the end time of
+ * the evolution is determined based on the provided <code>maxTime</code> value.
+ * Once the elapsed time reaches the configured <code>maxTime</code> value,
+ * {@link #isSatisfied(Population)} returns true.
+ *
+ * @param <P> phenotype of chromosome
+ * @since 3.1
+ */
+public class FixedElapsedTime<P> implements StoppingCondition<P> {
+
+ /** 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 <code>true</code> IFF the maximum allowed time period has elapsed
+ */
+ @Override
+ public boolean isSatisfied(Population<P> 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/convergence/FixedGenerationCount.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/FixedGenerationCount.java
new file mode 100644
index 0000000..37cfff9
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/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.convergence;
+
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Stops after a fixed number of generations.
+ * <p>
+ * 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 <P> phenotype of chromosome
+ * @since 2.0
+ */
+public class FixedGenerationCount<P> implements StoppingCondition<P> {
+ /** 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 <code>true</code> IFF the maximum number of generations has been
+ * exceeded
+ */
+ @Override
+ public boolean isSatisfied(Population<P> 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/convergence/StoppingCondition.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/StoppingCondition.java
new file mode 100644
index 0000000..601c098
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/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.convergence;
+
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Algorithm used to determine when to stop evolution.
+ *
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ */
+public interface StoppingCondition<P> {
+
+ /**
+ * Determine whether or not the given population satisfies the stopping
+ * condition.
+ * @param population population of chromosome
+ *
+ * @return <code>true</code> if this stopping condition is met by the given
+ * population, <code>false</code> otherwise.
+ */
+ boolean isSatisfied(Population<P> population);
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/UnchangedBestFitness.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/UnchangedBestFitness.java
new file mode 100644
index 0000000..2281b2a
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/UnchangedBestFitness.java
@@ -0,0 +1,72 @@
+/*
+ * 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.convergence;
+
+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 <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class UnchangedBestFitness<P> implements StoppingCondition<P> {
+
+ /** 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;
+
+ /**
+ * @param maxGenerationsWithUnchangedAverageFitness maximum number of
+ * generations with unchanged
+ * best fitness
+ */
+ public UnchangedBestFitness(final int maxGenerationsWithUnchangedAverageFitness) {
+ this.maxGenerationsWithUnchangedBestFitness = maxGenerationsWithUnchangedAverageFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isSatisfied(Population<P> 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/convergence/UnchangedMeanFitness.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/UnchangedMeanFitness.java
new file mode 100644
index 0000000..a729e0a
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/UnchangedMeanFitness.java
@@ -0,0 +1,85 @@
+/*
+ * 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.convergence;
+
+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 <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class UnchangedMeanFitness<P> implements StoppingCondition<P> {
+
+ /** 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;
+
+ /**
+ * @param maxGenerationsWithUnchangedMeanFitness maximum number of generations
+ * with unchanged mean fitness
+ */
+ public UnchangedMeanFitness(final int maxGenerationsWithUnchangedMeanFitness) {
+ this.maxGenerationsWithUnchangedMeanFitness = maxGenerationsWithUnchangedMeanFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isSatisfied(Population<P> 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<P> population) {
+ double totalFitness = 0.0;
+ for (Chromosome<P> chromosome : population) {
+ totalFitness += chromosome.evaluate();
+ }
+ return totalFitness / population.getPopulationSize();
+ }
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/package-info.java
new file mode 100644
index 0000000..d386944
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/convergence/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.convergence;
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 0000000..c56434d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicy.java
@@ -0,0 +1,53 @@
+/*
+ * 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.RandomProviderManager;
+
+/**
+ * An abstraction to represent the base crossover policy.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractChromosomeCrossoverPolicy<P> implements CrossoverPolicy<P> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ChromosomePair<P> crossover(final Chromosome<P> first,
+ final Chromosome<P> second,
+ final double crossoverRate) {
+ if (RandomProviderManager.getRandomProvider().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<P> crossover(Chromosome<P> first, Chromosome<P> 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 0000000..2184310
--- /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.internal.exception.GeneticException;
+
+/**
+ * An abstraction of crossover policy for list chromosomes.
+ * @param <T> genetype of chromosome
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractListChromosomeCrossoverPolicy<T, P> extends AbstractChromosomeCrossoverPolicy<P> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public ChromosomePair<P> crossover(final Chromosome<P> first, final Chromosome<P> second) {
+ // check for validity.
+ checkValidity(first, second);
+
+ final AbstractListChromosome<T, P> firstListChromosome = (AbstractListChromosome<T, P>) first;
+ final AbstractListChromosome<T, P> secondListChromosome = (AbstractListChromosome<T, P>) second;
+
+ return mate(firstListChromosome, secondListChromosome);
+ }
+
+ /**
+ * Validates the chromosome pair.
+ * @param first first chromosome
+ * @param second second chromosome
+ */
+ @SuppressWarnings("unchecked")
+ protected void checkValidity(final Chromosome<P> first, final Chromosome<P> second) {
+ if (!(first instanceof AbstractListChromosome<?, ?> && second instanceof AbstractListChromosome<?, ?>)) {
+ throw new GeneticException(GeneticException.INVALID_FIXED_LENGTH_CHROMOSOME);
+ }
+ final AbstractListChromosome<T, P> firstListChromosome = (AbstractListChromosome<T, P>) first;
+ final AbstractListChromosome<T, P> secondListChromosome = (AbstractListChromosome<T, P>) second;
+
+ final int length = firstListChromosome.getLength();
+ if (length != secondListChromosome.getLength()) {
+ throw new GeneticException(GeneticException.SIZE_MISMATCH, secondListChromosome.getLength(), length);
+ }
+
+ }
+
+ /**
+ * Performs mating between two chromosomes and returns the offspring pair.
+ * @param first The first parent chromosome participating in crossover
+ * @param second The second parent chromosome participating in crossover
+ * @return chromosome pair
+ */
+ protected abstract ChromosomePair<P> mate(AbstractListChromosome<T, P> first, AbstractListChromosome<T, P> second);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/CrossoverPolicy.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/CrossoverPolicy.java
new file mode 100644
index 0000000..65aa191
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/CrossoverPolicy.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * Policy used to create a pair of new chromosomes by performing a crossover
+ * operation on a source pair of chromosomes.
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ */
+public interface CrossoverPolicy<P> {
+
+ /**
+ * 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<P> crossover(Chromosome<P> first, Chromosome<P> 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 0000000..1d0da03
--- /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.RandomProviderManager;
+
+/**
+ * Cycle Crossover [CX] builds offspring from <b>ordered</b> chromosomes by
+ * identifying cycles between two parent chromosomes. To form the children, the
+ * cycles are copied from the respective parents.
+ * <p>
+ * To form a cycle the following procedure is applied:
+ * <ol>
+ * <li>start with the first gene of parent 1</li>
+ * <li>look at the gene at the same position of parent 2</li>
+ * <li>go to the position with the same gene in parent 1</li>
+ * <li>add this gene index to the cycle</li>
+ * <li>repeat the steps 2-5 until we arrive at the starting gene of this
+ * cycle</li>
+ * </ol>
+ * 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):
+ * <pre>
+ * 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
+ * </pre>
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @see <a href=
+ * "http://www.rubicite.com/Tutorials/GeneticAlgorithms/CrossoverOperators/CycleCrossoverOperator.aspx">
+ * Cycle Crossover Operator</a>
+ * @param <T> generic type of the {@link AbstractListChromosome}s for crossover
+ * @param <P> phenotype of chromosome
+ * @since 3.1
+ */
+public class CycleCrossover<T, P> extends AbstractListChromosomeCrossoverPolicy<T, P> {
+
+ /** If the start index shall be chosen randomly. */
+ private final boolean randomStart;
+
+ /**
+ * Creates a new {@link CycleCrossover} policy.
+ */
+ public CycleCrossover() {
+ this(false);
+ }
+
+ /**
+ * Creates a new {@link CycleCrossover} policy using the given
+ * {@code randomStart} behavior.
+ *
+ * @param randomStart whether the start index shall be chosen randomly or be set
+ * to 0
+ */
+ public CycleCrossover(final boolean randomStart) {
+ this.randomStart = randomStart;
+ }
+
+ /**
+ * Returns whether the starting index is chosen randomly or set to zero.
+ *
+ * @return {@code true} if the starting index is chosen randomly, {@code false}
+ * otherwise
+ */
+ public boolean isRandomStart() {
+ return randomStart;
+ }
+
+ /**
+ * Helper for {@link #crossover(Chromosome, Chromosome, double)}. Performs the
+ * actual crossover.
+ *
+ * @param first the first chromosome
+ * @param second the second chromosome
+ * @return the pair of new chromosomes that resulted from the crossover
+ */
+ @Override
+ protected ChromosomePair<P> mate(final AbstractListChromosome<T, P> first,
+ final AbstractListChromosome<T, P> second) {
+
+ final int length = first.getLength();
+ // array representations of the parents
+ final List<T> parent1Rep = first.getRepresentation();
+ final List<T> parent2Rep = second.getRepresentation();
+ // and of the children: do a crossover copy to simplify the later processing
+ final List<T> child1Rep = new ArrayList<>(second.getRepresentation());
+ final List<T> child2Rep = new ArrayList<>(first.getRepresentation());
+
+ // the set of all visited indices so far
+ final Set<Integer> visitedIndices = new HashSet<>(length);
+ // the indices of the current cycle
+ final List<Integer> indices = new ArrayList<>(length);
+
+ // determine the starting index
+ int idx = randomStart ? RandomProviderManager.getRandomProvider().nextInt(length) : 0;
+ int cycle = 1;
+
+ while (visitedIndices.size() < length) {
+ indices.add(idx);
+
+ T item = parent2Rep.get(idx);
+ idx = parent1Rep.indexOf(item);
+
+ while (idx != indices.get(0)) {
+ // add that index to the cycle indices
+ indices.add(idx);
+ // get the item in the second parent at that index
+ item = parent2Rep.get(idx);
+ // get the index of that item in the first parent
+ idx = parent1Rep.indexOf(item);
+ }
+
+ // for even cycles: swap the child elements on the indices found in this cycle
+ if (cycle++ % 2 != 0) {
+ for (int i : indices) {
+ final T tmp = child1Rep.get(i);
+ child1Rep.set(i, child2Rep.get(i));
+ child2Rep.set(i, tmp);
+ }
+ }
+
+ visitedIndices.addAll(indices);
+ // find next starting index: last one + 1 until we find an unvisited index
+ idx = (indices.get(0) + 1) % length;
+ while (visitedIndices.contains(idx) && visitedIndices.size() < length) {
+ idx++;
+ if (idx >= length) {
+ idx = 0;
+ }
+ }
+ indices.clear();
+ }
+
+ return new ChromosomePair<>(first.newChromosome(child1Rep), second.newChromosome(child2Rep));
+ }
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/NPointCrossover.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/NPointCrossover.java
new file mode 100644
index 0000000..f0313c1
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/NPointCrossover.java
@@ -0,0 +1,154 @@
+/*
+ * 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.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+import org.apache.commons.rng.UniformRandomProvider;
+
+/**
+ * N-point crossover policy. For each iteration a random crossover point is
+ * selected and the first part from each parent is copied to the corresponding
+ * child, and the second parts are copied crosswise.
+ *
+ * Example (2-point crossover):
+ * <pre>
+ * -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)
+ * </pre>
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @param <T> generic type of the {@link AbstractListChromosome}s for crossover
+ * @param <P> phenotype of chromosome
+ * @since 3.1
+ */
+public class NPointCrossover<T, P> extends AbstractListChromosomeCrossoverPolicy<T, P> {
+
+ /** The number of crossover points. */
+ private final int crossoverPoints;
+
+ /**
+ * Creates a new {@link NPointCrossover} policy using the given number of
+ * points.
+ * <p>
+ * <b>Note</b>: the number of crossover points must be <
+ * <code>chromosome length - 1</code>. 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):
+ * <pre>
+ * -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)
+ * </pre>
+ *
+ * @param first first parent (p1)
+ * @param second second parent (p2)
+ * @return pair of two children (c1,c2)
+ */
+ @Override
+ protected ChromosomePair<P> mate(final AbstractListChromosome<T, P> first,
+ final AbstractListChromosome<T, P> second) {
+
+ final int length = first.getLength();
+ if (crossoverPoints >= length) {
+ throw new GeneticException(GeneticException.TOO_LARGE, crossoverPoints, length);
+ }
+
+ // array representations of the parents
+ final List<T> parent1Rep = first.getRepresentation();
+ final List<T> parent2Rep = second.getRepresentation();
+ // and of the children
+ final List<T> child1Rep = new ArrayList<>(length);
+ final List<T> child2Rep = new ArrayList<>(length);
+
+ final UniformRandomProvider random = RandomProviderManager.getRandomProvider();
+
+ List<T> c1 = child1Rep;
+ List<T> c2 = child2Rep;
+
+ int remainingPoints = crossoverPoints;
+ int lastIndex = 0;
+ for (int i = 0; i < crossoverPoints; i++, remainingPoints--) {
+ // select the next crossover point at random
+ final int crossoverIndex = 1 + lastIndex + random.nextInt(length - lastIndex - remainingPoints);
+
+ // copy the current segment
+ for (int j = lastIndex; j < crossoverIndex; j++) {
+ c1.add(parent1Rep.get(j));
+ c2.add(parent2Rep.get(j));
+ }
+
+ // swap the children for the next segment
+ final List<T> tmp = c1;
+ c1 = c2;
+ c2 = tmp;
+
+ lastIndex = crossoverIndex;
+ }
+
+ // copy the last segment
+ for (int j = lastIndex; j < length; j++) {
+ c1.add(parent1Rep.get(j));
+ c2.add(parent2Rep.get(j));
+ }
+
+ return new ChromosomePair<>(first.newChromosome(child1Rep), second.newChromosome(child2Rep));
+ }
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OnePointBinaryCrossover.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OnePointBinaryCrossover.java
new file mode 100644
index 0000000..f860798
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OnePointBinaryCrossover.java
@@ -0,0 +1,115 @@
+/*
+ * 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.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * OnePoint Crossover Policy for Binary chromosomes.
+ * @param <P> the phenotype
+ */
+public class OnePointBinaryCrossover<P> extends AbstractChromosomeCrossoverPolicy<P> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ChromosomePair<P> crossover(Chromosome<P> first, Chromosome<P> second) {
+
+ if (!(first instanceof BinaryChromosome<?> && second instanceof BinaryChromosome<?>)) {
+ throw new GeneticException(GeneticException.INVALID_FIXED_LENGTH_CHROMOSOME);
+ }
+ final BinaryChromosome<P> firstChromosome = (BinaryChromosome<P>) first;
+ final BinaryChromosome<P> secondChromosome = (BinaryChromosome<P>) second;
+
+ final long alleleCount = firstChromosome.getLength();
+
+ // array representations of the parents
+ final long[] parent1Rep = firstChromosome.getRepresentation();
+ final long[] parent2Rep = secondChromosome.getRepresentation();
+
+ // and of the children
+ final long[] child1Rep = new long[parent1Rep.length];
+ final long[] child2Rep = new long[parent2Rep.length];
+
+ // select a crossover point at random (0 and length makes no sense)
+ final long crossoverIndex = 1 + (RandomProviderManager.getRandomProvider().nextLong(alleleCount - 1));
+
+ final int offset = (int) (alleleCount % Long.SIZE == 0 ? 0 : Long.SIZE - alleleCount % Long.SIZE);
+ final long offsettedCrossoverIndex = crossoverIndex + offset;
+
+ final int crossoverBlockIndex = (int) (offsettedCrossoverIndex / Long.SIZE);
+ final int crossoverBlockAlleleIndex = (int) offsettedCrossoverIndex % Long.SIZE;
+
+ if (crossoverBlockAlleleIndex == 0) {
+ // if the offsetted-crossover index is divisible by
+ // Long.SIZE then first copy all
+ // elements of previous array elements.
+ for (int i = 0; i < crossoverBlockIndex; i++) {
+ child1Rep[i] = parent1Rep[i];
+ child2Rep[i] = parent2Rep[i];
+ }
+ // copy all elements from crossover block index.
+ for (int i = crossoverBlockIndex; i < parent1Rep.length; i++) {
+ child1Rep[i] = parent2Rep[i];
+ child2Rep[i] = parent1Rep[i];
+ }
+ } else {
+ // copy all parent array elements to child till crossover block index - 1.
+ for (int i = 0; i < crossoverBlockIndex; i++) {
+ child1Rep[i] = parent1Rep[i];
+ child2Rep[i] = parent2Rep[i];
+ }
+ // do exchange of alleles of the array element indexed at crossover block index.
+ final long parent1CrossoverBlockRep = parent1Rep[crossoverBlockIndex];
+ final long parent2CrossoverBlockRep = parent2Rep[crossoverBlockIndex];
+ final long leftMask = Long.MIN_VALUE >> crossoverBlockAlleleIndex - 1;
+ final long rightMask = crossoverBlockAlleleIndex != 1 ?
+ (long) Math.pow(2, Long.SIZE - crossoverBlockAlleleIndex) - 1 :
+ Long.MAX_VALUE;
+
+ final long child1CrossoverBlockRep = (parent1CrossoverBlockRep & leftMask) |
+ (parent2CrossoverBlockRep & rightMask);
+ final long child2CrossoverBlockRep = (parent2CrossoverBlockRep & leftMask) |
+ (parent1CrossoverBlockRep & rightMask);
+
+ child1Rep[crossoverBlockIndex] = child1CrossoverBlockRep;
+ child2Rep[crossoverBlockIndex] = child2CrossoverBlockRep;
+
+ // Copy all the alleles which belong to array elements having index >
+ // crossover block index.
+ if (crossoverBlockIndex < parent1Rep.length - 1) {
+ for (int i = crossoverBlockIndex + 1; i < parent1Rep.length; i++) {
+ child1Rep[i] = parent2Rep[i];
+ child2Rep[i] = parent1Rep[i];
+ }
+ }
+ }
+
+ final BinaryChromosome<P> childChromosome1 = new BinaryChromosome<>(child1Rep, alleleCount,
+ firstChromosome.getFitnessFunction(), firstChromosome.getDecoder());
+ final BinaryChromosome<P> childChromosome2 = new BinaryChromosome<>(child2Rep, alleleCount,
+ secondChromosome.getFitnessFunction(), secondChromosome.getDecoder());
+
+ return new ChromosomePair<>(childChromosome1, childChromosome2);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OnePointCrossover.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OnePointCrossover.java
new file mode 100644
index 0000000..2c6da54
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OnePointCrossover.java
@@ -0,0 +1,102 @@
+/*
+ * 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.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * One point crossover policy. A random crossover point is selected and the
+ * first part from each parent is copied to the corresponding child, and the
+ * second parts are copied crosswise.
+ *
+ * Example:
+ * <pre>
+ * -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)
+ * </pre>
+ *
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @param <T> generic type of the {@link AbstractListChromosome}s for crossover
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ *
+ */
+public class OnePointCrossover<T, P> extends AbstractListChromosomeCrossoverPolicy<T, P> {
+
+ /**
+ * Performs one point crossover. A random crossover point is selected and the
+ * first part from each parent is copied to the corresponding child, and the
+ * second parts are copied crosswise.
+ *
+ * Example:
+ * <pre>
+ * -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)
+ * </pre>
+ *
+ * @param first first parent (p1)
+ * @param second second parent (p2)
+ * @return pair of two children (c1,c2)
+ */
+ @Override
+ protected ChromosomePair<P> mate(final AbstractListChromosome<T, P> first,
+ final AbstractListChromosome<T, P> second) {
+ final int length = first.getLength();
+ // array representations of the parents
+ final List<T> parent1Rep = first.getRepresentation();
+ final List<T> parent2Rep = second.getRepresentation();
+ // and of the children
+ final List<T> child1Rep = new ArrayList<>(length);
+ final List<T> child2Rep = new ArrayList<>(length);
+
+ // select a crossover point at random (0 and length makes no sense)
+ final int crossoverIndex = 1 + (RandomProviderManager.getRandomProvider().nextInt(length - 1));
+
+ // copy the first part
+ for (int i = 0; i < crossoverIndex; i++) {
+ child1Rep.add(parent1Rep.get(i));
+ child2Rep.add(parent2Rep.get(i));
+ }
+ // and switch the second part
+ for (int i = crossoverIndex; i < length; i++) {
+ child1Rep.add(parent2Rep.get(i));
+ child2Rep.add(parent1Rep.get(i));
+ }
+
+ return new ChromosomePair<>(first.newChromosome(child1Rep), second.newChromosome(child2Rep));
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OrderedCrossover.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OrderedCrossover.java
new file mode 100644
index 0000000..24608f9
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OrderedCrossover.java
@@ -0,0 +1,131 @@
+/*
+ * 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.Collections;
+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.RandomProviderManager;
+import org.apache.commons.rng.UniformRandomProvider;
+
+/**
+ * Order 1 Crossover [OX1] builds offspring from <b>ordered</b> chromosomes by
+ * copying a consecutive slice from one parent, and filling up the remaining
+ * genes from the other parent as they appear.
+ * <p>
+ * This policy works by applying the following rules:
+ * <ol>
+ * <li>select a random slice of consecutive genes from parent 1</li>
+ * <li>copy the slice to child 1 and mark out the genes in parent 2</li>
+ * <li>starting from the right side of the slice, copy genes from parent 2 as
+ * they appear to child 1 if they are not yet marked out.</li>
+ * </ol>
+ * <p>
+ * Example (random sublist from index 3 to 7, underlined):
+ * <pre>
+ * 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)
+ * </pre>
+ * <p>
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @see <a href=
+ * "http://www.rubicite.com/Tutorials/GeneticAlgorithms/CrossoverOperators/Order1CrossoverOperator.aspx">
+ * Order 1 Crossover Operator</a>
+ *
+ * @param <T> generic type of the {@link AbstractListChromosome}s for crossover
+ * @param <P> phenotype of chromosome
+ * @since 3.1
+ */
+public class OrderedCrossover<T, P> extends AbstractListChromosomeCrossoverPolicy<T, P> {
+
+ /**
+ * Helper for {@link #crossover(Chromosome, Chromosome, double)}. Performs the
+ * actual crossover.
+ *
+ * @param first the first chromosome
+ * @param second the second chromosome
+ * @return the pair of new chromosomes that resulted from the crossover
+ */
+ @Override
+ protected ChromosomePair<P> mate(final AbstractListChromosome<T, P> first,
+ final AbstractListChromosome<T, P> second) {
+
+ final int length = first.getLength();
+ // array representations of the parents
+ final List<T> parent1Rep = first.getRepresentation();
+ final List<T> parent2Rep = second.getRepresentation();
+ // and of the children
+ final List<T> child1 = new ArrayList<>(length);
+ final List<T> child2 = new ArrayList<>(length);
+ // sets of already inserted items for quick access
+ final Set<T> child1Set = new HashSet<>(length);
+ final Set<T> child2Set = new HashSet<>(length);
+
+ final UniformRandomProvider random = RandomProviderManager.getRandomProvider();
+ // choose random points, making sure that lb < ub.
+ final int a = random.nextInt(length);
+ int b;
+ do {
+ b = random.nextInt(length);
+ } while (a == b);
+ // determine the lower and upper bounds
+ final int lb = Math.min(a, b);
+ final int ub = Math.max(a, b);
+
+ // add the subLists that are between lb and ub
+ child1.addAll(parent1Rep.subList(lb, ub + 1));
+ child1Set.addAll(child1);
+ child2.addAll(parent2Rep.subList(lb, ub + 1));
+ child2Set.addAll(child2);
+
+ // iterate over every item in the parents
+ for (int i = 1; i <= length; i++) {
+ final int idx = (ub + i) % length;
+
+ // retrieve the current item in each parent
+ final T item1 = parent1Rep.get(idx);
+ final T item2 = parent2Rep.get(idx);
+
+ // if the first child already contains the item in the second parent add it
+ if (!child1Set.contains(item2)) {
+ child1.add(item2);
+ child1Set.add(item2);
+ }
+
+ // if the second child already contains the item in the first parent add it
+ if (!child2Set.contains(item1)) {
+ child2.add(item1);
+ child2Set.add(item1);
+ }
+ }
+
+ // rotate so that the original slice is in the same place as in the parents.
+ Collections.rotate(child1, lb);
+ Collections.rotate(child2, lb);
+
+ return new ChromosomePair<>(first.newChromosome(child1), second.newChromosome(child2));
+ }
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/UniformCrossover.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/UniformCrossover.java
new file mode 100644
index 0000000..23292f7
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/UniformCrossover.java
@@ -0,0 +1,123 @@
+/*
+ * 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.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+import org.apache.commons.rng.UniformRandomProvider;
+
+/**
+ * Perform Uniform Crossover [UX] on the specified chromosomes. A fixed mixing
+ * ratio is used to combine genes from the first and second parents, e.g. using
+ * a ratio of 0.5 would result in approximately 50% of genes coming from each
+ * parent. This is typically a poor method of crossover, but empirical evidence
+ * suggests that it is more exploratory and results in a larger part of the
+ * problem space being searched.
+ * <p>
+ * 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).
+ * <p>
+ * This policy works only on {@link AbstractListChromosome}, and therefore it is
+ * parameterized by T. Moreover, the chromosomes must have same lengths.
+ *
+ * @see <a href=
+ * "http://en.wikipedia.org/wiki/Crossover_%28genetic_algorithm%29">Crossover
+ * techniques (Wikipedia)</a>
+ * @see <a href=
+ * "http://www.obitko.com/tutorials/genetic-algorithms/crossover-mutation.php">Crossover
+ * (Obitko.com)</a>
+ * @see <a href="http://www.tomaszgwiazda.com/uniformX.htm">Uniform
+ * crossover</a>
+ * @param <T> generic type of the {@link AbstractListChromosome}s for crossover
+ * @param <P> phenotype of chromosome
+ * @since 3.1
+ */
+public class UniformCrossover<T, P> extends AbstractListChromosomeCrossoverPolicy<T, P> {
+
+ /** crossover rate. **/
+ public static final String CROSSOVER_RATE = "CROSSOVER_RATE";
+
+ /** The mixing ratio. */
+ private final double ratio;
+
+ /**
+ * Creates a new {@link UniformCrossover} policy using the given mixing ratio.
+ *
+ * @param ratio the mixing ratio
+ */
+ public UniformCrossover(final double ratio) {
+ if (ratio < 0.0d || ratio > 1.0d) {
+ throw new GeneticException(GeneticException.OUT_OF_RANGE, ratio, CROSSOVER_RATE, 0.0d, 1.0d);
+ }
+ this.ratio = ratio;
+ }
+
+ /**
+ * Returns the mixing ratio used by this {@link CrossoverPolicy}.
+ *
+ * @return the mixing ratio
+ */
+ public double getRatio() {
+ return ratio;
+ }
+
+ /**
+ * Helper for {@link #crossover(Chromosome, Chromosome, double)}. Performs the
+ * actual crossover.
+ *
+ * @param first the first chromosome
+ * @param second the second chromosome
+ * @return the pair of new chromosomes that resulted from the crossover
+ */
+ @Override
+ protected ChromosomePair<P> mate(final AbstractListChromosome<T, P> first,
+ final AbstractListChromosome<T, P> second) {
+ final int length = first.getLength();
+ // array representations of the parents
+ final List<T> parent1Rep = first.getRepresentation();
+ final List<T> parent2Rep = second.getRepresentation();
+ // and of the children
+ final List<T> child1Rep = new ArrayList<>(length);
+ final List<T> child2Rep = new ArrayList<>(length);
+
+ final UniformRandomProvider random = RandomProviderManager.getRandomProvider();
+
+ for (int index = 0; index < length; index++) {
+
+ if (random.nextDouble() < ratio) {
+ // swap the bits -> take other parent
+ child1Rep.add(parent2Rep.get(index));
+ child2Rep.add(parent1Rep.get(index));
+ } else {
+ child1Rep.add(parent1Rep.get(index));
+ child2Rep.add(parent2Rep.get(index));
+ }
+ }
+
+ return new ChromosomePair<>(first.newChromosome(child1Rep), second.newChromosome(child2Rep));
+ }
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/package-info.java
new file mode 100644
index 0000000..68c9282
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/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.crossover;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/AdaptiveLinearAverageRankBasedCrossoverRateGenerator.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/AdaptiveLinearAverageRankBasedCrossoverRateGenerator.java
new file mode 100644
index 0000000..1b1057d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/AdaptiveLinearAverageRankBasedCrossoverRateGenerator.java
@@ -0,0 +1,58 @@
+/*
+ * 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.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * Generates crossover rate based on linear function of relative average rank of
+ * input chromosomes in population.
+ * @param <P> phenotype of chromosome
+ */
+public class AdaptiveLinearAverageRankBasedCrossoverRateGenerator<P> implements CrossoverRateGenerator<P> {
+
+ /** minimum crossover rate. **/
+ private final double minimumRate;
+
+ /** maximum crossover rate. **/
+ private final double maximumRate;
+
+ /**
+ * @param minimumRate minimum crossover rate
+ * @param maximumRate maximum crossover rate
+ */
+ public AdaptiveLinearAverageRankBasedCrossoverRateGenerator(double minimumRate, double maximumRate) {
+ this.maximumRate = maximumRate;
+ this.minimumRate = minimumRate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double generate(Chromosome<P> first,
+ Chromosome<P> second,
+ PopulationStatisticalSummary<P> populationStats,
+ int generation) {
+ final int averageRank = (populationStats.findRank(first) + populationStats.findRank(second)) / 2;
+ return minimumRate +
+ (maximumRate - minimumRate) * (1.0 - (double) averageRank / (populationStats.getPopulationSize() - 1));
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/AdaptiveLinearMaximumRankBasedCrossoverRateGenerator.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/AdaptiveLinearMaximumRankBasedCrossoverRateGenerator.java
new file mode 100644
index 0000000..c03f488
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/AdaptiveLinearMaximumRankBasedCrossoverRateGenerator.java
@@ -0,0 +1,58 @@
+/*
+ * 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.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * Generates crossover rate based on linear function of relative maximum rank of
+ * input chromosomes in population.
+ * @param <P> phenotype of chromosome
+ */
+public class AdaptiveLinearMaximumRankBasedCrossoverRateGenerator<P> implements CrossoverRateGenerator<P> {
+
+ /** minimum crossover rate. **/
+ private final double minimumRate;
+
+ /** maximum crossover rate. **/
+ private final double maximumRate;
+
+ /**
+ * @param minimumRate minimum crossover rate
+ * @param maximumRate maximum crossover rate
+ */
+ public AdaptiveLinearMaximumRankBasedCrossoverRateGenerator(double minimumRate, double maximumRate) {
+ this.maximumRate = maximumRate;
+ this.minimumRate = minimumRate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double generate(Chromosome<P> first,
+ Chromosome<P> second,
+ PopulationStatisticalSummary<P> populationStats,
+ int generation) {
+ final int maximumRank = Math.max(populationStats.findRank(first), populationStats.findRank(second));
+ return minimumRate +
+ (maximumRate - minimumRate) * (1.0 - (double) maximumRank / (populationStats.getPopulationSize() - 1));
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/ConstantCrossoverRateGenerator.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/ConstantCrossoverRateGenerator.java
new file mode 100644
index 0000000..2f77ce1
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/ConstantCrossoverRateGenerator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * This class represents a constant crossover rate generator.
+ * @param <P> phenotype of chromosome
+ */
+public class ConstantCrossoverRateGenerator<P> implements CrossoverRateGenerator<P> {
+
+ /** the fixed value of crossover rate. **/
+ private final double crossoverRate;
+
+ /**
+ * @param crossoverRate crossover rate
+ */
+ public ConstantCrossoverRateGenerator(double crossoverRate) {
+ this.crossoverRate = crossoverRate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double generate(Chromosome<P> first,
+ Chromosome<P> second,
+ PopulationStatisticalSummary<P> populationStats,
+ int generation) {
+ return crossoverRate;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/CrossoverRateGenerator.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/CrossoverRateGenerator.java
new file mode 100644
index 0000000..438aeed
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/CrossoverRateGenerator.java
@@ -0,0 +1,42 @@
+/*
+ * 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.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * This abstraction represents crossover rate generator.
+ * @param <P> phenotype of chromosome
+ */
+public interface CrossoverRateGenerator<P> {
+
+ /**
+ * Generates crossover rate.
+ * @param first first chromosome
+ * @param second second chromosome
+ * @param populationStats population statistics summary
+ * @param generation generation number
+ * @return crossover rate rate of crossover
+ */
+ double generate(Chromosome<P> first,
+ Chromosome<P> second,
+ PopulationStatisticalSummary<P> populationStats,
+ int generation);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/package-info.java
new file mode 100644
index 0000000..886eab7
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/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.crossover.rategenerator;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/AbstractListChromosomeDecoder.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/AbstractListChromosomeDecoder.java
new file mode 100644
index 0000000..96a1920
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/AbstractListChromosomeDecoder.java
@@ -0,0 +1,59 @@
+/*
+ * 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 org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+
+/**
+ * An abstract Decoder of ListChromosome.
+ * @param <T> genotype fo chromosome
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractListChromosomeDecoder<T, P> implements Decoder<P> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public P decode(Chromosome<P> chromosome) {
+ checkValidity(chromosome);
+
+ return decode((AbstractListChromosome<T, P>) chromosome);
+ }
+
+ /**
+ * Checks validity of {@link Chromosome}.
+ * @param chromosome the {@link Chromosome}
+ */
+ protected void checkValidity(Chromosome<P> 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<T, P> chromosome);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/Decoder.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/Decoder.java
new file mode 100644
index 0000000..50f2ba9
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/Decoder.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.decoder;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+
+/**
+ * Decoder is responsible for converting chromosome genotype to phenotype.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public interface Decoder<P> {
+
+ /**
+ * Converts genotype to phenotype.
+ * @param chromosome The {@link Chromosome}
+ * @return phenotype The phenotype of chromosome
+ */
+ P decode(Chromosome<P> 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 0000000..037ccfd
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/RandomKeyDecoder.java
@@ -0,0 +1,75 @@
+/*
+ * 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 java.util.Objects;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+
+/**
+ * A concrete implementation of RandomKey decoder. This class is responsible for
+ * decoding permutation chromosome encoded with random key.
+ * @param <U> type of the permutation element
+ * @since 4.0
+ */
+public final class RandomKeyDecoder<U> extends AbstractListChromosomeDecoder<Double, List<U>> {
+
+ /** base sequence for decoding chromosome. **/
+ private final List<U> baseSequence;
+
+ /**
+ * @param baseSequence the unpermuted sequence
+ */
+ public RandomKeyDecoder(List<U> baseSequence) {
+ this.baseSequence = Collections.unmodifiableList(Objects.requireNonNull(baseSequence));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected List<U> decode(AbstractListChromosome<Double, List<U>> chromosome) {
+ final List<Double> representation = chromosome.getRepresentation();
+ final List<Double> sortedRepresentation = new ArrayList<>(representation);
+ Collections.sort(sortedRepresentation);
+
+ final int sequenceLength = baseSequence.size();
+
+ // the size of the three lists must be equal
+ if (representation.size() != sequenceLength) {
+ throw new GeneticException(GeneticException.SIZE_MISMATCH, representation.size(), sequenceLength);
+ }
+
+ // do not modify the original representation
+ final List<Double> representationCopy = new ArrayList<>(representation);
+
+ // now find the indices in the original repr and use them for permuting
+ final List<U> res = new ArrayList<>(sequenceLength);
+ for (int i = 0; i < sequenceLength; i++) {
+ final int index = representationCopy.indexOf(sortedRepresentation.get(i));
+ res.add(baseSequence.get(index));
+ representationCopy.set(index, null);
+ }
+
+ return res;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/TransparentListChromosomeDecoder.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/TransparentListChromosomeDecoder.java
new file mode 100644
index 0000000..b8d0be7
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/TransparentListChromosomeDecoder.java
@@ -0,0 +1,39 @@
+/*
+ * 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.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractListChromosome;
+
+/**
+ * A concrete implementation of transparent decoder for List Chromosome. Treats
+ * the gentype as phenotype.
+ * @param <T> the genotype of chromosome
+ * @since 4.0
+ */
+public final class TransparentListChromosomeDecoder<T> extends AbstractListChromosomeDecoder<T, List<T>> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected List<T> decode(AbstractListChromosome<T, List<T>> chromosome) {
+ return chromosome.getRepresentation();
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/package-info.java
new file mode 100644
index 0000000..57e19a8
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/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.decoder;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/fitness/FitnessFunction.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/fitness/FitnessFunction.java
new file mode 100644
index 0000000..ade6dea
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/fitness/FitnessFunction.java
@@ -0,0 +1,34 @@
+/*
+ * 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.fitness;
+
+/**
+ * This interface represents fitness function.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public interface FitnessFunction<P> {
+
+ /**
+ * 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 0000000..5b6d4c5
--- /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/internal/exception/GeneticException.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/exception/GeneticException.java
new file mode 100644
index 0000000..7209472
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/exception/GeneticException.java
@@ -0,0 +1,120 @@
+/*
+ * 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.internal.exception;
+
+import java.text.MessageFormat;
+
+/**
+ * This class represents the Exception encountered during GA optimization.
+ * @since 4.0
+ */
+public class GeneticException extends RuntimeException {
+
+ /** Error message for "out of range" condition. */
+ public static final String OUT_OF_RANGE = "Value {0} of {1} is out of range [{2}, {3}]";
+
+ /** Error message for "not strictly positive" condition. */
+ public static final String NOT_STRICTLY_POSITIVE = "Number {0} is not strictly positive";
+
+ /** Error message for "too large" condition. */
+ public static final String TOO_LARGE = "Number {0} is larger than {1}";
+
+ /** Error message for "too small" condition. */
+ public static final String TOO_SMALL = "Number {0} is smaller than {1}";
+
+ /** Error message for "out of range" condition. */
+ public static final String NO_DATA = "No data";
+
+ /** Error message for "size mismatch" condition. */
+ public static final String SIZE_MISMATCH = "Size mismatch: {0} != {1}";
+
+ /** Error message for "generic illegal argument" condition. */
+ public static final String ILLEGAL_ARGUMENT = "Illegal Argument Exception: {0}";
+
+ /** Error message for "generic illegal argument" condition. */
+ public static final String ILLEGAL_RANGE = "Illegal Range of Value Exception: " +
+ "[Expected min-{0}, max-{1}], [Passed min-{2}, max-{3}]";
+
+ /** Error message for "generic illegal argument" condition. */
+ public static final String INVALID_FIXED_LENGTH_CHROMOSOME = "Invalid Fixed Length Chromosome.";
+
+ /** Error message for "NULL ARGUMENT" condition. */
+ public static final String NULL_ARGUMENT = "Null Argument Exception: {0}";
+
+ /**
+ * Error message for "List of Chromosome bigger than population size" condition.
+ */
+ public static final String LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE = "List of chromosome bigger than " +
+ "population size: {0} > {1}";
+
+ /**
+ * Error message for "population limit not positive" condition.
+ */
+ public static final String POPULATION_LIMIT_NOT_POSITIVE = "Population limit not positive :{0}";
+
+ /**
+ * Error message for " population limit less than list of chromosomes size"
+ * condition.
+ */
+ public static final String POPULATION_LIMIT_LESS_THAN_LIST_OF_CHROMOSOMES_SIZE = "Population limit is " +
+ " lesser than list of chromosomes size : {0} < {1}";
+
+ /**
+ * Error message for different origin and permuted data.
+ */
+ public static final String DIFFERENT_ORIG_AND_PERMUTED_DATA = "Different original and permuted data";
+
+ /**
+ * Error message for chromosome length larger than expected.
+ */
+ public static final String LENGTH_TOO_LARGE = "Chromosome length larger than {0} not supported for" +
+ " string representation.";
+
+ /** Serializable version identifier. */
+ private static final long serialVersionUID = 20210516L;
+
+ /**
+ * Create an exception where the message is constructed by applying the
+ * {@code format()} method from {@code java.text.MessageFormat}.
+ *
+ * @param message Message format (with replaceable parameters).
+ * @param formatArguments Actual arguments to be displayed in the message.
+ */
+ public GeneticException(String message, Object... formatArguments) {
+ super(MessageFormat.format(message, formatArguments));
+ }
+
+ /**
+ * Create an exception.
+ * @param t instance of {@link Throwable}
+ */
+ public GeneticException(Throwable t) {
+ super(t);
+ }
+
+ /**
+ * Create an exception having both stacktrace and message.
+ * @param message the exception message
+ * @param t the instance of {@link Throwable}
+ * @param formatArguments arguments to format the exception message
+ */
+ public GeneticException(String message, Throwable t, Object... formatArguments) {
+ super(MessageFormat.format(message, formatArguments), t);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/exception/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/exception/package-info.java
new file mode 100644
index 0000000..b55e918
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/exception/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.internal.exception;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/stats/PopulationStatisticalSummaryImpl.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/stats/PopulationStatisticalSummaryImpl.java
new file mode 100644
index 0000000..b95b60f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/stats/PopulationStatisticalSummaryImpl.java
@@ -0,0 +1,177 @@
+/*
+ * 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.internal.stats;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * This class represents an implementation of population statistical summary.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class PopulationStatisticalSummaryImpl<P> implements PopulationStatisticalSummary<P> {
+
+ /** maximum fitness of the population. **/
+ private final double maxFitness;
+
+ /** minimum fitness of the population. **/
+ private final double minFitness;
+
+ /** mean fitness of the population. **/
+ private double meanFitness;
+
+ /** variance of population fitness. **/
+ private final double variance;
+
+ /** population size. **/
+ private final int populationSize;
+
+ /** a map of chromosome Id and corresponding rank in population. **/
+ private final Map<String, Integer> chromosomeIdRankMap = new HashMap<>();
+
+ /**
+ * @param population current population {@link Population} of chromosomes
+ */
+ public PopulationStatisticalSummaryImpl(Population<P> population) {
+
+ // Fetch all chromosomes.
+ List<Chromosome<P>> chromosomes = getChromosomes(Objects.requireNonNull(population));
+
+ // Sort all chromosomes.
+ Collections.sort(chromosomes);
+
+ this.populationSize = chromosomes.size();
+ this.maxFitness = chromosomes.get(chromosomes.size() - 1).evaluate();
+ this.minFitness = chromosomes.get(0).evaluate();
+ this.meanFitness = calculateMeanFitness(chromosomes);
+ this.variance = calculateVariance(chromosomes);
+
+ updateChromosomeIdRankMap(chromosomes);
+
+ }
+
+ /**
+ * Updates chromosome Id and rank.
+ * @param chromosomes list of chromosomes
+ */
+ private void updateChromosomeIdRankMap(List<Chromosome<P>> chromosomes) {
+ for (int rank = 0; rank < chromosomes.size(); rank++) {
+ this.chromosomeIdRankMap.put(chromosomes.get(rank).getId(), rank);
+ }
+ }
+
+ /**
+ * Fetches chromosomes.
+ * @param population
+ * @return list of chromosomes
+ */
+ private List<Chromosome<P>> getChromosomes(Population<P> population) {
+ List<Chromosome<P>> chromosomes = new ArrayList<>(population.getPopulationSize());
+ for (Chromosome<P> chromosome : population) {
+ chromosomes.add(chromosome);
+ }
+ return chromosomes;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double getMeanFitness() {
+ return this.meanFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double getFitnessVariance() {
+ return this.variance;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double getMaxFitness() {
+ return this.maxFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double getMinFitness() {
+ return this.minFitness;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getPopulationSize() {
+ return this.populationSize;
+ }
+
+ /**
+ * Calculate mean fitness.
+ * @param chromosomes list of chromosomes
+ * @return returns mean fitness
+ */
+ private double calculateMeanFitness(List<Chromosome<P>> chromosomes) {
+ double sum = 0.0;
+ for (Chromosome<P> chromosome : chromosomes) {
+ sum += chromosome.evaluate();
+ }
+ return sum / chromosomes.size();
+ }
+
+ /**
+ * Calculate variance of population fitness.
+ * @param chromosomes List of chromosomes
+ * @return fitness variance
+ */
+ private double calculateVariance(List<Chromosome<P>> chromosomes) {
+ if (this.meanFitness == 0) {
+ this.meanFitness = calculateMeanFitness(chromosomes);
+ }
+ double sumOfSquare = 0.0;
+ for (Chromosome<P> chromosome : chromosomes) {
+ sumOfSquare += Math.pow(chromosome.evaluate(), 2);
+ }
+
+ return (sumOfSquare / chromosomes.size()) - Math.pow(this.meanFitness, 2);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int findRank(Chromosome<P> chromosome) {
+ return chromosomeIdRankMap.get(chromosome.getId());
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/stats/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/stats/package-info.java
new file mode 100644
index 0000000..a0ae55d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/stats/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.internal.stats;
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 0000000..f99d585
--- /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 <P> phenotype of chromosome
+ * @since 4.0
+ */
+public interface ConvergenceListener<P> {
+
+ /**
+ * Notifies about the population statistics.
+ * @param generation current generation
+ * @param population population of chromosome
+ */
+ void notify(int generation, Population<P> 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 0000000..7fce28e
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/ConvergenceListenerRegistry.java
@@ -0,0 +1,91 @@
+/*
+ * 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 java.util.Objects;
+
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * This class is the default implementation of ConvergenceListenerRegistry. It
+ * will be responsible for registering the interested listeners and notifying
+ * all when required.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public final class ConvergenceListenerRegistry<P> {
+
+ /**
+ * The instance of the singleton class.
+ */
+ @SuppressWarnings("rawtypes")
+ private static final ConvergenceListenerRegistry INSTANCE = new ConvergenceListenerRegistry<>();
+
+ /**
+ * List of registered listeners.
+ */
+ private final List<ConvergenceListener<P>> listeners = new ArrayList<>();
+
+ /**
+ * private constructor to construct the singleton instance.
+ */
+ private ConvergenceListenerRegistry() {
+ }
+
+ /**
+ * Registers the interested ConvergenceListener passed as an argument.
+ * @param convergenceListener The {@link ConvergenceListener}
+ */
+ public void addConvergenceListener(ConvergenceListener<P> convergenceListener) {
+ this.listeners.add(convergenceListener);
+ }
+
+ /**
+ * Notifies all registered ConvergenceListeners about the population statistics.
+ * @param generation current generation
+ * @param population population of chromosomes
+ */
+ public synchronized void notifyAll(int generation, Population<P> population) {
+ for (ConvergenceListener<P> convergenceListener : listeners) {
+ convergenceListener.notify(generation, population);
+ }
+ }
+
+ /**
+ * Add instance of convergence listener.
+ * @param convergenceListeners list of {@link ConvergenceListener}
+ */
+ public void addConvergenceListeners(List<ConvergenceListener<P>> convergenceListeners) {
+ for (ConvergenceListener<P> convergenceListener : Objects.requireNonNull(convergenceListeners)) {
+ addConvergenceListener(convergenceListener);
+ }
+ }
+
+ /**
+ * Returns instance of this class.
+ * @param <P> The phenotype of chromosome
+ * @return instance
+ */
+ @SuppressWarnings("unchecked")
+ public static <P> ConvergenceListenerRegistry<P> 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 0000000..b0f7276
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/PopulationStatisticsLogger.java
@@ -0,0 +1,49 @@
+/*
+ * 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.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Logs population statistics during the convergence process.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public final class PopulationStatisticsLogger<P> implements ConvergenceListener<P> {
+
+ /** instance of log4j logger. **/
+ private static final Logger LOGGER = LoggerFactory.getLogger(PopulationStatisticsLogger.class);
+
+ /**
+ * Logs the population statistics during the process of convergence.
+ */
+ @Override
+ public void notify(int generation, Population<P> population) {
+ final PopulationStatisticalSummary<P> populationStatisticalSummary = new PopulationStatisticalSummaryImpl<>(
+ population);
+ LOGGER.info(
+ "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 0000000..f2e0d4a
--- /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 0000000..3e41fc2
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/AbstractListChromosomeMutationPolicy.java
@@ -0,0 +1,101 @@
+/*
+ * 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.RandomProviderManager;
+import org.apache.commons.rng.UniformRandomProvider;
+
+/**
+ * This abstraction represents an abstract mutation policy for ListChromosomes.
+ * @param <T> genotype of chromosome
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public abstract class AbstractListChromosomeMutationPolicy<T, P> implements MutationPolicy<P> {
+
+ /**
+ * 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<P> mutate(Chromosome<P> original, double mutationRate) {
+ // check for validity.
+ checkValidity(original);
+
+ @SuppressWarnings("unchecked")
+ final AbstractListChromosome<T, P> chromosome = (AbstractListChromosome<T, P>) original;
+ final List<T> newRep = new ArrayList<>(chromosome.getRepresentation());
+
+ final Set<Integer> mutableGeneIndexes = getMutableGeneIndexes(chromosome.getLength(), mutationRate);
+ for (int mutableGeneIndex : mutableGeneIndexes) {
+ newRep.set(mutableGeneIndex, mutateGene(newRep.get(mutableGeneIndex)));
+ }
+
+ return chromosome.newChromosome(newRep);
+ }
+
+ /**
+ * Checks input chromosome validity.
+ * @param original chromosome to be mutated
+ */
+ protected abstract void checkValidity(Chromosome<P> 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<Integer> getMutableGeneIndexes(int length, double mutationRate) {
+
+ // calculate the total mutation rate of all the alleles i.e. chromosome.
+ final double chromosomeMutationRate = mutationRate * length;
+ final Set<Integer> indexSet = new HashSet<>();
+ final UniformRandomProvider randomProvider = RandomProviderManager.getRandomProvider();
+
+ // if chromosomeMutationRate >= 1 then more than one allele will be mutated.
+ if (chromosomeMutationRate >= 1) {
+ final int noOfMutation = (int) Math.round(chromosomeMutationRate);
+ while (indexSet.size() < noOfMutation) {
+ indexSet.add(randomProvider.nextInt(length));
+ }
+ } else if (randomProvider.nextDouble() < chromosomeMutationRate) {
+ indexSet.add(randomProvider.nextInt(length));
+ }
+
+ return indexSet;
+ }
+
+ /**
+ * Mutates an individual gene/allele.
+ * @param originalValue the original value of gene
+ * @return mutated value of gene
+ */
+ protected abstract T mutateGene(T originalValue);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/BinaryMutation.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/BinaryMutation.java
new file mode 100644
index 0000000..2470f38
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/BinaryMutation.java
@@ -0,0 +1,135 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * Mutation for {@link BinaryChromosome}s. Randomly changes few genes.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class BinaryMutation<P> implements MutationPolicy<P> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Chromosome<P> mutate(Chromosome<P> original, double mutationRate) {
+ // check for validity.
+ checkValidity(original);
+ final BinaryChromosome<P> chromosome = (BinaryChromosome<P>) original;
+ final long[] representation = chromosome.getRepresentation();
+ final long[] newRep = new long[representation.length];
+ System.arraycopy(representation, 0, newRep, 0, representation.length);
+
+ final Map<Integer, Set<Integer>> mutableGeneIndexMap = getMutableGeneIndexes(chromosome.getLength(),
+ mutationRate);
+ for (Entry<Integer, Set<Integer>> entry : mutableGeneIndexMap.entrySet()) {
+ final int alleleBlockIndex = entry.getKey();
+ long mask = 0;
+ final Set<Integer> alleleElementIndexes = mutableGeneIndexMap.get(alleleBlockIndex);
+ for (int index : alleleElementIndexes) {
+ mask += index == 0 ? Long.MIN_VALUE : Math.pow(2, Long.SIZE - 1 - index);
+ }
+ newRep[alleleBlockIndex] = newRep[alleleBlockIndex] ^ mask;
+ }
+// for (int alleleBlockIndex : mutableGeneIndexMap.keySet()) {
+// long mask = 0;
+// final Set<Integer> alleleElementIndexes = mutableGeneIndexMap.get(alleleBlockIndex);
+// for (int index : alleleElementIndexes) {
+// mask += index == 0 ? Long.MIN_VALUE : Math.pow(2, Long.SIZE - 1 - index);
+// }
+// newRep[alleleBlockIndex] = newRep[alleleBlockIndex] ^ mask;
+// }
+
+ return chromosome.newChromosome(newRep, chromosome.getLength());
+ }
+
+ /**
+ * Checks input chromosome validity.
+ * @param original chromosome to be mutated
+ */
+ protected void checkValidity(Chromosome<P> original) {
+ if (!BinaryChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, original.getClass().getSimpleName());
+ }
+ }
+
+ /**
+ * 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 Map<Integer, Set<Integer>> getMutableGeneIndexes(long length, double mutationRate) {
+
+ // calculate the total mutation rate of all the alleles i.e. chromosome.
+ final double chromosomeMutationRate = mutationRate * length;
+ final Map<Integer, Set<Integer>> indexMap = new HashMap<>();
+
+ // if chromosomeMutationRate >= 1 then more than one allele will be mutated.
+ if (chromosomeMutationRate >= 1) {
+ final int noOfMutation = (int) Math.round(chromosomeMutationRate);
+ final Set<Long> mutationIndexes = new HashSet<>();
+ for (int i = 0; i < noOfMutation; i++) {
+ final long mutationIndex = generateMutationIndex(length, mutationIndexes);
+ mutationIndexes.add(mutationIndex);
+ updateIndexMap(indexMap, length, mutationIndex);
+ }
+ } else if (RandomProviderManager.getRandomProvider().nextDouble() < chromosomeMutationRate) {
+ updateIndexMap(indexMap, length);
+ }
+ return indexMap;
+ }
+
+ private long generateMutationIndex(long length, Set<Long> mutationIndexes) {
+ long mutationIndex = 0;
+ do {
+ mutationIndex = RandomProviderManager.getRandomProvider().nextLong(length);
+ } while (mutationIndexes.contains(mutationIndex));
+ return mutationIndex;
+ }
+
+ private void updateIndexMap(Map<Integer, Set<Integer>> indexMap, long length, long mutationIndex) {
+ final int offset = (int) (length % Long.SIZE == 0 ? 0 : Long.SIZE - length % Long.SIZE);
+ final long offsettedMutableAlleleIndex = offset + mutationIndex;
+
+ final int alleleBlockIndex = (int) (offsettedMutableAlleleIndex / Long.SIZE);
+
+ if (!indexMap.containsKey(alleleBlockIndex)) {
+ indexMap.put(alleleBlockIndex, new HashSet<>());
+ }
+ final int alleleElementIndex = (int) (offsettedMutableAlleleIndex % Long.SIZE);
+
+ indexMap.get(alleleBlockIndex).add(alleleElementIndex);
+ }
+
+ private void updateIndexMap(Map<Integer, Set<Integer>> indexMap, long length) {
+ updateIndexMap(indexMap, length, RandomProviderManager.getRandomProvider().nextLong(length));
+ }
+
+}
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 0000000..2ff7f0f
--- /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.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * Mutation for {@link IntegralValuedChromosome}. Randomly changes few genes.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class IntegralValuedMutation<P> extends AbstractListChromosomeMutationPolicy<Integer, P> {
+
+ /** minimum acceptable value of allele. **/
+ private final int min;
+
+ /** maximum acceptable value of allele. **/
+ private final int max;
+
+ /**
+ * @param min minimum value of allele
+ * @param max maximum value of allele
+ */
+ public IntegralValuedMutation(final int min, final int max) {
+ this.min = min;
+ this.max = max;
+ if (min >= max) {
+ throw new GeneticException(GeneticException.TOO_LARGE, min, max);
+ }
+ }
+
+ /**
+ * Returns the minimum acceptable value.
+ * @return minimum
+ */
+ public int getMin() {
+ return min;
+ }
+
+ /**
+ * Returns the maximum acceptable value.
+ * @return maximum
+ */
+ public int getMax() {
+ return max;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void checkValidity(Chromosome<P> original) {
+ if (!IntegralValuedChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, original.getClass().getSimpleName());
+ }
+ final IntegralValuedChromosome<P> chromosome = (IntegralValuedChromosome<P>) 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 + RandomProviderManager.getRandomProvider().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 0000000..096e419
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/MutationPolicy.java
@@ -0,0 +1,36 @@
+/*
+ * 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 <P> phenotype of chromosome
+ * @since 4.0
+ */
+public interface MutationPolicy<P> {
+
+ /**
+ * Mutate the given chromosome.
+ * @param original the original chromosome.
+ * @param mutationRate The probability of mutation
+ * @return the mutated chromosome.
+ */
+ Chromosome<P> mutate(Chromosome<P> 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 0000000..3dcbdcf
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/RealValuedMutation.java
@@ -0,0 +1,97 @@
+/*
+ * 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.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * This class mutates real-valued chromosome.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public class RealValuedMutation<P> extends AbstractListChromosomeMutationPolicy<Double, P> {
+
+ /** minimum value of chromosome gene/allele. **/
+ private final double min;
+
+ /** maximum value of chromosome gene/allele. **/
+ private final double max;
+
+ /**
+ * Constructs the mutation operator with normalized range of double values.
+ */
+ public RealValuedMutation() {
+ this.min = 0d;
+ this.max = 1d;
+ }
+
+ /**
+ * Constructs the mutation operator with provided range of double values.
+ * @param min minimum inclusive value of allele
+ * @param max maximum exclusive value of allele
+ */
+ public RealValuedMutation(double min, double max) {
+ this.min = min;
+ this.max = max;
+ if (min >= max) {
+ throw new GeneticException(GeneticException.TOO_LARGE, min, max);
+ }
+ }
+
+ /**
+ * Returns the minimum acceptable value.
+ * @return minimum
+ */
+ public double getMin() {
+ return min;
+ }
+
+ /**
+ * Returns the maximum acceptable value.
+ * @return maximum
+ */
+ public double getMax() {
+ return max;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void checkValidity(Chromosome<P> original) {
+ if (!RealValuedChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, original.getClass().getSimpleName());
+ }
+ final RealValuedChromosome<P> chromosome = (RealValuedChromosome<P>) 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 + RandomProviderManager.getRandomProvider().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 0000000..30c90e4
--- /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/mutation/rategenerator/AdaptiveLinearMutationRateGenerator.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/AdaptiveLinearMutationRateGenerator.java
new file mode 100644
index 0000000..555465f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/AdaptiveLinearMutationRateGenerator.java
@@ -0,0 +1,54 @@
+/*
+ * 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.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * Generates mutation rate using linear function of relative rank of input
+ * chromosome in population.
+ * @param <P> phenotype of chromosome
+ */
+public class AdaptiveLinearMutationRateGenerator<P> implements MutationRateGenerator<P> {
+
+ /** minimum crossover rate. **/
+ private final double minimumRate;
+
+ /** maximum crossover rate. **/
+ private final double maximumRate;
+
+ /**
+ * @param minimumRate minimum mutation rate
+ * @param maximumRate maximum mutation rate
+ */
+ public AdaptiveLinearMutationRateGenerator(double minimumRate, double maximumRate) {
+ this.minimumRate = minimumRate;
+ this.maximumRate = maximumRate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double generate(Chromosome<P> chromosome, PopulationStatisticalSummary<P> populationStats, int generation) {
+ return minimumRate + (maximumRate - minimumRate) *
+ (1.0 - (double) populationStats.findRank(chromosome) / (populationStats.getPopulationSize() - 1));
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/ConstantMutationRateGenerator.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/ConstantMutationRateGenerator.java
new file mode 100644
index 0000000..097e98d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/ConstantMutationRateGenerator.java
@@ -0,0 +1,47 @@
+/*
+ * 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.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * This class represents a constant mutation rate generator.
+ * @param <P> phenotype of chromosome
+ */
+public class ConstantMutationRateGenerator<P> implements MutationRateGenerator<P> {
+
+ /** the constant mutationRate. **/
+ private final double mutationRate;
+
+ /**
+ * @param mutationRate mutation rate
+ */
+ public ConstantMutationRateGenerator(double mutationRate) {
+ this.mutationRate = mutationRate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double generate(Chromosome<P> chromosome, PopulationStatisticalSummary<P> populationStats, int generation) {
+ return mutationRate;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/MutationRateGenerator.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/MutationRateGenerator.java
new file mode 100644
index 0000000..a206e02
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/MutationRateGenerator.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.mutation.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * This abstraction represents mutation rate generator.
+ * @param <P> phenotype of chromosome
+ */
+public interface MutationRateGenerator<P> {
+
+ /**
+ * Generates mutation rate based on input params.
+ * @param chromosome chromosome
+ * @param populationStats population statictics summary
+ * @param generation generation count
+ * @return mutation rate
+ */
+ double generate(Chromosome<P> chromosome, PopulationStatisticalSummary<P> populationStats, int generation);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/package-info.java
new file mode 100644
index 0000000..c7e56ce
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/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.rategenerator;
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 0000000..40fa263
--- /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 0000000..1622d9c
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/ListPopulation.java
@@ -0,0 +1,220 @@
+/*
+ * 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 java.util.Objects;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+
+/**
+ * Population of chromosomes represented by a {@link List}.
+ *
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ */
+public class ListPopulation<P> implements Population<P> {
+
+ /** new line constant. **/
+ public static final String NEW_LINE = System.getProperty("line.separator");
+
+ /** List of chromosomes. */
+ private final List<Chromosome<P>> chromosomes;
+
+ /** maximal size of the population. */
+ private int populationLimit;
+
+ /**
+ * Creates a new ListPopulation instance and initializes its inner chromosome
+ * list.
+ *
+ * @param populationLimit maximal size of the population
+ */
+ public ListPopulation(final int populationLimit) {
+ this(Collections.<Chromosome<P>>emptyList(), populationLimit);
+ }
+
+ /**
+ * Creates a new ListPopulation instance.
+ * <p>
+ * 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 List<Chromosome<P>> chromosomes, final int populationLimit) {
+
+ Objects.requireNonNull(chromosomes);
+
+ if (populationLimit <= 0) {
+ throw new GeneticException(GeneticException.NOT_STRICTLY_POSITIVE, populationLimit);
+ }
+ if (chromosomes.size() > populationLimit) {
+ throw new GeneticException(GeneticException.LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE,
+ chromosomes.size(), populationLimit);
+ }
+ this.populationLimit = populationLimit;
+ this.chromosomes = new ArrayList<>(populationLimit);
+ this.chromosomes.addAll(chromosomes);
+ }
+
+ /**
+ * Add a {@link Collection} of chromosomes to this {@link Population}.
+ * @param chromosomeColl a {@link Collection} of chromosomes
+ * @since 3.1
+ */
+ public void addChromosomes(final Collection<Chromosome<P>> chromosomeColl) {
+ if (chromosomes.size() + chromosomeColl.size() > populationLimit) {
+ throw new GeneticException(GeneticException.LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE,
+ chromosomes.size(), populationLimit);
+ }
+ this.chromosomes.addAll(chromosomeColl);
+ }
+
+ /**
+ * Returns an unmodifiable list of the chromosomes in this population.
+ * @return the unmodifiable list of chromosomes
+ */
+ public List<Chromosome<P>> getChromosomes() {
+ return Collections.unmodifiableList(chromosomes);
+ }
+
+ /**
+ * Access the list of chromosomes.
+ * @return the list of chromosomes
+ * @since 3.1
+ */
+ protected List<Chromosome<P>> getChromosomeList() {
+ return chromosomes;
+ }
+
+ /**
+ * Add the given chromosome to the population.
+ * @param chromosome the chromosome to add.
+ */
+ @Override
+ public void addChromosome(final Chromosome<P> chromosome) {
+ if (chromosomes.size() >= populationLimit) {
+ throw new GeneticException(GeneticException.LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE,
+ chromosomes.size(), populationLimit);
+ }
+ this.chromosomes.add(chromosome);
+ }
+
+ /**
+ * Access the fittest chromosome in this population.
+ * @return the fittest chromosome.
+ */
+ @Override
+ public Chromosome<P> getFittestChromosome() {
+ // best so far
+ return Collections.max(this.chromosomes);
+ }
+
+ /**
+ * Access the maximum population size.
+ * @return the maximum population size.
+ */
+ @Override
+ public int getPopulationLimit() {
+ return this.populationLimit;
+ }
+
+ /**
+ * Sets the maximal population size.
+ * @param populationLimit maximal population size.
+ */
+ public void setPopulationLimit(final int populationLimit) {
+ if (populationLimit <= 0) {
+ throw new GeneticException(GeneticException.POPULATION_LIMIT_NOT_POSITIVE, populationLimit);
+ }
+ if (populationLimit < chromosomes.size()) {
+ throw new GeneticException(GeneticException.POPULATION_LIMIT_LESS_THAN_LIST_OF_CHROMOSOMES_SIZE,
+ populationLimit, chromosomes.size());
+ }
+ this.populationLimit = populationLimit;
+ }
+
+ /**
+ * Access the current population size.
+ * @return the current population size.
+ */
+ @Override
+ public int getPopulationSize() {
+ return this.chromosomes.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder populationStrRepr = new StringBuilder();
+ for (Chromosome<P> chromosome : chromosomes) {
+ populationStrRepr.append(chromosome.toString());
+ populationStrRepr.append(NEW_LINE);
+ }
+ return populationStrRepr.toString();
+ }
+
+ /**
+ * Returns an iterator over the unmodifiable list of chromosomes.
+ * <p>
+ * Any call to {@link Iterator#remove()} will result in a
+ * {@link UnsupportedOperationException}.
+ * </p>
+ *
+ * @return chromosome iterator
+ */
+ @Override
+ public Iterator<Chromosome<P>> iterator() {
+ return getChromosomes().iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Population<P> nextGeneration(final double elitismRate) {
+ final List<Chromosome<P>> oldChromosomes = getChromosomeList();
+
+ if ((int) (oldChromosomes.size() * elitismRate) == 0) {
+ // if no of elite chromosome is 0 crete and return an empty population instance.
+ return new ListPopulation<>(getPopulationLimit());
+ } else {
+ // create a new generation of chromosomes with same parameters and add the elit
+ // individuals.
+ final ListPopulation<P> nextGeneration = new ListPopulation<>(getPopulationLimit());
+
+ // Sort the chromosome according to ascending order of fitness.
+ Collections.sort(oldChromosomes);
+
+ // index of the last "not good enough" chromosome
+ final int boundIndex = (int) Math.ceil((1.0 - elitismRate) * oldChromosomes.size());
+ for (int i = boundIndex; i < oldChromosomes.size(); i++) {
+ nextGeneration.addChromosome(oldChromosomes.get(i));
+ }
+ return nextGeneration;
+ }
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/Population.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/Population.java
new file mode 100644
index 0000000..65cfe5f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/Population.java
@@ -0,0 +1,59 @@
+/*
+ * 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 org.apache.commons.math4.ga.chromosome.Chromosome;
+
+/**
+ * A collection of chromosomes that facilitates generational evolution.
+ *
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ */
+public interface Population<P> extends Iterable<Chromosome<P>> {
+
+ /**
+ * Access the current population size.
+ * @return the current population size.
+ */
+ int getPopulationSize();
+
+ /**
+ * Access the maximum population size.
+ * @return the maximum population size.
+ */
+ int getPopulationLimit();
+
+ /**
+ * Start the population for the next generation.
+ * @param elitismRate the Elitism Rate
+ * @return the beginnings of the next generation.
+ */
+ Population<P> nextGeneration(double elitismRate);
+
+ /**
+ * Add the given chromosome to the population.
+ * @param chromosome the chromosome to add.
+ */
+ void addChromosome(Chromosome<P> chromosome);
+
+ /**
+ * Access the fittest chromosome in this population.
+ * @return the fittest chromosome.
+ */
+ Chromosome<P> getFittestChromosome();
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/package-info.java
new file mode 100644
index 0000000..4d77dc9
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/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.population;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/SelectionPolicy.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/SelectionPolicy.java
new file mode 100644
index 0000000..7c8682a
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/SelectionPolicy.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.selection;
+
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Algorithm used to select a chromosome pair from a population.
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ */
+public interface SelectionPolicy<P> {
+
+ /**
+ * Select two chromosomes from the population.
+ * @param population the population from which the chromosomes are chosen.
+ * @return the selected chromosomes.
+ */
+ ChromosomePair<P> select(Population<P> population);
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/TournamentSelection.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/TournamentSelection.java
new file mode 100644
index 0000000..8240f5d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/TournamentSelection.java
@@ -0,0 +1,108 @@
+/*
+ * 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.selection;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * Tournament selection scheme. Each of the two selected chromosomes is selected
+ * based on n-ary tournament -- this is done by drawing {@link #arity} random
+ * chromosomes without replacement from the population, and then selecting the
+ * fittest chromosome among them.
+ * @param <P> phenotype of chromosome
+ * @since 2.0
+ */
+public class TournamentSelection<P> implements SelectionPolicy<P> {
+
+ /** number of chromosomes included in the tournament selections. */
+ private final int arity;
+
+ /**
+ * Creates a new TournamentSelection instance.
+ *
+ * @param arity how many chromosomes will be drawn to the tournament
+ */
+ public TournamentSelection(final int arity) {
+ this.arity = arity;
+ }
+
+ /**
+ * Select two chromosomes from the population. Each of the two selected
+ * chromosomes is selected based on n-ary tournament -- this is done by drawing
+ * {@link #arity} random chromosomes without replacement from the population,
+ * and then selecting the fittest chromosome among them.
+ *
+ * @param population the population from which the chromosomes are chosen.
+ * @return the selected chromosomes.
+ */
+ @Override
+ public ChromosomePair<P> select(final Population<P> population) {
+ if (!(population instanceof ListPopulation<?>)) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT, population);
+ }
+ return new ChromosomePair<>(tournament((ListPopulation<P>) population),
+ tournament((ListPopulation<P>) population));
+ }
+
+ /**
+ * Helper for {@link #select(Population)}. Draw {@link #arity} random
+ * chromosomes without replacement from the population, and then select the
+ * fittest chromosome among them.
+ *
+ * @param population the population from which the chromosomes are chosen.
+ * @return the selected chromosome.
+ */
+ private Chromosome<P> tournament(final ListPopulation<P> population) {
+ if (population.getPopulationSize() < this.arity) {
+ throw new GeneticException(GeneticException.TOO_LARGE, arity, population.getPopulationSize());
+ }
+
+ // create a copy of the chromosome list
+ final List<Chromosome<P>> chromosomes = new ArrayList<>(population.getChromosomes());
+ final List<Chromosome<P>> selectedChromosomes = new ArrayList<>();
+
+ for (int i = 0; i < this.arity; i++) {
+ // select a random individual and add it to the tournament
+ final int rind = RandomProviderManager.getRandomProvider().nextInt(chromosomes.size());
+ selectedChromosomes.add(chromosomes.get(rind));
+ // do not select it again
+ chromosomes.remove(rind);
+ }
+
+ // the winner takes it all
+ return Collections.max(selectedChromosomes);
+ }
+
+ /**
+ * Gets the arity (number of chromosomes drawn to the tournament).
+ *
+ * @return arity of the tournament
+ */
+ public int getArity() {
+ return arity;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/package-info.java
new file mode 100644
index 0000000..b8ba3ae
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/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.selection;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/stats/PopulationStatisticalSummary.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/stats/PopulationStatisticalSummary.java
new file mode 100644
index 0000000..e24f3a0
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/stats/PopulationStatisticalSummary.java
@@ -0,0 +1,67 @@
+/*
+ * 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.stats;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+
+/**
+ * This interface represents the statistical summary for population fitness.
+ * @param <P> phenotype of chromosome
+ * @since 4.0
+ */
+public interface PopulationStatisticalSummary<P> {
+
+ /**
+ * Returns the arithmetic mean of population fitness.
+ * @return The mean or Double.NaN if no values have been added.
+ */
+ double getMeanFitness();
+
+ /**
+ * Returns the variance of the population fitness.
+ * @return The variance, Double.NaN if no values have been added or 0.0 for a
+ * single value set.
+ */
+ double getFitnessVariance();
+
+ /**
+ * Returns the minimum fitness of the population.
+ * @return The max or Double.NaN if no values have been added.
+ */
+ double getMinFitness();
+
+ /**
+ * Returns the maximum fitness of the population.
+ * @return The max or Double.NaN if no values have been added.
+ */
+ double getMaxFitness();
+
+ /**
+ * Returns the population size.
+ * @return The number of available values
+ */
+ long getPopulationSize();
+
+ /**
+ * Calculates the rank of chromosome in population based on its fitness.
+ * @param chromosome chromosome, for which rank would be found
+ * @return the rank of chromosome
+ */
+ int findRank(Chromosome<P> chromosome);
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/stats/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/stats/package-info.java
new file mode 100644
index 0000000..f40707d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/stats/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.stats;
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/ChromosomeRepresentationUtils.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/ChromosomeRepresentationUtils.java
new file mode 100644
index 0000000..4750335
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/ChromosomeRepresentationUtils.java
@@ -0,0 +1,211 @@
+/*
+ * 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.utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.rng.UniformRandomProvider;
+
+/**
+ * This interface generates all random representations for chromosomes.
+ * @since 4.0
+ */
+public interface ChromosomeRepresentationUtils {
+
+ /**
+ * Generates a representation corresponding to a random permutation of length l
+ * which can be passed to the RandomKey constructor.
+ *
+ * @param l length of the permutation
+ * @return representation of a random permutation
+ */
+ static List<Double> randomPermutation(final int l) {
+ final UniformRandomProvider randomProvider = RandomProviderManager.getRandomProvider();
+ final List<Double> repr = new ArrayList<>(l);
+ for (int i = 0; i < l; i++) {
+ repr.add(randomProvider.nextDouble());
+ }
+ return repr;
+ }
+
+ /**
+ * Generates a representation corresponding to an identity permutation of length
+ * l which can be passed to the RandomKey constructor.
+ *
+ * @param l length of the permutation
+ * @return representation of an identity permutation
+ */
+ static List<Double> identityPermutation(final int l) {
+ final List<Double> repr = new ArrayList<>(l);
+ for (int i = 0; i < l; i++) {
+ repr.add((double) i / l);
+ }
+ return repr;
+ }
+
+ /**
+ * Generates a representation of a permutation corresponding to the
+ * <code>data</code> sorted by <code>comparator</code>. The <code>data</code> is
+ * not modified during the process.
+ *
+ * This is useful if you want to inject some permutations to the initial
+ * population.
+ *
+ * @param <S> type of the data
+ * @param data list of data determining the order
+ * @param comparator how the data will be compared
+ * @return list representation of the permutation corresponding to the
+ * parameters
+ */
+ static <S> List<Double> comparatorPermutation(final List<S> data, final Comparator<S> comparator) {
+ final List<S> sortedData = new ArrayList<>(data);
+ Collections.sort(sortedData, comparator);
+
+ return inducedPermutation(data, sortedData);
+ }
+
+ /**
+ * Generates a representation of a permutation corresponding to a permutation
+ * which yields <code>permutedData</code> when applied to
+ * <code>originalData</code>.
+ *
+ * This method can be viewed as an inverse to decode().
+ *
+ * @param <S> type of the data
+ * @param originalData the original, unpermuted data
+ * @param permutedData the data, somehow permuted
+ * @return representation of a permutation corresponding to the permutation
+ * {@code originalData -> permutedData}
+ */
+ static <S> List<Double> inducedPermutation(final List<S> originalData, final List<S> permutedData) {
+
+ if (originalData.size() != permutedData.size()) {
+ throw new GeneticException(GeneticException.SIZE_MISMATCH, permutedData.size(), originalData.size());
+ }
+ final int l = originalData.size();
+
+ final List<S> origDataCopy = new ArrayList<>(originalData);
+
+ final Double[] res = new Double[l];
+ for (int i = 0; i < l; i++) {
+ final int index = origDataCopy.indexOf(permutedData.get(i));
+ if (index == -1) {
+ throw new GeneticException(GeneticException.DIFFERENT_ORIG_AND_PERMUTED_DATA);
+ }
+ res[index] = (double) i / l;
+ origDataCopy.set(index, null);
+ }
+ return Arrays.asList(res);
+ }
+
+ /**
+ * Returns a representation of a random binary array of length
+ * <code>length</code>.
+ * @param length length of the array
+ * @param min minimum inclusive value of allele
+ * @param max maximum exclusive value of allele
+ * @return a random binary array of length <code>length</code>
+ */
+ static List<Integer> randomIntegralRepresentation(final int length, final int min, final int max) {
+ final UniformRandomProvider randomProvider = RandomProviderManager.getRandomProvider();
+ final List<Integer> rList = new ArrayList<>(length);
+ for (int j = 0; j < length; j++) {
+ rList.add(min + randomProvider.nextInt(max - min));
+ }
+ return rList;
+ }
+
+ /**
+ * Returns a representation of a random binary array of length
+ * <code>length</code>.
+ * @param length length of the array
+ * @return a random binary array of length <code>length</code>
+ */
+ static long[] randomBinaryRepresentation(final long length) {
+ if (length > BinaryChromosome.MAX_LENGTH) {
+ throw new GeneticException(GeneticException.ILLEGAL_ARGUMENT,
+ "length exceeded the max length " + BinaryChromosome.MAX_LENGTH);
+ }
+ final UniformRandomProvider randomProvider = RandomProviderManager.getRandomProvider();
+ int elementCount = (int) Math.ceil(length / (double)Long.SIZE);
+ // random binary list
+ final long[] representation = new long[elementCount];
+ int remainder = (int) (length % Long.SIZE);
+ representation[0] = remainder == 0 ? randomProvider.nextLong() :
+ randomProvider.nextLong((long) Math.pow(2, remainder));
+ for (int i = 1; i < elementCount; i++) {
+ representation[i] = randomProvider.nextLong();
+ }
+ return representation;
+ }
+
+ /**
+ * Generates a random string representation of chromosome with specified
+ * characters.
+ * @param alleles characters representing alleles
+ * @param length length of chromosome
+ * @return returns chromosome representation as string
+ */
+ static String randomStringRepresentation(char[] alleles, final long length) {
+ Objects.requireNonNull(alleles);
+ final StringBuilder representationStr = new StringBuilder();
+ for (int i = 0; i < length; i++) {
+ representationStr
+ .append(alleles[(int) (RandomProviderManager.getRandomProvider().nextInt(alleles.length))]);
+ }
+ return representationStr.toString();
+ }
+
+ /**
+ * Generates a representation corresponding to a random double values[0..1] of
+ * length l.
+ * @param l length of the permutation
+ * @return representation of a random permutation
+ */
+ static List<Double> randomNormalizedDoubleRepresentation(final int l) {
+ return randomDoubleRepresentation(l, 0, 1);
+ }
+
+ /**
+ * Generates a representation corresponding to a random double values of length
+ * l.
+ * @param l length of representation
+ * @param min minimum inclusive value of chromosome gene
+ * @param max maximum exclusive value of chromosome gene
+ * @return representation as List of Double
+ */
+ static List<Double> randomDoubleRepresentation(final int l, double min, double max) {
+ if (min >= max) {
+ throw new GeneticException(GeneticException.TOO_LARGE, min, max);
+ }
+ final double range = max - min;
+ final UniformRandomProvider randomProvider = RandomProviderManager.getRandomProvider();
+ final List<Double> repr = new ArrayList<>(l);
+ for (int i = 0; i < l; i++) {
+ repr.add(min + randomProvider.nextDouble() * range);
+ }
+ return repr;
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/RandomProviderManager.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/RandomProviderManager.java
new file mode 100644
index 0000000..0c01896
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/RandomProviderManager.java
@@ -0,0 +1,47 @@
+/*
+ * 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.utils;
+
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.simple.RandomSource;
+import org.apache.commons.rng.simple.ThreadLocalRandomSource;
+
+/**
+ * An utility to generate per thread {@link UniformRandomProvider} instance.
+ * @since 4.0
+ */
+public final class RandomProviderManager {
+
+ /** The default RandomSource for random number generation. **/
+ private static RandomSource randomSource = RandomSource.XO_RO_SHI_RO_128_PP;
+
+ /**
+ * constructs the singleton instance.
+ */
+ private RandomProviderManager() {
+ }
+
+ /**
+ * Returns the (static) random generator.
+ * @return the static random generator shared by GA implementation classes
+ */
+ public static UniformRandomProvider getRandomProvider() {
+ return ThreadLocalRandomSource.current(RandomProviderManager.randomSource);
+ }
+
+}
diff --git a/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/package-info.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/package-info.java
new file mode 100644
index 0000000..0e8c79a
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/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.utils;
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestBinaryOneMax.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestBinaryOneMax.java
new file mode 100644
index 0000000..99a3785
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestBinaryOneMax.java
@@ -0,0 +1,187 @@
+/*
+ * 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 java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.convergence.FixedGenerationCount;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.crossover.OnePointBinaryCrossover;
+import org.apache.commons.math4.ga.crossover.OnePointCrossover;
+import org.apache.commons.math4.ga.decoder.Decoder;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.listener.ConvergenceListener;
+import org.apache.commons.math4.ga.listener.ConvergenceListenerRegistry;
+import org.apache.commons.math4.ga.mutation.BinaryMutation;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.TournamentSelection;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * This is also an example of usage.
+ */
+public class GeneticAlgorithmTestBinaryOneMax {
+
+ // parameters for the GA
+ private static final int DIMENSION = 50;
+ private static final int POPULATION_SIZE = 50;
+ private static final int NUM_GENERATIONS = 50;
+ private static final double CROSSOVER_RATE = 1;
+ private static final double MUTATION_RATE = 0.1;
+ private static final int TOURNAMENT_ARITY = 2;
+
+ @Test
+ public void test() {
+ removeListeners();
+
+ // initialize a new genetic algorithm
+ GeneticAlgorithm<List<Integer>> ga = new GeneticAlgorithm<>(new OnePointBinaryCrossover<List<Integer>>(),
+ CROSSOVER_RATE, new BinaryMutation<List<Integer>>(), MUTATION_RATE,
+ new TournamentSelection<List<Integer>>(TOURNAMENT_ARITY));
+
+ Assertions.assertEquals(0, ga.getGenerationsEvolved());
+
+ // initial population
+ Population<List<Integer>> initial = randomPopulation();
+ // stopping conditions
+ StoppingCondition<List<Integer>> stopCond = new FixedGenerationCount<>(NUM_GENERATIONS);
+
+ // best initial chromosome
+ Chromosome<List<Integer>> bestInitial = initial.getFittestChromosome();
+
+ // run the algorithm
+ Population<List<Integer>> finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ Chromosome<List<Integer>> bestFinal = finalPopulation.getFittestChromosome();
+
+ // the only thing we can test is whether the final solution is not worse than
+ // the initial one
+ // however, for some implementations of GA, this need not be true :)
+
+ Assertions.assertTrue(bestFinal.compareTo(bestInitial) > 0);
+ Assertions.assertEquals(NUM_GENERATIONS, ga.getGenerationsEvolved());
+
+ }
+
+ private void removeListeners() {
+ try {
+ ConvergenceListenerRegistry<String> registry = ConvergenceListenerRegistry.<String>getInstance();
+ Field listenersField = registry.getClass().getDeclaredField("listeners");
+ boolean accessible = listenersField.isAccessible();
+ if (!accessible) {
+ listenersField.setAccessible(true);
+ }
+ @SuppressWarnings("unchecked")
+ List<ConvergenceListener<String>> listeners = (List<ConvergenceListener<String>>) listenersField
+ .get(ConvergenceListenerRegistry.getInstance());
+ listeners.clear();
+ listenersField.setAccessible(accessible);
+ } catch (NoSuchFieldException | SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Initializes a random population.
+ */
+ private ListPopulation<List<Integer>> randomPopulation() {
+ List<Chromosome<List<Integer>>> popList = new LinkedList<>();
+
+ for (int i = 0; i < POPULATION_SIZE; i++) {
+ BinaryChromosome<List<Integer>> randChrom = new FindOnes(
+ ChromosomeRepresentationUtils.randomBinaryRepresentation(DIMENSION), DIMENSION);
+ popList.add(randChrom);
+ }
+ return new ListPopulation<>(popList, popList.size());
+ }
+
+ /**
+ * Chromosomes represented by a binary chromosome.
+ *
+ * The goal is to set all bits (genes) to 1.
+ */
+ private class FindOnes extends BinaryChromosome<List<Integer>> {
+
+ FindOnes(long[] representation, long length) {
+ super(representation, length, new OneMaxFitnessFunction(), new OneMaxDecoder());
+ }
+ }
+
+ private class OneMaxFitnessFunction implements FitnessFunction<List<Integer>> {
+
+ @Override
+ public double compute(List<Integer> decodedChromosome) {
+ double value = 0;
+ for (Integer allele : decodedChromosome) {
+ value += allele;
+ }
+ return value;
+ }
+
+ }
+
+ private class OneMaxDecoder implements Decoder<List<Integer>> {
+
+ @Override
+ public List<Integer> decode(Chromosome<List<Integer>> chromosome) {
+ BinaryChromosome<List<Integer>> binaryChromosome = (BinaryChromosome<List<Integer>>) chromosome;
+ List<Integer> phenotype = new ArrayList<>();
+ long[] representation = binaryChromosome.getRepresentation();
+ for (int i = 0; i < representation.length; i++) {
+ String value = Long.toUnsignedString(representation[i], 2);
+ for (int j = 64 - value.length(); j > 0; j--) {
+ phenotype.add(Integer.valueOf(0));
+ }
+ for (int j = 0; j < value.length(); j++) {
+ phenotype.add(Integer.parseInt("" + value.charAt(j)));
+ }
+ }
+ return phenotype;
+ }
+ }
+
+ @Test
+ public void testCrossoverRate() {
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new GeneticAlgorithm<>(new OnePointCrossover<>(), 1.5, new BinaryMutation<>(), .01,
+ new TournamentSelection<>(10));
+ });
+ }
+
+ @Test
+ public void testMutationRate() {
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new GeneticAlgorithm<>(new OnePointCrossover<>(), .5, new BinaryMutation<>(), 1.5,
+ new TournamentSelection<>(10));
+ });
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestPermutations.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestPermutations.java
new file mode 100644
index 0000000..4bfb2ec
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestPermutations.java
@@ -0,0 +1,144 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.chromosome.RealValuedChromosome;
+import org.apache.commons.math4.ga.convergence.FixedGenerationCount;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.crossover.OnePointCrossover;
+import org.apache.commons.math4.ga.decoder.RandomKeyDecoder;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+import org.apache.commons.math4.ga.mutation.RealValuedMutation;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.apache.commons.math4.ga.selection.TournamentSelection;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * This is also an example of usage.
+ *
+ * This algorithm does "stochastic sorting" of a sequence 0,...,N.
+ *
+ */
+public class GeneticAlgorithmTestPermutations {
+
+ // parameters for the GA
+ private static final int DIMENSION = 20;
+ private static final int POPULATION_SIZE = 80;
+ private static final int NUM_GENERATIONS = 200;
+ private static final double ELITISM_RATE = 0.2;
+ private static final double CROSSOVER_RATE = 1;
+ private static final double MUTATION_RATE = 0.08;
+ private static final int TOURNAMENT_ARITY = 2;
+
+ // numbers from 0 to N-1
+ private static final List<Integer> sequence = new ArrayList<>();
+ static {
+ for (int i = 0; i < DIMENSION; i++) {
+ sequence.add(i);
+ }
+ }
+
+ @Test
+ public void test() {
+ // to test a stochastic algorithm is hard, so this will rather be an usage
+ // example
+
+ // initialize a new genetic algorithm
+ GeneticAlgorithm<List<Integer>> ga = new GeneticAlgorithm<>(new OnePointCrossover<Integer, List<Integer>>(),
+ CROSSOVER_RATE, new RealValuedMutation<List<Integer>>(), MUTATION_RATE,
+ new TournamentSelection<List<Integer>>(TOURNAMENT_ARITY), ELITISM_RATE);
+
+ // initial population
+ Population<List<Integer>> initial = randomPopulation();
+ // stopping conditions
+ StoppingCondition<List<Integer>> stopCond = new FixedGenerationCount<>(NUM_GENERATIONS);
+
+ // best initial chromosome
+ Chromosome<List<Integer>> bestInitial = initial.getFittestChromosome();
+
+ // run the algorithm
+ Population<List<Integer>> finalPopulation = ga.evolve(initial, stopCond);
+
+ // best chromosome from the final population
+ Chromosome<List<Integer>> bestFinal = finalPopulation.getFittestChromosome();
+
+ // the only thing we can test is whether the final solution is not worse than
+ // the initial one
+ // however, for some implementations of GA, this need not be true :)
+
+ Assertions.assertTrue(bestFinal.compareTo(bestInitial) > 0);
+
+ }
+
+ /**
+ * Initializes a random population
+ */
+ private static Population<List<Integer>> randomPopulation() {
+ List<Chromosome<List<Integer>>> popList = new ArrayList<>();
+ for (int i = 0; i < POPULATION_SIZE; i++) {
+ Chromosome<List<Integer>> randChrom = new MinPermutations(
+ ChromosomeRepresentationUtils.randomPermutation(DIMENSION));
+ popList.add(randChrom);
+ }
+ return new ListPopulation<List<Integer>>(popList, popList.size());
+ }
+
+ /**
+ * Chromosomes representing a permutation of (0,1,2,...,DIMENSION-1).
+ *
+ * The goal is to sort the sequence.
+ */
+ private static class MinPermutations extends RealValuedChromosome<List<Integer>> {
+
+ MinPermutations(List<Double> representation) {
+ super(representation, new MinPermutationsFitnessFunction(), new RandomKeyDecoder<>(sequence));
+ }
+
+ @Override
+ public RealValuedChromosome<List<Integer>> newChromosome(List<Double> chromosomeRepresentation) {
+ return new MinPermutations(chromosomeRepresentation);
+ }
+
+ }
+
+ private static class MinPermutationsFitnessFunction implements FitnessFunction<List<Integer>> {
+
+ @Override
+ public double compute(List<Integer> decodedChromosome) {
+ double res = 0.0;
+ for (int i = 0; i < decodedChromosome.size(); i++) {
+ int value = decodedChromosome.get(i);
+ if (value != i) {
+ // bad position found
+ res += Math.abs(value - i);
+ }
+ }
+ // the most fitted chromosome is the one with minimal error
+ // therefore we must return negative value
+ return -res;
+ }
+
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/AbstractChromosomeTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/AbstractChromosomeTest.java
new file mode 100644
index 0000000..a682024
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/AbstractChromosomeTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class AbstractChromosomeTest {
+
+ @Test
+ public void testGetFitness() {
+ Chromosome<String> c1 = new AbstractChromosome<String>(chromosome -> 1, chromosome -> "1") {
+ };
+ Assertions.assertEquals(1, c1.evaluate(), .001);
+ }
+
+ @Test
+ public void testDecode() {
+ Chromosome<String> c1 = new AbstractChromosome<String>(chromosome -> 1, chromosome -> "1") {
+ };
+ Assertions.assertEquals("1", c1.decode());
+ }
+
+ @Test
+ public void testCompareTo() {
+ Chromosome<String> c1 = new AbstractChromosome<String>(chromosome -> 0, chromosome -> "0") {
+ };
+ Chromosome<String> c2 = new AbstractChromosome<String>(chromosome -> 10, chromosome -> "10") {
+ };
+ Chromosome<String> c3 = new AbstractChromosome<String>(chromosome -> 10, chromosome -> "10") {
+ };
+
+ Assertions.assertTrue(c1.compareTo(c2) < 0);
+ Assertions.assertTrue(c2.compareTo(c1) > 0);
+ Assertions.assertEquals(0, c3.compareTo(c2));
+ Assertions.assertEquals(0, c2.compareTo(c3));
+ }
+
+ @Test
+ public void testIsSame() {
+ AbstractChromosome<String> c1 = new AbstractChromosome<String>(chromosome -> 1, chromosome -> "1") {
+ };
+ AbstractChromosome<String> c2 = new AbstractChromosome<String>(chromosome -> 2, chromosome -> "2") {
+ };
+ AbstractChromosome<String> c3 = new AbstractChromosome<String>(chromosome -> 3, chromosome -> "1") {
+ };
+ Assertions.assertTrue(c1.isSame(c3));
+ Assertions.assertFalse(c1.isSame(c2));
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/BinaryChromosomeTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/BinaryChromosomeTest.java
new file mode 100644
index 0000000..ef6669a
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/BinaryChromosomeTest.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.chromosome;
+
+import org.apache.commons.math4.ga.dummy.DummyListChromosomeDecoder;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class BinaryChromosomeTest {
+
+ @Test
+ public void testInvalidConstructor() {
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new BinaryChromosome<String>(ChromosomeRepresentationUtils.randomBinaryRepresentation(10), Long.MAX_VALUE,
+ c -> 0, c -> "0");
+ });
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new BinaryChromosome<String>(ChromosomeRepresentationUtils.randomBinaryRepresentation(10), 100, c -> 0,
+ c -> "0");
+ });
+ }
+
+ @Test
+ public void testRandomConstructor() {
+ for (int i = 0; i < 20; i++) {
+ BinaryChromosome.<String>randomChromosome(10, c -> 1, new DummyListChromosomeDecoder<>("1"));
+ }
+ }
+
+ @Test
+ public void testGetStringRepresentation() {
+ int length = 10;
+ int startToEndGap = 1;
+ testStringRepresentationWithRanges(length, startToEndGap);
+
+ length = 64;
+ startToEndGap = 10;
+ testStringRepresentationWithRanges(length, startToEndGap);
+
+ length = 100;
+ startToEndGap = 50;
+ testStringRepresentationWithRanges(length, startToEndGap);
+
+ length = 128;
+ startToEndGap = 70;
+ testStringRepresentationWithRanges(length, startToEndGap);
+
+ length = 250;
+ startToEndGap = 128;
+ testStringRepresentationWithRanges(length, startToEndGap);
+
+ length = 350;
+ startToEndGap = 228;
+ testStringRepresentationWithRanges(length, startToEndGap);
+
+ length = 450;
+ startToEndGap = 108;
+ testStringRepresentationWithRanges(length, startToEndGap);
+
+ }
+
+ private void testStringRepresentationWithRanges(int length, int startToEndGap) {
+ for (int i = 0; i < 50; i++) {
+ String representationStr = ChromosomeRepresentationUtils.randomStringRepresentation(new char[] {'0', '1'},
+ length);
+ BinaryChromosome<String> chromosome = new BinaryChromosome<>(representationStr, c -> 0, c -> "0");
+ Assertions.assertEquals(representationStr, chromosome.getStringRepresentation());
+ for (int j = 0; j < length - startToEndGap; j++) {
+ int index = (int) ((length + 1 - startToEndGap) * Math.random());
+ Assertions.assertEquals(representationStr.substring(index, index + startToEndGap),
+ chromosome.getStringRepresentation(index, index + startToEndGap));
+ }
+ }
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/ChromosomePairTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/ChromosomePairTest.java
new file mode 100644
index 0000000..f43a27c
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/ChromosomePairTest.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.chromosome;
+
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+
+public class ChromosomePairTest {
+
+ @Test
+ public void testChromosomePair() {
+ Chromosome<String> chromosome1 = new AbstractChromosome<String>(c -> 0, c -> "0") {
+ };
+ Chromosome<String> chromosome2 = new AbstractChromosome<String>(c -> 1, c -> "1") {
+ };
+ ChromosomePair<String> chromosomePair = new ChromosomePair<>(chromosome1, chromosome2);
+
+ Assertions.assertEquals(chromosomePair.getFirst(), chromosome1);
+ Assertions.assertEquals(chromosomePair.getSecond(), chromosome2);
+
+ Assertions.assertNotNull(chromosomePair.toString());
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/IntegralValuedChromosomeTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/IntegralValuedChromosomeTest.java
new file mode 100644
index 0000000..e2a89fe
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/IntegralValuedChromosomeTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.dummy.DummyListChromosomeDecoder;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class IntegralValuedChromosomeTest {
+
+ @Test
+ public void testIntegralValuedChromosome() {
+ int min = 0;
+ int max = 10;
+ IntegralValuedChromosome<String> chromosome = new IntegralValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomIntegralRepresentation(10, min, max), c -> 0,
+ new DummyListChromosomeDecoder<>("0"), min, max);
+ Assertions.assertEquals(min, chromosome.getMin());
+ Assertions.assertEquals(max, chromosome.getMax());
+
+ IntegralValuedChromosome<String> chromosome1 = new IntegralValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomIntegralRepresentation(10, min, max).toArray(new Integer[10]),
+ c -> 0, new DummyListChromosomeDecoder<>("0"), min, max);
+ Assertions.assertEquals(min, chromosome1.getMin());
+ Assertions.assertEquals(max, chromosome1.getMax());
+ }
+
+ @Test
+ public void testCheckValidity() {
+ int min = 0;
+ int max = 10;
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new IntegralValuedChromosome<>(ChromosomeRepresentationUtils.randomIntegralRepresentation(10, min, max),
+ c -> 0, new DummyListChromosomeDecoder<>("0"), max, min);
+ });
+ }
+
+ @Test
+ public void testCheckValidity1() {
+ int min = 0;
+ int max = 10;
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new IntegralValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomIntegralRepresentation(10, min - 10, max + 10), c -> 0,
+ new DummyListChromosomeDecoder<>("0"), min, max);
+ });
+
+ }
+
+ @Test
+ public void testNewChromosome() {
+ int min = 0;
+ int max = 10;
+ IntegralValuedChromosome<String> chromosome = new IntegralValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomIntegralRepresentation(10, min, max), c -> 0,
+ new DummyListChromosomeDecoder<>("0"), min, max);
+ IntegralValuedChromosome<String> newChromosome = chromosome
+ .newChromosome(ChromosomeRepresentationUtils.randomIntegralRepresentation(10, min, max));
+ Assertions.assertEquals(chromosome.getMin(), newChromosome.getMin());
+ Assertions.assertEquals(chromosome.getMax(), newChromosome.getMax());
+ Assertions.assertEquals(chromosome.getDecoder(), newChromosome.getDecoder());
+ Assertions.assertEquals(chromosome.getFitnessFunction(), newChromosome.getFitnessFunction());
+
+ }
+
+ @Test
+ public void testRandomChromosome() {
+ int min = 0;
+ int max = 10;
+ IntegralValuedChromosome<String> chromosome = IntegralValuedChromosome.<String>randomChromosome(10, c -> 0,
+ new DummyListChromosomeDecoder<>("0"), min, max);
+ Assertions.assertEquals(min, chromosome.getMin());
+ Assertions.assertEquals(max, chromosome.getMax());
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/RealValuedChromosomeTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/RealValuedChromosomeTest.java
new file mode 100644
index 0000000..333e2ca
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/chromosome/RealValuedChromosomeTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.dummy.DummyListChromosomeDecoder;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class RealValuedChromosomeTest {
+
+ @Test
+ public void test() {
+ for (int i = 0; i < 10; i++) {
+ new RealValuedChromosome<>(ChromosomeRepresentationUtils.randomDoubleRepresentation(10, 0, 1), c1 -> 1,
+ new DummyListChromosomeDecoder<>("1"));
+ new RealValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomDoubleRepresentation(10, 0, 1).toArray(new Double[10]), c -> 0,
+ new DummyListChromosomeDecoder<>("0"));
+ }
+ }
+
+ @Test
+ public void testNewChromosome() {
+ for (int i = 0; i < 10; i++) {
+ RealValuedChromosome<String> chromosome = new RealValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomDoubleRepresentation(10, 0, 1), c1 -> 1,
+ new DummyListChromosomeDecoder<>("1"));
+ chromosome.newChromosome(ChromosomeRepresentationUtils.randomDoubleRepresentation(10, 0, 1));
+ }
+ }
+
+ @Test
+ public void testRandomChromosome() {
+ for (int i = 0; i < 10; i++) {
+ RealValuedChromosome.randomChromosome(5, c -> 0, new DummyListChromosomeDecoder<>("0"), 0, 2);
+ }
+ }
+
+ @Test
+ public void testCheckValidity() {
+ int min = 0;
+ int max = 10;
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new RealValuedChromosome<>(ChromosomeRepresentationUtils.randomDoubleRepresentation(10, min, max), c -> 0,
+ new DummyListChromosomeDecoder<>("0"), max, min);
+ });
+ }
+
+ @Test
+ public void testCheckValidity1() {
+ int min = 0;
+ int max = 10;
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new RealValuedChromosome<>(ChromosomeRepresentationUtils.randomDoubleRepresentation(10, min - 10, max + 10),
+ c -> 0, new DummyListChromosomeDecoder<>("0"), min, max);
+ });
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/FixedElapsedTimeTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/FixedElapsedTimeTest.java
new file mode 100644
index 0000000..e2681ab
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/FixedElapsedTimeTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 java.util.concurrent.TimeUnit;
+
+import org.apache.commons.math4.ga.convergence.FixedElapsedTime;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class FixedElapsedTimeTest {
+
+ @Test
+ public void testIsSatisfied() {
+ final Population<String> pop = new ListPopulation<>(10);
+
+ final long start = System.nanoTime();
+ final long duration = 3;
+ final FixedElapsedTime<String> tec = new FixedElapsedTime<String>(duration);
+
+ while (!tec.isSatisfied(pop)) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ final long end = System.nanoTime();
+ final long elapsedTime = end - start;
+ final long diff = Math.abs(elapsedTime - TimeUnit.SECONDS.toNanos(duration));
+
+ Assertions.assertTrue(diff < TimeUnit.MILLISECONDS.toNanos(100));
+ }
+
+ @Test
+ public void testNegativeTime() {
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new FixedElapsedTime<>(-10);
+ });
+ }
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/FixedGenerationCountTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/FixedGenerationCountTest.java
new file mode 100644
index 0000000..5bf1567
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/FixedGenerationCountTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.convergence.FixedGenerationCount;
+
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class FixedGenerationCountTest {
+
+ @Test
+ public void testIsSatisfied() {
+ FixedGenerationCount<String> fgc = new FixedGenerationCount<String>(20);
+
+ int cnt = 0;
+ Population<String> pop = new ListPopulation<>(10);
+
+ while (!fgc.isSatisfied(pop)) {
+ cnt++;
+ }
+ Assertions.assertEquals(cnt, fgc.getNumGenerations());
+ }
+
+ @Test
+ public void testNegativeGenerationCount() {
+ Assertions.assertThrows(GeneticException.class, () -> {
+ new FixedGenerationCount<String>(-1);
+ });
+ }
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/UnchangedBestFitnessTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/UnchangedBestFitnessTest.java
new file mode 100644
index 0000000..5fffd06
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/UnchangedBestFitnessTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 java.util.ArrayList;
+
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.convergence.UnchangedBestFitness;
+import org.apache.commons.math4.ga.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class UnchangedBestFitnessTest {
+
+ @Test
+ public void testIsSatisfied() {
+
+ final int noOfGenerationsWithUnchangedBestFitness = 5;
+ StoppingCondition<String> stoppingCondition = new UnchangedBestFitness<>(
+ noOfGenerationsWithUnchangedBestFitness);
+
+ double[] fitnesses = new double[10];
+ for (int i = 0; i < 10; i++) {
+ fitnesses[i] = i;
+ }
+ List<Chromosome<String>> chromosomes = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ final double fitness = fitnesses[i];
+ Chromosome<String> ch = new AbstractChromosome<String>(c -> fitness, c -> "Fixed") {
+ };
+ chromosomes.add(ch);
+ }
+ Population<String> pop = new ListPopulation<>(chromosomes, 10);
+
+ double initialMaxFitness = new PopulationStatisticalSummaryImpl<>(pop).getMaxFitness();
+
+ int counter = 0;
+ while (!stoppingCondition.isSatisfied(pop)) {
+ counter++;
+ }
+
+ double maxFitnessAfterConvergence = new PopulationStatisticalSummaryImpl<>(pop).getMaxFitness();
+
+ Assertions.assertEquals(initialMaxFitness, maxFitnessAfterConvergence, .001);
+ Assertions.assertEquals(noOfGenerationsWithUnchangedBestFitness, counter);
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/UnchangedMeanFitnessTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/UnchangedMeanFitnessTest.java
new file mode 100644
index 0000000..6e4042c
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/convergencecond/UnchangedMeanFitnessTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 java.util.ArrayList;
+
+import java.util.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.convergence.UnchangedMeanFitness;
+import org.apache.commons.math4.ga.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.population.ListPopulation;
+import org.apache.commons.math4.ga.population.Population;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class UnchangedMeanFitnessTest {
+
+ @Test
+ public void testIsSatisfied() {
+
+ final int noOfGenerationsWithUnchangedMeanFitness = 5;
+ StoppingCondition<String> stoppingCondition = new UnchangedMeanFitness<>(
+ noOfGenerationsWithUnchangedMeanFitness);
+
+ double[] fitnesses = new double[10];
+ for (int i = 0; i < 10; i++) {
+ fitnesses[i] = i;
+ }
+ List<Chromosome<String>> chromosomes = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ final double fitness = fitnesses[i];
+ Chromosome<String> ch = new AbstractChromosome<String>(c -> fitness, c -> "Fixed") {
+ };
+ chromosomes.add(ch);
+ }
+ Population<String> pop = new ListPopulation<>(chromosomes, 10);
+
+ double initialAverageFitness = new PopulationStatisticalSummaryImpl<>(pop).getMeanFitness();
+
+ int counter = 0;
+ while (!stoppingCondition.isSatisfied(pop)) {
+ counter++;
+ }
+
+ double averageFitnessAfterConvergence = new PopulationStatisticalSummaryImpl<>(pop).getMeanFitness();
+
+ Assertions.assertEquals(initialAverageFitness, averageFitnessAfterConvergence, .001);
+ Assertions.assertEquals(noOfGenerationsWithUnchangedMeanFitness, counter);
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicyTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicyTest.java
new file mode 100644
index 0000000..c1249b5
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicyTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.dummy.DummyChromosome;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class AbstractChromosomeCrossoverPolicyTest {
+
+ @Test
+ public void testCrossoverProbability() {
+
+ CrossoverPolicy<String> crossoverPolicy = new AbstractChromosomeCrossoverPolicy<String>() {
+ @Override
+ protected ChromosomePair<String> crossover(Chromosome<String> first, Chromosome<String> second) {
+ return null;
+ }
+ };
+
+ Chromosome<String> ch1 = new DummyChromosome();
+
+ Chromosome<String> ch2 = new DummyChromosome();
+
+ Assertions.assertNull(crossoverPolicy.crossover(ch1, ch2, 1.0));
+ Assertions.assertNotNull(crossoverPolicy.crossover(ch1, ch2, 0.0));
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/AbstractListChromosomeCrossoverPolicyTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/AbstractListChromosomeCrossoverPolicyTest.java
new file mode 100644
index 0000000..0739f0d
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/AbstractListChromosomeCrossoverPolicyTest.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.crossover;
+
+import org.apache.commons.math4.ga.chromosome.AbstractChromosome;
+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.dummy.DummyListChromosome;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class AbstractListChromosomeCrossoverPolicyTest {
+
+ @Test
+ public void testCrossoverWithNonListChromosome() {
+
+ CrossoverPolicy<String> crossoverPolicy = new AbstractListChromosomeCrossoverPolicy<Integer, String>() {
+
+ @Override
+ protected ChromosomePair<String> mate(AbstractListChromosome<Integer, String> first,
+ AbstractListChromosome<Integer, String> second) {
+ return new ChromosomePair<>(first, second);
+ }
+ };
+ Chromosome<String> ch1 = new AbstractChromosome<String>(c -> 0, c -> "0") {
+ };
+
+ Chromosome<String> ch2 = new AbstractChromosome<String>(c -> 1, c -> "1") {
+ };
+
+ Assertions.assertThrows(GeneticException.class, () -> {
+ crossoverPolicy.crossover(ch1, ch2, 1.0);
+ });
+
+ }
+
+ @Test
+ public void testCrossoverWithUnEqualLengthChromosome() {
+
+ CrossoverPolicy<String> crossoverPolicy = new AbstractListChromosomeCrossoverPolicy<Integer, String>() {
+
+ @Override
+ protected ChromosomePair<String> mate(AbstractListChromosome<Integer, String> first,
+ AbstractListChromosome<Integer, String> second) {
+ return new ChromosomePair<>(first, second);
+ }
+ };
+ Chromosome<String> ch1 = new DummyListChromosome(
+ ChromosomeRepresentationUtils.randomIntegralRepresentation(10, 0, 2));
+
+ Chromosome<String> ch2 = new DummyListChromosome(
+ ChromosomeRepresentationUtils.randomIntegralRepresentation(12, 0, 2));
+
+ Assertions.assertThrows(GeneticException.class, () -> {
+ crossoverPolicy.crossover(ch1, ch2, 1.0);
+ });
+
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/CycleCrossoverTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/CycleCrossoverTest.java
new file mode 100644
index 0000000..e8ac820
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/CycleCrossoverTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.ChromosomePair;
+import org.apache.commons.math4.ga.dummy.DummyListChromosome;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class CycleCrossoverTest {
+
+ @Test
+ public void testCrossoverExample() {
+ // taken from
+ // http://www.rubicite.com/Tutorials/GeneticAlgorithms/CrossoverOperators/CycleCrossoverOperator.aspx
+ final Integer[] p1 = new Integer[] {8, 4, 7, 3, 6, 2, 5, 1, 9, 0};
+ final Integer[] p2 = new Integer[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ final DummyListChromosome p1c = new DummyListChromosome(p1);
+ final DummyListChromosome p2c = new DummyListChromosome(p2);
+
+ final CrossoverPolicy<String> cp = new CycleCrossover<Integer, String>();
+ final ChromosomePair<String> pair = cp.crossover(p1c, p2c, 1.0);
+
+ final Integer[] c1 = ((DummyListChromosome) pair.getFirst()).getRepresentation()
+ .toArray(new Integer[p1.length]);
+ final Integer[] c2 = ((DummyListChromosome) pair.getSecond()).getRepresentation()
+ .toArray(new Integer[p2.length]);
+
+ final Integer[] c1e = new Integer[] {8, 1, 2, 3, 4, 5, 6, 7, 9, 0};
+ final Integer[] c2e = new Integer[] {0, 4, 7, 3, 6, 2, 5, 1, 8, 9};
+
+ Assertions.assertArrayEquals(c1e, c1);
+ Assertions.assertArrayEquals(c2e, c2);
+ }
+
+ @Test
+ public void testCrossoverExample2() {
+ // taken from http://www.scribd.com/doc/54206412/32/Cycle-crossover
+ final Integer[] p1 = new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ final Integer[] p2 = new Integer[] {9, 3, 7, 8, 2, 6, 5, 1, 4};
+ final DummyListChromosome p1c = new DummyListChromosome(p1);
+ final DummyListChromosome p2c = new DummyListChromosome(p2);
+
+ final CrossoverPolicy<String> cp = new CycleCrossover<Integer, String>();
+ final ChromosomePair<String> pair = cp.crossover(p1c, p2c, 1.0);
+
+ final Integer[] c1 = ((DummyListChromosome) pair.getFirst()).getRepresentation()
+ .toArray(new Integer[p1.length]);
+ final Integer[] c2 = ((DummyListChromosome) pair.getSecond()).getRepresentation()
+ .toArray(new Integer[p2.length]);
+
+ final Integer[] c1e = new Integer[] {1, 3, 7, 4, 2, 6, 5, 8, 9};
+ final Integer[] c2e = new Integer[] {9, 2, 3, 8, 5, 6, 7, 1, 4};
+
+ Assertions.assertArrayEquals(c1e, c1);
+ Assertions.assertArrayEquals(c2e, c2);
+ }
+
+ @Test
+ public void testCrossover() {
+ final Integer[] p1 = new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ final Integer[] p2 = new Integer[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ final DummyListChromosome p1c = new DummyListChromosome(p1);
+ final DummyListChromosome p2c = new DummyListChromosome(p2);
+
+ final CrossoverPolicy<String> cp = new CycleCrossover<Integer, String>(true);
+
+ for (int i = 0; i < 20; i++) {
+ final ChromosomePair<String> pair = cp.crossover(p1c, p2c, 1.0);
+
+ final Integer[] c1 = ((DummyListChromosome) pair.getFirst()).getRepresentation()
+ .toArray(new Integer[p1.length]);
+ final Integer[] c2 = ((DummyListChromosome) pair.getSecond()).getRepresentation()
+ .toArray(new Integer[p2.length]);
+
+ int index = 0;
+ // Determine if it is in the same spot as in the first parent, if
+ // not it comes from the second parent.
+ for (final Integer j : c1) {
+ if (!p1[index].equals(j)) {
+ Assertions.assertEquals(j, p2[index]);
+ } else {
+ Assertions.assertEquals(j, p1[index]);
+ }
+ index++;
+ }
+
+ // Same as above only for the second parent.
+ index = 0;
+ for (final Integer k : c2) {
+ if (p2[index] != k) {
+ Assertions.assertEquals(k, p1[index]);
+ } else {
+ Assertions.assertEquals(k, p2[index]);
+ }
+ index++;
+ }
+ }
+ }
+
+}
diff --git a/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/NPointCrossoverTest.java b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/NPointCrossoverTest.java
new file mode 100644
index 0000000..35a55b0
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/crossover/NPointCrossoverTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.List;
+
+import org.apache.commons.math4.ga.chromosome.AbstractChromosome;
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.chromosome.IntegralValuedChromosome;
+import org.apache.commons.math4.ga.dummy.DummyListChromosomeDecoder;
+import org.apache.commons.math4.ga.internal.exception.GeneticException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class NPointCrossoverTest {
+
+ @Test
+ public void testNumberIsTooLargeException() {
+ final Integer[] p1 = new Integer[] {1, 0, 1, 0, 0, 1, 0, 1, 1};
+ final Integer[] p2 = new Integer[] {0, 1, 1, 0, 1, 0, 1, 1, 1};
+
+ final IntegralValuedChromosome<String> p1c = new IntegralValuedChromosome<String>(p1, c -> 0,
+ new DummyListChromosomeDecoder<Integer>("0"), 0, 2);
+ final IntegralValuedChromosome<String> p2c = new IntegralValuedChromosome<String>(p2, c -> 0,
+ new DummyListChromosomeDecoder<Integer>("0"), 0, 2);
+
+ final CrossoverPolicy<String> cp = new NPointCrossover<Integer, String>(15);
+ Assertions.assertThrows(GeneticException.class, () -> {
+ cp.crossover(p1c, p2c, 1.0);
+ });
+ }
+
+ @Test
+ public void testCrossoverInvalidFixedLengthChromosomeFirst() {
+ final Integer[] p1 = new Integer[] {1, 0, 1, 0, 0, 1, 0, 1, 1};
+ final IntegralValuedChromosome<String> p1c = new IntegralValuedChromosome<String>(p1, chromosome -> 0,
+ new DummyListChromosomeDecoder<>("0"), 0, 2);
+ final AbstractChromosome<String> p2c = new AbstractChromosome<String>(chromosome -> 0,
+ new DummyListChromosomeDecoder<>("0")) {
+ };
+
... 1951 lines suppressed ...