Created
January 6, 2011 07:15
-
-
Save fearofcode/767639 to your computer and use it in GitHub Desktop.
Simple use of the Watchmaker framework (https://github.com/dwdyer/watchmaker) to optimize the sphere function in N dimension. The sphere function is just (x_1*x_1, ..., x_n*x_n) with a single global minimum at (0, ..., 0).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.eccasts.watchmakerexample; | |
import java.util.*; | |
import org.uncommons.maths.random.*; | |
import org.uncommons.watchmaker.framework.*; | |
import org.uncommons.watchmaker.framework.factories.AbstractCandidateFactory; | |
import org.uncommons.watchmaker.framework.operators.DoubleArrayCrossover; | |
import org.uncommons.watchmaker.framework.operators.EvolutionPipeline; | |
import org.uncommons.watchmaker.framework.selection.RouletteWheelSelection; | |
import org.uncommons.watchmaker.framework.termination.Stagnation; | |
public class FunctionOptimizer { | |
public static void main(String[] args) { | |
new FunctionOptimizer().work(); | |
} | |
private void work() { | |
int dimension = 10; | |
double max = 5.0; | |
double min = -max; | |
int populationSize = 50; | |
int crossoverPoints = 2; | |
double mutationProbability = 0.02; | |
CandidateFactory<double[]> factory = new ArrayFactory(dimension, min, max); | |
List<EvolutionaryOperator<double[]>> operators = new ArrayList<EvolutionaryOperator<double[]>>(dimension); | |
operators.add(new DoubleArrayCrossover(crossoverPoints)); | |
operators.add(new DoubleArrayMutation(new Probability(mutationProbability))); | |
EvolutionaryOperator<double[]> pipeline = new EvolutionPipeline<double[]>(operators); | |
EvolutionEngine<double[]> engine = new GenerationalEvolutionEngine<double[]>(factory, | |
pipeline, | |
new SphereFunction(dimension), | |
new RouletteWheelSelection(), | |
new MersenneTwisterRNG()); | |
engine.addEvolutionObserver(new EvolutionLogger()); | |
double[] best = engine.evolve(populationSize, | |
5, | |
new Stagnation(100, false)); | |
System.out.printf("(%f, %f)\n", best[0], best[1]); | |
} | |
private static class DoubleArrayMutation implements EvolutionaryOperator<double[]> { | |
private Probability p; | |
public DoubleArrayMutation(Probability p) { | |
this.p = p; | |
} | |
@Override | |
public List<double[]> apply(List<double[]> selectedCandidates, Random rng) { | |
List<double[]> newCandidates = new ArrayList<double[]>(selectedCandidates.size()); | |
newCandidates.addAll(selectedCandidates); | |
for(int i = 0; i < newCandidates.size(); i++) { | |
if(p.nextEvent(rng)) { | |
double[] mutated = newCandidates.get(i); | |
int dimension = rng.nextInt(mutated.length); | |
mutated[dimension] += rng.nextGaussian(); | |
newCandidates.set(i, mutated); | |
} | |
} | |
return newCandidates; | |
} | |
} | |
private static class SphereFunction implements FitnessEvaluator<double[]> { | |
private int dimension; | |
public SphereFunction(int dimension) { | |
this.dimension = dimension; | |
} | |
@Override | |
public double getFitness(double[] candidate, | |
List<? extends double[]> population) { | |
double sum = 0.0; | |
for(int i = 0; i < dimension; i++) | |
sum += candidate[i]*candidate[i]; | |
return sum; | |
} | |
@Override | |
public boolean isNatural() { | |
return false; | |
} | |
} | |
private static class ArrayFactory extends AbstractCandidateFactory<double[]> implements | |
CandidateFactory<double[]> { | |
private int dimension; | |
private double min; | |
private double max; | |
public ArrayFactory(int dimension, double min, double max) { | |
super(); | |
this.dimension = dimension; | |
this.min = min; | |
this.max = max; | |
} | |
@Override | |
public List<double[]> generateInitialPopulation(int populationSize, | |
Random rng) { | |
List<double[]> population = new ArrayList<double[]>(); | |
for(int i = 1; i <= populationSize; i++) | |
population.add(generateRandomCandidate(rng)); | |
return population; | |
} | |
@Override | |
public List<double[]> generateInitialPopulation(int populationSize, | |
Collection<double[]> seedCandidates, Random rng) { | |
List<double[]> population = new ArrayList<double[]>(); | |
population.addAll(seedCandidates); | |
for(int i = 1; i <= populationSize - seedCandidates.size(); i++) | |
population.add(generateRandomCandidate(rng)); | |
return population; | |
} | |
@Override | |
public double[] generateRandomCandidate(Random rng) { | |
double[] candidate = new double[dimension]; | |
for(int i = 0; i < dimension; i++) | |
candidate[i] = rng.nextDouble()*(max-min)+min; | |
return candidate; | |
} | |
} | |
private static class EvolutionLogger implements EvolutionObserver<double[]> | |
{ | |
public void populationUpdate(PopulationData<? extends double[]> data) | |
{ | |
System.out.printf("Generation %d: %f\n", | |
data.getGenerationNumber(), | |
data.getBestCandidateFitness()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment