aegis_sim.submodels.reproduction.pairing

 1import numpy as np
 2from numba import njit, prange
 3from aegis_sim import variables
 4from aegis_sim.dataclasses.genomes import Genomes
 5from aegis_sim import submodels
 6
 7
 8@njit(parallel=True)
 9def _assemble_children(genome_array, males, females, male_gamete_idx, female_gamete_idx):
10    """Assemble children genomes directly from parent genome array.
11
12    Reads each parent's selected chromatid and writes it into the children array
13    in one pass, parallelized over pairs. No intermediate arrays allocated.
14    """
15    n_pairs = len(males)
16    # genome_array shape: (n_individuals, ploidy, loci, bpl)
17    n_loci = genome_array.shape[2]
18    n_bpl = genome_array.shape[3]
19    children = np.empty((n_pairs, 2, n_loci, n_bpl), dtype=genome_array.dtype)
20
21    for p in prange(n_pairs):
22        m = males[p]
23        f = females[p]
24        mg = male_gamete_idx[p]
25        fg = female_gamete_idx[p]
26        for i in range(n_loci):
27            for j in range(n_bpl):
28                children[p, 0, i, j] = genome_array[m, mg, i, j]
29                children[p, 1, i, j] = genome_array[f, fg, i, j]
30
31    return children
32
33
34def pairing(genomes: Genomes, parental_sexes, ages, muta_prob):
35    """Return assorted chromatids."""
36
37    # Get pairs
38    males, females = submodels.matingmanager.pair_up_polygamously(parental_sexes)
39    assert len(males) == len(females)
40    n_pairs = len(males)
41
42    if n_pairs == 0:
43        gshape = genomes.shape()
44        children = np.empty(shape=(0, *gshape[1:]), dtype=np.bool_)
45        return children, ages[females], muta_prob[females]
46
47    # Random gamete selection (chromatid 0 or 1 per parent)
48    male_gamete_idx = (variables.rng.random(n_pairs) < 0.5).astype(np.int32)
49    female_gamete_idx = (variables.rng.random(n_pairs) < 0.5).astype(np.int32)
50
51    # Assemble children directly from genome array — no intermediate copies
52    children = _assemble_children(
53        genomes.array, males, females, male_gamete_idx, female_gamete_idx,
54    )
55
56    # TODO fix splitting of ages and muta_prob
57    return children, ages[females], muta_prob[females]
def pairing( genomes: aegis_sim.dataclasses.genomes.Genomes, parental_sexes, ages, muta_prob):
35def pairing(genomes: Genomes, parental_sexes, ages, muta_prob):
36    """Return assorted chromatids."""
37
38    # Get pairs
39    males, females = submodels.matingmanager.pair_up_polygamously(parental_sexes)
40    assert len(males) == len(females)
41    n_pairs = len(males)
42
43    if n_pairs == 0:
44        gshape = genomes.shape()
45        children = np.empty(shape=(0, *gshape[1:]), dtype=np.bool_)
46        return children, ages[females], muta_prob[females]
47
48    # Random gamete selection (chromatid 0 or 1 per parent)
49    male_gamete_idx = (variables.rng.random(n_pairs) < 0.5).astype(np.int32)
50    female_gamete_idx = (variables.rng.random(n_pairs) < 0.5).astype(np.int32)
51
52    # Assemble children directly from genome array — no intermediate copies
53    children = _assemble_children(
54        genomes.array, males, females, male_gamete_idx, female_gamete_idx,
55    )
56
57    # TODO fix splitting of ages and muta_prob
58    return children, ages[females], muta_prob[females]

Return assorted chromatids.