class Environment {
constructor(population, fitness, crossProb=0.5, mutationProb=0.1, tournamentSize=3) {
this.population = population;
this.fitness = fitness;
this.crossProb = crossProb;
this.mutationProb = mutationProb;
this.sampler = createSampler(tournamentSize);
}
get fits() {
return this.population.map(p => this.fitness(p));
}
update() {
const offspring = this.tournamentSelect();
const males = offspring.slice(0, Math.floor(offspring.length / 2));
const females = offspring.slice(Math.floor(offspring.length / 2));
for (let [child1, child2] of d3.zip(males, females)) {
if (Math.random() < this.crossProb) {
this.twoPointMate(child1, child2);
}
}
for (let child of offspring) {
if (Math.random() < this.mutationProb) {
child.mutate();
}
}
this.population = [...offspring];
}
tournamentSelect() {
const selected = [];
for (let i = 0; i < this.population.length; i++) {
const sample = this.sampler(this.population);
const fittest = d3.greatest(
sample,
(a, b) => this.fitness(a) - this.fitness(b)
);
selected.push(fittest.clone())
}
return selected;
}
twoPointMate(ind1, ind2) {
const r1 = Math.floor(Math.random() * (ind1.length + 1));
const r2 = Math.floor(Math.random() * (ind1.length + 1));
const [start, end] = [Math.min(r1, r2), Math.max(r1, r2)];
const tmp = ind1.chromosome.slice(start, end);
ind1.replaceGene(start, ind2.chromosome.slice(start, end));
ind2.replaceGene(start, tmp);
}
}