aegis_sim.dataclasses.population

  1import numpy as np
  2import pickle
  3import pathlib
  4
  5from aegis_sim.dataclasses.genomes import Genomes
  6from aegis_sim.dataclasses.phenotypes import Phenotypes
  7from aegis_sim import submodels
  8
  9
 10class Population:
 11    """Population data
 12
 13    Contains demographic, genetic and phenotypic data of living individuals.
 14    """
 15
 16    attrs = (
 17        "genomes",
 18        "ages",
 19        "births",
 20        "birthdays",
 21        "generations",
 22        "phenotypes",
 23        "infection",
 24        "sizes",
 25        "sexes",
 26    )
 27
 28    def __init__(
 29        self,
 30        genomes: Genomes,
 31        ages,
 32        births,
 33        birthdays,
 34        phenotypes: Phenotypes,
 35        infection,
 36        sizes,
 37        sexes,
 38        generations=None,
 39    ):
 40        self.genomes = genomes
 41        self.ages = ages
 42        self.births = births
 43        self.birthdays = birthdays
 44        self.phenotypes = phenotypes
 45        self.infection = infection
 46        self.sizes = sizes
 47        self.sexes = sexes
 48        self.generations = generations
 49
 50        assert isinstance(phenotypes, Phenotypes)
 51
 52        if not (
 53            len(genomes)
 54            == len(ages)
 55            == len(births)
 56            == len(birthdays)
 57            == len(phenotypes)
 58            == len(infection)
 59            == len(sizes)
 60            == len(sexes)
 61            # == len(generations)
 62        ):
 63            raise ValueError("Population attributes must have equal length")
 64
 65    def __len__(self):
 66        """Return the number of living individuals."""
 67        return len(self.genomes)
 68
 69    def __getitem__(self, index):
 70        """Return a subpopulation."""
 71        return Population(
 72            genomes=self.genomes.get(individuals=index),
 73            ages=self.ages[index],
 74            births=self.births[index],
 75            birthdays=self.birthdays[index],
 76            phenotypes=self.phenotypes.get(individuals=index),
 77            infection=self.infection[index],
 78            sizes=self.sizes[index],
 79            sexes=self.sexes[index],
 80            generations=self.generations[index] if self.generations is not None else None,
 81        )
 82
 83    def __imul__(self, index):
 84        """Redefine itself as its own subpopulation."""
 85        for attr in self.attrs:
 86            if attr == "genomes":
 87                self.genomes.keep(individuals=index)
 88            elif attr == "phenotypes":
 89                self.phenotypes.keep(individuals=index)
 90            elif attr == "generations":
 91                self.generations = None
 92            else:
 93                setattr(self, attr, getattr(self, attr)[index])
 94        return self
 95
 96    def __iadd__(self, population):
 97        """Merge with another population."""
 98
 99        for attr in self.attrs:
