Mesa 3.0.0b0__py3-none-any.whl → 3.0.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Mesa might be problematic. Click here for more details.
- examples/README.md +37 -0
- examples/__init__.py +0 -0
- examples/advanced/__init__.py +0 -0
- examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb +116 -0
- examples/advanced/epstein_civil_violence/Readme.md +33 -0
- examples/advanced/epstein_civil_violence/epstein_civil_violence/__init__.py +0 -0
- examples/advanced/epstein_civil_violence/epstein_civil_violence/agent.py +158 -0
- examples/advanced/epstein_civil_violence/epstein_civil_violence/model.py +146 -0
- examples/advanced/epstein_civil_violence/epstein_civil_violence/portrayal.py +33 -0
- examples/advanced/epstein_civil_violence/epstein_civil_violence/server.py +81 -0
- examples/advanced/epstein_civil_violence/requirements.txt +3 -0
- examples/advanced/epstein_civil_violence/run.py +3 -0
- examples/advanced/pd_grid/analysis.ipynb +228 -0
- examples/advanced/pd_grid/pd_grid/__init__.py +0 -0
- examples/advanced/pd_grid/pd_grid/agent.py +50 -0
- examples/advanced/pd_grid/pd_grid/model.py +72 -0
- examples/advanced/pd_grid/pd_grid/portrayal.py +19 -0
- examples/advanced/pd_grid/pd_grid/server.py +21 -0
- examples/advanced/pd_grid/readme.md +42 -0
- examples/advanced/pd_grid/requirements.txt +3 -0
- examples/advanced/pd_grid/run.py +3 -0
- examples/advanced/sugarscape_g1mt/Readme.md +87 -0
- examples/advanced/sugarscape_g1mt/app.py +61 -0
- examples/advanced/sugarscape_g1mt/requirements.txt +6 -0
- examples/advanced/sugarscape_g1mt/run.py +105 -0
- examples/advanced/sugarscape_g1mt/sugarscape_g1mt/__init__.py +0 -0
- examples/advanced/sugarscape_g1mt/sugarscape_g1mt/model.py +180 -0
- examples/advanced/sugarscape_g1mt/sugarscape_g1mt/resource_agents.py +26 -0
- examples/advanced/sugarscape_g1mt/sugarscape_g1mt/server.py +61 -0
- examples/advanced/sugarscape_g1mt/sugarscape_g1mt/sugar-map.txt +50 -0
- examples/advanced/sugarscape_g1mt/sugarscape_g1mt/trader_agents.py +321 -0
- examples/advanced/sugarscape_g1mt/tests.py +72 -0
- examples/advanced/wolf_sheep/Readme.md +57 -0
- examples/advanced/wolf_sheep/__init__.py +0 -0
- examples/advanced/wolf_sheep/requirements.txt +1 -0
- examples/advanced/wolf_sheep/run.py +3 -0
- examples/advanced/wolf_sheep/wolf_sheep/__init__.py +0 -0
- examples/advanced/wolf_sheep/wolf_sheep/agents.py +102 -0
- examples/advanced/wolf_sheep/wolf_sheep/model.py +136 -0
- examples/advanced/wolf_sheep/wolf_sheep/resources/sheep.png +0 -0
- examples/advanced/wolf_sheep/wolf_sheep/resources/wolf.png +0 -0
- examples/advanced/wolf_sheep/wolf_sheep/server.py +78 -0
- examples/basic/__init__.py +13 -0
- examples/basic/boid_flockers/Readme.md +43 -0
- examples/basic/boid_flockers/agents.py +71 -0
- examples/basic/boid_flockers/app.py +59 -0
- examples/basic/boid_flockers/model.py +70 -0
- examples/basic/boltzmann_wealth_model/Readme.md +60 -0
- examples/basic/boltzmann_wealth_model/agents.py +31 -0
- examples/basic/boltzmann_wealth_model/app.py +66 -0
- examples/basic/boltzmann_wealth_model/model.py +44 -0
- examples/basic/boltzmann_wealth_model/st_app.py +115 -0
- examples/basic/conways_game_of_life/Readme.md +35 -0
- examples/basic/conways_game_of_life/agents.py +47 -0
- examples/basic/conways_game_of_life/model.py +32 -0
- examples/basic/conways_game_of_life/portrayal.py +18 -0
- examples/basic/conways_game_of_life/requirements.txt +1 -0
- examples/basic/conways_game_of_life/server.py +11 -0
- examples/basic/conways_game_of_life/st_app.py +71 -0
- examples/basic/schelling/README.md +47 -0
- examples/basic/schelling/agents.py +26 -0
- examples/basic/schelling/analysis.ipynb +205 -0
- examples/basic/schelling/app.py +43 -0
- examples/basic/schelling/model.py +60 -0
- examples/basic/virus_on_network/README.md +61 -0
- examples/basic/virus_on_network/agents.py +69 -0
- examples/basic/virus_on_network/app.py +133 -0
- examples/basic/virus_on_network/model.py +99 -0
- mesa/__init__.py +4 -1
- mesa/agent.py +14 -19
- mesa/examples.py +3 -0
- mesa/experimental/__init__.py +8 -2
- mesa/experimental/cell_space/cell.py +9 -0
- mesa/experimental/cell_space/discrete_space.py +7 -1
- mesa/experimental/cell_space/grid.py +13 -0
- mesa/experimental/cell_space/network.py +3 -0
- mesa/model.py +63 -12
- mesa/time.py +5 -3
- mesa/visualization/components/matplotlib.py +9 -4
- mesa/visualization/solara_viz.py +13 -58
- {mesa-3.0.0b0.dist-info → mesa-3.0.0b1.dist-info}/METADATA +1 -1
- mesa-3.0.0b1.dist-info/RECORD +114 -0
- mesa-3.0.0b0.dist-info/RECORD +0 -45
- {mesa-3.0.0b0.dist-info → mesa-3.0.0b1.dist-info}/WHEEL +0 -0
- {mesa-3.0.0b0.dist-info → mesa-3.0.0b1.dist-info}/entry_points.txt +0 -0
- {mesa-3.0.0b0.dist-info → mesa-3.0.0b1.dist-info}/licenses/LICENSE +0 -0
- {mesa-3.0.0b0.dist-info → mesa-3.0.0b1.dist-info}/licenses/NOTICE +0 -0
examples/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Mesa core examples
|
|
2
|
+
This folder contains a collection of example models built using Mesa. These core models are maintained by the Mesa team and are intended to demonstrate the capabilities of Mesa.
|
|
3
|
+
|
|
4
|
+
More user examples and showcases can be found in the [mesa-examples](https://github.com/projectmesa/mesa-examples) repository.
|
|
5
|
+
|
|
6
|
+
## Basic Examples
|
|
7
|
+
The basic examples are relatively simple and only use stable Mesa features. They are good starting points for learning how to use Mesa.
|
|
8
|
+
|
|
9
|
+
### [Boltzmann Wealth Model](basic/boltzmann_wealth_model)
|
|
10
|
+
Completed code to go along with the [tutorial](https://mesa.readthedocs.io/latest/tutorials/intro_tutorial.html) on making a simple model of how a highly-skewed wealth distribution can emerge from simple rules.
|
|
11
|
+
|
|
12
|
+
### [Boids Flockers Model](basic/boid_flockers)
|
|
13
|
+
[Boids](https://en.wikipedia.org/wiki/Boids)-style flocking model, demonstrating the use of agents moving through a continuous space following direction vectors.
|
|
14
|
+
|
|
15
|
+
### [Conway's Game of Life](basic/conways_game_of_life)
|
|
16
|
+
Implementation of [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life), a cellular automata where simple rules can give rise to complex patterns.
|
|
17
|
+
|
|
18
|
+
### [Schelling Segregation Model](basic/schelling)
|
|
19
|
+
Mesa implementation of the classic [Schelling segregation](http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/) model.
|
|
20
|
+
|
|
21
|
+
### [Virus on a Network Model](basic/virus_on_network)
|
|
22
|
+
This model is based on the NetLogo [Virus on a Network](https://ccl.northwestern.edu/netlogo/models/VirusonaNetwork) model.
|
|
23
|
+
|
|
24
|
+
## Advanced Examples
|
|
25
|
+
The advanced examples are more complex and may use experimental Mesa features. They are good starting points for learning how to build more complex models.
|
|
26
|
+
|
|
27
|
+
### [Epstein Civil Violence Model](advanced/epstein_civil_violence)
|
|
28
|
+
Joshua Epstein's [model](http://www.uvm.edu/~pdodds/files/papers/others/2002/epstein2002a.pdf) of how a decentralized uprising can be suppressed or reach a critical mass of support.
|
|
29
|
+
|
|
30
|
+
### [Demographic Prisoner's Dilemma on a Grid](advanced/pd_grid)
|
|
31
|
+
Grid-based demographic prisoner's dilemma model, demonstrating how simple rules can lead to the emergence of widespread cooperation -- and how a model activation regime can change its outcome.
|
|
32
|
+
|
|
33
|
+
### [Sugarscape Model with Traders](advanced/sugarscape_g1mt)
|
|
34
|
+
This is Epstein & Axtell's Sugarscape model with Traders, a detailed description is in Chapter four of *Growing Artificial Societies: Social Science from the Bottom Up (1996)*. The model shows how emergent price equilibrium can happen via decentralized dynamics.
|
|
35
|
+
|
|
36
|
+
### [Wolf-Sheep Predation Model](advanced/wolf_sheep)
|
|
37
|
+
Implementation of an ecological model of predation and reproduction, based on the NetLogo [Wolf Sheep Predation](http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation) model.
|
examples/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"metadata": {},
|
|
6
|
+
"source": [
|
|
7
|
+
"This example implements the first model from \"Modeling civil violence: An agent-based computational approach,\" by Joshua Epstein. The paper (pdf) can be found [here](http://www.uvm.edu/~pdodds/files/papers/others/2002/epstein2002a.pdf).\n",
|
|
8
|
+
"\n",
|
|
9
|
+
"The model consists of two types of agents: \"Citizens\" (called \"Agents\" in the paper) and \"Cops.\" Agents decide whether or not to rebel by weighing their unhappiness ('grievance') against the risk of rebelling, which they estimate by comparing the local ratio of rebels to cops. \n",
|
|
10
|
+
"\n",
|
|
11
|
+
"\n"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"cell_type": "code",
|
|
16
|
+
"execution_count": 5,
|
|
17
|
+
"metadata": {},
|
|
18
|
+
"outputs": [],
|
|
19
|
+
"source": [
|
|
20
|
+
"%matplotlib inline\n",
|
|
21
|
+
"\n",
|
|
22
|
+
"from epstein_civil_violence.model import EpsteinCivilViolence"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"cell_type": "code",
|
|
27
|
+
"execution_count": 6,
|
|
28
|
+
"metadata": {},
|
|
29
|
+
"outputs": [],
|
|
30
|
+
"source": [
|
|
31
|
+
"model = EpsteinCivilViolence(\n",
|
|
32
|
+
" height=40,\n",
|
|
33
|
+
" width=40,\n",
|
|
34
|
+
" citizen_density=0.7,\n",
|
|
35
|
+
" cop_density=0.074,\n",
|
|
36
|
+
" citizen_vision=7,\n",
|
|
37
|
+
" cop_vision=7,\n",
|
|
38
|
+
" legitimacy=0.8,\n",
|
|
39
|
+
" max_jail_term=1000,\n",
|
|
40
|
+
" max_iters=1000,\n",
|
|
41
|
+
") # cap the number of steps the model takes\n",
|
|
42
|
+
"model.run_model()"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"cell_type": "markdown",
|
|
47
|
+
"metadata": {},
|
|
48
|
+
"source": [
|
|
49
|
+
"The model's data collector counts the number of citizens who are Active (in rebellion), Jailed, or Quiescent after each step."
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"cell_type": "code",
|
|
54
|
+
"execution_count": 7,
|
|
55
|
+
"metadata": {},
|
|
56
|
+
"outputs": [],
|
|
57
|
+
"source": [
|
|
58
|
+
"model_out = model.datacollector.get_model_vars_dataframe()"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"cell_type": "code",
|
|
63
|
+
"execution_count": 8,
|
|
64
|
+
"metadata": {},
|
|
65
|
+
"outputs": [
|
|
66
|
+
{
|
|
67
|
+
"data": {
|
|
68
|
+
"image/png": "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\n",
|
|
69
|
+
"text/plain": [
|
|
70
|
+
"<Figure size 432x288 with 1 Axes>"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"metadata": {
|
|
74
|
+
"needs_background": "light"
|
|
75
|
+
},
|
|
76
|
+
"output_type": "display_data"
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"source": [
|
|
80
|
+
"ax = model_out.plot()\n",
|
|
81
|
+
"ax.set_title(\"Citizen Condition Over Time\")\n",
|
|
82
|
+
"ax.set_xlabel(\"Step\")\n",
|
|
83
|
+
"ax.set_ylabel(\"Number of Citizens\")\n",
|
|
84
|
+
"_ = ax.legend(bbox_to_anchor=(1.35, 1.025))"
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"cell_type": "code",
|
|
89
|
+
"execution_count": null,
|
|
90
|
+
"metadata": {},
|
|
91
|
+
"outputs": [],
|
|
92
|
+
"source": []
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"metadata": {
|
|
96
|
+
"kernelspec": {
|
|
97
|
+
"display_name": "Python 3",
|
|
98
|
+
"language": "python",
|
|
99
|
+
"name": "python3"
|
|
100
|
+
},
|
|
101
|
+
"language_info": {
|
|
102
|
+
"codemirror_mode": {
|
|
103
|
+
"name": "ipython",
|
|
104
|
+
"version": 3
|
|
105
|
+
},
|
|
106
|
+
"file_extension": ".py",
|
|
107
|
+
"mimetype": "text/x-python",
|
|
108
|
+
"name": "python",
|
|
109
|
+
"nbconvert_exporter": "python",
|
|
110
|
+
"pygments_lexer": "ipython3",
|
|
111
|
+
"version": "3.7.3"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"nbformat": 4,
|
|
115
|
+
"nbformat_minor": 1
|
|
116
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Epstein Civil Violence Model
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
This model is based on Joshua Epstein's simulation of how civil unrest grows and is suppressed. Citizen agents wander the grid randomly, and are endowed with individual risk aversion and hardship levels; there is also a universal regime legitimacy value. There are also Cop agents, who work on behalf of the regime. Cops arrest Citizens who are actively rebelling; Citizens decide whether to rebel based on their hardship and the regime legitimacy, and their perceived probability of arrest.
|
|
6
|
+
|
|
7
|
+
The model generates mass uprising as self-reinforcing processes: if enough agents are rebelling, the probability of any individual agent being arrested is reduced, making more agents more likely to join the uprising. However, the more rebelling Citizens the Cops arrest, the less likely additional agents become to join.
|
|
8
|
+
|
|
9
|
+
## How to Run
|
|
10
|
+
|
|
11
|
+
To run the model interactively, run ``EpsteinCivilViolenceServer.py`` in this directory. e.g.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
$ python EpsteinCivilViolenceServer.py
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run.
|
|
18
|
+
|
|
19
|
+
## Files
|
|
20
|
+
|
|
21
|
+
* ``EpsteinCivilViolence.py``: Core model and agent code.
|
|
22
|
+
* ``EpsteinCivilViolenceServer.py``: Sets up the interactive visualization.
|
|
23
|
+
* ``Epstein Civil Violence.ipynb``: Jupyter notebook conducting some preliminary analysis of the model.
|
|
24
|
+
|
|
25
|
+
## Further Reading
|
|
26
|
+
|
|
27
|
+
This model is based adapted from:
|
|
28
|
+
|
|
29
|
+
[Epstein, J. “Modeling civil violence: An agent-based computational approach”, Proceedings of the National Academy of Sciences, Vol. 99, Suppl. 3, May 14, 2002](http://www.pnas.org/content/99/suppl.3/7243.short)
|
|
30
|
+
|
|
31
|
+
A similar model is also included with NetLogo:
|
|
32
|
+
|
|
33
|
+
Wilensky, U. (2004). NetLogo Rebellion model. http://ccl.northwestern.edu/netlogo/models/Rebellion. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
|
|
File without changes
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import mesa
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class EpsteinAgent(mesa.experimental.cell_space.CellAgent):
|
|
7
|
+
def update_neighbors(self):
|
|
8
|
+
"""
|
|
9
|
+
Look around and see who my neighbors are
|
|
10
|
+
"""
|
|
11
|
+
self.neighborhood = self.cell.get_neighborhood(radius=self.vision)
|
|
12
|
+
|
|
13
|
+
self.neighbors = self.neighborhood.agents
|
|
14
|
+
self.empty_neighbors = [c for c in self.neighborhood if c.is_empty]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Citizen(EpsteinAgent):
|
|
18
|
+
"""
|
|
19
|
+
A member of the general population, may or may not be in active rebellion.
|
|
20
|
+
Summary of rule: If grievance - risk > threshold, rebel.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
hardship: Agent's 'perceived hardship (i.e., physical or economic
|
|
24
|
+
privation).' Exogenous, drawn from U(0,1).
|
|
25
|
+
regime_legitimacy: Agent's perception of regime legitimacy, equal
|
|
26
|
+
across agents. Exogenous.
|
|
27
|
+
risk_aversion: Exogenous, drawn from U(0,1).
|
|
28
|
+
threshold: if (grievance - (risk_aversion * arrest_probability)) >
|
|
29
|
+
threshold, go/remain Active
|
|
30
|
+
vision: number of cells in each direction (N, S, E and W) that agent
|
|
31
|
+
can inspect
|
|
32
|
+
condition: Can be "Quiescent" or "Active;" deterministic function of
|
|
33
|
+
greivance, perceived risk, and
|
|
34
|
+
grievance: deterministic function of hardship and regime_legitimacy;
|
|
35
|
+
how aggrieved is agent at the regime?
|
|
36
|
+
arrest_probability: agent's assessment of arrest probability, given
|
|
37
|
+
rebellion
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
model,
|
|
43
|
+
hardship,
|
|
44
|
+
regime_legitimacy,
|
|
45
|
+
risk_aversion,
|
|
46
|
+
threshold,
|
|
47
|
+
vision,
|
|
48
|
+
):
|
|
49
|
+
"""
|
|
50
|
+
Create a new Citizen.
|
|
51
|
+
Args:
|
|
52
|
+
model: the model to which the agent belongs
|
|
53
|
+
hardship: Agent's 'perceived hardship (i.e., physical or economic
|
|
54
|
+
privation).' Exogenous, drawn from U(0,1).
|
|
55
|
+
regime_legitimacy: Agent's perception of regime legitimacy, equal
|
|
56
|
+
across agents. Exogenous.
|
|
57
|
+
risk_aversion: Exogenous, drawn from U(0,1).
|
|
58
|
+
threshold: if (grievance - (risk_aversion * arrest_probability)) >
|
|
59
|
+
threshold, go/remain Active
|
|
60
|
+
vision: number of cells in each direction (N, S, E and W) that
|
|
61
|
+
agent can inspect. Exogenous.
|
|
62
|
+
model: model instance
|
|
63
|
+
"""
|
|
64
|
+
super().__init__(model)
|
|
65
|
+
self.hardship = hardship
|
|
66
|
+
self.regime_legitimacy = regime_legitimacy
|
|
67
|
+
self.risk_aversion = risk_aversion
|
|
68
|
+
self.threshold = threshold
|
|
69
|
+
self.condition = "Quiescent"
|
|
70
|
+
self.vision = vision
|
|
71
|
+
self.jail_sentence = 0
|
|
72
|
+
self.grievance = self.hardship * (1 - self.regime_legitimacy)
|
|
73
|
+
self.arrest_probability = None
|
|
74
|
+
|
|
75
|
+
def step(self):
|
|
76
|
+
"""
|
|
77
|
+
Decide whether to activate, then move if applicable.
|
|
78
|
+
"""
|
|
79
|
+
if self.jail_sentence:
|
|
80
|
+
self.jail_sentence -= 1
|
|
81
|
+
return # no other changes or movements if agent is in jail.
|
|
82
|
+
self.update_neighbors()
|
|
83
|
+
self.update_estimated_arrest_probability()
|
|
84
|
+
net_risk = self.risk_aversion * self.arrest_probability
|
|
85
|
+
if self.grievance - net_risk > self.threshold:
|
|
86
|
+
self.condition = "Active"
|
|
87
|
+
else:
|
|
88
|
+
self.condition = "Quiescent"
|
|
89
|
+
|
|
90
|
+
if self.model.movement and self.empty_neighbors:
|
|
91
|
+
new_cell = self.random.choice(self.empty_neighbors)
|
|
92
|
+
self.move_to(new_cell)
|
|
93
|
+
|
|
94
|
+
def update_estimated_arrest_probability(self):
|
|
95
|
+
"""
|
|
96
|
+
Based on the ratio of cops to actives in my neighborhood, estimate the
|
|
97
|
+
p(Arrest | I go active).
|
|
98
|
+
"""
|
|
99
|
+
cops_in_vision = len([c for c in self.neighbors if isinstance(c, Cop)])
|
|
100
|
+
actives_in_vision = 1.0 # citizen counts herself
|
|
101
|
+
for c in self.neighbors:
|
|
102
|
+
if (
|
|
103
|
+
isinstance(c, Citizen)
|
|
104
|
+
and c.condition == "Active"
|
|
105
|
+
and c.jail_sentence == 0
|
|
106
|
+
):
|
|
107
|
+
actives_in_vision += 1
|
|
108
|
+
self.arrest_probability = 1 - math.exp(
|
|
109
|
+
-1 * self.model.arrest_prob_constant * (cops_in_vision / actives_in_vision)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class Cop(EpsteinAgent):
|
|
114
|
+
"""
|
|
115
|
+
A cop for life. No defection.
|
|
116
|
+
Summary of rule: Inspect local vision and arrest a random active agent.
|
|
117
|
+
|
|
118
|
+
Attributes:
|
|
119
|
+
unique_id: unique int
|
|
120
|
+
x, y: Grid coordinates
|
|
121
|
+
vision: number of cells in each direction (N, S, E and W) that cop is
|
|
122
|
+
able to inspect
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def __init__(self, model, vision):
|
|
126
|
+
"""
|
|
127
|
+
Create a new Cop.
|
|
128
|
+
Args:
|
|
129
|
+
x, y: Grid coordinates
|
|
130
|
+
vision: number of cells in each direction (N, S, E and W) that
|
|
131
|
+
agent can inspect. Exogenous.
|
|
132
|
+
model: model instance
|
|
133
|
+
"""
|
|
134
|
+
super().__init__(model)
|
|
135
|
+
self.vision = vision
|
|
136
|
+
|
|
137
|
+
def step(self):
|
|
138
|
+
"""
|
|
139
|
+
Inspect local vision and arrest a random active agent. Move if
|
|
140
|
+
applicable.
|
|
141
|
+
"""
|
|
142
|
+
self.update_neighbors()
|
|
143
|
+
active_neighbors = []
|
|
144
|
+
for agent in self.neighbors:
|
|
145
|
+
if (
|
|
146
|
+
isinstance(agent, Citizen)
|
|
147
|
+
and agent.condition == "Active"
|
|
148
|
+
and agent.jail_sentence == 0
|
|
149
|
+
):
|
|
150
|
+
active_neighbors.append(agent)
|
|
151
|
+
if active_neighbors:
|
|
152
|
+
arrestee = self.random.choice(active_neighbors)
|
|
153
|
+
sentence = self.random.randint(0, self.model.max_jail_term)
|
|
154
|
+
arrestee.jail_sentence = sentence
|
|
155
|
+
arrestee.condition = "Quiescent"
|
|
156
|
+
if self.model.movement and self.empty_neighbors:
|
|
157
|
+
new_pos = self.random.choice(self.empty_neighbors)
|
|
158
|
+
self.move_to(new_pos)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import mesa
|
|
2
|
+
|
|
3
|
+
from .agent import Citizen, Cop
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class EpsteinCivilViolence(mesa.Model):
|
|
7
|
+
"""
|
|
8
|
+
Model 1 from "Modeling civil violence: An agent-based computational
|
|
9
|
+
approach," by Joshua Epstein.
|
|
10
|
+
http://www.pnas.org/content/99/suppl_3/7243.full
|
|
11
|
+
Attributes:
|
|
12
|
+
height: grid height
|
|
13
|
+
width: grid width
|
|
14
|
+
citizen_density: approximate % of cells occupied by citizens.
|
|
15
|
+
cop_density: approximate % of cells occupied by cops.
|
|
16
|
+
citizen_vision: number of cells in each direction (N, S, E and W) that
|
|
17
|
+
citizen can inspect
|
|
18
|
+
cop_vision: number of cells in each direction (N, S, E and W) that cop
|
|
19
|
+
can inspect
|
|
20
|
+
legitimacy: (L) citizens' perception of regime legitimacy, equal
|
|
21
|
+
across all citizens
|
|
22
|
+
max_jail_term: (J_max)
|
|
23
|
+
active_threshold: if (grievance - (risk_aversion * arrest_probability))
|
|
24
|
+
> threshold, citizen rebels
|
|
25
|
+
arrest_prob_constant: set to ensure agents make plausible arrest
|
|
26
|
+
probability estimates
|
|
27
|
+
movement: binary, whether agents try to move at step end
|
|
28
|
+
max_iters: model may not have a natural stopping point, so we set a
|
|
29
|
+
max.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
width=40,
|
|
35
|
+
height=40,
|
|
36
|
+
citizen_density=0.7,
|
|
37
|
+
cop_density=0.074,
|
|
38
|
+
citizen_vision=7,
|
|
39
|
+
cop_vision=7,
|
|
40
|
+
legitimacy=0.8,
|
|
41
|
+
max_jail_term=1000,
|
|
42
|
+
active_threshold=0.1,
|
|
43
|
+
arrest_prob_constant=2.3,
|
|
44
|
+
movement=True,
|
|
45
|
+
max_iters=1000,
|
|
46
|
+
):
|
|
47
|
+
super().__init__()
|
|
48
|
+
self.width = width
|
|
49
|
+
self.height = height
|
|
50
|
+
self.citizen_density = citizen_density
|
|
51
|
+
self.cop_density = cop_density
|
|
52
|
+
self.citizen_vision = citizen_vision
|
|
53
|
+
self.cop_vision = cop_vision
|
|
54
|
+
self.legitimacy = legitimacy
|
|
55
|
+
self.max_jail_term = max_jail_term
|
|
56
|
+
self.active_threshold = active_threshold
|
|
57
|
+
self.arrest_prob_constant = arrest_prob_constant
|
|
58
|
+
self.movement = movement
|
|
59
|
+
self.max_iters = max_iters
|
|
60
|
+
self.iteration = 0
|
|
61
|
+
|
|
62
|
+
self.grid = mesa.experimental.cell_space.OrthogonalMooreGrid(
|
|
63
|
+
(width, height), capacity=1, torus=True
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
model_reporters = {
|
|
67
|
+
"Quiescent": lambda m: self.count_type_citizens(m, "Quiescent"),
|
|
68
|
+
"Active": lambda m: self.count_type_citizens(m, "Active"),
|
|
69
|
+
"Jailed": self.count_jailed,
|
|
70
|
+
"Cops": self.count_cops,
|
|
71
|
+
}
|
|
72
|
+
agent_reporters = {
|
|
73
|
+
"x": lambda a: a.cell.coordinate[0],
|
|
74
|
+
"y": lambda a: a.cell.coordinate[1],
|
|
75
|
+
"breed": lambda a: type(a).__name__,
|
|
76
|
+
"jail_sentence": lambda a: getattr(a, "jail_sentence", None),
|
|
77
|
+
"condition": lambda a: getattr(a, "condition", None),
|
|
78
|
+
"arrest_probability": lambda a: getattr(a, "arrest_probability", None),
|
|
79
|
+
}
|
|
80
|
+
self.datacollector = mesa.DataCollector(
|
|
81
|
+
model_reporters=model_reporters, agent_reporters=agent_reporters
|
|
82
|
+
)
|
|
83
|
+
if self.cop_density + self.citizen_density > 1:
|
|
84
|
+
raise ValueError("Cop density + citizen density must be less than 1")
|
|
85
|
+
|
|
86
|
+
for cell in self.grid.all_cells:
|
|
87
|
+
if self.random.random() < self.cop_density:
|
|
88
|
+
cop = Cop(self, vision=self.cop_vision)
|
|
89
|
+
cop.move_to(cell)
|
|
90
|
+
|
|
91
|
+
elif self.random.random() < (self.cop_density + self.citizen_density):
|
|
92
|
+
citizen = Citizen(
|
|
93
|
+
self,
|
|
94
|
+
hardship=self.random.random(),
|
|
95
|
+
regime_legitimacy=self.legitimacy,
|
|
96
|
+
risk_aversion=self.random.random(),
|
|
97
|
+
threshold=self.active_threshold,
|
|
98
|
+
vision=self.citizen_vision,
|
|
99
|
+
)
|
|
100
|
+
citizen.move_to(cell)
|
|
101
|
+
|
|
102
|
+
self.running = True
|
|
103
|
+
self.datacollector.collect(self)
|
|
104
|
+
|
|
105
|
+
def step(self):
|
|
106
|
+
"""
|
|
107
|
+
Advance the model by one step and collect data.
|
|
108
|
+
"""
|
|
109
|
+
self.agents.shuffle_do("step")
|
|
110
|
+
# collect data
|
|
111
|
+
self.datacollector.collect(self)
|
|
112
|
+
self.iteration += 1
|
|
113
|
+
if self.iteration > self.max_iters:
|
|
114
|
+
self.running = False
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def count_type_citizens(model, condition, exclude_jailed=True):
|
|
118
|
+
"""
|
|
119
|
+
Helper method to count agents by Quiescent/Active.
|
|
120
|
+
"""
|
|
121
|
+
citizens = model.agents_by_type[Citizen]
|
|
122
|
+
|
|
123
|
+
if exclude_jailed:
|
|
124
|
+
return len(
|
|
125
|
+
[
|
|
126
|
+
c
|
|
127
|
+
for c in citizens
|
|
128
|
+
if (c.condition == condition) and (c.jail_sentence == 0)
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
else:
|
|
132
|
+
return len([c for c in citizens if c.condition == condition])
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def count_jailed(model):
|
|
136
|
+
"""
|
|
137
|
+
Helper method to count jailed agents.
|
|
138
|
+
"""
|
|
139
|
+
return len([a for a in model.agents_by_type[Citizen] if a.jail_sentence > 0])
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def count_cops(model):
|
|
143
|
+
"""
|
|
144
|
+
Helper method to count jailed agents.
|
|
145
|
+
"""
|
|
146
|
+
return len(model.agents_by_type[Cop])
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from .agent import Citizen, Cop
|
|
2
|
+
|
|
3
|
+
COP_COLOR = "#000000"
|
|
4
|
+
AGENT_QUIET_COLOR = "#0066CC"
|
|
5
|
+
AGENT_REBEL_COLOR = "#CC0000"
|
|
6
|
+
JAIL_COLOR = "#757575"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def citizen_cop_portrayal(agent):
|
|
10
|
+
if agent is None:
|
|
11
|
+
return
|
|
12
|
+
|
|
13
|
+
portrayal = {
|
|
14
|
+
"Shape": "circle",
|
|
15
|
+
"x": agent.pos[0],
|
|
16
|
+
"y": agent.pos[1],
|
|
17
|
+
"Filled": "true",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if isinstance(agent, Citizen):
|
|
21
|
+
color = (
|
|
22
|
+
AGENT_QUIET_COLOR if agent.condition == "Quiescent" else AGENT_REBEL_COLOR
|
|
23
|
+
)
|
|
24
|
+
color = JAIL_COLOR if agent.jail_sentence else color
|
|
25
|
+
portrayal["Color"] = color
|
|
26
|
+
portrayal["r"] = 0.8
|
|
27
|
+
portrayal["Layer"] = 0
|
|
28
|
+
|
|
29
|
+
elif isinstance(agent, Cop):
|
|
30
|
+
portrayal["Color"] = COP_COLOR
|
|
31
|
+
portrayal["r"] = 0.5
|
|
32
|
+
portrayal["Layer"] = 1
|
|
33
|
+
return portrayal
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import mesa
|
|
2
|
+
|
|
3
|
+
from .agent import Citizen, Cop
|
|
4
|
+
from .model import EpsteinCivilViolence
|
|
5
|
+
|
|
6
|
+
COP_COLOR = "#000000"
|
|
7
|
+
AGENT_QUIET_COLOR = "#648FFF"
|
|
8
|
+
AGENT_REBEL_COLOR = "#FE6100"
|
|
9
|
+
JAIL_COLOR = "#808080"
|
|
10
|
+
JAIL_SHAPE = "rect"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def citizen_cop_portrayal(agent):
|
|
14
|
+
if agent is None:
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
portrayal = {
|
|
18
|
+
"Shape": "circle",
|
|
19
|
+
"x": agent.pos[0],
|
|
20
|
+
"y": agent.pos[1],
|
|
21
|
+
"Filled": "true",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if type(agent) is Citizen:
|
|
25
|
+
color = (
|
|
26
|
+
AGENT_QUIET_COLOR if agent.condition == "Quiescent" else AGENT_REBEL_COLOR
|
|
27
|
+
)
|
|
28
|
+
color = JAIL_COLOR if agent.jail_sentence else color
|
|
29
|
+
shape = JAIL_SHAPE if agent.jail_sentence else "circle"
|
|
30
|
+
portrayal["Color"] = color
|
|
31
|
+
portrayal["Shape"] = shape
|
|
32
|
+
if shape == "rect":
|
|
33
|
+
portrayal["w"] = 0.9
|
|
34
|
+
portrayal["h"] = 0.9
|
|
35
|
+
else:
|
|
36
|
+
portrayal["r"] = 0.5
|
|
37
|
+
portrayal["Filled"] = "false"
|
|
38
|
+
portrayal["Layer"] = 0
|
|
39
|
+
|
|
40
|
+
elif type(agent) is Cop:
|
|
41
|
+
portrayal["Color"] = COP_COLOR
|
|
42
|
+
portrayal["r"] = 0.9
|
|
43
|
+
portrayal["Layer"] = 1
|
|
44
|
+
|
|
45
|
+
return portrayal
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
model_params = {
|
|
49
|
+
"height": 40,
|
|
50
|
+
"width": 40,
|
|
51
|
+
"citizen_density": mesa.visualization.Slider(
|
|
52
|
+
"Initial Agent Density", 0.7, 0.0, 0.9, 0.1
|
|
53
|
+
),
|
|
54
|
+
"cop_density": mesa.visualization.Slider(
|
|
55
|
+
"Initial Cop Density", 0.04, 0.0, 0.1, 0.01
|
|
56
|
+
),
|
|
57
|
+
"citizen_vision": mesa.visualization.Slider("Citizen Vision", 7, 1, 10, 1),
|
|
58
|
+
"cop_vision": mesa.visualization.Slider("Cop Vision", 7, 1, 10, 1),
|
|
59
|
+
"legitimacy": mesa.visualization.Slider(
|
|
60
|
+
"Government Legitimacy", 0.82, 0.0, 1, 0.01
|
|
61
|
+
),
|
|
62
|
+
"max_jail_term": mesa.visualization.Slider("Max Jail Term", 30, 0, 50, 1),
|
|
63
|
+
}
|
|
64
|
+
canvas_element = mesa.visualization.CanvasGrid(citizen_cop_portrayal, 40, 40, 480, 480)
|
|
65
|
+
chart = mesa.visualization.ChartModule(
|
|
66
|
+
[
|
|
67
|
+
{"Label": "Quiescent", "Color": "#648FFF"},
|
|
68
|
+
{"Label": "Active", "Color": "#FE6100"},
|
|
69
|
+
{"Label": "Jailed", "Color": "#808080"},
|
|
70
|
+
],
|
|
71
|
+
data_collector_name="datacollector",
|
|
72
|
+
)
|
|
73
|
+
server = mesa.visualization.ModularServer(
|
|
74
|
+
EpsteinCivilViolence,
|
|
75
|
+
[
|
|
76
|
+
canvas_element,
|
|
77
|
+
chart,
|
|
78
|
+
],
|
|
79
|
+
"Epstein Civil Violence",
|
|
80
|
+
model_params,
|
|
81
|
+
)
|