Mesa 3.1.0.dev0__py3-none-any.whl → 3.1.1__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 (57) hide show
  1. mesa/__init__.py +3 -3
  2. mesa/agent.py +48 -0
  3. mesa/batchrunner.py +14 -1
  4. mesa/datacollection.py +1 -6
  5. mesa/examples/__init__.py +2 -2
  6. mesa/examples/advanced/epstein_civil_violence/app.py +5 -0
  7. mesa/examples/advanced/pd_grid/agents.py +2 -1
  8. mesa/examples/advanced/pd_grid/app.py +5 -0
  9. mesa/examples/advanced/pd_grid/model.py +3 -5
  10. mesa/examples/advanced/sugarscape_g1mt/agents.py +12 -65
  11. mesa/examples/advanced/sugarscape_g1mt/app.py +24 -19
  12. mesa/examples/advanced/sugarscape_g1mt/model.py +45 -52
  13. mesa/examples/advanced/wolf_sheep/agents.py +3 -1
  14. mesa/examples/advanced/wolf_sheep/model.py +17 -16
  15. mesa/examples/basic/boid_flockers/app.py +5 -0
  16. mesa/examples/basic/boltzmann_wealth_model/app.py +8 -5
  17. mesa/examples/basic/boltzmann_wealth_model/st_app.py +1 -1
  18. mesa/examples/basic/conways_game_of_life/app.py +5 -0
  19. mesa/examples/basic/conways_game_of_life/st_app.py +2 -2
  20. mesa/examples/basic/schelling/agents.py +11 -5
  21. mesa/examples/basic/schelling/app.py +6 -1
  22. mesa/examples/basic/virus_on_network/app.py +5 -0
  23. mesa/experimental/__init__.py +17 -10
  24. mesa/experimental/cell_space/__init__.py +19 -7
  25. mesa/experimental/cell_space/cell.py +22 -37
  26. mesa/experimental/cell_space/cell_agent.py +12 -1
  27. mesa/experimental/cell_space/cell_collection.py +18 -3
  28. mesa/experimental/cell_space/discrete_space.py +15 -64
  29. mesa/experimental/cell_space/grid.py +74 -4
  30. mesa/experimental/cell_space/network.py +13 -1
  31. mesa/experimental/cell_space/property_layer.py +444 -0
  32. mesa/experimental/cell_space/voronoi.py +13 -1
  33. mesa/experimental/devs/__init__.py +20 -2
  34. mesa/experimental/devs/eventlist.py +19 -1
  35. mesa/experimental/devs/simulator.py +24 -8
  36. mesa/experimental/mesa_signals/__init__.py +23 -0
  37. mesa/experimental/mesa_signals/mesa_signal.py +485 -0
  38. mesa/experimental/mesa_signals/observable_collections.py +133 -0
  39. mesa/experimental/mesa_signals/signals_util.py +52 -0
  40. mesa/mesa_logging.py +190 -0
  41. mesa/model.py +17 -23
  42. mesa/visualization/__init__.py +2 -2
  43. mesa/visualization/mpl_space_drawing.py +8 -5
  44. mesa/visualization/solara_viz.py +49 -11
  45. {mesa-3.1.0.dev0.dist-info → mesa-3.1.1.dist-info}/METADATA +1 -1
  46. mesa-3.1.1.dist-info/RECORD +94 -0
  47. {mesa-3.1.0.dev0.dist-info → mesa-3.1.1.dist-info}/WHEEL +1 -1
  48. mesa/experimental/UserParam.py +0 -67
  49. mesa/experimental/components/altair.py +0 -81
  50. mesa/experimental/components/matplotlib.py +0 -242
  51. mesa/experimental/devs/examples/epstein_civil_violence.py +0 -305
  52. mesa/experimental/devs/examples/wolf_sheep.py +0 -250
  53. mesa/experimental/solara_viz.py +0 -453
  54. mesa-3.1.0.dev0.dist-info/RECORD +0 -94
  55. {mesa-3.1.0.dev0.dist-info → mesa-3.1.1.dist-info}/entry_points.txt +0 -0
  56. {mesa-3.1.0.dev0.dist-info → mesa-3.1.1.dist-info}/licenses/LICENSE +0 -0
  57. {mesa-3.1.0.dev0.dist-info → mesa-3.1.1.dist-info}/licenses/NOTICE +0 -0
