Mesa 3.0.0a2__py3-none-any.whl → 3.0.0a4__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/time.py CHANGED
@@ -69,8 +69,6 @@ class BaseScheduler:
69
69
  self.model = model
70
70
  self.steps = 0
71
71
  self.time: TimeT = 0
72
- self._original_step = self.step
73
- self.step = self._wrapped_step
74
72
 
75
73
  if agents is None:
76
74
  agents = []
@@ -113,11 +111,6 @@ class BaseScheduler:
113
111
  self.steps += 1
114
112
  self.time += 1
115
113
 
116
- def _wrapped_step(self):
117
- """Wrapper for the step method to include time and step updating."""
118
- self._original_step()
119
- self.model._advance_time()
120
-
121
114
  def get_agent_count(self) -> int:
122
115
  """Returns the current number of agents in the queue."""
123
116
  return len(self._agents)
@@ -1,3 +1,14 @@
1
- from .solara_viz import JupyterViz, Slider, SolaraViz, make_text
1
+ from .components.altair import make_space_altair
2
+ from .components.matplotlib import make_plot_measure, make_space_matplotlib
3
+ from .solara_viz import JupyterViz, SolaraViz, make_text
4
+ from .UserParam import Slider
2
5
 
3
- __all__ = ["JupyterViz", "make_text", "Slider", "SolaraViz"]
6
+ __all__ = [
7
+ "JupyterViz",
8
+ "SolaraViz",
9
+ "make_text",
10
+ "Slider",
11
+ "make_space_altair",
12
+ "make_space_matplotlib",
13
+ "make_plot_measure",
14
+ ]
@@ -5,9 +5,24 @@ import solara
5
5
  with contextlib.suppress(ImportError):
6
6
  import altair as alt
7
7
 
8
+ from mesa.visualization.utils import update_counter
9
+
10
+
11
+ def make_space_altair(agent_portrayal=None):
12
+ if agent_portrayal is None:
13
+
14
+ def agent_portrayal(a):
15
+ return {"id": a.unique_id}
16
+
17
+ def MakeSpaceAltair(model):
18
+ return SpaceAltair(model, agent_portrayal)
19
+
20
+ return MakeSpaceAltair
21
+
8
22
 
9
23
  @solara.component
10
24
  def SpaceAltair(model, agent_portrayal, dependencies: list[any] | None = None):
25
+ update_counter.get()
11
26
  space = getattr(model, "grid", None)
12
27
  if space is None:
13
28
  # Sometimes the space is defined as model.space instead of model.grid
@@ -6,10 +6,25 @@ from matplotlib.figure import Figure
6
6
  from matplotlib.ticker import MaxNLocator
7
7
 
8
8
  import mesa
9
+ from mesa.experimental.cell_space import VoronoiGrid
10
+ from mesa.visualization.utils import update_counter
11
+
12
+
13
+ def make_space_matplotlib(agent_portrayal=None):
14
+ if agent_portrayal is None:
15
+
16
+ def agent_portrayal(a):
17
+ return {"id": a.unique_id}
18
+
19
+ def MakeSpaceMatplotlib(model):
20
+ return SpaceMatplotlib(model, agent_portrayal)
21
+
22
+ return MakeSpaceMatplotlib
9
23
 
10
24
 
11
25
  @solara.component
12
26
  def SpaceMatplotlib(model, agent_portrayal, dependencies: list[any] | None = None):
27
+ update_counter.get()
13
28
  space_fig = Figure()
14
29
  space_ax = space_fig.subplots()
15
30
  space = getattr(model, "grid", None)
