{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Prey-Predator\n", "\n", "Hare: \n", "* inflow: natural birth\n", "* outflow: death due to predation\n", "\n", "Lynx:\n", "* inflow: growth and give birth thanks to preying on hare\n", "* outflow: natural death\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Test function" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "def Test_Initialization(init_func, hare_number, lynx_number) :\n", " global hare_total, lynx_total\n", " init_func(hare_number, lynx_number)\n", " assert (hare_total == hare_number and lynx_total == lynx_number) , \"Mismatch initial population size\"\n", " print(\"Pass initalization test:\", init_func.__name__, hare_number, lynx_number)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Global variables" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "from numpy import random\n", "\n", "hare_id = 1\n", "hare_total = 0\n", "hare = []\n", "\n", "lynx_id = -1\n", "lynx_total = 0\n", "lynx = []\n", "\n", "random_generator = random.RandomState(1111)\n", "\n", "param = {\n", " \"hare_birth\": 0.8,\n", " \"hare_death\" : 0.3, # come into contact with lynx AND die\n", " \"lynx_birth\": 0.1,\n", " \"lynx_death\": 0.2\n", "}\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialization function \n", "\n", "This sets up the simulation with initial numbers of hares and lynxes.\n" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "def Initialize(hare_number=0, lynx_number=0):\n", " global hare_total, lynx_total, hare_id, lynx_id, hare, lynx\n", " hare_id = 0\n", " hare = []\n", " lynx_id = 0\n", " lynx = []\n", " \n", " # ask for inputs if not given\n", " if hare_number >= 0:\n", " hare_total = hare_number\n", " else :\n", " hare_total = int(input(\"Initial number of hares: \"))\n", " if lynx_number > 0:\n", " lynx_total = lynx_number\n", " else:\n", " lynx_total = int(input(\"Initial number of lynxes: \"))\n", " \n", " # add individuals to approriate lists\n", " for i in range(hare_total) :\n", " hare_id += 1\n", " hare.append( hare_id )\n", " \n", " for i in range(lynx_total) :\n", " lynx_id -= 1\n", " lynx.append( lynx_id )\n", " \n", "# Test_Initialization(Initialize, 10, 9)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simulate each time step (daily)\n", "\n", "This will do the following:\n", "* Calculate the total births of hare: $ \\text{hare_birth} \\times \\text{hare_total} $\n", "* Calculate the total deaths of hare due to predation: $ \\text{hare_predation} \\times \\text{hare_total} \\times \\text{lynx_total} $ \n", "* Calculate the total births of lynx: $ \\text{lynx_birth} \\times \\text{hare_total} \\times \\text{lynx_total} $\n", "* Calculate the total deaths of hare due to predation: $ \\text{lynx_death} \\times \\text{lynx_total} $ \n", "* Calculate the amount of changes to hare population (birth - death):\n", " + if change is 0: do nothing to hare population\n", " + if change > 0: add new individuals to hare list\n", " + if change < 0: choose random individuals from hare list and remove them\n", "* Calculate the amount of changes to lynx population (birth - death):\n", " + if change is 0: do nothing to lynx population\n", " + if change > 0: add new individuals to lynx list\n", " + if change < 0: choose random individuals from lynx list and remove them" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def Modify_Hare(amount_change):\n", " global hare_total, hare_id, hare, random_generator\n", " \n", "# if amount_change > 0 :\n", "# for i in range(amount_change) :\n", "# hare_id += 1\n", "# hare.append( hare_id )\n", " \n", "# elif amount_change + hare_total <= 0 :\n", "# hare = []\n", " \n", "# else :\n", "# new_hare = []\n", " \n", "# indices = sorted(random_generator.choice(hare_total, abs(amount_change), replace=False))\n", " \n", "# i, j = 0, 0\n", "# while j < hare_total :\n", "# # done removing\n", "# if i == abs(amount_change) :\n", "# new_hare.append(hare[j:])\n", "# break\n", "# elif j != indices[i] :\n", "# new_hare.append(hare[j])\n", "# else :\n", "# i += 1\n", "# j += 1\n", " \n", "# hare = new_hare[:]\n", " \n", " hare_total = hare_total + amount_change if hare_total + amount_change > 0 else 0\n", " \n", " return hare_total" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def Modify_Lynx(amount_change):\n", " global lynx_total, lynx_id, lynx, random_generator\n", " \n", "# if amount_change > 0 :\n", "# for i in range(amount_change) :\n", "# lynx_id += 1\n", "# # lynx.append( lynx_id )\n", " \n", "# elif amount_change + lynx_total <= 0 :\n", "# lynx = []\n", " \n", "# else :\n", "# new_lynx = []\n", " \n", "# indices = sorted(random_generator.choice(lynx_total, abs(amount_change), replace=False))\n", " \n", "# i, j = 0, 0\n", "# while j < lynx_total :\n", "# # done removing\n", "# if i == abs(amount_change) :\n", "# new_lynx.append(lynx[j:])\n", "# break\n", "# elif j != indices[i] :\n", "# new_lynx.append(lynx[j])\n", "# else :\n", "# i += 1\n", "# j += 1\n", " \n", "# lynx = new_lynx[:]\n", " \n", " lynx_total = lynx_total + amount_change if lynx_total + amount_change > 0 else 0\n", " \n", " return lynx_total" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def Simulate_One_Step():\n", " global param\n", " # calculate births, deaths, changes\n", " hare_in = param[\"hare_birth\"] * hare_total\n", " hare_out = param[\"hare_death\"] * hare_total * lynx_total\n", " lynx_in = param[\"lynx_birth\"] * hare_total * lynx_total\n", " lynx_out = param[\"lynx_death\"] * lynx_total\n", " hare_change = int(hare_in - hare_out)\n", " lynx_change = int(lynx_in - lynx_out)\n", " # note: one can condensed all calculations above to just 2 lines\n", " \n", " # make change to hare population\n", " if hare_change != 0 :\n", " Modify_Hare(hare_change)\n", " # make change to lynx population\n", " if lynx_change != 0 :\n", " Modify_Lynx(lynx_change)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Run the simulation" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---day 0 ---\n", "Hare total: 5999 Lynx total: 300\n", "---day 4 ---\n", "Oops! One of the population has died out....\n", "Hare total: 0 Lynx total: 60633847\n" ] } ], "source": [ "# param = {\n", "# \"hare_birth\": 0.6,\n", "# \"hare_death\" : 0.001,\n", "# \"lynx_birth\": 0.00001,\n", "# \"lynx_death\": 0.5\n", "# }\n", "# Initialize(50000, 600) # equilibrium\n", "\n", "\n", "def Print_Day(day) :\n", " global hare, lynx, hare_total, lynx_total\n", " print(\"---day\", str(day), \"---\")\n", "# print(hare)\n", "# print(lynx)\n", " print(\"Hare total:\", hare_total, \" Lynx total:\", lynx_total)\n", "\n", "\n", "param = { \n", " \"hare_birth\": 0.2,\n", " \"hare_death\" : 0.00003, \n", " \"lynx_birth\": 0.1,\n", " \"lynx_death\": 1\n", "} \n", " \n", "Initialize(5000, 6)\n", "# print(hare)\n", "# print(lynx)\n", " \n", "for day in range(0,101):\n", " if hare_total == 0 or lynx_total == 0:\n", " print(\"---day\", str(day), \"---\")\n", " print(\"Oops! One of the population has died out....\")\n", " print(\"Hare total:\", hare_total, \" Lynx total:\", lynx_total)\n", " break\n", " Simulate_One_Step()\n", " if day % 10 == 0 :\n", " Print_Day(day)\n", "\n", "# print(hare)\n", "# print(lynx)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.1" } }, "nbformat": 4, "nbformat_minor": 4 }