Generic implementation of Genetic algorithm in Java.
- git clone https://github.com/lagodiuk/genetic-algorithm.git
- mvn -f genetic-algorithm/pom.xml install
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.lagodiuk.ga.Chromosome;
import com.lagodiuk.ga.Fitness;
import com.lagodiuk.ga.GeneticAlgorithm;
import com.lagodiuk.ga.IterartionListener;
import com.lagodiuk.ga.Population;
public class Demo {
public static void main(String[] args) {
Population<MyVector> population = createInitialPopulation(5);
Fitness<MyVector, Double> fitness = new MyVectorFitness();
GeneticAlgorithm<MyVector, Double> ga = new GeneticAlgorithm<MyVector, Double>(population, fitness);
addListener(ga);
ga.evolve(500);
}
/**
* The simplest strategy for creating initial population <br/>
* in real life it could be more complex
*/
private static Population<MyVector> createInitialPopulation(int populationSize) {
Population<MyVector> population = new Population<MyVector>();
MyVector base = new MyVector();
for (int i = 0; i < populationSize; i++) {
// each member of initial population
// is mutated clone of base chromosome
MyVector chr = base.mutate();
population.addChromosome(chr);
}
return population;
}
/**
* After each iteration Genetic algorithm notifies listener
*/
private static void addListener(GeneticAlgorithm<MyVector, Double> ga) {
// just for pretty print
System.out.println(String.format("%s\t%s\t%s", "iter", "fit", "chromosome"));
// Lets add listener, which prints best chromosome after each iteration
ga.addIterationListener(new IterartionListener<MyVector, Double>() {
private final double threshold = 1e-5;
@Override
public void update(GeneticAlgorithm<MyVector, Double> ga) {
MyVector best = ga.getBest();
double bestFit = ga.fitness(best);
int iteration = ga.getIteration();
// Listener prints best achieved solution
System.out.println(String.format("%s\t%s\t%s", iteration, bestFit, best));
// If fitness is satisfying - we can stop Genetic algorithm
if (bestFit < this.threshold) {
ga.terminate();
}
}
});
}
/**
* Chromosome, which represents vector of five integers
*/
public static class MyVector implements Chromosome<MyVector>, Cloneable {
private static final Random random = new Random();
private final int[] vector = new int[5];
/**
* Returns clone of current chromosome, which is mutated a bit
*/
@Override
public MyVector mutate() {
MyVector result = this.clone();
// just select random element of vector
// and increase or decrease it on small value
int index = random.nextInt(this.vector.length);
int mutationValue = random.nextInt(3) - random.nextInt(3);
result.vector[index] += mutationValue;
return result;
}
/**
* Returns list of siblings <br/>
* Siblings are actually new chromosomes, <br/>
* created using any of crossover strategy
*/
@Override
public List<MyVector> crossover(MyVector other) {
MyVector thisClone = this.clone();
MyVector otherClone = other.clone();
// one point crossover
int index = random.nextInt(this.vector.length - 1);
for (int i = index; i < this.vector.length; i++) {
int tmp = thisClone.vector[i];
thisClone.vector[i] = otherClone.vector[i];
otherClone.vector[i] = tmp;
}
return Arrays.asList(thisClone, otherClone);
}
@Override
protected MyVector clone() {
MyVector clone = new MyVector();
System.arraycopy(this.vector, 0, clone.vector, 0, this.vector.length);
return clone;
}
public int[] getVector() {
return this.vector;
}
@Override
public String toString() {
return Arrays.toString(this.vector);
}
}
/**
* Fitness function, which calculates difference between chromosomes vector
* and target vector
*/
public static class MyVectorFitness implements Fitness<MyVector, Double> {
private final int[] target = { 10, 20, 30, 40, 50 };
@Override
public Double calculate(MyVector chromosome) {
double delta = 0;
int[] v = chromosome.getVector();
for (int i = 0; i < 5; i++) {
delta += this.sqr(v[i] - this.target[i]);
}
return delta;
}
private double sqr(double x) {
return x * x;
}
}
}