mirror of
https://github.com/gsi-upm/soil
synced 2024-11-22 03:02:28 +00:00
black formatting
This commit is contained in:
parent
b2d48cb4df
commit
c09e480d37
@ -258,9 +258,7 @@ class TerroristNetworkModel(TerroristSpreadModel):
|
||||
)
|
||||
neighbours = set(
|
||||
agent.id
|
||||
for agent in self.get_neighbors(
|
||||
agent_class=TerroristNetworkModel
|
||||
)
|
||||
for agent in self.get_neighbors(agent_class=TerroristNetworkModel)
|
||||
)
|
||||
search = (close_ups | step_neighbours) - neighbours
|
||||
for agent in self.get_agents(search):
|
||||
|
@ -47,7 +47,7 @@ def main(
|
||||
"file",
|
||||
type=str,
|
||||
nargs="?",
|
||||
default=cfg if sim is None else '',
|
||||
default=cfg if sim is None else "",
|
||||
help="Configuration file for the simulation (e.g., YAML or JSON)",
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -169,22 +169,26 @@ def main(
|
||||
sim.exporters = exporters
|
||||
sim.parallel = parallel
|
||||
sim.outdir = output
|
||||
sims = [sim, ]
|
||||
sims = [
|
||||
sim,
|
||||
]
|
||||
else:
|
||||
logger.info("Loading config file: {}".format(args.file))
|
||||
if not os.path.exists(args.file):
|
||||
logger.error("Please, input a valid file")
|
||||
return
|
||||
|
||||
sims = list(simulation.iter_from_config(
|
||||
args.file,
|
||||
dry_run=args.dry_run,
|
||||
exporters=exporters,
|
||||
parallel=parallel,
|
||||
outdir=output,
|
||||
exporter_params=exp_params,
|
||||
**kwargs,
|
||||
))
|
||||
sims = list(
|
||||
simulation.iter_from_config(
|
||||
args.file,
|
||||
dry_run=args.dry_run,
|
||||
exporters=exporters,
|
||||
parallel=parallel,
|
||||
outdir=output,
|
||||
exporter_params=exp_params,
|
||||
**kwargs,
|
||||
)
|
||||
)
|
||||
|
||||
for sim in sims:
|
||||
|
||||
|
@ -261,7 +261,6 @@ def prob(prob, random):
|
||||
return r < prob
|
||||
|
||||
|
||||
|
||||
def calculate_distribution(network_agents=None, agent_class=None):
|
||||
"""
|
||||
Calculate the threshold values (thresholds for a uniform distribution)
|
||||
@ -632,7 +631,8 @@ from .CounterModel import *
|
||||
|
||||
|
||||
class Agent(NetworkAgent, EventedAgent):
|
||||
'''Default agent class, has both network and event capabilities'''
|
||||
"""Default agent class, has both network and event capabilities"""
|
||||
|
||||
|
||||
try:
|
||||
import scipy
|
||||
|
@ -6,7 +6,9 @@ from collections import deque
|
||||
|
||||
|
||||
class ReceivedOrTimeout(BaseCond):
|
||||
def __init__(self, agent, expiration=None, timeout=None, check=True, ignore=False, **kwargs):
|
||||
def __init__(
|
||||
self, agent, expiration=None, timeout=None, check=True, ignore=False, **kwargs
|
||||
):
|
||||
if expiration is None:
|
||||
if timeout is not None:
|
||||
expiration = agent.now + timeout
|
||||
@ -23,7 +25,7 @@ class ReceivedOrTimeout(BaseCond):
|
||||
|
||||
def return_value(self, agent):
|
||||
if not self.ignore and self.expired(agent.now):
|
||||
raise TimedOut('No messages received')
|
||||
raise TimedOut("No messages received")
|
||||
if self.check:
|
||||
agent.check_messages()
|
||||
return None
|
||||
@ -34,7 +36,7 @@ class ReceivedOrTimeout(BaseCond):
|
||||
return (time + delta, self)
|
||||
|
||||
def __repr__(self):
|
||||
return f'ReceivedOrTimeout(expires={self.expiration})'
|
||||
return f"ReceivedOrTimeout(expires={self.expiration})"
|
||||
|
||||
|
||||
class EventedAgent(BaseAgent):
|
||||
@ -55,7 +57,7 @@ class EventedAgent(BaseAgent):
|
||||
def ask(self, msg, timeout=None, **kwargs):
|
||||
ask = Ask(timestamp=self.now, payload=msg, sender=self)
|
||||
self._inbox.append(ask)
|
||||
expiration = float('inf') if timeout is None else self.now + timeout
|
||||
expiration = float("inf") if timeout is None else self.now + timeout
|
||||
return ask.replied(expiration=expiration, **kwargs)
|
||||
|
||||
def check_messages(self):
|
||||
@ -71,4 +73,5 @@ class EventedAgent(BaseAgent):
|
||||
msg.reply = reply
|
||||
return changed
|
||||
|
||||
|
||||
Evented = EventedAgent
|
||||
|
@ -38,8 +38,6 @@ def state(name=None):
|
||||
self._last_return = None
|
||||
self._last_except = None
|
||||
|
||||
|
||||
|
||||
func.id = name or func.__name__
|
||||
func.is_default = False
|
||||
return func
|
||||
|
@ -81,4 +81,5 @@ class NetworkAgent(BaseAgent):
|
||||
self.remove_node()
|
||||
return super().die()
|
||||
|
||||
|
||||
NetAgent = NetworkAgent
|
||||
|
@ -313,19 +313,27 @@ class NetworkEnvironment(BaseEnvironment):
|
||||
|
||||
|
||||
class EventedEnvironment(BaseEnvironment):
|
||||
def broadcast(self, msg, sender=None, expiration=None, ttl=None, **kwargs):
|
||||
def broadcast(self, msg, sender=None, expiration=None, ttl=None, **kwargs):
|
||||
for agent in self.agents(**kwargs):
|
||||
if agent == sender:
|
||||
continue
|
||||
self.logger.info(f'Telling {repr(agent)}: {msg} ttl={ttl}')
|
||||
self.logger.info(f"Telling {repr(agent)}: {msg} ttl={ttl}")
|
||||
try:
|
||||
inbox = agent._inbox
|
||||
except AttributeError:
|
||||
self.logger.info(f'Agent {agent.unique_id} cannot receive events because it does not have an inbox')
|
||||
self.logger.info(
|
||||
f"Agent {agent.unique_id} cannot receive events because it does not have an inbox"
|
||||
)
|
||||
continue
|
||||
# Allow for AttributeError exceptions in this part of the code
|
||||
inbox.append(events.Tell(payload=msg, sender=sender, expiration=expiration if ttl is None else self.now+ttl))
|
||||
inbox.append(
|
||||
events.Tell(
|
||||
payload=msg,
|
||||
sender=sender,
|
||||
expiration=expiration if ttl is None else self.now + ttl,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Environment(NetworkEnvironment, EventedEnvironment):
|
||||
'''Default environment class, has both network and event capabilities'''
|
||||
"""Default environment class, has both network and event capabilities"""
|
||||
|
@ -3,9 +3,11 @@ from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
class Event:
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Message:
|
||||
payload: Any
|
||||
@ -17,6 +19,7 @@ class Message:
|
||||
def expired(self, when):
|
||||
return self.expiration is not None and self.expiration < when
|
||||
|
||||
|
||||
class Reply(Message):
|
||||
source: Message
|
||||
|
||||
|
10
soil/time.py
10
soil/time.py
@ -112,8 +112,9 @@ class TimedActivation(BaseScheduler):
|
||||
def _schedule(self, agent, condition=None, when=None):
|
||||
if condition:
|
||||
if not when:
|
||||
when, condition = condition.schedule_next(when or self.time,
|
||||
self.step_interval)
|
||||
when, condition = condition.schedule_next(
|
||||
when or self.time, self.step_interval
|
||||
)
|
||||
else:
|
||||
if when is None:
|
||||
when = self.time + self.step_interval
|
||||
@ -125,7 +126,6 @@ class TimedActivation(BaseScheduler):
|
||||
self._next[agent.unique_id] = key
|
||||
heappush(self._queue, (key, agent))
|
||||
|
||||
|
||||
def step(self) -> None:
|
||||
"""
|
||||
Executes agents in order, one at a time. After each step,
|
||||
@ -170,7 +170,9 @@ class TimedActivation(BaseScheduler):
|
||||
continue
|
||||
|
||||
if returned:
|
||||
next_check = returned.schedule_next(self.time, self.step_interval, first=True)
|
||||
next_check = returned.schedule_next(
|
||||
self.time, self.step_interval, first=True
|
||||
)
|
||||
self._schedule(agent, when=next_check[0], condition=next_check[1])
|
||||
else:
|
||||
next_check = (self.time + self.step_interval, None)
|
||||
|
@ -14,31 +14,32 @@ class Dead(agents.FSM):
|
||||
|
||||
class TestAgents(TestCase):
|
||||
def test_die_returns_infinity(self):
|
||||
'''The last step of a dead agent should return time.INFINITY'''
|
||||
"""The last step of a dead agent should return time.INFINITY"""
|
||||
d = Dead(unique_id=0, model=environment.Environment())
|
||||
ret = d.step()
|
||||
assert ret == stime.NEVER
|
||||
|
||||
def test_die_raises_exception(self):
|
||||
'''A dead agent should raise an exception if it is stepped after death'''
|
||||
"""A dead agent should raise an exception if it is stepped after death"""
|
||||
d = Dead(unique_id=0, model=environment.Environment())
|
||||
d.step()
|
||||
with pytest.raises(stime.DeadAgent):
|
||||
d.step()
|
||||
|
||||
|
||||
def test_agent_generator(self):
|
||||
'''
|
||||
"""
|
||||
The step function of an agent could be a generator. In that case, the state of the
|
||||
agent will be resumed after every call to step.
|
||||
'''
|
||||
"""
|
||||
a = 0
|
||||
|
||||
class Gen(agents.BaseAgent):
|
||||
def step(self):
|
||||
nonlocal a
|
||||
for i in range(5):
|
||||
yield
|
||||
a += 1
|
||||
|
||||
e = environment.Environment()
|
||||
g = Gen(model=e, unique_id=e.next_id())
|
||||
e.schedule.add(g)
|
||||
@ -50,8 +51,9 @@ class TestAgents(TestCase):
|
||||
def test_state_decorator(self):
|
||||
class MyAgent(agents.FSM):
|
||||
run = 0
|
||||
|
||||
@agents.default_state
|
||||
@agents.state('original')
|
||||
@agents.state("original")
|
||||
def root(self):
|
||||
self.run += 1
|
||||
return self.other
|
||||
@ -66,19 +68,19 @@ class TestAgents(TestCase):
|
||||
assert a.run == 1
|
||||
a.step()
|
||||
|
||||
|
||||
def test_broadcast(self):
|
||||
'''
|
||||
"""
|
||||
An agent should be able to broadcast messages to every other agent, AND each receiver should be able
|
||||
to process it
|
||||
'''
|
||||
"""
|
||||
|
||||
class BCast(agents.Evented):
|
||||
pings_received = 0
|
||||
|
||||
def step(self):
|
||||
print(self.model.broadcast)
|
||||
try:
|
||||
self.model.broadcast('PING')
|
||||
self.model.broadcast("PING")
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
while True:
|
||||
@ -96,12 +98,12 @@ class TestAgents(TestCase):
|
||||
pings_received = lambda: [a.pings_received for a in e.agents]
|
||||
assert sorted(pings_received()) == list(range(1, 11))
|
||||
e.step()
|
||||
assert all(x==10 for x in pings_received())
|
||||
assert all(x == 10 for x in pings_received())
|
||||
|
||||
def test_ask_messages(self):
|
||||
'''
|
||||
"""
|
||||
An agent should be able to ask another agent, and wait for a response.
|
||||
'''
|
||||
"""
|
||||
|
||||
# There are two agents, they try to send pings
|
||||
# This is arguably a very contrived example. In practice, the or
|
||||
@ -124,24 +126,24 @@ class TestAgents(TestCase):
|
||||
def step(self):
|
||||
target_id = (self.unique_id + 1) % self.count_agents()
|
||||
target = self.model.agents[target_id]
|
||||
print('starting')
|
||||
print("starting")
|
||||
while True:
|
||||
if pongs or not pings: #First agent, or anyone after that
|
||||
if pongs or not pings: # First agent, or anyone after that
|
||||
pings.append(self.now)
|
||||
response = yield target.ask('PING')
|
||||
response = yield target.ask("PING")
|
||||
responses.append(response)
|
||||
else:
|
||||
print('NOT sending ping')
|
||||
print('Checking msgs')
|
||||
print("NOT sending ping")
|
||||
print("Checking msgs")
|
||||
# Do not block if we have already received a PING
|
||||
if not self.check_messages():
|
||||
yield self.received()
|
||||
print('done')
|
||||
yield self.received()
|
||||
print("done")
|
||||
|
||||
def on_receive(self, msg, sender=None):
|
||||
if msg == 'PING':
|
||||
if msg == "PING":
|
||||
pongs.append(self.now)
|
||||
return 'PONG'
|
||||
return "PONG"
|
||||
raise Exception("This should never happen")
|
||||
|
||||
e = environment.EventedEnvironment(schedule_class=stime.OrderedTimedActivation)
|
||||
@ -149,7 +151,6 @@ class TestAgents(TestCase):
|
||||
e.add_agent(agent_class=Ping)
|
||||
assert e.now == 0
|
||||
|
||||
|
||||
for i in range(5):
|
||||
e.step()
|
||||
time = i + 1
|
||||
|
@ -44,7 +44,7 @@ def add_example_tests():
|
||||
for cfg, path in serialization.load_files(
|
||||
join(EXAMPLES, "**", "*.yml"),
|
||||
):
|
||||
if 'soil_output' in path:
|
||||
if "soil_output" in path:
|
||||
continue
|
||||
p = make_example_test(path=path, cfg=config.Config.from_raw(cfg))
|
||||
fname = os.path.basename(path)
|
||||
|
@ -182,8 +182,11 @@ class TestMain(TestCase):
|
||||
|
||||
n_trials = 50
|
||||
max_time = 2
|
||||
s = simulation.Simulation(model_params={'agents': [{'agent_class': CheckRun}]},
|
||||
num_trials=n_trials, max_time=max_time)
|
||||
s = simulation.Simulation(
|
||||
model_params={"agents": [{"agent_class": CheckRun}]},
|
||||
num_trials=n_trials,
|
||||
max_time=max_time,
|
||||
)
|
||||
runs = list(s.run_simulation(dry_run=True))
|
||||
over = list(x.now for x in runs if x.now > 2)
|
||||
assert len(runs) == n_trials
|
||||
|
@ -2,11 +2,12 @@ from unittest import TestCase
|
||||
|
||||
from soil import time, agents, environment
|
||||
|
||||
|
||||
class TestMain(TestCase):
|
||||
def test_cond(self):
|
||||
'''
|
||||
"""
|
||||
A condition should match a When if the concition is True
|
||||
'''
|
||||
"""
|
||||
|
||||
t = time.Cond(lambda t: True)
|
||||
f = time.Cond(lambda t: False)
|
||||
@ -16,17 +17,16 @@ class TestMain(TestCase):
|
||||
assert w is not f
|
||||
|
||||
def test_cond(self):
|
||||
'''
|
||||
"""
|
||||
Comparing a Cond to a Delta should always return False
|
||||
'''
|
||||
"""
|
||||
|
||||
c = time.Cond(lambda t: False)
|
||||
d = time.Delta(1)
|
||||
assert c is not d
|
||||
|
||||
def test_cond_env(self):
|
||||
'''
|
||||
'''
|
||||
""" """
|
||||
|
||||
times_started = []
|
||||
times_awakened = []
|
||||
@ -35,21 +35,18 @@ class TestMain(TestCase):
|
||||
done = []
|
||||
|
||||
class CondAgent(agents.BaseAgent):
|
||||
|
||||
def step(self):
|
||||
nonlocal done
|
||||
times_started.append(self.now)
|
||||
while True:
|
||||
times_asleep.append(self.now)
|
||||
yield time.Cond(lambda agent: agent.now >= 10,
|
||||
delta=2)
|
||||
yield time.Cond(lambda agent: agent.now >= 10, delta=2)
|
||||
times_awakened.append(self.now)
|
||||
if self.now >= 10:
|
||||
break
|
||||
done.append(self.now)
|
||||
|
||||
env = environment.Environment(agents=[{'agent_class': CondAgent}])
|
||||
|
||||
env = environment.Environment(agents=[{"agent_class": CondAgent}])
|
||||
|
||||
while env.schedule.time < 11:
|
||||
times.append(env.now)
|
||||
|
Loading…
Reference in New Issue
Block a user