Skip to content

Treast/genome.js

Folders and files

NameName
Last commit message
Last commit date
Mar 30, 2019
Mar 30, 2019
Apr 1, 2019
Mar 27, 2019
Mar 27, 2019
Mar 27, 2019
Mar 31, 2019
Mar 27, 2019
Jul 30, 2020
Mar 30, 2019
Mar 28, 2019
Mar 28, 2019
Mar 28, 2019
Mar 28, 2019
Mar 28, 2019

Repository files navigation

genome.js

genome.js is a Javascript to help build insane genetics algorithms in a few minutes.

Concept

General terms

  • Population: a subset of the possible solutions to the problem (ie. subset of chromosomes)

  • Chromosome: a specific solution to the problem

  • Gene: a value defining a chromosome

Specific terms

  • Blueprint: a schema defining the structure of every gene (number and possible values) in a chromosome.

Installation (via NPM)

npm install --save genome.js

Documentation

Population

Methods Return type Description
constructor(size: number, blueprint: Blueprint) Population Create a population with size chromosomes using the blueprint
setFitnessCalculation(fitnessCalculation: any) null Set the fitness calculation function. It should return a number value corresponding to the fitness of a chromosome.
setStopAt(fitness: number) null Stop the process once a chromosome reaches AT LEAST fitness value on its fitness.
setMutationRate(mutationRate: number) null Set the mutation rate value. It should be between 0 (no mutation at all) and 1 (every chromosome will be mutated)
setCutOff(cutOff: number) null Set the cut off value. It should be between 0 (no chromosome will be removed) and 1 (every chromosome will be removed)
run(rounds: number = 1) null Run the process rounds times.
getGenerationNumber() number Return the current round number.
getBestChromosome() Chromosome Return the best chromosome.

Chromosome

Methods Return type Description
getGenes() Gene[] Return the genes of the chromosome.
getFitness() Gene[] Return the fitness of the chromosome.

Gene

Methods Return type Description
get() number Return the allele (value) of the gene.

Blueprint

Methods Return type Description
constructor() Blueprint Create a new Blueprint.
add(factor: number, times: number = 1) null Define a property into the blueprint. The factor is used when you get back the allele (value) of a gene (ex: a gene created with add(26) will return a number between 0 and 25). You can add times a property by setting the times parameter.

GenoveEvent

Methods Return type Description
static on(eventType: GenomeEventType, callback: any) null STATIC Run the callback function when the event eventType is trigger.

Events

Name Description
GENOME_EVENT_POPULATION_CREATED Trigger when all chromosomes are initialized
GENOME_EVENT_GENERATION_BEGIN Trigger when a new generation is processed
GENOME_EVENT_GENERATION_END Trigger when a generation is done processing
GENOME_EVENT_GENERATION_FINISH Trigger when the all processing is done (rounds limit or fitness limit)

Example

/*
 * This example is based on the "infinite monkey theorem" (https://en.wikipedia.org/wiki/Infinite_monkey_theorem)
 *
 * The algorithm tries to reproduce a specific text input, here "helloworldhowareyoutoday" in a minimum rounds.
 */

// Importing all the dependencies
import {
  Population,
  Blueprint,
  Gene,
  Chromosome,
  GenomeEvent,
  GenomeEventType
} from "genome.js";

// Defining the string to reproduce
const answer = "helloworldhowareyoutoday";

// We create a blueprint to represent the data structure of a chromosome
const blueprint = new Blueprint();
// Our chromosomes will have 'answer.length' genes between 0 and 26 (not included), so that each gene can represent one letter of the alphabet
blueprint.add(26, answer.length);

// We generate a population of 500 chromosomes using our blueprint
const population = new Population(500, blueprint);

// Just some basic configurations
population.setMutationRate(0.01);
population.setCutOff(0.5);
population.setStopAt(100); // We stop the processing when a chromosome reach AT LEAST 100 on his fitness

// We define now the function that calculate the fitness of every chromosome on each generation
// Be sure to never return 0 (cause a bug, WIP)
population.setFitnessCalculation((genes: Gene[]) => {
  let sum = 1; // Avoid to have 0 on fitness

  for (let i = 0; i < genes.length; i += 1) {
    const charCode = answer.charCodeAt(i) - 97;
    const geneCharCode = Math.floor(genes[i].get());
    // If the gene value is corresponding with the answer letter at the same location, then increment 'sum'
    if (charCode === geneCharCode) {
      sum += 1;
    }
  }

  // Basically a percent of correct genes' values
  return (sum / (genes.length + 1)) * 100;
});

// We wait for a generation to end, and we display the best chromosome fitness into the console
GenomeEvent.on(
  GenomeEventType.GENOME_EVENT_GENERATION_END,
  (chromosomes: Chromosome[]) => {
    const bestChromosome = chromosomes[0];
    console.log(
      `Generation ${population.getGenerationNumber()}: ${bestChromosome.getFitness()}`
    );
  }
);

// Once the process in finished (when a chromosome reach the fitness limit or the process has reach the round limit), we display the string contained in its genes
GenomeEvent.on(
  GenomeEventType.GENOME_EVENT_GENERATION_FINISH,
  (chromosomes: Chromosome[]) => {
    let finalString = "";
    const bestChromosome = chromosomes[0];
    bestChromosome.getGenes().map((gene: Gene) => {
      finalString += String.fromCharCode(gene.get() + 97);
    });
    console.log(
      `Result (fitness: ${bestChromosome.getFitness()}): ${finalString}`
    );
  }
);

// We process the algorithm throught 500 rounds (more options comming soon)
population.run(500);