mesa/__init__.py CHANGED
@@ -13,16 +13,16 @@ from mesa.datacollection import DataCollector
13
13
  from mesa.model import Model
14
14
 
15
15
  __all__ = [
16
- "Model",
17
16
  "Agent",
18
- "space",
19
17
  "DataCollector",
18
+ "Model",
20
19
  "batch_run",
21
20
  "experimental",
21
+ "space",
22
22
  ]
23
23
 
24
24
  __title__ = "mesa"
25
- __version__ = "3.1.0.dev"
25
+ __version__ = "3.1.1"
26
26
  __license__ = "Apache 2.0"
27
27
  _this_year = datetime.datetime.now(tz=datetime.UTC).date().year
28
28
  __copyright__ = f"Copyright {_this_year} Project Mesa Team"
mesa/agent.py CHANGED
@@ -85,6 +85,54 @@ class Agent:
85
85
  def advance(self) -> None: # noqa: D102
86
86
  pass
87
87
 
88
+ @classmethod
89
+ def create_agents(cls, model: Model, n: int, *args, **kwargs) -> AgentSet[Agent]:
90
+ """Create N agents.
91
+
92
+ Args:
93
+ model: the model to which the agents belong
94
+ args: arguments to pass onto agent instances
95
+ each arg is either a single object or a sequence of length n
96
+ n: the number of agents to create
97
+ kwargs: keyword arguments to pass onto agent instances
98
+ each keyword arg is either a single object or a sequence of length n
99
+
100
+ Returns:
101
+ AgentSet containing the agents created.
102
+
103
+ """
104
+
105
+ class ListLike:
106
+ """Helper class to make default arguments act as if they are in a list of length N."""
107
+
108
+ def __init__(self, value):
109
+ self.value = value
110
+
111
+ def __getitem__(self, i):
112
+ return self.value
113
+
114
+ listlike_args = []
115
+ for arg in args:
116
+ if isinstance(arg, (list | np.ndarray | tuple)) and len(arg) == n:
117
+ listlike_args.append(arg)
118
+ else:
119
+ listlike_args.append(ListLike(arg))
120
+
121
+ listlike_kwargs = {}
122
+ for k, v in kwargs.items():
123
+ if isinstance(v, (list | np.ndarray | tuple)) and len(v) == n:
124
+ listlike_kwargs[k] = v
125
+ else:
126
+ listlike_kwargs[k] = ListLike(v)
127
+
128
+ agents = []
129
+ for i in range(n):
130
+ instance_args = [arg[i] for arg in listlike_args]
131
+ instance_kwargs = {k: v[i] for k, v in listlike_kwargs.items()}
132
+ agent = cls(model, *instance_args, **instance_kwargs)
133
+ agents.append(agent)
134
+ return AgentSet(agents, random=model.random)
135
+
88
136
  @property
89
137
  def random(self) -> Random:
90
138
  """Return a seeded stdlib rng."""
