Created
January 18, 2017 07:01
-
-
Save codyromano/bbddda0f9053b34643cf7153194d46f0 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| /** | |
| * @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