aegis_sim.submodels.genetics.composite.architecture

 1import numpy as np
 2from aegis_sim import constants
 3from aegis_sim import variables
 4
 5from aegis_sim.submodels.genetics.composite.interpreter import Interpreter
 6from aegis_sim import parameterization
 7from aegis_sim.submodels.genetics import ploider
 8
 9
10class CompositeArchitecture:
11    """
12
13    GUI
14    - when pleiotropy is not needed;
15    - it is quick, easy to analyze, delivers a diversity of phenotypes
16    - every trait (surv repr muta neut) can be evolvable or not
17    - if not evolvable, the value is set by !!!
18    - if evolvable, it can be agespecific or age-independent
19    - probability of a trait at each age is determined by a BITS_PER_LOCUS adjacent bits forming a "locus" / gene
20    - the method by which these loci are converted into a phenotypic value is the Interpreter type
21
22    """
23
24    def __init__(self, BITS_PER_LOCUS, AGE_LIMIT, THRESHOLD):
25        self.BITS_PER_LOCUS = BITS_PER_LOCUS
26        self.n_loci = sum(trait.length for trait in parameterization.traits.values())
27        self.length = self.n_loci * BITS_PER_LOCUS
28        self.AGE_LIMIT = AGE_LIMIT
29
30        self.evolvable = [trait for trait in parameterization.traits.values() if trait.evolvable]
31
32        self.interpreter = Interpreter(
33            self.BITS_PER_LOCUS,
34            THRESHOLD,
35        )
36
37        # Fixed seed=0 so all populations (including hybridizing ones with different RANDOM_SEEDs)
38        # share an identical physical genome layout; locus_permutation[i] = physical position of logical locus i
39        self.locus_permutation = np.random.default_rng(0).permutation(self.n_loci)
40
41    def get_number_of_bits(self):
42        return ploider.ploider.y * self.n_loci * self.BITS_PER_LOCUS
43
44    def get_shape(self):
45        return (ploider.ploider.y, self.n_loci, self.BITS_PER_LOCUS)
46
47    def init_genome_array(self, popsize):
48        # TODO enable agespecific False
49        array = variables.rng.random(size=(popsize, *self.get_shape()))
50
51        for trait in parameterization.traits.values():
52            phys_pos = self.locus_permutation[trait.start:trait.end]
53            array[:, :, phys_pos, :] = array[:, :, phys_pos, :] < trait.initgeno
54
55        return array
56
57    def compute(self, genomes):
58
59        if genomes.shape[1] == 1:  # Do not calculate mean if genomes are haploid
60            genomes = genomes[:, 0]
61        else:
62            genomes = ploider.ploider.diploid_to_haploid(genomes)
63
64        # Reorder from physical storage order to logical (trait×age) order
65        genomes = genomes[:, self.locus_permutation, :]
66
67        interpretome = np.zeros(shape=(genomes.shape[0], genomes.shape[1]), dtype=np.float32)
68        for trait in parameterization.traits.values():
69            loci = genomes[:, trait.slice]  # fetch
70            probs = self.interpreter.call(loci, trait.interpreter)  # interpret
71            # self.diffuse(probs)
72            interpretome[:, trait.slice] += probs  # add back
73
74        return interpretome
75
76    # def diffuse(self, probs):
77    #     window_size = parametermanager.parameters.DIFFUSION_FACTOR * 2 + 1
78    #     p = np.empty(shape=(probs.shape[0], probs.shape[1] + window_size - 1))
79    #     p[:, :window_size] = np.repeat(probs[:, 0], window_size).reshape(-1, window_size)
80    #     p[:, window_size - 1 :] = probs[:]
81    #     diffusome = np.convolve(p[0], np.ones(window_size) / window_size, mode="valid")
82
83    def get_map(self):
84        pass
class CompositeArchitecture:
11class CompositeArchitecture:
12    """
13
14    GUI
15    - when pleiotropy is not needed;
16    - it is quick, easy to analyze, delivers a diversity of phenotypes
17    - every trait (surv repr muta neut) can be evolvable or not
18    - if not evolvable, the value is set by !!!
19    - if evolvable, it can be agespecific or age-independent
20    - probability of a trait at each age is determined by a BITS_PER_LOCUS adjacent bits forming a "locus" / gene
21    - the method by which these loci are converted into a phenotypic value is the Interpreter type
22
23    """
24
25    def __init__(self, BITS_PER_LOCUS, AGE_LIMIT, THRESHOLD):
26        self.BITS_PER_LOCUS = BITS_PER_LOCUS
27        self.n_loci = sum(trait.length for trait in parameterization.traits.values())
28        self.length = self.n_loci * BITS_PER_LOCUS
29        self.AGE_LIMIT = AGE_LIMIT
30
31        self.evolvable = [trait for trait in parameterization.traits.values() if trait.evolvable]
32
33        self.interpreter = Interpreter(
34            self.BITS_PER_LOCUS,
35            THRESHOLD,
36        )
37
38        # Fixed seed=0 so all populations (including hybridizing ones with different RANDOM_SEEDs)
39        # share an identical physical genome layout; locus_permutation[i] = physical position of logical locus i
40        self.locus_permutation = np.random.default_rng(0).permutation(self.n_loci)
41
42    def get_number_of_bits(self):
43        return ploider.ploider.y * self.n_loci * self.BITS_PER_LOCUS
44
45    def get_shape(self):
46        return (ploider.ploider.y, self.n_loci, self.BITS_PER_LOCUS)
47
48    def init_genome_array(self, popsize):
49        # TODO enable agespecific False
50        array = variables.rng.random(size=(popsize, *self.get_shape()))
51
52        for trait in parameterization.traits.values():
53            phys_pos = self.locus_permutation[trait.start:trait.end]
54            array[:, :, phys_pos, :] = array[:, :, phys_pos, :] < trait.initgeno
55
56        return array
57
58    def compute(self, genomes):
59
60        if genomes.shape[1] == 1:  # Do not calculate mean if genomes are haploid
61            genomes = genomes[:, 0]
62        else:
63            genomes = ploider.ploider.diploid_to_haploid(genomes)
64
65        # Reorder from physical storage order to logical (trait×age) order
66        genomes = genomes[:, self.locus_permutation, :]
67
68        interpretome = np.zeros(shape=(genomes.shape[0], genomes.shape[1]), dtype=np.float32)
69        for trait in parameterization.traits.values():
70            loci = genomes[:, trait.slice]  # fetch
71            probs = self.interpreter.call(loci, trait.interpreter)  # interpret
72            # self.diffuse(probs)
73            interpretome[:, trait.slice] += probs  # add back
74
75        return interpretome
76
77    # def diffuse(self, probs):
78    #     window_size = parametermanager.parameters.DIFFUSION_FACTOR * 2 + 1
79    #     p = np.empty(shape=(probs.shape[0], probs.shape[1] + window_size - 1))
80    #     p[:, :window_size] = np.repeat(probs[:, 0], window_size).reshape(-1, window_size)
81    #     p[:, window_size - 1 :] = probs[:]
82    #     diffusome = np.convolve(p[0], np.ones(window_size) / window_size, mode="valid")
83
84    def get_map(self):
85        pass

