def test_death_z_test(self, reset_herbivore_params, omega_dict): """ Based on H.E. Plesser: biolab/test_bacteria.py Probabilistic test of death function. Testing on herbivores. Given that the sample size is large. Under the Z-test the distribution under the null hypothesis can be estimated approximately by the normal distribution. See https://en.wikipedia.org/wiki/Z-test. Assuming low fitness of animals such that omega can be interpreted as an approximation of the death probability. Testing with different values of omega We compute the number of dead animals returned by our death function from class Animal. Then we compare this value to the mean of dead animals derived from a fixed probability. Null hypothesis: The number of dead animals returned by the death function is statistically significant with a p-value greater than the alpha parameter. Alternative hypothesis: The number of dead animals returned is not statistically significant and we reject the null hypothesis. """ random.seed(123) # High age ensures low fitness herb = Herbivore(age=100, weight=10) # with low fitness we assume that the death probability is the same as omega herb.set_params(omega_dict) # death probability set equal to omega p = Herbivore.p["omega"] # Number of animals N = 1000 # Number of dead animals n = sum(herb.death() for _ in range(N)) # Performing the z-test assert phi_z_test(N, p, n) > TestAnimal.alpha
class TestAnimal: @pytest.fixture(autouse=True) def create_herb(self): """Creates a Herbivore object""" self.herb1 = Herbivore(5, 10) self.herb2 = Herbivore(5, 10) _w = Herbivore._params['zeta'] * (Herbivore._params['w_birth'] + Herbivore._params['sigma_birth']) self.enuf_weight_for_mum = _w self.mum_check_herb = Herbivore(5, self.enuf_weight_for_mum) self.death_prob_herb1 = Herbivore._params['omega'] * ( 1 - self.herb1.fitness()) def test_animal_fitness(self): f1 = self.herb1.fitness() f2 = self.herb2.fitness() assert f1 == pytest.approx( f2), "fitness should be same for same age and weight" def test_animal_dies(self): death_prob = self.death_prob_herb1 print('\n\n Death Probability: ', death_prob) N = 500 n_deaths = sum(self.herb1.dies() for _ in range(N)) print("Number of deaths:", n_deaths) assert binom_test(n_deaths, N, death_prob) > ALPHA
def test_set_params(self): """ Test that parameters can be set """ my_params = {"w_birth": 10, "sigma_birth": 2.5} Herbivore.set_params(my_params) assert Herbivore.p["w_birth"] == 10 assert Herbivore.p["sigma_birth"] == 2.5
def test_aging(self): """ Test that the animal age increases """ herb = Herbivore(weight=10, age=0) carn = Carnivore(weight=10) herb.aging() carn.aging() assert herb.age > 0, carn.age > 0
def create_herb(self): """Creates a Herbivore object""" self.herb1 = Herbivore(5, 10) self.herb2 = Herbivore(5, 10) _w = Herbivore._params['zeta'] * (Herbivore._params['w_birth'] + Herbivore._params['sigma_birth']) self.enuf_weight_for_mum = _w self.mum_check_herb = Herbivore(5, self.enuf_weight_for_mum) self.death_prob_herb1 = Herbivore._params['omega'] * ( 1 - self.herb1.fitness())
def test_add_remove_animals(self, highland_cell): """ :method: LandscapeCell.add_animals :method: LandscapeCell.remove_animals :property: LandscapeCell.animal_count Test that animals can be added and removed correctly """ animals = [Herbivore(), Carnivore(), Herbivore()] highland_cell.add_animals(animals) highland_cell.remove_animals([animals[0], animals[1]]) assert highland_cell.herb_count == 1
def test_eat_fodder(self): """ Weight of animal shall increase after eating fodder """ herb = Herbivore(weight=10, age=0) herb_weight = herb.weight herb.eat_fodder(cell=Lowland()) # new weight herb_weight_after = herb.weight assert herb_weight < herb_weight_after
def test_certain_birth(self, mocker, reset_herbivore_params): """ test give birth function Mock the random number generator to always return one. Then as long as weight is not zero. give_birth function shall return True. """ herb = Herbivore(weight=800, age=5) num_herbs = 10 mocker.patch("random.random", return_value=0) give_birth, _ = herb.give_birth(num_herbs) assert give_birth is True
def test_lose_weight(self, reset_herbivore_params, reset_carnivore_params): """ Test that animals lose weight """ herb, carn = Herbivore(weight=20), Carnivore(weight=20) # Decreasing parameters herb.p['eta'] = 0.1 carn.p['eta'] = 0.2 herb_initial_weight, carn_initial_weight = herb.weight, carn.weight herb.lose_weight(), carn.lose_weight() # New weight of animal must be less than before assert herb.weight < herb_initial_weight assert carn.weight < carn_initial_weight
def set_animal_parameters(species, params): """Set parameters for animal species. :param species: String, name of animal species :param params: Dict with valid parameter specification for species """ if species == "Herbivore": Herbivore.set_params(params) elif species == "Carnivore": Carnivore.set_params(params) else: raise ValueError( "species needs to be either Herbivore or Carnivore!")
def test_sorted_herbivores_and_carnivores(self, highland_cell): """ :method: LandscapeCell.add_animals :method: LandscapeCell.sorted_herbivores :method: LandscapeCell.sorted_carnivores Check that sorting algorithms sort the lists by fitness """ highland_cell.add_animals([Herbivore(weight=50), Herbivore(weight=20)]) highland_cell.add_animals([Carnivore(weight=25), Carnivore(weight=40)]) sorted_herbivores = list( [herb[0] for herb in highland_cell.sorted_herbivores]) sorted_carnivores = highland_cell.sorted_carnivores assert sorted_herbivores == highland_cell.herbivores[::-1] assert sorted_carnivores == highland_cell.carnivores[::-1]
def place_animals(self, listof): """ Places animal objects in cell. Information of animal type is provided by the input. Raises value error if carnivore species is not familias Parameters ---------- listof: list of dictionaries each dictionary has a structure like: (example) {'species': 'Carnivore', 'age': 5, 'weight': 20} """ for dct in listof: get = dct.get("species") if get == 'Herbivore': age = dct.get("age") weight = dct.get("weight") animal = Herbivore(age=age, weight=weight) self.herbivores_list.append(animal) elif get == 'Carnivore': age = dct.get("age") weight = dct.get("weight") animal = Carnivore(age=age, weight=weight) self.carnivores_list.append(animal) else: if get is not None: raise ValueError('Cant place animals rather than herbivore or carnivore')
def test_carn_eat(self, mocker): """ Firstly: To test if the carnivore has the right to eat (first should be able to prey) Secondly: To test for the low weight herbivores it takes longer prey list to fulfill their appetite """ mocker.patch('numpy.random.random', return_value=0) # It will definitely prey assert len(self.animal[1].eat(self.herb_list)) is not 0 herb_list_low = [] herb_list_high = [] for _ in range(20): herb_list_low.append(Herbivore(weight=5)) herb_list_high.append(Herbivore(weight=10)) carn = Carnivore(weight=20) assert len(carn.eat(herb_list_low)) > len(carn.eat(herb_list_high))
def test_constructor(self): """ Animals can be created """ herb = Herbivore(weight=10, age=0) carn = Carnivore() assert isinstance(herb, Herbivore), isinstance(carn, Carnivore)
def create_animal(self): """ Create animal object """ self.animal = [Herbivore(), Carnivore()] self.herb_list = [self.animal[0]] self.init_weight = []
def add_population(self, population): """Add a population to specific `island` cells by providing a list of dictionaries. :param population: List of dictionaries specifying population :Example: .. code-block:: python example_pop = { 'loc': (4,4), 'pop': [ {'species': 'Herbivore', 'age': 2, 'weight': 60}, {'species': 'Herbivore', 'age': 9, 'weight': 30}, {'species': 'Herbivore', 'age': 16, 'weight': 14} ] } """ if type(population) == list: for loc_dict in population: # This loop will be replaced with a more elegant iteration new_animals = [ Herbivore.from_dict(animal_dict) if animal_dict["species"] == "Herbivore" else Carnivore.from_dict(animal_dict) for animal_dict in loc_dict["pop"] ] self._island.landscape[loc_dict["loc"]].add_animals( new_animals) self._island.count_animals(animal_list=new_animals) else: raise ValueError( f"Pop list needs to be a list of dicts! Was of type " f"{type(population)}.")
def procreation(self, cell): """Iterates through each animal in the cell and procreates. :param cell: Current cell object :type cell: object """ new_herbs = [] new_carns = [] n_herbs, n_carns = cell.herb_count, cell.carn_count for herb in cell.herbivores: # Herbivores give birth) give_birth, birth_weight = herb.give_birth(n_herbs) if give_birth: new_herbs.append(Herbivore(weight=birth_weight, age=0)) for carn in cell.carnivores: # Carnivores give birth give_birth, birth_weight = carn.give_birth(n_carns) if give_birth: new_carns.append(Carnivore(weight=birth_weight, age=0)) cell.add_animals(new_herbs + new_carns) # Add new animals to cell self._island.count_animals(num_herbs=len(new_herbs), num_carns=len(new_carns))
def test_set_invalid_params(self, reset_herbivore_params): """ Test errors with illegal keys and values """ with pytest.raises(KeyError): assert Herbivore.p["w_death"] with pytest.raises(ValueError): assert Herbivore.set_params({"sigma_birth": -5})
def place_animals_in_list(self, list_of_diction): for animal in list_of_diction: if animal['species'] == "Herbivore": self._herb_list.append( Herbivore(age=animal['age'], weight=animal['weight'])) if animal['species'] == "Carnivore": self._carn_list.append( Carnivore(age=animal['age'], weight=animal['weight']))
def animals(self): """ create animals of different type, age and weight to use in test of fitness """ animals = [ Herbivore(age=0, weight=5), Herbivore(age=0, weight=1000), Herbivore(age=100, weight=5), Herbivore(age=100, weight=1000), Herbivore(age=0, weight=5), Carnivore(age=0, weight=5), Carnivore(age=0, weight=1000), Carnivore(age=100, weight=5), Carnivore(age=100, weight=1000) ] return animals
def test_mean_birth_weight(self, birth_dict, reset_herbivore_params): """ Test that the birth weight of animals are normal distributed using the normaltest from scipy. https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.normaltest.html Null hypothesis: The birth weight of the animal is normally distributed Alternative hypothesis: The birth weight are not normally distributed. We keep the null hypothesis if the p-value is larger than the significance level alpha """ random.seed(123) N = 1000 Herbivore.set_params(birth_dict) herb_birth_weights = [ Herbivore(age=5, weight=20).birth_weight for _ in range(N) ] k2, phi = stats.normaltest(herb_birth_weights) assert phi > TestAnimal.alpha
def test_animal_fitness(self, biosim): """ :property: Island.animal_fitness Test that animal fitness property is of correct shape and value """ fixed_herb_fitness = Herbivore(weight=20, age=5).fitness fixed_carn_fitness = Carnivore(weight=25, age=4).fitness assert biosim._island.animal_fitness == [[ fixed_herb_fitness, fixed_herb_fitness, fixed_herb_fitness ], [fixed_carn_fitness, fixed_carn_fitness]]
def test_shuffle_herbs(self, highland_cell): """ :method: LandscapeCell.add_animals :method: LandscapeCell.randomize_herbs Test that shuffle method shuffles herbivores list """ highland_cell.add_animals([Herbivore() for _ in range(1000)]) original_herbs = [animal for animal in highland_cell.herbivores] highland_cell.randomize_herbs() assert highland_cell.herbivores != original_herbs
def test_count_del_animals(self, island): """ :method: Island.count_animals :method: Island.del_animals Test counting and removing animals with lists passed and arguments only """ island.count_animals(num_herbs=10, num_carns=10) island.del_animals(animal_list=[Herbivore()]) island.del_animals(num_herbs=5, num_carns=5) assert island.num_animals == 9 assert island.num_herbs == 4 assert island.num_carns == 5
def test_kill_prey(self): """ Test kill prey. With a high fitness diff the carnivore will always kill the herbivore. """ carn = Carnivore(age=5, weight=30) herb_list = [Herbivore(age=100, weight=50) for _ in range(100)] mock_sorted_list = [(herb, herb.fitness) for herb in herb_list] kill_count = 0 for _ in mock_sorted_list: if carn.kill_prey(mock_sorted_list): kill_count += 1 assert kill_count == 100
def test_reset_animals(self, highland_cell): """ :method: LandscapeCell.add_animal :method: LandscapeCell.reset_animals :property: LandscapeCell.carnivores :property: LandscapeCell.has_moved Test that has_moved property is correctly set and reset """ highland_cell.add_animals([Carnivore(), Herbivore()]) highland_cell.carnivores[0].has_moved = True highland_cell.reset_animals() assert highland_cell.carnivores[0].has_moved is False
def test_mother_weight_condition(self, mocker): """ To test if the mother gives birth to the child and its weight decreases by a certain amount, the child should not be born and the mother's weight must remain unchanged """ animal_low_weight = [Herbivore(weight=0.5), Carnivore(weight=0.5)] # herbivore and carnivore with enough low weight for animal in animal_low_weight: mocker.patch('numpy.random.random', return_value=0) # To be sure the create_newborn # is None due to the weight of mother not the probability assert animal.create_newborn(2) is None
def test_single_procreation(self): """ test that the initial herbivore population will not reproduce a newborn population of greater numbers during a year cycle. Each mother can at most give birth to one animal. A high fitness and gamma parameter ensures highly fertile animals. """ num_newborns = 0 adult_herbs = [Herbivore(age=5, weight=40) for _ in range(100)] num_adults = len(adult_herbs) for herb in adult_herbs: herb.set_params(({"gamma": 0.99})) if herb.give_birth(num_adults): num_newborns += 1 assert num_newborns <= num_adults
def test_give_birth(self, gamma_dict, reset_herbivore_params): """Test that for animals with fitness close to one, and two animals of same type one specie in a cell. The give_birth function should be well approximated by the parameter gamma. An we test this against our function under the significance level alpha. Null hypothesis: The give_birth function returns correct with fixed gamma Alternative hypothesis: The give_birth function does not return correct. We reject our null hypothesis. """ random.seed(123) N = 1000 Herbivore.set_params(gamma_dict) num_herbs = 2 p = gamma_dict["gamma"] list_birth = [ Herbivore(weight=200, age=5).give_birth(num_herbs) for _ in range(N) ] # number when births return True n = sum([item[0] for item in list_birth]) mean = N * p assert phi_z_test(N, p, n) > TestAnimal.alpha
def test_weight_gain(self, reset_carnivore_params, reset_herbivore_params, params): """ Testing weight gain of carnivores. Assuming they have access to more fodder than they will eat. Making old heavy herbivores with low fitness. Carnivores should add beta * F weight Assuming fitness diff is larger than DeltaPhiMax such that the carnivore always kills the herbivore. """ carn = Carnivore(age=5, weight=40) # number of herbivores N = 1000 herb_list = [Herbivore(age=100, weight=200) for _ in range(N)] mock_sorted_list = [(herb, herb.fitness) for herb in herb_list] initial_weight = carn.weight _ = carn.kill_prey(mock_sorted_list) new_weight = carn.weight assert new_weight == initial_weight + carn.p["beta"] * carn.p["F"]