Exemplo n.º 1
0
    def test_function_runs_at_population_level(self):
        fakepop = Pop(fit_fun='policingdemog', inst='test/test')
        fakepop.numberOfDemes = 3
        fakepop.initialDemeSize = 4

        fakepop.createAndPopulateDemes()
        fakepop.clearDemeInfo()
        fakepop.populationMutationMigration()
        fakepop.updateDemeInfoPreProduction()
        fakepop.populationProduction()
        fakepop.updateDemeInfoPostProduction()

        try:
            fakepop.populationReproduction()
        except:
            assert False, "not running"
    def _foo(fitfun='pgg'):
        fakepop = Pop(inst='test/test')
        fakepop.numberOfDemes = 3
        fakepop.initialDemeSize = 10
        fakepop.fitnessParameters = fitpardict[fitfun]
        fakepop.fit_fun = fitfun
        fakepop.mutationRate = 0
        fakepop.migrationRate = 0
        fakepop.createAndPopulateDemes()
        for i in range(fakepop.demography):
            fakepop.individuals[i].resourcesAmount = i * 2
        parents = fakepop.individuals

        for ind in range(len(parents)):
            indiv = fakepop.individuals[ind]
            indiv.resourcesAmount = ind * 2
        fakepop.clearDemeInfo()
        fakepop.populationMutationMigration()
        fakepop.updateDemeInfoPreProduction()
        fakepop.populationProduction()
        fakepop.updateDemeInfoPostProduction()
        fakepop.populationReproduction()
        return (fakepop, parents)
class TestDebateFeature(object):
    def test_individuals_invest_time_into_debate(self):
        self.ind = Ind()
        assert hasattr(
            self.ind,
            "consensusTime"), "the individual does not have time for debate"

    def test_deme_has_consensus(self):
        self.deme = Dem()
        assert "consensus" in self.deme.politicsValues, "the deme cannot reach consensus"
        assert "consensusTime" in self.deme.politicsValues, "reaching consensus does not take any time"

    def test_debate_fitness_function_exists(self, getFitnessParameters):
        self.ind = Ind()
        self.ind.neighbours = [0]
        self.ind.resourcesAmount = 10
        pars = getFitnessParameters('debate')

        try:
            self.ind.reproduce('debate', **{**{'productivity': 0.6}, **pars})
        except ValueError as e:
            assert False, "include a debate function"

    def test_consensus_is_aggregate_of_opinions(self):
        self.pop = Pop(inst='test/test')
        self.pop.fit_fun = 'debate'
        self.pop.initialPhenotypes = [0.1, 0.2, 0.3, 0.4]
        self.pop.numberOfDemes = 3
        self.pop.initialDemeSize = 2
        self.pop.mutationRate = 0
        self.pop.migrationRate = 0

        self.pop.createAndPopulateDemes()
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()

        for deme in self.pop.demes:
            assert deme.politicsValues[
                "consensus"] == 0.3, "wrong consensus value"

    def test_consensus_takes_time_to_reach(self):
        self.pop = Pop(inst='test/test')
        self.pop.fit_fun = 'debate'
        self.pop.initialPhenotypes = [0.1, 0.2, 0.3, 0.4]
        self.pop.numberOfDemes = 3
        self.pop.initialDemeSize = 2
        self.pop.mutationRate = 0
        self.pop.migrationRate = 0

        self.pop.createAndPopulateDemes()
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()

        for deme in self.pop.demes:
            assert deme.politicsValues[
                "consensusTime"] is not None, "consensus reaching time has not been calculated"
            assert deme.politicsValues[
                "consensusTime"] > 0, "consensus reaching should take a bare minimum of time"
            disagreement = self.pop.fitnessParameters[
                "aconsensus"] * deme.demography * deme.varPhenotypes[2]
            assert deme.politicsValues[
                "consensusTime"] == self.pop.fitnessParameters[
                    "epsilon"] + disagreement / (
                        self.pop.fitnessParameters["bconsensus"] +
                        disagreement)

    def test_consensus_time_affects_individual_time_for_production(self):
        self.pop = Pop(inst='test/test')
        self.pop.fit_fun = 'debate'
        self.pop.initialPhenotypes = [0.1, 0.2, 0.3, 0.4]
        self.pop.numberOfDemes = 3
        self.pop.initialDemeSize = 2
        self.pop.mutationRate = 0
        self.pop.migrationRate = 0

        self.pop.createAndPopulateDemes()
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()

        for deme in self.pop.demes:
            assert "productionTime" in deme.politicsValues, deme.politicsValues
            assert deme.politicsValues[
                "productionTime"] == 1 - deme.politicsValues[
                    "consensusTime"], "wrong individual production time"

    def test_consensus_value_defines_policing_amount(self):
        self.pop = Pop(inst='test/test')
        self.pop.fit_fun = 'debate'
        self.pop.initialPhenotypes = [0.1, 0.2, 0.3, 0.4]
        self.pop.numberOfDemes = 3
        self.pop.initialDemeSize = 2
        self.pop.mutationRate = 0
        self.pop.migrationRate = 0

        self.pop.createAndPopulateDemes()
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()
        self.pop.populationProduction()
        self.pop.updateDemeInfoPostProduction()

        allres = [0] * self.pop.numberOfDemes
        for ind in self.pop.individuals:
            allres[ind.currentDeme] += ind.resourcesAmount

        for deme in self.pop.demes:
            assert deme.progressValues["institutionQuality"] is not None
            assert deme.progressValues["institutionQuality"] == (
                deme.politicsValues['consensus'] * deme.publicGood *
                self.pop.fitnessParameters['aquality'] /
                allres[deme.id])**self.pop.fitnessParameters['alphaquality']
            assert deme.progressValues["fineBudget"] is not None
            assert deme.progressValues["fineBudget"] == deme.politicsValues[
                'consensus'] * deme.publicGood * (
                    1 - self.pop.fitnessParameters['aquality'])

    def test_individual_consensus_time_always_less_than_one(self):
        self.pop = Pop(inst='test/test')
        self.pop.fit_fun = 'debate'
        self.pop.initialPhenotypes = [0.1, 0.2, 0.3, 0.4]
        self.pop.numberOfDemes = 3
        self.pop.initialDemeSize = 2
        self.pop.mutationRate = 0
        self.pop.migrationRate = 0

        self.pop.createAndPopulateDemes()
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()

        for deme in self.pop.demes:
            assert deme.politicsValues[
                'consensusTime'] < 1, "epsilon is {2} so asymptote should be: {1}. variance in opinions: {0}".format(
                    deme.varPhenotypes[2],
                    self.pop.fitnessParameters['epsilon'] + 1,
                    self.pop.fitnessParameters['epsilon'])

    def test_production_depends_on_debate_time(self, getFitnessParameters):
        fitfun = 'debate'
        pars = getFitnessParameters(fitfun)
        self.firstInd = Ind()
        self.firstInd.produceResources(fitfun, **{
            **{
                'productionTime': 0.8
            },
            **pars
        })

        self.secndInd = Ind()
        self.secndInd.produceResources(fitfun, **{
            **{
                'productionTime': 0.2
            },
            **pars
        })

        assert self.firstInd.resourcesAmount > self.secndInd.resourcesAmount, "Individual with {0}% production time should get more resources than individual with {1}%".format(
            self.firstInd.productionTime * 100,
            self.secndInd.productionTime * 100)

    def test_fitness_depends_on_debate_time(self, getFitnessParameters):
        fitfun = 'debate'
        pars = getFitnessParameters(fitfun)
        self.firstInd = Ind()
        self.firstInd.neighbours = [1, 2]
        self.firstInd.produceResources(fitfun, **{
            **{
                'productionTime': 0.8
            },
            **pars
        })
        self.firstInd.reproduce(fitfun, **pars)

        self.secndInd = Ind()
        self.secndInd.neighbours = [1, 2]
        self.secndInd.produceResources(fitfun, **{
            **{
                'productionTime': 0.2
            },
            **pars
        })
        self.secndInd.reproduce(fitfun, **pars)

        assert self.firstInd.fertilityValue > self.secndInd.fertilityValue, "Individual with {0}% production time should have higher fitness than individual with {1}%".format(
            self.firstInd.productionTime * 100,
            self.secndInd.productionTime * 100)
