lineage/population

Represents a collection of individuals organised across generations.

A Population tracks individuals by the generation they were born into, starting at generation 0. The simulation advances the population one generation at a time by selecting mating candidates, producing offspring, and adding them to the next generation.

The behaviour of each step is controlled by a PopulationRules value, which lets the caller customise mate selection, population alignment, and how many offspring are produced per generation.

Types

A function that transforms a population before the next generation is produced — for example, to cull individuals, enforce carrying capacity, or apply selection pressure

pub type Align =
  fn(Population) -> Population

The two pools of individuals from which mating partners are drawn.

For species without genetic sex both males and females may contain the same individuals, as in select_all.

Fields

  • males - Candidate paternal parents
  • females - Candidate maternal parents
pub type MatingCandidates {
  MatingCandidates(
    males: List(individual.Individual),
    females: List(individual.Individual),
  )
}

Constructors

A function that determines how many offspring to produce in the next generation, based on the current state of the population

pub type OffspringCount =
  fn(Population) -> Int

A collection of individuals grouped by the generation they belong to.

Generation numbers start at 0. Each generation maps to a list of individuals born in that step.

Fields

  • generations - A dict mapping generation number to the list of individuals born in that generation
pub type Population {
  Population(
    generations: dict.Dict(Int, List(individual.Individual)),
  )
}

Constructors

The complete set of rules governing how a population reproduces and changes over time.

Fields

  • select - Chooses which individuals are eligible to mate
  • align - Transforms the population before reproduction (e.g. culling)
  • amount - Determines how many offspring to produce per generation
pub type PopulationRules {
  PopulationRules(
    select: fn(Population) -> MatingCandidates,
    align: fn(Population) -> Population,
    amount: fn(Population) -> Int,
  )
}

Constructors

A function that inspects a population and returns the candidates eligible for mating in the next generation

pub type SelectMates =
  fn(Population) -> MatingCandidates

Values

pub fn advance(
  population: Population,
  rules: PopulationRules,
) -> Population

Advances the population by one generation.

First applies rules.align to the current population, then determines the next generation number as one greater than the current highest. Finally, produces as many offspring as rules.amount specifies, each added to the new generation.

Examples

let next = advance(population, rules)
dict.size(next.generations) == dict.size(population.generations) + 1
// -> True
pub fn from_list(
  members: List(individual.Individual),
) -> Population

Creates a population from an existing list of individuals, placing them all in generation 0.

Examples

pea.create_multiple(10) |> from_list
// -> Population with 10 individuals in generation 0
pub fn new() -> Population

Creates an empty population with no individuals and no generations

pub fn select_all(population: Population) -> MatingCandidates

A SelectMates implementation that places every individual in both the male and female candidate pools.

Suitable for hermaphroditic species such as the garden pea. Note that because both pools contain all individuals, self-fertilisation is possible.

Examples

let candidates = select_all(population)
list.length(candidates.males) == list.length(candidates.females)
// -> True
pub fn simulate(
  population: Population,
  cycles: Int,
  rules: PopulationRules,
) -> Population

Runs the simulation for a given number of cycles by calling advance repeatedly.

Each cycle produces one new generation. When cycles reaches 0 the population is returned as-is.

Examples

let result = simulate(population, 10, rules)
dict.size(result.generations)
// -> 11  (generation 0 plus 10 new generations)
pub fn to_json(
  population: Population,
  rules: individual.SpeciesRules,
) -> json.Json

Encodes a population as a JSON object.

Keys are generation numbers (as strings) and values are arrays of individuals encoded via individual.to_json. Species rules are required to resolve sex, fertility, and phenotype for each individual.

Examples

population |> to_json(pea.rules()) |> json.to_string
// -> "{\"0\":[{...},{...}],\"1\":[{...}]}"
Search Document