lineage/chromosome

Represents the chromosomal structure of an individual’s genome.

A Chromosome holds the alleles for all genes located on a single physical chromosome. A ChromosomeSet groups chromosomes by their identity (autosome number, X, Y, or other), with one list of chromosomes per identity to support any ploidity.

This module also provides the core operations needed for the reproductive cycle: creating new chromosomes from a gene map, forming gametes via random halving, merging two gametes into an offspring genome, and extracting the alleles carried at each gene position.

Types

A single chromosome: a mapping from gene index (position on the chromosome) to the allele carried at that position

pub type Chromosome =
  dict.Dict(Int, String)

Identifies which chromosome within the genome a set of genes belongs to.

Mirrors gene.GenePosition but strips the per-gene index, so that all genes on the same physical chromosome share the same ChromosomeIndex.

  • Autosome(no) — autosome identified by its chromosome number
  • X — X gonosome
  • Y — Y gonosome
  • Other(name) — any non-standard chromosome type, identified by name
pub type ChromosomeIndex {
  Autosome(no: Int)
  X
  Y
  Other(name: String)
}

Constructors

  • Autosome(no: Int)
  • X
  • Y
  • Other(name: String)

The full chromosomal genome of an individual.

Maps each ChromosomeIndex to a list of chromosomes of that type. The length of each list reflects the ploidity of the individual: a diploid individual will have two chromosomes per index.

pub type ChromosomeSet =
  dict.Dict(ChromosomeIndex, List(dict.Dict(Int, String)))

An ordered list of genes that defines the genome of a species

pub type GeneMap =
  List(gene.Gene)
