Skip to content

Instantly share code, notes, and snippets.

@codyromano
Created January 18, 2017 07:01
Show Gist options
  • Select an option

  • Save codyromano/bbddda0f9053b34643cf7153194d46f0 to your computer and use it in GitHub Desktop.

Select an option

Save codyromano/bbddda0f9053b34643cf7153194d46f0 to your computer and use it in GitHub Desktop.
/**
* @param {Array} population
* @param {Number} sampleSize
*/
function randomSample(population, sampleSize) {
const populationTotal = population.length;
let result = [];
while (sampleSize--) {
const randIndex = Math.floor(Math.random() * populationTotal);
result.push(population[randIndex]);
}
return result;
}
/**
* @param {Number} generations
* Controls how long the experiment will run
*
* @param {Function} mutationFn
* Affects how genes mutate from one generation to the next
*
* @param {Function} getFitnessFn
* Returns the fitness score for a subject's genes
*
* @param {Function} optimalFitnessFn
* Returns the optimal fitness score
*
* @param {Function} displayFn
* Displays progress
*
* @param {Array} geneSet
* The entire superset of possible genes
*
* @param {Number} genesPerSubject
* The number of genes available to individuals in the population
*
* @param {Array|null} genes
* Genes belonging to an individual
*
* @param {Mixed} prevBestFitness
* @param {Mixed} prevBestGenes
*/
function findBestGenes(
generations = 1000,
mutationFn,
getFitnessFn,
optimalFitnessFn,
displayFn,
geneSet,
genesPerSubject = 100,
genes = null,
prevBestFitness = null) {
// When no generations remain, we've reached the end of the experiment
if (generations <= 0) {
return genes;
}
// Initialize a random simple on the first call
if (genes === null) {
genes = randomSample(geneSet, genesPerSubject);
}
let mutatedGenes = mutationFn(genes, geneSet);
let mutatedFitness = getFitnessFn(mutatedGenes);
let bestFitness, bestGenes;
// If the mutated genes outperform the previous
// genes, designate them as a winner
if (prevBestFitness === null || mutatedFitness > prevBestFitness) {
bestFitness = mutatedFitness;
bestGenes = mutatedGenes;
// Otherwise, stick with what we have
} else {
bestFitness = prevBestFitness;
bestGenes = genes;
}
displayFn(bestGenes, bestFitness);
// Optimal genes discovered
if (bestFitness >= optimalFitnessFn()) {
return genes;
}
// TODO: Optimize by implementing this without recursion
// It's expensive and unnecessary
const callRecursive = findBestGenes.bind(
null,
generations - 1,
mutationFn,
getFitnessFn,
optimalFitnessFn,
displayFn,
geneSet,
genesPerSubject,
bestGenes,
bestFitness
);
setTimeout(callRecursive, 100);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment