mirror of
https://github.com/gsi-upm/soil
synced 2024-11-24 11:52:29 +00:00
WIP
This commit is contained in:
parent
0a9c6d8b19
commit
f811ee18c5
@ -3,13 +3,14 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [UNRELEASED]
|
||||
## [0.3 UNRELEASED]
|
||||
### Changed
|
||||
* Configuration schema is very different now. Check `soil.config` for more information. We are using Pydantic for (de)serialization.
|
||||
* Configuration schema is very different now. Check `soil.config` for more information. We are also using Pydantic for (de)serialization.
|
||||
* There may be more than one topology/network in the simulation
|
||||
* Agents are split into groups now. Each group may be assigned a given set of agents or an agent distribution, and a network topology to be assigned to.
|
||||
### Removed
|
||||
* Any `tsih` and `History` integration in the main classes. To record the state of environments/agents, just use a datacollector. In some cases this may be slower or consume more memory than the previous system. However, few cases actually used the full potential of the history, and it came at the cost of unnecessary complexity and worse performance for the majority of cases.
|
||||
|
||||
## [0.20.7]
|
||||
### Changed
|
||||
* Creating a `time.When` from another `time.When` does not nest them anymore (it returns the argument)
|
||||
|
55
README.md
55
README.md
@ -5,6 +5,42 @@ Learn how to run your own simulations with our [documentation](http://soilsim.re
|
||||
|
||||
Follow our [tutorial](examples/tutorial/soil_tutorial.ipynb) to develop your own agent models.
|
||||
|
||||
|
||||
# Changes in version 0.3
|
||||
|
||||
Version 0.3 came packed with many changes to provide much better integration with MESA.
|
||||
For a long time, we tried to keep soil backwards-compatible, but it turned out to be a big endeavour and the resulting code was less readable.
|
||||
This translates to harder maintenance and a worse experience for newcomers.
|
||||
In the end, we decided to make some breaking changes.
|
||||
|
||||
If you have an older Soil simulation, you have two options:
|
||||
|
||||
* Update the necessary configuration files and code. You may use the examples in the `examples` folder for reference, as well as the documentation.
|
||||
* Keep using a previous `soil` version.
|
||||
|
||||
## Mesa compatibility
|
||||
|
||||
Soil is in the process of becoming fully compatible with MESA.
|
||||
The idea is to provide a set of modular classes and functions that extend the functionality of mesa, whilst staying compatible.
|
||||
In the end, it should be possible to add regular mesa agents to a soil simulation, or use a soil agent within a mesa simulation/model.
|
||||
|
||||
This is a non-exhaustive list of tasks to achieve compatibility:
|
||||
|
||||
- [ ] Integrate `soil.Simulation` with mesa's runners:
|
||||
- [ ] `soil.Simulation` could mimic/become a `mesa.batchrunner`
|
||||
- [ ] Integrate `soil.Environment` with `mesa.Model`:
|
||||
- [x] `Soil.Environment` inherits from `mesa.Model`
|
||||
- [x] `Soil.Environment` includes a Mesa-like Scheduler (see the `soil.time` module.
|
||||
- [ ] Allow for `mesa.Model` to be used in a simulation.
|
||||
- [ ] Integrate `soil.Agent` with `mesa.Agent`:
|
||||
- [x] Rename agent.id to unique_id?
|
||||
- [x] mesa agents can be used in soil simulations (see `examples/mesa`)
|
||||
- [ ] Provide examples
|
||||
- [ ] Using mesa modules in a soil simulation
|
||||
- [ ] Using soil modules in a mesa simulation
|
||||
- [ ] Document the new APIs and usage
|
||||
|
||||
|
||||
## Citation
|
||||
|
||||
|
||||
@ -31,25 +67,6 @@ If you use Soil in your research, don't forget to cite this paper:
|
||||
|
||||
```
|
||||
|
||||
## Mesa compatibility
|
||||
|
||||
Soil is in the process of becoming fully compatible with MESA.
|
||||
As of this writing,
|
||||
|
||||
This is a non-exhaustive list of tasks to achieve compatibility:
|
||||
|
||||
* Environments.agents and mesa.Agent.agents are not the same. env is a property, and it only takes into account network and environment agents. Might rename environment_agents to other_agents or sth like that
|
||||
|
||||
- [ ] Integrate `soil.Simulation` with mesa's runners:
|
||||
- [ ] `soil.Simulation` could mimic/become a `mesa.batchrunner`
|
||||
- [ ] Integrate `soil.Environment` with `mesa.Model`:
|
||||
- [x] `Soil.Environment` inherits from `mesa.Model`
|
||||
- [x] `Soil.Environment` includes a Mesa-like Scheduler (see the `soil.time` module.
|
||||
- [ ] Integrate `soil.Agent` with `mesa.Agent`:
|
||||
- [x] Rename agent.id to unique_id?
|
||||
- [x] mesa agents can be used in soil simulations (see `examples/mesa`)
|
||||
- [ ] Document the new APIs and usage
|
||||
|
||||
@Copyright GSI - Universidad Politécnica de Madrid 2017-2021
|
||||
|
||||
[![SOIL](logo_gsi.png)](https://www.gsi.upm.es)
|
||||
|
@ -13,7 +13,7 @@ Here's an example (``example.yml``).
|
||||
|
||||
|
||||
This example configuration will run three trials (``num_trials``) of a simulation containing a randomly generated network (``network_params``).
|
||||
The 100 nodes in the network will be SISaModel agents (``network_agents.agent_type``), which is an agent behavior that is included in Soil.
|
||||
The 100 nodes in the network will be SISaModel agents (``network_agents.agent_class``), which is an agent behavior that is included in Soil.
|
||||
10% of the agents (``weight=1``) will start in the content state, 10% in the discontent state, and the remaining 80% (``weight=8``) in the neutral state.
|
||||
All agents will have access to the environment (``environment_params``), which only contains one variable, ``prob_infected``.
|
||||
The state of the agents will be updated every 2 seconds (``interval``).
|
||||
@ -116,7 +116,7 @@ Agents
|
||||
======
|
||||
|
||||
Agents are a way of modelling behavior.
|
||||
Agents can be characterized with two variables: agent type (``agent_type``) and state.
|
||||
Agents can be characterized with two variables: agent type (``agent_class``) and state.
|
||||
The agent type is a ``soil.Agent`` class, which contains the code that encapsulates the behavior of the agent.
|
||||
The state is a set of variables, which may change during the simulation, and that the code may use to control the behavior.
|
||||
All agents provide a ``step`` method either explicitly or implicitly (by inheriting it from a superclass), which controls how the agent will behave in each step of the simulation.
|
||||
@ -142,7 +142,7 @@ Hence, every node in the network will be associated to an agent of that type.
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
agent_type: SISaModel
|
||||
agent_class: SISaModel
|
||||
|
||||
It is also possible to add more than one type of agent to the simulation.
|
||||
|
||||
@ -152,9 +152,9 @@ For instance, with following configuration, it is five times more likely for a n
|
||||
.. code:: yaml
|
||||
|
||||
network_agents:
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
weight: 1
|
||||
- agent_type: CounterModel
|
||||
- agent_class: CounterModel
|
||||
weight: 5
|
||||
|
||||
The third option is to specify the type of agent on the node itself, e.g.:
|
||||
@ -165,10 +165,10 @@ The third option is to specify the type of agent on the node itself, e.g.:
|
||||
topology:
|
||||
nodes:
|
||||
- id: first
|
||||
agent_type: BaseAgent
|
||||
agent_class: BaseAgent
|
||||
states:
|
||||
first:
|
||||
agent_type: SISaModel
|
||||
agent_class: SISaModel
|
||||
|
||||
|
||||
This would also work with a randomly generated network:
|
||||
@ -179,9 +179,9 @@ This would also work with a randomly generated network:
|
||||
network:
|
||||
generator: complete
|
||||
n: 5
|
||||
agent_type: BaseAgent
|
||||
agent_class: BaseAgent
|
||||
states:
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
|
||||
|
||||
|
||||
@ -192,11 +192,11 @@ e.g., to populate the network with SISaModel, roughly 10% of them with a discont
|
||||
.. code:: yaml
|
||||
|
||||
network_agents:
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
weight: 9
|
||||
state:
|
||||
id: neutral
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: discontent
|
||||
@ -206,7 +206,7 @@ For instance, to add a state for the two nodes in this configuration:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
agent_type: SISaModel
|
||||
agent_class: SISaModel
|
||||
network:
|
||||
generator: complete_graph
|
||||
n: 2
|
||||
@ -231,10 +231,10 @@ These agents are programmed in much the same way as network agents, the only dif
|
||||
.. code::
|
||||
|
||||
environment_agents:
|
||||
- agent_type: MyAgent
|
||||
- agent_class: MyAgent
|
||||
state:
|
||||
mood: happy
|
||||
- agent_type: DummyAgent
|
||||
- agent_class: DummyAgent
|
||||
|
||||
|
||||
You may use environment agents to model events that a normal agent cannot control, such as natural disasters or chance.
|
||||
|
@ -8,15 +8,15 @@ network_params:
|
||||
n: 100
|
||||
m: 2
|
||||
network_agents:
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: content
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: discontent
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
weight: 8
|
||||
state:
|
||||
id: neutral
|
||||
|
@ -3,11 +3,11 @@ name: quickstart
|
||||
num_trials: 1
|
||||
max_time: 1000
|
||||
network_agents:
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
state:
|
||||
id: neutral
|
||||
weight: 1
|
||||
- agent_type: SISaModel
|
||||
- agent_class: SISaModel
|
||||
state:
|
||||
id: content
|
||||
weight: 2
|
||||
|
@ -211,11 +211,11 @@ nodes in that network. Notice how node 0 is the only one with a TV.
|
||||
sim = soil.Simulation(topology=G,
|
||||
num_trials=1,
|
||||
max_time=MAX_TIME,
|
||||
environment_agents=[{'agent_type': NewsEnvironmentAgent,
|
||||
environment_agents=[{'agent_class': NewsEnvironmentAgent,
|
||||
'state': {
|
||||
'event_time': EVENT_TIME
|
||||
}}],
|
||||
network_agents=[{'agent_type': NewsSpread,
|
||||
network_agents=[{'agent_class': NewsSpread,
|
||||
'weight': 1}],
|
||||
states={0: {'has_tv': True}},
|
||||
default_state={'has_tv': False},
|
||||
@ -285,14 +285,14 @@ For this demo, we will use a python dictionary:
|
||||
},
|
||||
'network_agents': [
|
||||
{
|
||||
'agent_type': NewsSpread,
|
||||
'agent_class': NewsSpread,
|
||||
'weight': 1,
|
||||
'state': {
|
||||
'has_tv': False
|
||||
}
|
||||
},
|
||||
{
|
||||
'agent_type': NewsSpread,
|
||||
'agent_class': NewsSpread,
|
||||
'weight': 2,
|
||||
'state': {
|
||||
'has_tv': True
|
||||
@ -300,7 +300,7 @@ For this demo, we will use a python dictionary:
|
||||
}
|
||||
],
|
||||
'environment_agents':[
|
||||
{'agent_type': NewsEnvironmentAgent,
|
||||
{'agent_class': NewsEnvironmentAgent,
|
||||
'state': {
|
||||
'event_time': 10
|
||||
}
|
||||
|
@ -98,11 +98,11 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_all_dumb\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: false\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
@ -122,19 +122,19 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_half_herd\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: false\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: false\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
@ -154,12 +154,12 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_all_herd\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
@ -181,12 +181,12 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_wise_herd\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: WiseViewer\r\n",
|
||||
"- agent_class: WiseViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
@ -207,12 +207,12 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_all_wise\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: WiseViewer\r\n",
|
||||
"- agent_class: WiseViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: WiseViewer\r\n",
|
||||
"- agent_class: WiseViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
|
@ -141,10 +141,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -1758,10 +1758,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -3363,10 +3363,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -4977,10 +4977,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -6591,10 +6591,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -8211,10 +8211,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -9828,10 +9828,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -11448,10 +11448,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -13062,10 +13062,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -14679,10 +14679,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -16296,10 +16296,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -17916,10 +17916,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -19521,10 +19521,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -21144,10 +21144,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -22767,10 +22767,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -24375,10 +24375,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -25992,10 +25992,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -27603,10 +27603,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -29220,10 +29220,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -30819,10 +30819,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -32439,10 +32439,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -34056,10 +34056,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -35676,10 +35676,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -37293,10 +37293,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -38913,10 +38913,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -40518,10 +40518,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -42129,10 +42129,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -43746,10 +43746,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -45357,10 +45357,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -46974,10 +46974,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -48588,10 +48588,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -50202,10 +50202,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -51819,10 +51819,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -53436,10 +53436,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -55041,10 +55041,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -56655,10 +56655,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -58257,10 +58257,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -59877,10 +59877,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -61494,10 +61494,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -63108,10 +63108,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -64713,10 +64713,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -66330,10 +66330,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -67947,10 +67947,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -69561,10 +69561,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -71178,10 +71178,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -72801,10 +72801,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -74418,10 +74418,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -76035,10 +76035,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -77643,10 +77643,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
@ -79260,10 +79260,10 @@
|
||||
" 'load_module': 'newsspread',\n",
|
||||
" 'max_time': 30,\n",
|
||||
" 'name': 'Sim_all_dumb',\n",
|
||||
" 'network_agents': [{'agent_type': 'DumbViewer',\n",
|
||||
" 'network_agents': [{'agent_class': 'DumbViewer',\n",
|
||||
" 'state': {'has_tv': False},\n",
|
||||
" 'weight': 1},\n",
|
||||
" {'agent_type': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" {'agent_class': 'DumbViewer', 'state': {'has_tv': True}, 'weight': 1}],\n",
|
||||
" 'network_params': {'generator': 'barabasi_albert_graph', 'm': 5, 'n': 500},\n",
|
||||
" 'num_trials': 50,\n",
|
||||
" 'seed': 'None',\n",
|
||||
|
@ -30,6 +30,7 @@ agents:
|
||||
times: 1
|
||||
environment:
|
||||
# In this group we are not specifying any topology
|
||||
topology: False
|
||||
fixed:
|
||||
- name: 'Environment Agent 1'
|
||||
agent_class: CounterModel
|
||||
|
@ -10,7 +10,7 @@ network_params:
|
||||
n: 10
|
||||
n_edges: 5
|
||||
network_agents:
|
||||
- agent_type: CounterModel
|
||||
- agent_class: CounterModel
|
||||
weight: 1
|
||||
state:
|
||||
state_id: 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
from networkx import Graph
|
||||
import networkx as nx
|
||||
from random import choice
|
||||
|
||||
def mygenerator(n=5, n_edges=5):
|
||||
'''
|
||||
@ -14,9 +13,9 @@ def mygenerator(n=5, n_edges=5):
|
||||
|
||||
for i in range(n_edges):
|
||||
nodes = list(G.nodes)
|
||||
n_in = choice(nodes)
|
||||
n_in = self.random.choice(nodes)
|
||||
nodes.remove(n_in) # Avoid loops
|
||||
n_out = choice(nodes)
|
||||
n_out = self.random.choice(nodes)
|
||||
G.add_edge(n_in, n_out)
|
||||
return G
|
||||
|
||||
@ -24,4 +23,4 @@ def mygenerator(n=5, n_edges=5):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -27,8 +27,8 @@ if __name__ == '__main__':
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
from soil import Simulation
|
||||
s = Simulation(network_agents=[{'ids': [0], 'agent_type': Fibonacci},
|
||||
{'ids': [1], 'agent_type': Odds}],
|
||||
s = Simulation(network_agents=[{'ids': [0], 'agent_class': Fibonacci},
|
||||
{'ids': [1], 'agent_class': Odds}],
|
||||
network_params={"generator": "complete_graph", "n": 2},
|
||||
max_time=100,
|
||||
)
|
||||
|
@ -10,11 +10,11 @@ network_params:
|
||||
generator: social_wealth.graph_generator
|
||||
n: 5
|
||||
network_agents:
|
||||
- agent_type: social_wealth.SocialMoneyAgent
|
||||
- agent_class: social_wealth.SocialMoneyAgent
|
||||
weight: 1
|
||||
environment_class: social_wealth.MoneyEnv
|
||||
environment_params:
|
||||
mesa_agent_type: social_wealth.MoneyAgent
|
||||
mesa_agent_class: social_wealth.MoneyAgent
|
||||
N: 10
|
||||
width: 50
|
||||
height: 50
|
||||
|
@ -70,7 +70,7 @@ model_params = {
|
||||
1,
|
||||
description="Choose how many agents to include in the model",
|
||||
),
|
||||
"network_agents": [{"agent_type": SocialMoneyAgent}],
|
||||
"network_agents": [{"agent_class": SocialMoneyAgent}],
|
||||
"height": UserSettableParameter(
|
||||
"slider",
|
||||
"height",
|
||||
|
@ -99,7 +99,7 @@ if __name__ == '__main__':
|
||||
G = graph_generator()
|
||||
fixed_params = {"topology": G,
|
||||
"width": 10,
|
||||
"network_agents": [{"agent_type": SocialMoneyAgent,
|
||||
"network_agents": [{"agent_class": SocialMoneyAgent,
|
||||
'weight': 1}],
|
||||
"height": 10}
|
||||
|
||||
|
@ -89,11 +89,11 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_all_dumb\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: false\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
@ -113,19 +113,19 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_half_herd\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: false\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: DumbViewer\r\n",
|
||||
"- agent_class: DumbViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: false\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
@ -145,12 +145,12 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_all_herd\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
@ -172,12 +172,12 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_wise_herd\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: HerdViewer\r\n",
|
||||
"- agent_class: HerdViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: WiseViewer\r\n",
|
||||
"- agent_class: WiseViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
@ -198,12 +198,12 @@
|
||||
"max_time: 30\r\n",
|
||||
"name: Sim_all_wise\r\n",
|
||||
"network_agents:\r\n",
|
||||
"- agent_type: WiseViewer\r\n",
|
||||
"- agent_class: WiseViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" id: neutral\r\n",
|
||||
" weight: 1\r\n",
|
||||
"- agent_type: WiseViewer\r\n",
|
||||
"- agent_class: WiseViewer\r\n",
|
||||
" state:\r\n",
|
||||
" has_tv: true\r\n",
|
||||
" weight: 1\r\n",
|
||||
|
@ -8,11 +8,11 @@ interval: 1
|
||||
max_time: 300
|
||||
name: Sim_all_dumb
|
||||
network_agents:
|
||||
- agent_type: newsspread.DumbViewer
|
||||
- agent_class: newsspread.DumbViewer
|
||||
state:
|
||||
has_tv: false
|
||||
weight: 1
|
||||
- agent_type: newsspread.DumbViewer
|
||||
- agent_class: newsspread.DumbViewer
|
||||
state:
|
||||
has_tv: true
|
||||
weight: 1
|
||||
@ -31,19 +31,19 @@ interval: 1
|
||||
max_time: 300
|
||||
name: Sim_half_herd
|
||||
network_agents:
|
||||
- agent_type: newsspread.DumbViewer
|
||||
- agent_class: newsspread.DumbViewer
|
||||
state:
|
||||
has_tv: false
|
||||
weight: 1
|
||||
- agent_type: newsspread.DumbViewer
|
||||
- agent_class: newsspread.DumbViewer
|
||||
state:
|
||||
has_tv: true
|
||||
weight: 1
|
||||
- agent_type: newsspread.HerdViewer
|
||||
- agent_class: newsspread.HerdViewer
|
||||
state:
|
||||
has_tv: false
|
||||
weight: 1
|
||||
- agent_type: newsspread.HerdViewer
|
||||
- agent_class: newsspread.HerdViewer
|
||||
state:
|
||||
has_tv: true
|
||||
weight: 1
|
||||
@ -62,12 +62,12 @@ interval: 1
|
||||
max_time: 300
|
||||
name: Sim_all_herd
|
||||
network_agents:
|
||||
- agent_type: newsspread.HerdViewer
|
||||
- agent_class: newsspread.HerdViewer
|
||||
state:
|
||||
has_tv: true
|
||||
state_id: neutral
|
||||
weight: 1
|
||||
- agent_type: newsspread.HerdViewer
|
||||
- agent_class: newsspread.HerdViewer
|
||||
state:
|
||||
has_tv: true
|
||||
state_id: neutral
|
||||
@ -88,12 +88,12 @@ interval: 1
|
||||
max_time: 300
|
||||
name: Sim_wise_herd
|
||||
network_agents:
|
||||
- agent_type: newsspread.HerdViewer
|
||||
- agent_class: newsspread.HerdViewer
|
||||
state:
|
||||
has_tv: true
|
||||
state_id: neutral
|
||||
weight: 1
|
||||
- agent_type: newsspread.WiseViewer
|
||||
- agent_class: newsspread.WiseViewer
|
||||
state:
|
||||
has_tv: true
|
||||
weight: 1
|
||||
@ -113,12 +113,12 @@ interval: 1
|
||||
max_time: 300
|
||||
name: Sim_all_wise
|
||||
network_agents:
|
||||
- agent_type: newsspread.WiseViewer
|
||||
- agent_class: newsspread.WiseViewer
|
||||
state:
|
||||
has_tv: true
|
||||
state_id: neutral
|
||||
weight: 1
|
||||
- agent_type: newsspread.WiseViewer
|
||||
- agent_class: newsspread.WiseViewer
|
||||
state:
|
||||
has_tv: true
|
||||
weight: 1
|
||||
|
@ -27,7 +27,7 @@ s = Simulation(name='Programmatic',
|
||||
network_params={'generator': mygenerator},
|
||||
num_trials=1,
|
||||
max_time=100,
|
||||
agent_type=MyAgent,
|
||||
agent_class=MyAgent,
|
||||
dry_run=True)
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
from soil.agents import FSM, NetworkAgent, state, default_state
|
||||
from soil import Environment
|
||||
from random import random, shuffle
|
||||
from itertools import islice
|
||||
import logging
|
||||
|
||||
@ -128,7 +127,7 @@ class Patron(FSM, NetworkAgent):
|
||||
Try to become friends with another agent. The chances of
|
||||
success depend on both agents' openness.
|
||||
'''
|
||||
if force or self['openness'] > random():
|
||||
if force or self['openness'] > self.random.random():
|
||||
self.env.add_edge(self, other_agent)
|
||||
self.info('Made some friend {}'.format(other_agent))
|
||||
return True
|
||||
@ -138,7 +137,7 @@ class Patron(FSM, NetworkAgent):
|
||||
''' Look for random agents around me and try to befriend them'''
|
||||
befriended = False
|
||||
k = int(10*self['openness'])
|
||||
shuffle(others)
|
||||
self.random.shuffle(others)
|
||||
for friend in islice(others, k): # random.choice >= 3.7
|
||||
if friend == self:
|
||||
continue
|
||||
|
@ -8,18 +8,18 @@ network_params:
|
||||
generator: empty_graph
|
||||
n: 30
|
||||
network_agents:
|
||||
- agent_type: pubcrawl.Patron
|
||||
- agent_class: pubcrawl.Patron
|
||||
description: Extroverted patron
|
||||
state:
|
||||
openness: 1.0
|
||||
weight: 9
|
||||
- agent_type: pubcrawl.Patron
|
||||
- agent_class: pubcrawl.Patron
|
||||
description: Introverted patron
|
||||
state:
|
||||
openness: 0.1
|
||||
weight: 1
|
||||
environment_agents:
|
||||
- agent_type: pubcrawl.Police
|
||||
- agent_class: pubcrawl.Police
|
||||
environment_class: pubcrawl.CityPubs
|
||||
environment_params:
|
||||
altercations: 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
from soil.agents import FSM, state, default_state, BaseAgent, NetworkAgent
|
||||
from enum import Enum
|
||||
from random import random, choice
|
||||
import logging
|
||||
import math
|
||||
|
||||
@ -57,10 +56,10 @@ class Male(RabbitModel):
|
||||
|
||||
# Males try to mate
|
||||
for f in self.get_agents(state_id=Female.fertile.id,
|
||||
agent_type=Female,
|
||||
agent_class=Female,
|
||||
limit_neighbors=False,
|
||||
limit=self.max_females):
|
||||
r = random()
|
||||
r = self.random.random()
|
||||
if r < self['mating_prob']:
|
||||
self.impregnate(f)
|
||||
break # Take a break
|
||||
@ -85,11 +84,11 @@ class Female(RabbitModel):
|
||||
self['pregnancy'] += 1
|
||||
self.debug('Pregnancy: {}'.format(self['pregnancy']))
|
||||
if self['pregnancy'] >= self.gestation:
|
||||
number_of_babies = int(8+4*random())
|
||||
number_of_babies = int(8+4*self.random.random())
|
||||
self.info('Having {} babies'.format(number_of_babies))
|
||||
for i in range(number_of_babies):
|
||||
state = {}
|
||||
state['gender'] = choice(list(Genders)).value
|
||||
state['gender'] = self.random.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)
|
||||
@ -124,8 +123,7 @@ class RandomAccident(BaseAgent):
|
||||
for i in self.env.network_agents:
|
||||
if i.state['id'] == i.dead.id:
|
||||
continue
|
||||
r = random()
|
||||
if r < prob_death:
|
||||
if self.prob(prob_death):
|
||||
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']))
|
||||
|
@ -3,9 +3,9 @@ name: rabbits_example
|
||||
max_time: 100
|
||||
interval: 1
|
||||
seed: MySeed
|
||||
agent_type: rabbit_agents.RabbitModel
|
||||
agent_class: rabbit_agents.RabbitModel
|
||||
environment_agents:
|
||||
- agent_type: rabbit_agents.RandomAccident
|
||||
- agent_class: rabbit_agents.RandomAccident
|
||||
environment_params:
|
||||
prob_death: 0.001
|
||||
default_state:
|
||||
@ -13,8 +13,8 @@ default_state:
|
||||
topology:
|
||||
nodes:
|
||||
- id: 1
|
||||
agent_type: rabbit_agents.Male
|
||||
agent_class: rabbit_agents.Male
|
||||
- id: 0
|
||||
agent_type: rabbit_agents.Female
|
||||
agent_class: rabbit_agents.Female
|
||||
directed: true
|
||||
links: []
|
||||
|
@ -4,7 +4,6 @@ Example of a fully programmatic simulation, without definition files.
|
||||
'''
|
||||
from soil import Simulation, agents
|
||||
from soil.time import Delta
|
||||
from random import expovariate
|
||||
import logging
|
||||
|
||||
|
||||
@ -20,7 +19,7 @@ class MyAgent(agents.FSM):
|
||||
@agents.state
|
||||
def ping(self):
|
||||
self.info('Ping')
|
||||
return self.pong, Delta(expovariate(1/16))
|
||||
return self.pong, Delta(self.random.expovariate(1/16))
|
||||
|
||||
@agents.state
|
||||
def pong(self):
|
||||
@ -29,15 +28,15 @@ class MyAgent(agents.FSM):
|
||||
self.info(str(self.pong_counts))
|
||||
if self.pong_counts < 1:
|
||||
return self.die()
|
||||
return None, Delta(expovariate(1/16))
|
||||
return None, Delta(self.random.expovariate(1/16))
|
||||
|
||||
|
||||
s = Simulation(name='Programmatic',
|
||||
network_agents=[{'agent_type': MyAgent, 'id': 0}],
|
||||
network_agents=[{'agent_class': MyAgent, 'id': 0}],
|
||||
topology={'nodes': [{'id': 0}], 'links': []},
|
||||
num_trials=1,
|
||||
max_time=100,
|
||||
agent_type=MyAgent,
|
||||
agent_class=MyAgent,
|
||||
dry_run=True)
|
||||
|
||||
|
||||
|
@ -13,11 +13,11 @@ template:
|
||||
generator: complete_graph
|
||||
n: 10
|
||||
network_agents:
|
||||
- agent_type: CounterModel
|
||||
- agent_class: CounterModel
|
||||
weight: "{{ x1 }}"
|
||||
state:
|
||||
state_id: 0
|
||||
- agent_type: AggregatedCounter
|
||||
- agent_class: AggregatedCounter
|
||||
weight: "{{ 1 - x1 }}"
|
||||
environment_params:
|
||||
name: "{{ x3 }}"
|
||||
|
@ -1,4 +1,3 @@
|
||||
import random
|
||||
import networkx as nx
|
||||
from soil.agents import Geo, NetworkAgent, FSM, state, default_state
|
||||
from soil import Environment
|
||||
@ -26,26 +25,26 @@ class TerroristSpreadModel(FSM, Geo):
|
||||
self.prob_interaction = model.environment_params['prob_interaction']
|
||||
|
||||
if self['id'] == self.civilian.id: # Civilian
|
||||
self.mean_belief = random.uniform(0.00, 0.5)
|
||||
self.mean_belief = self.random.uniform(0.00, 0.5)
|
||||
elif self['id'] == self.terrorist.id: # Terrorist
|
||||
self.mean_belief = random.uniform(0.8, 1.00)
|
||||
self.mean_belief = self.random.uniform(0.8, 1.00)
|
||||
elif self['id'] == self.leader.id: # Leader
|
||||
self.mean_belief = 1.00
|
||||
else:
|
||||
raise Exception('Invalid state id: {}'.format(self['id']))
|
||||
|
||||
if 'min_vulnerability' in model.environment_params:
|
||||
self.vulnerability = random.uniform( model.environment_params['min_vulnerability'], model.environment_params['max_vulnerability'] )
|
||||
self.vulnerability = self.random.uniform( model.environment_params['min_vulnerability'], model.environment_params['max_vulnerability'] )
|
||||
else :
|
||||
self.vulnerability = random.uniform( 0, model.environment_params['max_vulnerability'] )
|
||||
self.vulnerability = self.random.uniform( 0, model.environment_params['max_vulnerability'] )
|
||||
|
||||
|
||||
@state
|
||||
def civilian(self):
|
||||
neighbours = list(self.get_neighboring_agents(agent_type=TerroristSpreadModel))
|
||||
neighbours = list(self.get_neighboring_agents(agent_class=TerroristSpreadModel))
|
||||
if len(neighbours) > 0:
|
||||
# Only interact with some of the neighbors
|
||||
interactions = list(n for n in neighbours if random.random() <= self.prob_interaction)
|
||||
interactions = list(n for n in neighbours if self.random.random() <= self.prob_interaction)
|
||||
influence = sum( self.degree(i) for i in interactions )
|
||||
mean_belief = sum( i.mean_belief * self.degree(i) / influence for i in interactions )
|
||||
mean_belief = mean_belief * self.information_spread_intensity + self.mean_belief * ( 1 - self.information_spread_intensity )
|
||||
@ -64,7 +63,7 @@ class TerroristSpreadModel(FSM, Geo):
|
||||
@state
|
||||
def terrorist(self):
|
||||
neighbours = self.get_agents(state_id=[self.terrorist.id, self.leader.id],
|
||||
agent_type=TerroristSpreadModel,
|
||||
agent_class=TerroristSpreadModel,
|
||||
limit_neighbors=True)
|
||||
if len(neighbours) > 0:
|
||||
influence = sum( self.degree(n) for n in neighbours )
|
||||
@ -103,7 +102,7 @@ class TrainingAreaModel(FSM, Geo):
|
||||
@default_state
|
||||
@state
|
||||
def terrorist(self):
|
||||
for neighbour in self.get_neighboring_agents(agent_type=TerroristSpreadModel):
|
||||
for neighbour in self.get_neighboring_agents(agent_class=TerroristSpreadModel):
|
||||
if neighbour.vulnerability > self.min_vulnerability:
|
||||
neighbour.vulnerability = neighbour.vulnerability ** ( 1 - self.training_influence )
|
||||
|
||||
@ -129,7 +128,7 @@ class HavenModel(FSM, Geo):
|
||||
self.max_vulnerability = model.environment_params['max_vulnerability']
|
||||
|
||||
def get_occupants(self, **kwargs):
|
||||
return self.get_neighboring_agents(agent_type=TerroristSpreadModel, **kwargs)
|
||||
return self.get_neighboring_agents(agent_class=TerroristSpreadModel, **kwargs)
|
||||
|
||||
@state
|
||||
def civilian(self):
|
||||
@ -182,15 +181,15 @@ class TerroristNetworkModel(TerroristSpreadModel):
|
||||
|
||||
def update_relationships(self):
|
||||
if self.count_neighboring_agents(state_id=self.civilian.id) == 0:
|
||||
close_ups = set(self.geo_search(radius=self.vision_range, agent_type=TerroristNetworkModel))
|
||||
step_neighbours = set(self.ego_search(self.sphere_influence, agent_type=TerroristNetworkModel, center=False))
|
||||
neighbours = set(agent.id for agent in self.get_neighboring_agents(agent_type=TerroristNetworkModel))
|
||||
close_ups = set(self.geo_search(radius=self.vision_range, agent_class=TerroristNetworkModel))
|
||||
step_neighbours = set(self.ego_search(self.sphere_influence, agent_class=TerroristNetworkModel, center=False))
|
||||
neighbours = set(agent.id for agent in self.get_neighboring_agents(agent_class=TerroristNetworkModel))
|
||||
search = (close_ups | step_neighbours) - neighbours
|
||||
for agent in self.get_agents(search):
|
||||
social_distance = 1 / self.shortest_path_length(agent.id)
|
||||
spatial_proximity = ( 1 - self.get_distance(agent.id) )
|
||||
prob_new_interaction = self.weight_social_distance * social_distance + self.weight_link_distance * spatial_proximity
|
||||
if agent['id'] == agent.civilian.id and random.random() < prob_new_interaction:
|
||||
if agent['id'] == agent.civilian.id and self.random.random() < prob_new_interaction:
|
||||
self.add_edge(agent)
|
||||
break
|
||||
|
||||
|
@ -8,19 +8,19 @@ network_params:
|
||||
# theta: 20
|
||||
n: 100
|
||||
network_agents:
|
||||
- agent_type: TerroristNetworkModel.TerroristNetworkModel
|
||||
- agent_class: TerroristNetworkModel.TerroristNetworkModel
|
||||
weight: 0.8
|
||||
state:
|
||||
id: civilian # Civilians
|
||||
- agent_type: TerroristNetworkModel.TerroristNetworkModel
|
||||
- agent_class: TerroristNetworkModel.TerroristNetworkModel
|
||||
weight: 0.1
|
||||
state:
|
||||
id: leader # Leaders
|
||||
- agent_type: TerroristNetworkModel.TrainingAreaModel
|
||||
- agent_class: TerroristNetworkModel.TrainingAreaModel
|
||||
weight: 0.05
|
||||
state:
|
||||
id: terrorist # Terrorism
|
||||
- agent_type: TerroristNetworkModel.HavenModel
|
||||
- agent_class: TerroristNetworkModel.HavenModel
|
||||
weight: 0.05
|
||||
state:
|
||||
id: civilian # Civilian
|
||||
|
@ -2,7 +2,7 @@
|
||||
name: torvalds_example
|
||||
max_time: 10
|
||||
interval: 2
|
||||
agent_type: CounterModel
|
||||
agent_class: CounterModel
|
||||
default_state:
|
||||
skill_level: 'beginner'
|
||||
network_params:
|
||||
|
@ -12330,11 +12330,11 @@ Notice how node 0 is the only one with a TV.</p>
|
||||
<span class="n">sim</span> <span class="o">=</span> <span class="n">soil</span><span class="o">.</span><span class="n">Simulation</span><span class="p">(</span><span class="n">topology</span><span class="o">=</span><span class="n">G</span><span class="p">,</span>
|
||||
<span class="n">num_trials</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="n">max_time</span><span class="o">=</span><span class="n">MAX_TIME</span><span class="p">,</span>
|
||||
<span class="n">environment_agents</span><span class="o">=</span><span class="p">[{</span><span class="s1">'agent_type'</span><span class="p">:</span> <span class="n">NewsEnvironmentAgent</span><span class="p">,</span>
|
||||
<span class="n">environment_agents</span><span class="o">=</span><span class="p">[{</span><span class="s1">'agent_class'</span><span class="p">:</span> <span class="n">NewsEnvironmentAgent</span><span class="p">,</span>
|
||||
<span class="s1">'state'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'event_time'</span><span class="p">:</span> <span class="n">EVENT_TIME</span>
|
||||
<span class="p">}}],</span>
|
||||
<span class="n">network_agents</span><span class="o">=</span><span class="p">[{</span><span class="s1">'agent_type'</span><span class="p">:</span> <span class="n">NewsSpread</span><span class="p">,</span>
|
||||
<span class="n">network_agents</span><span class="o">=</span><span class="p">[{</span><span class="s1">'agent_class'</span><span class="p">:</span> <span class="n">NewsSpread</span><span class="p">,</span>
|
||||
<span class="s1">'weight'</span><span class="p">:</span> <span class="mi">1</span><span class="p">}],</span>
|
||||
<span class="n">states</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="p">{</span><span class="s1">'has_tv'</span><span class="p">:</span> <span class="kc">True</span><span class="p">}},</span>
|
||||
<span class="n">default_state</span><span class="o">=</span><span class="p">{</span><span class="s1">'has_tv'</span><span class="p">:</span> <span class="kc">False</span><span class="p">},</span>
|
||||
@ -12468,14 +12468,14 @@ For this demo, we will use a python dictionary:</p>
|
||||
<span class="p">},</span>
|
||||
<span class="s1">'network_agents'</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s1">'agent_type'</span><span class="p">:</span> <span class="n">NewsSpread</span><span class="p">,</span>
|
||||
<span class="s1">'agent_class'</span><span class="p">:</span> <span class="n">NewsSpread</span><span class="p">,</span>
|
||||
<span class="s1">'weight'</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
||||
<span class="s1">'state'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'has_tv'</span><span class="p">:</span> <span class="kc">False</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s1">'agent_type'</span><span class="p">:</span> <span class="n">NewsSpread</span><span class="p">,</span>
|
||||
<span class="s1">'agent_class'</span><span class="p">:</span> <span class="n">NewsSpread</span><span class="p">,</span>
|
||||
<span class="s1">'weight'</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
|
||||
<span class="s1">'state'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'has_tv'</span><span class="p">:</span> <span class="kc">True</span>
|
||||
@ -12483,7 +12483,7 @@ For this demo, we will use a python dictionary:</p>
|
||||
<span class="p">}</span>
|
||||
<span class="p">],</span>
|
||||
<span class="s1">'environment_agents'</span><span class="p">:[</span>
|
||||
<span class="p">{</span><span class="s1">'agent_type'</span><span class="p">:</span> <span class="n">NewsEnvironmentAgent</span><span class="p">,</span>
|
||||
<span class="p">{</span><span class="s1">'agent_class'</span><span class="p">:</span> <span class="n">NewsEnvironmentAgent</span><span class="p">,</span>
|
||||
<span class="s1">'state'</span><span class="p">:</span> <span class="p">{</span>
|
||||
<span class="s1">'event_time'</span><span class="p">:</span> <span class="mi">10</span>
|
||||
<span class="p">}</span>
|
||||
|
@ -459,11 +459,11 @@
|
||||
"sim = soil.Simulation(topology=G,\n",
|
||||
" num_trials=1,\n",
|
||||
" max_time=MAX_TIME,\n",
|
||||
" environment_agents=[{'agent_type': NewsEnvironmentAgent,\n",
|
||||
" environment_agents=[{'agent_class': NewsEnvironmentAgent,\n",
|
||||
" 'state': {\n",
|
||||
" 'event_time': EVENT_TIME\n",
|
||||
" }}],\n",
|
||||
" network_agents=[{'agent_type': NewsSpread,\n",
|
||||
" network_agents=[{'agent_class': NewsSpread,\n",
|
||||
" 'weight': 1}],\n",
|
||||
" states={0: {'has_tv': True}},\n",
|
||||
" default_state={'has_tv': False},\n",
|
||||
@ -588,14 +588,14 @@
|
||||
" },\n",
|
||||
" 'network_agents': [\n",
|
||||
" {\n",
|
||||
" 'agent_type': NewsSpread,\n",
|
||||
" 'agent_class': NewsSpread,\n",
|
||||
" 'weight': 1,\n",
|
||||
" 'state': {\n",
|
||||
" 'has_tv': False\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" 'agent_type': NewsSpread,\n",
|
||||
" 'agent_class': NewsSpread,\n",
|
||||
" 'weight': 2,\n",
|
||||
" 'state': {\n",
|
||||
" 'has_tv': True\n",
|
||||
@ -603,7 +603,7 @@
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" 'environment_agents':[\n",
|
||||
" {'agent_type': NewsEnvironmentAgent,\n",
|
||||
" {'agent_class': NewsEnvironmentAgent,\n",
|
||||
" 'state': {\n",
|
||||
" 'event_time': 10\n",
|
||||
" }\n",
|
||||
|
@ -1,4 +1,3 @@
|
||||
import random
|
||||
from . import FSM, state, default_state
|
||||
|
||||
|
||||
@ -16,13 +15,13 @@ class BassModel(FSM):
|
||||
@default_state
|
||||
@state
|
||||
def innovation(self):
|
||||
if random.random() < self.innovation_prob:
|
||||
if self.prob(self.innovation_prob):
|
||||
self.sentimentCorrelation = 1
|
||||
return self.aware
|
||||
else:
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=self.aware.id)
|
||||
num_neighbors_aware = len(aware_neighbors)
|
||||
if random.random() < (self['imitation_prob']*num_neighbors_aware):
|
||||
if self.prob((self['imitation_prob']*num_neighbors_aware)):
|
||||
self.sentimentCorrelation = 1
|
||||
return self.aware
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import random
|
||||
from . import FSM, state, default_state
|
||||
|
||||
|
||||
@ -39,10 +38,10 @@ class BigMarketModel(FSM):
|
||||
@state
|
||||
def enterprise(self):
|
||||
|
||||
if random.random() < self.tweet_probability: # Tweets
|
||||
if self.random.random() < self.tweet_probability: # Tweets
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=self.number_of_enterprises) # Nodes neighbour users
|
||||
for x in aware_neighbors:
|
||||
if random.uniform(0,10) < 5:
|
||||
if self.random.uniform(0,10) < 5:
|
||||
x.sentiment_about[self.id] += 0.1 # Increments for enterprise
|
||||
else:
|
||||
x.sentiment_about[self.id] -= 0.1 # Decrements for enterprise
|
||||
@ -57,11 +56,11 @@ class BigMarketModel(FSM):
|
||||
|
||||
@state
|
||||
def user(self):
|
||||
if random.random() < self.tweet_probability: # Tweets
|
||||
if random.random() < self.tweet_relevant_probability: # Tweets something relevant
|
||||
if self.random.random() < self.tweet_probability: # Tweets
|
||||
if self.random.random() < self.tweet_relevant_probability: # Tweets something relevant
|
||||
# Tweet probability per enterprise
|
||||
for i in range(len(self.enterprises)):
|
||||
random_num = random.random()
|
||||
random_num = self.random.random()
|
||||
if random_num < self.tweet_probability_about[i]:
|
||||
# The condition is fulfilled, sentiments are evaluated towards that enterprise
|
||||
if self.sentiment_about[i] < 0:
|
||||
|
@ -1,4 +1,3 @@
|
||||
import random
|
||||
from . import BaseAgent
|
||||
|
||||
|
||||
@ -23,7 +22,7 @@ class IndependentCascadeModel(BaseAgent):
|
||||
def behaviour(self):
|
||||
aware_neighbors_1_time_step = []
|
||||
# Outside effects
|
||||
if random.random() < self.innovation_prob:
|
||||
if self.prob(self.innovation_prob):
|
||||
if self.state['id'] == 0:
|
||||
self.state['id'] = 1
|
||||
self.state['sentimentCorrelation'] = 1
|
||||
@ -40,7 +39,7 @@ class IndependentCascadeModel(BaseAgent):
|
||||
if x.state['time_awareness'] == (self.env.now-1):
|
||||
aware_neighbors_1_time_step.append(x)
|
||||
num_neighbors_aware = len(aware_neighbors_1_time_step)
|
||||
if random.random() < (self.imitation_prob*num_neighbors_aware):
|
||||
if self.prob(self.imitation_prob*num_neighbors_aware):
|
||||
self.state['id'] = 1
|
||||
self.state['sentimentCorrelation'] = 1
|
||||
else:
|
||||
|
@ -1,4 +1,3 @@
|
||||
import random
|
||||
import numpy as np
|
||||
from . import BaseAgent
|
||||
|
||||
@ -24,23 +23,26 @@ class SpreadModelM2(BaseAgent):
|
||||
def __init__(self, model=None, unique_id=0, state=()):
|
||||
super().__init__(model=environment, unique_id=unique_id, state=state)
|
||||
|
||||
self.prob_neutral_making_denier = np.random.normal(environment.environment_params['prob_neutral_making_denier'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_infect = np.random.normal(environment.environment_params['prob_infect'],
|
||||
environment.environment_params['standard_variance'])
|
||||
# Use a single generator with the same seed as `self.random`
|
||||
random = np.random.default_rng(seed=self._seed)
|
||||
self.prob_neutral_making_denier = random.normal(environment.environment_params['prob_neutral_making_denier'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_cured_healing_infected = np.random.normal(environment.environment_params['prob_cured_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_cured_vaccinate_neutral = np.random.normal(environment.environment_params['prob_cured_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_infect = random.normal(environment.environment_params['prob_infect'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_vaccinated_healing_infected = np.random.normal(environment.environment_params['prob_vaccinated_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_vaccinated_vaccinate_neutral = np.random.normal(environment.environment_params['prob_vaccinated_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_generate_anti_rumor = np.random.normal(environment.environment_params['prob_generate_anti_rumor'],
|
||||
self.prob_cured_healing_infected = random.normal(environment.environment_params['prob_cured_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_cured_vaccinate_neutral = random.normal(environment.environment_params['prob_cured_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_vaccinated_healing_infected = random.normal(environment.environment_params['prob_vaccinated_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_vaccinated_vaccinate_neutral = random.normal(environment.environment_params['prob_vaccinated_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_generate_anti_rumor = random.normal(environment.environment_params['prob_generate_anti_rumor'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
def step(self):
|
||||
|
||||
@ -58,7 +60,7 @@ class SpreadModelM2(BaseAgent):
|
||||
# Infected
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors) > 0:
|
||||
if random.random() < self.prob_neutral_making_denier:
|
||||
if self.prob(self.prob_neutral_making_denier):
|
||||
self.state['id'] = 3 # Vaccinated making denier
|
||||
|
||||
def infected_behaviour(self):
|
||||
@ -66,7 +68,7 @@ class SpreadModelM2(BaseAgent):
|
||||
# Neutral
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_infect:
|
||||
if self.prob(self.prob_infect):
|
||||
neighbor.state['id'] = 1 # Infected
|
||||
|
||||
def cured_behaviour(self):
|
||||
@ -74,13 +76,13 @@ class SpreadModelM2(BaseAgent):
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
if self.prob(self.prob_cured_vaccinate_neutral):
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
if self.prob(self.prob_cured_healing_infected):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
def vaccinated_behaviour(self):
|
||||
@ -88,19 +90,19 @@ class SpreadModelM2(BaseAgent):
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
if self.prob(self.prob_cured_healing_infected):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
if self.prob(self.prob_cured_vaccinate_neutral):
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Generate anti-rumor
|
||||
infected_neighbors_2 = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_2:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
if self.prob(self.prob_generate_anti_rumor):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
@ -165,7 +167,7 @@ class ControlModelM2(BaseAgent):
|
||||
# Infected
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors) > 0:
|
||||
if random.random() < self.prob_neutral_making_denier:
|
||||
if self.random(self.prob_neutral_making_denier):
|
||||
self.state['id'] = 3 # Vaccinated making denier
|
||||
|
||||
def infected_behaviour(self):
|
||||
@ -173,7 +175,7 @@ class ControlModelM2(BaseAgent):
|
||||
# Neutral
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_infect:
|
||||
if self.prob(self.prob_infect):
|
||||
neighbor.state['id'] = 1 # Infected
|
||||
self.state['visible'] = False
|
||||
|
||||
@ -183,13 +185,13 @@ class ControlModelM2(BaseAgent):
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
if self.prob(self.prob_cured_vaccinate_neutral):
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
if self.prob(self.prob_cured_healing_infected):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
def vaccinated_behaviour(self):
|
||||
@ -198,19 +200,19 @@ class ControlModelM2(BaseAgent):
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
if self.prob(self.prob_cured_healing_infected):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
if self.prob(self.prob_cured_vaccinate_neutral):
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Generate anti-rumor
|
||||
infected_neighbors_2 = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_2:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
if self.prob(self.prob_generate_anti_rumor):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
def beacon_off_behaviour(self):
|
||||
@ -224,19 +226,19 @@ class ControlModelM2(BaseAgent):
|
||||
# Cure (M2 feature added)
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
if self.prob(self.prob_generate_anti_rumor):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
neutral_neighbors_infected = neighbor.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors_infected:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
if self.prob(self.prob_generate_anti_rumor):
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
infected_neighbors_infected = neighbor.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_infected:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
if self.prob(self.prob_generate_anti_rumor):
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
if self.prob(self.prob_cured_vaccinate_neutral):
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
@ -1,4 +1,3 @@
|
||||
import random
|
||||
import numpy as np
|
||||
from . import FSM, state
|
||||
|
||||
@ -32,62 +31,64 @@ class SISaModel(FSM):
|
||||
def __init__(self, environment, unique_id=0, state=()):
|
||||
super().__init__(model=environment, unique_id=unique_id, state=state)
|
||||
|
||||
self.neutral_discontent_spon_prob = np.random.normal(self.env['neutral_discontent_spon_prob'],
|
||||
random = np.random.default_rng(seed=self._seed)
|
||||
|
||||
self.neutral_discontent_spon_prob = random.normal(self.env['neutral_discontent_spon_prob'],
|
||||
self.env['standard_variance'])
|
||||
self.neutral_discontent_infected_prob = np.random.normal(self.env['neutral_discontent_infected_prob'],
|
||||
self.neutral_discontent_infected_prob = random.normal(self.env['neutral_discontent_infected_prob'],
|
||||
self.env['standard_variance'])
|
||||
self.neutral_content_spon_prob = np.random.normal(self.env['neutral_content_spon_prob'],
|
||||
self.neutral_content_spon_prob = random.normal(self.env['neutral_content_spon_prob'],
|
||||
self.env['standard_variance'])
|
||||
self.neutral_content_infected_prob = np.random.normal(self.env['neutral_content_infected_prob'],
|
||||
self.neutral_content_infected_prob = random.normal(self.env['neutral_content_infected_prob'],
|
||||
self.env['standard_variance'])
|
||||
|
||||
self.discontent_neutral = np.random.normal(self.env['discontent_neutral'],
|
||||
self.discontent_neutral = random.normal(self.env['discontent_neutral'],
|
||||
self.env['standard_variance'])
|
||||
self.discontent_content = np.random.normal(self.env['discontent_content'],
|
||||
self.discontent_content = random.normal(self.env['discontent_content'],
|
||||
self.env['variance_d_c'])
|
||||
|
||||
self.content_discontent = np.random.normal(self.env['content_discontent'],
|
||||
self.content_discontent = random.normal(self.env['content_discontent'],
|
||||
self.env['variance_c_d'])
|
||||
self.content_neutral = np.random.normal(self.env['content_neutral'],
|
||||
self.content_neutral = random.normal(self.env['content_neutral'],
|
||||
self.env['standard_variance'])
|
||||
|
||||
@state
|
||||
def neutral(self):
|
||||
# Spontaneous effects
|
||||
if random.random() < self.neutral_discontent_spon_prob:
|
||||
if self.prob(self.neutral_discontent_spon_prob):
|
||||
return self.discontent
|
||||
if random.random() < self.neutral_content_spon_prob:
|
||||
if self.prob(self.neutral_content_spon_prob):
|
||||
return self.content
|
||||
|
||||
# Infected
|
||||
discontent_neighbors = self.count_neighboring_agents(state_id=self.discontent)
|
||||
if random.random() < discontent_neighbors * self.neutral_discontent_infected_prob:
|
||||
if self.prob(scontent_neighbors * self.neutral_discontent_infected_prob):
|
||||
return self.discontent
|
||||
content_neighbors = self.count_neighboring_agents(state_id=self.content.id)
|
||||
if random.random() < content_neighbors * self.neutral_content_infected_prob:
|
||||
if self.prob(s * self.neutral_content_infected_prob):
|
||||
return self.content
|
||||
return self.neutral
|
||||
|
||||
@state
|
||||
def discontent(self):
|
||||
# Healing
|
||||
if random.random() < self.discontent_neutral:
|
||||
if self.prob(self.discontent_neutral):
|
||||
return self.neutral
|
||||
|
||||
# Superinfected
|
||||
content_neighbors = self.count_neighboring_agents(state_id=self.content.id)
|
||||
if random.random() < content_neighbors * self.discontent_content:
|
||||
if self.prob(s * self.discontent_content):
|
||||
return self.content
|
||||
return self.discontent
|
||||
|
||||
@state
|
||||
def content(self):
|
||||
# Healing
|
||||
if random.random() < self.content_neutral:
|
||||
if self.prob(self.content_neutral):
|
||||
return self.neutral
|
||||
|
||||
# Superinfected
|
||||
discontent_neighbors = self.count_neighboring_agents(state_id=self.discontent.id)
|
||||
if random.random() < discontent_neighbors * self.content_discontent:
|
||||
if self.prob(scontent_neighbors * self.content_discontent):
|
||||
self.discontent
|
||||
return self.content
|
||||
|
@ -1,4 +1,3 @@
|
||||
import random
|
||||
from . import BaseAgent
|
||||
|
||||
|
||||
@ -68,10 +67,10 @@ class SentimentCorrelationModel(BaseAgent):
|
||||
disgust_prob = self.disgust_prob+(len(disgusted_neighbors_1_time_step)*self.disgust_prob)
|
||||
outside_effects_prob = self.outside_effects_prob
|
||||
|
||||
num = random.random()
|
||||
num = self.random.random()
|
||||
|
||||
if num<outside_effects_prob:
|
||||
self.state['id'] = random.randint(1, 4)
|
||||
self.state['id'] = self.random.randint(1, 4)
|
||||
|
||||
self.state['sentimentCorrelation'] = self.state['id'] # It is stored when it has been infected for the dynamic network
|
||||
self.state['time_awareness'][self.state['id']-1] = self.env.now
|
||||
|
@ -2,7 +2,7 @@ import logging
|
||||
from collections import OrderedDict, defaultdict
|
||||
from collections.abc import MutableMapping, Mapping, Set
|
||||
from abc import ABCMeta
|
||||
from copy import deepcopy
|
||||
from copy import deepcopy, copy
|
||||
from functools import partial, wraps
|
||||
from itertools import islice, chain
|
||||
import json
|
||||
@ -11,8 +11,6 @@ import networkx as nx
|
||||
from mesa import Agent as MesaAgent
|
||||
from typing import Dict, List
|
||||
|
||||
from random import shuffle
|
||||
|
||||
from .. import serialization, utils, time, config
|
||||
|
||||
|
||||
@ -28,6 +26,7 @@ IGNORED_FIELDS = ('model', 'logger')
|
||||
class DeadAgent(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BaseAgent(MesaAgent, MutableMapping):
|
||||
"""
|
||||
A special type of Mesa Agent that:
|
||||
@ -82,6 +81,9 @@ class BaseAgent(MesaAgent, MutableMapping):
|
||||
def __hash__(self):
|
||||
return hash(self.unique_id)
|
||||
|
||||
def prob(self, probability):
|
||||
return prob(probability, self.model.random)
|
||||
|
||||
# TODO: refactor to clean up mesa compatibility
|
||||
@property
|
||||
def id(self):
|
||||
@ -356,7 +358,7 @@ class FSM(BaseAgent, metaclass=MetaFSM):
|
||||
return state
|
||||
|
||||
|
||||
def prob(prob=1):
|
||||
def prob(prob, random):
|
||||
'''
|
||||
A true/False uniform distribution with a given probability.
|
||||
To be used like this:
|
||||
@ -474,7 +476,7 @@ def _convert_agent_classs(ind, to_string=False, **kwargs):
|
||||
return deserialize_definition(ind, **kwargs)
|
||||
|
||||
|
||||
def _agent_from_definition(definition, value=-1, unique_id=None):
|
||||
def _agent_from_definition(definition, random, value=-1, unique_id=None):
|
||||
"""Used in the initialization of agents given an agent distribution."""
|
||||
if value < 0:
|
||||
value = random.random()
|
||||
@ -491,7 +493,7 @@ def _agent_from_definition(definition, value=-1, unique_id=None):
|
||||
raise Exception('Definition for value {} not found in: {}'.format(value, definition))
|
||||
|
||||
|
||||
def _definition_to_dict(definition, size=None, default_state=None):
|
||||
def _definition_to_dict(definition, random, size=None, default_state=None):
|
||||
state = default_state or {}
|
||||
agents = {}
|
||||
remaining = {}
|
||||
@ -668,7 +670,7 @@ def filter_group(group, *id_args, unique_id=None, state_id=None, agent_class=Non
|
||||
yield from f
|
||||
|
||||
|
||||
def from_config(cfg: Dict[str, config.AgentConfig], env):
|
||||
def from_config(cfg: Dict[str, config.AgentConfig], env, random):
|
||||
'''
|
||||
Agents are specified in groups.
|
||||
Each group can be specified in two ways, either through a fixed list in which each item has
|
||||
@ -677,10 +679,15 @@ def from_config(cfg: Dict[str, config.AgentConfig], env):
|
||||
of each agent type.
|
||||
'''
|
||||
default = cfg.get('default', None)
|
||||
return {k: _group_from_config(c, default=default, env=env) for (k, c) in cfg.items() if k is not 'default'}
|
||||
return {k: _group_from_config(c, default=default, env=env, random=random) for (k, c) in cfg.items() if k is not 'default'}
|
||||
|
||||
|
||||
def _group_from_config(cfg: config.AgentConfig, default: config.SingleAgentConfig, env):
|
||||
def _group_from_config(cfg: config.AgentConfig, default: config.SingleAgentConfig, env, random):
|
||||
if cfg and not isinstance(cfg, config.AgentConfig):
|
||||
cfg = config.AgentConfig(**cfg)
|
||||
if default and not isinstance(default, config.SingleAgentConfig):
|
||||
default = config.SingleAgentConfig(**default)
|
||||
|
||||
agents = {}
|
||||
if cfg.fixed is not None:
|
||||
agents = _from_fixed(cfg.fixed, topology=cfg.topology, default=default, env=env)
|
||||
@ -690,7 +697,7 @@ def _group_from_config(cfg: config.AgentConfig, default: config.SingleAgentConfi
|
||||
agents.update(_from_distro(cfg.distribution, target,
|
||||
topology=cfg.topology or default.topology,
|
||||
default=default,
|
||||
env=env))
|
||||
env=env, random=random))
|
||||
assert len(agents) == n
|
||||
if cfg.override:
|
||||
for attrs in cfg.override:
|
||||
@ -733,7 +740,8 @@ def _from_distro(distro: List[config.AgentDistro],
|
||||
n: int,
|
||||
topology: str,
|
||||
default: config.SingleAgentConfig,
|
||||
env):
|
||||
env,
|
||||
random):
|
||||
|
||||
agents = {}
|
||||
|
||||
|
@ -9,19 +9,6 @@ from typing import Any, Callable, Dict, List, Optional, Union, Type
|
||||
from pydantic import BaseModel, Extra
|
||||
import networkx as nx
|
||||
|
||||
class General(BaseModel):
|
||||
id: str = 'Unnamed Simulation'
|
||||
group: str = None
|
||||
dir_path: Optional[str] = None
|
||||
num_trials: int = 1
|
||||
max_time: float = 100
|
||||
interval: float = 1
|
||||
seed: str = ""
|
||||
|
||||
@staticmethod
|
||||
def default():
|
||||
return General()
|
||||
|
||||
|
||||
# Could use TypeAlias in python >= 3.10
|
||||
nodeId = int
|
||||
@ -125,10 +112,18 @@ class AgentConfig(SingleAgentConfig):
|
||||
|
||||
class Config(BaseModel, extra=Extra.forbid):
|
||||
version: Optional[str] = '1'
|
||||
general: General = General.default()
|
||||
topologies: Optional[Dict[str, NetConfig]] = {}
|
||||
environment: EnvConfig = EnvConfig.default()
|
||||
agents: Optional[Dict[str, AgentConfig]] = {}
|
||||
|
||||
id: str = 'Unnamed Simulation'
|
||||
group: str = None
|
||||
dir_path: Optional[str] = None
|
||||
num_trials: int = 1
|
||||
max_time: float = 100
|
||||
interval: float = 1
|
||||
seed: str = ""
|
||||
|
||||
model_class: Union[Type, str]
|
||||
model_parameters: Optiona[Dict[str, Any]] = {}
|
||||
|
||||
|
||||
def convert_old(old, strict=True):
|
||||
'''
|
||||
@ -137,10 +132,14 @@ def convert_old(old, strict=True):
|
||||
This is still a work in progress and might not work in many cases.
|
||||
'''
|
||||
|
||||
#TODO: implement actual conversion
|
||||
print('The old configuration format is no longer supported. \
|
||||
Update your config files or run Soil==0.20')
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
new = {}
|
||||
|
||||
|
||||
general = {}
|
||||
for k in ['id',
|
||||
'group',
|
||||
@ -173,8 +172,8 @@ def convert_old(old, strict=True):
|
||||
'default': {},
|
||||
}
|
||||
|
||||
if 'agent_type' in old:
|
||||
agents['default']['agent_class'] = old['agent_type']
|
||||
if 'agent_class' in old:
|
||||
agents['default']['agent_class'] = old['agent_class']
|
||||
|
||||
if 'default_state' in old:
|
||||
agents['default']['state'] = old['default_state']
|
||||
@ -182,8 +181,8 @@ def convert_old(old, strict=True):
|
||||
|
||||
def updated_agent(agent):
|
||||
newagent = dict(agent)
|
||||
newagent['agent_class'] = newagent['agent_type']
|
||||
del newagent['agent_type']
|
||||
newagent['agent_class'] = newagent['agent_class']
|
||||
del newagent['agent_class']
|
||||
return newagent
|
||||
|
||||
for agent in old.get('environment_agents', []):
|
||||
@ -207,9 +206,9 @@ def convert_old(old, strict=True):
|
||||
else:
|
||||
by_weight.append(agent)
|
||||
|
||||
if 'agent_type' in old and (not fixed and not by_weight):
|
||||
if 'agent_class' in old and (not fixed and not by_weight):
|
||||
agents['network']['topology'] = 'default'
|
||||
by_weight = [{'agent_class': old['agent_type']}]
|
||||
by_weight = [{'agent_class': old['agent_class']}]
|
||||
|
||||
|
||||
# TODO: translate states properly
|
||||
|
@ -2,23 +2,5 @@ from mesa import DataCollector as MDC
|
||||
|
||||
class SoilDataCollector(MDC):
|
||||
|
||||
|
||||
def __init__(self, environment, *args, **kwargs):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Populate model and env reporters so they have a key per
|
||||
# So they can be shown in the web interface
|
||||
self.environment = environment
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def model_vars(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@model_vars.setter
|
||||
def model_vars(self, value):
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def agent_reporters(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
@ -5,7 +5,7 @@ import math
|
||||
import random
|
||||
import logging
|
||||
|
||||
from typing import Dict
|
||||
from typing import Any, Dict, Optional, Union
|
||||
from collections import namedtuple
|
||||
from time import time as current_time
|
||||
from copy import deepcopy
|
||||
@ -17,20 +17,24 @@ import networkx as nx
|
||||
from mesa import Model
|
||||
from mesa.datacollection import DataCollector
|
||||
|
||||
from . import serialization, agents, analysis, utils, time, config, network
|
||||
from . import serialization, analysis, utils, time, network
|
||||
|
||||
from .agents import AgentView, BaseAgent, NetworkAgent, from_config as agents_from_config
|
||||
|
||||
|
||||
Record = namedtuple('Record', 'dict_id t_step key value')
|
||||
|
||||
|
||||
class Environment(Model):
|
||||
class BaseEnvironment(Model):
|
||||
"""
|
||||
The environment is key in a simulation. It contains the network topology,
|
||||
a reference to network and environment agents, as well as the environment
|
||||
params, which are used as shared state between agents.
|
||||
The environment is key in a simulation. It controls how agents interact,
|
||||
and what information is available to them.
|
||||
|
||||
This is an opinionated version of `mesa.Model` class, which adds many
|
||||
convenience methods and abstractions.
|
||||
|
||||
The environment parameters and the state of every agent can be accessed
|
||||
both by using the environment as a dictionary or with the environment's
|
||||
both by using the environment as a dictionary and with the environment's
|
||||
:meth:`soil.environment.Environment.get` method.
|
||||
"""
|
||||
|
||||
@ -40,67 +44,62 @@ class Environment(Model):
|
||||
schedule=None,
|
||||
dir_path=None,
|
||||
interval=1,
|
||||
agents: Dict[str, config.AgentConfig] = {},
|
||||
topologies: Dict[str, config.NetConfig] = {},
|
||||
agent_class=BaseAgent,
|
||||
agents: [tuple[type, Dict[str, Any]]] = {},
|
||||
agent_reporters: Optional[Any] = None,
|
||||
model_reporters: Optional[Any] = None,
|
||||
tables: Optional[Any] = None,
|
||||
**env_params):
|
||||
|
||||
super().__init__()
|
||||
super().__init__(seed=seed)
|
||||
self.current_id = -1
|
||||
|
||||
self.seed = '{}_{}'.format(seed, env_id)
|
||||
self.id = env_id
|
||||
|
||||
self.dir_path = dir_path or os.getcwd()
|
||||
|
||||
if schedule is None:
|
||||
schedule = time.TimedActivation()
|
||||
schedule = time.TimedActivation(self)
|
||||
self.schedule = schedule
|
||||
|
||||
seed = seed or current_time()
|
||||
self.agent_class = agent_class
|
||||
|
||||
random.seed(seed)
|
||||
|
||||
|
||||
self.topologies = {}
|
||||
self._node_ids = {}
|
||||
for (name, cfg) in topologies.items():
|
||||
self.set_topology(cfg=cfg,
|
||||
graph=name)
|
||||
self.agents = agents or {}
|
||||
self.init_agents(agents)
|
||||
|
||||
self.env_params = env_params or {}
|
||||
|
||||
self.interval = interval
|
||||
self['SEED'] = seed
|
||||
|
||||
self.logger = utils.logger.getChild(self.id)
|
||||
self.datacollector = DataCollector(model_reporters, agent_reporters, tables)
|
||||
|
||||
self.datacollector = DataCollector(
|
||||
model_reporters=model_reporters,
|
||||
agent_reporters=agent_reporters,
|
||||
tables=tables,
|
||||
)
|
||||
|
||||
def __read_agent_tuple(self, tup):
|
||||
cls = self.agent_class
|
||||
args = tup
|
||||
if isinstance(tup, tuple):
|
||||
cls = tup[0]
|
||||
args = tup[1]
|
||||
return serialization.deserialize(cls)(unique_id=self.next_id(),
|
||||
model=self, **args)
|
||||
|
||||
def init_agents(self, agents: [tuple[type, Dict[str, Any]]] = {}):
|
||||
agents = [self.__read_agent_tuple(tup) for tup in agents]
|
||||
self._agents = {'default': {agent.id: agent for agent in agents}}
|
||||
|
||||
@property
|
||||
def topology(self):
|
||||
return self.topologies['default']
|
||||
def agents(self):
|
||||
return AgentView(self._agents)
|
||||
|
||||
@property
|
||||
def network_agents(self):
|
||||
yield from self.agents(agent_class=agents.NetworkAgent)
|
||||
|
||||
@staticmethod
|
||||
def from_config(conf: config.Config, trial_id, **kwargs) -> Environment:
|
||||
'''Create an environment for a trial of the simulation'''
|
||||
conf = conf
|
||||
if kwargs:
|
||||
conf = config.Config(**conf.dict(exclude_defaults=True), **kwargs)
|
||||
seed = '{}_{}'.format(conf.general.seed, trial_id)
|
||||
id = '{}_trial_{}'.format(conf.general.id, trial_id).replace('.', '-')
|
||||
opts = conf.environment.params.copy()
|
||||
dir_path = conf.general.dir_path
|
||||
opts.update(conf)
|
||||
opts.update(kwargs)
|
||||
env = serialization.deserialize(conf.environment.environment_class)(env_id=id, seed=seed, dir_path=dir_path, **opts)
|
||||
return env
|
||||
def find_one(self, *args, **kwargs):
|
||||
return AgentView(self._agents).one(*args, **kwargs)
|
||||
|
||||
def count_agents(self, *args, **kwargs):
|
||||
return sum(1 for i in self.agents(*args, **kwargs))
|
||||
|
||||
@property
|
||||
def now(self):
|
||||
@ -109,115 +108,42 @@ class Environment(Model):
|
||||
raise Exception('The environment has not been scheduled, so it has no sense of time')
|
||||
|
||||
|
||||
def topology_for(self, agent_id):
|
||||
return self.topologies[self._node_ids[agent_id][0]]
|
||||
# def init_agent(self, agent_id, agent_definitions, state=None):
|
||||
# state = state or {}
|
||||
|
||||
def node_id_for(self, agent_id):
|
||||
return self._node_ids[agent_id][1]
|
||||
# agent_class = None
|
||||
# if 'agent_class' in self.states.get(agent_id, {}):
|
||||
# agent_class = self.states[agent_id]['agent_class']
|
||||
# elif 'agent_class' in self.default_state:
|
||||
# agent_class = self.default_state['agent_class']
|
||||
|
||||
def set_topology(self, cfg=None, dir_path=None, graph='default'):
|
||||
topology = cfg
|
||||
if not isinstance(cfg, nx.Graph):
|
||||
topology = network.from_config(cfg, dir_path=dir_path or self.dir_path)
|
||||
|
||||
self.topologies[graph] = topology
|
||||
|
||||
@property
|
||||
def agents(self):
|
||||
return agents.AgentView(self._agents)
|
||||
|
||||
def count_agents(self, *args, **kwargs):
|
||||
return sum(1 for i in self.find_all(*args, **kwargs))
|
||||
|
||||
def find_all(self, *args, **kwargs):
|
||||
return agents.AgentView(self._agents).filter(*args, **kwargs)
|
||||
|
||||
def find_one(self, *args, **kwargs):
|
||||
return agents.AgentView(self._agents).one(*args, **kwargs)
|
||||
|
||||
@agents.setter
|
||||
def agents(self, agents_def: Dict[str, config.AgentConfig]):
|
||||
self._agents = agents.from_config(agents_def, env=self)
|
||||
for d in self._agents.values():
|
||||
for a in d.values():
|
||||
self.schedule.add(a)
|
||||
|
||||
def init_agent(self, agent_id, agent_definitions, graph='default'):
|
||||
node = self.topologies[graph].nodes[agent_id]
|
||||
init = False
|
||||
state = dict(node)
|
||||
|
||||
agent_class = None
|
||||
if 'agent_class' in self.states.get(agent_id, {}):
|
||||
agent_class = self.states[agent_id]['agent_class']
|
||||
elif 'agent_class' in node:
|
||||
agent_class = node['agent_class']
|
||||
elif 'agent_class' in self.default_state:
|
||||
agent_class = self.default_state['agent_class']
|
||||
|
||||
if agent_class:
|
||||
agent_class = agents.deserialize_type(agent_class)
|
||||
elif agent_definitions:
|
||||
agent_class, state = agents._agent_from_definition(agent_definitions, unique_id=agent_id)
|
||||
else:
|
||||
serialization.logger.debug('Skipping node {}'.format(agent_id))
|
||||
return
|
||||
return self.set_agent(agent_id, agent_class, state)
|
||||
|
||||
def agent_to_node(self, agent_id, graph_name='default', node_id=None, shuffle=False):
|
||||
#TODO: test
|
||||
if node_id is None:
|
||||
G = self.topologies[graph_name]
|
||||
candidates = list(G.nodes(data=True))
|
||||
if shuffle:
|
||||
random.shuffle(candidates)
|
||||
for next_id, data in candidates:
|
||||
if data.get('agent_id', None) is None:
|
||||
node_id = next_id
|
||||
data['agent_id'] = agent_id
|
||||
break
|
||||
|
||||
|
||||
self._node_ids[agent_id] = (graph_name, node_id)
|
||||
print(self._node_ids)
|
||||
# if agent_class:
|
||||
# agent_class = agents.deserialize_type(agent_class)
|
||||
# elif agent_definitions:
|
||||
# agent_class, state = agents._agent_from_definition(agent_definitions, unique_id=agent_id)
|
||||
# else:
|
||||
# serialization.logger.debug('Skipping agent {}'.format(agent_id))
|
||||
# return
|
||||
# return self.add_agent(agent_id, agent_class, state)
|
||||
|
||||
|
||||
def set_agent(self, agent_id, agent_class, state=None, graph='default'):
|
||||
node = self.topologies[graph].nodes[agent_id]
|
||||
def add_agent(self, agent_id, agent_class, state=None, graph='default'):
|
||||
defstate = deepcopy(self.default_state) or {}
|
||||
defstate.update(self.states.get(agent_id, {}))
|
||||
defstate.update(node.get('state', {}))
|
||||
if state:
|
||||
defstate.update(state)
|
||||
a = None
|
||||
if agent_class:
|
||||
state = defstate
|
||||
a = agent_class(model=self,
|
||||
unique_id=agent_id
|
||||
)
|
||||
unique_id=agent_id)
|
||||
|
||||
for (k, v) in state.items():
|
||||
setattr(a, k, v)
|
||||
|
||||
node['agent'] = a
|
||||
self.schedule.add(a)
|
||||
return a
|
||||
|
||||
def add_node(self, agent_class, state=None, graph='default'):
|
||||
agent_id = int(len(self.topologies[graph].nodes()))
|
||||
self.topologies[graph].add_node(agent_id)
|
||||
a = self.set_agent(agent_id, agent_class, state, graph=graph)
|
||||
a['visible'] = True
|
||||
return a
|
||||
|
||||
def add_edge(self, agent1, agent2, start=None, graph='default', **attrs):
|
||||
if hasattr(agent1, 'id'):
|
||||
agent1 = agent1.id
|
||||
if hasattr(agent2, 'id'):
|
||||
agent2 = agent2.id
|
||||
start = start or self.now
|
||||
return self.topologies[graph].add_edge(agent1, agent2, **attrs)
|
||||
|
||||
def log(self, message, *args, level=logging.INFO, **kwargs):
|
||||
if not self.logger.isEnabledFor(level):
|
||||
return
|
||||
@ -238,14 +164,6 @@ class Environment(Model):
|
||||
self.schedule.step()
|
||||
self.datacollector.collect(self)
|
||||
|
||||
def run(self, until, *args, **kwargs):
|
||||
until = until or float('inf')
|
||||
|
||||
while self.schedule.next_time < until:
|
||||
self.step()
|
||||
utils.logger.debug(f'Simulation step {self.schedule.time}/{until}. Next: {self.schedule.next_time}')
|
||||
self.schedule.time = until
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.env_params
|
||||
|
||||
@ -289,5 +207,90 @@ class Environment(Model):
|
||||
yield from self._agent_to_tuples(agent, now)
|
||||
|
||||
|
||||
class AgentConfigEnvironment(BaseEnvironment):
|
||||
|
||||
SoilEnvironment = Environment
|
||||
def __init__(self, *args,
|
||||
agents: Dict[str, config.AgentConfig] = {},
|
||||
**kwargs):
|
||||
return super().__init__(*args, agents=agents, **kwargs)
|
||||
|
||||
def init_agents(self, agents: Union[Dict[str, config.AgentConfig], [tuple[type, Dict[str, Any]]]] = {}):
|
||||
if not isinstance(agents, dict):
|
||||
return BaseEnvironment.init_agents(self, agents)
|
||||
|
||||
self._agents = agents_from_config(agents,
|
||||
env=self,
|
||||
random=self.random)
|
||||
for d in self._agents.values():
|
||||
for a in d.values():
|
||||
self.schedule.add(a)
|
||||
|
||||
|
||||
class NetworkConfigEnvironment(BaseEnvironment):
|
||||
|
||||
def __init__(self, *args, topologies: Dict[str, config.NetConfig] = {}, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.topologies = {}
|
||||
self._node_ids = {}
|
||||
for (name, cfg) in topologies.items():
|
||||
self.set_topology(cfg=cfg, graph=name)
|
||||
|
||||
@property
|
||||
def topology(self):
|
||||
return self.topologies['default']
|
||||
|
||||
def set_topology(self, cfg=None, dir_path=None, graph='default'):
|
||||
topology = cfg
|
||||
if not isinstance(cfg, nx.Graph):
|
||||
topology = network.from_config(cfg, dir_path=dir_path or self.dir_path)
|
||||
|
||||
self.topologies[graph] = topology
|
||||
|
||||
def topology_for(self, agent_id):
|
||||
return self.topologies[self._node_ids[agent_id][0]]
|
||||
|
||||
@property
|
||||
def network_agents(self):
|
||||
yield from self.agents(agent_class=NetworkAgent)
|
||||
|
||||
def agent_to_node(self, agent_id, graph_name='default', node_id=None, shuffle=False):
|
||||
node_id = network.agent_to_node(G=self.topologies[graph_name], agent_id=agent_id,
|
||||
node_id=node_id, shuffle=shuffle,
|
||||
random=self.random)
|
||||
|
||||
self._node_ids[agent_id] = (graph_name, node_id)
|
||||
|
||||
|
||||
def add_node(self, agent_class, state=None, graph='default'):
|
||||
agent_id = int(len(self.topologies[graph].nodes()))
|
||||
self.topologies[graph].add_node(agent_id)
|
||||
a = self.add_agent(agent_id, agent_class, state, graph=graph)
|
||||
a['visible'] = True
|
||||
return a
|
||||
|
||||
def add_edge(self, agent1, agent2, start=None, graph='default', **attrs):
|
||||
if hasattr(agent1, 'id'):
|
||||
agent1 = agent1.id
|
||||
if hasattr(agent2, 'id'):
|
||||
agent2 = agent2.id
|
||||
start = start or self.now
|
||||
return self.topologies[graph].add_edge(agent1, agent2, **attrs)
|
||||
|
||||
def add_agent(self, *args, state=None, graph='default', **kwargs):
|
||||
node = self.topologies[graph].nodes[agent_id]
|
||||
node_state = node.get('state', {})
|
||||
if node_state:
|
||||
node_state.update(state or {})
|
||||
state = node_state
|
||||
a = super().add_agent(*args, state=state, **kwargs)
|
||||
node['agent'] = a
|
||||
return a
|
||||
|
||||
def node_id_for(self, agent_id):
|
||||
return self._node_ids[agent_id][1]
|
||||
|
||||
class Environment(AgentConfigEnvironment, NetworkConfigEnvironment):
|
||||
def __init__(self, *args, **kwargs):
|
||||
agents = kwargs.pop('agents', {})
|
||||
NetworkConfigEnvironment.__init__(self, *args, **kwargs)
|
||||
AgentConfigEnvironment.__init__(self, *args, agents=agents, **kwargs)
|
||||
|
@ -49,8 +49,8 @@ class Exporter:
|
||||
self.simulation = simulation
|
||||
outdir = outdir or os.path.join(os.getcwd(), 'soil_output')
|
||||
self.outdir = os.path.join(outdir,
|
||||
simulation.config.general.group or '',
|
||||
simulation.config.general.id)
|
||||
simulation.group or '',
|
||||
simulation.name)
|
||||
self.dry_run = dry_run
|
||||
self.copy_to = copy_to
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
from typing import Dict
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
|
||||
import networkx as nx
|
||||
|
||||
@ -40,3 +41,25 @@ def from_config(cfg: config.NetConfig, dir_path: str = None):
|
||||
return nx.json_graph.node_link_graph(cfg.topology)
|
||||
|
||||
return nx.Graph()
|
||||
|
||||
|
||||
def agent_to_node(G, agent_id, node_id=None, shuffle=False, random=random):
|
||||
'''
|
||||
Link an agent to a node in a topology.
|
||||
|
||||
If node_id is None, a node without an agent_id will be found.
|
||||
'''
|
||||
#TODO: test
|
||||
if node_id is None:
|
||||
candidates = list(G.nodes(data=True))
|
||||
if shuffle:
|
||||
random.shuffle(candidates)
|
||||
for next_id, data in candidates:
|
||||
if data.get('agent_id', None) is None:
|
||||
node_id = next_id
|
||||
data['agent_id'] = agent_id
|
||||
break
|
||||
|
||||
if node_id is None:
|
||||
raise ValueError(f"Not enough nodes in topology to assign one to agent {agent_id}")
|
||||
return node_id
|
||||
|
@ -122,8 +122,6 @@ def load_files(*patterns, **kwargs):
|
||||
for i in glob(pattern, **kwargs):
|
||||
for config in load_file(i):
|
||||
path = os.path.abspath(i)
|
||||
if 'general' in config and 'dir_path' not in config['general']:
|
||||
config['general']['dir_path'] = os.path.dirname(path)
|
||||
yield config, path
|
||||
|
||||
|
||||
|
@ -7,6 +7,10 @@ import traceback
|
||||
import logging
|
||||
import networkx as nx
|
||||
|
||||
from dataclasses import dataclass, field, asdict
|
||||
from typing import Union
|
||||
|
||||
|
||||
from networkx.readwrite import json_graph
|
||||
from multiprocessing import Pool
|
||||
from functools import partial
|
||||
@ -14,13 +18,15 @@ import pickle
|
||||
|
||||
from . import serialization, utils, basestring, agents
|
||||
from .environment import Environment
|
||||
from .utils import logger
|
||||
from .utils import logger, run_and_return_exceptions
|
||||
from .exporters import default
|
||||
from .time import INFINITY
|
||||
|
||||
from .config import Config, convert_old
|
||||
|
||||
|
||||
#TODO: change documentation for simulation
|
||||
@dataclass
|
||||
class Simulation:
|
||||
"""
|
||||
Parameters
|
||||
@ -30,23 +36,16 @@ class Simulation:
|
||||
|
||||
kwargs: parameters to use to initialize a new configuration, if one has not been provided.
|
||||
"""
|
||||
|
||||
def __init__(self, config=None,
|
||||
**kwargs):
|
||||
if kwargs:
|
||||
cfg = {}
|
||||
if config:
|
||||
cfg.update(config.dict(include_defaults=False))
|
||||
cfg.update(kwargs)
|
||||
config = Config(**cfg)
|
||||
if not config:
|
||||
raise ValueError("You need to specify a simulation configuration")
|
||||
self.config = config
|
||||
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.config.general.id
|
||||
name: str = 'Unnamed simulation'
|
||||
group: str = None
|
||||
model_class: Union[str, type] = 'soil.Environment'
|
||||
model_params: dict = field(default_factory=dict)
|
||||
seed: str = field(default_factory=lambda: current_time())
|
||||
dir_path: str = field(default_factory=lambda: os.getcwd())
|
||||
max_time: float = float('inf')
|
||||
max_steps: int = -1
|
||||
num_trials: int = 3
|
||||
dry_run: bool = False
|
||||
|
||||
def run_simulation(self, *args, **kwargs):
|
||||
return self.run(*args, **kwargs)
|
||||
@ -58,14 +57,14 @@ class Simulation:
|
||||
def _run_sync_or_async(self, parallel=False, **kwargs):
|
||||
if parallel and not os.environ.get('SENPY_DEBUG', None):
|
||||
p = Pool()
|
||||
func = partial(self.run_trial_exceptions, **kwargs)
|
||||
for i in p.imap_unordered(func, range(self.config.general.num_trials)):
|
||||
func = partial(run_and_return_exceptions, self.run_trial, **kwargs)
|
||||
for i in p.imap_unordered(func, self.num_trials):
|
||||
if isinstance(i, Exception):
|
||||
logger.error('Trial failed:\n\t%s', i.message)
|
||||
continue
|
||||
yield i
|
||||
else:
|
||||
for i in range(self.config.general.num_trials):
|
||||
for i in range(self.num_trials):
|
||||
yield self.run_trial(trial_id=i,
|
||||
**kwargs)
|
||||
|
||||
@ -80,12 +79,12 @@ class Simulation:
|
||||
logger.info('Output directory: %s', outdir)
|
||||
exporters = serialization.deserialize_all(exporters,
|
||||
simulation=self,
|
||||
known_modules=['soil.exporters',],
|
||||
known_modules=['soil.exporters', ],
|
||||
dry_run=dry_run,
|
||||
outdir=outdir,
|
||||
**exporter_params)
|
||||
|
||||
with utils.timer('simulation {}'.format(self.config.general.id)):
|
||||
with utils.timer('simulation {}'.format(self.name)):
|
||||
for exporter in exporters:
|
||||
exporter.sim_start()
|
||||
|
||||
@ -104,95 +103,95 @@ class Simulation:
|
||||
for exporter in exporters:
|
||||
exporter.sim_end()
|
||||
|
||||
def run_model(self, until=None, *args, **kwargs):
|
||||
until = until or float('inf')
|
||||
|
||||
while self.schedule.next_time < until:
|
||||
self.step()
|
||||
utils.logger.debug(f'Simulation step {self.schedule.time}/{until}. Next: {self.schedule.next_time}')
|
||||
self.schedule.time = until
|
||||
|
||||
def get_env(self, trial_id=0, **kwargs):
|
||||
'''Create an environment for a trial of the simulation'''
|
||||
# opts = self.environment_params.copy()
|
||||
# opts.update({
|
||||
# 'name': '{}_trial_{}'.format(self.name, trial_id),
|
||||
# 'topology': self.topology.copy(),
|
||||
# 'network_params': self.network_params,
|
||||
# 'seed': '{}_trial_{}'.format(self.seed, trial_id),
|
||||
# 'initial_time': 0,
|
||||
# 'interval': self.interval,
|
||||
# 'network_agents': self.network_agents,
|
||||
# 'initial_time': 0,
|
||||
# 'states': self.states,
|
||||
# 'dir_path': self.dir_path,
|
||||
# 'default_state': self.default_state,
|
||||
# 'history': bool(self._history),
|
||||
# 'environment_agents': self.environment_agents,
|
||||
# })
|
||||
# opts.update(kwargs)
|
||||
print(self.config)
|
||||
env = Environment.from_config(self.config, trial_id=trial_id, **kwargs)
|
||||
return env
|
||||
def deserialize_reporters(reporters):
|
||||
for (k, v) in reporters.items():
|
||||
if isinstance(v, str) and v.startswith('py:'):
|
||||
reporters[k] = serialization.deserialize(value.lsplit(':', 1)[1])
|
||||
|
||||
model_params = self.model_params.copy()
|
||||
model_params.update(kwargs)
|
||||
|
||||
agent_reporters = deserialize_reporters(model_params.pop('agent_reporters', {}))
|
||||
model_reporters = deserialize_reporters(model_params.pop('model_reporters', {}))
|
||||
|
||||
env = serialization.deserialize(self.model_class)
|
||||
return env(id=f'{self.name}_trial_{trial_id}',
|
||||
seed=f'{self.seed}_trial_{trial_id}',
|
||||
dir_path=self.dir_path,
|
||||
agent_reporters=agent_reporters,
|
||||
model_reporters=model_reporters,
|
||||
**model_params)
|
||||
|
||||
def run_trial(self, trial_id=None, until=None, log_level=logging.INFO, **opts):
|
||||
"""
|
||||
Run a single trial of the simulation
|
||||
|
||||
"""
|
||||
model = self.get_env(trial_id, **opts)
|
||||
return self.run_model(model, trial_id=trial_id, until=until, log_level=log_level)
|
||||
|
||||
def run_model(self, model, trial_id=None, until=None, log_level=logging.INFO, **opts):
|
||||
trial_id = trial_id if trial_id is not None else current_time()
|
||||
if log_level:
|
||||
logger.setLevel(log_level)
|
||||
# Set-up trial environment and graph
|
||||
until = until or self.config.general.max_time
|
||||
until = until or self.max_time
|
||||
|
||||
env = self.get_env(trial_id, **opts)
|
||||
# Set up agents on nodes
|
||||
with utils.timer('Simulation {} trial {}'.format(self.config.general.id, trial_id)):
|
||||
env.run(until)
|
||||
return env
|
||||
is_done = lambda: False
|
||||
if self.max_time and hasattr(self.schedule, 'time'):
|
||||
is_done = lambda x: is_done() or self.schedule.time >= self.max_time
|
||||
if self.max_steps and hasattr(self.schedule, 'time'):
|
||||
is_done = lambda: is_done() or self.schedule.steps >= self.max_steps
|
||||
|
||||
def run_trial_exceptions(self, *args, **kwargs):
|
||||
'''
|
||||
A wrapper for run_trial that catches exceptions and returns them.
|
||||
It is meant for async simulations
|
||||
'''
|
||||
try:
|
||||
return self.run_trial(*args, **kwargs)
|
||||
except Exception as ex:
|
||||
if ex.__cause__ is not None:
|
||||
ex = ex.__cause__
|
||||
ex.message = ''.join(traceback.format_exception(type(ex), ex, ex.__traceback__)[:])
|
||||
return ex
|
||||
with utils.timer('Simulation {} trial {}'.format(self.name, trial_id)):
|
||||
while not is_done():
|
||||
utils.logger.debug(f'Simulation time {model.schedule.time}/{until}. Next: {getattr(model.schedule, "next_time", model.schedule.time + self.interval)}')
|
||||
model.step()
|
||||
return model
|
||||
|
||||
def to_dict(self):
|
||||
return self.config.dict()
|
||||
d = asdict(self)
|
||||
d['model_class'] = serialization.serialize(d['model_class'])[0]
|
||||
d['model_params'] = serialization.serialize(d['model_params'])[0]
|
||||
d['dir_path'] = str(d['dir_path'])
|
||||
|
||||
return d
|
||||
|
||||
def to_yaml(self):
|
||||
return yaml.dump(self.config.dict())
|
||||
return yaml.dump(self.asdict())
|
||||
|
||||
|
||||
def all_from_config(config):
|
||||
def iter_from_config(config):
|
||||
configs = list(serialization.load_config(config))
|
||||
for config, path in configs:
|
||||
if config.get('version', '1') == '1':
|
||||
config = convert_old(config)
|
||||
if not isinstance(config, Config):
|
||||
config = Config(**config)
|
||||
if not config.general.dir_path:
|
||||
config.general.dir_path = os.path.dirname(path)
|
||||
sim = Simulation(config=config)
|
||||
yield sim
|
||||
d = dict(config)
|
||||
if 'dir_path' not in d:
|
||||
d['dir_path'] = os.path.dirname(path)
|
||||
if d.get('version', '2') == '1' or 'agents' in d or 'network_agents' in d or 'environment_agents' in d:
|
||||
d = convert_old(d)
|
||||
d.pop('version', None)
|
||||
yield Simulation(**d)
|
||||
|
||||
|
||||
def from_config(conf_or_path):
|
||||
lst = list(all_from_config(conf_or_path))
|
||||
lst = list(iter_from_config(conf_or_path))
|
||||
if len(lst) > 1:
|
||||
raise AttributeError('Provide only one configuration')
|
||||
return lst[0]
|
||||
|
||||
def from_old_config(conf_or_path):
|
||||
config = list(serialization.load_config(conf_or_path))
|
||||
if len(config) > 1:
|
||||
raise AttributeError('Provide only one configuration')
|
||||
config = convert_old(config[0][0])
|
||||
return Simulation(config)
|
||||
|
||||
|
||||
def run_from_config(*configs, **kwargs):
|
||||
for sim in all_from_config(configs):
|
||||
name = config.general.id
|
||||
logger.info("Using config(s): {name}".format(name=name))
|
||||
for sim in iter_from_config(configs):
|
||||
logger.info(f"Using config(s): {sim.id}")
|
||||
sim.run_simulation(**kwargs)
|
||||
|
11
soil/time.py
11
soil/time.py
@ -37,9 +37,10 @@ class TimedActivation(BaseScheduler):
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(self)
|
||||
super().__init__(*args, **kwargs)
|
||||
self._queue = []
|
||||
self.next_time = 0
|
||||
self.logger = logger.getChild(f'time_{ self.model }')
|
||||
|
||||
def add(self, agent: MesaAgent):
|
||||
if agent.unique_id not in self._agents:
|
||||
@ -52,7 +53,8 @@ class TimedActivation(BaseScheduler):
|
||||
an agent will signal when it wants to be scheduled next.
|
||||
"""
|
||||
|
||||
if self.next_time == INFINITY:
|
||||
self.logger.debug(f'Simulation step {self.next_time}')
|
||||
if not self.model.running:
|
||||
return
|
||||
|
||||
self.time = self.next_time
|
||||
@ -60,7 +62,7 @@ class TimedActivation(BaseScheduler):
|
||||
|
||||
while self._queue and self._queue[0][0] == self.time:
|
||||
(when, agent_id) = heappop(self._queue)
|
||||
logger.debug(f'Stepping agent {agent_id}')
|
||||
self.logger.debug(f'Stepping agent {agent_id}')
|
||||
|
||||
returned = self._agents[agent_id].step()
|
||||
when = (returned or Delta(1)).abs(self.time)
|
||||
@ -74,7 +76,8 @@ class TimedActivation(BaseScheduler):
|
||||
if not self._queue:
|
||||
self.time = INFINITY
|
||||
self.next_time = INFINITY
|
||||
self.model.running = False
|
||||
return
|
||||
|
||||
self.next_time = self._queue[0][0]
|
||||
|
||||
self.logger.debug(f'Next step: {self.next_time}')
|
||||
|
@ -1,6 +1,7 @@
|
||||
import logging
|
||||
from time import time as current_time, strftime, gmtime, localtime
|
||||
import os
|
||||
import traceback
|
||||
|
||||
from shutil import copyfile
|
||||
|
||||
@ -89,3 +90,17 @@ def unflatten_dict(d):
|
||||
target = target[token]
|
||||
target[tokens[-1]] = v
|
||||
return out
|
||||
|
||||
|
||||
def run_and_return_exceptions(self, func, *args, **kwargs):
|
||||
'''
|
||||
A wrapper for run_trial that catches exceptions and returns them.
|
||||
It is meant for async simulations.
|
||||
'''
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as ex:
|
||||
if ex.__cause__ is not None:
|
||||
ex = ex.__cause__
|
||||
ex.message = ''.join(traceback.format_exception(type(ex), ex, ex.__traceback__)[:])
|
||||
return ex
|
||||
|
@ -6,11 +6,11 @@ network_params:
|
||||
n: 100
|
||||
m: 2
|
||||
network_agents:
|
||||
- agent_type: ControlModelM2
|
||||
- agent_class: ControlModelM2
|
||||
weight: 0.1
|
||||
state:
|
||||
id: 1
|
||||
- agent_type: ControlModelM2
|
||||
- agent_class: ControlModelM2
|
||||
weight: 0.9
|
||||
state:
|
||||
id: 0
|
||||
|
@ -10,21 +10,21 @@ network_params:
|
||||
generator: complete_graph
|
||||
n: 10
|
||||
network_agents:
|
||||
- agent_type: CounterModel
|
||||
- agent_class: CounterModel
|
||||
weight: 0.4
|
||||
state:
|
||||
state_id: 0
|
||||
- agent_type: AggregatedCounter
|
||||
- agent_class: AggregatedCounter
|
||||
weight: 0.6
|
||||
environment_agents:
|
||||
- agent_id: 'Environment Agent 1'
|
||||
agent_type: CounterModel
|
||||
agent_class: CounterModel
|
||||
state:
|
||||
times: 10
|
||||
environment_class: Environment
|
||||
environment_params:
|
||||
am_i_complete: true
|
||||
agent_type: CounterModel
|
||||
agent_class: CounterModel
|
||||
default_state:
|
||||
times: 1
|
||||
states:
|
||||
|
@ -46,7 +46,7 @@ class TestAnalysis(TestCase):
|
||||
'generator': 'complete_graph',
|
||||
'n': 2
|
||||
},
|
||||
'agent_type': Ping,
|
||||
'agent_class': Ping,
|
||||
'states': [{'interval': 1}, {'interval': 2}],
|
||||
'max_time': 30,
|
||||
'num_trials': 1,
|
||||
|
@ -1,8 +1,10 @@
|
||||
from unittest import TestCase
|
||||
import os
|
||||
import yaml
|
||||
import copy
|
||||
from os.path import join
|
||||
|
||||
from soil import simulation, serialization, config, network, agents
|
||||
from soil import simulation, serialization, config, network, agents, utils
|
||||
|
||||
ROOT = os.path.abspath(os.path.dirname(__file__))
|
||||
EXAMPLES = join(ROOT, '..', 'examples')
|
||||
@ -10,6 +12,17 @@ EXAMPLES = join(ROOT, '..', 'examples')
|
||||
FORCE_TESTS = os.environ.get('FORCE_TESTS', '')
|
||||
|
||||
|
||||
def isequal(a, b):
|
||||
if isinstance(a, dict):
|
||||
for (k, v) in a.items():
|
||||
if v:
|
||||
isequal(a[k], b[k])
|
||||
else:
|
||||
assert not b.get(k, None)
|
||||
return
|
||||
assert a == b
|
||||
|
||||
|
||||
class TestConfig(TestCase):
|
||||
|
||||
def test_conversion(self):
|
||||
@ -18,18 +31,23 @@ class TestConfig(TestCase):
|
||||
converted_defaults = config.convert_old(old, strict=False)
|
||||
converted = converted_defaults.dict(skip_defaults=True)
|
||||
|
||||
def isequal(a, b):
|
||||
if isinstance(a, dict):
|
||||
for (k, v) in a.items():
|
||||
if v:
|
||||
isequal(a[k], b[k])
|
||||
else:
|
||||
assert not b.get(k, None)
|
||||
return
|
||||
assert a == b
|
||||
|
||||
isequal(converted, expected)
|
||||
|
||||
def test_configuration_changes(self):
|
||||
"""
|
||||
The configuration should not change after running
|
||||
the simulation.
|
||||
"""
|
||||
config = serialization.load_file(join(EXAMPLES, 'complete.yml'))[0]
|
||||
s = simulation.from_config(config)
|
||||
init_config = copy.copy(s.config)
|
||||
|
||||
s.run_simulation(dry_run=True)
|
||||
nconfig = s.config
|
||||
# del nconfig['to
|
||||
isequal(init_config, nconfig)
|
||||
|
||||
|
||||
def test_topology_config(self):
|
||||
netconfig = config.NetConfig(**{
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
@ -48,7 +66,7 @@ class TestConfig(TestCase):
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'agent_type': 'CounterModel',
|
||||
'agent_class': 'CounterModel',
|
||||
# 'states': [{'times': 10}, {'times': 20}],
|
||||
'max_time': 2,
|
||||
'dry_run': True,
|
||||
@ -63,7 +81,6 @@ class TestConfig(TestCase):
|
||||
assert len(env.agents) == 2
|
||||
assert env.agents[0].topology == env.topologies['default']
|
||||
|
||||
|
||||
def test_agents_from_config(self):
|
||||
'''We test that the known complete configuration produces
|
||||
the right agents in the right groups'''
|
||||
@ -74,8 +91,25 @@ class TestConfig(TestCase):
|
||||
assert len(env.agents(group='network')) == 10
|
||||
assert len(env.agents(group='environment')) == 1
|
||||
|
||||
assert sum(1 for a in env.agents(group='network', agent_type=agents.CounterModel)) == 4
|
||||
assert sum(1 for a in env.agents(group='network', agent_type=agents.AggregatedCounter)) == 6
|
||||
assert sum(1 for a in env.agents(group='network', agent_class=agents.CounterModel)) == 4
|
||||
assert sum(1 for a in env.agents(group='network', agent_class=agents.AggregatedCounter)) == 6
|
||||
|
||||
def test_yaml(self):
|
||||
"""
|
||||
The YAML version of a newly created configuration should be equivalent
|
||||
to the configuration file used.
|
||||
Values not present in the original config file should have reasonable
|
||||
defaults.
|
||||
"""
|
||||
with utils.timer('loading'):
|
||||
config = serialization.load_file(join(EXAMPLES, 'complete.yml'))[0]
|
||||
s = simulation.from_config(config)
|
||||
with utils.timer('serializing'):
|
||||
serial = s.to_yaml()
|
||||
with utils.timer('recovering'):
|
||||
recovered = yaml.load(serial, Loader=yaml.SafeLoader)
|
||||
for (k, v) in config.items():
|
||||
assert recovered[k] == v
|
||||
|
||||
def make_example_test(path, cfg):
|
||||
def wrapped(self):
|
||||
|
@ -36,7 +36,7 @@ class Exporters(TestCase):
|
||||
config = {
|
||||
'name': 'exporter_sim',
|
||||
'network_params': {},
|
||||
'agent_type': 'CounterModel',
|
||||
'agent_class': 'CounterModel',
|
||||
'max_time': 2,
|
||||
'num_trials': 5,
|
||||
'environment_params': {}
|
||||
@ -62,7 +62,7 @@ class Exporters(TestCase):
|
||||
'generator': 'complete_graph',
|
||||
'n': 4
|
||||
},
|
||||
'agent_type': 'CounterModel',
|
||||
'agent_class': 'CounterModel',
|
||||
'max_time': 2,
|
||||
'num_trials': n_trials,
|
||||
'dry_run': False,
|
||||
|
@ -41,7 +41,7 @@ class TestHistory(TestCase):
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'network_agents': [{
|
||||
'agent_type': 'AggregatedCounter',
|
||||
'agent_class': 'AggregatedCounter',
|
||||
'weight': 1,
|
||||
'state': {'state_id': 0}
|
||||
|
||||
|
@ -1,9 +1,6 @@
|
||||
from unittest import TestCase
|
||||
|
||||
import os
|
||||
import io
|
||||
import yaml
|
||||
import copy
|
||||
import pickle
|
||||
import networkx as nx
|
||||
from functools import partial
|
||||
@ -29,56 +26,17 @@ class CustomAgent(agents.FSM, agents.NetworkAgent):
|
||||
|
||||
class TestMain(TestCase):
|
||||
|
||||
def test_load_graph(self):
|
||||
"""
|
||||
Load a graph from file if the extension is known.
|
||||
Raise an exception otherwise.
|
||||
"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
}
|
||||
}
|
||||
G = network.from_config(config['network_params'])
|
||||
assert G
|
||||
assert len(G) == 2
|
||||
with self.assertRaises(AttributeError):
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'unknown.extension')
|
||||
}
|
||||
}
|
||||
G = network.from_config(config['network_params'])
|
||||
print(G)
|
||||
|
||||
def test_generate_barabasi(self):
|
||||
"""
|
||||
If no path is given, a generator and network parameters
|
||||
should be used to generate a network
|
||||
"""
|
||||
cfg = {
|
||||
'params': {
|
||||
'generator': 'barabasi_albert_graph'
|
||||
}
|
||||
}
|
||||
with self.assertRaises(Exception):
|
||||
G = network.from_config(cfg)
|
||||
cfg['params']['n'] = 100
|
||||
cfg['params']['m'] = 10
|
||||
G = network.from_config(cfg)
|
||||
assert len(G) == 100
|
||||
|
||||
def test_empty_simulation(self):
|
||||
"""A simulation with a base behaviour should do nothing"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'agent_type': 'BaseAgent',
|
||||
'environment_params': {
|
||||
'model_params': {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'agent_class': 'BaseAgent',
|
||||
}
|
||||
}
|
||||
s = simulation.from_old_config(config)
|
||||
s = simulation.from_config(config)
|
||||
s.run_simulation(dry_run=True)
|
||||
|
||||
|
||||
@ -88,21 +46,21 @@ class TestMain(TestCase):
|
||||
agent should be able to update its state."""
|
||||
config = {
|
||||
'name': 'CounterAgent',
|
||||
'network_params': {
|
||||
'generator': nx.complete_graph,
|
||||
'n': 2,
|
||||
},
|
||||
'agent_type': 'CounterModel',
|
||||
'states': {
|
||||
0: {'times': 10},
|
||||
1: {'times': 20},
|
||||
},
|
||||
'max_time': 2,
|
||||
'num_trials': 1,
|
||||
'environment_params': {
|
||||
'max_time': 2,
|
||||
'model_params': {
|
||||
'network_params': {
|
||||
'generator': nx.complete_graph,
|
||||
'n': 2,
|
||||
},
|
||||
'agent_class': 'CounterModel',
|
||||
'states': {
|
||||
0: {'times': 10},
|
||||
1: {'times': 20},
|
||||
},
|
||||
}
|
||||
}
|
||||
s = simulation.from_old_config(config)
|
||||
s = simulation.from_config(config)
|
||||
|
||||
def test_counter_agent(self):
|
||||
"""
|
||||
@ -110,24 +68,24 @@ class TestMain(TestCase):
|
||||
agent should be able to update its state."""
|
||||
config = {
|
||||
'version': '2',
|
||||
'general': {
|
||||
'name': 'CounterAgent',
|
||||
'max_time': 2,
|
||||
'dry_run': True,
|
||||
'num_trials': 1,
|
||||
},
|
||||
'topologies': {
|
||||
'default': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
}
|
||||
},
|
||||
'agents': {
|
||||
'default': {
|
||||
'agent_class': 'CounterModel',
|
||||
'name': 'CounterAgent',
|
||||
'dry_run': True,
|
||||
'num_trials': 1,
|
||||
'max_time': 2,
|
||||
'model_params': {
|
||||
'topologies': {
|
||||
'default': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
}
|
||||
},
|
||||
'counters': {
|
||||
'topology': 'default',
|
||||
'fixed': [{'state': {'times': 10}}, {'state': {'times': 20}}],
|
||||
'agents': {
|
||||
'default': {
|
||||
'agent_class': 'CounterModel',
|
||||
},
|
||||
'counters': {
|
||||
'topology': 'default',
|
||||
'fixed': [{'state': {'times': 10}}, {'state': {'times': 20}}],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,33 +99,37 @@ class TestMain(TestCase):
|
||||
assert env.agents[0]['times'] == 11
|
||||
assert env.agents[1]['times'] == 21
|
||||
|
||||
def test_custom_agent(self):
|
||||
"""Allow for search of neighbors with a certain state_id"""
|
||||
def test_init_and_count_agents(self):
|
||||
"""Agents should be properly initialized and counting should filter them properly"""
|
||||
#TODO: separate this test into two or more test cases
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'network_agents': [{
|
||||
'agent_type': CustomAgent,
|
||||
'weight': 1
|
||||
|
||||
}],
|
||||
'max_time': 10,
|
||||
'environment_params': {
|
||||
}
|
||||
'model_params': {
|
||||
'agents': [(CustomAgent, {'weight': 1}),
|
||||
(CustomAgent, {'weight': 3}),
|
||||
],
|
||||
'topologies': {
|
||||
'default': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
s = simulation.from_old_config(config)
|
||||
s = simulation.from_config(config)
|
||||
env = s.run_simulation(dry_run=True)[0]
|
||||
assert env.agents[1].count_agents(state_id='normal') == 2
|
||||
assert env.agents[1].count_agents(state_id='normal', limit_neighbors=True) == 1
|
||||
assert env.agents[0].neighbors == 1
|
||||
assert env.agents[0].weight == 1
|
||||
assert env.count_agents() == 2
|
||||
assert env.count_agents(weight=1) == 1
|
||||
assert env.count_agents(weight=3) == 1
|
||||
assert env.count_agents(agent_class=CustomAgent) == 2
|
||||
|
||||
|
||||
def test_torvalds_example(self):
|
||||
"""A complete example from a documentation should work."""
|
||||
config = serialization.load_file(join(EXAMPLES, 'torvalds.yml'))[0]
|
||||
config['network_params']['path'] = join(EXAMPLES,
|
||||
config['model_params']['network_params']['path'] = join(EXAMPLES,
|
||||
config['network_params']['path'])
|
||||
s = simulation.from_old_config(config)
|
||||
s = simulation.from_config(config)
|
||||
env = s.run_simulation(dry_run=True)[0]
|
||||
for a in env.network_agents:
|
||||
skill_level = a.state['skill_level']
|
||||
@ -184,47 +146,6 @@ class TestMain(TestCase):
|
||||
assert a.state['total'] == 3
|
||||
assert a.state['neighbors'] == 1
|
||||
|
||||
def test_yaml(self):
|
||||
"""
|
||||
The YAML version of a newly created configuration should be equivalent
|
||||
to the configuration file used.
|
||||
Values not present in the original config file should have reasonable
|
||||
defaults.
|
||||
"""
|
||||
with utils.timer('loading'):
|
||||
config = serialization.load_file(join(EXAMPLES, 'complete.yml'))[0]
|
||||
s = simulation.from_old_config(config)
|
||||
with utils.timer('serializing'):
|
||||
serial = s.to_yaml()
|
||||
with utils.timer('recovering'):
|
||||
recovered = yaml.load(serial, Loader=yaml.SafeLoader)
|
||||
for (k, v) in config.items():
|
||||
assert recovered[k] == v
|
||||
|
||||
def test_configuration_changes(self):
|
||||
"""
|
||||
The configuration should not change after running
|
||||
the simulation.
|
||||
"""
|
||||
config = serialization.load_file(join(EXAMPLES, 'complete.yml'))[0]
|
||||
s = simulation.from_old_config(config)
|
||||
init_config = copy.copy(s.config)
|
||||
|
||||
s.run_simulation(dry_run=True)
|
||||
nconfig = s.config
|
||||
# del nconfig['to
|
||||
assert init_config == nconfig
|
||||
|
||||
def test_save_geometric(self):
|
||||
"""
|
||||
There is a bug in networkx that prevents it from creating a GEXF file
|
||||
from geometric models. We should work around it.
|
||||
"""
|
||||
G = nx.random_geometric_graph(20, 0.1)
|
||||
env = Environment(topology=G)
|
||||
f = io.BytesIO()
|
||||
env.dump_gexf(f)
|
||||
|
||||
def test_serialize_class(self):
|
||||
ser, name = serialization.serialize(agents.BaseAgent, known_modules=[])
|
||||
assert name == 'soil.agents.BaseAgent'
|
||||
@ -247,7 +168,7 @@ class TestMain(TestCase):
|
||||
des = serialization.deserialize(name, ser)
|
||||
assert i == des
|
||||
|
||||
def test_serialize_agent_type(self):
|
||||
def test_serialize_agent_class(self):
|
||||
'''A class from soil.agents should be serialized without the module part'''
|
||||
ser = agents.serialize_type(CustomAgent)
|
||||
assert ser == 'test_main.CustomAgent'
|
||||
@ -258,33 +179,33 @@ class TestMain(TestCase):
|
||||
def test_deserialize_agent_distribution(self):
|
||||
agent_distro = [
|
||||
{
|
||||
'agent_type': 'CounterModel',
|
||||
'agent_class': 'CounterModel',
|
||||
'weight': 1
|
||||
},
|
||||
{
|
||||
'agent_type': 'test_main.CustomAgent',
|
||||
'agent_class': 'test_main.CustomAgent',
|
||||
'weight': 2
|
||||
},
|
||||
]
|
||||
converted = agents.deserialize_definition(agent_distro)
|
||||
assert converted[0]['agent_type'] == agents.CounterModel
|
||||
assert converted[1]['agent_type'] == CustomAgent
|
||||
assert converted[0]['agent_class'] == agents.CounterModel
|
||||
assert converted[1]['agent_class'] == CustomAgent
|
||||
pickle.dumps(converted)
|
||||
|
||||
def test_serialize_agent_distribution(self):
|
||||
agent_distro = [
|
||||
{
|
||||
'agent_type': agents.CounterModel,
|
||||
'agent_class': agents.CounterModel,
|
||||
'weight': 1
|
||||
},
|
||||
{
|
||||
'agent_type': CustomAgent,
|
||||
'agent_class': CustomAgent,
|
||||
'weight': 2
|
||||
},
|
||||
]
|
||||
converted = agents.serialize_definition(agent_distro)
|
||||
assert converted[0]['agent_type'] == 'CounterModel'
|
||||
assert converted[1]['agent_type'] == 'test_main.CustomAgent'
|
||||
assert converted[0]['agent_class'] == 'CounterModel'
|
||||
assert converted[1]['agent_class'] == 'test_main.CustomAgent'
|
||||
pickle.dumps(converted)
|
||||
|
||||
def test_subgraph(self):
|
||||
@ -292,7 +213,7 @@ class TestMain(TestCase):
|
||||
G = nx.Graph()
|
||||
G.add_node(3)
|
||||
G.add_edge(1, 2)
|
||||
distro = agents.calculate_distribution(agent_type=agents.NetworkAgent)
|
||||
distro = agents.calculate_distribution(agent_class=agents.NetworkAgent)
|
||||
distro[0]['topology'] = 'default'
|
||||
aconfig = config.AgentConfig(distribution=distro, topology='default')
|
||||
env = Environment(name='Test', topologies={'default': G}, agents={'network': aconfig})
|
||||
@ -303,7 +224,7 @@ class TestMain(TestCase):
|
||||
assert len(a2.subgraph(limit_neighbors=True)) == 2
|
||||
assert len(a3.subgraph(limit_neighbors=True)) == 1
|
||||
assert len(a3.subgraph(limit_neighbors=True, center=False)) == 0
|
||||
assert len(a3.subgraph(agent_type=agents.NetworkAgent)) == 3
|
||||
assert len(a3.subgraph(agent_class=agents.NetworkAgent)) == 3
|
||||
|
||||
def test_templates(self):
|
||||
'''Loading a template should result in several configs'''
|
||||
@ -313,19 +234,19 @@ class TestMain(TestCase):
|
||||
def test_until(self):
|
||||
config = {
|
||||
'name': 'until_sim',
|
||||
'network_params': {},
|
||||
'agent_type': 'CounterModel',
|
||||
'model_params': {
|
||||
'network_params': {},
|
||||
'agent_class': 'CounterModel',
|
||||
},
|
||||
'max_time': 2,
|
||||
'num_trials': 50,
|
||||
'environment_params': {}
|
||||
}
|
||||
s = simulation.from_old_config(config)
|
||||
s = simulation.from_config(config)
|
||||
runs = list(s.run_simulation(dry_run=True))
|
||||
over = list(x.now for x in runs if x.now>2)
|
||||
assert len(runs) == config['num_trials']
|
||||
assert len(over) == 0
|
||||
|
||||
|
||||
def test_fsm(self):
|
||||
'''Basic state change'''
|
||||
class ToggleAgent(agents.FSM):
|
||||
|
85
tests/test_network.py
Normal file
85
tests/test_network.py
Normal file
@ -0,0 +1,85 @@
|
||||
from unittest import TestCase
|
||||
|
||||
import io
|
||||
import os
|
||||
import networkx as nx
|
||||
|
||||
from os.path import join
|
||||
|
||||
from soil import network, environment
|
||||
|
||||
ROOT = os.path.abspath(os.path.dirname(__file__))
|
||||
EXAMPLES = join(ROOT, '..', 'examples')
|
||||
|
||||
|
||||
class TestNetwork(TestCase):
|
||||
def test_load_graph(self):
|
||||
"""
|
||||
Load a graph from file if the extension is known.
|
||||
Raise an exception otherwise.
|
||||
"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
}
|
||||
}
|
||||
G = network.from_config(config['network_params'])
|
||||
assert G
|
||||
assert len(G) == 2
|
||||
with self.assertRaises(AttributeError):
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'unknown.extension')
|
||||
}
|
||||
}
|
||||
G = network.from_config(config['network_params'])
|
||||
print(G)
|
||||
|
||||
def test_generate_barabasi(self):
|
||||
"""
|
||||
If no path is given, a generator and network parameters
|
||||
should be used to generate a network
|
||||
"""
|
||||
cfg = {
|
||||
'params': {
|
||||
'generator': 'barabasi_albert_graph'
|
||||
}
|
||||
}
|
||||
with self.assertRaises(Exception):
|
||||
G = network.from_config(cfg)
|
||||
cfg['params']['n'] = 100
|
||||
cfg['params']['m'] = 10
|
||||
G = network.from_config(cfg)
|
||||
assert len(G) == 100
|
||||
|
||||
def test_save_geometric(self):
|
||||
"""
|
||||
There is a bug in networkx that prevents it from creating a GEXF file
|
||||
from geometric models. We should work around it.
|
||||
"""
|
||||
G = nx.random_geometric_graph(20, 0.1)
|
||||
env = environment.NetworkEnvironment(topology=G)
|
||||
f = io.BytesIO()
|
||||
env.dump_gexf(f)
|
||||
|
||||
def test_custom_agent_neighbors(self):
|
||||
"""Allow for search of neighbors with a certain state_id"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'network_agents': [{
|
||||
'agent_class': CustomAgent,
|
||||
'weight': 1
|
||||
|
||||
}],
|
||||
'max_time': 10,
|
||||
'environment_params': {
|
||||
}
|
||||
}
|
||||
s = simulation.from_config(config)
|
||||
env = s.run_simulation(dry_run=True)[0]
|
||||
assert env.agents[1].count_agents(state_id='normal') == 2
|
||||
assert env.agents[1].count_agents(state_id='normal', limit_neighbors=True) == 1
|
||||
assert env.agents[0].neighbors == 1
|
||||
|
Loading…
Reference in New Issue
Block a user