Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wants to merge 10 commits into
base: feature__MATH-1563__genetic_algorithm
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,29 @@
* 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,
/**
* Optimizes the population.
* @param dimension problem dimension
* @param minCrossoverRate minimum crossover rate
* @param maxCrossoverRate maximum crossover rate
* @param minMutationRate minimum mutation rate
* @param maxMutationRate maximum mutation rate
* @param elitismRate elitism rate
* @param tournamentSize tournament size for tournament
* selection
* @param generationCountWithUnchangedBestFitness number of generation to be
* evolved with best unchanged
* fitness for convergence
* @param populationSize size of population
* @return returns best chromosome
*/
public Chromosome<Coordinate> optimize(int dimension,
double minCrossoverRate,
double maxCrossoverRate,
double minMutationRate,
Expand All @@ -75,7 +91,7 @@ public void optimize(int dimension,
// best chromosome from the final population
final Chromosome<Coordinate> bestFinal = finalPopulation.getFittestChromosome();

logger.info(bestFinal.toString());
return bestFinal;
}

private static Population<Coordinate> getInitialPopulation(int dimension, int populationSize) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
*/
package org.apache.commons.math4.examples.ga.mathfunctions.adaptive;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
Expand All @@ -27,43 +36,40 @@ 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;
/** indicates the absolute file path where output would be stored. **/
@Option(names = {"-o", "--output"}, required = true, paramLabel = "OUTPUT_FILE_PATH", arity = "1")
private String output;
/** instance of logger. **/
private final Logger logger = LoggerFactory.getLogger(StandAlone.class);

public static void main(String[] args) {
CommandLine.run(new StandAlone(), args);
Expand All @@ -79,10 +85,18 @@ public void run() {
// validate all input options.
validateInput();

final AdaptiveMathFunctionOptimizer optimizer = new AdaptiveMathFunctionOptimizer();

optimizer.optimize(dimension, minCrossoverRate, maxCrossoverRate, minMutationRate, maxMutationRate, elitismRate,
tournamentSize, generationsEvolvedWithUnchangedBestFitness, populationSize);
try (PrintWriter writer = new PrintWriter(new File(output), Charset.defaultCharset().name())) {
writer.println("Optimization Result:");
final AdaptiveMathFunctionOptimizer optimizer = new AdaptiveMathFunctionOptimizer();
writer.println(optimizer
.optimize(dimension, minCrossoverRate, maxCrossoverRate, minMutationRate, maxMutationRate,
elitismRate, tournamentSize, generationsEvolvedWithUnchangedBestFitness, populationSize)
.toString());
} catch (FileNotFoundException e) {
logger.error("Error while writing to file", e);
} catch (UnsupportedEncodingException e) {
logger.error("Encoding not supported for writing to output file", e);
}

}

Expand Down Expand Up @@ -121,5 +135,9 @@ private void validateInput() {
throw new IllegalArgumentException(
"Number of generations evolved with unchanged best fitness should be >= 1.");
}
File outFile = new File(output);
if (outFile.exists() && !outFile.delete()) {
throw new IllegalArgumentException("Existing output file could not be deleted.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
*/

public final class MathFunctionOptimizer {

/** length of chromosome. **/
private static final int CHROMOSOME_LENGTH_PER_DIMENSION = 12;
/** instance of logger. **/
Expand All @@ -55,8 +56,9 @@ public final class MathFunctionOptimizer {
* @param generationCountWithUnchangedBestFitness no of generation evolved with
* unchanged best fitness
* @param populationSize size of population
* @return returns best chromosome
*/
public void optimize(int dimension,
public Chromosome<Coordinate> optimize(int dimension,
double crossoverRate,
double mutationRate,
double elitismRate,
Expand All @@ -81,7 +83,7 @@ public void optimize(int dimension,
// best chromosome from the final population
final Chromosome<Coordinate> bestFinal = finalPopulation.getFittestChromosome();

logger.info(bestFinal.toString());
return bestFinal;
}

private static Population<Coordinate> getInitialPopulation(int dimension, int populationSize) {
Expand All @@ -101,14 +103,14 @@ private static Population<Coordinate> getInitialPopulation(int dimension, int po
final BinaryChromosome<Coordinate> binaryChromosome =
(BinaryChromosome<Coordinate>) chromosome;
final long length = binaryChromosome.getLength();
final List<Double> coordinates = new ArrayList<>();
final List<Double> dimValues = 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);
dimValues.add(Integer.parseUnsignedInt(dimensionStrValue, 2) / 100d);
}

return new Coordinate(coordinates);
return new Coordinate(dimValues);
}));
}
return population;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@
*/
package org.apache.commons.math4.examples.ga.mathfunctions;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

import org.apache.commons.math4.examples.ga.mathfunctions.legacy.LegacyMathFunctionOptimizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import picocli.CommandLine;
import picocli.CommandLine.Command;
Expand All @@ -28,35 +36,33 @@ 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;
/** indicates the absolute file path where output would be stored. **/
@Option(names = {"-o", "--output"}, required = true, paramLabel = "OUTPUT_FILE_PATH")
private String output;
/** instance of logger. **/
private final Logger logger = LoggerFactory.getLogger(StandAlone.class);

public static void main(String[] args) {
CommandLine.run(new StandAlone(), args);
Expand All @@ -72,14 +78,26 @@ 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);
try (PrintWriter writer = new PrintWriter(new File(output), Charset.defaultCharset().name())) {
writer.println("Optimization Result:");
if (!legacy) {
writer.println(
new MathFunctionOptimizer()
.optimize(dimension, crossoverRate, mutationRate, elitismRate, tournamentSize,
generationsEvolvedWithUnchangedBestFitness, populationSize)
.toString());
} else {
writer.println(
new LegacyMathFunctionOptimizer()
.optimize(dimension, crossoverRate, mutationRate, elitismRate, tournamentSize,
generationsEvolvedWithUnchangedBestFitness, populationSize)
.toString());
}
} catch (FileNotFoundException e) {
logger.error("Error while writing to file", e);
} catch (UnsupportedEncodingException e) {
logger.error("Encoding not supported for writing to output file", e);
}

}

private void validateInput() {
Expand All @@ -105,5 +123,9 @@ private void validateInput() {
throw new IllegalArgumentException(
"Number of generations evolved with unchanged best fitness should be >= 1.");
}
File outFile = new File(output);
if (outFile.exists() && !outFile.delete()) {
throw new IllegalArgumentException("Existing output file could not be deleted.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* the legacy genetic algorithm.
*/
public final class LegacyMathFunctionOptimizer {

/** length of chromosome per dimension. **/
private static final int CHROMOSOME_LENGTH_PER_DIMENSION = 12;

Expand All @@ -44,8 +45,9 @@ public final class LegacyMathFunctionOptimizer {
* @param generationCountWithUnchangedBestFitness no of generation evolved with
* unchanged best fitness
* @param populationSize size of population
* @return returns best chromosome
*/
public void optimize(int dimension,
public Chromosome optimize(int dimension,
double crossoverRate,
double mutationRate,
double elitismRate,
Expand All @@ -67,9 +69,7 @@ public void optimize(int dimension,
// best chromosome from the final population
final Chromosome bestFinal = finalPopulation.getFittestChromosome();

//CHECKSTYLE: stop all
System.out.println("best=" + bestFinal.toString());
//CHECKSTYLE: resume all
return bestFinal;
}

private static Population getInitialPopulation(int dimension, int populationSize, double elitismRate) {
Expand Down
Loading