1
0
mirror of https://github.com/gsi-upm/soil synced 2024-11-22 19:22:29 +00:00
soil/examples/rabbits/rabbit_agents.py

136 lines
4.3 KiB
Python
Raw Normal View History

from soil.agents import FSM, state, default_state, BaseAgent, NetworkAgent
2017-10-16 17:23:52 +00:00
from enum import Enum
from random import random, choice
2017-10-17 17:48:56 +00:00
import logging
import math
2017-10-16 17:23:52 +00:00
class Genders(Enum):
male = 'male'
female = 'female'
class RabbitModel(FSM):
2017-10-16 17:23:52 +00:00
defaults = {
'age': 0,
'gender': Genders.male.value,
'mating_prob': 0.001,
'offspring': 0,
}
sexual_maturity = 3 #4*30
2017-10-16 17:23:52 +00:00
life_expectancy = 365 * 3
gestation = 33
pregnancy = -1
max_females = 5
2017-10-16 17:23:52 +00:00
@default_state
@state
def newborn(self):
self.debug(f'I am a newborn at age {self["age"]}')
2017-10-16 17:23:52 +00:00
self['age'] += 1
if self['age'] >= self.sexual_maturity:
self.debug('I am fertile!')
2017-10-16 17:23:52 +00:00
return self.fertile
2022-05-12 14:14:47 +00:00
@state
def fertile(self):
raise Exception("Each subclass should define its fertile state")
@state
def dead(self):
self.info('Agent {} is dying'.format(self.id))
self.die()
class Male(RabbitModel):
2017-10-16 17:23:52 +00:00
@state
def fertile(self):
self['age'] += 1
if self['age'] > self.life_expectancy:
return self.dead
if self['gender'] == Genders.female.value:
return
# Males try to mate
2022-05-12 14:14:47 +00:00
for f in self.get_agents(state_id=Female.fertile.id,
agent_type=Female,
limit_neighbors=False,
limit=self.max_females):
2017-10-16 17:23:52 +00:00
r = random()
if r < self['mating_prob']:
self.impregnate(f)
break # Take a break
def impregnate(self, whom):
whom['pregnancy'] = 0
whom['mate'] = self.id
whom.set_state(whom.pregnant)
2017-10-17 17:48:56 +00:00
self.debug('{} impregnating: {}. {}'.format(self.id, whom.id, whom.state))
2017-10-16 17:23:52 +00:00
2022-05-12 14:14:47 +00:00
class Female(RabbitModel):
@state
def fertile(self):
# Just wait for a Male
pass
2017-10-16 17:23:52 +00:00
@state
def pregnant(self):
self['age'] += 1
if self['age'] > self.life_expectancy:
return self.dead
self['pregnancy'] += 1
2017-10-17 17:48:56 +00:00
self.debug('Pregnancy: {}'.format(self['pregnancy']))
2017-10-16 17:23:52 +00:00
if self['pregnancy'] >= self.gestation:
2017-10-17 17:48:56 +00:00
number_of_babies = int(8+4*random())
self.info('Having {} babies'.format(number_of_babies))
2017-10-17 17:48:56 +00:00
for i in range(number_of_babies):
state = {}
state['gender'] = choice(list(Genders)).value
child = self.env.add_node(self.__class__, state)
self.env.add_edge(self.id, child.id)
self.env.add_edge(self['mate'], child.id)
# self.add_edge()
self.debug('A BABY IS COMING TO LIFE')
self.env['rabbits_alive'] = self.env.get('rabbits_alive', self.topology.number_of_nodes())+1
2017-10-17 17:48:56 +00:00
self.debug('Rabbits alive: {}'.format(self.env['rabbits_alive']))
self['offspring'] += 1
self.env.get_agent(self['mate'])['offspring'] += 1
del self['mate']
self['pregnancy'] = -1
return self.fertile
2017-10-16 17:23:52 +00:00
@state
def dead(self):
2022-05-12 14:14:47 +00:00
super().dead()
2017-10-16 17:23:52 +00:00
if 'pregnancy' in self and self['pregnancy'] > -1:
2017-10-17 17:48:56 +00:00
self.info('A mother has died carrying a baby!!')
2017-10-16 17:23:52 +00:00
class RandomAccident(NetworkAgent):
2017-10-16 17:23:52 +00:00
level = logging.DEBUG
2017-10-17 17:48:56 +00:00
2017-10-16 17:23:52 +00:00
def step(self):
rabbits_total = self.topology.number_of_nodes()
if 'rabbits_alive' not in self.env:
self.env['rabbits_alive'] = 0
2017-10-17 17:48:56 +00:00
rabbits_alive = self.env.get('rabbits_alive', rabbits_total)
prob_death = self.env.get('prob_death', 1e-100)*math.floor(math.log10(max(1, rabbits_alive)))
2017-10-17 17:48:56 +00:00
self.debug('Killing some rabbits with prob={}!'.format(prob_death))
2017-10-16 17:23:52 +00:00
for i in self.env.network_agents:
2017-10-17 17:48:56 +00:00
if i.state['id'] == i.dead.id:
continue
2017-10-16 17:23:52 +00:00
r = random()
if r < prob_death:
2017-10-17 17:48:56 +00:00
self.debug('I killed a rabbit: {}'.format(i.id))
rabbits_alive = self.env['rabbits_alive'] = rabbits_alive -1
self.log('Rabbits alive: {}'.format(self.env['rabbits_alive']))
2017-10-16 17:23:52 +00:00
i.set_state(i.dead)
2017-10-17 17:48:56 +00:00
self.log('Rabbits alive: {}/{}'.format(rabbits_alive, rabbits_total))
if self.count_agents(state_id=RabbitModel.dead.id) == self.topology.number_of_nodes():
2017-10-17 17:48:56 +00:00
self.die()