1
0
mirror of https://github.com/gsi-upm/soil synced 2024-11-25 04:12:29 +00:00

Agent step can be a generator

This commit is contained in:
J. Fernando Sánchez 2022-10-17 08:58:51 +02:00
parent 0efcd24d90
commit 77d08fc592
5 changed files with 52 additions and 17 deletions

View File

@ -21,7 +21,6 @@ class RabbitEnv(Environment):
return self.count_agents(agent_class=Female) return self.count_agents(agent_class=Female)
class Rabbit(FSM, NetworkAgent): class Rabbit(FSM, NetworkAgent):
sexual_maturity = 30 sexual_maturity = 30
@ -125,8 +124,6 @@ class Female(Rabbit):
class RandomAccident(BaseAgent): class RandomAccident(BaseAgent):
level = logging.INFO
def step(self): def step(self):
rabbits_alive = self.model.G.number_of_nodes() rabbits_alive = self.model.G.number_of_nodes()
@ -144,6 +141,7 @@ class RandomAccident(BaseAgent):
i.set_state(i.dead) i.set_state(i.dead)
self.debug('Rabbits alive: {}'.format(rabbits_alive)) self.debug('Rabbits alive: {}'.format(rabbits_alive))
if __name__ == '__main__': if __name__ == '__main__':
from soil import easy from soil import easy
sim = easy('rabbits.yml') sim = easy('rabbits.yml')

View File

@ -47,7 +47,25 @@ class MetaAgent(ABCMeta):
} }
for attr, func in namespace.items(): for attr, func in namespace.items():
if ( if attr == 'step' and inspect.isgeneratorfunction(func):
orig_func = func
new_nmspc['_MetaAgent__coroutine'] = None
@wraps(func)
def func(self):
while True:
if not self.__coroutine:
self.__coroutine = orig_func(self)
try:
return next(self.__coroutine)
except StopIteration as ex:
self.__coroutine = None
return ex.value
func.id = name or func.__name__
func.is_default = False
new_nmspc[attr] = func
elif (
isinstance(func, types.FunctionType) isinstance(func, types.FunctionType)
or isinstance(func, property) or isinstance(func, property)
or isinstance(func, classmethod) or isinstance(func, classmethod)

View File

@ -125,7 +125,7 @@ def get_dc_dfs(dc, trial_id=None):
dfs[table_name] = dc.get_table_dataframe(table_name) dfs[table_name] = dc.get_table_dataframe(table_name)
if trial_id: if trial_id:
for (name, df) in dfs.items(): for (name, df) in dfs.items():
df['trial_id'] = trial_id df["trial_id"] = trial_id
yield from dfs.items() yield from dfs.items()

View File

@ -59,9 +59,7 @@ def try_backup(path, move=False):
backup_dir = os.path.join(outdir, "backup") backup_dir = os.path.join(outdir, "backup")
if not os.path.exists(backup_dir): if not os.path.exists(backup_dir):
os.makedirs(backup_dir) os.makedirs(backup_dir)
newpath = os.path.join( newpath = os.path.join(backup_dir, "{}@{}".format(os.path.basename(path), stamp))
backup_dir, "{}@{}".format(os.path.basename(path), stamp)
)
if move: if move:
move(path, newpath) move(path, newpath)
else: else:

View File

@ -13,14 +13,35 @@ class Dead(agents.FSM):
class TestMain(TestCase): class TestMain(TestCase):
def test_die_returns_infinity(self):
'''The last step of a dead agent should return time.INFINITY'''
d = Dead(unique_id=0, model=environment.Environment())
ret = d.step().abs(0)
print(ret, "next")
assert ret == stime.INFINITY
def test_die_raises_exception(self): def test_die_raises_exception(self):
'''A dead agent should raise an exception if it is stepped after death'''
d = Dead(unique_id=0, model=environment.Environment()) d = Dead(unique_id=0, model=environment.Environment())
d.step() d.step()
with pytest.raises(agents.DeadAgent): with pytest.raises(agents.DeadAgent):
d.step() d.step()
def test_die_returns_infinity(self):
d = Dead(unique_id=0, model=environment.Environment()) def test_agent_generator(self):
ret = d.step().abs(0) '''
print(ret, "next") The step function of an agent could be a generator. In that case, the state of the
assert ret == stime.INFINITY agent will be resumed after every call to step.
'''
class Gen(agents.BaseAgent):
def step(self):
a = 0
for i in range(5):
yield a
a += 1
e = environment.Environment()
g = Gen(model=e, unique_id=e.next_id())
for i in range(5):
t = g.step()
assert t == i