Mesa 3.0.0a4__py3-none-any.whl → 3.0.0b0__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.

Files changed (41) hide show
  1. mesa/__init__.py +2 -3
  2. mesa/agent.py +116 -85
  3. mesa/batchrunner.py +22 -23
  4. mesa/cookiecutter-mesa/hooks/post_gen_project.py +2 -0
  5. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +1 -0
  6. mesa/datacollection.py +138 -27
  7. mesa/experimental/UserParam.py +17 -6
  8. mesa/experimental/__init__.py +2 -0
  9. mesa/experimental/cell_space/__init__.py +14 -1
  10. mesa/experimental/cell_space/cell.py +84 -23
  11. mesa/experimental/cell_space/cell_agent.py +117 -21
  12. mesa/experimental/cell_space/cell_collection.py +54 -17
  13. mesa/experimental/cell_space/discrete_space.py +79 -7
  14. mesa/experimental/cell_space/grid.py +19 -8
  15. mesa/experimental/cell_space/network.py +9 -7
  16. mesa/experimental/cell_space/voronoi.py +26 -33
  17. mesa/experimental/components/altair.py +10 -0
  18. mesa/experimental/components/matplotlib.py +18 -0
  19. mesa/experimental/devs/__init__.py +2 -0
  20. mesa/experimental/devs/eventlist.py +36 -15
  21. mesa/experimental/devs/examples/epstein_civil_violence.py +65 -29
  22. mesa/experimental/devs/examples/wolf_sheep.py +40 -35
  23. mesa/experimental/devs/simulator.py +55 -15
  24. mesa/experimental/solara_viz.py +10 -19
  25. mesa/main.py +6 -4
  26. mesa/model.py +51 -54
  27. mesa/space.py +145 -120
  28. mesa/time.py +57 -67
  29. mesa/visualization/UserParam.py +19 -6
  30. mesa/visualization/__init__.py +3 -2
  31. mesa/visualization/components/altair.py +4 -2
  32. mesa/visualization/components/matplotlib.py +176 -85
  33. mesa/visualization/solara_viz.py +167 -84
  34. mesa/visualization/utils.py +3 -1
  35. {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/METADATA +55 -13
  36. mesa-3.0.0b0.dist-info/RECORD +45 -0
  37. mesa-3.0.0b0.dist-info/licenses/LICENSE +202 -0
  38. mesa-3.0.0a4.dist-info/licenses/LICENSE → mesa-3.0.0b0.dist-info/licenses/NOTICE +2 -2
  39. mesa-3.0.0a4.dist-info/RECORD +0 -44
  40. {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/WHEEL +0 -0
  41. {mesa-3.0.0a4.dist-info → mesa-3.0.0b0.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,5 @@
1
+ """Altair components."""
2
+
1
3
  import contextlib
2
4
 
3
5
  import solara
@@ -8,6 +10,14 @@ with contextlib.suppress(ImportError):
8
10
 
9
11
  @solara.component
10
12
  def SpaceAltair(model, agent_portrayal, dependencies: list[any] | None = None):
13
+ """A component that renders a Space using Altair.
14
+
15
+ Args:
16
+ model: a model instance
17
+ agent_portrayal: agent portray specification
18
+ dependencies: optional list of dependencies (currently not used)
19
+
20
+ """
11
21
  space = getattr(model, "grid", None)
12
22
  if space is None:
13
23
  # Sometimes the space is defined as model.space instead of model.grid
@@ -1,3 +1,5 @@
1
+ """Support for using matplotlib to draw spaces."""
2
+
1
3
  from collections import defaultdict
2
4
 
3
5
  import networkx as nx
@@ -11,6 +13,14 @@ from mesa.experimental.cell_space import VoronoiGrid
11
13
 
12
14
  @solara.component
13
15
  def SpaceMatplotlib(model, agent_portrayal, dependencies: list[any] | None = None):
16
+ """A component for rendering a space using Matplotlib.
17
+
18
+ Args:
19
+ model: a model instance
20
+ agent_portrayal: a specification of how to portray an agent.
21
+ dependencies: list of dependencies.
22
+
23
+ """
14
24
  space_fig = Figure()
15
25
  space_ax = space_fig.subplots()
16
26
  space = getattr(model, "grid", None)
@@ -205,6 +215,14 @@ def _draw_voronoi(space, space_ax, agent_portrayal):
205
215
 
206
216
  @solara.component
207
217
  def PlotMatplotlib(model, measure, dependencies: list[any] | None = None):
218
+ """A solara component for creating a matplotlib figure.
219
+
220
+ Args:
221
+ model: Model instance
222
+ measure: measure to plot
223
+ dependencies: list of additional dependencies
224
+
225
+ """
208
226
  fig = Figure()
209
227
  ax = fig.subplots()
210
228
  df = model.datacollector.get_model_vars_dataframe()
@@ -1,3 +1,5 @@
1
+ """Support for event scheduling."""
2
+
1
3
  from .eventlist import Priority, SimulationEvent
2
4
  from .simulator import ABMSimulator, DEVSimulator
3
5
 
@@ -1,3 +1,5 @@
1
+ """Eventlist which is at the core of event scheduling."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import itertools
@@ -10,15 +12,17 @@ from weakref import WeakMethod, ref
10
12
 
11
13
 
12
14
  class Priority(IntEnum):
15
+ """Enumeration of priority levels."""
16
+
13
17
  LOW = 10
14
18
  DEFAULT = 5
15
19
  HIGH = 1
16
20
 
17
21
 
18
22
  class SimulationEvent:
19
- """A simulation event
23
+ """A simulation event.
20
24
 
21
- the callable is wrapped using weakref, so there is no need to explicitly cancel event if e.g., an agent
25
+ The callable is wrapped using weakref, so there is no need to explicitly cancel event if e.g., an agent
22
26
  is removed from the simulation.
23
27
 
24
28
  Attributes:
@@ -34,7 +38,7 @@ class SimulationEvent:
34
38
  _ids = itertools.count()
35
39
 
36
40
  @property
37
- def CANCELED(self) -> bool:
41
+ def CANCELED(self) -> bool: # noqa: D102
38
42
  return self._canceled
39
43
 
40
44
  def __init__(
@@ -45,6 +49,15 @@ class SimulationEvent:
45
49
  function_args: list[Any] | None = None,
46
50
  function_kwargs: dict[str, Any] | None = None,
47
51
  ) -> None:
52
+ """Initialize a simulation event.
53
+
54
+ Args:
55
+ time: the instant of time of the simulation event
56
+ function: the callable to invoke
57
+ priority: the priority of the event
58
+ function_args: arguments for callable
59
+ function_kwargs: keyword arguments for the callable
60
+ """
48
61
  super().__init__()
49
62
  if not callable(function):
50
63
  raise Exception()
@@ -64,20 +77,20 @@ class SimulationEvent:
64
77
  self.function_kwargs = function_kwargs if function_kwargs else {}
65
78
 
66
79
  def execute(self):
67
- """execute this event"""
80
+ """Execute this event."""
68
81
  if not self._canceled:
69
82
  fn = self.fn()
70
83
  if fn is not None:
71
84
  fn(*self.function_args, **self.function_kwargs)
72
85
 
73
86
  def cancel(self) -> None:
74
- """cancel this event"""
87
+ """Cancel this event."""
75
88
  self._canceled = True
76
89
  self.fn = None
77
90
  self.function_args = []
78
91
  self.function_kwargs = {}
79
92
 
80
- def __lt__(self, other):
93
+ def __lt__(self, other): # noqa
81
94
  # Define a total ordering for events to be used by the heapq
82
95
  return (self.time, self.priority, self.unique_id) < (
83
96
  other.time,
@@ -87,30 +100,31 @@ class SimulationEvent:
87
100
 
88
101
 
89
102
  class EventList:
90
- """An event list
103
+ """An event list.
91
104
 
92
105
  This is a heap queue sorted list of events. Events are always removed from the left, so heapq is a performant and
93
106
  appropriate data structure. Events are sorted based on their time stamp, their priority, and their unique_id
94
107
  as a tie-breaker, guaranteeing a complete ordering.
95
108
 
109
+
96
110
  """
97
111
 
98
112
  def __init__(self):
113
+ """Initialize an event list."""
99
114
  self._events: list[SimulationEvent] = []
100
115
  heapify(self._events)
101
116
 
102
117
  def add_event(self, event: SimulationEvent):
103
- """Add the event to the event list
118
+ """Add the event to the event list.
104
119
 
105
120
  Args:
106
121
  event (SimulationEvent): The event to be added
107
122
 
108
123
  """
109
-
110
124
  heappush(self._events, event)
111
125
 
112
126
  def peak_ahead(self, n: int = 1) -> list[SimulationEvent]:
113
- """Look at the first n non-canceled event in the event list
127
+ """Look at the first n non-canceled event in the event list.
114
128
 
115
129
  Args:
116
130
  n (int): The number of events to look ahead
@@ -139,7 +153,7 @@ class EventList:
139
153
  return peek
140
154
 
141
155
  def pop_event(self) -> SimulationEvent:
142
- """pop the first element from the event list"""
156
+ """Pop the first element from the event list."""
143
157
  while self._events:
144
158
  event = heappop(self._events)
145
159
  if not event.CANCELED:
@@ -147,16 +161,17 @@ class EventList:
147
161
  raise IndexError("Event list is empty")
148
162
 
149
163
  def is_empty(self) -> bool:
164
+ """Return whether the event list is empty."""
150
165
  return len(self) == 0
151
166
 
152
- def __contains__(self, event: SimulationEvent) -> bool:
167
+ def __contains__(self, event: SimulationEvent) -> bool: # noqa
153
168
  return event in self._events
154
169
 
155
- def __len__(self) -> int:
170
+ def __len__(self) -> int: # noqa
156
171
  return len(self._events)
157
172
 
158
173
  def __repr__(self) -> str:
159
- """Return a string representation of the event list"""
174
+ """Return a string representation of the event list."""
160
175
  events_str = ", ".join(
161
176
  [
162
177
  f"Event(time={e.time}, priority={e.priority}, id={e.unique_id})"
@@ -167,7 +182,12 @@ class EventList:
167
182
  return f"EventList([{events_str}])"
168
183
 
169
184
  def remove(self, event: SimulationEvent) -> None:
170
- """remove an event from the event list"""
185
+ """Remove an event from the event list.
186
+
187
+ Args:
188
+ event (SimulationEvent): The event to be removed
189
+
190
+ """
171
191
  # we cannot simply remove items from _eventlist because this breaks
172
192
  # heap structure invariant. So, we use a form of lazy deletion.
173
193
  # SimEvents have a CANCELED flag that we set to True, while popping and peak_ahead
@@ -175,4 +195,5 @@ class EventList:
175
195
  event.cancel()
176
196
 
177
197
  def clear(self):
198
+ """Clear the event list."""
178
199
  self._events.clear()
@@ -1,3 +1,5 @@
1
+ """Epstein civil violence example using ABMSimulator."""
2
+
1
3
  import enum
2
4
  import math
3
5
 
@@ -7,21 +9,32 @@ from mesa.space import SingleGrid
7
9
 
8
10
 
9
11
  class EpsteinAgent(Agent):
12
+ """Epstein Agent."""
13
+
10
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
+ """
11
22
  super().__init__(model)
12
23
  self.vision = vision
13
24
  self.movement = movement
14
25
 
15
26
 
16
27
  class AgentState(enum.IntEnum):
28
+ """Agent states."""
29
+
17
30
  QUIESCENT = enum.auto()
18
31
  ARRESTED = enum.auto()
19
32
  ACTIVE = enum.auto()
20
33
 
21
34
 
22
35
  class Citizen(EpsteinAgent):
23
- """
24
- A member of the general population, may or may not be in active rebellion.
36
+ """A member of the general population, may or may not be in active rebellion.
37
+
25
38
  Summary of rule: If grievance - risk > threshold, rebel.
26
39
 
27
40
  Attributes:
@@ -55,10 +68,13 @@ class Citizen(EpsteinAgent):
55
68
  threshold,
56
69
  arrest_prob_constant,
57
70
  ):
58
- """
59
- Create a new Citizen.
71
+ """Create a new Citizen.
72
+
60
73
  Args:
61
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
62
78
  hardship: Agent's 'perceived hardship (i.e., physical or economic
63
79
  privation).' Exogenous, drawn from U(0,1).
64
80
  regime_legitimacy: Agent's perception of regime legitimacy, equal
@@ -66,8 +82,8 @@ class Citizen(EpsteinAgent):
66
82
  risk_aversion: Exogenous, drawn from U(0,1).
67
83
  threshold: if (grievance - (risk_aversion * arrest_probability)) >
68
84
  threshold, go/remain Active
69
- vision: number of cells in each direction (N, S, E and W) that
70
- agent can inspect. Exogenous.
85
+ arrest_prob_constant : agent's assessment of arrest probability
86
+
71
87
  """
72
88
  super().__init__(model, vision, movement)
73
89
  self.hardship = hardship
@@ -80,9 +96,7 @@ class Citizen(EpsteinAgent):
80
96
  self.arrest_prob_constant = arrest_prob_constant
81
97
 
82
98
  def step(self):
83
- """
84
- Decide whether to activate, then move if applicable.
85
- """
99
+ """Decide whether to activate, then move if applicable."""
86
100
  self.update_neighbors()
87
101
  self.update_estimated_arrest_probability()
88
102
  net_risk = self.risk_aversion * self.arrest_probability
@@ -95,9 +109,7 @@ class Citizen(EpsteinAgent):
95
109
  self.model.grid.move_agent(self, new_pos)
96
110
 
97
111
  def update_neighbors(self):
98
- """
99
- Look around and see who my neighbors are
100
- """
112
+ """Look around and see who my neighbors are."""
101
113
  self.neighborhood = self.model.grid.get_neighborhood(
102
114
  self.pos, moore=True, radius=self.vision
103
115
  )
@@ -107,10 +119,7 @@ class Citizen(EpsteinAgent):
107
119
  ]
108
120
 
109
121
  def update_estimated_arrest_probability(self):
110
- """
111
- Based on the ratio of cops to actives in my neighborhood, estimate the
112
- p(Arrest | I go active).
113
- """
122
+ """Based on the ratio of cops to actives in my neighborhood, estimate the p(Arrest | I go active)."""
114
123
  cops_in_vision = len([c for c in self.neighbors if isinstance(c, Cop)])
115
124
  actives_in_vision = 1.0 # citizen counts herself
116
125
  for c in self.neighbors:
@@ -121,18 +130,25 @@ class Citizen(EpsteinAgent):
121
130
  )
122
131
 
123
132
  def sent_to_jail(self, value):
133
+ """Sent agent to jail.
134
+
135
+ Args:
136
+ value: duration of jail sentence
137
+
138
+ """
124
139
  self.model.active_agents.remove(self)
125
140
  self.condition = AgentState.ARRESTED
126
141
  self.model.simulator.schedule_event_relative(self.release_from_jail, value)
127
142
 
128
143
  def release_from_jail(self):
144
+ """Release agent from jail."""
129
145
  self.model.active_agents.add(self)
130
146
  self.condition = AgentState.QUIESCENT
131
147
 
132
148
 
133
149
  class Cop(EpsteinAgent):
134
- """
135
- A cop for life. No defection.
150
+ """A cop for life. No defection.
151
+
136
152
  Summary of rule: Inspect local vision and arrest a random active agent.
137
153
 
138
154
  Attributes:
@@ -143,14 +159,19 @@ class Cop(EpsteinAgent):
143
159
  """
144
160
 
145
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
+ """
146
170
  super().__init__(model, vision, movement)
147
171
  self.max_jail_term = max_jail_term
148
172
 
149
173
  def step(self):
150
- """
151
- Inspect local vision and arrest a random active agent. Move if
152
- applicable.
153
- """
174
+ """Inspect local vision and arrest a random active agent. Move if applicable."""
154
175
  self.update_neighbors()
155
176
  active_neighbors = []
156
177
  for agent in self.neighbors:
@@ -164,9 +185,7 @@ class Cop(EpsteinAgent):
164
185
  self.model.grid.move_agent(self, new_pos)
165
186
 
166
187
  def update_neighbors(self):
167
- """
168
- Look around and see who my neighbors are.
169
- """
188
+ """Look around and see who my neighbors are."""
170
189
  self.neighborhood = self.model.grid.get_neighborhood(
171
190
  self.pos, moore=True, radius=self.vision
172
191
  )
@@ -177,9 +196,8 @@ class Cop(EpsteinAgent):
177
196
 
178
197
 
179
198
  class EpsteinCivilViolence(Model):
180
- """
181
- Model 1 from "Modeling civil violence: An agent-based computational
182
- approach," by Joshua Epstein.
199
+ """Model 1 from "Modeling civil violence: An agent-based computational approach," by Joshua Epstein.
200
+
183
201
  http://www.pnas.org/content/99/suppl_3/7243.full
184
202
  Attributes:
185
203
  height: grid height
@@ -218,6 +236,23 @@ class EpsteinCivilViolence(Model):
218
236
  max_iters=1000,
219
237
  seed=None,
220
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
+ """
221
256
  super().__init__(seed)
222
257
  if cop_density + citizen_density > 1:
223
258
  raise ValueError("Cop density + citizen density must be less than 1")
@@ -257,7 +292,8 @@ class EpsteinCivilViolence(Model):
257
292
  self.active_agents = self.agents
258
293
 
259
294
  def step(self):
260
- self.active_agents.shuffle(inplace=True).do("step")
295
+ """Run one step of the model."""
296
+ self.active_agents.shuffle_do("step")
261
297
 
262
298
 
263
299
  if __name__ == "__main__":
@@ -1,20 +1,23 @@
1
- """
2
- Wolf-Sheep Predation Model
3
- ================================
4
-
5
- Replication of the model found in NetLogo:
6
- Wilensky, U. (1997). NetLogo Wolf Sheep Predation model.
7
- http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation.
8
- Center for Connected Learning and Computer-Based Modeling,
9
- Northwestern University, Evanston, IL.
10
- """
1
+ """Example of using ABM simulator for Wolf-Sheep Predation Model."""
11
2
 
12
3
  import mesa
4
+ from mesa.experimental.cell_space import FixedAgent
13
5
  from mesa.experimental.devs.simulator import ABMSimulator
14
6
 
15
7
 
16
8
  class Animal(mesa.Agent):
9
+ """Base Animal class."""
10
+
17
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
+ """
18
21
  super().__init__(model)
19
22
  self.energy = energy
20
23
  self.p_reproduce = p_reproduce
@@ -22,12 +25,14 @@ class Animal(mesa.Agent):
22
25
  self.moore = moore
23
26
 
24
27
  def random_move(self):
28
+ """Move to random neighboring cell."""
25
29
  next_moves = self.model.grid.get_neighborhood(self.pos, self.moore, True)
26
30
  next_move = self.random.choice(next_moves)
27
31
  # Now move:
28
32
  self.model.grid.move_agent(self, next_move)
29
33
 
30
34
  def spawn_offspring(self):
35
+ """Create offspring."""
31
36
  self.energy /= 2
32
37
  offspring = self.__class__(
33
38
  self.model,
@@ -38,13 +43,15 @@ class Animal(mesa.Agent):
38
43
  )
39
44
  self.model.grid.place_agent(offspring, self.pos)
40
45
 
41
- def feed(self): ...
46
+ def feed(self): ... # noqa: D102
42
47
 
43
48
  def die(self):
49
+ """Die."""
44
50
  self.model.grid.remove_agent(self)
45
51
  self.remove()
46
52
 
47
53
  def step(self):
54
+ """Execute one step of the agent."""
48
55
  self.random_move()
49
56
  self.energy -= 1
50
57
 
@@ -57,13 +64,10 @@ class Animal(mesa.Agent):
57
64
 
58
65
 
59
66
  class Sheep(Animal):
60
- """
61
- A sheep that walks around, reproduces (asexually) and gets eaten.
62
-
63
- The init is the same as the RandomWalker.
64
- """
67
+ """A sheep that walks around, reproduces (asexually) and gets eaten."""
65
68
 
66
69
  def feed(self):
70
+ """Eat grass and gain energy."""
67
71
  # If there is grass available, eat it
68
72
  agents = self.model.grid.get_cell_list_contents(self.pos)
69
73
  grass_patch = next(obj for obj in agents if isinstance(obj, GrassPatch))
@@ -73,11 +77,10 @@ class Sheep(Animal):
73
77
 
74
78
 
75
79
  class Wolf(Animal):
76
- """
77
- A wolf that walks around, reproduces (asexually) and eats sheep.
78
- """
80
+ """A wolf that walks around, reproduces (asexually) and eats sheep."""
79
81
 
80
82
  def feed(self):
83
+ """Eat wolf and gain energy."""
81
84
  agents = self.model.grid.get_cell_list_contents(self.pos)
82
85
  sheep = [obj for obj in agents if isinstance(obj, Sheep)]
83
86
  if len(sheep) > 0:
@@ -88,13 +91,11 @@ class Wolf(Animal):
88
91
  sheep_to_eat.die()
89
92
 
90
93
 
91
- class GrassPatch(mesa.Agent):
92
- """
93
- A patch of grass that grows at a fixed rate and it is eaten by sheep
94
- """
94
+ class GrassPatch(FixedAgent):
95
+ """A patch of grass that grows at a fixed rate and it is eaten by sheep."""
95
96
 
96
97
  @property
97
- def fully_grown(self) -> bool:
98
+ def fully_grown(self) -> bool: # noqa: D102
98
99
  return self._fully_grown
99
100
 
100
101
  @fully_grown.setter
@@ -109,12 +110,13 @@ class GrassPatch(mesa.Agent):
109
110
  )
110
111
 
111
112
  def __init__(self, model, fully_grown, countdown, grass_regrowth_time):
112
- """
113
- Creates a new patch of grass
113
+ """Creates a new patch of grass.
114
114
 
115
115
  Args:
116
- grown: (boolean) Whether the patch of grass is fully grown or not
116
+ model: a model instance
117
+ fully_grown: (boolean) Whether the patch of grass is fully grown or not
117
118
  countdown: Time for the patch of grass to be fully grown again
119
+ grass_regrowth_time: regrowth time for the grass
118
120
  """
119
121
  super().__init__(model)
120
122
  self._fully_grown = fully_grown
@@ -125,13 +127,12 @@ class GrassPatch(mesa.Agent):
125
127
  setattr, countdown, function_args=[self, "fully_grown", True]
126
128
  )
127
129
 
128
- def set_fully_grown(self):
130
+ def set_fully_grown(self): # noqa
129
131
  self.fully_grown = True
130
132
 
131
133
 
132
134
  class WolfSheep(mesa.Model):
133
- """
134
- Wolf-Sheep Predation Model
135
+ """Wolf-Sheep Predation Model.
135
136
 
136
137
  A model for simulating wolf and sheep (predator-prey) ecosystem modelling.
137
138
  """
@@ -151,10 +152,11 @@ class WolfSheep(mesa.Model):
151
152
  simulator=None,
152
153
  seed=None,
153
154
  ):
154
- """
155
- Create a new Wolf-Sheep model with the given parameters.
155
+ """Create a new Wolf-Sheep model with the given parameters.
156
156
 
157
157
  Args:
158
+ height: height of the grid
159
+ width: width of the grid
158
160
  initial_sheep: Number of sheep to start with
159
161
  initial_wolves: Number of wolves to start with
160
162
  sheep_reproduce: Probability of each sheep reproducing each step
@@ -164,7 +166,9 @@ class WolfSheep(mesa.Model):
164
166
  grass_regrowth_time: How long it takes for a grass patch to regrow
165
167
  once it is eaten
166
168
  sheep_gain_from_food: Energy sheep gain from grass, if enabled.
167
- moore:
169
+ moore: whether to use moore or von Neumann grid
170
+ simulator: Simulator to use for simulating wolf and sheep
171
+ seed: Random seed
168
172
  """
169
173
  super().__init__(seed=seed)
170
174
  # Set parameters
@@ -226,8 +230,9 @@ class WolfSheep(mesa.Model):
226
230
  self.grid.place_agent(patch, pos)
227
231
 
228
232
  def step(self):
229
- self.agents_by_type[Sheep].shuffle(inplace=True).do("step")
230
- self.agents_by_type[Wolf].shuffle(inplace=True).do("step")
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")
231
236
 
232
237
 
233
238
  if __name__ == "__main__":