Created
November 20, 2016 20:20
-
-
Save kana-sama/9c1bffe0970241a0f1bdfaaa829a77a5 to your computer and use it in GitHub Desktop.
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
const POPULATION_SIZE = 100 | |
class GeneticAlgorithm { | |
generate(length) { | |
let chromosome = '' | |
for (let i = 0; i < length; i += 1) { | |
chromosome += String(Number(Math.random(1) > 0.5)) | |
} | |
return chromosome | |
} | |
static mutationsMap = { | |
'0': '1', | |
'1': '0', | |
} | |
mutate(chromosome, p) { | |
let newChromosome = '' | |
for (let bit of chromosome) { | |
const willMutate = (Math.random() < p) | |
if (willMutate) { | |
bit = GeneticAlgorithm.mutationsMap[bit] | |
} | |
newChromosome += bit | |
} | |
return newChromosome | |
} | |
crossover(chromosome1, chromosome2, changeFrom) { | |
let newChromosome1 = '' | |
let newChromosome2 = '' | |
for (const index in chromosome1) { | |
let char1 = chromosome1[Number(index)] | |
let char2 = chromosome2[Number(index)] | |
if (index >= changeFrom) { | |
[char1, char2] = [char2, char1] | |
} | |
newChromosome1 += char1 | |
newChromosome2 += char2 | |
} | |
return [newChromosome1, newChromosome2] | |
} | |
select(population, fitnesses) { | |
let fullFitness = fitnesses.reduce((sum, current) => sum + current) | |
let selectedPoint = Math.random() * fullFitness | |
let selectedChromosome = 0 | |
while (selectedPoint > 0) { | |
selectedPoint -= fitnesses[selectedChromosome] | |
selectedChromosome += 1 | |
} | |
return population[selectedChromosome - 1] | |
} | |
run(fitness, length, p_c, p_m, iterations) { | |
let population = [] | |
for (let i = 0; i < POPULATION_SIZE; i += 1) { | |
population.push(this.generate(length)) | |
} | |
let fitnesses = population.map(fitness) | |
do { | |
let newPopulation = [] | |
while (newPopulation.length < POPULATION_SIZE) { | |
let chromosome1 = this.select(population, fitnesses) | |
let chromosome2 | |
do { | |
chromosome2 = this.select(population, fitnesses) | |
} while (chromosome1 === chromosome2) | |
const willCrossover = (Math.random() < p_c) | |
if (willCrossover) { | |
const crossoverPosition = Math.trunc(Math.random() * length) | |
let [newChromosome1, newChromosome2] = this.crossover(chromosome1, chromosome2, crossoverPosition) | |
newChromosome1 = this.mutate(newChromosome1, p_m) | |
newChromosome2 = this.mutate(newChromosome2, p_m) | |
newPopulation.push(newChromosome1, newChromosome2) | |
} | |
} | |
population = newPopulation | |
fitnesses = population.map(fitness) | |
} while (!fitnesses.some(f => f === 1)) | |
for (let i = 0; i < POPULATION_SIZE; i += 1) { | |
if (fitnesses[i] === 1) { | |
return population[i] | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment