Mesa 3.0.0a3__py3-none-any.whl → 3.0.0a5__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 (40) hide show
  1. mesa/__init__.py +2 -3
  2. mesa/agent.py +193 -75
  3. mesa/batchrunner.py +18 -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 +67 -0
  8. mesa/experimental/__init__.py +5 -1
  9. mesa/experimental/cell_space/__init__.py +7 -0
  10. mesa/experimental/cell_space/cell.py +61 -20
  11. mesa/experimental/cell_space/cell_agent.py +12 -7
  12. mesa/experimental/cell_space/cell_collection.py +54 -17
  13. mesa/experimental/cell_space/discrete_space.py +16 -5
  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 +81 -0
  18. mesa/experimental/components/matplotlib.py +242 -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 +71 -39
  22. mesa/experimental/devs/examples/wolf_sheep.py +43 -44
  23. mesa/experimental/devs/simulator.py +55 -15
  24. mesa/experimental/solara_viz.py +453 -0
  25. mesa/main.py +6 -4
  26. mesa/model.py +64 -61
  27. mesa/space.py +154 -123
  28. mesa/time.py +57 -67
  29. mesa/visualization/UserParam.py +19 -6
  30. mesa/visualization/__init__.py +14 -2
  31. mesa/visualization/components/altair.py +18 -1
  32. mesa/visualization/components/matplotlib.py +26 -2
  33. mesa/visualization/solara_viz.py +231 -225
  34. mesa/visualization/utils.py +9 -0
  35. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/METADATA +2 -1
  36. mesa-3.0.0a5.dist-info/RECORD +44 -0
  37. mesa-3.0.0a3.dist-info/RECORD +0 -39
  38. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/WHEEL +0 -0
  39. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/entry_points.txt +0 -0
  40. {mesa-3.0.0a3.dist-info → mesa-3.0.0a5.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,4 @@
1
- """
2
- Mesa visualization module for creating interactive model visualizations.
1
+ """Mesa visualization module for creating interactive model visualizations.
3
2
 
4
3
  This module provides components to create browser- and Jupyter notebook-based visualizations of
5
4
  Mesa models, allowing users to watch models run step-by-step and interact with model parameters.
@@ -8,7 +7,6 @@ Key features:
8
7
  - SolaraViz: Main component for creating visualizations, supporting grid displays and plots
9
8
  - ModelController: Handles model execution controls (step, play, pause, reset)
10
9
  - UserInputs: Generates UI elements for adjusting model parameters
11
- - Card: Renders individual visualization elements (space, measures)
12
10
 
13
11
  The module uses Solara for rendering in Jupyter notebooks or as standalone web applications.
14
12
  It supports various types of visualizations including matplotlib plots, agent grids, and
@@ -23,15 +21,24 @@ Usage:
23
21
  See the Visualization Tutorial and example models for more details.
24
22
  """
25
23
 
26
- import threading
24
+ from __future__ import annotations
25
+
26
+ import asyncio
27
+ import copy
28
+ from collections.abc import Callable
29
+ from typing import TYPE_CHECKING, Literal
27
30
 
28
- import reacton.ipywidgets as widgets
31
+ import reacton.core
29
32
  import solara
30
33
  from solara.alias import rv
31
34
 
32
35
  import mesa.visualization.components.altair as components_altair
33
36
  import mesa.visualization.components.matplotlib as components_matplotlib
34
37
  from mesa.visualization.UserParam import Slider
38
+ from mesa.visualization.utils import force_update, update_counter
39
+
40
+ if TYPE_CHECKING:
41
+ from mesa.model import Model
35
42
 
36
43
 
37
44
  # TODO: Turn this function into a Solara component once the current_step.value
@@ -39,8 +46,7 @@ from mesa.visualization.UserParam import Slider
39
46
  def Card(
40
47
  model, measures, agent_portrayal, space_drawer, dependencies, color, layout_type
41
48
  ):
42
- """
43
- Create a card component for visualizing model space or measures.
49
+ """Create a card component for visualizing model space or measures.
44
50
 
45
51
  Args:
46
52
  model: The Mesa model instance
@@ -86,237 +92,183 @@ def Card(
86
92
 
87
93
  @solara.component
88
94
  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,
95
+ model: Model | solara.Reactive[Model],
96
+ components: list[reacton.core.Component]
97
+ | list[Callable[[Model], reacton.core.Component]]
98
+ | Literal["default"] = "default",
99
+ play_interval: int = 100,
100
+ model_params=None,
101
+ seed: float = 0,
102
+ name: str | None = None,
97
103
  ):
98
- """
99
- Initialize a component to visualize a model.
104
+ """Solara visualization component.
105
+
106
+ This component provides a visualization interface for a given model using Solara.
107
+ It supports various visualization components and allows for interactive model
108
+ stepping and parameter adjustments.
100
109
 
101
110
  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
111
+ model (Model | solara.Reactive[Model]): A Model instance or a reactive Model.
112
+ This is the main model to be visualized. If a non-reactive model is provided,
113
+ it will be converted to a reactive model.
114
+ components (list[solara.component] | Literal["default"], optional): List of solara
115
+ components or functions that return a solara component.
116
+ These components are used to render different parts of the model visualization.
117
+ Defaults to "default", which uses the default Altair space visualization.
118
+ play_interval (int, optional): Interval for playing the model steps in milliseconds.
119
+ This controls the speed of the model's automatic stepping. Defaults to 100 ms.
120
+ model_params (dict, optional): Parameters for (re-)instantiating a model.
121
+ Can include user-adjustable parameters and fixed parameters. Defaults to None.
122
+ seed (int, optional): Seed for the random number generator. This ensures reproducibility
123
+ of the model's behavior. Defaults to 0.
124
+ name (str | None, optional): Name of the visualization. Defaults to the models class name.
125
+
126
+ Returns:
127
+ solara.component: A Solara component that renders the visualization interface for the model.
128
+
129
+ Example:
130
+ >>> model = MyModel()
131
+ >>> page = SolaraViz(model)
132
+ >>> page
133
+
134
+ Notes:
135
+ - The `model` argument can be either a direct model instance or a reactive model. If a direct
136
+ model instance is provided, it will be converted to a reactive model using `solara.use_reactive`.
137
+ - The `play_interval` argument controls the speed of the model's automatic stepping. A lower
138
+ value results in faster stepping, while a higher value results in slower stepping.
114
139
  """
115
- if name is None:
116
- name = model_class.__name__
140
+ if components == "default":
141
+ components = [components_altair.make_space_altair()]
117
142
 
118
- current_step = solara.use_reactive(0)
143
+ # Convert model to reactive
144
+ if not isinstance(model, solara.Reactive):
145
+ model = solara.use_reactive(model) # noqa: SH102, RUF100
119
146
 
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
- )
147
+ def connect_to_model():
148
+ # Patch the step function to force updates
149
+ original_step = model.value.step
126
150
 
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
- )
151
+ def step():
152
+ original_step()
153
+ force_update()
146
154
 
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})
155
+ model.value.step = step
156
+ # Add a trigger to model itself
157
+ model.value.force_update = force_update
158
+ force_update()
150
159
 
