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/04/03 14:19:23 UTC
[commons-math] 01/01: 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 99ca99198449c9ccfc28fbd0987e9c6a2611e0e6
Author: avbasak1 <av...@in.ibm.com>
AuthorDate: Sun Mar 13 00:54:18 2022 +0100
MATH-1563: Introducing new implementation of GA functionality (WIP).
Closes #208.
---
commons-math-examples/examples-ga/LICENCE | 201 ++++++++++++++
commons-math-examples/examples-ga/NOTICE | 5 +
.../examples-ga-math-functions-adaptive/LICENCE | 201 ++++++++++++++
.../examples-ga-math-functions-adaptive/NOTICE | 5 +
.../examples-ga-math-functions-adaptive/pom.xml | 44 +++
.../adaptive/AdaptiveMathFunctionOptimizer.java | 109 ++++++++
.../ga/mathfunctions/adaptive/Coordinate.java | 54 ++++
.../ga/mathfunctions/adaptive/StandAlone.java | 125 +++++++++
.../ga/mathfunctions/adaptive/package-info.java | 20 ++
.../examples-ga/examples-ga-math-functions/LICENCE | 201 ++++++++++++++
.../examples-ga/examples-ga-math-functions/NOTICE | 5 +
.../examples-ga/examples-ga-math-functions/pom.xml | 50 ++++
.../examples/ga/mathfunctions/Coordinate.java | 54 ++++
.../ga/mathfunctions/MathFunctionOptimizer.java | 116 ++++++++
.../examples/ga/mathfunctions/StandAlone.java | 109 ++++++++
.../legacy/LegacyBinaryChromosome.java | 65 +++++
.../legacy/LegacyMathFunctionOptimizer.java | 84 ++++++
.../mathfunctions/legacy/UnchangedBestFitness.java | 67 +++++
.../ga/mathfunctions/legacy/package-info.java | 20 ++
.../examples/ga/mathfunctions/package-info.java | 20 ++
.../examples-ga/examples-ga-tsp/LICENCE | 201 ++++++++++++++
.../examples-ga/examples-ga-tsp/NOTICE | 5 +
.../examples-ga/examples-ga-tsp/pom.xml | 52 ++++
.../apache/commons/math4/examples/ga/tsp/City.java | 77 ++++++
.../math4/examples/ga/tsp/DistanceMatrix.java | 73 +++++
.../commons/math4/examples/ga/tsp/StandAlone.java | 111 ++++++++
.../math4/examples/ga/tsp/TSPOptimizer.java | 104 +++++++
.../examples/ga/tsp/legacy/LegacyTSPOptimizer.java | 84 ++++++
.../examples/ga/tsp/legacy/TSPChromosome.java | 73 +++++
.../ga/tsp/legacy/UnchangedBestFitness.java | 67 +++++
.../math4/examples/ga/tsp/legacy/package-info.java | 20 ++
.../math4/examples/ga/tsp/package-info.java | 20 ++
.../examples-parallel-ga-math-functions/pom.xml | 42 +++
.../ga/parallel/mathfunctions/Coordinate.java | 54 ++++
.../ParallelMathFunctionOptimizer.java | 131 +++++++++
.../ga/parallel/mathfunctions/StandAlone.java | 78 ++++++
.../ga/parallel/mathfunctions/package-info.java | 20 ++
commons-math-examples/examples-ga/pom.xml | 62 +++++
.../resources/spotbugs/spotbugs-exclude-filter.xml | 60 ++++
commons-math-examples/pom.xml | 14 +
commons-math-ga/LICENCE | 201 ++++++++++++++
commons-math-ga/NOTICE | 5 +
commons-math-ga/pom.xml | 59 ++++
.../commons/math4/ga/AbstractGeneticAlgorithm.java | 265 ++++++++++++++++++
.../commons/math4/ga/AdaptiveGeneticAlgorithm.java | 226 +++++++++++++++
.../apache/commons/math4/ga/GeneticAlgorithm.java | 203 ++++++++++++++
.../commons/math4/ga/ParallelGeneticAlgorithm.java | 127 +++++++++
.../math4/ga/chromosome/AbstractChromosome.java | 148 ++++++++++
.../ga/chromosome/AbstractListChromosome.java | 124 +++++++++
.../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 | 55 ++++
.../AbstractListChromosomeCrossoverPolicy.java | 79 ++++++
.../math4/ga/crossover/CrossoverPolicy.java | 39 +++
.../commons/math4/ga/crossover/CycleCrossover.java | 168 ++++++++++++
.../math4/ga/crossover/NPointCrossover.java | 156 +++++++++++
.../ga/crossover/OnePointBinaryCrossover.java | 115 ++++++++
.../math4/ga/crossover/OnePointCrossover.java | 102 +++++++
.../math4/ga/crossover/OrderedCrossover.java | 130 +++++++++
.../math4/ga/crossover/UniformCrossover.java | 123 +++++++++
.../commons/math4/ga/crossover/package-info.java | 20 ++
...nearAverageRankBasedCrossoverRateGenerator.java | 58 ++++
...nearMaximumRankBasedCrossoverRateGenerator.java | 58 ++++
.../ConstantCrossoverRateGenerator.java | 51 ++++
.../rategenerator/CrossoverRateGenerator.java | 43 +++
.../ga/crossover/rategenerator/package-info.java | 20 ++
.../ga/decoder/AbstractListChromosomeDecoder.java | 61 +++++
.../apache/commons/math4/ga/decoder/Decoder.java | 36 +++
.../commons/math4/ga/decoder/RandomKeyDecoder.java | 76 ++++++
.../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 ++
.../exception/GeneticIllegalArgumentException.java | 120 ++++++++
.../math4/ga/internal/exception/package-info.java | 20 ++
.../stats/PopulationStatisticalSummaryImpl.java | 178 ++++++++++++
.../math4/ga/internal/stats/package-info.java | 20 ++
.../math4/ga/listener/ConvergenceListener.java | 37 +++
.../ga/listener/PopulationStatisticsLogger.java | 49 ++++
.../commons/math4/ga/listener/package-info.java | 20 ++
.../AbstractListChromosomeMutationPolicy.java | 109 ++++++++
.../commons/math4/ga/mutation/BinaryMutation.java | 128 +++++++++
.../math4/ga/mutation/IntegralValuedMutation.java | 111 ++++++++
.../commons/math4/ga/mutation/MutationPolicy.java | 36 +++
.../math4/ga/mutation/RealValuedMutation.java | 115 ++++++++
.../commons/math4/ga/mutation/package-info.java | 20 ++
.../AdaptiveLinearMutationRateGenerator.java | 54 ++++
.../ConstantMutationRateGenerator.java | 48 ++++
.../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 | 222 +++++++++++++++
.../commons/math4/ga/population/Population.java | 67 +++++
.../commons/math4/ga/population/package-info.java | 20 ++
.../math4/ga/selection/SelectionPolicy.java | 35 +++
.../math4/ga/selection/TournamentSelection.java | 109 ++++++++
.../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 | 213 +++++++++++++++
.../math4/ga/utils/RandomProviderManager.java | 47 ++++
.../commons/math4/ga/utils/package-info.java | 20 ++
.../math4/ga/GeneticAlgorithmTestBinaryOneMax.java | 162 +++++++++++
.../math4/ga/GeneticAlgorithmTestPermutations.java | 145 ++++++++++
.../ga/chromosome/AbstractChromosomeTest.java | 65 +++++
.../math4/ga/chromosome/BinaryChromosomeTest.java | 101 +++++++
.../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 | 35 +++
.../math4/ga/exception/GeneticExceptionTest.java | 39 +++
.../listener/PopulationStatisticsLoggerTest.java | 45 +++
.../math4/ga/mutation/BinaryMutationTest.java | 90 ++++++
.../ga/mutation/IntegralValuedMutationTest.java | 86 ++++++
.../math4/ga/mutation/RealValuedMutationTest.java | 110 ++++++++
.../AdaptiveLinearMutationRateGeneratorTest.java | 61 +++++
.../ConstantMutationRateGeneratorTest.java | 45 +++
.../math4/ga/population/ListPopulationTest.java | 202 ++++++++++++++
.../ga/selection/TournamentSelectionTest.java | 115 ++++++++
.../utils/ChromosomeRepresentationUtilsTest.java | 163 +++++++++++
pom.xml | 1 +
.../checkstyle/checkstyle-suppressions.xml | 1 +
150 files changed, 11728 insertions(+)
diff --git a/commons-math-examples/examples-ga/LICENCE b/commons-math-examples/examples-ga/LICENCE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/commons-math-examples/examples-ga/LICENCE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/commons-math-examples/examples-ga/NOTICE b/commons-math-examples/examples-ga/NOTICE
new file mode 100644
index 0000000..28031e8
--- /dev/null
+++ b/commons-math-examples/examples-ga/NOTICE
@@ -0,0 +1,5 @@
+Apache Commons Math
+Copyright 2001-2022 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/LICENCE b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/LICENCE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/LICENCE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/NOTICE b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/NOTICE
new file mode 100644
index 0000000..28031e8
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/NOTICE
@@ -0,0 +1,5 @@
+Apache Commons Math
+Copyright 2001-2022 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/pom.xml b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/pom.xml
new file mode 100644
index 0000000..b73679d
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/pom.xml
@@ -0,0 +1,44 @@
+<?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-adaptive</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ <name>GA: Math Functions Adaptive</name>
+
+ <properties>
+ <!-- OSGi -->
+ <commons.osgi.symbolicName>org.apache.commons.math4.examples.ga.mathfunctions.adaptive</commons.osgi.symbolicName>
+ <commons.osgi.export>org.apache.commons.math4.examples.ga.mathfunctions.adaptive</commons.osgi.export>
+ <!-- Java 9+ -->
+ <commons.automatic.module.name>org.apache.commons.math4.examples.ga.mathfunctions.adaptive</commons.automatic.module.name>
+ <!-- Workaround to avoid duplicating config files. -->
+ <math.parent.dir>${basedir}/../../..</math.parent.dir>
+
+ <uberjar.name>examples-ga-mathfunctions-adaptive</uberjar.name>
+ <project.mainClass>org.apache.commons.math4.examples.ga.mathfunctions.adaptive.StandAlone</project.mainClass>
+ </properties>
+
+</project>
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/AdaptiveMathFunctionOptimizer.java b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/AdaptiveMathFunctionOptimizer.java
new file mode 100644
index 0000000..cd41f98
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/AdaptiveMathFunctionOptimizer.java
@@ -0,0 +1,109 @@
+/*
+ * 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.adaptive;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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.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 final class AdaptiveMathFunctionOptimizer {
+ /** length of chromosome. **/
+ private static final int CHROMOSOME_LENGTH_PER_DIMENSION = 12;
+
+ /** instance of logger. **/
+ private final Logger logger = LoggerFactory.getLogger(AdaptiveMathFunctionOptimizer.class);
+
+ public void optimize(int dimension,
+ double minCrossoverRate,
+ double maxCrossoverRate,
+ double minMutationRate,
+ double maxMutationRate,
+ double elitismRate,
+ int tournamentSize,
+ int generationCountWithUnchangedBestFitness,
+ int populationSize) {
+
+ // initialize a new genetic algorithm
+ final AbstractGeneticAlgorithm<Coordinate> ga = new AdaptiveGeneticAlgorithm<>(new OnePointBinaryCrossover<>(),
+ new AdaptiveLinearMaximumRankBasedCrossoverRateGenerator<>(minCrossoverRate, maxCrossoverRate),
+ new BinaryMutation<>(), new AdaptiveLinearMutationRateGenerator<>(minMutationRate, maxMutationRate),
+ new TournamentSelection<>(tournamentSize), elitismRate, new PopulationStatisticsLogger<>());
+
+ // stopping condition
+ final StoppingCondition<Coordinate> stopCond = new UnchangedBestFitness<>(
+ generationCountWithUnchangedBestFitness);
+
+ // run the algorithm
+ final Population<Coordinate> finalPopulation = ga.evolve(getInitialPopulation(dimension, populationSize),
+ stopCond, Runtime.getRuntime().availableProcessors());
+
+ // best chromosome from the final population
+ final Chromosome<Coordinate> bestFinal = finalPopulation.getFittestChromosome();
+
+ logger.info(bestFinal.toString());
+ }
+
+ private static Population<Coordinate> getInitialPopulation(int dimension, int populationSize) {
+ final Population<Coordinate> population = new ListPopulation<>(populationSize);
+
+ for (int i = 0; i < populationSize; i++) {
+ population.addChromosome(BinaryChromosome
+ .<Coordinate>randomChromosome(dimension * CHROMOSOME_LENGTH_PER_DIMENSION, 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);
+ }, chromosome -> {
+ final BinaryChromosome<Coordinate> binaryChromosome =
+ (BinaryChromosome<Coordinate>) chromosome;
+ final long length = binaryChromosome.getLength();
+ final List<Double> coordinates = new ArrayList<>();
+
+ for (int j = 0; j < length; j += 12) {
+ final String dimensionStrValue = binaryChromosome.getStringRepresentation(j, j + 12);
+ coordinates.add(Integer.parseUnsignedInt(dimensionStrValue, 2) / 100d);
+ }
+
+ return new Coordinate(coordinates);
+ }));
+ }
+ return population;
+ }
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/Coordinate.java b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/Coordinate.java
new file mode 100644
index 0000000..51585d7
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/Coordinate.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.adaptive;
+
+import java.util.List;
+
+/**
+ * This class represents the coordinate of the problem domain i.e. the phenotype
+ * of chromosome.
+ */
+public class Coordinate {
+
+ /** coordinate of all dimensions. **/
+ private final List<Double> values;
+
+ /**
+ * constructor.
+ * @param values coordinates of all dimensions.
+ */
+ public Coordinate(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-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/StandAlone.java b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/StandAlone.java
new file mode 100644
index 0000000..0c59729
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/StandAlone.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.examples.ga.mathfunctions.adaptive;
+
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+
+@Command(name = "adaptive-mathfunction-optimizer", mixinStandardHelpOptions = true,
+ version = "adaptive-mathfunction-optimizer 1.0")
+public class StandAlone implements Runnable {
+
+ /** number of dimension. **/
+ @Option(names = "-d", paramLabel = "DIMENSION", required = true, description = "Dimension of problem domain.")
+ private int dimension;
+
+ /** size of tournament. **/
+ @Option(names = "-t", paramLabel = "TOURNAMENT_SIZE", required = true, description = "Tournament size.")
+ private int tournamentSize;
+
+ /** size of population. **/
+ @Option(names = "-p", paramLabel = "POPULATION_SIZE", required = true, description = "Size of population.")
+ private int populationSize;
+
+ /** minimum rate of crossover. **/
+ @Option(names = "-c", paramLabel = "MIN_CROSSOVER_RATE",
+ description = "Crossover rate (default: ${DEFAULT-VALUE}).")
+ private double minCrossoverRate = 0;
+
+ /** maximum rate of crossover. **/
+ @Option(names = "-C", paramLabel = "MAX_CROSSOVER_RATE",
+ description = "Crossover rate (default: ${DEFAULT-VALUE}).")
+ private double maxCrossoverRate = 1.0;
+
+ /** minimum rate of mutation. **/
+ @Option(names = "-m", paramLabel = "MIN_MUTATION_RATE",
+ description = "Minimum Mutation rate (default: ${DEFAULT-VALUE}).")
+ private double minMutationRate = 0;
+
+ /** maximum rate of mutation. **/
+ @Option(names = "-M", paramLabel = "MAX_MUTATION_RATE",
+ description = "Maximum Mutation rate (default: ${DEFAULT-VALUE}).")
+ private double maxMutationRate = 0.1;
+
+ /** rate of elitism. **/
+ @Option(names = "-e", paramLabel = "ELITISM_RATE", description = "Elitism rate (default: ${DEFAULT-VALUE}).")
+ private double elitismRate = 0.25;
+
+ /** number of generations with unchanged best fitness. **/
+ @Option(names = "-g", paramLabel = "GENERATIONS_EVOLVED_WITH_UNCHANGED_BEST_FITNESS",
+ description = "No of generations evolved with unchanged best fitness (default: ${DEFAULT-VALUE}).")
+ private int generationsEvolvedWithUnchangedBestFitness = 50;
+
+ public static void main(String[] args) {
+ CommandLine.run(new StandAlone(), args);
+ }
+
+ /**
+ * This method is responsible for validating input and invoking
+ * {@link AdaptiveMathFunctionOptimizer}.
+ */
+ @Override
+ public void run() {
+
+ // validate all input options.
+ validateInput();
+
+ final AdaptiveMathFunctionOptimizer optimizer = new AdaptiveMathFunctionOptimizer();
+
+ optimizer.optimize(dimension, minCrossoverRate, maxCrossoverRate, minMutationRate, maxMutationRate, elitismRate,
+ tournamentSize, generationsEvolvedWithUnchangedBestFitness, populationSize);
+
+ }
+
+ private void validateInput() {
+ if (this.dimension < 1) {
+ throw new IllegalArgumentException("Dimension should be > 0.");
+ }
+ if (this.tournamentSize < 1) {
+ throw new IllegalArgumentException("Tournament size should be > 0.");
+ }
+ if (populationSize < 2) {
+ throw new IllegalArgumentException("Population size should be > 1.");
+ }
+ if (minCrossoverRate > 1) {
+ throw new IllegalArgumentException("Minimum crossover rate should be <= 1.");
+ }
+ if (maxCrossoverRate > 1) {
+ throw new IllegalArgumentException("Maximum crossover rate should be <= 1.");
+ }
+ if (maxCrossoverRate < minCrossoverRate) {
+ throw new IllegalArgumentException("Minimum crossover rate should be lesser than maximum crossover rate.");
+ }
+ if (minMutationRate > 1) {
+ throw new IllegalArgumentException("Minimum mutation rate should be <= 1.");
+ }
+ if (maxMutationRate > 1) {
+ throw new IllegalArgumentException("Maximum mutation rate should be <= 1.");
+ }
+ if (minMutationRate > maxMutationRate) {
+ throw new IllegalArgumentException("Minimum mutation rate should be lesser than maximum mutation rate.");
+ }
+ if (elitismRate >= 1) {
+ throw new IllegalArgumentException("Elitism rate should be < 1.");
+ }
+ if (generationsEvolvedWithUnchangedBestFitness < 1) {
+ throw new IllegalArgumentException(
+ "Number of generations evolved with unchanged best fitness should be >= 1.");
+ }
+ }
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/package-info.java b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/package-info.java
new file mode 100644
index 0000000..0f5050f
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions-adaptive/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/adaptive/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.adaptive;
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/LICENCE b/commons-math-examples/examples-ga/examples-ga-math-functions/LICENCE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/LICENCE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/NOTICE b/commons-math-examples/examples-ga/examples-ga-math-functions/NOTICE
new file mode 100644
index 0000000..28031e8
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/NOTICE
@@ -0,0 +1,5 @@
+Apache Commons Math
+Copyright 2001-2022 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
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..ce58e44
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/pom.xml
@@ -0,0 +1,50 @@
+<?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>
+ <name>GA: Math Functions</name>
+
+ <properties>
+ <!-- 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.StandAlone</project.mainClass>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math3</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/Coordinate.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/Coordinate.java
new file mode 100644
index 0000000..eee31fb
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/Coordinate.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;
+
+import java.util.List;
+
+/**
+ * This class represents the coordinate of the problem domain i.e. the phenotype
+ * of chromosome.
+ */
+public class Coordinate {
+
+ /** coordinate of all dimensions. **/
+ private final List<Double> values;
+
+ /**
+ * constructor.
+ * @param values coordinates of all dimensions.
+ */
+ public Coordinate(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/MathFunctionOptimizer.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/MathFunctionOptimizer.java
new file mode 100644
index 0000000..73b00a0
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/MathFunctionOptimizer.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.mathfunctions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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.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 final class MathFunctionOptimizer {
+ /** length of chromosome. **/
+ private static final int CHROMOSOME_LENGTH_PER_DIMENSION = 12;
+ /** instance of logger. **/
+ private final Logger logger = LoggerFactory.getLogger(MathFunctionOptimizer.class);
+
+ /**
+ * Optimizes the population.
+ * @param dimension dimension
+ * @param crossoverRate crossover rate
+ * @param mutationRate mutation rate
+ * @param elitismRate elitism rate
+ * @param tournamentSize tournament size
+ * @param generationCountWithUnchangedBestFitness no of generation evolved with
+ * unchanged best fitness
+ * @param populationSize size of population
+ */
+ public void optimize(int dimension,
+ double crossoverRate,
+ double mutationRate,
+ double elitismRate,
+ int tournamentSize,
+ int generationCountWithUnchangedBestFitness,
+ int populationSize) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm<Coordinate> ga = new GeneticAlgorithm<Coordinate>(
+ new OnePointBinaryCrossover<Coordinate>(), crossoverRate, new BinaryMutation<Coordinate>(),
+ mutationRate, new TournamentSelection<Coordinate>(tournamentSize), elitismRate,
+ new PopulationStatisticsLogger<Coordinate>());
+
+ // stopping condition
+ final StoppingCondition<Coordinate> stopCond = new UnchangedBestFitness<>(
+ generationCountWithUnchangedBestFitness);
+
+ // run the algorithm
+ final Population<Coordinate> finalPopulation = ga.evolve(getInitialPopulation(dimension, populationSize),
+ stopCond, Runtime.getRuntime().availableProcessors());
+
+ // best chromosome from the final population
+ final Chromosome<Coordinate> bestFinal = finalPopulation.getFittestChromosome();
+
+ logger.info(bestFinal.toString());
+ }
+
+ private static Population<Coordinate> getInitialPopulation(int dimension, int populationSize) {
+ final Population<Coordinate> population = new ListPopulation<>(populationSize);
+
+ for (int i = 0; i < populationSize; i++) {
+ population.addChromosome(BinaryChromosome
+ .<Coordinate>randomChromosome(dimension * CHROMOSOME_LENGTH_PER_DIMENSION, 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);
+
+ }, chromosome -> {
+ final BinaryChromosome<Coordinate> binaryChromosome =
+ (BinaryChromosome<Coordinate>) chromosome;
+ final long length = binaryChromosome.getLength();
+ final List<Double> coordinates = new ArrayList<>();
+
+ for (int j = 0; j < length; j += 12) {
+ final String dimensionStrValue = binaryChromosome.getStringRepresentation(j, j + 12);
+ coordinates.add(Integer.parseUnsignedInt(dimensionStrValue, 2) / 100d);
+ }
+
+ return new Coordinate(coordinates);
+ }));
+ }
+ return population;
+ }
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/StandAlone.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/StandAlone.java
new file mode 100644
index 0000000..4d54ac5
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/StandAlone.java
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+import org.apache.commons.math4.examples.ga.mathfunctions.legacy.LegacyMathFunctionOptimizer;
+
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+
+@Command(name = "mathfunction-optimizer", mixinStandardHelpOptions = true, version = "mathfunction-optimizer 1.0")
+public class StandAlone implements Runnable {
+
+ /** number of dimension. **/
+ @Option(names = "-d", paramLabel = "DIMENSION", required = true, description = "Dimension of problem domain.")
+ private int dimension;
+
+ /** size of tournament. **/
+ @Option(names = "-t", paramLabel = "TOURNAMENT_SIZE", required = true, description = "Tournament size.")
+ private int tournamentSize;
+
+ /** size of population. **/
+ @Option(names = "-p", paramLabel = "POPULATION_SIZE", required = true, description = "Size of population.")
+ private int populationSize;
+
+ /** rate of crossover. **/
+ @Option(names = "-c", paramLabel = "CROSSOVER_RATE", description = "Crossover rate (default: ${DEFAULT-VALUE}).")
+ private double crossoverRate = 1.0;
+
+ /** rate of elitism. **/
+ @Option(names = "-e", paramLabel = "ELITISM_RATE", description = "Elitism rate (default: ${DEFAULT-VALUE}).")
+ private double elitismRate = 0.25;
+
+ /** rate of mutation. **/
+ @Option(names = "-m", paramLabel = "MUTATION_RATE", description = "Mutation rate (default: ${DEFAULT-VALUE}).")
+ private double mutationRate = 0.01;
+
+ /** number of generations with unchanged best fitness. **/
+ @Option(names = "-g", paramLabel = "GENERATIONS_EVOLVED_WITH_UNCHANGED_BEST_FITNESS",
+ description = "No of generations evolved with unchanged best fitness (default: ${DEFAULT-VALUE}).")
+ private int generationsEvolvedWithUnchangedBestFitness = 50;
+
+ /** indicates whether the algorithm should be legacy or not. **/
+ @Option(names = "--legacy", description = "Indicates which version of algorithm to execute current or legacy.")
+ private boolean legacy;
+
+ public static void main(String[] args) {
+ CommandLine.run(new StandAlone(), args);
+ }
+
+ /**
+ * This method is responsible for validating input and then invoking math
+ * function optimizer.
+ */
+ @Override
+ public void run() {
+
+ // validate all input options.
+ validateInput();
+
+ if (!legacy) {
+ new MathFunctionOptimizer().optimize(dimension, crossoverRate, mutationRate, elitismRate, tournamentSize,
+ generationsEvolvedWithUnchangedBestFitness, populationSize);
+ } else {
+ new LegacyMathFunctionOptimizer().optimize(dimension, crossoverRate, mutationRate, elitismRate,
+ tournamentSize, generationsEvolvedWithUnchangedBestFitness, populationSize);
+ }
+
+ }
+
+ private void validateInput() {
+ if (this.dimension < 1) {
+ throw new IllegalArgumentException("Dimension should be > 0.");
+ }
+ if (this.tournamentSize < 1) {
+ throw new IllegalArgumentException("Tournament size should be > 0.");
+ }
+ if (populationSize <= 1) {
+ throw new IllegalArgumentException("Population size should be > 1.");
+ }
+ if (crossoverRate > 1) {
+ throw new IllegalArgumentException("Crossover rate should be <= 1.");
+ }
+ if (elitismRate >= 1) {
+ throw new IllegalArgumentException("Elitism rate should be < 1.");
+ }
+ if (mutationRate > 1) {
+ throw new IllegalArgumentException("Mutation rate should be <= 1.");
+ }
+ if (generationsEvolvedWithUnchangedBestFitness < 1) {
+ throw new IllegalArgumentException(
+ "Number of generations evolved with unchanged best fitness should be >= 1.");
+ }
+ }
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/legacy/LegacyBinaryChromosome.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/legacy/LegacyBinaryChromosome.java
new file mode 100644
index 0000000..cac3577
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/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.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));
+ }
+ double val = 0.0;
+ for (int i = 0; i < allelesStr.length(); i += 12) {
+ val += Math.pow(Integer.parseInt(allelesStr.substring(i, i + 12), 2) / 100.0, 2);
+ }
+
+ return -Math.pow(val, .25) * (Math.pow(Math.sin(50 * Math.pow(val, .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/legacy/LegacyMathFunctionOptimizer.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/legacy/LegacyMathFunctionOptimizer.java
new file mode 100644
index 0000000..ca49162
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/legacy/LegacyMathFunctionOptimizer.java
@@ -0,0 +1,84 @@
+/*
+ * 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.legacy;
+
+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;
+
+/**
+ * This class represents an optimizer for a 2-dimensional math function using
+ * the legacy genetic algorithm.
+ */
+public final class LegacyMathFunctionOptimizer {
+ /** length of chromosome per dimension. **/
+ private static final int CHROMOSOME_LENGTH_PER_DIMENSION = 12;
+
+ /**
+ * Optimizes the initial population using legacy genetic algorithm.
+ * @param dimension dimension of problem domain
+ * @param crossoverRate rate of crossover
+ * @param mutationRate rate of mutation
+ * @param elitismRate rate of elitism
+ * @param tournamentSize size of tournament
+ * @param generationCountWithUnchangedBestFitness no of generation evolved with
+ * unchanged best fitness
+ * @param populationSize size of population
+ */
+ public void optimize(int dimension,
+ double crossoverRate,
+ double mutationRate,
+ double elitismRate,
+ int tournamentSize,
+ int generationCountWithUnchangedBestFitness,
+ int populationSize) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm geneticAlgorithm = new GeneticAlgorithm(new OnePointCrossover<>(), crossoverRate,
+ new BinaryMutation(), mutationRate, new TournamentSelection(tournamentSize));
+
+ // stopping condition
+ final StoppingCondition stopCond = new UnchangedBestFitness(generationCountWithUnchangedBestFitness);
+
+ // run the algorithm
+ final Population finalPopulation = geneticAlgorithm
+ .evolve(getInitialPopulation(dimension, populationSize, elitismRate), stopCond);
+
+ // best chromosome from the final population
+ final Chromosome bestFinal = finalPopulation.getFittestChromosome();
+
+ //CHECKSTYLE: stop all
+ System.out.println("best=" + bestFinal.toString());
+ //CHECKSTYLE: resume all
+ }
+
+ private static Population getInitialPopulation(int dimension, int populationSize, double elitismRate) {
+ final Population population = new ElitisticListPopulation(populationSize, elitismRate);
+ for (int i = 0; i < populationSize; i++) {
+ population.addChromosome(new LegacyBinaryChromosome(
+ BinaryChromosome.randomBinaryRepresentation(dimension * 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/legacy/UnchangedBestFitness.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/legacy/UnchangedBestFitness.java
new file mode 100644
index 0000000..eabb11d
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/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.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/legacy/package-info.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/legacy/package-info.java
new file mode 100644
index 0000000..24ca3d7
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/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.legacy;
diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/package-info.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/package-info.java
new file mode 100644
index 0000000..f2344be
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/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;
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/LICENCE b/commons-math-examples/examples-ga/examples-ga-tsp/LICENCE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/LICENCE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/NOTICE b/commons-math-examples/examples-ga/examples-ga-tsp/NOTICE
new file mode 100644
index 0000000..28031e8
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/NOTICE
@@ -0,0 +1,5 @@
+Apache Commons Math
+Copyright 2001-2022 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
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..ffc645e
--- /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>
+ <name>GA: TSP</name>
+
+ <properties>
+ <!-- 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-tsp</uberjar.name>
+ <project.mainClass>org.apache.commons.math4.examples.ga.tsp.StandAlone</project.mainClass>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math3</artifactId>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/City.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/City.java
new file mode 100644
index 0000000..ced4c91
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/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;
+
+/**
+ * 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/DistanceMatrix.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/DistanceMatrix.java
new file mode 100644
index 0000000..b6620fa
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/DistanceMatrix.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math4.examples.ga.tsp;
+
+import java.util.List;
+
+/**
+ * This class represents the distance matrix between cities.
+ */
+public final class DistanceMatrix {
+
+ /** instance of the class. **/
+ private static DistanceMatrix instance;
+
+ /** distances between cities. **/
+ private double[][] distances;
+
+ private DistanceMatrix(List<City> cities) {
+ initialize(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.
+ * @param cities the cities
+ * @return instance
+ */
+ public static synchronized DistanceMatrix getInstance(List<City> cities) {
+ if (instance == null) {
+ instance = new DistanceMatrix(cities);
+ }
+ return instance;
+ }
+
+}
diff --git a/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/StandAlone.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/StandAlone.java
new file mode 100644
index 0000000..8828fec
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/StandAlone.java
@@ -0,0 +1,111 @@
+/*
+ * 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.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math4.examples.ga.tsp.legacy.LegacyTSPOptimizer;
+
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+
+@Command(name = "tsp-optimizer", mixinStandardHelpOptions = true, version = "tsp-optimizer 1.0")
+public class StandAlone implements Runnable {
+
+ /** 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)}));
+
+ /** size of tournament. **/
+ @Option(names = "-t", paramLabel = "TOURNAMENT_SIZE", required = true, description = "Tournament size.")
+ private int tournamentSize;
+
+ /** size of population. **/
+ @Option(names = "-p", paramLabel = "POPULATION_SIZE", required = true, description = "Size of population.")
+ private int populationSize;
+
+ /** rate of crossover. **/
+ @Option(names = "-c", paramLabel = "CROSSOVER_RATE", description = "Crossover rate (default: ${DEFAULT-VALUE}).")
+ private double crossoverRate = 1.0;
+
+ /** rate of elitism. **/
+ @Option(names = "-e", paramLabel = "ELITISM_RATE", description = "Elitism rate (default: ${DEFAULT-VALUE}).")
+ private double elitismRate = 0.25;
+
+ /** rate of mutation. **/
+ @Option(names = "-m", paramLabel = "MUTATION_RATE", description = "Mutation rate (default: ${DEFAULT-VALUE}).")
+ private double mutationRate = 0.01;
+
+ /** number of generations with unchanged best fitness. **/
+ @Option(names = "-g", paramLabel = "GENERATIONS_EVOLVED_WITH_UNCHANGED_BEST_FITNESS",
+ description = "No of generations evolved with unchanged best fitness (default: ${DEFAULT-VALUE}).")
+ private int generationsEvolvedWithUnchangedBestFitness = 50;
+
+ /** indicates whether the algorithm should be legacy or not. **/
+ @Option(names = "--legacy", description = "Indicates which version of algorithm to execute current or legacy.")
+ private boolean legacy;
+
+ public static void main(String[] args) {
+ CommandLine.run(new StandAlone(), args);
+ }
+
+ /**
+ * This method is responsible for validating input and invoking TSP optimizer.
+ */
+ @Override
+ public void run() {
+
+ // validate all input options.
+ validateInput();
+
+ if (!legacy) {
+ new TSPOptimizer().optimize(CITIES, crossoverRate, mutationRate, elitismRate, tournamentSize,
+ generationsEvolvedWithUnchangedBestFitness, populationSize);
+ } else {
+ new LegacyTSPOptimizer().optimize(CITIES, crossoverRate, mutationRate, elitismRate, tournamentSize,
+ generationsEvolvedWithUnchangedBestFitness, populationSize);
+ }
+
+ }
+
+ private void validateInput() {
+ if (this.tournamentSize < 1) {
+ throw new IllegalArgumentException("Tournament size should be > 0.");
+ }
+ if (populationSize < 2) {
+ throw new IllegalArgumentException("Population size should be > 1.");
+ }
+ if (crossoverRate > 1) {
+ throw new IllegalArgumentException("Crossover rate should be <= 1.");
+ }
+ if (elitismRate >= 1) {
+ throw new IllegalArgumentException("Elitism rate should be < 1.");
+ }
+ if (mutationRate > 1) {
+ throw new IllegalArgumentException("Mutation rate should be <= 1.");
+ }
+ if (generationsEvolvedWithUnchangedBestFitness < 1) {
+ throw new IllegalArgumentException(
+ "Number of generations evolved with unchanged best fitness should be >= 1.");
+ }
+ }
+}
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..4b0e85c
--- /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,104 @@
+/*
+ * 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.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.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 final class TSPOptimizer {
+ /** instance of logger. **/
+ private final Logger logger = LoggerFactory.getLogger(TSPOptimizer.class);
+
+ /**
+ * Optimizes the TSP problem.
+ * @param cities list of cities
+ * @param crossoverRate rate of crossover
+ * @param mutationRate rate of mutation
+ * @param elitismRate rate of elitism
+ * @param tournamentSize size of tournament
+ * @param generationCountWithUnchangedBestFitness no of generations evolved with
+ * unchanged best fitness
+ * @param populationSize size of population
+ */
+ public void optimize(List<City> cities,
+ double crossoverRate,
+ double mutationRate,
+ double elitismRate,
+ int tournamentSize,
+ int generationCountWithUnchangedBestFitness,
+ int populationSize) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm<List<City>> ga = new GeneticAlgorithm<>(new OnePointCrossover<Integer, List<City>>(),
+ crossoverRate, new RealValuedMutation<>(), mutationRate, new TournamentSelection<>(tournamentSize),
+ elitismRate, new PopulationStatisticsLogger<>());
+
+ // stopping condition
+ final StoppingCondition<List<City>> stopCond = new UnchangedBestFitness<>(
+ generationCountWithUnchangedBestFitness);
+
+ // run the algorithm
+ final Population<List<City>> finalPopulation = ga.evolve(getInitialPopulation(cities, populationSize), stopCond,
+ Runtime.getRuntime().availableProcessors());
+
+ // best chromosome from the final population
+ final RealValuedChromosome<List<City>> bestFinal = (RealValuedChromosome<List<City>>) finalPopulation
+ .getFittestChromosome();
+
+ logger.info(bestFinal.decode().toString());
+ }
+
+ private static Population<List<City>> getInitialPopulation(List<City> cities, int populationSize) {
+ final Population<List<City>> simulationPopulation = new ListPopulation<>(populationSize);
+
+ for (int i = 0; i < populationSize; i++) {
+ simulationPopulation.addChromosome(new RealValuedChromosome<>(
+ ChromosomeRepresentationUtils.randomPermutation(cities.size()), decodedChromosome -> {
+ final DistanceMatrix distanceMatrix = DistanceMatrix.getInstance(cities);
+ double totalDistance = 0.0;
+ int index1 = 0;
+ int index2 = 0;
+ for (int j = 0; j < cities.size(); j++) {
+ index1 = j;
+ index2 = (j == cities.size() - 1) ? 0 : j + 1;
+ totalDistance += distanceMatrix.getDistance(cities.get(index1), cities.get(index2));
+ }
+ return -totalDistance;
+ }, 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/legacy/LegacyTSPOptimizer.java b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/LegacyTSPOptimizer.java
new file mode 100644
index 0000000..9d826e7
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-ga-tsp/src/main/java/org/apache/commons/math4/examples/ga/tsp/legacy/LegacyTSPOptimizer.java
@@ -0,0 +1,84 @@
+/*
+ * 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.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.City;
+
+/**
+ * This class represents the tsp optimizer based on legacy implementation of
+ * Genetic Algorithm.
+ */
+public class LegacyTSPOptimizer {
+ /**
+ * Optimizes the TSP problem.
+ * @param cities list of cities
+ * @param crossoverRate rate of crossover
+ * @param mutationRate rate of mutation
+ * @param elitismRate rate of elitism
+ * @param tournamentSize size of tournament
+ * @param generationCountWithUnchangedBestFitness no of generations evolved with
+ * unchanged best fitness
+ * @param populationSize size of population
+ */
+ public void optimize(List<City> cities,
+ double crossoverRate,
+ double mutationRate,
+ double elitismRate,
+ int tournamentSize,
+ int generationCountWithUnchangedBestFitness,
+ int populationSize) {
+
+ // initialize a new genetic algorithm
+ final GeneticAlgorithm ga = new GeneticAlgorithm(new OnePointCrossover<Integer>(), crossoverRate,
+ new RandomKeyMutation(), mutationRate, new TournamentSelection(tournamentSize));
+
+ // stopping condition
+ final StoppingCondition stopCond = new UnchangedBestFitness(generationCountWithUnchangedBestFitness);
+
+ // run the algorithm
+ final Population finalPopulation = ga.evolve(getInitialPopulation(cities, populationSize, elitismRate),
+ stopCond);
+
+ // best chromosome from the final population
+ @SuppressWarnings("unchecked")
+ final RandomKey<City> bestFinal = (RandomKey<City>) finalPopulation.getFittestChromosome();
+
+ //CHECKSTYLE: stop all
+ System.out.println("best=" + bestFinal.toString());
+ //CHECKSTYLE: resume all
+ }
+
+ private static Population getInitialPopulation(List<City> cities, int populationSize, double elitismRate) {
+ final Population simulationPopulation = new ElitisticListPopulation(populationSize, elitismRate);
+
+ for (int i = 0; i < populationSize; 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/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..a5f7f3f
--- /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,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math4.examples.ga.tsp.legacy;
+
+import java.util.List;
+
+import org.apache.commons.math3.genetics.RandomKey;
+import org.apache.commons.math4.examples.ga.tsp.City;
+import org.apache.commons.math4.examples.ga.tsp.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) {
+ final DistanceMatrix distanceMatrix = DistanceMatrix.getInstance(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 += distanceMatrix.getDistance(permutedCities.get(index1), permutedCities.get(index2));
+ }
+ return totalDistance;
+ }
+
+}
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-parallel-ga-math-functions/pom.xml b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/pom.xml
new file mode 100644
index 0000000..e4db098
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/pom.xml
@@ -0,0 +1,42 @@
+<?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-parallel-ga-math-functions</artifactId>
+ <name>Parallel GA: Math Functions</name>
+
+ <properties>
+ <!-- OSGi -->
+ <commons.osgi.symbolicName>org.apache.commons.math4.examples.ga.parallel.mathfunctions</commons.osgi.symbolicName>
+ <commons.osgi.export>org.apache.commons.math4.examples.ga.parallel.mathfunctions</commons.osgi.export>
+ <!-- Java 9+ -->
+ <commons.automatic.module.name>org.apache.commons.math4.examples.ga.parallel.mathfunctions</commons.automatic.module.name>
+ <!-- Workaround to avoid duplicating config files. -->
+ <math.parent.dir>${basedir}/../../..</math.parent.dir>
+
+ <uberjar.name>examples-ga-parallel-mathfunctions</uberjar.name>
+ <project.mainClass>org.apache.commons.math4.examples.ga.parallel.mathfunctions.StandAlone</project.mainClass>
+ </properties>
+</project>
\ No newline at end of file
diff --git a/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/Coordinate.java b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/Coordinate.java
new file mode 100644
index 0000000..875d134
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/Coordinate.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.parallel.mathfunctions;
+
+import java.util.List;
+
+/**
+ * This class represents the coordinate of the problem domain i.e. the phenotype
+ * of chromosome.
+ */
+public class Coordinate {
+
+ /** coordinate of all dimensions. **/
+ private final List<Double> values;
+
+ /**
+ * constructor.
+ * @param values coordinates of all dimensions.
+ */
+ public Coordinate(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-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/ParallelMathFunctionOptimizer.java b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/ParallelMathFunctionOptimizer.java
new file mode 100644
index 0000000..6a1d56a
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/ParallelMathFunctionOptimizer.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.examples.ga.parallel.mathfunctions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.math4.ga.AdaptiveGeneticAlgorithm;
+import org.apache.commons.math4.ga.GeneticAlgorithm;
+import org.apache.commons.math4.ga.ParallelGeneticAlgorithm;
+import org.apache.commons.math4.ga.chromosome.BinaryChromosome;
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+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.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 final class ParallelMathFunctionOptimizer {
+ /** length of chromosome. **/
+ private static final int CHROMOSOME_LENGTH_PER_DIMENSION = 12;
+ /** instance of logger. **/
+ private final Logger logger = LoggerFactory.getLogger(ParallelMathFunctionOptimizer.class);
+
+ /**
+ * Optimizes the population.
+ * @param dimension dimension
+ * @param tournamentSize tournament size
+ * @param generationCountWithUnchangedBestFitness no of generation evolved with
+ * unchanged best fitness
+ * @param populationSize size of population
+ */
+ public void optimize(int dimension,
+ int tournamentSize,
+ int generationCountWithUnchangedBestFitness,
+ int populationSize) {
+
+ ParallelGeneticAlgorithm<Coordinate> parallelGeneticAlgorithm = new ParallelGeneticAlgorithm<>();
+
+ parallelGeneticAlgorithm.addAlgorithmExecutionConfig(
+ new GeneticAlgorithm<Coordinate>(new OnePointBinaryCrossover<Coordinate>(), .8,
+ new BinaryMutation<Coordinate>(), .02, new TournamentSelection<Coordinate>(tournamentSize), .2,
+ new PopulationStatisticsLogger<Coordinate>()),
+ getInitialPopulation(dimension, populationSize),
+ new UnchangedBestFitness<>(generationCountWithUnchangedBestFitness));
+ parallelGeneticAlgorithm.addAlgorithmExecutionConfig(
+ new GeneticAlgorithm<Coordinate>(new OnePointBinaryCrossover<Coordinate>(), .75,
+ new BinaryMutation<Coordinate>(), .03, new TournamentSelection<Coordinate>(tournamentSize), .3,
+ new PopulationStatisticsLogger<Coordinate>()),
+ getInitialPopulation(dimension, populationSize),
+ new UnchangedBestFitness<>(generationCountWithUnchangedBestFitness));
+ parallelGeneticAlgorithm.addAlgorithmExecutionConfig(
+ new AdaptiveGeneticAlgorithm<>(new OnePointBinaryCrossover<>(),
+ new AdaptiveLinearMaximumRankBasedCrossoverRateGenerator<>(.5, 1), new BinaryMutation<>(),
+ new AdaptiveLinearMutationRateGenerator<>(.01, .05), new TournamentSelection<>(tournamentSize),
+ .25, new PopulationStatisticsLogger<>()),
+ getInitialPopulation(dimension, populationSize),
+ new UnchangedBestFitness<>(generationCountWithUnchangedBestFitness));
+
+ // run the algorithm
+ final List<Population<Coordinate>> finalPopulations = parallelGeneticAlgorithm
+ .evolve(Runtime.getRuntime().availableProcessors());
+
+ // find best chromosomes from all populations.
+ List<Chromosome<Coordinate>> bestChromosomes = new ArrayList<>();
+ for (Population<Coordinate> population : finalPopulations) {
+ bestChromosomes.add(population.getFittestChromosome());
+ }
+
+ // best chromosome after convergence.
+ final Chromosome<Coordinate> bestFinal = Collections.max(bestChromosomes);
+
+ logger.info(bestFinal.toString());
+ }
+
+ private static Population<Coordinate> getInitialPopulation(int dimension, int populationSize) {
+ final Population<Coordinate> population = new ListPopulation<>(populationSize);
+
+ for (int i = 0; i < populationSize; i++) {
+ population.addChromosome(BinaryChromosome
+ .<Coordinate>randomChromosome(dimension * CHROMOSOME_LENGTH_PER_DIMENSION, 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);
+ }, chromosome -> {
+ final BinaryChromosome<Coordinate> binaryChromosome =
+ (BinaryChromosome<Coordinate>) chromosome;
+ final long length = binaryChromosome.getLength();
+ final List<Double> coordinates = new ArrayList<>();
+
+ for (int j = 0; j < length; j += 12) {
+ final String dimensionStrValue = binaryChromosome.getStringRepresentation(j, j + 12);
+ coordinates.add(Integer.parseUnsignedInt(dimensionStrValue, 2) / 100d);
+ }
+
+ return new Coordinate(coordinates);
+ }));
+ }
+ return population;
+ }
+}
diff --git a/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/StandAlone.java b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/StandAlone.java
new file mode 100644
index 0000000..97beb7e
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/StandAlone.java
@@ -0,0 +1,78 @@
+/*
+ * 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.parallel.mathfunctions;
+
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+
+@Command(name = "mathfunction-optimizer", mixinStandardHelpOptions = true, version = "mathfunction-optimizer 1.0")
+public class StandAlone implements Runnable {
+
+ /** number of dimension. **/
+ @Option(names = "-d", paramLabel = "DIMENSION", required = true, description = "Dimension of problem domain.")
+ private int dimension;
+
+ /** size of tournament. **/
+ @Option(names = "-t", paramLabel = "TOURNAMENT_SIZE", required = true, description = "Tournament size.")
+ private int tournamentSize;
+
+ /** size of population. **/
+ @Option(names = "-p", paramLabel = "POPULATION_SIZE", required = true, description = "Size of population.")
+ private int populationSize;
+
+ /** number of generations with unchanged best fitness. **/
+ @Option(names = "-g", paramLabel = "GENERATIONS_EVOLVED_WITH_UNCHANGED_BEST_FITNESS",
+ description = "No of generations evolved with unchanged best fitness (default: ${DEFAULT-VALUE}).")
+ private int generationsEvolvedWithUnchangedBestFitness = 50;
+
+ public static void main(String[] args) {
+ CommandLine.run(new StandAlone(), args);
+ }
+
+ /**
+ * This method is responsible for validating input and then invoking math
+ * function optimizer.
+ */
+ @Override
+ public void run() {
+
+ // validate all input options.
+ validateInput();
+
+ final ParallelMathFunctionOptimizer optimizer = new ParallelMathFunctionOptimizer();
+
+ optimizer.optimize(dimension, tournamentSize, generationsEvolvedWithUnchangedBestFitness, populationSize);
+
+ }
+
+ private void validateInput() {
+ if (this.dimension < 1) {
+ throw new IllegalArgumentException("Dimension should be > 0.");
+ }
+ if (this.tournamentSize < 1) {
+ throw new IllegalArgumentException("Tournament size should be > 0.");
+ }
+ if (populationSize <= 1) {
+ throw new IllegalArgumentException("Population size should be > 1.");
+ }
+ if (generationsEvolvedWithUnchangedBestFitness < 1) {
+ throw new IllegalArgumentException(
+ "Number of generations evolved with unchanged best fitness should be >= 1.");
+ }
+ }
+}
diff --git a/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/package-info.java b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/package-info.java
new file mode 100644
index 0000000..bb65c35
--- /dev/null
+++ b/commons-math-examples/examples-ga/examples-parallel-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/parallel/mathfunctions/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.parallel.mathfunctions;
diff --git a/commons-math-examples/examples-ga/pom.xml b/commons-math-examples/examples-ga/pom.xml
new file mode 100644
index 0000000..462daf2
--- /dev/null
+++ b/commons-math-examples/examples-ga/pom.xml
@@ -0,0 +1,62 @@
+<?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>GA</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-math4-ga</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>info.picocli</groupId>
+ <artifactId>picocli</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <modules>
+ <module>examples-ga-math-functions</module>
+ <module>examples-ga-math-functions-adaptive</module>
+ <module>examples-ga-tsp</module>
+ <module>examples-parallel-ga-math-functions</module>
+ </modules>
+
+</project>
diff --git a/commons-math-examples/examples-ga/src/main/resources/spotbugs/spotbugs-exclude-filter.xml b/commons-math-examples/examples-ga/src/main/resources/spotbugs/spotbugs-exclude-filter.xml
new file mode 100644
index 0000000..3de6902
--- /dev/null
+++ b/commons-math-examples/examples-ga/src/main/resources/spotbugs/spotbugs-exclude-filter.xml
@@ -0,0 +1,60 @@
+<?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.
+-->
+
+<!--
+ This file contains some false positive bugs detected by spotbugs. Their
+ false positive nature has been analyzed individually and they have been
+ put here to instruct spotbugs it must ignore them.
+-->
+<FindBugsFilter
+ xmlns="https://github.com/spotbugs/filter/3.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
+
+ <Match>
+ <Class name="~.*\.jmh\..*generated\..*"/>
+ </Match>
+
+ <!-- Deliberately floating-point equality checks. -->
+ <Match>
+ <Class name="org.apache.commons.math4.neuralnet.twod.NeuronSquareMesh2D"/>
+ <Method name="createLinks"/>
+ <BugPattern name="SF_SWITCH_FALLTHROUGH"/>
+ </Match>
+ <Match>
+ <!-- The constant is inlined resulting in a dead-local-store error -->
+ <Class name="org.apache.commons.math4.core.jdkmath.AccurateMath"/>
+ <Method name="atan"/>
+ <BugPattern name="DLS_DEAD_LOCAL_STORE"/>
+ </Match>
+ <Match>
+ <!-- The constant is intentionally close to but not exactly pi/2 -->
+ <Class name="org.apache.commons.math4.core.jdkmath.AccurateMath$CodyWaite"/>
+ <BugPattern name="CNT_ROUGH_CONSTANT_VALUE"/>
+ </Match>
+
+ <!-- Disable checks for exposure of internal references.
+ TODO: Revise this to use more targeted exclusions. -->
+ <Match>
+ <Or>
+ <BugPattern name="EI_EXPOSE_REP"/>
+ <BugPattern name="EI_EXPOSE_REP2"/>
+ </Or>
+ </Match>
+
+</FindBugsFilter>
diff --git a/commons-math-examples/pom.xml b/commons-math-examples/pom.xml
index ccef4d6..c848836 100644
--- a/commons-math-examples/pom.xml
+++ b/commons-math-examples/pom.xml
@@ -52,6 +52,7 @@
<math.rng.version>1.4</math.rng.version>
<math.geometry.version>1.0</math.geometry.version>
<math.imaging.version>1.0-alpha3-SNAPSHOT</math.imaging.version>
+ <math.slf4j.version>1.7.32</math.slf4j.version>
<!-- Disable JApiCmp failures (but keep the report). The examples API is allowed to change. -->
<commons.japicmp.breakBuildOnBinaryIncompatibleModifications>false</commons.japicmp.breakBuildOnBinaryIncompatibleModifications>
@@ -70,6 +71,12 @@
<dependency>
<groupId>org.apache.commons</groupId>
+ <artifactId>commons-math4-ga</artifactId>
+ <version>${math.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
<artifactId>commons-math4-legacy</artifactId>
<version>${math.version}</version>
</dependency>
@@ -104,6 +111,12 @@
<version>${math.picocli.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${math.slf4j.version}</version>
+ </dependency>
+
</dependencies>
</dependencyManagement>
@@ -168,6 +181,7 @@
<modules>
<module>examples-sofm</module>
<module>examples-kmeans</module>
+ <module>examples-ga</module>
</modules>
</project>
diff --git a/commons-math-ga/LICENCE b/commons-math-ga/LICENCE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/commons-math-ga/LICENCE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/commons-math-ga/NOTICE b/commons-math-ga/NOTICE
new file mode 100644
index 0000000..28031e8
--- /dev/null
+++ b/commons-math-ga/NOTICE
@@ -0,0 +1,5 @@
+Apache Commons Math
+Copyright 2001-2022 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/commons-math-ga/pom.xml b/commons-math-ga/pom.xml
new file mode 100644
index 0000000..6669845
--- /dev/null
+++ b/commons-math-ga/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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-math4-ga</artifactId>
+ <name>Genetic Algorithms</name>
+
+ <description>Genetic Algorithms</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>
+ <math.slf4j.version>1.7.32</math.slf4j.version>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-rng-simple</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${math.slf4j.version}</version>
+ </dependency>
+
+ </dependencies>
+
+</project>
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..e06ca7f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/AbstractGeneticAlgorithm.java
@@ -0,0 +1,265 @@
+/*
+ * 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 java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.crossover.CrossoverPolicy;
+import org.apache.commons.math4.ga.listener.ConvergenceListener;
+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;
+
+/**
+ * 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;
+
+ /** The registry for all interested convergence listeners. **/
+ private ConvergenceListenerRegistry<P> convergenceListenerRegistry = new ConvergenceListenerRegistry<>();
+
+ /**
+ * @param crossoverPolicy The {@link CrossoverPolicy}
+ * @param mutationPolicy The {@link MutationPolicy}
+ * @param selectionPolicy The {@link SelectionPolicy}
+ * @param convergenceListeners An optional collection of
+ * {@link ConvergenceListener} with variable arity
+ */
+ @SafeVarargs
+ protected AbstractGeneticAlgorithm(final CrossoverPolicy<P> crossoverPolicy,
+ final MutationPolicy<P> mutationPolicy,
+ final SelectionPolicy<P> selectionPolicy,
+ ConvergenceListener<P>... convergenceListeners) {
+ this.crossoverPolicy = crossoverPolicy;
+ this.mutationPolicy = mutationPolicy;
+ this.selectionPolicy = selectionPolicy;
+ updateListenerRigistry(convergenceListeners);
+ }
+
+ /**
+ * @param crossoverPolicy The {@link CrossoverPolicy}
+ * @param mutationPolicy The {@link MutationPolicy}
+ * @param selectionPolicy The {@link SelectionPolicy}
+ * @param elitismRate The elitism rate
+ * @param convergenceListeners An optional collection of
+ * {@link ConvergenceListener} with variable arity
+ */
+ @SafeVarargs
+ protected AbstractGeneticAlgorithm(final CrossoverPolicy<P> crossoverPolicy,
+ final MutationPolicy<P> mutationPolicy,
+ final SelectionPolicy<P> selectionPolicy,
+ double elitismRate,
+ ConvergenceListener<P>... convergenceListeners) {
+ this.crossoverPolicy = crossoverPolicy;
+ this.mutationPolicy = mutationPolicy;
+ this.selectionPolicy = selectionPolicy;
+ this.elitismRate = elitismRate;
+ updateListenerRigistry(convergenceListeners);
+ }
+
+ // suppressed warnings as the parameter is annotated as @SafeVarargs in
+ // constructor.
+ @SuppressWarnings("unchecked")
+ private void updateListenerRigistry(ConvergenceListener<P>... convergenceListeners) {
+ if (convergenceListeners.length > 0) {
+ for (ConvergenceListener<P> convergenceListener : convergenceListeners) {
+ convergenceListenerRegistry.addConvergenceListener(convergenceListener);
+ }
+ }
+ }
+
+ /**
+ * Returns the crossover policy.
+ * @return crossover policy
+ */
+ protected CrossoverPolicy<P> getCrossoverPolicy() {
+ return crossoverPolicy;
+ }
+
+ /**
+ * Returns the mutation policy.
+ * @return mutation policy
+ */
+ protected MutationPolicy<P> getMutationPolicy() {
+ return mutationPolicy;
+ }
+
+ /**
+ * Returns the selection policy.
+ * @return selection policy
+ */
+ protected SelectionPolicy<P> getSelectionPolicy() {
+ return selectionPolicy;
+ }
+
+ /**
+ * Returns the number of generations evolved to reach {@link StoppingCondition}
+ * in the last run.
+ * @return number of generations evolved
+ */
+ 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.
+ * @param threadCount number of threads for executor service.
+ * @return the population that satisfies the stopping condition.
+ */
+ public Population<P> evolve(final Population<P> initial,
+ final StoppingCondition<P> condition,
+ final int threadCount) {
+ final ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+ try {
+ return evolve(initial, condition, executorService);
+ } finally {
+ executorService.shutdown();
+ }
+ }
+
+ /**
+ * 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.
+ * @param executorService the executor service to run threads.
+ * @return the population that satisfies the stopping condition.
+ */
+ public Population<P> evolve(final Population<P> initial,
+ final StoppingCondition<P> condition,
+ ExecutorService executorService) {
+ 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.notifyAll(generationsEvolved, current);
+
+ current = nextGeneration(current, executorService);
+ 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
+ * @param executorService the executor service to run threads
+ * @return the population for the next generation.
+ */
+ protected abstract Population<P> nextGeneration(Population<P> current, ExecutorService executorService);
+
+ /**
+ * Returns the elitism rate.
+ * @return elitism rate
+ */
+ protected double getElitismRate() {
+ return elitismRate;
+ }
+
+ /**
+ * Responsible for registering the interested listeners and notifying all when
+ * required.
+ * @param <P> phenotype
+ */
+ private class ConvergenceListenerRegistry<P> {
+
+ /**
+ * List of registered listeners.
+ */
+ private final List<ConvergenceListener<P>> listeners = new ArrayList<>();
+
+ /**
+ * Registers the interested ConvergenceListener passed as an argument.
+ * @param convergenceListener The {@link ConvergenceListener}
+ */
+ private void addConvergenceListener(ConvergenceListener<P> convergenceListener) {
+ Objects.requireNonNull(convergenceListener);
+ this.listeners.add(convergenceListener);
+ }
+
+ /**
+ * Notifies all registered ConvergenceListeners about the population statistics.
+ * @param generation current generation
+ * @param population population of chromosomes
+ */
+ private void notifyAll(int generation, Population<P> population) {
+ for (ConvergenceListener<P> convergenceListener : listeners) {
+ convergenceListener.notify(generation, population);
+ }
+ }
+ }
+
+}
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..226e604
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/AdaptiveGeneticAlgorithm.java
@@ -0,0 +1,226 @@
+/*
+ * 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 java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+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.ConstantCrossoverRateGenerator;
+import org.apache.commons.math4.ga.crossover.rategenerator.CrossoverRateGenerator;
+import org.apache.commons.math4.ga.internal.exception.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.internal.stats.PopulationStatisticalSummaryImpl;
+import org.apache.commons.math4.ga.listener.ConvergenceListener;
+import org.apache.commons.math4.ga.mutation.MutationPolicy;
+import org.apache.commons.math4.ga.mutation.rategenerator.ConstantMutationRateGenerator;
+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(AdaptiveGeneticAlgorithm.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
+ * @param convergenceListeners An optional collection of
+ * {@link ConvergenceListener} with
+ * variable arity
+ */
+ @SafeVarargs
+ public AdaptiveGeneticAlgorithm(CrossoverPolicy<P> crossoverPolicy,
+ CrossoverRateGenerator<P> crossoverProbabilityGenerator,
+ MutationPolicy<P> mutationPolicy,
+ MutationRateGenerator<P> mutationProbabilityGenerator,
+ SelectionPolicy<P> selectionPolicy,
+ ConvergenceListener<P>... convergenceListeners) {
+ super(crossoverPolicy, mutationPolicy, selectionPolicy, convergenceListeners);
+ 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
+ * @param convergenceListeners An optional collection of
+ * {@link ConvergenceListener} with
+ * variable arity
+ */
+ @SafeVarargs
+ public AdaptiveGeneticAlgorithm(CrossoverPolicy<P> crossoverPolicy,
+ CrossoverRateGenerator<P> crossoverProbabilityGenerator,
+ MutationPolicy<P> mutationPolicy,
+ MutationRateGenerator<P> mutationProbabilityGenerator,
+ SelectionPolicy<P> selectionPolicy,
+ double elitismRate,
+ ConvergenceListener<P>... convergenceListeners) {
+ super(crossoverPolicy, mutationPolicy, selectionPolicy, elitismRate, convergenceListeners);
+ this.crossoverRateGenerator = crossoverProbabilityGenerator;
+ this.mutationRateGenerator = mutationProbabilityGenerator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Population<P> nextGeneration(final Population<P> current, final ExecutorService executorService) {
+
+ LOGGER.debug("Reproducing next generation.");
+
+ // 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();
+
+ final Population<P> offsprings = reproduceOffsprings(current, executorService,
+ maxOffspringCount);
+
+ LOGGER.debug("Performing adaptive mutation of offsprings.");
+
+ nextGeneration.addChromosomes(mutateChromosomes(executorService, offsprings));
+
+ LOGGER.debug("New Generation: " + System.lineSeparator() + nextGeneration.toString());
+
+ return nextGeneration;
+ }
+
+ private List<Chromosome<P>> mutateChromosomes(final ExecutorService executorService,
+ final Population<P> offspringPopulation) {
+
+ // recompute the statistics of the offspring population.
+ final PopulationStatisticalSummary<P> offspringPopulationStats = ConstantMutationRateGenerator.class
+ .isAssignableFrom(this.mutationRateGenerator.getClass()) ? null :
+ new PopulationStatisticalSummaryImpl<>(offspringPopulation);
+
+ List<Future<Chromosome<P>>> mutatedChromosomes = new ArrayList<>();
+
+ // apply mutation policy to the offspring chromosomes and add the mutated
+ // chromosomes to next generation.
+ for (Chromosome<P> chromosome : offspringPopulation) {
+ mutatedChromosomes.add(executorService.submit(new Callable<Chromosome<P>>() {
+
+ @Override
+ public Chromosome<P> call() throws Exception {
+ return getMutationPolicy().mutate(chromosome, mutationRateGenerator.generate(chromosome,
+ offspringPopulationStats, getGenerationsEvolved()));
+ }
+ }));
+ }
+ List<Chromosome<P>> mutatedOffsprings = new ArrayList<>();
+ try {
+ for (Future<Chromosome<P>> mutatedChromosome : mutatedChromosomes) {
+ mutatedOffsprings.add(mutatedChromosome.get());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ throw new GeneticIllegalArgumentException(e);
+ }
+
+ return mutatedOffsprings;
+ }
+
+ private Population<P> reproduceOffsprings(final Population<P> current,
+ final ExecutorService executorService,
+ final int maxOffspringCount) {
+ // compute statistics of current generation chromosomes.
+ final PopulationStatisticalSummary<P> currentGenPopulationStats = ConstantCrossoverRateGenerator.class
+ .isAssignableFrom(this.crossoverRateGenerator.getClass()) ? null :
+ new PopulationStatisticalSummaryImpl<>(current);
+ List<Future<ChromosomePair<P>>> chromosomePairs = new ArrayList<>();
+ for (int i = maxOffspringCount / 2; i > 0; i--) {
+ chromosomePairs.add(executorService.submit(() -> {
+ // select parent chromosomes
+ ChromosomePair<P> pair = getSelectionPolicy().select(current);
+ LOGGER.debug("Selected Chromosomes: " + System.lineSeparator() + pair.toString());
+
+ final double crossoverRate = crossoverRateGenerator.generate(pair.getFirst(), pair.getSecond(),
+ currentGenPopulationStats, getGenerationsEvolved());
+ // apply crossover policy to create two offspring
+ pair = getCrossoverPolicy().crossover(pair.getFirst(), pair.getSecond(), crossoverRate);
+ LOGGER.debug("Offsprings after Crossover: " + System.lineSeparator() + pair.toString());
+
+ return pair;
+ }));
+ }
+
+ // Initialize an empty population for offsprings.
+ final Population<P> offspringPopulation = current.nextGeneration(0);
+ try {
+ for (Future<ChromosomePair<P>> chromosomePair : chromosomePairs) {
+ ChromosomePair<P> pair = chromosomePair.get();
+ offspringPopulation.addChromosome(pair.getFirst());
+ offspringPopulation.addChromosome(pair.getSecond());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ throw new GeneticIllegalArgumentException(e);
+ }
+ return offspringPopulation;
+ }
+
+ /**
+ * 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..ef37a88
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/GeneticAlgorithm.java
@@ -0,0 +1,203 @@
+/*
+ * 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 java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.apache.commons.math4.ga.chromosome.ChromosomePair;
+import org.apache.commons.math4.ga.crossover.CrossoverPolicy;
+import org.apache.commons.math4.ga.internal.exception.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.listener.ConvergenceListener;
+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(GeneticAlgorithm.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}
+ * @param convergenceListeners An optional collection of
+ * {@link ConvergenceListener} with variable arity
+ */
+ @SafeVarargs
+ public GeneticAlgorithm(final CrossoverPolicy<P> crossoverPolicy,
+ final double crossoverRate,
+ final MutationPolicy<P> mutationPolicy,
+ final double mutationRate,
+ final SelectionPolicy<P> selectionPolicy,
+ ConvergenceListener<P>... convergenceListeners) {
+ super(crossoverPolicy, mutationPolicy, selectionPolicy, convergenceListeners);
+
+ 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
+ * @param convergenceListeners An optional collection of
+ * {@link ConvergenceListener} with variable arity
+ */
+ @SafeVarargs
+ public GeneticAlgorithm(final CrossoverPolicy<P> crossoverPolicy,
+ final double crossoverRate,
+ final MutationPolicy<P> mutationPolicy,
+ final double mutationRate,
+ final SelectionPolicy<P> selectionPolicy,
+ final double elitismRate,
+ ConvergenceListener<P>... convergenceListeners) {
+ super(crossoverPolicy, mutationPolicy, selectionPolicy, elitismRate, convergenceListeners);
+
+ 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.OUT_OF_RANGE, crossoverRateInput,
+ CROSSOVER_RATE, 0, 1);
+ }
+ if (inputMutationRate < 0 || inputMutationRate > 1) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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, ExecutorService executorService) {
+
+ LOGGER.debug("Reproducing next generation.");
+ final Population<P> nextGeneration = current.nextGeneration(getElitismRate());
+ List<Future<ChromosomePair<P>>> chromosomePairs = new ArrayList<>();
+
+ int maxOffspringCount = nextGeneration.getPopulationLimit() - nextGeneration.getPopulationSize();
+
+ for (int i = maxOffspringCount / 2; i > 0; i--) {
+
+ chromosomePairs.add(executorService.submit(() -> {
+ // select parent chromosomes
+ ChromosomePair<P> pair = getSelectionPolicy().select(current);
+ LOGGER.debug("Selected Chromosomes: " + System.lineSeparator() + pair.toString());
+
+ // apply crossover policy to create two offspring
+ pair = getCrossoverPolicy().crossover(pair.getFirst(), pair.getSecond(), crossoverRate);
+ LOGGER.debug("Offsprings after Crossover: " + System.lineSeparator() + 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: " + System.lineSeparator() + pair.toString());
+
+ return pair;
+ }));
+ }
+
+ try {
+ for (Future<ChromosomePair<P>> chromosomePair : chromosomePairs) {
+ ChromosomePair<P> pair = chromosomePair.get();
+ nextGeneration.addChromosome(pair.getFirst());
+ nextGeneration.addChromosome(pair.getSecond());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ throw new GeneticIllegalArgumentException(e);
+ }
+ LOGGER.debug("New Generation :" + System.lineSeparator() + 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/ParallelGeneticAlgorithm.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/ParallelGeneticAlgorithm.java
new file mode 100644
index 0000000..c546351
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/ParallelGeneticAlgorithm.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;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.apache.commons.math4.ga.convergence.StoppingCondition;
+import org.apache.commons.math4.ga.internal.exception.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.population.Population;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of parallel genetic algorithm following island model. Few
+ * independently generated populations are converged by separate algorithms in
+ * parallel. All genetic operators and convergent conditions can be chosen
+ * independently for each algorithm. After convergence the algorithm returns the
+ * list of converged populations.
+ * @param <P> chromosome phenotype
+ */
+public class ParallelGeneticAlgorithm<P> {
+
+ /** instance of logger. **/
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParallelGeneticAlgorithm.class);
+
+ /** List of algorithm execution configurations to be executed in parallel. **/
+ private List<AlgorithmExecutionConfig> algorithmConfigParams = new ArrayList<>();
+
+ /**
+ * Adds an instance of Genetic algorithm to be executed in parallel.
+ * @param algorithm the algorithm for optimization
+ * @param initialPopulation initial population to converge
+ * @param stoppingCondition stopping condition for deciding the convergence
+ */
+ public void addAlgorithmExecutionConfig(AbstractGeneticAlgorithm<P> algorithm,
+ Population<P> initialPopulation,
+ StoppingCondition<P> stoppingCondition) {
+ LOGGER.info("Adding a GA optimizer instance.");
+ this.algorithmConfigParams.add(new AlgorithmExecutionConfig(algorithm, initialPopulation, stoppingCondition));
+ }
+
+ /**
+ * Evolve the given population. Evolution stops when the stopping condition is
+ * satisfied.
+ * @param threadCount number of threads to be used in executor service.
+ * @return the population that satisfies the stopping condition.
+ */
+ public List<Population<P>> evolve(int threadCount) {
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+ try {
+ return evolve(executorService);
+ } finally {
+ executorService.shutdown();
+ }
+ }
+
+ /**
+ * 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 executorService the executor service to run threads.
+ * @return the population that satisfies the stopping condition.
+ */
+ private List<Population<P>> evolve(ExecutorService executorService) {
+ List<Future<Population<P>>> futureConvergedPopulations = new ArrayList<>();
+ for (AlgorithmExecutionConfig algorithmConfigParam : algorithmConfigParams) {
+ futureConvergedPopulations.add(executorService.submit(() -> {
+ return algorithmConfigParam.algorithm.evolve(algorithmConfigParam.initialPopulation,
+ algorithmConfigParam.stoppingCondition, executorService);
+ }));
+ }
+
+ List<Population<P>> convergedPopulations = new ArrayList<>();
+ try {
+ for (Future<Population<P>> future : futureConvergedPopulations) {
+ convergedPopulations.add(future.get());
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ throw new GeneticIllegalArgumentException(e);
+ }
+
+ return convergedPopulations;
+ }
+
+ private final class AlgorithmExecutionConfig {
+
+ /** instance of genetic algorithm. **/
+ private AbstractGeneticAlgorithm<P> algorithm;
+
+ /** initial population to converge. **/
+ private Population<P> initialPopulation;
+
+ /** stopping condition to decide convergence. **/
+ private StoppingCondition<P> stoppingCondition;
+
+ private AlgorithmExecutionConfig(AbstractGeneticAlgorithm<P> algorithm,
+ Population<P> initialPopulation,
+ StoppingCondition<P> stoppingCondition) {
+ this.algorithm = algorithm;
+ this.initialPopulation = initialPopulation;
+ this.stoppingCondition = stoppingCondition;
+ }
+
+ }
+
+}
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..ccb8ed5
--- /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 the fitness function
+ */
+ protected FitnessFunction<P> getFitnessFunction() {
+ return fitnessFunction;
+ }
+
+ /**
+ * Returns the decoder instance.
+ * @return the 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 chromosome 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..a0e873d
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/chromosome/AbstractListChromosome.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math4.ga.chromosome;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.commons.math4.ga.decoder.AbstractListChromosomeDecoder;
+import org.apache.commons.math4.ga.fitness.FitnessFunction;
+
+/**
+ * An abstract list 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 chromosome 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..210b7f0
--- /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.GeneticIllegalArgumentException;
+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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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
+ */
+ private void checkMaximumLength(long chromosomeLength) {
+ if (chromosomeLength > MAX_LENGTH) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 chromosome length
+ */
+ public long getLength() {
+ return length;
+ }
+
+ /**
+ * Returns the binary representation.
+ * @return chromosome 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.ILLEGAL_ARGUMENT,
+ "start " + start + " is greater than end " + end);
+ }
+ if (end > length) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.ILLEGAL_ARGUMENT,
+ "end " + end + " is greater than length " + length);
+ }
+ 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 zero 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 new instance of 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..91d598b
--- /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 chromosome 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..51f9f91
--- /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.GeneticIllegalArgumentException;
+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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.TOO_LARGE, min, max);
+ }
+ for (int i : getRepresentation()) {
+ if (i < min || i >= max) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..4b1f067
--- /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.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.utils.ChromosomeRepresentationUtils;
+
+/**
+ * A chromosome representation encoded with real values as allele/gene. 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.TOO_LARGE, min, max);
+ }
+ for (double i : getRepresentation()) {
+ if (i < min || i >= max) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..be98071
--- /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.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Stops convergence process 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..a80e049
--- /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.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.population.Population;
+
+/**
+ * Stops convergence process 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..56d9655
--- /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;
+
+/**
+ * An implementation of 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..25bacc9
--- /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;
+
+/**
+ * An implementation of 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..027efb4
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractChromosomeCrossoverPolicy.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.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 of base crossover policy. Checks the crossoverRate and decides
+ * whether to proceed for crossover or not based on a generated random number
+ * and invokes {@link #crossover(Chromosome, Chromosome)} operation accordingly.
+ * @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..261a51f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/AbstractListChromosomeCrossoverPolicy.java
@@ -0,0 +1,79 @@
+/*
+ * 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.GeneticIllegalArgumentException;
+
+/**
+ * An abstraction of crossover policy for {@link AbstractListChromosome}.
+ * Validates input chromosomes and invoke the
+ * {@link #mate(AbstractListChromosome, AbstractListChromosome)} operation.
+ * @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")
+ private void checkValidity(final Chromosome<P> first, final Chromosome<P> second) {
+ if (!(first instanceof AbstractListChromosome<?, ?> && second instanceof AbstractListChromosome<?, ?>)) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..ff4bf34
--- /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..24154213
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/NPointCrossover.java
@@ -0,0 +1,156 @@
+/*
+ * 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.GeneticIllegalArgumentException;
+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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..11babc0
--- /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.GeneticIllegalArgumentException;
+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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..c53180f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/OrderedCrossover.java
@@ -0,0 +1,130 @@
+/*
+ * 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..bb0f07f
--- /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.GeneticIllegalArgumentException;
+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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..52d84a4
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/ConstantCrossoverRateGenerator.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+/**
+ * An implementation of crossover rate generator which provides configured
+ * constant crossover rate.
+ * @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..3b5a400
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/crossover/rategenerator/CrossoverRateGenerator.java
@@ -0,0 +1,43 @@
+/*
+ * 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 input chromosomes, population statistics
+ * and number of generations evolved.
+ * @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..7836508
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/AbstractListChromosomeDecoder.java
@@ -0,0 +1,61 @@
+/*
+ * 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.GeneticIllegalArgumentException;
+
+/**
+ * An abstract Decoder for {@link AbstractListChromosome}.
+ * @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) {
+ // check for validity
+ checkValidity(chromosome);
+
+ return decode((AbstractListChromosome<T, P>) chromosome);
+ }
+
+ /**
+ * Checks validity of {@link Chromosome}.
+ * @param chromosome the {@link Chromosome}
+ */
+ private void checkValidity(Chromosome<P> chromosome) {
+ if (!AbstractListChromosome.class.isAssignableFrom(chromosome.getClass())) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..3055236
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/Decoder.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.decoder;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+
+/**
+ * An abstraction of chromosome decoder. Converts chromosome's 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..807c1f5
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/decoder/RandomKeyDecoder.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.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.GeneticIllegalArgumentException;
+
+/**
+ * A concrete implementation of {@link AbstractListChromosomeDecoder}. Decodes
+ * 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..8e0ffb6
--- /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;
+
+/**
+ * An implementation of transparent decoder for {@link AbstractListChromosome}.
+ * Treats the genotype same 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..991e8a2
--- /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;
+
+/**
+ * An abstraction of 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/GeneticIllegalArgumentException.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/exception/GeneticIllegalArgumentException.java
new file mode 100644
index 0000000..67feb76
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/exception/GeneticIllegalArgumentException.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;
+
+/**
+ * Exception class with constants for frequently used messages.
+ * @since 4.0
+ */
+public class GeneticIllegalArgumentException extends IllegalArgumentException {
+
+ /** 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 GeneticIllegalArgumentException(String message, Object... formatArguments) {
+ super(MessageFormat.format(message, formatArguments));
+ }
+
+ /**
+ * Create an exception.
+ * @param t instance of {@link Throwable}
+ */
+ public GeneticIllegalArgumentException(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 GeneticIllegalArgumentException(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..e83c864
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/internal/stats/PopulationStatisticalSummaryImpl.java
@@ -0,0 +1,178 @@
+/*
+ * 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;
+
+/**
+ * An implementation of statistical summary for chromosome's fitness in
+ * population.
+ * @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..080f16a
--- /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;
+
+/**
+ * Notified about population statistics and generations evolved to perform
+ * necessary activity.
+ * @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/PopulationStatisticsLogger.java b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/listener/PopulationStatisticsLogger.java
new file mode 100644
index 0000000..bf18124
--- /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 once notified.
+ * @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 {} ::: Mean Fitness: {}, Max Fitness: {}, Fitness Variance: {}",
+ 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..3a80f68
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/AbstractListChromosomeMutationPolicy.java
@@ -0,0 +1,109 @@
+/*
+ * 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.internal.exception.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+import org.apache.commons.rng.UniformRandomProvider;
+
+/**
+ * An abstraction of mutation operator for {@link AbstractListChromosome}.
+ * @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 based on mutation rate. Checks chromosome
+ * validity and finds the mutable gene indexes. For each selected gene invokes
+ * {@link #mutateGene(Object)} to perform mutation.
+ * @param original the original chromosome.
+ * @param mutationRate the rate of mutation per gene
+ * @return the mutated chromosome.
+ */
+ @Override
+ public AbstractListChromosome<T, 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);
+ }
+
+ /**
+ * Validates input chromosome.
+ * @param original chromosome
+ */
+ private void checkValidity(Chromosome<P> original) {
+ if (!AbstractListChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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
+ */
+ private 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..c6582f6
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/BinaryMutation.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math4.ga.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.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * Mutation operator 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 BinaryChromosome<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;
+ }
+
+ return chromosome.newChromosome(newRep, chromosome.getLength());
+ }
+
+ /**
+ * Checks input chromosome validity.
+ * @param original chromosome to be mutated
+ */
+ private void checkValidity(Chromosome<P> original) {
+ if (!BinaryChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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
+ */
+ private 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..f0952c7
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/IntegralValuedMutation.java
@@ -0,0 +1,111 @@
+/*
+ * 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.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * Mutation operator for {@link IntegralValuedChromosome}. Randomly changes few
+ * gene's value with random values chosen between specified min and max.
+ * @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(exclusive) value of allele
+ */
+ public IntegralValuedMutation(final int min, final int max) {
+ this.min = min;
+ this.max = max;
+
+ // To perform mutation for an IntegralValuedChromosome the minimum difference
+ // between
+ // max and min should be 2.
+ if ((max - min) < 2) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.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
+ public IntegralValuedChromosome<P> mutate(Chromosome<P> original, double mutationRate) {
+ // check for validity
+ checkValidity(original);
+
+ return (IntegralValuedChromosome<P>) super.mutate(original, mutationRate);
+ }
+
+ /**
+ * This method validates input chromosome.
+ * @param original chromosome
+ */
+ private void checkValidity(Chromosome<P> original) {
+ if (!IntegralValuedChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.ILLEGAL_ARGUMENT,
+ original.getClass().getSimpleName());
+ }
+ final IntegralValuedChromosome<P> chromosome = (IntegralValuedChromosome<P>) original;
+ if (chromosome.getMin() != this.min || chromosome.getMax() != this.max) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.ILLEGAL_RANGE, this.min, this.max,
+ chromosome.getMin(), chromosome.getMax());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Integer mutateGene(Integer originalValue) {
+ Integer mutatedValue = 0;
+ do {
+ mutatedValue = min + RandomProviderManager.getRandomProvider().nextInt(max - min);
+ } while (mutatedValue.equals(originalValue));
+
+ return mutatedValue;
+ }
+
+}
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..c50c5b2
--- /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;
+
+/**
+ * An abstraction of mutation operator for chromosomes.
+ * @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..54d676c
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/RealValuedMutation.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.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.GeneticIllegalArgumentException;
+import org.apache.commons.math4.ga.utils.RandomProviderManager;
+
+/**
+ * Mutation operator for {@link RealValuedChromosome}. Mutates the randomly
+ * selected genes with a new random real value chosen within specified min an
+ * max.
+ * @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 exclusive 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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
+ public RealValuedChromosome<P> mutate(Chromosome<P> original, double mutationRate) {
+ // check for validity.
+ checkValidity(original);
+ return (RealValuedChromosome<P>) super.mutate(original, mutationRate);
+ }
+
+ /**
+ * This method validates the input chromosome.
+ * @param original chromosome
+ */
+ private void checkValidity(Chromosome<P> original) {
+ if (!RealValuedChromosome.class.isAssignableFrom(original.getClass())) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.ILLEGAL_ARGUMENT,
+ original.getClass().getSimpleName());
+ }
+ final RealValuedChromosome<P> chromosome = (RealValuedChromosome<P>) original;
+ if (chromosome.getMin() != this.min || chromosome.getMax() != this.max) {
+ throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.ILLEGAL_RANGE, this.min, this.max,
+ chromosome.getMin(), chromosome.getMax());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Double mutateGene(Double originalValue) {
+ Double mutatedValue = 0.0;
+ do {
+ mutatedValue = min + RandomProviderManager.getRandomProvider().nextDouble() * (max - min);
+ } while (mutatedValue.equals(originalValue));
+
+ return mutatedValue;
+ }
+
+}
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..ad1739b
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/mutation/rategenerator/ConstantMutationRateGenerator.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.mutation.rategenerator;
+
+import org.apache.commons.math4.ga.chromosome.Chromosome;
+import org.apache.commons.math4.ga.stats.PopulationStatisticalSummary;
+
+/**
+ * An implementation of mutation rate generator which provides a configured
+ * constant mutation rate.
+ * @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..006cc4f
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/ListPopulation.java
@@ -0,0 +1,222 @@
+/*
+ * 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.GeneticIllegalArgumentException;
+
+/**
+ * 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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.NOT_STRICTLY_POSITIVE,
+ populationLimit);
+ }
+ if (chromosomes.size() > populationLimit) {
+ throw new GeneticIllegalArgumentException(
+ GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(
+ GeneticIllegalArgumentException.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);
+ }
+
+ /**
+ * 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 GeneticIllegalArgumentException(
+ GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.POPULATION_LIMIT_NOT_POSITIVE,
+ populationLimit);
+ }
+ if (populationLimit < chromosomes.size()) {
+ throw new GeneticIllegalArgumentException(
+ GeneticIllegalArgumentException.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 = this.chromosomes;
+
+ 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;
+ }
+ }
+
+// @Override
+// public void addChromosomes(List<Chromosome<P>> chromosomes) {
+// this.chromosomes.addAll(chromosomes);
+// }
+
+}
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..e6db1e6
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/population/Population.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.population;
+
+import java.util.Collection;
+
+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);
+
+ /**
+ * Add the given chromosomes to the population.
+ * @param chromosomes the chromosomes to add.
+ */
+ void addChromosomes(Collection<Chromosome<P>> chromosomes);
+
+ /**
+ * 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..afaf795
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/selection/TournamentSelection.java
@@ -0,0 +1,109 @@
+/*
+ * 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.GeneticIllegalArgumentException;
+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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..731a108
--- /dev/null
+++ b/commons-math-ga/src/main/java/org/apache/commons/math4/ga/utils/ChromosomeRepresentationUtils.java
@@ -0,0 +1,213 @@
+/*
+ * 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.GeneticIllegalArgumentException;
+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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(
+ GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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 GeneticIllegalArgumentException(GeneticIllegalArgumentException.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..2876b8f
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestBinaryOneMax.java
@@ -0,0 +1,162 @@
+/*
+ * 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.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.GeneticIllegalArgumentException;
+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() {
+
+ // 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,
+ Runtime.getRuntime().availableProcessors());
+
+ // 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());
+
+ }
+
+ /**
+ * 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(GeneticIllegalArgumentException.class, () -> {
+ new GeneticAlgorithm<>(new OnePointCrossover<>(), 1.5, new BinaryMutation<>(), .01,
+ new TournamentSelection<>(10));
+ });
+ }
+
+ @Test
+ public void testMutationRate() {
+ Assertions.assertThrows(GeneticIllegalArgumentException.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..72ad0a7
--- /dev/null
+++ b/commons-math-ga/src/test/java/org/apache/commons/math4/ga/GeneticAlgorithmTestPermutations.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.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,
+ Runtime.getRuntime().availableProcessors());
+
+ // 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));
... 2825 lines suppressed ...