MATH-1563: Introducing new implementation of GA functionality (WIP).

Closes #209.
This commit is contained in:
avijit-basak 2022-04-08 12:36:43 +05:30 committed by Gilles Sadowski
parent 99ca991984
commit efcd557a6d
29 changed files with 36 additions and 152 deletions

View File

@ -76,7 +76,15 @@ public final class TSPOptimizer {
final RealValuedChromosome<List<City>> bestFinal = (RealValuedChromosome<List<City>>) finalPopulation
.getFittestChromosome();
logger.info(bestFinal.decode().toString());
StringBuilder schedule = new StringBuilder();
schedule.append("Travel Shcedule: " + System.lineSeparator());
List<City> bestCities = bestFinal.decode();
for (City city : bestCities) {
schedule.append("City - " + city.getIndex() + System.lineSeparator());
}
schedule.append("Total distance - " + Math.abs(bestFinal.evaluate()));
logger.info(schedule.toString());
}
private static Population<List<City>> getInitialPopulation(List<City> cities, int populationSize) {
@ -87,12 +95,9 @@ public final class TSPOptimizer {
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));
totalDistance += distanceMatrix.getDistance(decodedChromosome.get(j),
decodedChromosome.get((j == cities.size() - 1) ? 0 : j + 1));
}
return -totalDistance;
}, new RandomKeyDecoder<City>(cities)));

View File

@ -27,12 +27,18 @@ 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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class represents the tsp optimizer based on legacy implementation of
* Genetic Algorithm.
*/
public class LegacyTSPOptimizer {
/** instance of logger. **/
private final Logger logger = LoggerFactory.getLogger(LegacyTSPOptimizer.class);
/**
* Optimizes the TSP problem.
* @param cities list of cities
@ -67,9 +73,13 @@ public class LegacyTSPOptimizer {
@SuppressWarnings("unchecked")
final RandomKey<City> bestFinal = (RandomKey<City>) finalPopulation.getFittestChromosome();
//CHECKSTYLE: stop all
System.out.println("best=" + bestFinal.toString());
//CHECKSTYLE: resume all
StringBuilder schedule = new StringBuilder("Travel Shcedule: " + System.lineSeparator());
List<City> bestCities = bestFinal.decode(cities);
for (City city : bestCities) {
schedule.append("City - " + city.getIndex() + System.lineSeparator());
}
schedule.append("Total distance - " + Math.abs(bestFinal.fitness()));
logger.info(schedule.toString());
}
private static Population getInitialPopulation(List<City> cities, int populationSize, double elitismRate) {

View File

@ -42,46 +42,22 @@ 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 elitism rate having default value of .25. */
private final double elitismRate;
/**
* 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. **/
/** 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}
@ -100,13 +76,7 @@ public abstract class AbstractGeneticAlgorithm<P> {
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);

View File

@ -53,35 +53,11 @@ 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
@ -123,8 +99,7 @@ public class AdaptiveGeneticAlgorithm<P> extends AbstractGeneticAlgorithm<P> {
final int maxOffspringCount = nextGeneration.getPopulationLimit() - nextGeneration.getPopulationSize();
final Population<P> offsprings = reproduceOffsprings(current, executorService,
maxOffspringCount);
final Population<P> offsprings = reproduceOffsprings(current, executorService, maxOffspringCount);
LOGGER.debug("Performing adaptive mutation of offsprings.");
@ -139,9 +114,10 @@ public class AdaptiveGeneticAlgorithm<P> extends AbstractGeneticAlgorithm<P> {
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);
final PopulationStatisticalSummary<P> offspringPopulationStats =
mutationRateGenerator instanceof ConstantMutationRateGenerator ?
null :
new PopulationStatisticalSummaryImpl<>(offspringPopulation);
List<Future<Chromosome<P>>> mutatedChromosomes = new ArrayList<>();

View File

@ -43,44 +43,15 @@ 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}

View File

@ -42,7 +42,6 @@ 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<>();
@ -99,7 +98,6 @@ public class ParallelGeneticAlgorithm<P> {
} catch (InterruptedException | ExecutionException e) {
throw new GeneticIllegalArgumentException(e);
}
return convergedPopulations;
}
@ -107,10 +105,8 @@ public class ParallelGeneticAlgorithm<P> {
/** 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;
@ -121,7 +117,5 @@ public class ParallelGeneticAlgorithm<P> {
this.initialPopulation = initialPopulation;
this.stoppingCondition = stoppingCondition;
}
}
}

View File

@ -36,16 +36,12 @@ 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;

View File

@ -35,12 +35,10 @@ 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.
*/

View File

@ -25,7 +25,6 @@ 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;

View File

@ -33,7 +33,6 @@ public class IntegralValuedChromosome<P> extends AbstractListChromosome<Integer,
/** minimum acceptable value of allele. **/
private final int min;
/** maximum acceptable value of allele. **/
private final int max;

View File

@ -36,7 +36,6 @@ 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;

View File

@ -36,7 +36,6 @@ 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;
@ -73,7 +72,6 @@ public class FixedElapsedTime<P> implements StoppingCondition<P> {
if (endTime < 0) {
endTime = System.nanoTime() + maxTimePeriod;
}
return System.nanoTime() >= endTime;
}

View File

@ -30,9 +30,9 @@ import org.apache.commons.math4.ga.population.Population;
* @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;

View File

@ -30,13 +30,11 @@ 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;

View File

@ -31,13 +31,11 @@ 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;
@ -66,7 +64,6 @@ public class UnchangedMeanFitness<P> implements StoppingCondition<P> {
this.generationsHavingUnchangedMeanFitness = 0;
lastMeanFitness = currentMeanFitness;
}
return false;
}

