Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Treast/genome.js
Browse files Browse the repository at this point in the history
  • Loading branch information
Vincent Riva authored and Vincent Riva committed Apr 1, 2019
2 parents 30b6f1a + 6814b42 commit 99976a2
Showing 1 changed file with 120 additions and 107 deletions.
227 changes: 120 additions & 107 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,141 +1,154 @@

# genome.js

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


_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
- **Population**: a subset of the possible solutions to the problem (ie. subset of _chromosomes_)

- **Gene**: a value defining a chromosome
- **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*.
- **Blueprint**: a schema defining the structure of every _gene_ (number and possible values) in a _chromosome_.

## Installation (via NPM)



```npm install --save genome.js```


`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.|

| 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.|

| 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.|

| 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.|

| 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.|

| 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)*|
| 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);

```js
/*
* 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);
```

0 comments on commit 99976a2

Please sign in to comment.