1
0
mirror of https://github.com/gsi-upm/soil synced 2025-08-23 19:52:19 +00:00
* Removed old/unnecessary models
* Added a `simulation.{iter_}from_py` method to load simulations from python
files
* Changed tests of examples to run programmatic simulations
* Fixed programmatic examples
This commit is contained in:
J. Fernando Sánchez
2022-11-13 20:31:05 +01:00
parent d3cee18635
commit 2869b1e1e6
41 changed files with 499 additions and 1100 deletions

View File

@@ -1,4 +1,5 @@
from soil.agents import FSM, state, default_state
from soil.time import Delta
class Fibonacci(FSM):
@@ -11,7 +12,7 @@ class Fibonacci(FSM):
def counting(self):
self.log("Stopping at {}".format(self.now))
prev, self["prev"] = self["prev"], max([self.now, self["prev"]])
return None, self.env.timeout(prev)
return None, Delta(prev)
class Odds(FSM):
@@ -21,18 +22,26 @@ class Odds(FSM):
@state
def odds(self):
self.log("Stopping at {}".format(self.now))
return None, self.env.timeout(1 + self.now % 2)
return None, Delta(1 + self.now % 2)
from soil import Simulation
simulation = Simulation(
model_params={
'agents':[
{'agent_class': Fibonacci, 'node_id': 0},
{'agent_class': Odds, 'node_id': 1}
],
'topology': {
'params': {
'generator': 'complete_graph',
'n': 2
}
},
},
max_time=100,
)
if __name__ == "__main__":
from soil import Simulation
s = Simulation(
network_agents=[
{"ids": [0], "agent_class": Fibonacci},
{"ids": [1], "agent_class": Odds},
],
network_params={"generator": "complete_graph", "n": 2},
max_time=100,
)
s.run(dry_run=True)
simulation.run(dry_run=True)

View File

@@ -18,6 +18,7 @@ An example scenario could play like the following:
- If there are no more passengers available in the simulation, Drivers die
"""
from __future__ import annotations
from typing import Optional
from soil import *
from soil import events
from mesa.space import MultiGrid
@@ -39,7 +40,7 @@ class Journey:
tip: float
passenger: Passenger
driver: Driver = None
driver: Optional[Driver] = None
class City(EventedEnvironment):
@@ -239,5 +240,4 @@ simulation = Simulation(
)
if __name__ == "__main__":
with easy(simulation) as s:
s.run()
simulation.run()

View File

@@ -111,4 +111,5 @@ server = ModularServer(
)
server.port = 8521
server.launch(open_browser=False)
if __name__ == '__main__':
server.launch(open_browser=False)

View File

@@ -28,7 +28,7 @@ class MoneyAgent(MesaAgent):
It will only share wealth with neighbors based on grid proximity
"""
def __init__(self, unique_id, model, wealth=1):
def __init__(self, unique_id, model, wealth=1, **kwargs):
super().__init__(unique_id=unique_id, model=model)
self.wealth = wealth

View File

@@ -10,32 +10,48 @@ def mygenerator():
# Add only a node
G = Graph()
G.add_node(1)
G.add_node(2)
return G
class MyAgent(agents.FSM):
times_run = 0
@agents.default_state
@agents.state
def neutral(self):
self.debug("I am running")
if agents.prob(0.2):
if self.prob(0.2):
self.times_run += 1
self.info("This runs 2/10 times on average")
s = Simulation(
simulation = Simulation(
name="Programmatic",
network_params={"generator": mygenerator},
model_params={
'topology': {
'params': {
'generator': mygenerator
},
},
'agents': {
'distribution': [{
'agent_class': MyAgent,
'topology': True,
}]
}
},
seed='Program',
agent_reporters={'times_run': 'times_run'},
num_trials=1,
max_time=100,
agent_class=MyAgent,
dry_run=True,
)
if __name__ == "__main__":
# By default, logging will only print WARNING logs (and above).
# You need to choose a lower logging level to get INFO/DEBUG traces
logging.basicConfig(level=logging.INFO)
envs = simulation.run()
# By default, logging will only print WARNING logs (and above).
# You need to choose a lower logging level to get INFO/DEBUG traces
logging.basicConfig(level=logging.INFO)
envs = s.run()
# Uncomment this to output the simulation to a YAML file
# s.dump_yaml('simulation.yaml')
for agent in envs[0].agents:
print(agent.times_run)

View File

@@ -170,6 +170,6 @@ class Police(FSM):
if __name__ == "__main__":
from soil import simulation
from soil import run_from_config
simulation.run_from_config("pubcrawl.yml", dry_run=True, dump=None, parallel=False)
run_from_config("pubcrawl.yml", dry_run=True, dump=None, parallel=False)

View File

@@ -5,6 +5,8 @@ import math
class RabbitEnv(Environment):
prob_death = 1e-100
@property
def num_rabbits(self):
return self.count_agents(agent_class=Rabbit)
@@ -129,7 +131,7 @@ class RandomAccident(BaseAgent):
if not rabbits_alive:
return self.die()
prob_death = self.model.get("prob_death", 1e-100) * math.floor(
prob_death = self.model.prob_death * math.floor(
math.log10(max(1, rabbits_alive))
)
self.debug("Killing some rabbits with prob={}!".format(prob_death))

View File

@@ -31,11 +31,11 @@ class MyAgent(agents.FSM):
s = Simulation(
name="Programmatic",
network_agents=[{"agent_class": MyAgent, "id": 0}],
topology={"nodes": [{"id": 0}], "links": []},
model_params={
'agents': [{'agent_class': MyAgent}],
},
num_trials=1,
max_time=100,
agent_class=MyAgent,
dry_run=True,
)

View File

@@ -108,14 +108,14 @@ class TerroristSpreadModel(FSM, Geo):
return
return self.leader
def ego_search(self, steps=1, center=False, node=None, **kwargs):
def ego_search(self, steps=1, center=False, agent=None, **kwargs):
"""Get a list of nodes in the ego network of *node* of radius *steps*"""
node = as_node(node if node is not None else self)
node = agent.node
G = self.subgraph(**kwargs)
return nx.ego_graph(G, node, center=center, radius=steps).nodes()
def degree(self, node, force=False):
node = as_node(node)
def degree(self, agent, force=False):
node = agent.node
if (
force
or (not hasattr(self.model, "_degree"))
@@ -125,8 +125,8 @@ class TerroristSpreadModel(FSM, Geo):
self.model._last_step = self.now
return self.model._degree[node]
def betweenness(self, node, force=False):
node = as_node(node)
def betweenness(self, agent, force=False):
node = agent.node
if (
force
or (not hasattr(self.model, "_betweenness"))

View File

@@ -216,13 +216,13 @@
" @soil.agents.state\n",
" def neutral(self):\n",
" r = random.random()\n",
" if self['has_tv'] and r < self.env['prob_tv_spread']:\n",
" if self['has_tv'] and r < self.model['prob_tv_spread']:\n",
" return self.infected\n",
" return\n",
" \n",
" @soil.agents.state\n",
" def infected(self):\n",
" prob_infect = self.env['prob_neighbor_spread']\n",
" prob_infect = self.model['prob_neighbor_spread']\n",
" for neighbor in self.get_neighboring_agents(state_id=self.neutral.id):\n",
" r = random.random()\n",
" if r < prob_infect:\n",
@@ -271,11 +271,11 @@
"class NewsEnvironmentAgent(soil.agents.NetworkAgent):\n",
" def step(self):\n",
" if self.now == self['event_time']:\n",
" self.env['prob_tv_spread'] = 1\n",
" self.env['prob_neighbor_spread'] = 1\n",
" self.model['prob_tv_spread'] = 1\n",
" self.model['prob_neighbor_spread'] = 1\n",
" elif self.now > self['event_time']:\n",
" self.env['prob_tv_spread'] = self.env['prob_tv_spread'] * TV_FACTOR\n",
" self.env['prob_neighbor_spread'] = self.env['prob_neighbor_spread'] * NEIGHBOR_FACTOR"
" self.model['prob_tv_spread'] = self.model['prob_tv_spread'] * TV_FACTOR\n",
" self.model['prob_neighbor_spread'] = self.model['prob_neighbor_spread'] * NEIGHBOR_FACTOR"
]
},
{