class TestPolicingFunction(object):
    def test_policing_function_returns_value_correct_format(
            self, getFitnessParameters):
        pars = getFitnessParameters('policing')
        reproductiveValue = fitness.functions['policing'](1, **pars)

        assert reproductiveValue is not None, "Fitness function with policing returns None"
        assert type(
            reproductiveValue
        ) is float, "Fitness function with policing returns a {0} instead of a float".format(
            type(reproductiveValue))
        assert reproductiveValue >= 0, "Fitness function with policing returns a negative value"

        gc.collect()

    def test_fertility_depends_on_public_good(self, getFitnessParameters):
        fitfun = 'policing'
        self.fakepop = Pop(fit_fun=fitfun, inst='test/test')
        self.fakepop.fitnessParameters = getFitnessParameters(fitfun)
        self.fakepop.numberOfDemes = 2
        self.fakepop.initialDemeSize = 1
        self.fakepop.individualResources = 4
        self.fakepop.initialPhenotypes = [0.2, 0.3]
        self.fakepop.numberOfPhenotypes = len(self.fakepop.initialPhenotypes)
        self.fakepop.migrationRate = 0
        self.fakepop.mutationRate = 0

        self.fakepop.createAndPopulateDemes()
        self.fakepop.clearDemeInfo()
        self.fakepop.populationMutationMigration()

        for ind in range(self.fakepop.demography):
            indiv = self.fakepop.individuals[ind]
            if indiv.currentDeme == 0:
                self.fakepop.fitnessParameters.update({"pg": 1})
                indiv.fertility(self.fakepop.fit_fun,
                                **self.fakepop.fitnessParameters)
                fertility0 = indiv.fertilityValue
            elif indiv.currentDeme == 1:
                self.fakepop.fitnessParameters.update({"pg": 3})
                indiv.fertility(self.fakepop.fit_fun,
                                **self.fakepop.fitnessParameters)
                fertility1 = indiv.fertilityValue

        assert fertility0 < fertility1

        gc.collect()

    def test_individual_fertility_calculation(self, getFitnessParameters):
        fitfun = 'policing'
        kwargs = getFitnessParameters(fitfun)
        self.fakepop = Pop(fit_fun=fitfun, inst='test/test')
        self.fakepop.fitnessParameters = kwargs
        self.fakepop.numberOfDemes = 2
        self.fakepop.initialDemeSize = 10
        self.fakepop.initialPhenotypes = kwargs["x"]
        self.fakepop.numberOfPhenotypes = len(self.fakepop.initialPhenotypes)
        self.fakepop.migrationRate = 0
        self.fakepop.mutationRate = 0

        self.fakepop.createAndPopulateDemes()
        self.fakepop.clearDemeInfo()
        self.fakepop.populationMutationMigration()

        for ind in self.fakepop.individuals:
            assert ind.fertilityValue is None
            ind.resourcesAmount = 2
            ind.fertility(fitfun, **kwargs)
            x = kwargs["x"][0]
            y = kwargs["x"][1]
            p = kwargs["pg"]
            n = kwargs["n"]
            payoff = (1 - x) * ind.resourcesAmount + kwargs["b"] * (1 - y) * (
                p / n) - kwargs["c"] * y * ((1 - x)**2) * (p / n)
            assert payoff == 1.11925, "pars: x={0},y={1},res={2},b={3},pg={4},n={5},c={6}".format(
                x, y, ind.resourcesAmount, kwargs["b"], p, n, kwargs["c"])
            assert (kwargs["fb"] * payoff) / (
                kwargs["gamma"] *
                n) == 22.385, "pars: fb={0},p-off={1},gamma={2},n={3}".format(
                    kwargs["fb"], payoff, kwargs["gamma"], n)
            assert ind.fertilityValue == (kwargs["fb"] * payoff) / (
                kwargs["gamma"] *
                n), "Fitness function does not return what is expected"
            assert ind.fertilityValue == 22.385, "python disagrees with mathematica. Payoff {0}(p) vs {1}(m). Parameters: {2}".format(
                payoff, 1.11925, kwargs)

        gc.collect()

    def test_population_fertility_calculation(self):
        fitfun = 'policing'
        self.fakepop = Pop(fit_fun=fitfun, inst='test/test')
        self.fakepop.fitnessParameters = {
            "b": 0.5,
            "c": 0.05,
            "fb": 2,
            "gamma": 0.01
        }
        self.fakepop.numberOfDemes = 2
        self.fakepop.initialDemeSize = 10
        self.fakepop.individualResources = 2
        self.fakepop.initialPhenotypes = [0.2, 0.5]
        self.fakepop.numberOfPhenotypes = len(self.fakepop.initialPhenotypes)
        self.fakepop.migrationRate = 0
        self.fakepop.mutationRate = 0

        self.fakepop.createAndPopulateDemes()
        self.fakepop.clearDemeInfo()
        self.fakepop.populationMutationMigration()

        x = self.fakepop.initialPhenotypes[0]
        y = self.fakepop.initialPhenotypes[1]
        r = self.fakepop.individualResources
        b = self.fakepop.fitnessParameters["b"]
        c = self.fakepop.fitnessParameters["c"]
        fb = self.fakepop.fitnessParameters["fb"]
        gamma = self.fakepop.fitnessParameters["gamma"]
        n = self.fakepop.initialDemeSize
        p = x * r * n

        payoff = (1 - x) * r + b * (1 - y) * (p / n) - c * y * (p / n) * (
            (1 - x)**2)
        expectedFertility = (fb * payoff) / (gamma * n)

        for indiv in self.fakepop.individuals:
            indiv.resourcesAmount = 2
            # REPRODUCTION
            infoToAdd = {}
            infoToAdd["n"] = self.fakepop.demes[indiv.currentDeme].demography
            assert infoToAdd["n"] == n, "group size changed"
            infoToAdd["xmean"] = self.fakepop.demes[
                indiv.currentDeme].meanPhenotypes
            infoToAdd["pg"] = p
            assert infoToAdd["pg"] == p, "pg changed"
            infoToAdd["x"] = indiv.phenotypicValues
            assert infoToAdd["x"] == [x, y], "phenotypes changed"

            test = fitness.functions['policing'](r, **{
                **self.fakepop.fitnessParameters,
                **infoToAdd
            })
            assert test == expectedFertility, "pars fed to function = res: {1}, {0}".format(
                {
                    **self.fakepop.fitnessParameters,
                    **infoToAdd
                }, indiv.resourcesAmount)
            #assert False, test

            indiv.fertility(self.fakepop.fit_fun, **{
                **self.fakepop.fitnessParameters,
                **infoToAdd
            })
            assert indiv.fertilityValue == expectedFertility, "pars fed to function {2} = res: {1}, {0}".format(
                {
                    **self.fakepop.fitnessParameters,
                    **infoToAdd
                }, indiv.resourcesAmount, self.fakepop.fit_fun)

            indiv.reproduce(self.fakepop.fit_fun, **{
                **self.fakepop.fitnessParameters,
                **infoToAdd
            })
            assert indiv.fertilityValue == expectedFertility, "pars fed to function {2} = res: {1}, {0}".format(
                {
                    **self.fakepop.fitnessParameters,
                    **infoToAdd
                }, indiv.resourcesAmount, self.fakepop.fit_fun)

        gc.collect()

    def test_policing_function_in_population_reproduction(self):
        self.fakepop = Pop(inst='test/test', fit_fun='policing')
        self.fakepop.numberOfDemes = 3
        self.fakepop.initialDemeSize = 3
        self.fakepop.createAndPopulateDemes()
        self.fakepop.clearDemeInfo()
        self.fakepop.populationMutationMigration()
        self.fakepop.updateDemeInfoPreProduction()
        self.fakepop.populationProduction()
        self.fakepop.updateDemeInfoPostProduction()

        try:
            self.fakepop.populationReproduction()
        except Exception as e:
            assert False, "something went wrong, raised {0}: {1}".format(
                e.__class__.__name__, str(e))

    def test_deme_has_policing_consensus(self):
        self.fakeDeme = Dem()

        assert "consensus" in self.fakeDeme.politicsValues
