MATH-1618: Replace class "OnePointCrossover" with "NPointCrossover".

The former is a particular case of the latter.
This commit is contained in:
Gilles Sadowski 2022-06-10 10:06:25 +02:00
parent 3c30a6d520
commit f0fe9ab8eb
3 changed files with 65 additions and 31 deletions

View File

@ -129,7 +129,7 @@ public final class MathFunctionOptimizer2 {
// Offspring generators.
final Map<GeneticOperator<Chromosome>, ApplicationRate> operators = new HashMap<>();
operators.put(Operators.mutation(mutation), RateGenerators.constant(1));
operators.put(Operators.onePointCrossover(), RateGenerators.constant(crossover));
operators.put(Operators.nPointCrossover(1), RateGenerators.constant(crossover));
final Callable<Population<Chromosome, Coordinates>> ga =
GeneticAlgorithmFactory.<Chromosome, Coordinates>create(numGenes,
@ -145,14 +145,12 @@ public final class MathFunctionOptimizer2 {
new GenerationLogger());
try {
// Run the GA and retrieve contents of the last generation.
final List<Map.Entry<Chromosome, Double>> lastGen = ga.call().contents(true);
final Map.Entry<Chromosome, Double> top = lastGen.get(0);
final Coordinates best = decoder.apply(top.getKey());
final double bestValue = fitnessFunction.applyAsDouble(best);
// Run the GA and retrieve the best individual from the last generation.
final Map.Entry<Chromosome, Double> best = ga.call().contents(true).get(0);
// CHECKSTYLE: stop all
System.out.println("fitness=" + bestValue + " for " + best.toString());
System.out.println("fitness=" + best.getValue() +
" for " + decoder.apply(best.getKey()).toString());
// CHECKSTYLE: resume all
} catch (Exception e) {
// Rethrow.

View File

@ -27,7 +27,21 @@ import org.apache.commons.math4.ga2.AbstractCrossover;
* Genetic operator.
* Class is immutable.
*/
/* package-private */ class OnePointCrossover extends AbstractCrossover<Chromosome> {
/* package-private */ class NPointCrossover extends AbstractCrossover<Chromosome> {
/** Number of crossover points. */
private final int numberOfPoints;
/**
* @param n Number of crossover points.
*/
NPointCrossover(int n) {
if (n <= 0) {
throw new IllegalArgumentException("Not strictly positive: " + n);
}
numberOfPoints = n;
}
/** {@inheritDoc} */
@Override
protected List<Chromosome> apply(Chromosome parent1,
@ -40,36 +54,57 @@ import org.apache.commons.math4.ga2.AbstractCrossover;
parent2.size());
}
// Index of crossover point.
final int xIndex = 1 + rng.nextInt(size - 1);
final BitSet p1 = parent1.asBitSet();
final BitSet p2 = parent2.asBitSet();
final BitSet c1;
final BitSet c2;
final BitSet c1 = parent1.asBitSet();
final BitSet c2 = parent2.asBitSet();
final int midIndex = size / 2;
if (xIndex > midIndex) {
c1 = parent1.asBitSet();
c2 = parent2.asBitSet();
// Number or remaining crossover points.
int remainingPoints = numberOfPoints;
// Index of crossover end point.
int xEnd = 0;
while (remainingPoints > 0) {
// Index of crossover start point.
final int xStart = xEnd + 1 + rng.nextInt(size - xEnd - remainingPoints);
for (int i = xIndex; i < size; i++) {
c1.set(i, p2.get(i));
c2.set(i, p1.get(i));
}
if (--remainingPoints > 0) {
xEnd = xStart + 1 + rng.nextInt(size - xStart - remainingPoints);
swap(c1, c2, xStart, xEnd);
--remainingPoints;
} else {
c1 = parent2.asBitSet();
c2 = parent1.asBitSet();
for (int i = 0; i < xIndex; i++) {
c1.set(i, p1.get(i));
c2.set(i, p2.get(i));
xEnd = xStart;
break;
}
}
if (numberOfPoints % 2 != 0) {
swap(c1, c2, xEnd, size);
}
final List<Chromosome> offsprings = new ArrayList<>(2);
offsprings.add(Chromosome.from(c1, size));
offsprings.add(Chromosome.from(c2, size));
return offsprings;
}
/**
* Swaps contents (in-place) within the given range.
*
* @param a Chromosome.
* @param b Chromosome.
* @param start Index from which contents should be swapped.
* @param end Index at which swapping should stop.
*/
private void swap(BitSet a,
BitSet b,
int start,
int end) {
for (int i = start; i < end; i++) {
final boolean aV = a.get(i);
final boolean bV = b.get(i);
a.set(i, bV);
b.set(i, aV);
}
}
}

View File

@ -35,9 +35,10 @@ public final class Operators {
return new Mutation(probability);
}
/**
* @return a one-point crossover operator.
* @param n Number of crossover points.
* @return an n-point crossover operator.
*/
public static GeneticOperator<Chromosome> onePointCrossover() {
return new OnePointCrossover();
public static GeneticOperator<Chromosome> nPointCrossover(int n) {
return new NPointCrossover(n);
}
}