100            if attr == "genomes":
101                self.genomes.add(population.genomes)
102            elif attr == "phenotypes":
103                assert isinstance(population.phenotypes, Phenotypes)
104                self.phenotypes.add(population.phenotypes)
105            elif attr == "generations":
106                self.generations = None
107            else:
108                val = np.concatenate([getattr(self, attr), getattr(population, attr)])
109                setattr(self, attr, val)
110        return self
111
112    # def shuffle(self):
113    #     order = np.random.arange(len(self))
114    #     np.random.shuffle(order)
115    #     self *= order
116
117    @staticmethod
118    def load_pickle_from(path: pathlib.Path):
119        assert path.exists(), f"pickle_path {path} does not exist"
120        with open(path, "rb") as file_:
121            return pickle.load(file_)
122
123    def save_pickle_to(self, path):
124        with open(path, "wb") as file_:
125            pickle.dump(self, file_)
126
127    @staticmethod
128    def initialize(n, AGE_LIMIT):
129        genomes = Genomes(submodels.architect.architecture.init_genome_array(n))
130        ages = np.random.randint(low=0, high=AGE_LIMIT, size=n, dtype=np.int32)
131        births = np.zeros(n, dtype=np.int32)
132        birthdays = np.zeros(n, dtype=np.int32)
133        # generations = np.zeros(n, dtype=np.int32)
134        generations = None
135
136        phenotypes = submodels.architect.__call__(genomes)
137        assert isinstance(phenotypes, Phenotypes)
138
139        infection = np.zeros(n, dtype=np.int32)
140        sizes = np.zeros(n, dtype=np.float32)
141        sexes = submodels.sexsystem.get_sex(n)
142        return Population(
143            genomes=genomes,
144            ages=ages,
145            births=births,
146            birthdays=birthdays,
147            generations=generations,
148            phenotypes=phenotypes,
149            infection=infection,
150            sizes=sizes,
151            sexes=sexes,
152        )
153
154    @staticmethod
155    def make_eggs(offspring_genomes: Genomes, step, offspring_sexes, parental_generations):
156        n = len(offspring_genomes)
157        eggs = Population(
158            genomes=offspring_genomes,
159            ages=np.zeros(n, dtype=np.int32),
160            births=np.zeros(n, dtype=np.int32),
161            birthdays=np.zeros(n, dtype=np.int32) + step,
162            # generations=parental_generations + 1,
163            generations=None,
164            # phenotypes=submodels.architect.__call__(offspring_genomes), # Do not compute phenotypes until eggs are laid! Why? Because it is computationally expensive.
165            phenotypes=Phenotypes.init_phenotype_array(n),
166            infection=np.zeros(n, dtype=np.int32),
167            sizes=np.zeros(n, dtype=np.float32),
168            sexes=offspring_sexes,
169        )
170        return eggs
class Population:
 11class Population:
 12    """Population data
 13
 14    Contains demographic, genetic and phenotypic data of living individuals.
 15    """
 16
 17    attrs = (
 18        "genomes",
 19        "ages",
 20        "births",
 21        "birthdays",
 22        "generations",
 23        "phenotypes",
 24        "infection",
 25        "sizes",
 26        "sexes",
 27    )
 28
 29    def __init__(
 30        self,
 31        genomes: Genomes,
 32        ages,
 33        births,
 34        birthdays,
 35        phenotypes: Phenotypes,
 36        infection,
 37        sizes,
 38        sexes,
 39        generations=None,
 40    ):
 41        self.genomes = genomes
 42        self.ages = ages
 43        self.births = births
 44        self.birthdays = birthdays
 45        self.phenotypes = phenotypes
 46        self.infection = infection
 47        self.sizes = sizes
 48        self.sexes = sexes
 49        self.generations = generations
 50
 51        assert isinstance(phenotypes, Phenotypes)
 52
 53        if not (
 54            len(genomes)
 55            == len(ages)
 56            == len(births)
 57            == len(birthdays)
 58            == len(phenotypes)
 59            == len(infection)
 60            == len(sizes)
 61            == len(sexes)
 62            # == len(generations)
 63        ):
 64            raise ValueError("Population attributes must have equal length")
 65
 66    def __len__(self):
 67        """Return the number of living individuals."""
 68        return len(self.genomes)
 69
 70    def __getitem__(self, index):
 71        """Return a subpopulation."""
 72        return Population(
 73            genomes=self.genomes.get(individuals=index),
 74            ages=self.ages[index],
 75            births=self.births[index],
 76            birthdays=self.birthdays[index],
 77            phenotypes=self.phenotypes.get(individuals=index),
 78            infection=self.infection[index],
 79            sizes=self.sizes[index],
 80            sexes=self.sexes[index],
 81            generations=self.generations[index] if self.generations is not None else None,
 82        )
 83
 84    def __imul__(self, index):
 85        """Redefine itself as its own subpopulation."""
 86        for attr in self.attrs:
 87            if attr == "genomes":
 88                self.genomes.keep(individuals=index)
 89            elif attr == "phenotypes":
 90                self.phenotypes.keep(individuals=index)
 91            elif attr == "generations":
 92                self.generations = None
 93            else:
 94                setattr(self, attr, getattr(self, attr)[index])
 95        return self
 96
 97    def __iadd__(self, population):
 98        """Merge with another population."""
 99
100        for attr in self.attrs:
101            if attr == "genomes":
102                self.genomes.add(population.genomes)
103            elif attr == "phenotypes":
104                assert isinstance(population.phenotypes, Phenotypes)
105                self.phenotypes.add(population.phenotypes)
106            elif attr == "generations":
107                self.generations = None
108            else:
109                val = np.concatenate([getattr(self, attr), getattr(population, attr)])
110                setattr(self, attr, val)
111        return self
112
113    # def shuffle(self):
114    #     order = np.random.arange(len(self))
115    #     np.random.shuffle(order)
116    #     self *= order
117
118    @staticmethod
119    def load_pickle_from(path: pathlib.Path):
120        assert path.exists(), f"pickle_path {path} does not exist"
121        with open(path, "rb") as file_:
122            return pickle.load(file_)
123
124    def save_pickle_to(self, path):
125        with open(path, "wb") as file_:
126            pickle.dump(self, file_)
127
128    @staticmethod
129    def initialize(n, AGE_LIMIT):
130        genomes = Genomes(submodels.architect.architecture.init_genome_array(n))
131        ages = np.random.randint(low=0, high=AGE_LIMIT, size=n, dtype=np.int32)
132        births = np.zeros(n, dtype=np.int32)
133        birthdays = np.zeros(n, dtype=np.int32)
134        # generations = np.zeros(n, dtype=np.int32)
135        generations = None
136
137        phenotypes = submodels.architect.__call__(genomes)
138        assert isinstance(phenotypes, Phenotypes)
139
140        infection = np.zeros(n, dtype=np.int32)
141        sizes = np.zeros(n, dtype=np.float32)
142        sexes = submodels.sexsystem.get_sex(n)
143        return Population(
144            genomes=genomes,
145            ages=ages,
146            births=births,
147            birthdays=birthdays,
148            generations=generations,
149            phenotypes=phenotypes,
150            infection=infection,
151            sizes=sizes,
152            sexes=sexes,
153        )
154
155    @staticmethod
156    def make_eggs(offspring_genomes: Genomes, step, offspring_sexes, parental_generations):
157        n = len(offspring_genomes)
158        eggs = Population(
159            genomes=offspring_genomes,
160            ages=np.zeros(n, dtype=np.int32),
161            births=np.zeros(n, dtype=np.int32),
162            birthdays=np.zeros(n, dtype=np.int32) + step,
163            # generations=parental_generations + 1,
164            generations=None,
165            # phenotypes=submodels.architect.__call__(offspring_genomes), # Do not compute phenotypes until eggs are laid! Why? Because it is computationally expensive.
166            phenotypes=Phenotypes.init_phenotype_array(n),
167            infection=np.zeros(n, dtype=np.int32),
168            sizes=np.zeros(n, dtype=np.float32),
169            sexes=offspring_sexes,
170        )
171        return eggs