class TestPopulation(object):
    def test_population_contains_demes(self):
        self.pop = Pop(inst='test/test')
        self.pop.createAndPopulateDemes()
        assert hasattr(self.pop, "demes"), "This population has no deme yet!"

        for deme in self.pop.demes:
            assert type(deme) is Dem

        gc.collect()

    def test_identify_deme_neighbours(self):
        self.fakepop = Pop(inst='test/test')
        self.nd = self.fakepop.numberOfDemes

        for deme in range(self.nd):
            newDemeInstance = Dem()
            newDemeInstance.id = deme
            assert deme in range(self.nd)
            newDemeInstance.neighbours = self.fakepop.identifyNeighbours(
                self.nd, deme)
            assert deme not in newDemeInstance.neighbours, "Deme {0} counts itself as a neighbour".format(
                deme)
            assert all(
                x in range(self.nd) for x in newDemeInstance.neighbours
            ), "Neighbour(s) of deme {0} are missing: takes into account {1} out of its {2} neighbours".format(
                deme, newDemeInstance.neighbours, self.nd - 1)

        gc.collect()

    def test_demes_are_populated(self):
        self.pop = Pop(inst='test/test')
        self.pop.createAndPopulateDemes()
        for deme in self.pop.demes:
            assert deme.demography is not None, "Deme {0} is not populated".format(
                deme)

        gc.collect()

    def test_individual_attributes_are_non_empty(self,
                                                 objectAttributesAreNotNone):
        self.pop = Pop(inst='test/test')
        self.pop.createAndPopulateDemes()
        for ind in self.pop.individuals:
            testObj, attrObj = objectAttributesAreNotNone(
                ind, ["phenotypicValues", "currentDeme"])
            assert testObj, "Individual {0} has attribute(s) {1} set to None".format(
                ind, attrObj)

        gc.collect()

    def test_population_has_the_right_size(self):
        self.howManyDemes = 10
        self.howManyIndividualsPerDeme = 10
        self.pop = Pop(inst='test/test')
        self.pop.createAndPopulateDemes(nDemes=self.howManyDemes,
                                        dSize=self.howManyIndividualsPerDeme)

        assert len(
            self.pop.individuals
        ) == self.howManyIndividualsPerDeme * self.howManyDemes, "You created a population of {0} individuals instead of {1}!".format(
            len(self.pop.individuals),
            self.howManyIndividualsPerDeme * self.howManyDemes)

    def test_population_has_fitness_method_or_pgg_parameters(self):
        self.fakepop = Pop(inst='test/test')

        assert hasattr(self.fakepop,
                       "fitnessParameters"), "Provide fitness parameters"

        if not hasattr(self.fakepop, "fitnessMethod"):
            for key in ["fb", "b", "c", "gamma"]:
                assert key in self.fakepop.fitnessParameters, "PGG parameter {0} not provided".format(
                    key)

    def test_simulation_stops_if_population_extinct(self):
        self.fakepop = Pop(inst='test/test')
        self.fakepop.numberOfDemes = 10
        self.fakepop.numberOfGenerations = 10

        self.fakepop.fitnessParameters[
            "fb"] = 0.0001  # to make the population die out

        self.fakepop.createAndPopulateDemes()
        assert self.fakepop.demography == self.fakepop.numberOfDemes * self.fakepop.initialDemeSize

    def test_population_mutation_updates_individual_phenotypes(self):
        self.fakepop = Pop(inst='test/test')
        self.fakepop.numberOfDemes = 2
        self.fakepop.initialDemeSize = 50
        self.fakepop.migrationRate = 0
        self.fakepop.mutationRate = 1
        # the two following lines are very important so that the test does not fail at the boundaries,
        # e.g. if phen = 0 and dev < 0, mutated phenotype will still be 0
        self.fakepop.initialPhenotypes = [0.5]
        self.fakepop.numberOfPhenotypes = 1

        self.fakepop.createAndPopulateDemes(nDemes=self.fakepop.numberOfDemes,
                                            dSize=self.fakepop.initialDemeSize)

        origPhenDeme0 = []
        origPhenDeme1 = []

        for ind in self.fakepop.individuals:
            if ind.currentDeme == 0:
                origPhenDeme0.append(ind.phenotypicValues[0])
            elif ind.currentDeme == 1:
                origPhenDeme1.append(ind.phenotypicValues[0])

        self.fakepop.clearDemeInfo()
        self.fakepop.populationMutationMigration()

        phenDeme0 = []
        devDeme0 = []
        phenDeme1 = []
        devDeme1 = []

        for ind in self.fakepop.individuals:
            if ind.currentDeme == 0:
                phenDeme0.append(ind.phenotypicValues[0])
                devDeme0.append(ind.mutationDeviation[0])
            elif ind.currentDeme == 1:
                phenDeme1.append(ind.phenotypicValues[0])
                devDeme1.append(ind.mutationDeviation[0])

        assert len(origPhenDeme0) == len(
            phenDeme0
        ), "Number of individuals in deme 0 have changed from {0} to {1} after mutation".format(
            len(origPhenDeme0), len(phenDeme0))
        assert len(origPhenDeme1) == len(
            phenDeme1
        ), "Number of individuals in deme 1 have changed from {0} to {1} after mutation".format(
            len(origPhenDeme1), len(phenDeme1))

        for i in range(self.fakepop.initialDemeSize):
            assert origPhenDeme0[i] != phenDeme0[
                i], "Individual {0} in deme 0 mutated from {1} to {2} when deviation was supposed to be {3}".format(
                    i, origPhenDeme0[i], phenDeme0[i], devDeme0[i])
            assert origPhenDeme1[i] != phenDeme1[
                i], "Individual {0} in deme 1 mutated from {1} to {2} when deviation was supposed to be {3}".format(
                    i, origPhenDeme1[i], phenDeme1[i], devDeme1[i])

    def test_demes_update_function(self):
        self.fakepop = Pop(inst='test/test')
        self.fakepop.numberOfDemes = 2

        self.fakepop.createAndPopulateDemes()
        self.fakepop.clearDemeInfo()
        self.fakepop.populationMutationMigration()

        demogdeme0 = self.fakepop.demes[0].demography
        phendeme0 = self.fakepop.demes[0].totalPhenotypes[0]
        demogdeme1 = self.fakepop.demes[1].demography
        phendeme1 = self.fakepop.demes[1].totalPhenotypes[0]

        self.fakepop.updateDemeInfoPreProduction()
        self.fakepop.populationProduction()
        self.fakepop.updateDemeInfoPostProduction()

        assert self.fakepop.demes[0].meanPhenotypes[0] == ar.specialdivision(
            phendeme0, demogdeme0)
        assert self.fakepop.demes[1].meanPhenotypes[0] == ar.specialdivision(
            phendeme1, demogdeme1)