pub type TypedChromosome =
  dict.Dict(Int, #(gene.Gene, String))
pub type TypedChromosomeSet =
  dict.Dict(
    ChromosomeIndex,
    List(dict.Dict(Int, #(gene.Gene, String))),
  )

A crossover function that exchanges segments between two chromosomes and returns the resulting pair

pub type Xover =
  fn(dict.Dict(Int, String), dict.Dict(Int, String)) -> #(
    dict.Dict(Int, String),
    dict.Dict(Int, String),
  )

Values

pub fn annotate_set(
  chromosomes: dict.Dict(
    ChromosomeIndex,
    List(dict.Dict(Int, String)),
  ),
  definitions: List(gene.Gene),
) -> dict.Dict(
  ChromosomeIndex,
  List(dict.Dict(Int, #(gene.Gene, String))),
)

Annotates a ChromosomeSet with gene metadata, producing a TypedChromosomeSet.

For each chromosome index in the set, the genes from definitions that belong to that index are looked up by their offset. Each allele in the raw chromosome is then paired with its Gene, producing a TypedChromosome. Offsets with no matching gene in definitions are silently dropped.

Examples

let typed = annotate_set(individual.genome, pea.genome())
pub fn create_gamete(
  chromosomes: dict.Dict(
    ChromosomeIndex,
    List(dict.Dict(Int, String)),
  ),
) -> dict.Dict(ChromosomeIndex, List(dict.Dict(Int, String)))

Creates a gamete from a chromosome set by randomly selecting half of the chromosomes at each index.

For a diploid individual this yields one chromosome per index, as expected for a haploid gamete. The halving is random, so each call may produce a different result.

Examples

let gamete = create_gamete(diploid_genome)
// each chromosome list in gamete has length 1 (half of 2)
pub fn drain(
  chromosomes: dict.Dict(
    ChromosomeIndex,
    List(dict.Dict(Int, String)),
  ),
  index: ChromosomeIndex,
) -> dict.Dict(ChromosomeIndex, List(dict.Dict(Int, String)))

Reduces the chromosomes at a given index to a random half, removing the entry entirely if it was already empty.

Unlike create_gamete, which acts on the whole set, drain targets a single chromosome index. Returns the chromosome set unchanged if the index is not present.

pub fn encode_chromosome(
  chromosome: dict.Dict(Int, String),
) -> json.Json

Encodes a single chromosome as a JSON object.

Keys are the gene indices (as strings) and values are the allele strings.

Examples

encode_chromosome(chromosome) |> json.to_string
// -> "{\"50\":\"R\",\"35\":\"G\"}"
pub fn encode_set(
  chromosomes: dict.Dict(
    ChromosomeIndex,
    List(dict.Dict(Int, String)),
  ),
) -> json.Json

Encodes a full chromosome set as a JSON object.

Keys are chromosome identifiers produced by index_to_string. Each value is a JSON array of encoded chromosomes, one per copy at that index.

Examples

encode_set(genome) |> json.to_string
// -> "{\"1\":[{...},{...}],\"X\":[{...}]}"
pub fn extract_genes(
  chromosome: dict.Dict(Int, String),
  index: ChromosomeIndex,
  genes: List(gene.Gene),
) -> dict.Dict(gene.Gene, String)

Extracts the allele carried at each gene position from a single chromosome.

The chromosome’s offset-keyed entries are matched against the full GenePosition of each gene in the gene map using reverse_index. Only genes whose position falls on the given index chromosome will produce results.

Examples

let alleles = extract_genes(chromosome, Autosome(3), pea.genome())
// -> dict mapping each gene on chromosome 3 to its allele
pub fn extract_genes_from_set(
  chromosomes: List(dict.Dict(Int, String)),
  index: ChromosomeIndex,
  genes: List(gene.Gene),
) -> dict.Dict(gene.Gene, List(String))

Extracts alleles across a list of chromosomes at the same index, grouping them into a list per gene.

Calls extract_genes on each chromosome and collects the results so that each gene maps to all the alleles it carries across the set — one per chromosome copy.

Examples

let alleles = extract_genes_from_set(diploid_chr3, Autosome(3), pea.genome())
// -> each gene on chromosome 3 maps to a list of 2 alleles
pub fn index(position: gene.GenePosition) -> ChromosomeIndex

Converts a gene.GenePosition to the ChromosomeIndex of the chromosome it belongs to, discarding the per-gene offset.

Examples

index(gene.Autosome(3, 70))
// -> Autosome(3)
index(gene.X(12))
// -> X
pub fn index_to_string(index: ChromosomeIndex) -> String

Converts a ChromosomeIndex to a human-readable string.

Autosomes are represented by their number, gonosomes by "X" or "Y", and other chromosomes by "Other " followed by the name.

Examples

index_to_string(Autosome(3))
// -> "3"
index_to_string(X)
// -> "X"
index_to_string(Other("plastid"))
// -> "Other plastid"
pub fn indices(
  definitions: List(gene.Gene),
) -> set.Set(ChromosomeIndex)

Returns the set of distinct chromosome indices present in a gene map.

Examples

indices(pea.genome())
// -> set containing Autosome(1), Autosome(2), Autosome(3), Autosome(4), Autosome(5)
pub fn map_to_genes(
  chromosomes: dict.Dict(
    ChromosomeIndex,
    List(dict.Dict(Int, String)),
  ),
  genes: List(gene.Gene),
) -> dict.Dict(gene.Gene, List(String))

Maps an entire chromosome set to a dict of genes and their allele lists.

Iterates over every chromosome index in the set, calls extract_genes_from_set for each, and merges the results. The final dict maps each Gene to all alleles it carries across all chromosomes and all copies — the full genotype ready for expression.

Examples

let genotype = map_to_genes(individual.genome, pea.genome())
// -> dict mapping each gene to a list of alleles (length = ploidity)
pub fn merge(
  left: dict.Dict(ChromosomeIndex, List(dict.Dict(Int, String))),
  right: dict.Dict(ChromosomeIndex, List(dict.Dict(Int, String))),
) -> dict.Dict(ChromosomeIndex, List(dict.Dict(Int, String)))

Merges two chromosome sets into one by concatenating the chromosome lists at each index.

Keys present in only one of the two sets are included as-is. This is the operation used to combine the two gametes produced during mating.

Examples

let offspring_genome = merge(father_gamete, mother_gamete)
pub fn new(
  definitions: List(gene.Gene),
) -> dict.Dict(Int, String)

Creates a single chromosome from a gene map by sampling one allele per gene.

Each gene contributes one entry to the chromosome, keyed by its index on the chromosome. Genes from different chromosome types may be mixed in definitions; all will be included regardless.

Examples

let chr = new(pea.genome())
dict.size(chr)
// -> 7
pub fn new_set(
  definitions: List(gene.Gene),
  amount: Int,
) -> dict.Dict(ChromosomeIndex, List(dict.Dict(Int, String)))

Creates a new full chromosome set from a gene map at a given ploidity.

For each distinct chromosome index in the gene map, amount chromosomes are created by randomly sampling alleles for the genes on that chromosome.

Examples

let genome = new_set(pea.genome(), 2)
dict.size(genome)
// -> 5  (one entry per autosome: 1, 2, 3, 4, 5)
pub fn reverse_index(
  index: ChromosomeIndex,
  offset: Int,
) -> gene.GenePosition

Reconstructs a gene.GenePosition from a ChromosomeIndex and an offset.

This is the inverse of index: given the chromosome identity and the position of a gene on that chromosome, it returns the full GenePosition.

Examples

reverse_index(Autosome(3), 70)
// -> gene.Autosome(3, 70)
reverse_index(X, 12)
// -> gene.X(12)
Search Document