Skip to content

Commit

Permalink
MATH-1563: Introducing new implementation of GA functionality (WIP).
Browse files Browse the repository at this point in the history
Closes #209.
  • Loading branch information
avijit-basak authored and Gilles Sadowski committed Apr 11, 2022
1 parent 99ca991 commit efcd557
Show file tree
Hide file tree
Showing 29 changed files with 36 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@ public void optimize(List<City> cities,
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) {
Expand All @@ -87,12 +95,9 @@ private static Population<List<City>> getInitialPopulation(List<City> cities, in
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)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@
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
Expand Down Expand Up @@ -67,9 +73,13 @@ public void optimize(List<City> cities,
@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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -100,13 +76,7 @@ protected AbstractGeneticAlgorithm(final CrossoverPolicy<P> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -123,8 +99,7 @@ protected Population<P> nextGeneration(final Population<P> current, final Execut

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.");

Expand All @@ -139,9 +114,10 @@ private List<Chromosome<P>> mutateChromosomes(final ExecutorService executorServ
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<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<>();

Expand Down Expand Up @@ -99,18 +98,15 @@ private List<Population<P>> evolve(ExecutorService executorService) {
} 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;

Expand All @@ -121,7 +117,5 @@ private AlgorithmExecutionConfig(AbstractGeneticAlgorithm<P> algorithm,
this.initialPopulation = initialPopulation;
this.stoppingCondition = stoppingCondition;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -73,7 +72,6 @@ public boolean isSatisfied(Population<P> population) {
if (endTime < 0) {
endTime = System.nanoTime() + maxTimePeriod;
}

return System.nanoTime() >= endTime;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
* @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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -66,7 +64,6 @@ public boolean isSatisfied(Population<P> population) {
this.generationsHavingUnchangedMeanFitness = 0;
lastMeanFitness = currentMeanFitness;
}

return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ private void checkValidity(final Chromosome<P> first, final Chromosome<P> second
throw new GeneticIllegalArgumentException(GeneticIllegalArgumentException.SIZE_MISMATCH,
secondListChromosome.getLength(), length);
}

}

/**
Expand Down
Loading

0 comments on commit efcd557

Please sign in to comment.