Mesa 3.0.0b2__py3-none-any.whl → 3.0.0rc0__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.
- mesa/__init__.py +1 -1
- mesa/batchrunner.py +26 -1
- mesa/examples/README.md +11 -11
- mesa/examples/advanced/epstein_civil_violence/agents.py +44 -38
- mesa/examples/advanced/epstein_civil_violence/app.py +29 -28
- mesa/examples/advanced/epstein_civil_violence/model.py +33 -65
- mesa/examples/advanced/pd_grid/app.py +8 -4
- mesa/examples/advanced/sugarscape_g1mt/app.py +5 -13
- mesa/examples/advanced/wolf_sheep/app.py +25 -18
- mesa/examples/basic/boid_flockers/app.py +2 -2
- mesa/examples/basic/boltzmann_wealth_model/app.py +14 -10
- mesa/examples/basic/conways_game_of_life/app.py +15 -3
- mesa/examples/basic/schelling/app.py +5 -5
- mesa/examples/basic/virus_on_network/app.py +25 -47
- mesa/space.py +0 -30
- mesa/visualization/__init__.py +16 -5
- mesa/visualization/components/__init__.py +83 -0
- mesa/visualization/components/{altair.py → altair_components.py} +34 -2
- mesa/visualization/components/matplotlib_components.py +176 -0
- mesa/visualization/mpl_space_drawing.py +558 -0
- mesa/visualization/solara_viz.py +30 -20
- {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/METADATA +1 -1
- {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/RECORD +27 -25
- mesa/visualization/components/matplotlib.py +0 -386
- {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/WHEEL +0 -0
- {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/entry_points.txt +0 -0
- {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/licenses/LICENSE +0 -0
- {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/licenses/NOTICE +0 -0
mesa/__init__.py
CHANGED
|
@@ -24,7 +24,7 @@ __all__ = [
|
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
__title__ = "mesa"
|
|
27
|
-
__version__ = "3.0.
|
|
27
|
+
__version__ = "3.0.0rc0"
|
|
28
28
|
__license__ = "Apache 2.0"
|
|
29
29
|
_this_year = datetime.datetime.now(tz=datetime.timezone.utc).date().year
|
|
30
30
|
__copyright__ = f"Copyright {_this_year} Project Mesa Team"
|
mesa/batchrunner.py
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
"""batchrunner for running a factorial experiment design over a model.
|
|
1
|
+
"""batchrunner for running a factorial experiment design over a model.
|
|
2
|
+
|
|
3
|
+
To take advantage of parallel execution of experiments, `batch_run` uses
|
|
4
|
+
multiprocessing if ``number_processes`` is larger than 1. It is strongly advised
|
|
5
|
+
to only run in parallel using a normal python file (so don't try to do it in a
|
|
6
|
+
jupyter notebook). Moreover, best practice when using multiprocessing is to
|
|
7
|
+
put the code inside an ``if __name__ == '__main__':`` code black as shown below::
|
|
8
|
+
|
|
9
|
+
from mesa.batchrunner import batch_run
|
|
10
|
+
|
|
11
|
+
params = {"width": 10, "height": 10, "N": range(10, 500, 10)}
|
|
12
|
+
|
|
13
|
+
if __name__ == '__main__':
|
|
14
|
+
results = batch_run(
|
|
15
|
+
MoneyModel,
|
|
16
|
+
parameters=params,
|
|
17
|
+
iterations=5,
|
|
18
|
+
max_steps=100,
|
|
19
|
+
number_processes=None,
|
|
20
|
+
data_collection_period=1,
|
|
21
|
+
display_progress=True,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
"""
|
|
2
27
|
|
|
3
28
|
import itertools
|
|
4
29
|
import multiprocessing
|
mesa/examples/README.md
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
# Mesa core examples
|
|
2
|
-
|
|
2
|
+
These examples are a collection of classic agent based models built using Mesa. These core examples are maintained by the Mesa team and are intended to demonstrate the capabilities of Mesa.
|
|
3
3
|
|
|
4
4
|
More user examples and showcases can be found in the [mesa-examples](https://github.com/projectmesa/mesa-examples) repository.
|
|
5
5
|
|
|
6
6
|
## Basic Examples
|
|
7
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
8
|
|
|
9
|
-
### [Boltzmann Wealth Model](basic/boltzmann_wealth_model)
|
|
9
|
+
### [Boltzmann Wealth Model](examples/basic/boltzmann_wealth_model)
|
|
10
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
11
|
|
|
12
|
-
### [Boids Flockers Model](basic/boid_flockers)
|
|
12
|
+
### [Boids Flockers Model](examples/basic/boid_flockers)
|
|
13
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
14
|
|
|
15
|
-
### [Conway's Game of Life](basic/conways_game_of_life)
|
|
15
|
+
### [Conway's Game of Life](examples/basic/conways_game_of_life)
|
|
16
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
17
|
|
|
18
|
-
### [Schelling Segregation Model](basic/schelling)
|
|
18
|
+
### [Schelling Segregation Model](examples/basic/schelling)
|
|
19
19
|
Mesa implementation of the classic [Schelling segregation](http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/) model.
|
|
20
20
|
|
|
21
|
-
### [Virus on a Network Model](basic/virus_on_network)
|
|
21
|
+
### [Virus on a Network Model](examples/basic/virus_on_network)
|
|
22
22
|
This model is based on the NetLogo [Virus on a Network](https://ccl.northwestern.edu/netlogo/models/VirusonaNetwork) model.
|
|
23
23
|
|
|
24
24
|
## Advanced Examples
|
|
25
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
26
|
|
|
27
|
-
### [Epstein Civil Violence Model](advanced/epstein_civil_violence)
|
|
28
|
-
Joshua Epstein's [model](
|
|
27
|
+
### [Epstein Civil Violence Model](examples/advanced/epstein_civil_violence)
|
|
28
|
+
Joshua Epstein's [model](https://www.pnas.org/doi/10.1073/pnas.092080199) of how a decentralized uprising can be suppressed or reach a critical mass of support.
|
|
29
29
|
|
|
30
|
-
### [Demographic Prisoner's Dilemma on a Grid](advanced/pd_grid)
|
|
30
|
+
### [Demographic Prisoner's Dilemma on a Grid](examples/advanced/pd_grid)
|
|
31
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
32
|
|
|
33
|
-
### [Sugarscape Model with Traders](advanced/sugarscape_g1mt)
|
|
33
|
+
### [Sugarscape Model with Traders](examples/advanced/sugarscape_g1mt)
|
|
34
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
35
|
|
|
36
|
-
### [Wolf-Sheep Predation Model](advanced/wolf_sheep)
|
|
36
|
+
### [Wolf-Sheep Predation Model](examples/advanced/wolf_sheep)
|
|
37
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.
|
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import math
|
|
2
|
+
from enum import Enum
|
|
2
3
|
|
|
3
4
|
import mesa
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
class CitizenState(Enum):
|
|
8
|
+
ACTIVE = 1
|
|
9
|
+
QUIET = 2
|
|
10
|
+
ARRESTED = 3
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
class EpsteinAgent(mesa.experimental.cell_space.CellAgent):
|
|
7
14
|
def update_neighbors(self):
|
|
8
15
|
"""
|
|
9
16
|
Look around and see who my neighbors are
|
|
10
17
|
"""
|
|
11
18
|
self.neighborhood = self.cell.get_neighborhood(radius=self.vision)
|
|
12
|
-
|
|
13
19
|
self.neighbors = self.neighborhood.agents
|
|
14
20
|
self.empty_neighbors = [c for c in self.neighborhood if c.is_empty]
|
|
15
21
|
|
|
22
|
+
def move(self):
|
|
23
|
+
if self.model.movement and self.empty_neighbors:
|
|
24
|
+
new_pos = self.random.choice(self.empty_neighbors)
|
|
25
|
+
self.move_to(new_pos)
|
|
26
|
+
|
|
16
27
|
|
|
17
28
|
class Citizen(EpsteinAgent):
|
|
18
29
|
"""
|
|
@@ -38,13 +49,7 @@ class Citizen(EpsteinAgent):
|
|
|
38
49
|
"""
|
|
39
50
|
|
|
40
51
|
def __init__(
|
|
41
|
-
self,
|
|
42
|
-
model,
|
|
43
|
-
hardship,
|
|
44
|
-
regime_legitimacy,
|
|
45
|
-
risk_aversion,
|
|
46
|
-
threshold,
|
|
47
|
-
vision,
|
|
52
|
+
self, model, regime_legitimacy, threshold, vision, arrest_prob_constant
|
|
48
53
|
):
|
|
49
54
|
"""
|
|
50
55
|
Create a new Citizen.
|
|
@@ -62,16 +67,21 @@ class Citizen(EpsteinAgent):
|
|
|
62
67
|
model: model instance
|
|
63
68
|
"""
|
|
64
69
|
super().__init__(model)
|
|
65
|
-
self.hardship =
|
|
70
|
+
self.hardship = self.random.random()
|
|
71
|
+
self.risk_aversion = self.random.random()
|
|
66
72
|
self.regime_legitimacy = regime_legitimacy
|
|
67
|
-
self.risk_aversion = risk_aversion
|
|
68
73
|
self.threshold = threshold
|
|
69
|
-
self.
|
|
74
|
+
self.state = CitizenState.QUIET
|
|
70
75
|
self.vision = vision
|
|
71
76
|
self.jail_sentence = 0
|
|
72
77
|
self.grievance = self.hardship * (1 - self.regime_legitimacy)
|
|
78
|
+
self.arrest_prob_constant = arrest_prob_constant
|
|
73
79
|
self.arrest_probability = None
|
|
74
80
|
|
|
81
|
+
self.neighborhood = []
|
|
82
|
+
self.neighbors = []
|
|
83
|
+
self.empty_neighbors = []
|
|
84
|
+
|
|
75
85
|
def step(self):
|
|
76
86
|
"""
|
|
77
87
|
Decide whether to activate, then move if applicable.
|
|
@@ -81,32 +91,33 @@ class Citizen(EpsteinAgent):
|
|
|
81
91
|
return # no other changes or movements if agent is in jail.
|
|
82
92
|
self.update_neighbors()
|
|
83
93
|
self.update_estimated_arrest_probability()
|
|
94
|
+
|
|
84
95
|
net_risk = self.risk_aversion * self.arrest_probability
|
|
85
|
-
if self.grievance - net_risk > self.threshold:
|
|
86
|
-
self.
|
|
96
|
+
if (self.grievance - net_risk) > self.threshold:
|
|
97
|
+
self.state = CitizenState.ACTIVE
|
|
87
98
|
else:
|
|
88
|
-
self.
|
|
99
|
+
self.state = CitizenState.QUIET
|
|
89
100
|
|
|
90
|
-
|
|
91
|
-
new_cell = self.random.choice(self.empty_neighbors)
|
|
92
|
-
self.move_to(new_cell)
|
|
101
|
+
self.move()
|
|
93
102
|
|
|
94
103
|
def update_estimated_arrest_probability(self):
|
|
95
104
|
"""
|
|
96
105
|
Based on the ratio of cops to actives in my neighborhood, estimate the
|
|
97
106
|
p(Arrest | I go active).
|
|
98
107
|
"""
|
|
99
|
-
cops_in_vision =
|
|
100
|
-
actives_in_vision = 1
|
|
101
|
-
for
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
and c.jail_sentence == 0
|
|
106
|
-
):
|
|
108
|
+
cops_in_vision = 0
|
|
109
|
+
actives_in_vision = 1 # citizen counts herself
|
|
110
|
+
for neighbor in self.neighbors:
|
|
111
|
+
if isinstance(neighbor, Cop):
|
|
112
|
+
cops_in_vision += 1
|
|
113
|
+
elif neighbor.state == CitizenState.ACTIVE:
|
|
107
114
|
actives_in_vision += 1
|
|
115
|
+
|
|
116
|
+
# there is a body of literature on this equation
|
|
117
|
+
# the round is not in the pnas paper but without it, its impossible to replicate
|
|
118
|
+
# the dynamics shown there.
|
|
108
119
|
self.arrest_probability = 1 - math.exp(
|
|
109
|
-
-1 * self.
|
|
120
|
+
-1 * self.arrest_prob_constant * round(cops_in_vision / actives_in_vision)
|
|
110
121
|
)
|
|
111
122
|
|
|
112
123
|
|
|
@@ -122,7 +133,7 @@ class Cop(EpsteinAgent):
|
|
|
122
133
|
able to inspect
|
|
123
134
|
"""
|
|
124
135
|
|
|
125
|
-
def __init__(self, model, vision):
|
|
136
|
+
def __init__(self, model, vision, max_jail_term):
|
|
126
137
|
"""
|
|
127
138
|
Create a new Cop.
|
|
128
139
|
Args:
|
|
@@ -133,6 +144,7 @@ class Cop(EpsteinAgent):
|
|
|
133
144
|
"""
|
|
134
145
|
super().__init__(model)
|
|
135
146
|
self.vision = vision
|
|
147
|
+
self.max_jail_term = max_jail_term
|
|
136
148
|
|
|
137
149
|
def step(self):
|
|
138
150
|
"""
|
|
@@ -142,17 +154,11 @@ class Cop(EpsteinAgent):
|
|
|
142
154
|
self.update_neighbors()
|
|
143
155
|
active_neighbors = []
|
|
144
156
|
for agent in self.neighbors:
|
|
145
|
-
if (
|
|
146
|
-
isinstance(agent, Citizen)
|
|
147
|
-
and agent.condition == "Active"
|
|
148
|
-
and agent.jail_sentence == 0
|
|
149
|
-
):
|
|
157
|
+
if isinstance(agent, Citizen) and agent.state == CitizenState.ACTIVE:
|
|
150
158
|
active_neighbors.append(agent)
|
|
151
159
|
if active_neighbors:
|
|
152
160
|
arrestee = self.random.choice(active_neighbors)
|
|
153
|
-
|
|
154
|
-
arrestee.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
new_pos = self.random.choice(self.empty_neighbors)
|
|
158
|
-
self.move_to(new_pos)
|
|
161
|
+
arrestee.jail_sentence = self.random.randint(0, self.max_jail_term)
|
|
162
|
+
arrestee.state = CitizenState.ARRESTED
|
|
163
|
+
|
|
164
|
+
self.move()
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
from mesa.examples.advanced.epstein_civil_violence.agents import
|
|
1
|
+
from mesa.examples.advanced.epstein_civil_violence.agents import (
|
|
2
|
+
Citizen,
|
|
3
|
+
CitizenState,
|
|
4
|
+
Cop,
|
|
5
|
+
)
|
|
2
6
|
from mesa.examples.advanced.epstein_civil_violence.model import EpsteinCivilViolence
|
|
3
7
|
from mesa.visualization import (
|
|
4
8
|
Slider,
|
|
5
9
|
SolaraViz,
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
make_plot_component,
|
|
11
|
+
make_space_component,
|
|
8
12
|
)
|
|
9
13
|
|
|
10
14
|
COP_COLOR = "#000000"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
agent_colors = {
|
|
17
|
+
CitizenState.ACTIVE: "#FE6100",
|
|
18
|
+
CitizenState.QUIET: "#648FFF",
|
|
19
|
+
CitizenState.ARRESTED: "#808080",
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
def citizen_cop_portrayal(agent):
|
|
@@ -19,34 +25,24 @@ def citizen_cop_portrayal(agent):
|
|
|
19
25
|
return
|
|
20
26
|
|
|
21
27
|
portrayal = {
|
|
22
|
-
"size":
|
|
23
|
-
"shape": "s", # square marker
|
|
28
|
+
"size": 50,
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
if isinstance(agent, Citizen):
|
|
27
|
-
color =
|
|
28
|
-
AGENT_QUIET_COLOR if agent.condition == "Quiescent" else AGENT_REBEL_COLOR
|
|
29
|
-
)
|
|
30
|
-
color = JAIL_COLOR if agent.jail_sentence else color
|
|
31
|
-
shape = JAIL_SHAPE if agent.jail_sentence else "circle"
|
|
32
|
-
portrayal["color"] = color
|
|
33
|
-
portrayal["shape"] = shape
|
|
34
|
-
if shape == "s":
|
|
35
|
-
portrayal["w"] = 0.9
|
|
36
|
-
portrayal["h"] = 0.9
|
|
37
|
-
else:
|
|
38
|
-
portrayal["r"] = 0.5
|
|
39
|
-
portrayal["filled"] = False
|
|
40
|
-
portrayal["layer"] = 0
|
|
41
|
-
|
|
32
|
+
portrayal["color"] = agent_colors[agent.state]
|
|
42
33
|
elif isinstance(agent, Cop):
|
|
43
34
|
portrayal["color"] = COP_COLOR
|
|
44
|
-
portrayal["r"] = 0.9
|
|
45
|
-
portrayal["layer"] = 1
|
|
46
35
|
|
|
47
36
|
return portrayal
|
|
48
37
|
|
|
49
38
|
|
|
39
|
+
def post_process(ax):
|
|
40
|
+
ax.set_aspect("equal")
|
|
41
|
+
ax.set_xticks([])
|
|
42
|
+
ax.set_yticks([])
|
|
43
|
+
ax.get_figure().set_size_inches(10, 10)
|
|
44
|
+
|
|
45
|
+
|
|
50
46
|
model_params = {
|
|
51
47
|
"height": 40,
|
|
52
48
|
"width": 40,
|
|
@@ -58,8 +54,13 @@ model_params = {
|
|
|
58
54
|
"max_jail_term": Slider("Max Jail Term", 30, 0, 50, 1),
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
space_component =
|
|
62
|
-
|
|
57
|
+
space_component = make_space_component(
|
|
58
|
+
citizen_cop_portrayal, post_process=post_process, draw_grid=False
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
chart_component = make_plot_component(
|
|
62
|
+
{state.name.lower(): agent_colors[state] for state in CitizenState}
|
|
63
|
+
)
|
|
63
64
|
|
|
64
65
|
epstein_model = EpsteinCivilViolence()
|
|
65
66
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import mesa
|
|
2
|
-
from mesa.examples.advanced.epstein_civil_violence.agents import
|
|
2
|
+
from mesa.examples.advanced.epstein_civil_violence.agents import (
|
|
3
|
+
Citizen,
|
|
4
|
+
CitizenState,
|
|
5
|
+
Cop,
|
|
6
|
+
)
|
|
3
7
|
|
|
4
8
|
|
|
5
9
|
class EpsteinCivilViolence(mesa.Model):
|
|
@@ -7,7 +11,8 @@ class EpsteinCivilViolence(mesa.Model):
|
|
|
7
11
|
Model 1 from "Modeling civil violence: An agent-based computational
|
|
8
12
|
approach," by Joshua Epstein.
|
|
9
13
|
http://www.pnas.org/content/99/suppl_3/7243.full
|
|
10
|
-
|
|
14
|
+
|
|
15
|
+
Args:
|
|
11
16
|
height: grid height
|
|
12
17
|
width: grid width
|
|
13
18
|
citizen_density: approximate % of cells occupied by citizens.
|
|
@@ -45,61 +50,49 @@ class EpsteinCivilViolence(mesa.Model):
|
|
|
45
50
|
seed=None,
|
|
46
51
|
):
|
|
47
52
|
super().__init__(seed=seed)
|
|
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
53
|
self.movement = movement
|
|
59
54
|
self.max_iters = max_iters
|
|
60
|
-
self.iteration = 0
|
|
61
55
|
|
|
62
|
-
self.grid = mesa.experimental.cell_space.
|
|
56
|
+
self.grid = mesa.experimental.cell_space.OrthogonalVonNeumannGrid(
|
|
63
57
|
(width, height), capacity=1, torus=True, random=self.random
|
|
64
58
|
)
|
|
65
59
|
|
|
66
60
|
model_reporters = {
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"Cops": self.count_cops,
|
|
61
|
+
"active": CitizenState.ACTIVE.name,
|
|
62
|
+
"quiet": CitizenState.QUIET.name,
|
|
63
|
+
"arrested": CitizenState.ARRESTED.name,
|
|
71
64
|
}
|
|
72
65
|
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
66
|
"jail_sentence": lambda a: getattr(a, "jail_sentence", None),
|
|
77
|
-
"condition": lambda a: getattr(a, "condition", None),
|
|
78
67
|
"arrest_probability": lambda a: getattr(a, "arrest_probability", None),
|
|
79
68
|
}
|
|
80
69
|
self.datacollector = mesa.DataCollector(
|
|
81
70
|
model_reporters=model_reporters, agent_reporters=agent_reporters
|
|
82
71
|
)
|
|
83
|
-
if
|
|
72
|
+
if cop_density + citizen_density > 1:
|
|
84
73
|
raise ValueError("Cop density + citizen density must be less than 1")
|
|
85
74
|
|
|
86
75
|
for cell in self.grid.all_cells:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
76
|
+
klass = self.random.choices(
|
|
77
|
+
[Citizen, Cop, None],
|
|
78
|
+
cum_weights=[citizen_density, citizen_density + cop_density, 1],
|
|
79
|
+
)[0]
|
|
90
80
|
|
|
91
|
-
|
|
81
|
+
if klass == Cop:
|
|
82
|
+
cop = Cop(self, vision=cop_vision, max_jail_term=max_jail_term)
|
|
83
|
+
cop.move_to(cell)
|
|
84
|
+
elif klass == Citizen:
|
|
92
85
|
citizen = Citizen(
|
|
93
86
|
self,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
vision=self.citizen_vision,
|
|
87
|
+
regime_legitimacy=legitimacy,
|
|
88
|
+
threshold=active_threshold,
|
|
89
|
+
vision=citizen_vision,
|
|
90
|
+
arrest_prob_constant=arrest_prob_constant,
|
|
99
91
|
)
|
|
100
92
|
citizen.move_to(cell)
|
|
101
93
|
|
|
102
94
|
self.running = True
|
|
95
|
+
self._update_counts()
|
|
103
96
|
self.datacollector.collect(self)
|
|
104
97
|
|
|
105
98
|
def step(self):
|
|
@@ -107,40 +100,15 @@ class EpsteinCivilViolence(mesa.Model):
|
|
|
107
100
|
Advance the model by one step and collect data.
|
|
108
101
|
"""
|
|
109
102
|
self.agents.shuffle_do("step")
|
|
110
|
-
|
|
103
|
+
self._update_counts()
|
|
111
104
|
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
105
|
|
|
123
|
-
if
|
|
124
|
-
|
|
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])
|
|
106
|
+
if self.steps > self.max_iters:
|
|
107
|
+
self.running = False
|
|
133
108
|
|
|
134
|
-
|
|
135
|
-
|
|
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])
|
|
109
|
+
def _update_counts(self):
|
|
110
|
+
"""Helper function for counting nr. of citizens in given state."""
|
|
111
|
+
counts = self.agents_by_type[Citizen].groupby("state").count()
|
|
140
112
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"""
|
|
144
|
-
Helper method to count jailed agents.
|
|
145
|
-
"""
|
|
146
|
-
return len(model.agents_by_type[Cop])
|
|
113
|
+
for state in CitizenState:
|
|
114
|
+
setattr(self, state.name, counts.get(state, 0))
|
|
@@ -3,7 +3,11 @@ Solara-based visualization for the Spatial Prisoner's Dilemma Model.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from mesa.examples.advanced.pd_grid.model import PdGrid
|
|
6
|
-
from mesa.visualization import
|
|
6
|
+
from mesa.visualization import (
|
|
7
|
+
SolaraViz,
|
|
8
|
+
make_plot_component,
|
|
9
|
+
make_space_component,
|
|
10
|
+
)
|
|
7
11
|
from mesa.visualization.UserParam import Slider
|
|
8
12
|
|
|
9
13
|
|
|
@@ -13,7 +17,7 @@ def pd_agent_portrayal(agent):
|
|
|
13
17
|
"""
|
|
14
18
|
return {
|
|
15
19
|
"color": "blue" if agent.move == "C" else "red",
|
|
16
|
-
"
|
|
20
|
+
"marker": "s", # square marker
|
|
17
21
|
"size": 25,
|
|
18
22
|
}
|
|
19
23
|
|
|
@@ -32,10 +36,10 @@ model_params = {
|
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
# Create grid visualization component using Altair
|
|
35
|
-
grid_viz =
|
|
39
|
+
grid_viz = make_space_component(agent_portrayal=pd_agent_portrayal)
|
|
36
40
|
|
|
37
41
|
# Create plot for tracking cooperating agents over time
|
|
38
|
-
plot_component =
|
|
42
|
+
plot_component = make_plot_component("Cooperating_Agents")
|
|
39
43
|
|
|
40
44
|
# Initialize model
|
|
41
45
|
initial_model = PdGrid()
|
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
import os.path
|
|
2
|
-
import sys
|
|
3
|
-
|
|
4
|
-
sys.path.insert(
|
|
5
|
-
0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../"))
|
|
6
|
-
)
|
|
7
|
-
|
|
8
|
-
|
|
9
1
|
import numpy as np
|
|
10
2
|
import solara
|
|
11
3
|
from matplotlib.figure import Figure
|
|
12
|
-
from sugarscape_g1mt.model import SugarscapeG1mt
|
|
13
|
-
from sugarscape_g1mt.trader_agents import Trader
|
|
14
4
|
|
|
15
|
-
from mesa.
|
|
5
|
+
from mesa.examples.advanced.sugarscape_g1mt.agents import Trader
|
|
6
|
+
from mesa.examples.advanced.sugarscape_g1mt.model import SugarscapeG1mt
|
|
7
|
+
from mesa.visualization import SolaraViz, make_plot_component
|
|
16
8
|
|
|
17
9
|
|
|
18
10
|
def SpaceDrawer(model):
|
|
@@ -63,8 +55,8 @@ model1 = SugarscapeG1mt(50, 50)
|
|
|
63
55
|
|
|
64
56
|
page = SolaraViz(
|
|
65
57
|
model1,
|
|
66
|
-
components=[SpaceDrawer,
|
|
58
|
+
components=[SpaceDrawer, make_plot_component(["Trader", "Price"])],
|
|
67
59
|
name="Sugarscape {G1, M, T}",
|
|
68
|
-
play_interval=
|
|
60
|
+
play_interval=150,
|
|
69
61
|
)
|
|
70
62
|
page # noqa
|
|
@@ -3,13 +3,10 @@ from mesa.examples.advanced.wolf_sheep.model import WolfSheep
|
|
|
3
3
|
from mesa.visualization import (
|
|
4
4
|
Slider,
|
|
5
5
|
SolaraViz,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
make_plot_component,
|
|
7
|
+
make_space_component,
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
WOLF_COLOR = "#000000"
|
|
11
|
-
SHEEP_COLOR = "#648FFF"
|
|
12
|
-
|
|
13
10
|
|
|
14
11
|
def wolf_sheep_portrayal(agent):
|
|
15
12
|
if agent is None:
|
|
@@ -17,23 +14,23 @@ def wolf_sheep_portrayal(agent):
|
|
|
17
14
|
|
|
18
15
|
portrayal = {
|
|
19
16
|
"size": 25,
|
|
20
|
-
"shape": "s", # square marker
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
if isinstance(agent, Wolf):
|
|
24
|
-
portrayal["color"] =
|
|
25
|
-
portrayal["
|
|
20
|
+
portrayal["color"] = "tab:red"
|
|
21
|
+
portrayal["marker"] = "o"
|
|
22
|
+
portrayal["zorder"] = 2
|
|
26
23
|
elif isinstance(agent, Sheep):
|
|
27
|
-
portrayal["color"] =
|
|
28
|
-
portrayal["
|
|
24
|
+
portrayal["color"] = "tab:cyan"
|
|
25
|
+
portrayal["marker"] = "o"
|
|
26
|
+
portrayal["zorder"] = 2
|
|
29
27
|
elif isinstance(agent, GrassPatch):
|
|
30
28
|
if agent.fully_grown:
|
|
31
|
-
portrayal["color"] = "
|
|
29
|
+
portrayal["color"] = "tab:green"
|
|
32
30
|
else:
|
|
33
|
-
portrayal["color"] = "
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
portrayal["Layer"] = 1
|
|
31
|
+
portrayal["color"] = "tab:brown"
|
|
32
|
+
portrayal["marker"] = "s"
|
|
33
|
+
portrayal["size"] = 75
|
|
37
34
|
|
|
38
35
|
return portrayal
|
|
39
36
|
|
|
@@ -62,10 +59,20 @@ model_params = {
|
|
|
62
59
|
}
|
|
63
60
|
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
def post_process(ax):
|
|
63
|
+
ax.set_aspect("equal")
|
|
64
|
+
ax.set_xticks([])
|
|
65
|
+
ax.set_yticks([])
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
space_component = make_space_component(
|
|
69
|
+
wolf_sheep_portrayal, draw_grid=False, post_process=post_process
|
|
70
|
+
)
|
|
71
|
+
lineplot_component = make_plot_component(
|
|
72
|
+
{"Wolves": "tab:orange", "Sheep": "tab:cyan", "Grass": "tab:green"}
|
|
73
|
+
)
|
|
67
74
|
|
|
68
|
-
model = WolfSheep()
|
|
75
|
+
model = WolfSheep(grass=True)
|
|
69
76
|
|
|
70
77
|
|
|
71
78
|
page = SolaraViz(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from mesa.examples.basic.boid_flockers.model import BoidFlockers
|
|
2
|
-
from mesa.visualization import Slider, SolaraViz,
|
|
2
|
+
from mesa.visualization import Slider, SolaraViz, make_space_component
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def boid_draw(agent):
|
|
@@ -51,7 +51,7 @@ model = BoidFlockers()
|
|
|
51
51
|
|
|
52
52
|
page = SolaraViz(
|
|
53
53
|
model,
|
|
54
|
-
[
|
|
54
|
+
[make_space_component(agent_portrayal=boid_draw, backend="matplotlib")],
|
|
55
55
|
model_params=model_params,
|
|
56
56
|
name="Boid Flocking Model",
|
|
57
57
|
)
|