151
- # 3. Set up UI
160
+ solara.use_effect(connect_to_model, [model.value])
152
161
 
153
162
  with solara.AppBar():
154
- solara.AppBarTitle(name)
163
+ solara.AppBarTitle(name if name else model.value.__class__.__name__)
164
+
165
+ with solara.Sidebar(), solara.Column():
166
+ with solara.Card("Controls"):
167
+ ModelController(model, play_interval)
168
+
169
+ if model_params is not None:
170
+ with solara.Card("Model Parameters"):
171
+ ModelCreator(
172
+ model,
173
+ model_params,
174
+ seed=seed,
175
+ )
176
+ with solara.Card("Information"):
177
+ ShowSteps(model.value)
155
178
 
156
- # render layout and plot
157
- def do_reseed():
158
- """Update the random seed for the model."""
159
- reactive_seed.value = model.random.random()
179
+ ComponentsView(components, model.value)
160
180
 
161
- dependencies = [
162
- *list(model_parameters.values()),
163
- current_step.value,
164
- reactive_seed.value,
165
- ]
166
181
 
167
- # if space drawer is disabled, do not include it
168
- layout_types = [{"Space": "default"}] if space_drawer else []
182
+ def _wrap_component(
183
+ component: reacton.core.Component | Callable[[Model], reacton.core.Component],
184
+ ) -> reacton.core.Component:
185
+ """Wrap a component in an auto-updated Solara component if needed."""
186
+ if isinstance(component, reacton.core.Component):
187
+ return component
169
188
 