@@ -20,6 +35,8 @@ def SpaceMatplotlib(model, agent_portrayal, dependencies: list[any] | None = Non
20
35
  _draw_network_grid(space, space_ax, agent_portrayal)
21
36
  elif isinstance(space, mesa.space.ContinuousSpace):
22
37
  _draw_continuous_space(space, space_ax, agent_portrayal)
38
+ elif isinstance(space, VoronoiGrid):
39
+ _draw_voronoi(space, space_ax, agent_portrayal)
23
40
  else:
24
41
  _draw_grid(space, space_ax, agent_portrayal)
25
42
  solara.FigureMatplotlib(space_fig, format="png", dependencies=dependencies)
@@ -150,8 +167,66 @@ def _draw_continuous_space(space, space_ax, agent_portrayal):
150
167
  _split_and_scatter(portray(space), space_ax)
151
168
 
152
169
 
170
+ def _draw_voronoi(space, space_ax, agent_portrayal):
171
+ def portray(g):
172
+ x = []
173
+ y = []
174
+ s = [] # size
175
+ c = [] # color
176
+
177
+ for cell in g.all_cells:
178
+ for agent in cell.agents:
179
+ data = agent_portrayal(agent)
180
+ x.append(cell.coordinate[0])
181
+ y.append(cell.coordinate[1])
182
+ if "size" in data:
183
+ s.append(data["size"])
184
+ if "color" in data:
185
+ c.append(data["color"])
186
+ out = {"x": x, "y": y}
187
+ # This is the default value for the marker size, which auto-scales
188
+ # according to the grid area.
189
+ out["s"] = s
190
+ if len(c) > 0:
191
+ out["c"] = c
192
+
193
+ return out
194
+
195
+ x_list = [i[0] for i in space.centroids_coordinates]
196
+ y_list = [i[1] for i in space.centroids_coordinates]
197
+ x_max = max(x_list)
198
+ x_min = min(x_list)
199
+ y_max = max(y_list)
200
+ y_min = min(y_list)
201
+
202
+ width = x_max - x_min
203
+ x_padding = width / 20
204
+ height = y_max - y_min
205
+ y_padding = height / 20
206
+ space_ax.set_xlim(x_min - x_padding, x_max + x_padding)
207
+ space_ax.set_ylim(y_min - y_padding, y_max + y_padding)
208
+ space_ax.scatter(**portray(space))
209
+
210
+ for cell in space.all_cells:
211
+ polygon = cell.properties["polygon"]
212
+ space_ax.fill(
213
+ *zip(*polygon),
214
+ alpha=min(1, cell.properties[space.cell_coloring_property]),
215
+ c="red",
216
+ ) # Plot filled polygon
217
+ space_ax.plot(*zip(*polygon), color="black") # Plot polygon edges in red
218
+
219
+
220
+ def make_plot_measure(measure: str | dict[str, str] | list[str] | tuple[str]):
221
+ def MakePlotMeasure(model):
222
+ return PlotMatplotlib(model, measure)
223
+
224
+ return MakePlotMeasure
225
+
226
+
153
227
  @solara.component
154
228
  def PlotMatplotlib(model, measure, dependencies: list[any] | None = None):
229
+ update_counter.get()
155
230
  fig = Figure()
156
231
  ax = fig.subplots()
157
232
  df = model.datacollector.get_model_vars_dataframe()
@@ -23,15 +23,20 @@ Usage:
23
23
  See the Visualization Tutorial and example models for more details.
24
24
  """
25
25
 
26
- import threading
26
+ import copy
27
+ import time
28
+ from typing import TYPE_CHECKING, Literal
27
29
 
28
- import reacton.ipywidgets as widgets
29
30
  import solara
30
31
  from solara.alias import rv
31
32
 
32
33
  import mesa.visualization.components.altair as components_altair
33
34
  import mesa.visualization.components.matplotlib as components_matplotlib
34
35
  from mesa.visualization.UserParam import Slider
36
+ from mesa.visualization.utils import force_update, update_counter
37
+
38
+ if TYPE_CHECKING:
39
+ from mesa.model import Model
35
40
 
36
41
 
37
42
  # TODO: Turn this function into a Solara component once the current_step.value
@@ -86,120 +91,56 @@ def Card(
86
91
 
87
92
  @solara.component
88
93
  def SolaraViz(
89
- model_class,
90
- model_params,
91
- measures=None,
92
- name=None,
93
- agent_portrayal=None,
94
- space_drawer="default",
95
- play_interval=150,
96
- seed=None,
94
+ model: "Model" | solara.Reactive["Model"],
95
+ components: list[solara.component] | Literal["default"] = "default",
96
+ *args,
97
+ play_interval=100,
98
+ model_params=None,
99
+ seed=0,
100
+ name: str | None = None,
97
101
  ):
98
- """
99
- Initialize a component to visualize a model.
100
-
101
- Args:
102
- model_class: Class of the model to instantiate
103
- model_params: Parameters for initializing the model
104
- measures: List of callables or data attributes to plot
105
- name: Name for display
106
- agent_portrayal: Options for rendering agents (dictionary);
107
- Default drawer supports custom `"size"`, `"color"`, and `"shape"`.
108
- space_drawer: Method to render the agent space for
109
- the model; default implementation is the `SpaceMatplotlib` component;
110
- simulations with no space to visualize should
111
- specify `space_drawer=False`
112
- play_interval: Play interval (default: 150)
113
- seed: The random seed used to initialize the model
114
- """
115
- if name is None:
116
- name = model_class.__name__
102
+ update_counter.get()
103
+ if components == "default":
104
+ components = [components_altair.make_space_altair()]
117
105
 
118
- current_step = solara.use_reactive(0)
106
+ # Convert model to reactive
107
+ if not isinstance(model, solara.Reactive):
108
+ model = solara.use_reactive(model)
119
109
 
120
- # 1. Set up model parameters
121
- reactive_seed = solara.use_reactive(0)
122
- user_params, fixed_params = split_model_params(model_params)
123
- model_parameters, set_model_parameters = solara.use_state(
124
- {**fixed_params, **{k: v.get("value") for k, v in user_params.items()}}
125
- )
110
+ def connect_to_model():
111
+ # Patch the step function to force updates
112
+ original_step = model.value.step
126
113
 
127
- # 2. Set up Model
128
- def make_model():
129
- """Create a new model instance with current parameters and seed."""
130
- model = model_class.__new__(
131
- model_class, **model_parameters, seed=reactive_seed.value
132
- )
133
- model.__init__(**model_parameters)
134
- current_step.value = 0
135
- return model
136
-
137
- reset_counter = solara.use_reactive(0)
138
- model = solara.use_memo(
139
- make_model,
140
- dependencies=[
141
- *list(model_parameters.values()),
142
- reset_counter.value,
143
- reactive_seed.value,
144
- ],
145
- )
114
+ def step():
115
+ original_step()
116
+ force_update()
146
117
 
147
- def handle_change_model_params(name: str, value: any):
148
- """Update model parameters when user input changes."""
149
- set_model_parameters({**model_parameters, name: value})
118
+ model.value.step = step
119
+ # Add a trigger to model itself
120
+ model.value.force_update = force_update
121
+ force_update()
150
122
 
151
- # 3. Set up UI
123
+ solara.use_effect(connect_to_model, [model.value])
152
124
 
153
125
  with solara.AppBar():
154
- solara.AppBarTitle(name)
155
-
156
- # render layout and plot
157
- def do_reseed():
158
- """Update the random seed for the model."""
159
- reactive_seed.value = model.random.random()
160
-
161
- dependencies = [current_step.value, reactive_seed.value]
162
-
163
- # if space drawer is disabled, do not include it
164
- layout_types = [{"Space": "default"}] if space_drawer else []
165
-
166
- if measures:
167
- layout_types += [{"Measure": elem} for elem in range(len(measures))]
168
-
169
- grid_layout_initial = make_initial_grid_layout(layout_types=layout_types)
170
- grid_layout, set_grid_layout = solara.use_state(grid_layout_initial)
126
+ solara.AppBarTitle(name if name else model.value.__class__.__name__)
171
127
 
172
128
  with solara.Sidebar():
173
129
  with solara.Card("Controls", margin=1, elevation=2):
174
- solara.InputText(
175
- label="Seed",
176
- value=reactive_seed,
177
- continuous_update=True,
178
- )
179
- UserInputs(user_params, on_change=handle_change_model_params)
180
- ModelController(model, play_interval, current_step, reset_counter)
181
- solara.Button(label="Reseed", color="primary", on_click=do_reseed)
130
+ if model_params is not None:
131
+ ModelCreator(
132
+ model,
133
+ model_params,
134
+ seed=seed,
135
+ )
136
+ ModelController(model, play_interval)
182
137
  with solara.Card("Information", margin=1, elevation=2):
183
- solara.Markdown(md_text=f"Step - {current_step}")
184
-
185
- items = [
186
- Card(
187
- model,
188
- measures,
189
- agent_portrayal,
190
- space_drawer,
191
- dependencies,
192
- color="white",
193
- layout_type=layout_types[i],
194
- )
195
- for i in range(len(layout_types))
196
- ]
197
- solara.GridDraggable(
198
- items=items,
199
- grid_layout=grid_layout,
200
- resizable=True,
201
- draggable=True,
202
- on_grid_layout=set_grid_layout,
138
+ ShowSteps(model.value)
139
+
140
+ solara.Column(
141
+ [
142
+ *(component(model.value) for component in components),
143
+ ]
203
144
  )
204
145
 
205
146
 
@@ -207,107 +148,57 @@ JupyterViz = SolaraViz
207
148
 
208
149
 
209
150
  @solara.component
210
- def ModelController(model, play_interval, current_step, reset_counter):
151
+ def ModelController(model: solara.Reactive["Model"], play_interval=100):
211
152
  """
212
153
  Create controls for model execution (step, play, pause, reset).
213
154
 
214
155
  Args:
215
- model: The model being visualized
156
+ model: The reactive model being visualized
216
157
  play_interval: Interval between steps during play
217
- current_step: Reactive value for the current step
218
- reset_counter: Counter to trigger model reset
219
158
  """
159
+ if not isinstance(model, solara.Reactive):
160
+ model = solara.use_reactive(model)
161
+
220
162
  playing = solara.use_reactive(False)
221
- thread = solara.use_reactive(None)
222
- # We track the previous step to detect if user resets the model via
223
- # clicking the reset button or changing the parameters. If previous_step >
224
- # current_step, it means a model reset happens while the simulation is
225
- # still playing.
226
- previous_step = solara.use_reactive(0)
227
-
228
- def on_value_play(change):
229
- """Handle play/pause state changes."""
230
- if previous_step.value > current_step.value and current_step.value == 0:
231
- # We add extra checks for current_step.value == 0, just to be sure.
232
- # We automatically stop the playing if a model is reset.
233
- playing.value = False
234
- elif model.running:
163
+ original_model = solara.use_reactive(None)
164
+
165
+ def save_initial_model():
166
+ """Save the initial model for comparison."""
167
+ original_model.set(copy.deepcopy(model.value))
168
+ playing.value = False
169
+ force_update()
170
+
171
+ solara.use_effect(save_initial_model, [model.value])
172
+
173
+ def step():
174
+ while playing.value:
175
+ time.sleep(play_interval / 1000)
235
176
  do_step()
236
- else:
237
- playing.value = False
177
+
178
+ solara.use_thread(step, [playing.value])
238
179
 
239
180
  def do_step():
240
181
  """Advance the model by one step."""
241
- model.step()
242
- previous_step.value = current_step.value
243
- current_step.value = model._steps
182
+ model.value.step()
244
183
 
245
184
  def do_play():
246
185
  """Run the model continuously."""
247
- model.running = True
248
- while model.running:
249
- do_step()
250
-
251
- def threaded_do_play():
252
- """Start a new thread for continuous model execution."""
253
- if thread is not None and thread.is_alive():
254
- return
255
- thread.value = threading.Thread(target=do_play)
256
- thread.start()
186
+ playing.value = True
257
187
 
258
188
  def do_pause():
259
189
  """Pause the model execution."""
260
- if (thread is None) or (not thread.is_alive()):
261
- return
262
- model.running = False
263
- thread.join()
190
+ playing.value = False
264
191
 
265
192
  def do_reset():
266
- """Reset the model."""
267
- reset_counter.value += 1
268
-
269
- def do_set_playing(value):
270
- """Set the playing state."""
271
- if current_step.value == 0:
272
- # This means the model has been recreated, and the step resets to
273
- # 0. We want to avoid triggering the playing.value = False in the
274
- # on_value_play function.
275
- previous_step.value = current_step.value
276
- playing.set(value)
277
-
278
- with solara.Row():
279
- solara.Button(label="Step", color="primary", on_click=do_step)
280
- # This style is necessary so that the play widget has almost the same
281
- # height as typical Solara buttons.
282
- solara.Style(
283
- """
284
- .widget-play {
285
- height: 35px;
286
- }
287
- .widget-play button {
288
- color: white;
289
- background-color: #1976D2; // Solara blue color
290
- }
291
- """
292
- )
293
- widgets.Play(
294
- value=0,
295
- interval=play_interval,
296
- repeat=True,
297
- show_repeat=False,
298
- on_value=on_value_play,
299
- playing=playing.value,
300
- on_playing=do_set_playing,
301
- )
193
+ """Reset the model to its initial state."""
194
+ playing.value = False
195
+ model.value = copy.deepcopy(original_model.value)
196
+
197
+ with solara.Row(justify="space-between"):
302
198
  solara.Button(label="Reset", color="primary", on_click=do_reset)
303
- # threaded_do_play is not used for now because it
304
- # doesn't work in Google colab. We use
305
- # ipywidgets.Play until it is fixed. The threading
306
- # version is definite a much better implementation,
307
- # if it works.
308
- # solara.Button(label="▶", color="primary", on_click=viz.threaded_do_play)
309
- # solara.Button(label="⏸︎", color="primary", on_click=viz.do_pause)
310
- # solara.Button(label="Reset", color="primary", on_click=do_reset)
199
+ solara.Button(label="Step", color="primary", on_click=do_step)
200
+ solara.Button(label="▶", color="primary", on_click=do_play)
201
+ solara.Button(label="⏸︎", color="primary", on_click=do_pause)
311
202
 
312
203
 
313
204
  def split_model_params(model_params):
@@ -348,6 +239,45 @@ def check_param_is_fixed(param):
348
239
  return True
349
240
 
350
241
 
242
+ @solara.component
243
+ def ModelCreator(model, model_params, seed=1):
244
+ user_params, fixed_params = split_model_params(model_params)
245
+
246
+ reactive_seed = solara.use_reactive(seed)
247
+
248
+ model_parameters, set_model_parameters = solara.use_state(
249
+ {
250
+ **fixed_params,
251
+ **{k: v.get("value") for k, v in user_params.items()},
252
+ }
253
+ )
254
+
255
+ def do_reseed():
256
+ """Update the random seed for the model."""
257
+ reactive_seed.value = model.value.random.random()
258
+
259
+ def on_change(name, value):
260
+ set_model_parameters({**model_parameters, name: value})
261
+
262
+ def create_model():
263
+ model.value = model.value.__class__.__new__(
264
+ model.value.__class__, **model_parameters, seed=reactive_seed.value
265
+ )
266
+ model.value.__init__(**model_parameters)
267
+
268
+ solara.use_effect(create_model, [model_parameters, reactive_seed.value])
269
+
270
+ solara.InputText(
271
+ label="Seed",
272
+ value=reactive_seed,
273
+ continuous_update=True,
274
+ )
275
+
276
+ solara.Button(label="Reseed", color="primary", on_click=do_reseed)
277
+
278
+ UserInputs(user_params, on_change=on_change)
279
+
280
+
351
281
  @solara.component
352
282
  def UserInputs(user_params, on_change=None):
353
283
  """
@@ -456,3 +386,9 @@ def make_initial_grid_layout(layout_types):
456
386
  }