View File

@ -65,7 +65,6 @@ public abstract class AbstractListChromosomeCrossoverPolicy<T, P> extends Abstra
throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.SIZE_MISMATCH,
secondListChromosome.getLength(), length);
}
}
/**

View File

@ -29,7 +29,6 @@ public class AdaptiveLinearAverageRankBasedCrossoverRateGenerator<P> implements
/** minimum crossover rate. **/
private final double minimumRate;
/** maximum crossover rate. **/
private final double maximumRate;
@ -54,5 +53,4 @@ public class AdaptiveLinearAverageRankBasedCrossoverRateGenerator<P> implements
return minimumRate +
(maximumRate - minimumRate) * (1.0 - (double) averageRank / (populationStats.getPopulationSize() - 1));
}
}

View File

@ -29,7 +29,6 @@ public class AdaptiveLinearMaximumRankBasedCrossoverRateGenerator<P> implements
/** minimum crossover rate. **/
private final double minimumRate;
/** maximum crossover rate. **/
private final double maximumRate;

View File

@ -37,19 +37,14 @@ public class PopulationStatisticalSummaryImpl<P> implements PopulationStatistica
/** 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<>();

View File

@ -45,5 +45,4 @@ public final class PopulationStatisticsLogger<P> implements ConvergenceListener<
generation, populationStatisticalSummary.getMeanFitness(), populationStatisticalSummary.getMaxFitness(),
populationStatisticalSummary.getFitnessVariance());
}
}

View File

@ -95,7 +95,6 @@ public abstract class AbstractListChromosomeMutationPolicy<T, P> implements Muta
} else if (randomProvider.nextDouble() < chromosomeMutationRate) {
indexSet.add(randomProvider.nextInt(length));
}
return indexSet;
}

View File

@ -31,7 +31,6 @@ public class IntegralValuedMutation<P> extends AbstractListChromosomeMutationPol
/** minimum acceptable value of allele. **/
private final int min;
/** maximum acceptable value of allele. **/
private final int max;

View File

@ -32,7 +32,6 @@ public class RealValuedMutation<P> extends AbstractListChromosomeMutationPolicy<
/** minimum value of chromosome gene/allele. **/
private final double min;
/** maximum exclusive value of chromosome gene/allele. **/
private final double max;

View File

@ -29,7 +29,6 @@ public class AdaptiveLinearMutationRateGenerator<P> implements MutationRateGener
/** minimum crossover rate. **/
private final double minimumRate;
/** maximum crossover rate. **/
private final double maximumRate;
@ -50,5 +49,4 @@ public class AdaptiveLinearMutationRateGenerator<P> implements MutationRateGener
return minimumRate + (maximumRate - minimumRate) *
(1.0 - (double) populationStats.findRank(chromosome) / (populationStats.getPopulationSize() - 1));
}
}

View File

@ -44,5 +44,4 @@ public class ConstantMutationRateGenerator<P> implements MutationRateGenerator<P
public double generate(Chromosome<P> chromosome, PopulationStatisticalSummary<P> populationStats, int generation) {
return mutationRate;
}
}

View File

@ -36,10 +36,8 @@ 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;
@ -213,10 +211,4 @@ public class ListPopulation<P> implements Population<P> {
return nextGeneration;
}
}
// @Override
// public void addChromosomes(List<Chromosome<P>> chromosomes) {
// this.chromosomes.addAll(chromosomes);
// }
}

View File

@ -105,5 +105,4 @@ public class TournamentSelection<P> implements SelectionPolicy<P> {
public int getArity() {
return arity;
}
}

View File

@ -43,5 +43,4 @@ public final class RandomProviderManager {
public static UniformRandomProvider getRandomProvider() {
return ThreadLocalRandomSource.current(RandomProviderManager.randomSource);
}
}

View File

@ -56,7 +56,7 @@ public class GeneticAlgorithmTestBinaryOneMax {
// 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));
new TournamentSelection<List<Integer>>(TOURNAMENT_ARITY), .25);
Assertions.assertEquals(0, ga.getGenerationsEvolved());
@ -147,7 +147,7 @@ public class GeneticAlgorithmTestBinaryOneMax {
public void testCrossoverRate() {
Assertions.assertThrows(GeneticIllegalArgumentException.class, () -> {
new GeneticAlgorithm<>(new OnePointCrossover<>(), 1.5, new BinaryMutation<>(), .01,
new TournamentSelection<>(10));
new TournamentSelection<>(10), .25);
});
}
@ -155,7 +155,7 @@ public class GeneticAlgorithmTestBinaryOneMax {
public void testMutationRate() {
Assertions.assertThrows(GeneticIllegalArgumentException.class, () -> {
new GeneticAlgorithm<>(new OnePointCrossover<>(), .5, new BinaryMutation<>(), 1.5,
new TournamentSelection<>(10));
new TournamentSelection<>(10), .25);
});
}