Mesa 3.0.3__py3-none-any.whl → 3.1.0__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 +4 -6
- mesa/agent.py +48 -25
- mesa/batchrunner.py +14 -1
- mesa/datacollection.py +1 -6
- mesa/examples/__init__.py +2 -2
- mesa/examples/advanced/epstein_civil_violence/app.py +5 -0
- mesa/examples/advanced/pd_grid/app.py +5 -0
- mesa/examples/advanced/sugarscape_g1mt/app.py +7 -2
- mesa/examples/basic/boid_flockers/app.py +5 -0
- mesa/examples/basic/boltzmann_wealth_model/app.py +8 -5
- mesa/examples/basic/boltzmann_wealth_model/st_app.py +1 -1
- mesa/examples/basic/conways_game_of_life/app.py +5 -0
- mesa/examples/basic/conways_game_of_life/st_app.py +2 -2
- mesa/examples/basic/schelling/app.py +5 -0
- mesa/examples/basic/virus_on_network/app.py +5 -0
- mesa/experimental/__init__.py +17 -10
- mesa/experimental/cell_space/__init__.py +19 -7
- mesa/experimental/cell_space/cell.py +22 -37
- mesa/experimental/cell_space/cell_agent.py +12 -1
- mesa/experimental/cell_space/cell_collection.py +14 -1
- mesa/experimental/cell_space/discrete_space.py +15 -64
- mesa/experimental/cell_space/grid.py +74 -4
- mesa/experimental/cell_space/network.py +13 -1
- mesa/experimental/cell_space/property_layer.py +444 -0
- mesa/experimental/cell_space/voronoi.py +13 -1
- mesa/experimental/devs/__init__.py +20 -2
- mesa/experimental/devs/eventlist.py +19 -1
- mesa/experimental/devs/simulator.py +24 -8
- mesa/experimental/mesa_signals/__init__.py +23 -0
- mesa/experimental/mesa_signals/mesa_signal.py +485 -0
- mesa/experimental/mesa_signals/observable_collections.py +133 -0
- mesa/experimental/mesa_signals/signals_util.py +52 -0
- mesa/mesa_logging.py +190 -0
- mesa/model.py +17 -74
- mesa/visualization/__init__.py +2 -2
- mesa/visualization/mpl_space_drawing.py +2 -2
- mesa/visualization/solara_viz.py +12 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/METADATA +3 -4
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/RECORD +43 -44
- mesa/experimental/UserParam.py +0 -67
- mesa/experimental/components/altair.py +0 -81
- mesa/experimental/components/matplotlib.py +0 -242
- mesa/experimental/devs/examples/epstein_civil_violence.py +0 -305
- mesa/experimental/devs/examples/wolf_sheep.py +0 -250
- mesa/experimental/solara_viz.py +0 -453
- mesa/time.py +0 -391
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/WHEEL +0 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/entry_points.txt +0 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/licenses/LICENSE +0 -0
- {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
"""Epstein civil violence example using ABMSimulator."""
|
|
2
|
-
|
|
3
|
-
import enum
|
|
4
|
-
import math
|
|
5
|
-
|
|
6
|
-
from mesa import Agent, Model
|
|
7
|
-
from mesa.experimental.devs.simulator import ABMSimulator
|
|
8
|
-
from mesa.space import SingleGrid
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class EpsteinAgent(Agent):
|
|
12
|
-
"""Epstein Agent."""
|
|
13
|
-
|
|
14
|
-
def __init__(self, model, vision, movement):
|
|
15
|
-
"""Initialize the agent.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
model: a model instance
|
|
19
|
-
vision: size of neighborhood
|
|
20
|
-
movement: boolean whether agent can move or not
|
|
21
|
-
"""
|
|
22
|
-
super().__init__(model)
|
|
23
|
-
self.vision = vision
|
|
24
|
-
self.movement = movement
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class AgentState(enum.IntEnum):
|
|
28
|
-
"""Agent states."""
|
|
29
|
-
|
|
30
|
-
QUIESCENT = enum.auto()
|
|
31
|
-
ARRESTED = enum.auto()
|
|
32
|
-
ACTIVE = enum.auto()
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class Citizen(EpsteinAgent):
|
|
36
|
-
"""A member of the general population, may or may not be in active rebellion.
|
|
37
|
-
|
|
38
|
-
Summary of rule: If grievance - risk > threshold, rebel.
|
|
39
|
-
|
|
40
|
-
Attributes:
|
|
41
|
-
unique_id: unique int
|
|
42
|
-
model :
|
|
43
|
-
hardship: Agent's 'perceived hardship (i.e., physical or economic
|
|
44
|
-
privation).' Exogenous, drawn from U(0,1).
|
|
45
|
-
regime_legitimacy: Agent's perception of regime legitimacy, equal
|
|
46
|
-
across agents. Exogenous.
|
|
47
|
-
risk_aversion: Exogenous, drawn from U(0,1).
|
|
48
|
-
threshold: if (grievance - (risk_aversion * arrest_probability)) >
|
|
49
|
-
threshold, go/remain Active
|
|
50
|
-
vision: number of cells in each direction (N, S, E and W) that agent
|
|
51
|
-
can inspect
|
|
52
|
-
condition: Can be "Quiescent" or "Active;" deterministic function of
|
|
53
|
-
greivance, perceived risk, and
|
|
54
|
-
grievance: deterministic function of hardship and regime_legitimacy;
|
|
55
|
-
how aggrieved is agent at the regime?
|
|
56
|
-
arrest_probability: agent's assessment of arrest probability, given
|
|
57
|
-
rebellion
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
|
-
def __init__(
|
|
61
|
-
self,
|
|
62
|
-
model,
|
|
63
|
-
vision,
|
|
64
|
-
movement,
|
|
65
|
-
hardship,
|
|
66
|
-
regime_legitimacy,
|
|
67
|
-
risk_aversion,
|
|
68
|
-
threshold,
|
|
69
|
-
arrest_prob_constant,
|
|
70
|
-
):
|
|
71
|
-
"""Create a new Citizen.
|
|
72
|
-
|
|
73
|
-
Args:
|
|
74
|
-
model : model instance
|
|
75
|
-
vision: number of cells in each direction (N, S, E and W) that
|
|
76
|
-
agent can inspect. Exogenous.
|
|
77
|
-
movement: whether agent can move or not
|
|
78
|
-
hardship: Agent's 'perceived hardship (i.e., physical or economic
|
|
79
|
-
privation).' Exogenous, drawn from U(0,1).
|
|
80
|
-
regime_legitimacy: Agent's perception of regime legitimacy, equal
|
|
81
|
-
across agents. Exogenous.
|
|
82
|
-
risk_aversion: Exogenous, drawn from U(0,1).
|
|
83
|
-
threshold: if (grievance - (risk_aversion * arrest_probability)) >
|
|
84
|
-
threshold, go/remain Active
|
|
85
|
-
arrest_prob_constant : agent's assessment of arrest probability
|
|
86
|
-
|
|
87
|
-
"""
|
|
88
|
-
super().__init__(model, vision, movement)
|
|
89
|
-
self.hardship = hardship
|
|
90
|
-
self.regime_legitimacy = regime_legitimacy
|
|
91
|
-
self.risk_aversion = risk_aversion
|
|
92
|
-
self.threshold = threshold
|
|
93
|
-
self.condition = AgentState.QUIESCENT
|
|
94
|
-
self.grievance = self.hardship * (1 - self.regime_legitimacy)
|
|
95
|
-
self.arrest_probability = None
|
|
96
|
-
self.arrest_prob_constant = arrest_prob_constant
|
|
97
|
-
|
|
98
|
-
def step(self):
|
|
99
|
-
"""Decide whether to activate, then move if applicable."""
|
|
100
|
-
self.update_neighbors()
|
|
101
|
-
self.update_estimated_arrest_probability()
|
|
102
|
-
net_risk = self.risk_aversion * self.arrest_probability
|
|
103
|
-
if self.grievance - net_risk > self.threshold:
|
|
104
|
-
self.condition = AgentState.ACTIVE
|
|
105
|
-
else:
|
|
106
|
-
self.condition = AgentState.QUIESCENT
|
|
107
|
-
if self.movement and self.empty_neighbors:
|
|
108
|
-
new_pos = self.random.choice(self.empty_neighbors)
|
|
109
|
-
self.model.grid.move_agent(self, new_pos)
|
|
110
|
-
|
|
111
|
-
def update_neighbors(self):
|
|
112
|
-
"""Look around and see who my neighbors are."""
|
|
113
|
-
self.neighborhood = self.model.grid.get_neighborhood(
|
|
114
|
-
self.pos, moore=True, radius=self.vision
|
|
115
|
-
)
|
|
116
|
-
self.neighbors = self.model.grid.get_cell_list_contents(self.neighborhood)
|
|
117
|
-
self.empty_neighbors = [
|
|
118
|
-
c for c in self.neighborhood if self.model.grid.is_cell_empty(c)
|
|
119
|
-
]
|
|
120
|
-
|
|
121
|
-
def update_estimated_arrest_probability(self):
|
|
122
|
-
"""Based on the ratio of cops to actives in my neighborhood, estimate the p(Arrest | I go active)."""
|
|
123
|
-
cops_in_vision = len([c for c in self.neighbors if isinstance(c, Cop)])
|
|
124
|
-
actives_in_vision = 1.0 # citizen counts herself
|
|
125
|
-
for c in self.neighbors:
|
|
126
|
-
if isinstance(c, Citizen) and c.condition == AgentState.ACTIVE:
|
|
127
|
-
actives_in_vision += 1
|
|
128
|
-
self.arrest_probability = 1 - math.exp(
|
|
129
|
-
-1 * self.arrest_prob_constant * (cops_in_vision / actives_in_vision)
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
def sent_to_jail(self, value):
|
|
133
|
-
"""Sent agent to jail.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
value: duration of jail sentence
|
|
137
|
-
|
|
138
|
-
"""
|
|
139
|
-
self.model.active_agents.remove(self)
|
|
140
|
-
self.condition = AgentState.ARRESTED
|
|
141
|
-
self.model.simulator.schedule_event_relative(self.release_from_jail, value)
|
|
142
|
-
|
|
143
|
-
def release_from_jail(self):
|
|
144
|
-
"""Release agent from jail."""
|
|
145
|
-
self.model.active_agents.add(self)
|
|
146
|
-
self.condition = AgentState.QUIESCENT
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
class Cop(EpsteinAgent):
|
|
150
|
-
"""A cop for life. No defection.
|
|
151
|
-
|
|
152
|
-
Summary of rule: Inspect local vision and arrest a random active agent.
|
|
153
|
-
|
|
154
|
-
Attributes:
|
|
155
|
-
unique_id: unique int
|
|
156
|
-
x, y: Grid coordinates
|
|
157
|
-
vision: number of cells in each direction (N, S, E and W) that cop is
|
|
158
|
-
able to inspect
|
|
159
|
-
"""
|
|
160
|
-
|
|
161
|
-
def __init__(self, model, vision, movement, max_jail_term):
|
|
162
|
-
"""Initialize a Cop agent.
|
|
163
|
-
|
|
164
|
-
Args:
|
|
165
|
-
model: a model instance
|
|
166
|
-
vision: size of neighborhood
|
|
167
|
-
movement: whether agent can move or not
|
|
168
|
-
max_jail_term: maximum jail sentence
|
|
169
|
-
"""
|
|
170
|
-
super().__init__(model, vision, movement)
|
|
171
|
-
self.max_jail_term = max_jail_term
|
|
172
|
-
|
|
173
|
-
def step(self):
|
|
174
|
-
"""Inspect local vision and arrest a random active agent. Move if applicable."""
|
|
175
|
-
self.update_neighbors()
|
|
176
|
-
active_neighbors = []
|
|
177
|
-
for agent in self.neighbors:
|
|
178
|
-
if isinstance(agent, Citizen) and agent.condition == "Active":
|
|
179
|
-
active_neighbors.append(agent)
|
|
180
|
-
if active_neighbors:
|
|
181
|
-
arrestee = self.random.choice(active_neighbors)
|
|
182
|
-
arrestee.sent_to_jail(self.random.randint(0, self.max_jail_term))
|
|
183
|
-
if self.movement and self.empty_neighbors:
|
|
184
|
-
new_pos = self.random.choice(self.empty_neighbors)
|
|
185
|
-
self.model.grid.move_agent(self, new_pos)
|
|
186
|
-
|
|
187
|
-
def update_neighbors(self):
|
|
188
|
-
"""Look around and see who my neighbors are."""
|
|
189
|
-
self.neighborhood = self.model.grid.get_neighborhood(
|
|
190
|
-
self.pos, moore=True, radius=self.vision
|
|
191
|
-
)
|
|
192
|
-
self.neighbors = self.model.grid.get_cell_list_contents(self.neighborhood)
|
|
193
|
-
self.empty_neighbors = [
|
|
194
|
-
c for c in self.neighborhood if self.model.grid.is_cell_empty(c)
|
|
195
|
-
]
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
class EpsteinCivilViolence(Model):
|
|
199
|
-
"""Model 1 from "Modeling civil violence: An agent-based computational approach," by Joshua Epstein.
|
|
200
|
-
|
|
201
|
-
http://www.pnas.org/content/99/suppl_3/7243.full
|
|
202
|
-
Attributes:
|
|
203
|
-
height: grid height
|
|
204
|
-
width: grid width
|
|
205
|
-
citizen_density: approximate % of cells occupied by citizens.
|
|
206
|
-
cop_density: approximate % of cells occupied by cops.
|
|
207
|
-
citizen_vision: number of cells in each direction (N, S, E and W) that
|
|
208
|
-
citizen can inspect
|
|
209
|
-
cop_vision: number of cells in each direction (N, S, E and W) that cop
|
|
210
|
-
can inspect
|
|
211
|
-
legitimacy: (L) citizens' perception of regime legitimacy, equal
|
|
212
|
-
across all citizens
|
|
213
|
-
max_jail_term: (J_max)
|
|
214
|
-
active_threshold: if (grievance - (risk_aversion * arrest_probability))
|
|
215
|
-
> threshold, citizen rebels
|
|
216
|
-
arrest_prob_constant: set to ensure agents make plausible arrest
|
|
217
|
-
probability estimates
|
|
218
|
-
movement: binary, whether agents try to move at step end
|
|
219
|
-
max_iters: model may not have a natural stopping point, so we set a
|
|
220
|
-
max.
|
|
221
|
-
"""
|
|
222
|
-
|
|
223
|
-
def __init__(
|
|
224
|
-
self,
|
|
225
|
-
width=40,
|
|
226
|
-
height=40,
|
|
227
|
-
citizen_density=0.7,
|
|
228
|
-
cop_density=0.074,
|
|
229
|
-
citizen_vision=7,
|
|
230
|
-
cop_vision=7,
|
|
231
|
-
legitimacy=0.8,
|
|
232
|
-
max_jail_term=1000,
|
|
233
|
-
active_threshold=0.1,
|
|
234
|
-
arrest_prob_constant=2.3,
|
|
235
|
-
movement=True,
|
|
236
|
-
max_iters=1000,
|
|
237
|
-
seed=None,
|
|
238
|
-
):
|
|
239
|
-
"""Initialize the Eppstein civil violence model.
|
|
240
|
-
|
|
241
|
-
Args:
|
|
242
|
-
width: the width of the grid
|
|
243
|
-
height: the height of the grid
|
|
244
|
-
citizen_density: density of citizens
|
|
245
|
-
cop_density: density of cops
|
|
246
|
-
citizen_vision: size of citizen vision
|
|
247
|
-
cop_vision: size of cop vision
|
|
248
|
-
legitimacy: perceived legitimacy
|
|
249
|
-
max_jail_term: maximum jail term
|
|
250
|
-
active_threshold: threshold for citizen to become active
|
|
251
|
-
arrest_prob_constant: arrest probability
|
|
252
|
-
movement: allow agent movement or not
|
|
253
|
-
max_iters: number of iterations
|
|
254
|
-
seed: seed for random number generator
|
|
255
|
-
"""
|
|
256
|
-
super().__init__(seed)
|
|
257
|
-
if cop_density + citizen_density > 1:
|
|
258
|
-
raise ValueError("Cop density + citizen density must be less than 1")
|
|
259
|
-
|
|
260
|
-
self.width = width
|
|
261
|
-
self.height = height
|
|
262
|
-
self.citizen_density = citizen_density
|
|
263
|
-
self.cop_density = cop_density
|
|
264
|
-
|
|
265
|
-
self.max_iters = max_iters
|
|
266
|
-
|
|
267
|
-
self.grid = SingleGrid(self.width, self.height, torus=True)
|
|
268
|
-
|
|
269
|
-
for _, pos in self.grid.coord_iter():
|
|
270
|
-
if self.random.random() < self.cop_density:
|
|
271
|
-
agent = Cop(
|
|
272
|
-
self,
|
|
273
|
-
cop_vision,
|
|
274
|
-
movement,
|
|
275
|
-
max_jail_term,
|
|
276
|
-
)
|
|
277
|
-
elif self.random.random() < (self.cop_density + self.citizen_density):
|
|
278
|
-
agent = Citizen(
|
|
279
|
-
self,
|
|
280
|
-
citizen_vision,
|
|
281
|
-
movement,
|
|
282
|
-
hardship=self.random.random(),
|
|
283
|
-
regime_legitimacy=legitimacy,
|
|
284
|
-
risk_aversion=self.random.random(),
|
|
285
|
-
threshold=active_threshold,
|
|
286
|
-
arrest_prob_constant=arrest_prob_constant,
|
|
287
|
-
)
|
|
288
|
-
else:
|
|
289
|
-
continue
|
|
290
|
-
self.grid.place_agent(agent, pos)
|
|
291
|
-
|
|
292
|
-
self.active_agents = self.agents
|
|
293
|
-
|
|
294
|
-
def step(self):
|
|
295
|
-
"""Run one step of the model."""
|
|
296
|
-
self.active_agents.shuffle_do("step")
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if __name__ == "__main__":
|
|
300
|
-
model = EpsteinCivilViolence(seed=15)
|
|
301
|
-
simulator = ABMSimulator()
|
|
302
|
-
|
|
303
|
-
simulator.setup(model)
|
|
304
|
-
|
|
305
|
-
simulator.run_for(time_delta=100)
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
"""Example of using ABM simulator for Wolf-Sheep Predation Model."""
|
|
2
|
-
|
|
3
|
-
import mesa
|
|
4
|
-
from mesa.experimental.cell_space import FixedAgent
|
|
5
|
-
from mesa.experimental.devs.simulator import ABMSimulator
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Animal(mesa.Agent):
|
|
9
|
-
"""Base Animal class."""
|
|
10
|
-
|
|
11
|
-
def __init__(self, model, moore, energy, p_reproduce, energy_from_food):
|
|
12
|
-
"""Initialize Animal instance.
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
model: a model instance
|
|
16
|
-
moore: using moore grid or not
|
|
17
|
-
energy: initial energy
|
|
18
|
-
p_reproduce: probability of reproduction
|
|
19
|
-
energy_from_food: energy gained from 1 unit of food
|
|
20
|
-
"""
|
|
21
|
-
super().__init__(model)
|
|
22
|
-
self.energy = energy
|
|
23
|
-
self.p_reproduce = p_reproduce
|
|
24
|
-
self.energy_from_food = energy_from_food
|
|
25
|
-
self.moore = moore
|
|
26
|
-
|
|
27
|
-
def random_move(self):
|
|
28
|
-
"""Move to random neighboring cell."""
|
|
29
|
-
next_moves = self.model.grid.get_neighborhood(self.pos, self.moore, True)
|
|
30
|
-
next_move = self.random.choice(next_moves)
|
|
31
|
-
# Now move:
|
|
32
|
-
self.model.grid.move_agent(self, next_move)
|
|
33
|
-
|
|
34
|
-
def spawn_offspring(self):
|
|
35
|
-
"""Create offspring."""
|
|
36
|
-
self.energy /= 2
|
|
37
|
-
offspring = self.__class__(
|
|
38
|
-
self.model,
|
|
39
|
-
self.moore,
|
|
40
|
-
self.energy,
|
|
41
|
-
self.p_reproduce,
|
|
42
|
-
self.energy_from_food,
|
|
43
|
-
)
|
|
44
|
-
self.model.grid.place_agent(offspring, self.pos)
|
|
45
|
-
|
|
46
|
-
def feed(self): ... # noqa: D102
|
|
47
|
-
|
|
48
|
-
def die(self):
|
|
49
|
-
"""Die."""
|
|
50
|
-
self.model.grid.remove_agent(self)
|
|
51
|
-
self.remove()
|
|
52
|
-
|
|
53
|
-
def step(self):
|
|
54
|
-
"""Execute one step of the agent."""
|
|
55
|
-
self.random_move()
|
|
56
|
-
self.energy -= 1
|
|
57
|
-
|
|
58
|
-
self.feed()
|
|
59
|
-
|
|
60
|
-
if self.energy < 0:
|
|
61
|
-
self.die()
|
|
62
|
-
elif self.random.random() < self.p_reproduce:
|
|
63
|
-
self.spawn_offspring()
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class Sheep(Animal):
|
|
67
|
-
"""A sheep that walks around, reproduces (asexually) and gets eaten."""
|
|
68
|
-
|
|
69
|
-
def feed(self):
|
|
70
|
-
"""Eat grass and gain energy."""
|
|
71
|
-
# If there is grass available, eat it
|
|
72
|
-
agents = self.model.grid.get_cell_list_contents(self.pos)
|
|
73
|
-
grass_patch = next(obj for obj in agents if isinstance(obj, GrassPatch))
|
|
74
|
-
if grass_patch.fully_grown:
|
|
75
|
-
self.energy += self.energy_from_food
|
|
76
|
-
grass_patch.fully_grown = False
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class Wolf(Animal):
|
|
80
|
-
"""A wolf that walks around, reproduces (asexually) and eats sheep."""
|
|
81
|
-
|
|
82
|
-
def feed(self):
|
|
83
|
-
"""Eat wolf and gain energy."""
|
|
84
|
-
agents = self.model.grid.get_cell_list_contents(self.pos)
|
|
85
|
-
sheep = [obj for obj in agents if isinstance(obj, Sheep)]
|
|
86
|
-
if len(sheep) > 0:
|
|
87
|
-
sheep_to_eat = self.random.choice(sheep)
|
|
88
|
-
self.energy += self.energy
|
|
89
|
-
|
|
90
|
-
# Kill the sheep
|
|
91
|
-
sheep_to_eat.die()
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class GrassPatch(FixedAgent):
|
|
95
|
-
"""A patch of grass that grows at a fixed rate and it is eaten by sheep."""
|
|
96
|
-
|
|
97
|
-
@property
|
|
98
|
-
def fully_grown(self) -> bool: # noqa: D102
|
|
99
|
-
return self._fully_grown
|
|
100
|
-
|
|
101
|
-
@fully_grown.setter
|
|
102
|
-
def fully_grown(self, value: bool):
|
|
103
|
-
self._fully_grown = value
|
|
104
|
-
|
|
105
|
-
if not value:
|
|
106
|
-
self.model.simulator.schedule_event_relative(
|
|
107
|
-
setattr,
|
|
108
|
-
self.grass_regrowth_time,
|
|
109
|
-
function_args=[self, "fully_grown", True],
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
def __init__(self, model, fully_grown, countdown, grass_regrowth_time):
|
|
113
|
-
"""Creates a new patch of grass.
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
model: a model instance
|
|
117
|
-
fully_grown: (boolean) Whether the patch of grass is fully grown or not
|
|
118
|
-
countdown: Time for the patch of grass to be fully grown again
|
|
119
|
-
grass_regrowth_time: regrowth time for the grass
|
|
120
|
-
"""
|
|
121
|
-
super().__init__(model)
|
|
122
|
-
self._fully_grown = fully_grown
|
|
123
|
-
self.grass_regrowth_time = grass_regrowth_time
|
|
124
|
-
|
|
125
|
-
if not self.fully_grown:
|
|
126
|
-
self.model.simulator.schedule_event_relative(
|
|
127
|
-
setattr, countdown, function_args=[self, "fully_grown", True]
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
def set_fully_grown(self): # noqa
|
|
131
|
-
self.fully_grown = True
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
class WolfSheep(mesa.Model):
|
|
135
|
-
"""Wolf-Sheep Predation Model.
|
|
136
|
-
|
|
137
|
-
A model for simulating wolf and sheep (predator-prey) ecosystem modelling.
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
def __init__(
|
|
141
|
-
self,
|
|
142
|
-
height,
|
|
143
|
-
width,
|
|
144
|
-
initial_sheep,
|
|
145
|
-
initial_wolves,
|
|
146
|
-
sheep_reproduce,
|
|
147
|
-
wolf_reproduce,
|
|
148
|
-
grass_regrowth_time,
|
|
149
|
-
wolf_gain_from_food=13,
|
|
150
|
-
sheep_gain_from_food=5,
|
|
151
|
-
moore=False,
|
|
152
|
-
simulator=None,
|
|
153
|
-
seed=None,
|
|
154
|
-
):
|
|
155
|
-
"""Create a new Wolf-Sheep model with the given parameters.
|
|
156
|
-
|
|
157
|
-
Args:
|
|
158
|
-
height: height of the grid
|
|
159
|
-
width: width of the grid
|
|
160
|
-
initial_sheep: Number of sheep to start with
|
|
161
|
-
initial_wolves: Number of wolves to start with
|
|
162
|
-
sheep_reproduce: Probability of each sheep reproducing each step
|
|
163
|
-
wolf_reproduce: Probability of each wolf reproducing each step
|
|
164
|
-
wolf_gain_from_food: Energy a wolf gains from eating a sheep
|
|
165
|
-
grass: Whether to have the sheep eat grass for energy
|
|
166
|
-
grass_regrowth_time: How long it takes for a grass patch to regrow
|
|
167
|
-
once it is eaten
|
|
168
|
-
sheep_gain_from_food: Energy sheep gain from grass, if enabled.
|
|
169
|
-
moore: whether to use moore or von Neumann grid
|
|
170
|
-
simulator: Simulator to use for simulating wolf and sheep
|
|
171
|
-
seed: Random seed
|
|
172
|
-
"""
|
|
173
|
-
super().__init__(seed=seed)
|
|
174
|
-
# Set parameters
|
|
175
|
-
self.height = height
|
|
176
|
-
self.width = width
|
|
177
|
-
self.initial_sheep = initial_sheep
|
|
178
|
-
self.initial_wolves = initial_wolves
|
|
179
|
-
self.simulator = simulator
|
|
180
|
-
|
|
181
|
-
# self.sheep_reproduce = sheep_reproduce
|
|
182
|
-
# self.wolf_reproduce = wolf_reproduce
|
|
183
|
-
# self.grass_regrowth_time = grass_regrowth_time
|
|
184
|
-
# self.wolf_gain_from_food = wolf_gain_from_food
|
|
185
|
-
# self.sheep_gain_from_food = sheep_gain_from_food
|
|
186
|
-
# self.moore = moore
|
|
187
|
-
|
|
188
|
-
self.grid = mesa.space.MultiGrid(self.height, self.width, torus=False)
|
|
189
|
-
|
|
190
|
-
for _ in range(self.initial_sheep):
|
|
191
|
-
pos = (
|
|
192
|
-
self.random.randrange(self.width),
|
|
193
|
-
self.random.randrange(self.height),
|
|
194
|
-
)
|
|
195
|
-
energy = self.random.randrange(2 * sheep_gain_from_food)
|
|
196
|
-
sheep = Sheep(
|
|
197
|
-
self,
|
|
198
|
-
moore,
|
|
199
|
-
energy,
|
|
200
|
-
sheep_reproduce,
|
|
201
|
-
sheep_gain_from_food,
|
|
202
|
-
)
|
|
203
|
-
self.grid.place_agent(sheep, pos)
|
|
204
|
-
|
|
205
|
-
# Create wolves
|
|
206
|
-
for _ in range(self.initial_wolves):
|
|
207
|
-
pos = (
|
|
208
|
-
self.random.randrange(self.width),
|
|
209
|
-
self.random.randrange(self.height),
|
|
210
|
-
)
|
|
211
|
-
energy = self.random.randrange(2 * wolf_gain_from_food)
|
|
212
|
-
wolf = Wolf(
|
|
213
|
-
self,
|
|
214
|
-
moore,
|
|
215
|
-
energy,
|
|
216
|
-
wolf_reproduce,
|
|
217
|
-
wolf_gain_from_food,
|
|
218
|
-
)
|
|
219
|
-
self.grid.place_agent(wolf, pos)
|
|
220
|
-
|
|
221
|
-
# Create grass patches
|
|
222
|
-
possibly_fully_grown = [True, False]
|
|
223
|
-
for _agent, pos in self.grid.coord_iter():
|
|
224
|
-
fully_grown = self.random.choice(possibly_fully_grown)
|
|
225
|
-
if fully_grown:
|
|
226
|
-
countdown = grass_regrowth_time
|
|
227
|
-
else:
|
|
228
|
-
countdown = self.random.randrange(grass_regrowth_time)
|
|
229
|
-
patch = GrassPatch(self, fully_grown, countdown, grass_regrowth_time)
|
|
230
|
-
self.grid.place_agent(patch, pos)
|
|
231
|
-
|
|
232
|
-
def step(self):
|
|
233
|
-
"""Perform one step of the model."""
|
|
234
|
-
self.agents_by_type[Sheep].shuffle_do("step")
|
|
235
|
-
self.agents_by_type[Wolf].shuffle_do("step")
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if __name__ == "__main__":
|
|
239
|
-
import time
|
|
240
|
-
|
|
241
|
-
simulator = ABMSimulator()
|
|
242
|
-
|
|
243
|
-
model = WolfSheep(25, 25, 60, 40, 0.2, 0.1, 20, simulator=simulator, seed=15)
|
|
244
|
-
|
|
245
|
-
simulator.setup(model)
|
|
246
|
-
|
|
247
|
-
start_time = time.perf_counter()
|
|
248
|
-
simulator.run(100)
|
|
249
|
-
print(simulator.time)
|
|
250
|
-
print("Time:", time.perf_counter() - start_time)
|