457
387
  for i in range(len(layout_types))
458
388
  ]
389
+
390
+
391
+ @solara.component
392
+ def ShowSteps(model):
393
+ update_counter.get()
394
+ return solara.Text(f"Step: {model.steps}")
@@ -0,0 +1,7 @@
1
+ import solara
2
+
3
+ update_counter = solara.reactive(0)
4
+
5
+
6
+ def force_update():
7
+ update_counter.value += 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: Mesa
3
- Version: 3.0.0a2
3
+ Version: 3.0.0a4
4
4
  Summary: Agent-based modeling (ABM) in Python
5
5
  Project-URL: homepage, https://github.com/projectmesa/mesa
6
6
  Project-URL: repository, https://github.com/projectmesa/mesa
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
17
17
  Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
20
21
  Classifier: Topic :: Scientific/Engineering
21
22
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
23
  Classifier: Topic :: Scientific/Engineering :: Artificial Life
@@ -42,6 +43,9 @@ Requires-Dist: myst-parser; extra == 'docs'
42
43
  Requires-Dist: pydata-sphinx-theme; extra == 'docs'
43
44
  Requires-Dist: seaborn; extra == 'docs'
44
45
  Requires-Dist: sphinx; extra == 'docs'
46
+ Provides-Extra: examples
47
+ Requires-Dist: pytest>=4.6; extra == 'examples'
48
+ Requires-Dist: scipy; extra == 'examples'
45
49
  Description-Content-Type: text/markdown
