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 &lt;
+     * <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}
+ * &lt; {@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 ...