2

I'm trying to modify the python code for Fibonacci mortal rabbits in order to vary the fecundity of the rabbits depending on their age. Let's make an example.

My rabbits achieve maturity after 3 months and die after 6 months. During their 4 months of fecundity they produce a different number of offspring depending on their age. When they are 3 months old produce 2 pairs of bunnies, at 4 months produce 3 pairs of bunnies and so on till the sixth month. Each pair of bunnies is formed by a female and a male. In the end I would count the number of pairs not the number of individuals. Fecundity values from the birth to the death:

fecundity = [0, 0, 2, 3, 3, 1]

The python code that I'm using (https://github.com/jschendel/Rosalind/blob/master/011_FIBD.py) is:

n = 12
m = 6
#n = months to run
#m = how many months the rabbits live

# Populate the initial rabbits.
Rabbits = [1]+[0]*(m-1)

# Calculate the new rabbits (bunnies), in a given month.
# Start at use range(1,n) since our initial population is 0 month old.
for month in range(1, n):
    Bunnies = 0
    # Get the number of Rabbits able to old enough to give birth.
    for j in range(1,m):
        Bunnies += Rabbits[(month-j-1)%m]
    # Bunnies replace the old rabbits who died.
    Rabbits[(month)%m] = Bunnies

# Total rabbits is the sum of the living rabbits.
Total_Rabbits = sum(Rabbits)

I'm not sure how to implement the variation of fecundity. Any help is appreciated!

Thank you, Valentina

Valentina
  • 115
  • 1
  • 9
  • Should not `[0, 0, 2, 3, 3, 1]` be *pairs* of rabbits (one male, one female)? – Fabrizio Calderan Mar 10 '16 at 11:22
  • Yes, I haven't specified it! The newborns are pairs of rabbits (one F one M). But in the end I would count the number of pairs not the number of single individuals. I edit the question – Valentina Mar 10 '16 at 11:24
  • 1
    `for year in range(1, n):` should be month, not year. `Rabbits[year-j-1%m]` are the Rabbits born j months ago, apply on that line your fecundity factor. – xvan Mar 10 '16 at 11:47

2 Answers2

2

Define your fecundity array to stop when a rabbit dies :

fecundity = [0, 0, 2, 3, 3, 1]

means your rabbits die at the age of 7 months old. After that, you just write a recursive function to calculate the number of new_borns in a specific step. I initialize the steps as 1 pair for step 0, and 0 pair for step < 0. You can of course change it to fit your case. (What I call a step is one unit of time, here the month). Here is the function :

def new_borns(step):
    if step < 0:
        return 0
    if step == 0:
        return 1
    nb_newborns = 0
    # We create a loop on living pairs
    for old_step in range(1, len(fecondity) +1):
        nb_newborns += (fecundity[old_step -1]) * new_borns(step - old_step)
    return nb_newborns

The total population of a specific step is the total of new_borns for the previous steps, still living (ie, for the length of your fecundity array).

def FIBD(step):
    population = 0
    for i in range(len(fecundity)):
        population += new_borns(step - i)
    return population

To know how many pairs you have at step 7, just call FIBD(7) The number of months the rabbit can live is the length of the fecundity array.

Of course, this recursive function is very very slow and bad. You need a caching system to avoid to calculate multiple times the same step. Here is the full file to write.

#!/usr/bin/env python

fecundity = [0, 0, 2, 3, 3, 1]
new_borns_cache = [1]

def new_borns(step):
    if step < 0:
        return 0
    try :
        return new_borns_cache[step]
    except IndexError:
        if step == 0:
            return 1
        sum = 0
        for old_step in range(1, len(fecundity) +1):
            sum += (fecundity[old_step -1]) * new_borns(step - old_step)
        return sum

def fibd(step):
    population = 0
    for i in range(len(fecundity)):
        population += new_borns(step - i)
    return population

To use it, just import , and call fibd(7)

Dunatotatos
  • 1,706
  • 15
  • 25
  • 1
    A term which could be very interesting, and is linked to this kind of algorithms is "convolution product". Just for your interest. – Dunatotatos Mar 10 '16 at 13:53
0

I came to an answer myself and I really modified the code that I posted previously. I think that now it is much simpler

import numpy as np

m = 15
n = 18
fecundity = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 1, 1, 1])
Bunnies = np.array([0]*m)
Rabbits = np.array([1]+[0]*(m-1))

for month in range(0, 18):
    # every month I shift the list of 1 since they're getting older
    Rabbits = np.roll(Rabbits, 1)
    # I set the newborns as 0
    Rabbits[0] = 0
    # I calculate the newborns
    Bunnies = Rabbits * fecundity
    # and then I assign them to the rabbits 0 month old
    Rabbits[0] = sum(Bunnies)

# the sum of Rabbits is the number of final pairs of Rabbits after n months
Total_Rabbits = sum(Rabbits)
# 26 Rabbits
Valentina
  • 115
  • 1
  • 9