mesa/batchrunner.py CHANGED
@@ -106,7 +106,14 @@ def _make_model_kwargs(
106
106
  Parameters
107
107
  ----------
108
108
  parameters : Mapping[str, Union[Any, Iterable[Any]]]
109
- Single or multiple values for each model parameter name
109
+ Single or multiple values for each model parameter name.
110
+
111
+ Allowed values for each parameter:
112
+ - A single value (e.g., `32`, `"relu"`).
113
+ - A non-empty iterable (e.g., `[0.01, 0.1]`, `["relu", "sigmoid"]`).
114
+
115
+ Not allowed:
116
+ - Empty lists or empty iterables (e.g., `[]`, `()`, etc.). These should be removed manually.
110
117
 
111
118
  Returns:
112
119
  -------
@@ -118,6 +125,12 @@ def _make_model_kwargs(
118
125
  if isinstance(values, str):
119
126
  # The values is a single string, so we shouldn't iterate over it.
120
127
  all_values = [(param, values)]
128
+ elif isinstance(values, list | tuple | set) and len(values) == 0:
129
+ # If it's an empty iterable, raise an error
130
+ raise ValueError(
131
+ f"Parameter '{param}' contains an empty iterable, which is not allowed."
132
+ )
133
+
121
134
  else:
122
135
  try:
123
136
  all_values = [(param, value) for value in values]
mesa/datacollection.py CHANGED
@@ -228,12 +228,7 @@ class DataCollector:
228
228
  reports = tuple(rep(agent) for rep in rep_funcs)
229
229
  return _prefix + reports
230
230
 
231
- agent_records = map(
232
- get_reports,
233
- model.schedule.agents
234
- if hasattr(model, "schedule") and model.schedule is not None
235
- else model.agents,
236
- )
231
+ agent_records = map(get_reports, model.agents)
237
232
  return agent_records
238
233
 
239
234
  def _record_agenttype(self, model, agent_type):
mesa/examples/__init__.py CHANGED
@@ -12,10 +12,10 @@ __all__ = [
12
12
  "BoidFlockers",
13
13
  "BoltzmannWealth",
14
14
  "ConwaysGameOfLife",
15
- "Schelling",
16
- "VirusOnNetwork",
17
15
  "EpsteinCivilViolence",
18
16
  "PdGrid",
17
+ "Schelling",
19
18
  "SugarscapeG1mt",
19
+ "VirusOnNetwork",
20
20
  "WolfSheep",
21
21
  ]
@@ -44,6 +44,11 @@ def post_process(ax):
44
44
 
45
45
 
46
46
  model_params = {
47
+ "seed": {
48
+ "type": "InputText",
49
+ "value": 42,
50
+ "label": "Random Seed",
51
+ },
47
52
  "height": 40,
48
53
  "width": 40,
49
54
  "citizen_density": Slider("Initial Agent Density", 0.7, 0.0, 0.9, 0.1),
@@ -4,7 +4,7 @@ from mesa.experimental.cell_space import CellAgent
4
4
  class PDAgent(CellAgent):
5
5
  """Agent member of the iterated, spatial prisoner's dilemma model."""
6
6
 
7
- def __init__(self, model, starting_move=None):
7
+ def __init__(self, model, starting_move=None, cell=None):
8
8
  """
9
9
  Create a new Prisoner's Dilemma agent.
10
10
 
@@ -15,6 +15,7 @@ class PDAgent(CellAgent):
15
15
  """
16
16
  super().__init__(model)
17
17
  self.score = 0
18
+ self.cell = cell
18
19
  if starting_move:
19
20
  self.move = starting_move
20
21
  else:
@@ -24,6 +24,11 @@ def pd_agent_portrayal(agent):
24
24
 
25
25
  # Model parameters
26
26
  model_params = {
27
+ "seed": {
28
+ "type": "InputText",
29
+ "value": 42,
30
+ "label": "Random Seed",
31
+ },
27
32
  "width": Slider("Grid Width", value=50, min=10, max=100, step=1),
28
33
  "height": Slider("Grid Height", value=50, min=10, max=100, step=1),
29
34
  "activation_order": {
@@ -32,11 +32,9 @@ class PdGrid(mesa.Model):
32
32
  if payoffs is not None:
33
33
  self.payoff = payoffs
34
34
 
35
- # Create agents
36
- for x in range(width):
37
- for y in range(height):
38
- agent = PDAgent(self)
39
- agent.cell = self.grid[(x, y)]
35
+ PDAgent.create_agents(
36
+ self, len(self.grid.all_cells.cells), cell=self.grid.all_cells.cells
37
+ )
40
38
 
41
39
  self.datacollector = mesa.DataCollector(
42
40
  {
@@ -1,6 +1,6 @@
1
1
  import math
2
2
 
3
- from mesa.experimental.cell_space import CellAgent, FixedAgent
3
+ from mesa.experimental.cell_space import CellAgent
4
4
 
5
5
 
6
6
  # Helper function
@@ -18,31 +18,6 @@ def get_distance(cell_1, cell_2):
18
18
  return math.sqrt(dx**2 + dy**2)
19
19
 
20
20
 
21
- class Resource(FixedAgent):
22
- """
23
- Resource:
24
- - contains an amount of sugar and spice
25
- - grows 1 amount of sugar at each turn
26
- - grows 1 amount of spice at each turn
27
- """
28
-
29
- def __init__(self, model, max_sugar, max_spice, cell):
30
- super().__init__(model)
31
- self.sugar_amount = max_sugar
32
- self.max_sugar = max_sugar
33
- self.spice_amount = max_spice
34
- self.max_spice = max_spice
35
- self.cell = cell
36
-
37
- def step(self):
38
- """
39
- Growth function, adds one unit of sugar and spice each step up to
40
- max amount
41
- """
42
- self.sugar_amount = min([self.max_sugar, self.sugar_amount + 1])
43
- self.spice_amount = min([self.max_spice, self.spice_amount + 1])
44
-
45
-
46
21
  class Trader(CellAgent):
47
22
  """
48
23
  Trader:
@@ -70,12 +45,6 @@ class Trader(CellAgent):
70
45
  self.prices = []
71
46
  self.trade_partners = []
72
47
 
73
- def get_resource(self, cell):
74
- for agent in cell.agents:
75
- if isinstance(agent, Resource):
76
- return agent
77
- raise Exception(f"Resource agent not found in the position {cell.coordinate}")
78
-
79
48
  def get_trader(self, cell):
80
49
  """
81
50
  helper function used in self.trade_with_neighbors()
@@ -85,17 +54,6 @@ class Trader(CellAgent):
85
54
  if isinstance(agent, Trader):
86
55
  return agent
87
56
 
88
- def is_occupied_by_other(self, cell):
89
- """
90
- helper function part 1 of self.move()
91
- """
92
-
93
- if cell is self.cell:
94
- # agent's position is considered unoccupied as agent can stay there
95
- return False
96
- # get contents of each cell in neighborhood
97
- return any(isinstance(a, Trader) for a in cell.agents)
98
-
99
57
  def calculate_welfare(self, sugar, spice):
100
58
  """
101
59
  helper function
@@ -264,15 +222,15 @@ class Trader(CellAgent):
264
222
  neighboring_cells = [
265
223
  cell
266
224
  for cell in self.cell.get_neighborhood(self.vision, include_center=True)
267
- if not self.is_occupied_by_other(cell)
225
+ if cell.is_empty
268
226
  ]
269
227
 
270
228
  # 2. determine which move maximizes welfare
271
229
 
272
230
  welfares = [
273
231
  self.calculate_welfare(
274
- self.sugar + self.get_resource(cell).sugar_amount,
275
- self.spice + self.get_resource(cell).spice_amount,
232
+ self.sugar + cell.sugar,
233
+ self.spice + cell.spice,
276
234
  )
277
235
  for cell in neighboring_cells
278
236
  ]
@@ -282,6 +240,7 @@ class Trader(CellAgent):
282
240
  # find the highest welfare in welfares
283
241
  max_welfare = max(welfares)
284
242
  # get the index of max welfare cells
243
+ # fixme: rewrite using enumerate and single loop
285
244
  candidate_indices = [
286
245
  i for i in range(len(welfares)) if math.isclose(welfares[i], max_welfare)
287
246
  ]
@@ -296,19 +255,17 @@ class Trader(CellAgent):
296
255
  for cell in candidates
297
256
  if math.isclose(get_distance(self.cell, cell), min_dist, rel_tol=1e-02)
298
257
  ]
258
+
299
259
  # 4. Move Agent
300
260
  self.cell = self.random.choice(final_candidates)
301
261
 
302
262
  def eat(self):
303
- patch = self.get_resource(self.cell)
304
- if patch.sugar_amount > 0:
305
- self.sugar += patch.sugar_amount
306
- patch.sugar_amount = 0
263
+ self.sugar += self.cell.sugar
264
+ self.cell.sugar = 0
307
265
  self.sugar -= self.metabolism_sugar
308
266
 
309
- if patch.spice_amount > 0:
310
- self.spice += patch.spice_amount
311
- patch.spice_amount = 0
267
+ self.spice += self.cell.spice
268
+ self.cell.spice = 0
312
269
  self.spice -= self.metabolism_spice
313
270
 
314
271
  def maybe_die(self):
@@ -327,18 +284,8 @@ class Trader(CellAgent):
327
284
  2- trade (2 sessions)
328
285
  3- collect data
329
286
  """
330
-
331
- neighbor_agents = [
332
- self.get_trader(cell)
333
- for cell in self.cell.get_neighborhood(radius=self.vision)
334
- if self.is_occupied_by_other(cell)
335
- ]
336
-
337
- if len(neighbor_agents) == 0:
338
- return
339
-
340
- # iterate through traders in neighboring cells and trade
341
- for a in neighbor_agents:
287
+ # iterate through traders in neighboring cells and trade
288
+ for a in self.cell.get_neighborhood(radius=self.vision).agents:
342
289
  self.trade(a)
343
290
 
344
291
  return
@@ -2,7 +2,6 @@ import numpy as np
2
2
  import solara
3
3
  from matplotlib.figure import Figure
4
4
 
5
- from mesa.examples.advanced.sugarscape_g1mt.agents import Trader
6
5
  from mesa.examples.advanced.sugarscape_g1mt.model import SugarscapeG1mt
7
6
  from mesa.visualization import Slider, SolaraViz, make_plot_component
8
7
 
@@ -10,24 +9,13 @@ from mesa.visualization import Slider, SolaraViz, make_plot_component
10
9
  def SpaceDrawer(model):
11
10
  def portray(g):
12
11
  layers = {
13
- "sugar": [[np.nan for j in range(g.height)] for i in range(g.width)],
14
- "spice": [[np.nan for j in range(g.height)] for i in range(g.width)],
15
12
  "trader": {"x": [], "y": [], "c": "tab:red", "marker": "o", "s": 10},
16
13
  }
17
14
 
18
15
  for agent in g.all_cells.agents:
19
16
  i, j = agent.cell.coordinate
20
- if isinstance(agent, Trader):
21
- layers["trader"]["x"].append(i)
22
- layers["trader"]["y"].append(j)
23
- else:
24
- # Don't visualize resource with value <= 1.
25
- layers["sugar"][i][j] = (
26
- agent.sugar_amount if agent.sugar_amount > 1 else np.nan
27
- )
28
- layers["spice"][i][j] = (
29
- agent.spice_amount if agent.spice_amount > 1 else np.nan
30
- )
17
+ layers["trader"]["x"].append(i)
18
+ layers["trader"]["y"].append(j)
31
19
  return layers
32
20
 
33
21
  fig = Figure()
@@ -36,10 +24,18 @@ def SpaceDrawer(model):
36
24
  # Sugar
37
25
  # Important note: imshow by default draws from upper left. You have to
38
26
  # always explicitly specify origin="lower".
39
- im = ax.imshow(out["sugar"], cmap="spring", origin="lower")
27
+ im = ax.imshow(
28
+ np.ma.masked_where(model.grid.sugar.data <= 1, model.grid.sugar.data),
29
+ cmap="spring",
30
+ origin="lower",
31
+ )
40
32
  fig.colorbar(im, orientation="vertical")
41
33
  # Spice
42
- ax.imshow(out["spice"], cmap="winter", origin="lower")
34
+ ax.imshow(
35
+ np.ma.masked_where(model.grid.spice.data <= 1, model.grid.spice.data),
36
+ cmap="winter",
37
+ origin="lower",
38
+ )
43
39
  # Trader
44
40
  ax.scatter(**out["trader"])
45
41
  ax.set_axis_off()
@@ -47,6 +43,11 @@ def SpaceDrawer(model):
47
43
 
48
44
 
49
45
  model_params = {
46
+ "seed": {
47
+ "type": "InputText",
48
+ "value": 42,
49
+ "label": "Random Seed",
50
+ },
50
51
  "width": 50,
51
52
  "height": 50,
52
53
  # Population parameters
@@ -66,11 +67,15 @@ model_params = {
66
67
  "enable_trade": {"type": "Checkbox", "value": True, "label": "Enable Trading"},
67
68
  }
68
69
 
69
- model1 = SugarscapeG1mt()
70
+ model = SugarscapeG1mt()
70
71
 
71
72
  page = SolaraViz(
72
- model1,
73
- components=[SpaceDrawer, make_plot_component(["Trader", "Price"])],
73
+ model,
74
+ components=[
75
+ SpaceDrawer,
76
+ make_plot_component("#Traders"),
77
+ make_plot_component("Price"),
78
+ ],
74
79
  model_params=model_params,
75
80
  name="Sugarscape {G1, M, T}",
76
81
  play_interval=150,
@@ -3,8 +3,9 @@ from pathlib import Path
3
3
  import numpy as np
4
4
 
5
5
  import mesa
6
- from mesa.examples.advanced.sugarscape_g1mt.agents import Resource, Trader
6
+ from mesa.examples.advanced.sugarscape_g1mt.agents import Trader
7
7
  from mesa.experimental.cell_space import OrthogonalVonNeumannGrid
8
+ from mesa.experimental.cell_space.property_layer import PropertyLayer
8
9
 
9
10
 
10
11
  # Helper Functions
@@ -58,14 +59,8 @@ class SugarscapeG1mt(mesa.Model):
58
59
  # Initiate width and height of sugarscape
59
60
  self.width = width
60
61
  self.height = height
62
+
61
63
  # Initiate population attributes
62
- self.initial_population = initial_population
63
- self.endowment_min = endowment_min
64
- self.endowment_max = endowment_max
65
- self.metabolism_min = metabolism_min
66
- self.metabolism_max = metabolism_max
67
- self.vision_min = vision_min
68
- self.vision_max = vision_max
69
64
  self.enable_trade = enable_trade
70
65
  self.running = True
71
66
 
@@ -76,55 +71,46 @@ class SugarscapeG1mt(mesa.Model):
76
71
  # initiate datacollector
77
72
  self.datacollector = mesa.DataCollector(
78
73
  model_reporters={
79
- "Trader": lambda m: len(m.agents_by_type[Trader]),
80
- "Trade Volume": lambda m: sum(
81
- len(a.trade_partners) for a in m.agents_by_type[Trader]
82
- ),
74
+ "#Traders": lambda m: len(m.agents),
75
+ "Trade Volume": lambda m: sum(len(a.trade_partners) for a in m.agents),
83
76
  "Price": lambda m: geometric_mean(
84
- flatten([a.prices for a in m.agents_by_type[Trader]])
77
+ flatten([a.prices for a in m.agents])
85
78
  ),
86
79
  },
87
80
  agent_reporters={"Trade Network": lambda a: get_trade(a)},
88
81
  )
89
82
 
90
- # read in landscape file from supplmentary material
91
- sugar_distribution = np.genfromtxt(Path(__file__).parent / "sugar-map.txt")
92
- spice_distribution = np.flip(sugar_distribution, 1)
93
-
94
- for cell in self.grid.all_cells:
95
- max_sugar = sugar_distribution[cell.coordinate]
96
- max_spice = spice_distribution[cell.coordinate]
97
- Resource(self, max_sugar, max_spice, cell)
98
-
99
- for _ in range(self.initial_population):
100
- # get agent position
101
- x = self.random.randrange(self.width)
102
- y = self.random.randrange(self.height)
103
- # see Growing Artificial Societies p. 108 for initialization
104
- # give agents initial endowment
105
- sugar = int(self.random.uniform(self.endowment_min, self.endowment_max + 1))
106
- spice = int(self.random.uniform(self.endowment_min, self.endowment_max + 1))
107
- # give agents initial metabolism
108
- metabolism_sugar = int(
109
- self.random.uniform(self.metabolism_min, self.metabolism_max + 1)
110
- )
111
- metabolism_spice = int(
112
- self.random.uniform(self.metabolism_min, self.metabolism_max + 1)
113
- )
114
- # give agents vision
115
- vision = int(self.random.uniform(self.vision_min, self.vision_max + 1))
116
-
117
- cell = self.grid[(x, y)]
118
- # create Trader object
119
- Trader(
120
- self,
121
- cell,
122
- sugar=sugar,
123
- spice=spice,
124
- metabolism_sugar=metabolism_sugar,
125
- metabolism_spice=metabolism_spice,
126
- vision=vision,
127
- )
83
+ # read in landscape file from supplementary material
84
+ self.sugar_distribution = np.genfromtxt(Path(__file__).parent / "sugar-map.txt")
85
+ self.spice_distribution = np.flip(self.sugar_distribution, 1)
86
+
87
+ self.grid.add_property_layer(
88
+ PropertyLayer.from_data("sugar", self.sugar_distribution)
89
+ )
90
+ self.grid.add_property_layer(
91
+ PropertyLayer.from_data("spice", self.spice_distribution)
92
+ )
93
+
94
+ Trader.create_agents(
95
+ self,
96
+ initial_population,
97
+ self.random.choices(self.grid.all_cells.cells, k=initial_population),
98
+ sugar=self.rng.integers(
99
+ endowment_min, endowment_max, (initial_population,), endpoint=True
100
+ ),
101
+ spice=self.rng.integers(
102
+ endowment_min, endowment_max, (initial_population,), endpoint=True
103
+ ),
104
+ metabolism_sugar=self.rng.integers(
105
+ metabolism_min, metabolism_max, (initial_population,), endpoint=True
106
+ ),
107
+ metabolism_spice=self.rng.integers(
108
+ metabolism_min, metabolism_max, (initial_population,), endpoint=True
109
+ ),
110
+ vision=self.rng.integers(
111
+ vision_min, vision_max, (initial_population,), endpoint=True
112
+ ),
113
+ )
128
114
 
129
115
  def step(self):
130
116
  """
@@ -132,7 +118,12 @@ class SugarscapeG1mt(mesa.Model):
132
118
  and then randomly activates traders
133
119
  """
134
120
  # step Resource agents
135
- self.agents_by_type[Resource].do("step")
121
+ self.grid.sugar.data = np.minimum(
122
+ self.grid.sugar.data + 1, self.sugar_distribution
123
+ )
124
+ self.grid.spice.data = np.minimum(
125
+ self.grid.spice.data + 1, self.spice_distribution
126
+ )
136
127
 
137
128
  # step trader agents
138
129
  # to account for agent death and removal we need a separate data structure to
@@ -157,6 +148,8 @@ class SugarscapeG1mt(mesa.Model):
157
148
  agent.trade_with_neighbors()
158
149
 
159
150
  # collect model level data
151
+ # fixme we can already collect agent class data
152
+ # fixme, we don't have resource agents anymore so this can be done simpler
160
153
  self.datacollector.collect(self)
161
154
  """
162
155
  Mesa is working on updating datacollector agent reporter
@@ -4,7 +4,9 @@ from mesa.experimental.cell_space import CellAgent, FixedAgent
4
4
  class Animal(CellAgent):
5
5
  """The base animal class."""
6
6
 
7
- def __init__(self, model, energy, p_reproduce, energy_from_food, cell):
7
+ def __init__(
8
+ self, model, energy=8, p_reproduce=0.04, energy_from_food=4, cell=None
9
+ ):
8
10
  """Initialize an animal.
9
11
 
10
12
  Args:
@@ -90,22 +90,23 @@ class WolfSheep(Model):
90
90
  self.datacollector = DataCollector(model_reporters)
91
91
 
92
92
  # Create sheep:
93
- for _ in range(initial_sheep):
94
- pos = (
95
- self.random.randrange(width),
96
- self.random.randrange(height),
97
- )
98
- energy = self.random.randrange(2 * sheep_gain_from_food)
99
- Sheep(self, energy, sheep_reproduce, sheep_gain_from_food, self.grid[pos])
100
-
101
- # Create wolves
102
- for _ in range(initial_wolves):
103
- pos = (
104
- self.random.randrange(width),
105
- self.random.randrange(height),
106
- )
107
- energy = self.random.randrange(2 * wolf_gain_from_food)
108
- Wolf(self, energy, wolf_reproduce, wolf_gain_from_food, self.grid[pos])
93
+ Sheep.create_agents(
94
+ self,
95
+ initial_sheep,
96
+ energy=self.rng.random((initial_sheep,)) * 2 * sheep_gain_from_food,
97
+ p_reproduce=sheep_reproduce,
98
+ energy_from_food=sheep_gain_from_food,
99
+ cell=self.random.choices(self.grid.all_cells.cells, k=initial_sheep),
100
+ )
101
+ # Create Wolves:
102
+ Wolf.create_agents(
103
+ self,
104
+ initial_wolves,
105
+ energy=self.rng.random((initial_wolves,)) * 2 * wolf_gain_from_food,
106
+ p_reproduce=wolf_reproduce,
107
+ energy_from_food=wolf_gain_from_food,
108
+ cell=self.random.choices(self.grid.all_cells.cells, k=initial_wolves),
109
+ )
109
110
 
110
111
  # Create grass patches if enabled
111
112
  if grass:
@@ -12,6 +12,11 @@ def boid_draw(agent):
12
12
 
13
13
 
14
14
  model_params = {
15
+ "seed": {
16
+ "type": "InputText",
17
+ "value": 42,
18
+ "label": "Random Seed",
19
+ },
15
20
  "population": Slider(
16
21
  label="Number of boids",
17
22
  value=100,
@@ -1,10 +1,13 @@
1
1
  from mesa.examples.basic.boltzmann_wealth_model.model import BoltzmannWealth
2
+ from mesa.mesa_logging import DEBUG, log_to_stderr
2
3
  from mesa.visualization import (
3
4
  SolaraViz,
4
5
  make_plot_component,
5
6
  make_space_component,
6
7
  )
7
8
 
9
+ log_to_stderr(DEBUG)
10
+
8
11
 
9
12
  def agent_portrayal(agent):
10
13
  color = agent.wealth # we are using a colormap to translate wealth to color
@@ -12,6 +15,11 @@ def agent_portrayal(agent):
12
15
 
13
16
 
14
17
  model_params = {
18
+ "seed": {
19
+ "type": "InputText",
20
+ "value": 42,
21
+ "label": "Random Seed",
22
+ },
15
23
  "n": {
16
24
  "type": "SliderInt",
17
25
  "value": 50,
@@ -20,11 +28,6 @@ model_params = {
20
28
  "max": 100,
21
29
  "step": 1,
22
30
  },
23
- "seed": {
24
- "type": "InputText",
25
- "value": 42,
26
- "label": "Random Seed",
27
- },
28
31
  "width": 10,
29
32
  "height": 10,
30
33
  }
@@ -68,7 +68,7 @@ if run:
68
68
  for i in range(num_ticks):
69
69
  model.step()
70
70
  my_bar.progress((i / num_ticks), text="Simulation progress")
71
- placeholder.text("Step = %d" % i)
71
+ placeholder.text(f"Step = {i}")
72
72
  for cell in model.grid.coord_iter():
73
73
  cell_content, (x, y) = cell
74
74
  agent_count = len(cell_content)