[Riddle] simulation of behaviors in population

There are things that aren’t interesting because they are complicated, but because they have simple solutions. Today I will present one of those riddles that comes from the book "THE SELFISH GENE" by Richard Dawkins. You can find there more of such stuff and all is presented from biological point of view, far away from informatics.

Consider this problem: in population, in given situation, species may behave in two ways: as a fighter or as a coward. Fighter always wins fight with coward. This behavior is set by a single gene, if a specimen behave in a way that give him an advantage, then he is in a better position and will have more descendants. For us it means that his gene have better chance to spread in population.

Assume that species don’t remember behavior of other species and that they can’t predict it. Score function that says, how profitable the behavior is will be needed – we will use arbitrary numbers, like in the book: let's attribute +50 points to win, 0 to fail, -10 to waisting time, -100 for serious damage.

  • Coward meets Coward, the winner gets +50 points, both of them get -10 points for waisting time (they could do something valuable instead). Those -10 points are here because cowards waist time on trying to make their opponents scary, if they can't do that they run away,
  • Coward meets Fighter, the winner gets 50 points, the loser gets 0 points, as we said, fighter always wins with coward,
  • Fighter meets Fighter, the winner gets 50 points, the loser gets -100 points for a serious damage.

At the beginning there are only cowards - nothing interesting for us. When fighter (obviously a mutant) appears in population, then he is in a privileged position, his genes spreads quickly. Situation changes when fighters become dominant part in the population, then it’s much better to be a coward. At first it looks like amount of fighters and cowards will changes periodically, in fact it will go into a stable ratio (there is a lot of math here, but it’s not important here). The goal is to display at each generation the percentage of cowards and fighters in population (this should summarize to 100% ofc). There is a given number of generations to show and initial generation (again in a form of percentages of cowards and fighters).

We will use following notations:
sf – score of all fighters in generation
sc – score of all cowards in generation
pf – percentage of fighters in generation
pc – percentage of cowards in generation
Score function may be described as:
sf = (-25 * pc) + (50 * pf)
sc = (15 * pc) + (0 * pf)

As we will see later, it would be better if values of sf and sc would be non negative. We will be also interested rather in ratios that in concrete values, so we may add constant value to both equations:

sf = 25 + (-25 * pc) + (50 * pf)
sc = 25 + (15 * pc) + (0 * pf)

Now percentage of cowards and fighters in next generation may be counted simply:

pf = sf / (sf + sc)
pc = sc / (sf + sc)
Implementations in C and in Haskell.
#include <stdio.h>
#include <stdlib.h>

int main() {
    double pg = 0.9, pj = 0.1;

    const unsigned iters = 20;
    unsigned i;

    for (i=0; i<iters; i++) {
        printf("pg: %1.2f pg: %1.2f\n", pg, pj);

        double zg = 25 + (15 * pg) + (0 * pj);
        double zj = 25 + (-25 * pg) + (50 * pj);

        pg = zg / (zg+zj);
        pj = zj / (zg+zj);
    }

    return EXIT_SUCCESS;
}

main = generate (0.9, 0.1) 20

generate _ 0 = putStr ""
generate (pc, pf) iterations = do
                putStrLn ("pc: " ++ (show pc) ++ ", pf: " ++ (show pf))
                generate (new_pc, new_pf) (iterations-1) where
                                new_pc = sc / (sc + sf)
                                new_pf = sf / (sc + sf)
                                sc = 25 + (15 * pc) + (0 * pf)
                                sf = 25 + (-25 * pc) + (50 * pf)

0 commentaires:

Post a Comment