170
- if measures:
171
- layout_types += [{"Measure": elem} for elem in range(len(measures))]
189
+ @solara.component
190
+ def WrappedComponent(model):
191
+ update_counter.get()
192
+ return component(model)
172
193
 
173
- grid_layout_initial = make_initial_grid_layout(layout_types=layout_types)
174
- grid_layout, set_grid_layout = solara.use_state(grid_layout_initial)
194
+ return WrappedComponent
175
195
 
176
- with solara.Sidebar():
177
- with solara.Card("Controls", margin=1, elevation=2):
178
- solara.InputText(
179
- label="Seed",
180
- value=reactive_seed,
181
- continuous_update=True,
182
- )
183
- UserInputs(user_params, on_change=handle_change_model_params)
184
- ModelController(model, play_interval, current_step, reset_counter)
185
- solara.Button(label="Reseed", color="primary", on_click=do_reseed)
186
- with solara.Card("Information", margin=1, elevation=2):
187
- solara.Markdown(md_text=f"Step - {current_step}")
188
-
189
- items = [
190
- Card(
191
- model,
192
- measures,
193
- agent_portrayal,
194
- space_drawer,
195
- dependencies,
196
- color="white",
197
- layout_type=layout_types[i],
198
- )
199
- for i in range(len(layout_types))
200
- ]
201
- solara.GridDraggable(
202
- items=items,
203
- grid_layout=grid_layout,
204
- resizable=True,
205
- draggable=True,
206
- on_grid_layout=set_grid_layout,
207
- )
196
+
197
+ @solara.component
198
+ def ComponentsView(
199
+ components: list[reacton.core.Component]
200
+ | list[Callable[[Model], reacton.core.Component]],
201
+ model: Model,
202
+ ):
203
+ """Display a list of components.
204
+
205
+ Args:
206
+ components: List of components to display
207
+ model: Model instance to pass to each component
208
+ """
209
+ wrapped_components = [_wrap_component(component) for component in components]
210
+
211
+ with solara.Column():
212
+ for component in wrapped_components:
213
+ component(model)
208
214
 
209
215
 
210
216
  JupyterViz = SolaraViz
211
217
 
212
218
 
213
219
  @solara.component
214
- def ModelController(model, play_interval, current_step, reset_counter):
215
- """
216
- Create controls for model execution (step, play, pause, reset).
220
+ def ModelController(model: solara.Reactive[Model], play_interval=100):
221
+ """Create controls for model execution (step, play, pause, reset).
217
222
 
218
223
  Args:
