https://github.com/clebert/otus
A modular JavaScript API for programming with genetic algorithms.
https://github.com/clebert/otus
genetic-algorithm genetic-programming
Last synced: 12 months ago
JSON representation
A modular JavaScript API for programming with genetic algorithms.
- Host: GitHub
- URL: https://github.com/clebert/otus
- Owner: clebert
- License: mit
- Created: 2020-05-27T15:13:42.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2023-03-26T22:49:43.000Z (about 3 years ago)
- Last Synced: 2025-06-21T04:43:39.900Z (about 1 year ago)
- Topics: genetic-algorithm, genetic-programming
- Language: TypeScript
- Homepage:
- Size: 1.32 MB
- Stars: 3
- Watchers: 3
- Forks: 1
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Otus
> A modular JavaScript API for programming with
> [genetic algorithms](https://en.wikipedia.org/wiki/Genetic_algorithm).
## Installation
```
npm install otus
```
## Features
- Support for three modular exchangeable
[genetic operators](https://en.wikipedia.org/wiki/Genetic_operator)
(selection, crossover, mutation)
- A ready-to-use implementation of each of the supported genetic operators:
- [Fitness proportionate selection](https://en.wikipedia.org/wiki/Fitness_proportionate_selection)
(via [stochastic acceptance](https://arxiv.org/abs/1109.3627))
- [Uniform crossover]()
- [Uniform mutation]()
- [Genetic representation](https://en.wikipedia.org/wiki/Genetic_representation)
using plain JavaScript objects
- Support for [elitism](https://en.wikipedia.org/wiki/Genetic_algorithm#Elitism)
- Support for adaptive parameters
([adaptive genetic algorithms](https://en.wikipedia.org/wiki/Genetic_algorithm#Adaptive_GAs))
- Immutable/functional API
- Built-in support for TypeScript
- No dependencies
## Terminology
### [Genotype](https://en.wikipedia.org/wiki/Genotype)
The genotype defines all genes and their possible values using alleles. It is so
to speak the blueprint for the construction of phenotypes.
Type definition
```ts
interface Genotype {
readonly [geneName: string]: Allele;
}
```
### [Allele](https://en.wikipedia.org/wiki/Allele)
The possible values of a particular gene are called alleles. An allele is a
function with which the initial value of a gene is generated as well as all
further values of a gene in the course of mutations.
Type definition
```ts
type Allele = () => TValue;
```
### [Phenotype](https://en.wikipedia.org/wiki/Phenotype)
The phenotype represents a
[candidate solution](https://en.wikipedia.org/wiki/Feasible_region#Candidate_solution)
and contains all genes defined by the genotype with concrete values.
Type definition
```ts
type Phenotype = {
readonly [TGeneName in keyof TGenotype]: Gene;
};
```
### [Gene](https://en.wikipedia.org/wiki/Gene)
A gene represents a concrete property of a solution which can be mutated and
altered.
Type definition
```ts
type Gene<
TGenotype extends Genotype,
TGeneName extends keyof TGenotype,
> = ReturnType;
```
### [Selection operator]()
The selection operator is used to select individual solutions from a population
for later breeding (using the crossover operator). The selection is usually
based on the fitness of each individual, which is determined by a fitness
function.
Type definition
```ts
type SelectionOperator = (
phenotypes: readonly Phenotype[],
fitnessFunction: FitnessFunction,
) => Phenotype;
```
### [Fitness function](https://en.wikipedia.org/wiki/Fitness_function)
A fitness function is a particular type of
[objective function](https://en.wikipedia.org/wiki/Loss_function) that is used
to summarise, as a single figure of merit, how close a given solution is to
achieving the set aims.
Type definition
```ts
type FitnessFunction = (
phenotype: Phenotype,
) => number;
```
### [Crossover operator]()
The crossover operator is used in the process of taking two parent solutions and
producing a child solution from them. By recombining portions of good solutions,
the genetic algorithm is more likely to create a better solution.
Type definition
```ts
type CrossoverOperator = (
phenotypeA: Phenotype,
phenotypeB: Phenotype,
) => Phenotype;
```
### [Mutation operator]()
The mutation operator encourages genetic diversity amongst solutions and
attempts to prevent the genetic algorithm converging to a local minimum by
stopping the solutions becoming too close to one another.
Type definition
```ts
type MutationOperator = (
phenotype: Phenotype,
genotype: TGenotype,
) => Phenotype;
```
## Usage example
```js
import {
cacheFitnessFunction,
createFitnessProportionateSelectionOperator,
createFloatAllele,
createIntegerAllele,
createUniformCrossoverOperator,
createUniformMutationOperator,
geneticAlgorithm,
getFittestPhenotype,
} from 'otus';
```
```js
const smallNumberGenotype = {
base: createFloatAllele(1, 10), // float between 1.0 (inclusive) and 10.0 (exclusive)
exponent: createIntegerAllele(2, 4), // integer between 2 (inclusive) and 4 (inclusive)
};
```
```js
function isAnswerToEverything(smallNumberPhenotype) {
const number = Math.pow(
smallNumberPhenotype.base,
smallNumberPhenotype.exponent,
);
return number === 42 ? Number.MAX_SAFE_INTEGER : 1 / Math.abs(42 - number);
}
```
```js
const state = {
genotype: smallNumberGenotype,
phenotypes: [],
populationSize: 100,
elitePopulationSize: 2,
fitnessFunction: cacheFitnessFunction(isAnswerToEverything),
selectionOperator: createFitnessProportionateSelectionOperator(),
crossoverOperator: createUniformCrossoverOperator(0.5),
mutationOperator: createUniformMutationOperator(0.1),
};
```
```js
for (let i = 0; i < 100; i += 1) {
state = geneticAlgorithm(state);
}
```
```js
const answerToEverythingPhenotype = getFittestPhenotype(state);
```
```js
console.log(
`The answer to everything:`,
Math.pow(
answerToEverythingPhenotype.base,
answerToEverythingPhenotype.exponent,
),
answerToEverythingPhenotype,
);
```
```
The answer to everything: 42.00057578051458 { base: 3.4760425291663264, exponent: 3 }
```
## API reference
### Genetic algorithm function
```ts
function geneticAlgorithm(
state: GeneticAlgorithmState,
): GeneticAlgorithmState;
```
```ts
interface GeneticAlgorithmState {
readonly genotype: TGenotype;
readonly phenotypes: readonly Phenotype[];
readonly populationSize: number;
readonly elitePopulationSize?: number;
readonly fitnessFunction: FitnessFunction;
readonly selectionOperator: SelectionOperator;
readonly crossoverOperator: CrossoverOperator;
readonly mutationOperator: MutationOperator;
}
```
### Genetic operator factory functions
```ts
function createFitnessProportionateSelectionOperator<
TGenotype extends Genotype,
>(randomFunction?: () => number): SelectionOperator;
```
```ts
function createUniformCrossoverOperator(
probability: number,
randomFunction?: () => number,
): CrossoverOperator;
```
```ts
function createUniformMutationOperator(
probability: number,
randomFunction?: () => number,
): MutationOperator;
```
### Allele factory functions
```ts
function createFloatAllele(
min: number,
max: number,
randomFunction?: () => number,
): Allele;
```
> The created allele returns a random float between min (inclusive) and max
> (exclusive).
```ts
function createIntegerAllele(
min: number,
max: number,
randomFunction?: () => number,
): Allele;
```
> The created allele returns a random integer between min (inclusive) and max
> (inclusive).
### Utility functions
```ts
function getFittestPhenotype(
state: GeneticAlgorithmState,
): Phenotype | undefined;
```
```ts
function cacheFitnessFunction(
fitnessFunction: FitnessFunction,
): FitnessFunction;
```
```ts
function createRandomPhenotype(
genotype: TGenotype,
): Phenotype;
```