class TestTechnology(object):
    def test_deme_technology_is_right_format(self):
        self.pop = Pop(fit_fun='technology', inst='test/test')
        self.pop.numberOfDemes = 2
        self.pop.initialDemeSize = 3
        #self.fakeDeme.publicGood = 20
        self.pop.initialPhenotypes = [0.5] * 4
        self.pop.createAndPopulateDemes()

        assert self.pop.demes[
            0].technologyLevel is self.pop.initialTechnologyLevel

        self.pop.clearDemeInfo()

        assert self.pop.demes[0].technologyLevel is not None
        assert type(self.pop.demes[0].technologyLevel) is float
        assert self.pop.demes[0].technologyLevel >= 0

        gc.collect()

    def test_deme_has_consensus_policing_level(self):
        self.fakeDeme = Dem()

        try:
            tmp = getattr(self.fakeDeme, "politicsValues")
            get = tmp['consensus']
        except AttributeError as e:
            assert False, "where is the policing consensus?"

        gc.collect()

    # def test_deme_policing_consensus_of_right_format(self, instantiateSingleIndividualsDemes):
    # 	gc.collect()

    # 	self.fakepop = instantiateSingleIndividualsDemes(2)

    # 	self.fakepop.clearDemeInfo()
    # 	self.fakepop.populationMutationMigration()
    # 	self.fakepop.update()

    # 	for dem in self.fakepop.demes:
    # 		assert dem.policingConsensus is not None, "No value in the policing consensus"
    # 		assert dem.policingConsensus >= 0, "Policing consensus shouldn't be negative"
    # 		assert type(dem.policingConsensus) is float, "Policing consensus should be float, not {0} ({1})".format(type(dem.policingConsensus),dem.policingConsensus)
    # 		if dem.demography > 0:
    # 			assert dem.policingConsensus == dem.meanPhenotypes[1], "Group size: {0}, phenotypes: {1}".format(dem.demography, [i.phenotypicValues for i in self.fakepop.individuals if i.currentDeme == dem.id])
    # 		else:
    # 			assert dem.policingConsensus == 0, "It would seem we have a format issue: deme mean phenotypes are {0}".format(dem.meanPhenotypes)

    def test_technology_fitness_function_exists(self, getFitnessParameters):
        self.indiv = Ind()
        self.indiv.phenotypicValues = [0.5, 0.2, 0.3]
        self.indiv.resourcesAmount = 5
        self.indiv.neighbours = [0, 2]

        try:
            self.pars = getFitnessParameters("technology")
            self.indiv.reproduce(
                "technology", **{
                    **{
                        'fine': 0.4,
                        'investmentReward': 0.6
                    },
                    **self.pars
                })
        except KeyError as e:
            assert False, "{0}".format(e)

        gc.collect()

    # def test_individuals_return_goods(self, getFitnessParameters):
    # 	self.indiv = Ind()

    # 	self.pars = getFitnessParameters("technology")
    # 	self.indiv.reproduce("technology", **self.pars)

    # 	assert self.indiv.punishmentFee is not None
    # 	assert type(self.indiv.punishmentFee) is float
    # 	assert self.indiv.punishmentFee >= 0

    # def test_returned_goods_get_calculated_and_in_right_format(self, instantiateSingleIndividualsDemes):
    # 	self.fakepop = instantiateSingleIndividualsDemes(2)

    # 	self.fakepop.clearDemeInfo()
    # 	self.fakepop.populationMutationMigration()
    # 	self.fakepop.update()

    # 	for dem in self.fakepop.demes:
    # 		assert dem.returnedGoods is not None, "No value in the effective public good"
    # 		assert dem.returnedGoods >= 0, "Effective public good shouldn't be negative"
    # 		assert type(dem.returnedGoods) is float, "Effective public good should be float, not {0}".format(type(dem.effectivePublicGood))

    # 		# resources = 0

    # 		# for ind in self.fakepop.individuals:
    # 		# 	if ind.currentDeme == dem:
    # 		# 		ind.

    # 		# assert dem.returnedGoods ==

    # def test_individual_returns_resources(self, getFitnessParameters):
    # 	ndemes = 3
    # 	initdemesize = 2
    # 	pars = getFitnessParameters('technology')
    # 	fitfun = 'technology'
    # 	phen = [0.5] * 3

    # 	## WHEN THERE IS NO POLICING, NO GOODS ARE RETURNED
    # 	self.fakepopNoPolicing = Pop(fit_fun=fitfun, inst='test')
    # 	self.fakepopNoPolicing.fit_fun = fitfun
    # 	self.fakepopNoPolicing.fitnessParameters = pars
    # 	self.fakepopNoPolicing.nDemes = ndemes
    # 	self.fakepopNoPolicing.initialDemeSize = initdemesize
    # 	self.fakepopNoPolicing.initialPhenotypes = phen
    # 	self.fakepopNoPolicing.migrationRate = 0
    # 	self.fakepopNoPolicing.fitnessParameters.update({'p':0})

    # 	self.fakepopNoPolicing.createAndPopulateDemes()
    # 	self.fakepopNoPolicing.clearDemeInfo()
    # 	self.fakepopNoPolicing.populationMutationMigration()
    # 	self.fakepopNoPolicing.updateDemeInfo()

    # 	collectGoods = [0] * self.fakepopNoPolicing.numberOfDemes
    # 	for ind in self.fakepopNoPolicing.individuals:
    # 		collectGoods[ind.currentDeme] += ind.resourcesAmount * ind.phenotypicValues[0]
    # 	for dem in range(self.fakepopNoPolicing.numberOfDemes):
    # 		assert self.fakepopNoPolicing.fit_fun == 'technology'
    # 		assert self.fakepopNoPolicing.fitnessParameters['p'] == 0
    # 		assert self.fakepopNoPolicing.demes[dem].progressValues['effectivePublicGood'] == self.fakepopNoPolicing.demes[dem].publicGood
    # 		assert self.fakepopNoPolicing.demes[dem].progressValues['effectivePublicGood'] == collectGoods[dem]

    # 	## WHEN THERE IS POLICING, GOODS MUST BE RETURNED
    # 	self.fakepopPolicing = Pop(fit_fun=fitfun, inst='test')
    # 	self.fakepopPolicing.fitnessParameters = pars
    # 	self.fakepopPolicing.nDemes = ndemes
    # 	self.fakepopPolicing.initialDemeSize = initdemesize
    # 	self.fakepopPolicing.initialPhenotypes = phen
    # 	self.fakepopPolicing.migrationRate = 0
    # 	self.fakepopPolicing.fitnessParameters.update({'p':0.8})

    # 	self.fakepopPolicing.createAndPopulateDemes()
    # 	self.fakepopPolicing.clearDemeInfo()
    # 	self.fakepopPolicing.populationMutationMigration()
    # 	self.fakepopPolicing.updateDemeInfo()

    # 	collectGoods = [0] * self.fakepopPolicing.numberOfDemes
    # 	for ind in self.fakepopPolicing.individuals:
    # 		collectGoods[ind.currentDeme] += ind.resourcesAmount * ind.phenotypicValues[0]
    # 	for dem in range(self.fakepopPolicing.numberOfDemes):
    # 		assert self.fakepopPolicing.demes[dem].progressValues['effectivePublicGood'] > collectGoods[dem] * (1-self.fakepopPolicing.fitnessParameters['p']), "goods are not returned after policing"

    # def test_effective_public_good_of_right_format(self, instantiateSingleIndividualsDemes):
    # 	self.fakepop = instantiateSingleIndividualsDemes(2)
    # 	self.fakepop.fit_fun = 'technology'

    # 	self.fakepop.clearDemeInfo()
    # 	self.fakepop.populationMutationMigration()
    # 	self.fakepop.updateDemeInfo()

    # 	for dem in self.fakepop.demes:
    # 		assert dem.progressValues['effectivePublicGood'] is not None, "No value in the effective public good"
    # 		assert dem.progressValues['effectivePublicGood'] >= 0, "Effective public good shouldn't be negative"
    # 		assert type(dem.progressValues['effectivePublicGood']) is float, "Effective public good should be float, not {0}".format(type(dem.effectivePublicGood))

    def test_technology_fitness_fct_returns_value(self, getFitnessParameters):
        self.ind = Ind()
        self.ind.resourcesAmount = 5
        self.pars = getFitnessParameters('technology')
        infoToAdd = {}
        infoToAdd['n'] = 10
        infoToAdd['xmean'] = [0.3]
        infoToAdd['x'] = [0.6]
        infoToAdd['fine'] = 0.2
        infoToAdd['investmentReward'] = 0.4

        try:
            self.ind.fertility('technology', **{**self.pars, **infoToAdd})
        except TypeError as e:
            if str(
                    e
            ) == "float() argument must be a string or a number, not 'NoneType'":
                assert False, "technology fonction returns nothing!"
            else:
                assert False, str(e)

        gc.collect()

    def test_technology_fitness_fct_takes_args(self, getFitnessParameters):
        self.ind = Ind()
        self.pars = getFitnessParameters('technology')
        self.ind.resourcesAmount = 1

        try:
            self.ind.fertility(
                'technology', **{
                    **{
                        'fine': 0.2,
                        'investmentReward': 0.4
                    },
                    **self.pars
                })
        except TypeError as e:
            assert False, "technology fitness function does not yet take arguments, fix this!"

        gc.collect()

    def test_initial_deme_technology_is_not_null(self):
        self.pop = Pop(inst='test/test')
        self.pop.createAndPopulateDemes()

        assert type(self.pop.demes[0].technologyLevel
                    ) is float, "initial technology level info missing"
        assert self.pop.demes[
            0].technologyLevel > 0, "technology level cannot be null or negative"

        gc.collect()

    def test_deme_technology_level_gets_updated_with_individual_investments(
            self, getFitnessParameters):
        self.pars = getFitnessParameters('technology')
        self.pop = Pop(fit_fun='technology', inst='test/test')
        self.pop.numberOfDemes = 2
        self.pop.initialDemeSize = 10
        self.pop.initialPhenotypes = [0.5] * 4
        self.pop.fitnessParameters = self.pars
        self.pop.createAndPopulateDemes()

        demeTech = self.pop.demes[0].technologyLevel

        self.pop.lifecycle()
        self.pop.clearDemeInfo()

        assert demeTech != self.pop.demes[
            0].technologyLevel, "the technology level has not changed!"

        gc.collect()

    def test_public_good_gets_updated(self):
        self.pop = Pop(fit_fun='technology', inst='test/test')
        self.pop.numberOfDemes = 2
        self.pop.initialDemeSize = 10
        self.pop.initialPhenotypes = [0.5] * 4
        self.pop.createAndPopulateDemes()

        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()
        self.pop.populationProduction()
        self.pop.updateDemeInfoPostProduction()

        assert type(
            self.pop.demes[0].publicGood
        ) is float, "publicGood must be created due to individual investments during reproduction"
        assert self.pop.demes[
            0].publicGood >= 0, "public good cannot be negative"

        gc.collect()

    def test_technology_updates_with_correct_number(self):
        self.pop = Pop(fit_fun='technology', inst='test/test')
        self.pop.numberOfDemes = 2
        self.pop.initialDemeSize = 10
        self.pop.fit_fun = 'technology'
        self.pop.initialPhenotypes = [0.5] * 4
        self.pop.createAndPopulateDemes()

        assert self.pop.demes[
            0].technologyLevel == self.pop.initialTechnologyLevel, "wrong technology level assigned to deme when created"
        self.pop.clearDemeInfo()
        assert self.pop.demes[
            0].technologyLevel == self.pop.initialTechnologyLevel, "wrong technology level after first clearing"
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()
        self.pop.populationProduction()
        self.pop.updateDemeInfoPostProduction()
        # calculate new technology level as it should be
        publicGood = self.pop.demes[0].publicGood
        tech = self.pop.demes[0].technologyLevel
        tech_new = tech * (self.pop.fitnessParameters['atech'] +
                           ((1 - self.pop.fitnessParameters['p']) * publicGood)
                           **(1 - self.pop.fitnessParameters['betaTech'])) / (
                               1 + self.pop.fitnessParameters['btech'] * tech)
        self.pop.populationReproduction()
        self.pop.clearDemeInfo()
        assert self.pop.demes[
            0].technologyLevel == tech_new, "wrong value for new technology level."

        gc.collect()

    def test_individual_can_produce_its_own_resources(
            self, instantiateSingleIndividualsDemes, getFitnessParameters):
        self.args = getFitnessParameters('technology')
        self.pop = instantiateSingleIndividualsDemes(2)
        self.pop.fit_fun = 'technology'
        self.pop.fitnessParameters.update(self.args)
        self.pop.initialPhenotypes = [0.5] * 4
        self.pop.individualResources = 0
        self.pop.fitnessParameters['p'] = 0

        self.pop.createAndPopulateDemes()
        self.pop.individuals[0].resourcesAmount = 0

        assert hasattr(self.pop.individuals[0],
                       "produceResources"), "put your farmers to work!"
        self.resBEFORE = self.pop.individuals[0].resourcesAmount
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()
        self.ind = self.pop.individuals[0]
        self.deme = self.pop.demes[self.ind.currentDeme]
        self.ind.produceResources(
            'technology', **{
                **self.pop.fitnessParameters,
                **self.deme.progressValues
            })
        assert self.ind.resourcesAmount > self.resBEFORE, "that one did not get the point of production: it didn't increase its amount of resources!"

        gc.collect()

    def test_individual_resources_increase_with_technology(
            self, getFitnessParameters):
        #up_dict = {'civilianPublicTime': 0, 'labourForce': 10}
        phen = [0.5] * 4
        res = 0

        # First Individual
        self.ind1 = Ind()
        self.pars = getFitnessParameters('technology')
        #self.pars.update({'civilianPublicTime': 0, 'labourForce': 10, 'technologyLevel': 2})
        tech1 = 2.4
        tech2 = 5.9

        res1 = (self.pars['n']**(-self.pars['alphaResources'])) * (
            tech1**self.pars['alphaResources'])
        res2 = (self.pars['n']**(-self.pars['alphaResources'])) * (
            tech2**self.pars['alphaResources'])
        assert res1 < res2

        self.pars.update({'tech': tech1, 'p': 0})
        self.ind1.phenotypicValues = phen
        self.ind1.resourcesAmount = res

        self.ind1.pars = self.pars
        self.ind1.produceResources('technology', **self.ind1.pars)
        assert self.ind1.resourcesAmount == res1

        # Second Individual
        self.ind2 = Ind()
        self.pars.update({'tech': tech2})
        self.ind2.phenotypicValues = phen
        self.ind2.resourcesAmount = res

        self.ind2.pars = self.pars
        self.ind2.produceResources('technology', **self.ind2.pars)
        assert self.ind2.resourcesAmount == res2

        assert self.ind1.resourcesAmount < self.ind2.resourcesAmount, "ind1 knows 2 and gets {0}, ind2 knows 5 and gets {1}, when really those with more knowledge should get more resources, all else being equal".format(
            self.ind1.resourcesAmount, self.ind2.resourcesAmount)

        gc.collect()

    def test_group_labour_force_is_calculated_and_given_to_individual_instance(
            self):
        self.pop = Pop(fit_fun='technology', inst='test/test')
        self.pop.numberOfDemes = 3
        self.pop.initialDemeSize = 20
        self.pop.createAndPopulateDemes()
        self.deme = self.pop.demes[0]
        assert hasattr(self.deme, "progressValues"), "make dict"
        assert type(self.deme.progressValues) is dict
        progressKeys = ["fine", "investmentReward"]
        for key in progressKeys:
            assert key in self.deme.progressValues

        self.pop.clearDemeInfo()
        for pheno in self.pop.demes[0].meanPhenotypes:
            assert pheno is not None, "none phenotypes before migration"
        self.pop.populationMutationMigration()
        for pheno in self.pop.demes[0].meanPhenotypes:
            assert pheno is not None, "none phenotypes before update"
        self.pop.updateDemeInfoPreProduction()
        self.pop.populationProduction()
        self.pop.updateDemeInfoPostProduction()

        self.demeAFTER = self.pop.demes[0]
        for key in progressKeys:
            assert self.demeAFTER.progressValues[key] is not None
        # deme labour force = total private time: (demography - nleaders)(1-T1) + nleaders(1-T2)
        # where T1 and T2 is effective time spent in debate by civilian and leader respectively

        gc.collect()

    def test_production_increase_function(self):
        #pars = getFitnessParameters('technology')
        self.pop = Pop(fit_fun='technology', inst='test/test')
        self.pop.numberOfDemes = 2
        self.pop.initialDemeSize = 5

        self.pop.createAndPopulateDemes()
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()
        self.pars = self.pop.fitnessParameters

        for ind in self.pop.individuals:
            deme = self.pop.demes[ind.currentDeme]
            infoToAdd = {}
            infoToAdd["tech"] = deme.technologyLevel
            infoToAdd["n"] = deme.demography
            infoToAdd["xmean"] = deme.meanPhenotypes
            infoToAdd["pg"] = deme.publicGood
            infoToAdd["x"] = ind.phenotypicValues
            # assert deme.progressValues["labourForce"] is not None, "labour force is none!"
            # assert deme.progressValues["labourForce"] != 0, "labour force is null!"
            assert deme.technologyLevel is not None, "technology is none!"
            fine = deme.publicGood * self.pars['p'] / deme.demography
            benef = ((deme.publicGood * (1 - self.pars['p']))**
                     self.pars["betaTech"]) / deme.demography
            resourcesProduced = deme.demography**(
                -self.pars['alphaResources']
            ) * infoToAdd['tech']**self.pars['alphaResources']

            ind.produceResources(self.pop.fit_fun, **{
                **self.pop.fitnessParameters,
                **infoToAdd
            })
            assert ind.resourcesAmount == resourcesProduced, "ind produced {0} instead of {1}".format(
                ind.resourcesAmount, payoff)

            gc.collect()

    def test_fitness_function_returns_correct_value(self):
        self.pop = Pop(fit_fun='technology', inst='test/test')
        self.pop.numberOfDemes = 3
        self.pop.initialDemeSize = 5
        self.pop.createAndPopulateDemes()
        self.pop.clearDemeInfo()
        self.pop.populationMutationMigration()
        self.pop.updateDemeInfoPreProduction()
        self.pop.populationProduction()
        self.pop.updateDemeInfoPostProduction()

        for ind in self.pop.individuals:
            #assert self.pop.demes[ind.currentDeme].progressValues['technologyLevel'] > 1, "technology level too low: {0}".format(self.pop.demes[ind.currentDeme].progressValues['technologyLevel'])
            #assert ind.resourcesAmount > 0, "not enough resources to reproduce: {0}".format(ind.resourcesAmount)
            infoToAdd = {}
            infoToAdd['n'] = self.pop.demes[ind.currentDeme].demography
            infoToAdd['xmean'] = self.pop.demes[ind.currentDeme].meanPhenotypes
            infoToAdd['tech'] = self.pop.demes[ind.currentDeme].technologyLevel
            infoToAdd['pg'] = self.pop.demes[ind.currentDeme].publicGood
            infoToAdd['x'] = ind.phenotypicValues
            ind.reproduce(
                'technology', **{
                    **self.pop.fitnessParameters,
                    **infoToAdd,
                    **self.pop.demes[ind.currentDeme].progressValues
                })

            fine = infoToAdd['pg'] * self.pop.fitnessParameters[
                'p'] / infoToAdd['n']
            benef = ((infoToAdd['pg'] * (1 - self.pop.fitnessParameters['p']))
                     **self.pop.fitnessParameters["betaTech"]) / infoToAdd['n']
            payoff = (1 - self.pop.fitnessParameters['q']) * (
                1 - infoToAdd['x'][0]
            ) * ind.resourcesAmount + self.pop.fitnessParameters['q'] * (
                (1 - infoToAdd['x'][0]) * ind.resourcesAmount - fine) + benef
            w = (self.pop.fitnessParameters['rb'] + payoff) / (
                1 + self.pop.fitnessParameters['gamma'] * infoToAdd['n'])
            assert ind.fertilityValue == w, "wrong fitness calculation for individual, should return {0}".format(
                w)

        gc.collect()

    def test_individuals_reproduce_after_production(self,
                                                    getFitnessParameters):
        self.params = getFitnessParameters('technology')
        self.params.update({'p': 0, 'tech': 10.5})
        self.ind = Ind()
        self.ind.neighbours = [1, 2]
        self.ind.phenotypicValues = [0.5] * 3

        res = (self.params['n']**(-self.params['alphaResources'])) * (
            self.params['tech']**self.params['alphaResources'])
        assert res > 0, "no resources produced"
        fine = self.params['pg'] * self.params['p'] / self.params['n']
        benef = ((self.params['pg'] * (1 - self.params['p']))**
                 self.params["betaTech"]) / self.params['n']
        payoff = (1 - self.params['q']) * (
            1 - self.ind.phenotypicValues[0]) * res + self.params['q'] * (
                (1 - self.ind.phenotypicValues[0]) * res - fine) + benef
        f = (self.params["rb"] +
             payoff) / (1 + self.params["gamma"] * self.params["n"])

        self.ind.produceResources('technology', **self.params)
        self.ind.reproduce(
            'technology', **{
                **{
                    'fine': fine,
                    'investmentReward': benef
                },
                **self.params
            })
        assert self.ind.fertilityValue == f, "wrong fertility value"

        self.ind2 = Ind()
        self.ind2.neighbours = [1, 2]
        self.ind2.phenotypicValues = [0.5] * 3
        res2 = (self.params['n']**(-self.params['alphaResources'])) * (
            self.params['tech']**self.params['alphaResources'])
        fine2 = self.params['pg'] * self.params['p'] / self.params['n']
        benef2 = ((self.params['pg'] * (1 - self.params['p']))**
                  self.params["betaTech"]) / self.params['n']
        payoff2 = (1 - self.params['q']) * (
            1 - self.ind2.phenotypicValues[0]) * res2 + self.params['q'] * (
                (1 - self.ind2.phenotypicValues[0]) * res2 - fine2) + benef2
        assert self.params['q'] * (self.params['pg'] *
                                   self.params['p']) / self.params['n'] == 0
        assert (1 -
                self.params['q'] * self.params['d'] * self.params['p']) == 1
        assert (1 - self.ind.phenotypicValues[0]) == 0.5
        assert res2 > 0, "no resources produced"
        f2 = (self.params["rb"] +
              payoff2) / (1 + self.params["gamma"] * self.params["n"])
        assert f2 == f, "all being equal, the fertility values should be the same"

        self.ind2.produceResources('technology', **self.params)
        self.ind2.reproduce(
            'technology', **{
                **{
                    'fine': fine2,
                    'investmentReward': benef2
                },
                **self.params
            })
        assert self.ind2.fertilityValue == f, "wrong fertility value"

        self.params.update({'p': 0.7})
        self.ind3 = Ind()
        self.ind3.neighbours = [1, 2]
        self.ind3.phenotypicValues = [0.5] * 3
        res3 = (self.params['n']**(-self.params['alphaResources'])) * (
            self.params['tech']**self.params['alphaResources'])
        fine3 = self.params['pg'] * self.params['p'] / self.params['n']
        benef3 = ((self.params['pg'] * (1 - self.params['p']))**
                  self.params["betaTech"]) / self.params['n']
        payoff3 = (1 - self.params['q']) * (
            1 - self.ind3.phenotypicValues[0]) * res3 + self.params['q'] * (
                (1 - self.ind3.phenotypicValues[0]) * res3 - fine3) + benef3
        assert res3 > 0, "no resources produced"
        f3 = (self.params["rb"] +
              payoff3) / (1 + self.params["gamma"] * self.params["n"])

        self.ind3.produceResources('technology', **self.params)
        self.ind3.reproduce(
            'technology', **{
                **{
                    'fine': fine3,
                    'investmentReward': benef3
                },
                **self.params
            })
        assert self.ind3.fertilityValue == f3, "wrong fertility value"

        gc.collect()