46
50
 
47
51
  # Mesa: Agent-based modeling in Python
@@ -98,15 +102,18 @@ Or any other (development) branch on this repo or your own fork:
98
102
  pip install -U -e git+https://github.com/YOUR_FORK/mesa@YOUR_BRANCH#egg=mesa
99
103
  ```
100
104
 
105
+ ## Resources
101
106
  For resources or help on using Mesa, check out the following:
102
107
 
103
108
  - [Intro to Mesa Tutorial](http://mesa.readthedocs.org/en/stable/tutorials/intro_tutorial.html) (An introductory model, the Boltzmann
104
109
  Wealth Model, for beginners or those new to Mesa.)
110
+ - [Visualization Tutorial](https://mesa.readthedocs.io/en/stable/tutorials/visualization_tutorial.html) (An introduction into our Solara visualization)
105
111
  - [Complexity Explorer Tutorial](https://www.complexityexplorer.org/courses/172-agent-based-models-with-python-an-introduction-to-mesa) (An advanced-beginner model,
106
112
  SugarScape with Traders, with instructional videos)
107
113
  - [Mesa Examples](https://github.com/projectmesa/mesa-examples/tree/main/examples) (A repository of seminal ABMs using Mesa and
108
114
  examples of employing specific Mesa Features)
109
115
  - [Docs](http://mesa.readthedocs.org/) (Mesa's documentation, API and useful snippets)
116
+ - [Development version docs](https://mesa.readthedocs.io/en/latest/) (the latest version docs if you're using a pre-release Mesa version)
110
117
  - [Discussions](https://github.com/projectmesa/mesa/discussions) (GitHub threaded discussions about Mesa)
111
118
  - [Matrix Chat](https://matrix.to/#/#project-mesa:matrix.org) (Chat Forum via Matrix to talk about Mesa)
112
119
 
@@ -0,0 +1,44 @@
1
+ mesa/__init__.py,sha256=UIq0dHx3cmtSSVuVFYYLpYS1rzbfn_tcT7vbqo1XLa0,618
2
+ mesa/agent.py,sha256=45KS_Cus2Yu-2g5moA8W6ntLWPKNnj9jUeNZiO4NqoI,22920
3
+ mesa/batchrunner.py,sha256=-n5mtNGWuKkE0kxWVenXw8b4LXe_LVAZ3rNEBcR2l1A,6097
4
+ mesa/datacollection.py,sha256=WUpZoFC2ZdLtKZ0oTwZTqraoP_yNx_yQY9pxO0TR8y0,11442
5
+ mesa/main.py,sha256=7MovfNz88VWNnfXP0kcERB6C3GfkVOh0hb0o32hM9LU,1602
6
+ mesa/model.py,sha256=_z_aPVu3ADJHZZD7YavBG7fdCYaDQqpkVNEcatWMM90,8551
7
+ mesa/space.py,sha256=5St5E26Np_b_fWv-_NEH82ZU0H3C9xHBAschRJtPpng,62698
8
+ mesa/time.py,sha256=53VX0x8zujaq32R6w_aBv1NmLpWO_h5K5BQTaK4mO3Q,14960
9
+ mesa/cookiecutter-mesa/cookiecutter.json,sha256=tBSWli39fOWUXGfiDCTKd92M7uKaBIswXbkOdbUufYY,337
10
+ mesa/cookiecutter-mesa/hooks/post_gen_project.py,sha256=8JoXZKIioRYEWJURC0udj8WS3rg0c4So62sOZSGbrMY,294
11
+ mesa/cookiecutter-mesa/{{cookiecutter.snake}}/README.md,sha256=Yji4lGY-NtQSnW-oBj0_Jhs-XhCfZA8R1mBBM_IllGs,80
12
+ mesa/cookiecutter-mesa/{{cookiecutter.snake}}/app.pytemplate,sha256=36f9k9CH6TK6VrXsPvTFXGUfCKzCLwgYTeK-Gt27GNg,584
13
+ mesa/cookiecutter-mesa/{{cookiecutter.snake}}/setup.pytemplate,sha256=UtRpLM_CkeUZRec-Ef_LiO_x7SKaWN11fOiH9T1UmTw,214
14
+ mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate,sha256=Aml4Z6E1yj7E7DtHNSUqnKNRUdkxG9WWtJyW8fkxCng,1870
16
+ mesa/experimental/UserParam.py,sha256=WgnY3Q0padtGqUCaezgYzd6cZ7LziuIQnGKP3DBuHZY,1641
17
+ mesa/experimental/__init__.py,sha256=8KfQcTMv9HJEAjmK5A_KdnFYfoY0nHAz97G_JLJVMNM,183
18
+ mesa/experimental/solara_viz.py,sha256=WXQY4b5jLp_ABvhV2df6yerDIijBzns3pXd4hCl5fAA,15253
19
+ mesa/experimental/cell_space/__init__.py,sha256=gXntv_Ie13SIegBumJNaIPcTUmTQLb4LlGd1JxoIn9M,708
20
+ mesa/experimental/cell_space/cell.py,sha256=AUnvVnXWhdgzr0bLKDRDO9c93v22Zkw6W-tWxhEhGdQ,4578
21
+ mesa/experimental/cell_space/cell_agent.py,sha256=Q3SoeK8Af7p4bdcm_E6Hr2uiHCSRsXYvttPUAOo4lRs,1080
22
+ mesa/experimental/cell_space/cell_collection.py,sha256=4FmfDEg9LoFiJ0mF_nC8KUt9fCJ7Q21erjWPeBTQ_lw,2293
23
+ mesa/experimental/cell_space/discrete_space.py,sha256=ta__YojsrrhWL4DgMzUqZpSgbeexKMrA6bxlYPJGfK0,1921
24
+ mesa/experimental/cell_space/grid.py,sha256=gYDExuFBMF3OThUkhbXmolQFKBOqTukcibjfgXicP00,6948
25
+ mesa/experimental/cell_space/network.py,sha256=mAaFHBdd4s9kxUWHbViovLW2-pU2yXH0dtY_vF8sCJg,1179
26
+ mesa/experimental/cell_space/voronoi.py,sha256=swwfV1Hfi7wp3XfM-rb9Lq5H0yAPH9zohZnXzU8SiHM,9997
27
+ mesa/experimental/components/altair.py,sha256=V2CQ-Zr7PeijgWtYBNH3VklGVfrf1ee70XVh0DBBONQ,2366
28
+ mesa/experimental/components/matplotlib.py,sha256=J61gHkXd37XyZiNLGF1NaQPOYqDdh9tpSfbOzMqK3dI,7570
29
+ mesa/experimental/devs/__init__.py,sha256=CWam15vCj-RD_biMyqv4sJfos1fsL823P7MDEGrbwW8,174
30
+ mesa/experimental/devs/eventlist.py,sha256=nyUFNDWnnSPQnrMtj7Qj1PexxKyOwSJuIGBoxtSwVI0,5269
31
+ mesa/experimental/devs/simulator.py,sha256=0SMC7daIOyL2rYfoQOOTaTOYDos0gLeBUbU1Krd42HA,9557
32
+ mesa/experimental/devs/examples/epstein_civil_violence.py,sha256=wCquOwcNYc--DYGM9Vg4YGx1Kh--HRhSVGjGgzT4k-I,9491
33
+ mesa/experimental/devs/examples/wolf_sheep.py,sha256=Hz3sExzjKEzrkFcE2gd7p7a0Ubg-QBGrV-4XQYWgt3c,7501
34
+ mesa/visualization/UserParam.py,sha256=WgnY3Q0padtGqUCaezgYzd6cZ7LziuIQnGKP3DBuHZY,1641
35
+ mesa/visualization/__init__.py,sha256=T_3QNz9BVuyfcbcMK_2RGGfMYhB7J-8XtaVPViXm1OU,372
36
+ mesa/visualization/solara_viz.py,sha256=8eQ-4dTYWuP0fmoaRMV3QqA1DL0tG0wPLmLAiYiiDO0,12188
37
+ mesa/visualization/utils.py,sha256=ade9YVhKx3gEaqDySj4YeSixTOHWGjzIIFDPGXL4uAs,103
38
+ mesa/visualization/components/altair.py,sha256=2VE4yRHrvBNXpDQUPuj0ejsPU0v3BqSzkphjbIcqzoc,2707
39
+ mesa/visualization/components/matplotlib.py,sha256=v-XwsChqWy9ukLe3zi-Q93UBUF20lxTB7lwckX4pB3M,8138
40
+ mesa-3.0.0a4.dist-info/METADATA,sha256=2DMGHgOya24WeUxtyEsBY1rzGlFxVkMZ2bcKFXeCZRw,8339
41
+ mesa-3.0.0a4.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
42
+ mesa-3.0.0a4.dist-info/entry_points.txt,sha256=IOcQtetGF8l4wHpOs_hGb19Rz-FS__BMXOJR10IBPsA,39
43
+ mesa-3.0.0a4.dist-info/licenses/LICENSE,sha256=OGUgret9fRrm8J3pdsPXETIjf0H8puK_Nmy970ZzT78,572
44
+ mesa-3.0.0a4.dist-info/RECORD,,