GUI

  • when pleiotropy is not needed;
  • it is quick, easy to analyze, delivers a diversity of phenotypes
  • every trait (surv repr muta neut) can be evolvable or not
  • if not evolvable, the value is set by !!!
  • if evolvable, it can be agespecific or age-independent
  • probability of a trait at each age is determined by a BITS_PER_LOCUS adjacent bits forming a "locus" / gene
  • the method by which these loci are converted into a phenotypic value is the Interpreter type
CompositeArchitecture(BITS_PER_LOCUS, AGE_LIMIT, THRESHOLD)
25    def __init__(self, BITS_PER_LOCUS, AGE_LIMIT, THRESHOLD):
26        self.BITS_PER_LOCUS = BITS_PER_LOCUS
27        self.n_loci = sum(trait.length for trait in parameterization.traits.values())
28        self.length = self.n_loci * BITS_PER_LOCUS
29        self.AGE_LIMIT = AGE_LIMIT
30
31        self.evolvable = [trait for trait in parameterization.traits.values() if trait.evolvable]
32
33        self.interpreter = Interpreter(
34            self.BITS_PER_LOCUS,
35            THRESHOLD,
36        )
37
38        # Fixed seed=0 so all populations (including hybridizing ones with different RANDOM_SEEDs)
39        # share an identical physical genome layout; locus_permutation[i] = physical position of logical locus i
40        self.locus_permutation = np.random.default_rng(0).permutation(self.n_loci)
BITS_PER_LOCUS
n_loci
length
AGE_LIMIT
evolvable
interpreter
locus_permutation
def get_number_of_bits(self):
42    def get_number_of_bits(self):
43        return ploider.ploider.y * self.n_loci * self.BITS_PER_LOCUS
def get_shape(self):
45    def get_shape(self):
46        return (ploider.ploider.y, self.n_loci, self.BITS_PER_LOCUS)
def init_genome_array(self, popsize):
48    def init_genome_array(self, popsize):
49        # TODO enable agespecific False
50        array = variables.rng.random(size=(popsize, *self.get_shape()))
51
52        for trait in parameterization.traits.values():
53            phys_pos = self.locus_permutation[trait.start:trait.end]
54            array[:, :, phys_pos, :] = array[:, :, phys_pos, :] < trait.initgeno
55
56        return array
def compute(self, genomes):
58    def compute(self, genomes):
59
60        if genomes.shape[1] == 1:  # Do not calculate mean if genomes are haploid
61            genomes = genomes[:, 0]
62        else:
63            genomes = ploider.ploider.diploid_to_haploid(genomes)
64
65        # Reorder from physical storage order to logical (trait×age) order
66        genomes = genomes[:, self.locus_permutation, :]
67
68        interpretome = np.zeros(shape=(genomes.shape[0], genomes.shape[1]), dtype=np.float32)
69        for trait in parameterization.traits.values():
70            loci = genomes[:, trait.slice]  # fetch
71            probs = self.interpreter.call(loci, trait.interpreter)  # interpret
72            # self.diffuse(probs)
73            interpretome[:, trait.slice] += probs  # add back
74
75        return interpretome
def get_map(self):
84    def get_map(self):
85        pass