Population data

Contains demographic, genetic and phenotypic data of living individuals.

Population( genomes: aegis_sim.dataclasses.genomes.Genomes, ages, births, birthdays, phenotypes: aegis_sim.dataclasses.phenotypes.Phenotypes, infection, sizes, sexes, generations=None)
29    def __init__(
30        self,
31        genomes: Genomes,
32        ages,
33        births,
34        birthdays,
35        phenotypes: Phenotypes,
36        infection,
37        sizes,
38        sexes,
39        generations=None,
40    ):
41        self.genomes = genomes
42        self.ages = ages
43        self.births = births
44        self.birthdays = birthdays
45        self.phenotypes = phenotypes
46        self.infection = infection
47        self.sizes = sizes
48        self.sexes = sexes
49        self.generations = generations
50
51        assert isinstance(phenotypes, Phenotypes)
52
53        if not (
54            len(genomes)
55            == len(ages)
56            == len(births)
57            == len(birthdays)
58            == len(phenotypes)
59            == len(infection)
60            == len(sizes)
61            == len(sexes)
62            # == len(generations)
63        ):
64            raise ValueError("Population attributes must have equal length")
attrs = ('genomes', 'ages', 'births', 'birthdays', 'generations', 'phenotypes', 'infection', 'sizes', 'sexes')
genomes
ages
births
birthdays
phenotypes
infection
sizes
sexes
generations
@staticmethod
def load_pickle_from(path: pathlib.Path):
118    @staticmethod
119    def load_pickle_from(path: pathlib.Path):
120        assert path.exists(), f"pickle_path {path} does not exist"
121        with open(path, "rb") as file_:
122            return pickle.load(file_)
def save_pickle_to(self, path):
124    def save_pickle_to(self, path):
125        with open(path, "wb") as file_:
126            pickle.dump(self, file_)
@staticmethod
def initialize(n, AGE_LIMIT):
128    @staticmethod
129    def initialize(n, AGE_LIMIT):
130        genomes = Genomes(submodels.architect.architecture.init_genome_array(n))
131        ages = np.random.randint(low=0, high=AGE_LIMIT, size=n, dtype=np.int32)
132        births = np.zeros(n, dtype=np.int32)
133        birthdays = np.zeros(n, dtype=np.int32)
134        # generations = np.zeros(n, dtype=np.int32)
135        generations = None
136
137        phenotypes = submodels.architect.__call__(genomes)
138        assert isinstance(phenotypes, Phenotypes)
139
140        infection = np.zeros(n, dtype=np.int32)
141        sizes = np.zeros(n, dtype=np.float32)
142        sexes = submodels.sexsystem.get_sex(n)
143        return Population(
144            genomes=genomes,
145            ages=ages,
146            births=births,
147            birthdays=birthdays,
148            generations=generations,
149            phenotypes=phenotypes,
150            infection=infection,
151            sizes=sizes,
152            sexes=sexes,
153        )
@staticmethod
def make_eggs( offspring_genomes: aegis_sim.dataclasses.genomes.Genomes, step, offspring_sexes, parental_generations):
155    @staticmethod
156    def make_eggs(offspring_genomes: Genomes, step, offspring_sexes, parental_generations):
157        n = len(offspring_genomes)
158        eggs = Population(
159            genomes=offspring_genomes,
160            ages=np.zeros(n, dtype=np.int32),
161            births=np.zeros(n, dtype=np.int32),
162            birthdays=np.zeros(n, dtype=np.int32) + step,
163            # generations=parental_generations + 1,
164            generations=None,
165            # phenotypes=submodels.architect.__call__(offspring_genomes), # Do not compute phenotypes until eggs are laid! Why? Because it is computationally expensive.
166            phenotypes=Phenotypes.init_phenotype_array(n),
167            infection=np.zeros(n, dtype=np.int32),
168            sizes=np.zeros(n, dtype=np.float32),
169            sexes=offspring_sexes,
170        )
171        return eggs