219
- model: The model being visualized
220
- play_interval: Interval between steps during play
221
- current_step: Reactive value for the current step
222
- reset_counter: Counter to trigger model reset
224
+ model (solara.Reactive[Model]): Reactive model instance
225
+ play_interval (int, optional): Interval for playing the model steps in milliseconds.
223
226
  """
224
227
  playing = solara.use_reactive(False)
225
- thread = solara.use_reactive(None)
226
- # We track the previous step to detect if user resets the model via
227
- # clicking the reset button or changing the parameters. If previous_step >
228
- # current_step, it means a model reset happens while the simulation is
229
- # still playing.
230
- previous_step = solara.use_reactive(0)
231
-
232
- def on_value_play(change):
233
- """Handle play/pause state changes."""
234
- if previous_step.value > current_step.value and current_step.value == 0:
235
- # We add extra checks for current_step.value == 0, just to be sure.
236
- # We automatically stop the playing if a model is reset.
237
- playing.value = False
238
- elif model.running:
228
+ original_model = solara.use_reactive(None)
229
+
230
+ def save_initial_model():
231
+ """Save the initial model for comparison."""
232
+ original_model.set(copy.deepcopy(model.value))
233
+ playing.value = False
234
+ force_update()
235
+
236
+ solara.use_effect(save_initial_model, [model.value])
237
+
238
+ async def step():
239
+ while playing.value:
240
+ await asyncio.sleep(play_interval / 1000)
239
241
  do_step()
240
- else:
241
- playing.value = False
242
+
243
+ solara.lab.use_task(step, dependencies=[playing.value], prefer_threaded=False)
242
244
 
243
245
  def do_step():
244
246
  """Advance the model by one step."""
245
- model.step()
246
- previous_step.value = current_step.value
247
- current_step.value = model.steps
248
-
249
- def do_play():
250
- """Run the model continuously."""
251
- model.running = True
252
- while model.running:
253
- do_step()
247
+ model.value.step()
254
248
 
255
- def threaded_do_play():
256
- """Start a new thread for continuous model execution."""
257
- if thread is not None and thread.is_alive():
258
- return
259
- thread.value = threading.Thread(target=do_play)
260
- thread.start()
249
+ def do_reset():
250
+ """Reset the model to its initial state."""
251
+ playing.value = False
252
+ model.value = copy.deepcopy(original_model.value)
261
253
 
262
- def do_pause():
263
- """Pause the model execution."""
264
- if (thread is None) or (not thread.is_alive()):
265
- return
266
- model.running = False
267
- thread.join()
254
+ def do_play_pause():
255
+ """Toggle play/pause."""
256
+ playing.value = not playing.value
268
257
 
269
- def do_reset():
270
- """Reset the model."""
271
- reset_counter.value += 1
272
-
273
- def do_set_playing(value):
274
- """Set the playing state."""
275
- if current_step.value == 0:
276
- # This means the model has been recreated, and the step resets to
277
- # 0. We want to avoid triggering the playing.value = False in the
278
- # on_value_play function.
279
- previous_step.value = current_step.value
280
- playing.set(value)
281
-
282
- with solara.Row():
283
- solara.Button(label="Step", color="primary", on_click=do_step)
284
- # This style is necessary so that the play widget has almost the same
285
- # height as typical Solara buttons.
286
- solara.Style(
287
- """
288
- .widget-play {
289
- height: 35px;
290
- }
291
- .widget-play button {
292
- color: white;
293
- background-color: #1976D2; // Solara blue color
294
- }
295
- """
258
+ with solara.Row(justify="space-between"):
259
+ solara.Button(label="Reset", color="primary", on_click=do_reset)
260
+ solara.Button(
261
+ label="▶" if not playing.value else "❚❚",
262
+ color="primary",
263
+ on_click=do_play_pause,
296
264
  )
297
- widgets.Play(
298
- value=0,
299
- interval=play_interval,
300
- repeat=True,
301
- show_repeat=False,
302
- on_value=on_value_play,
303
- playing=playing.value,
304
- on_playing=do_set_playing,
265
+ solara.Button(
266
+ label="Step", color="primary", on_click=do_step, disabled=playing.value
305
267
  )
306
- solara.Button(label="Reset", color="primary", on_click=do_reset)
307
- # threaded_do_play is not used for now because it
308
- # doesn't work in Google colab. We use
309
- # ipywidgets.Play until it is fixed. The threading
310
- # version is definite a much better implementation,
311
- # if it works.
312
- # solara.Button(label="▶", color="primary", on_click=viz.threaded_do_play)
313
- # solara.Button(label="⏸︎", color="primary", on_click=viz.do_pause)
314
- # solara.Button(label="Reset", color="primary", on_click=do_reset)
315
268
 
316
269
 
317
270
  def split_model_params(model_params):
318
- """
319
- Split model parameters into user-adjustable and fixed parameters.
271
+ """Split model parameters into user-adjustable and fixed parameters.
320
272
 
321
273
  Args:
322
274
  model_params: Dictionary of all model parameters
@@ -335,8 +287,7 @@ def split_model_params(model_params):
335
287
 
336
288
 
337
289
  def check_param_is_fixed(param):
338
- """
339
- Check if a parameter is fixed (not user-adjustable).
290
+ """Check if a parameter is fixed (not user-adjustable).
340
291
 
341
292
  Args:
342
293
  param: Parameter to check
@@ -353,18 +304,84 @@ def check_param_is_fixed(param):
353
304
 
354
305
 
355
306
  @solara.component
356
- def UserInputs(user_params, on_change=None):
307
+ def ModelCreator(model, model_params, seed=1):
308
+ """Solara component for creating and managing a model instance with user-defined parameters.
309
+
310
+ This component allows users to create a model instance with specified parameters and seed.
311
+ It provides an interface for adjusting model parameters and reseeding the model's random
312
+ number generator.
313
+
314
+ Args:
315
+ model (solara.Reactive[Model]): A reactive model instance. This is the main model to be created and managed.
316
+ model_params (dict): Dictionary of model parameters. This includes both user-adjustable parameters and fixed parameters.
317
+ seed (int, optional): Initial seed for the random number generator. Defaults to 1.
318
+
319
+ Returns:
320
+ solara.component: A Solara component that renders the model creation and management interface.
321
+
322
+ Example:
323
+ >>> model = solara.reactive(MyModel())
324
+ >>> model_params = {
325
+ >>> "param1": {"type": "slider", "value": 10, "min": 0, "max": 100},
326
+ >>> "param2": {"type": "slider", "value": 5, "min": 1, "max": 10},
327
+ >>> }
328
+ >>> creator = ModelCreator(model, model_params)
329
+ >>> creator
330
+
331
+ Notes:
332
+ - The `model_params` argument should be a dictionary where keys are parameter names and values either fixed values
333
+ or are dictionaries containing parameter details such as type, value, min, and max.
334
+ - The `seed` argument ensures reproducibility by setting the initial seed for the model's random number generator.
335
+ - The component provides an interface for adjusting user-defined parameters and reseeding the model.
336
+
357
337
  """
358
- Initialize user inputs for configurable model parameters.
338
+ user_params, fixed_params = split_model_params(model_params)
339
+
340
+ reactive_seed = solara.use_reactive(seed)
341
+
342
+ model_parameters, set_model_parameters = solara.use_state(
343
+ {
344
+ **fixed_params,
345
+ **{k: v.get("value") for k, v in user_params.items()},
346
+ }
347
+ )
348
+
349
+ def do_reseed():
350
+ """Update the random seed for the model."""
351
+ reactive_seed.value = model.value.random.random()
352
+
353
+ def on_change(name, value):
354
+ set_model_parameters({**model_parameters, name: value})
355
+
356
+ def create_model():
357
+ model.value = model.value.__class__(**model_parameters)
358
+ model.value._seed = reactive_seed.value
359
+
360
+ solara.use_effect(create_model, [model_parameters, reactive_seed.value])
361
+
362
+ with solara.Row(justify="space-between"):
363
+ solara.InputText(
364
+ label="Seed",
365
+ value=reactive_seed,
366
+ continuous_update=True,
367
+ )
368
+
369
+ solara.Button(label="Reseed", color="primary", on_click=do_reseed)
370
+
371
+ UserInputs(user_params, on_change=on_change)
372
+
373
+
374
+ @solara.component
375
+ def UserInputs(user_params, on_change=None):
376
+ """Initialize user inputs for configurable model parameters.
377
+
359
378
  Currently supports :class:`solara.SliderInt`, :class:`solara.SliderFloat`,
