An open API service indexing awesome lists of open source software.

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.

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