360
379
  :class:`solara.Select`, and :class:`solara.Checkbox`.
361
380
 
362
381
  Args:
363
- user_params: Dictionary with options for the input, including label,
364
- min and max values, and other fields specific to the input type.
382
+ user_params: Dictionary with options for the input, including label, min and max values, and other fields specific to the input type.
365
383
  on_change: Function to be called with (name, value) when the value of an input changes.
366
384
  """
367
-
368
385
  for name, options in user_params.items():
369
386
 
370
387
  def change_handler(value, name=name):
@@ -422,26 +439,8 @@ def UserInputs(user_params, on_change=None):
422
439
  raise ValueError(f"{input_type} is not a supported input type")
423
440
 
424
441
 
425
- def make_text(renderer):
426
- """
427
- Create a function that renders text using Markdown.
428
-
429
- Args:
430
- renderer: Function that takes a model and returns a string
431
-
432
- Returns:
433
- function: A function that renders the text as Markdown
434
- """
435
-
436
- def function(model):
437
- solara.Markdown(renderer(model))
438
-
439
- return function
440
-
441
-
442
442
  def make_initial_grid_layout(layout_types):
443
- """
444
- Create an initial grid layout for visualization components.
443
+ """Create an initial grid layout for visualization components.
445
444
 
446
445
  Args:
447
446
  layout_types: List of layout types (Space or Measure)
@@ -460,3 +459,10 @@ def make_initial_grid_layout(layout_types):
460
459
  }
461
460
  for i in range(len(layout_types))
462
461
  ]
462
+
463
+
464
+ @solara.component
465
+ def ShowSteps(model):
466
+ """Display the current step of the model."""
467
+ update_counter.get()
468
+ return solara.Text(f"Step: {model.steps}")
@@ -0,0 +1,9 @@
1
+ """Solara related utils."""
2
+
3
+ import solara
4
+
5
+ update_counter = solara.reactive(0)
6
+
7
+
8
+ def force_update(): # noqa: D103
9
+ update_counter.value += 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: Mesa
3
- Version: 3.0.0a3
3
+ Version: 3.0.0a5
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
@@ -0,0 +1,44 @@
1
+ mesa/__init__.py,sha256=rKO9SY4p-VL83PFsk5hAbDCbhhUO8azgxc9buDoFCX4,618
2
+ mesa/agent.py,sha256=-KwohXkdrj6CZMn7paf3Jv_7fCfDPhsJasRNm-jgTTY,25043
3
+ mesa/batchrunner.py,sha256=YUYyCy8XBxbUj83BczXmxA6tsT6ttimIeqiD3-wkYL4,6103
4
+ mesa/datacollection.py,sha256=xyb07aBpd-HSDh5bk-XcVqGiDu5bfaLlxj5eDlGIwqY,16138
5
+ mesa/main.py,sha256=_KgeVGbi0znzezjjoM09vhGdyaqcuDEwb9M7vH2c_O4,1668
6
+ mesa/model.py,sha256=vUS64fuZI26b3TYX0BTK90S8lxPdmFI1tgxatNEYUI8,7981
7
+ mesa/space.py,sha256=1sVl78o5lYP6aEg32QIb9-tcv3V3UeFdC7A_h_8CgO8,62838
8
+ mesa/time.py,sha256=kGXHDjnRn-Ixwgxt3fijEvLRybWQe0g9pE5ZpW4Kaaw,14983
9
+ mesa/cookiecutter-mesa/cookiecutter.json,sha256=tBSWli39fOWUXGfiDCTKd92M7uKaBIswXbkOdbUufYY,337
10
+ mesa/cookiecutter-mesa/hooks/post_gen_project.py,sha256=UKz12l6mKc7fILK0MvV5djsTKwkmD4DlH8LYjFO8ehI,316
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=WgJccMfsAlD_mA3zTBPJVHadF3FtO8xgi8SPKORzyMs,22
15
+ mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate,sha256=Aml4Z6E1yj7E7DtHNSUqnKNRUdkxG9WWtJyW8fkxCng,1870
16
+ mesa/experimental/UserParam.py,sha256=f32nmFjroe76HpxU75ZCEOqFW2nAsDfmqIf8kQ1zt-E,2086
17
+ mesa/experimental/__init__.py,sha256=1hxkjcZvdJhhQx4iLlTTUAPs_SqRyN-us4qR8U6JKkw,209
18
+ mesa/experimental/solara_viz.py,sha256=uWrNQAX3oEWSftmyjNorN839dBCUp86hnhpL704dyGQ,15212
19
+ mesa/experimental/cell_space/__init__.py,sha256=Nz1EkgzhvrTcfOJI1M_WkHsIgPkU8QIOCNJl7jLlYpw,908
20
+ mesa/experimental/cell_space/cell.py,sha256=L1XMxq1mIaouviiPSgurj4uda0dAx7zMWnam6_aK79s,5907
21
+ mesa/experimental/cell_space/cell_agent.py,sha256=06R_7djVlD2S-kS86ugxiaeualWaTrSUmF82t3UBi44,1169
22
+ mesa/experimental/cell_space/cell_collection.py,sha256=ZcyuPEevCZEXW7jFnX6StjBMw4UBDQvUspZRcFi2dFg,3426
23
+ mesa/experimental/cell_space/discrete_space.py,sha256=q5MRPzMYzZb3hQW90L0PmVFJepXhjbZK_9hT4y6OLdY,2293
24
+ mesa/experimental/cell_space/grid.py,sha256=WT9AtQCgPzV8VonX0oSPRXgZNXoOR_mVgEAEOp5I4YA,7319
25
+ mesa/experimental/cell_space/network.py,sha256=hzhxGipRyM1PWOQFlPz--tc3pA_RRBT8Xq4pXHx5sD8,1252
26
+ mesa/experimental/cell_space/voronoi.py,sha256=lSY8zQhELvOy0RfDyZIek09UMwY9_20UY9SPqFWsNoM,10014
27
+ mesa/experimental/components/altair.py,sha256=49OHgrm1JncfrKqDfw_5ifPtsbMKdgVYCacL9SMwucc,2624
28
+ mesa/experimental/components/matplotlib.py,sha256=j477UBk_7yW5vzT3rjhnuTixpA7PedDNghoK9TLgHVY,8043
29
+ mesa/experimental/devs/__init__.py,sha256=EByaC66ikUIu9G9p1geLm6ESEMWZOPTO9r9627S83j0,211
30
+ mesa/experimental/devs/eventlist.py,sha256=Trvc5S-NG5B792uuk_cY8Q_5Rw99zioUYDQXcXWVuCo,5972
31
+ mesa/experimental/devs/simulator.py,sha256=wvqkLIDgbJNaem9nwMacyEYRp0W3ai5Oxptw3-QmbSw,10595
32
+ mesa/experimental/devs/examples/epstein_civil_violence.py,sha256=E8YSV3O5ihKsntGtnltHM-4IyS8eg2DSRUqmIiw_1iU,10916
33
+ mesa/experimental/devs/examples/wolf_sheep.py,sha256=aj5kiEWy-ezQXOomc5mgEdkup1yRYQknQm65ajPWBxs,8051
34
+ mesa/visualization/UserParam.py,sha256=Dl2WOwLYLf0pfLpabCZtIdFRyKZrK6Qtc3utZx5GPYg,2139
35
+ mesa/visualization/__init__.py,sha256=sa8lqeLcDtte19SMzFiKP6K4CrVLxAPwrhDu_AsDWTs,395
36
+ mesa/visualization/solara_viz.py,sha256=vVyAqp3aov8EKmYAvDELEdb5Fonr5JxLws6YZZ02GIk,16459
37
+ mesa/visualization/utils.py,sha256=lJHgRKF5BHLf72Tw3YpwyiWuRoIimaTKQ7xBCw_Rx3A,146
38
+ mesa/visualization/components/altair.py,sha256=E-iblqpWhx72qrjkNz4Ie9c66Hh1OFpLVjuDIg9m2sA,2804
39
+ mesa/visualization/components/matplotlib.py,sha256=wGPxZAS6c3HZgyrkoFKA6z5CqaTr2YVB6sDZtywTt_I,8277
40
+ mesa-3.0.0a5.dist-info/METADATA,sha256=EqwMNNaGiRZhmZVkg032KxexPwvNlEYGmzF9jQ5N05s,8339
41
+ mesa-3.0.0a5.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
42
+ mesa-3.0.0a5.dist-info/entry_points.txt,sha256=IOcQtetGF8l4wHpOs_hGb19Rz-FS__BMXOJR10IBPsA,39
43
+ mesa-3.0.0a5.dist-info/licenses/LICENSE,sha256=OGUgret9fRrm8J3pdsPXETIjf0H8puK_Nmy970ZzT78,572
44
+ mesa-3.0.0a5.dist-info/RECORD,,