From 4f5c6f9ed187148191e201101b437d9153e13fa8 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:59:24 +0200 Subject: [PATCH 01/37] adding numba to project.toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index f769264..6e82350 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,7 @@ test = [ dev = [ "mesa_frames[test, docs]", "mesa", + "numba" ] [tool.hatch.envs.test] From 1095dca1690e4f9b2bdb82e4244ad63c8531e1d3 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:00:33 +0200 Subject: [PATCH 02/37] splitting agent_type --- examples/sugarscape_ig/ss_polars/model.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/sugarscape_ig/ss_polars/model.py b/examples/sugarscape_ig/ss_polars/model.py index 70830e0..e2ae4ae 100644 --- a/examples/sugarscape_ig/ss_polars/model.py +++ b/examples/sugarscape_ig/ss_polars/model.py @@ -9,6 +9,7 @@ class SugarscapePolars(ModelDF): def __init__( self, + agent_type: type[AntPolarsLoop] | type[AntPolarsNumba], n_agents: int, sugar_grid: np.ndarray | None = None, initial_sugar: np.ndarray | None = None, @@ -30,7 +31,7 @@ def __init__( sugar=sugar_grid.flatten(), max_sugar=sugar_grid.flatten() ) self.space.set_cells(sugar_grid) - self.agents += AntPolars(self, n_agents, initial_sugar, metabolism, vision) + self.agents += agent_type(self, n_agents, initial_sugar, metabolism, vision) self.space.place_to_empty(self.agents) def run_model(self, steps: int) -> list[int]: From 29e995b3e555e6d92de59eda84c0a3e48083530e Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:02:28 +0200 Subject: [PATCH 03/37] splitting antpolars and antpolarsloop --- examples/sugarscape_ig/ss_polars/agents.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 6b3cba4..57d7d5e 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -1,3 +1,4 @@ +import numba as nb import numpy as np import polars as pl @@ -32,6 +33,20 @@ def __init__( ) self.add(agents) + def eat(self): + cells = self.space.cells.filter(pl.col("agent_id").is_not_null()) + self[cells["agent_id"], "sugar"] = ( + self[cells["agent_id"], "sugar"] + + cells["sugar"] + - self[cells["agent_id"], "metabolism"] + ) + + def step(self): + self.shuffle().do("move").do("eat") + self.discard(self.agents.filter(pl.col("sugar") <= 0)) + + +class AntPolarsLoop(AntPolars): def move(self): neighborhood: pl.DataFrame = self.space.get_neighborhood( radius=self["vision"], agents=self, include_center=True From da6d27e73074443bc80386ab7f56011f7b5c1ad4 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:28:26 +0200 Subject: [PATCH 04/37] adding py-spy to dev tools --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6e82350..aa3971c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,7 +87,8 @@ test = [ dev = [ "mesa_frames[test, docs]", "mesa", - "numba" + "numba", + "py-spy", ] [tool.hatch.envs.test] From f236b543cce17609d83f50aa935ecfbeb4783772 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:29:40 +0200 Subject: [PATCH 05/37] splitting between numba, loop with DF and loop non vectorized implementations --- examples/sugarscape_ig/ss_polars/agents.py | 226 ++++++++++++++++++--- examples/sugarscape_ig/ss_polars/model.py | 4 +- 2 files changed, 198 insertions(+), 32 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 57d7d5e..c21d629 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -1,11 +1,13 @@ -import numba as nb +from abc import abstractmethod + import numpy as np import polars as pl +from numba import b1, guvectorize, int64 from mesa_frames import AgentSetPolars, ModelDF -class AntPolars(AgentSetPolars): +class AntPolarsBase(AgentSetPolars): def __init__( self, model: ModelDF, @@ -26,9 +28,9 @@ def __init__( agents = pl.DataFrame( { "unique_id": pl.arange(n_agents, eager=True), - "sugar": model.random.integers(6, 25, n_agents), - "metabolism": model.random.integers(2, 4, n_agents), - "vision": model.random.integers(1, 6, n_agents), + "sugar": initial_sugar, + "metabolism": metabolism, + "vision": vision, } ) self.add(agents) @@ -45,18 +47,24 @@ def step(self): self.shuffle().do("move").do("eat") self.discard(self.agents.filter(pl.col("sugar") <= 0)) - -class AntPolarsLoop(AntPolars): def move(self): + neighborhood = self._get_neighborhood() + agent_order = self._get_agent_order(neighborhood) + neighborhood = self._prepare_neighborhood(neighborhood, agent_order) + best_moves = self.get_best_moves(neighborhood, agent_order) + self.space.move_agents(agent_order["agent_id_center"], best_moves) + + def _get_neighborhood(self): neighborhood: pl.DataFrame = self.space.get_neighborhood( radius=self["vision"], agents=self, include_center=True ) - # Join self.space.cells to obtain properties ('sugar') per cell + neighborhood = neighborhood.join(self.space.cells, on=["dim_0", "dim_1"]) # Join self.pos to obtain the agent_id of the center cell # TODO: get_neighborhood/get_neighbors should return 'agent_id_center' instead of center position when input is AgentLike + neighborhood = neighborhood.with_columns( agent_id_center=neighborhood.join( self.pos, @@ -64,33 +72,53 @@ def move(self): right_on=["dim_0", "dim_1"], )["unique_id"] ) + return neighborhood + def _get_agent_order(self, neighborhood): # Order of agents moves based on the original order of agents. # The agent in his cell has order 0 (highest) - agent_order = neighborhood.unique( - subset=["agent_id_center"], keep="first", maintain_order=True - ).with_row_count("agent_order") + return ( + neighborhood.unique( + subset=["agent_id_center"], keep="first", maintain_order=True + ) + .with_row_count("agent_order") + .select(["agent_id_center", "agent_order"]) + ) + + def _prepare_neighborhood(self, neighborhood, agent_order): neighborhood = neighborhood.join(agent_order, on="agent_id_center") + # Add blocking agent order neighborhood = neighborhood.join( agent_order.select( pl.col("agent_id_center").alias("agent_id"), pl.col("agent_order").alias("blocking_agent_order"), ), on="agent_id", - ) + how="left", + ).rename({"agent_id": "blocking_agent_id"}) # Filter impossible moves neighborhood = neighborhood.filter( - pl.col("agent_order") >= pl.col("blocking_agent_order") + (pl.col("agent_order") >= pl.col("blocking_agent_order")) + | pl.col("blocking_agent_order").is_null() + ) + # Sort cells by agent_order, sugar and radius (nearest first) + + return neighborhood.sort( + ["agent_order", "sugar", "radius"], descending=[False, True, False] ) - # Sort cells by sugar and radius (nearest first) - neighborhood = neighborhood.sort(["sugar", "radius"], descending=[True, False]) + def get_best_moves(self, neighborhood, agent_order): + raise NotImplementedError("This method should be implemented by subclasses") + +class AntPolarsLoopDF(AntPolarsBase): + def get_best_moves(self, neighborhood, agent_order): best_moves = pl.DataFrame() # While there are agents that do not have a best move, keep looking for one + while len(best_moves) < len(self.agents): # Get the best moves for each agent and if duplicates are found, select the one with the highest order new_best_moves = ( @@ -99,16 +127,16 @@ def move(self): .sort("agent_order") .unique(subset=["dim_0", "dim_1"], keep="first") ) - # Agents can make the move if: # - There is no blocking agent # - The agent is in its own cell # - The blocking agent has moved before him - condition = pl.col("agent_id").is_null() | ( - pl.col("agent_id") == pl.col("agent_id_center") + + condition = pl.col("blocking_agent_id").is_null() | ( + pl.col("blocking_agent_id") == pl.col("agent_id_center") ) if len(best_moves) > 0: - condition = condition | pl.col("agent_id").is_in( + condition = condition | pl.col("blocking_agent_id").is_in( best_moves["agent_id_center"] ) new_best_moves = new_best_moves.filter(condition) @@ -119,22 +147,160 @@ def move(self): neighborhood = neighborhood.filter( ~pl.col("agent_id_center").is_in(best_moves["agent_id_center"]) ) - # Remove cells that have been already selected neighborhood = neighborhood.join( best_moves.select(["dim_0", "dim_1"]), on=["dim_0", "dim_1"], how="anti" ) - self.space.move_agents(self, best_moves.select(["dim_0", "dim_1"])) + return best_moves.select(["dim_0", "dim_1"]) - def eat(self): - cells = self.space.cells.filter(pl.col("agent_id").is_not_null()) - self[cells["agent_id"], "sugar"] = ( - self[cells["agent_id"], "sugar"] - + cells["sugar"] - - self[cells["agent_id"], "metabolism"] + +import numpy as np +import polars as pl +from numba import guvectorize, int64 + + +class AntPolarsLoop(AntPolarsBase): + numba_target = None + + def get_best_moves(self, neighborhood, agent_order): + occupied_cells, free_cells, target_cells = self._prepare_cells(neighborhood) + best_moves_func = self._get_best_moves() + + processed_agents = np.zeros(len(self.agents), dtype=np.bool_) + + if self.numba_target is None: + # Non-vectorized case: we need to create and pass the best_moves array + map_batches_func = lambda df: best_moves_func( + occupied_cells, + free_cells, + target_cells, + df.struct.field("agent_order"), + df.struct.field("blocking_agent_order"), + processed_agents, + best_moves=np.full(len(self.agents), -1, dtype=np.int64), + ) + else: + # Vectorized case: Polars will create the output array (best_moves) automatically + map_batches_func = lambda df: best_moves_func( + occupied_cells, + free_cells, + target_cells, + df.struct.field("agent_order"), + df.struct.field("blocking_agent_order"), + processed_agents, + ) + + best_moves = ( + neighborhood.fill_null(-1) + .select( + pl.struct(["agent_order", "blocking_agent_order"]).map_batches( + map_batches_func + ) + ) + .with_columns( + dim_0=pl.col("agent_order") // self.space.dimensions[1], + dim_1=pl.col("agent_order") % self.space.dimensions[1], + ) + .drop("agent_order") ) + return best_moves - def step(self): - self.shuffle().do("move").do("eat") - self.discard(self.agents.filter(pl.col("sugar") <= 0)) + def _prepare_cells(self, neighborhood: pl.DataFrame): + occupied_cells = ( + neighborhood[["agent_id_center"]] + .unique() + .join(self.pos, left_on="agent_id_center", right_on="unique_id") + .with_columns( + flattened=(pl.col("dim_0") * self.space.dimensions[1] + pl.col("dim_1")) + )["flattened"] + .to_numpy() + ) + free_cells = np.ones( + self.space.dimensions[0] * self.space.dimensions[1], dtype=np.bool_ + ) + free_cells[occupied_cells] = False + target_cells = ( + neighborhood["dim_0"] * self.space.dimensions[1] + neighborhood["dim_1"] + ).to_numpy() + return occupied_cells, free_cells, target_cells + + def _get_best_moves(self): + raise NotImplementedError("Subclasses must implement this method") + + +class AntPolarsLoopNoVec(AntPolarsLoop): + def _get_best_moves(self): + def inner_get_best_moves( + occupied_cells: np.ndarray, + free_cells: np.ndarray, + target_cells: np.ndarray, + agent_id_center: np.ndarray, + blocking_agent: np.ndarray, + processed_agents: np.ndarray, + best_moves: np.ndarray, + ) -> np.ndarray: + for i, agent in enumerate(agent_id_center): + if not processed_agents[agent]: + if free_cells[target_cells[i]] or blocking_agent[i] == agent: + best_moves[agent] = target_cells[i] + # Free current cell + free_cells[occupied_cells[agent]] = True + # Occupy target cell + free_cells[target_cells[i]] = False + processed_agents[agent] = True + return best_moves + + return inner_get_best_moves + + +class AntPolarsNumba(AntPolarsLoop): + def _get_best_moves(self): + @guvectorize( + [ + ( + int64[:], + int64[:], + int64[:], + int64[:], + int64[:], + int64[:], + int64[:], + ) + ], + "(n), (m), (p), (p), (p), (n)->(n)", + nopython=True, + target=self.numba_target, + ) + def vectorized_get_best_moves( + occupied_cells, + free_cells, + target_cells, + agent_id_center, + blocking_agent, + processed_agents, + best_moves, + ): + for i, agent in enumerate(agent_id_center): + if not processed_agents[agent]: + if free_cells[target_cells[i]] or blocking_agent[i] == agent: + best_moves[agent] = target_cells[i] + # Free current cell + free_cells[occupied_cells[agent]] = True + # Occupy target cell + free_cells[target_cells[i]] = False + processed_agents[agent] = True + + return vectorized_get_best_moves + + +class AntPolarsNumbaCPU(AntPolarsNumba): + numba_target = "cpu" + + +class AntPolarsNumbaParallel(AntPolarsNumba): + numba_target = "parallel" + + +class AntPolarsNumbaGPU(AntPolarsNumba): + numba_target = "gpu" diff --git a/examples/sugarscape_ig/ss_polars/model.py b/examples/sugarscape_ig/ss_polars/model.py index e2ae4ae..8ddc73c 100644 --- a/examples/sugarscape_ig/ss_polars/model.py +++ b/examples/sugarscape_ig/ss_polars/model.py @@ -3,13 +3,13 @@ from mesa_frames import GridPolars, ModelDF -from .agents import AntPolars +from .agents import AntPolarsBase class SugarscapePolars(ModelDF): def __init__( self, - agent_type: type[AntPolarsLoop] | type[AntPolarsNumba], + agent_type: type[AntPolarsBase], n_agents: int, sugar_grid: np.ndarray | None = None, initial_sugar: np.ndarray | None = None, From 9947bf02e947c0b547c45c4662454b2147bd50ec Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:30:03 +0200 Subject: [PATCH 06/37] performance comparison between loop and numba --- .../sugarscape_ig/performance_comparison.py | 83 +++++++++++++++++-- 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index c6b2ad4..110c1fc 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -3,8 +3,16 @@ import matplotlib.pyplot as plt import numpy as np import perfplot +import seaborn as sns from ss_mesa.model import SugarscapeMesa from ss_pandas.model import SugarscapePandas +from ss_polars.agents import ( + AntPolarsLoopDF, + AntPolarsLoopNoVec, + AntPolarsNumbaCPU, + AntPolarsNumbaGPU, + AntPolarsNumbaParallel, +) from ss_polars.model import SugarscapePolars @@ -34,9 +42,58 @@ def mesa_frames_pandas_concise(setup: SugarScapeSetup): ).run_model(100) -def mesa_frames_polars_concise(setup: SugarScapeSetup): +def mesa_frames_polars_loop_DF(setup: SugarScapeSetup): return SugarscapePolars( - setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision + AntPolarsLoopDF, + setup.n, + setup.sugar_grid, + setup.initial_sugar, + setup.metabolism, + setup.vision, + ).run_model(100) + + +def mesa_frames_polars_loop_no_vec(setup: SugarScapeSetup): + return SugarscapePolars( + AntPolarsLoopNoVec, + setup.n, + setup.sugar_grid, + setup.initial_sugar, + setup.metabolism, + setup.vision, + ).run_model(100) + + +def mesa_frames_polars_numba_cpu(setup: SugarScapeSetup): + return SugarscapePolars( + AntPolarsNumbaCPU, + setup.n, + setup.sugar_grid, + setup.initial_sugar, + setup.metabolism, + setup.vision, + ).run_model(100) + + +def mesa_frames_polars_numba_gpu(setup: SugarScapeSetup): + return SugarscapePolars( + AntPolarsNumbaGPU, + setup.n, + setup.sugar_grid, + setup.initial_sugar, + setup.metabolism, + setup.vision, + ).run_model(100) + + +def mesa_frames_polars_numba_parallel(setup: SugarScapeSetup): + return SugarscapePolars( + AntPolarsNumbaParallel, + setup.n, + setup.sugar_grid, + setup.initial_sugar, + setup.metabolism, + setup.vision, ).run_model(100) @@ -61,9 +118,9 @@ def plot_and_print_benchmark(labels, kernels, n_range, title, image_path): def main(): - """# Mesa comparison + # Mesa comparison sns.set_theme(style="whitegrid") - labels_0 = [ + """labels_0 = [ "mesa", # "mesa-frames (pd concise)", "mesa-frames (pl concise)", @@ -81,15 +138,25 @@ def main(): # FLAME2-GPU comparison labels_1 = [ # "mesa-frames (pd concise)", - "mesa-frames (pl concise)", + "mesa-frames (pl loop DF)", + "mesa-frames (pl loop no vec)", + "mesa-frames (pl numba CPU)", + "mesa-frames (pl numba parallel)", + # "mesa-frames (pl numba GPU)", ] + # Polars best_moves (non-vectorized loop vs DF loop vs numba loop) kernels_1 = [ # mesa_frames_pandas_concise, - mesa_frames_polars_concise, + mesa_frames_polars_loop_DF, + mesa_frames_polars_loop_no_vec, + mesa_frames_polars_numba_cpu, + mesa_frames_polars_numba_parallel, + # mesa_frames_polars_numba_gpu, ] - n_range_1 = [k for k in range(1, 3 * 10**6 + 2, 10**6)] + n_range_1 = [k for k in range(1, 2 * 10**6 + 2, 10**6)] + # n_range_1 = [k for k in range(10000, 100002, 10000)] title_1 = "100 steps of the SugarScape IG model:\n" + " vs ".join(labels_1) - image_path_1 = "benchmark_plot_1.png" + image_path_1 = "polars_comparison.png" plot_and_print_benchmark(labels_1, kernels_1, n_range_1, title_1, image_path_1) From 1d90c206564e29e27b1bdbe5b2adda933289ff0d Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 1 Sep 2024 16:27:57 +0200 Subject: [PATCH 07/37] fix: cuda target, not gpu --- examples/sugarscape_ig/ss_polars/agents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index c21d629..5908f81 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -303,4 +303,4 @@ class AntPolarsNumbaParallel(AntPolarsNumba): class AntPolarsNumbaGPU(AntPolarsNumba): - numba_target = "gpu" + numba_target = "cuda" From 77d6699a03a4266a82039887d675df448bc71d78 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 1 Sep 2024 16:28:32 +0200 Subject: [PATCH 08/37] adding polars comparison --- .../sugarscape_ig/performance_comparison.py | 4 +- examples/sugarscape_ig/polars_comparison.png | Bin 0 -> 60352 bytes examples/sugarscape_ig/polars_comparison.svg | 415 ++++++++++++++++++ 3 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 examples/sugarscape_ig/polars_comparison.png create mode 100644 examples/sugarscape_ig/polars_comparison.svg diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 110c1fc..b772dbc 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -142,7 +142,7 @@ def main(): "mesa-frames (pl loop no vec)", "mesa-frames (pl numba CPU)", "mesa-frames (pl numba parallel)", - # "mesa-frames (pl numba GPU)", + #"mesa-frames (pl numba GPU)", ] # Polars best_moves (non-vectorized loop vs DF loop vs numba loop) kernels_1 = [ @@ -151,7 +151,7 @@ def main(): mesa_frames_polars_loop_no_vec, mesa_frames_polars_numba_cpu, mesa_frames_polars_numba_parallel, - # mesa_frames_polars_numba_gpu, + #mesa_frames_polars_numba_gpu, ] n_range_1 = [k for k in range(1, 2 * 10**6 + 2, 10**6)] # n_range_1 = [k for k in range(10000, 100002, 10000)] diff --git a/examples/sugarscape_ig/polars_comparison.png b/examples/sugarscape_ig/polars_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..235a52e9703934932454278358f4620c6363b672 GIT binary patch literal 60352 zcmeFZdpy(s8$UdA%9(P?u}G9TC1Yk(DoUsnD`5_$GKb80*j71|kP69=PC7Vj5jl)S z4ke@1EM_LLFy;_TGk$NM&*yvJ|J;Ax|J;wq{eC<=%-j2QcwevUb-kX~^SZ9xIPT^o zC#@k30)ga?I3GL-0*N6&Ah6*k3E)oQCA}8l7cA-!GRhplOpM2ltW+I}3va-s>hALL z1Qp~ z=dY%B>gmZCZcHNq#$o=TexOcJFHrYT2`s_TgEKe;I}&A#l9*GEc*I{DYFaun5Y}*8A#W09U(|jw^Dx~QDXzN z`kp4frQWMDd_P{3fD^gG*5RDH%U^3Yea_FJ#!^Flj(d`Yn~_^=zG876#?zJARu@Yo z?Wb6mt)`Dc*f}Dz5*I||8RA_5@3M8eVRg`$V{YPM@0Q1QQ^N@!WZ}@X4TmO5Yqfto z)H()2866kZ!fR*f>FH(2{v*Z~Gs5X6z8{POeW!7)2PUd6CcDJKf!Rc?N}RO1I8!lC z2o5>uGe&W+g)~aViM)Lei*4a2$5>NJQa;}ty^?5Q{8^P&pG(5`XR-us3&n7qX+)ns zj3a@f+;yXZV>IJ=4m9uJ_5)Qu3>fDn3Gaj;;e7F%IZP==vXYY0nI}fSw(EWAj^~w$ z`n|cbBsO=^l&$2uUW1uMpu5`T{I6(fE<}U|QFd~e>TDg94EyN>^as&<>sv*JNXWr; zP?NM4hq7+;vl3}pKBVlse3hS!MAq VJ>i0x6{`N4oCfcY1_qoy(Xioa9m{fE5> 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 record -o polars_comparison.svg -- python performance_comparison.py Reset ZoomSearch _place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (301 samples, 0.10%)sample_cells (mesa_frames/abstract/space.py:703) (301 samples, 0.10%)mesa_frames_polars_loop_DF (sugarscape_ig/performance_comparison.py:46) (389 samples, 0.13%)__init__ (sugarscape_ig/ss_polars/model.py:35) (348 samples, 0.12%)place_to_empty (mesa_frames/abstract/space.py:651) (348 samples, 0.12%)set (mesa_frames/concrete/polars/agentset.py:190) (545 samples, 0.19%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (545 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (545 samples, 0.19%)wrapper (polars/series/utils.py:107) (545 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (543 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (543 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (568 samples, 0.19%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (571 samples, 0.20%)wrapper (polars/series/utils.py:107) (571 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (570 samples, 0.20%)set (mesa_frames/concrete/polars/agentset.py:191) (584 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,161 samples, 0.40%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,159 samples, 0.40%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (552 samples, 0.19%)wrapper (polars/series/utils.py:107) (550 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (547 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (546 samples, 0.19%)get (mesa_frames/concrete/polars/agentset.py:173) (573 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:41) (580 samples, 0.20%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (580 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:1026) (580 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:456) (580 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (596 samples, 0.20%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (600 samples, 0.21%)wrapper (polars/series/utils.py:107) (599 samples, 0.20%)get (mesa_frames/concrete/polars/agentset.py:173) (617 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (622 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (622 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (622 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (682 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (569 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1640) (576 samples, 0.20%)contains (mesa_frames/concrete/agents.py:144) (572 samples, 0.20%)wrapper (polars/series/utils.py:107) (571 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (571 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (533 samples, 0.18%)_get_df_coords (mesa_frames/abstract/space.py:1647) (534 samples, 0.18%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (534 samples, 0.18%)wrapper (polars/series/utils.py:107) (534 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (534 samples, 0.18%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (518 samples, 0.18%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (518 samples, 0.18%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (518 samples, 0.18%)wrapper (polars/series/utils.py:107) (517 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (517 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (517 samples, 0.18%)_get_df_coords (mesa_frames/abstract/space.py:1657) (523 samples, 0.18%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,686 samples, 0.58%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,314 samples, 2.16%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,314 samples, 2.16%)_..join (polars/dataframe/frame.py:6927) (6,313 samples, 2.16%)j..collect (polars/lazyframe/frame.py:2027) (6,313 samples, 2.16%)c.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (8,732 samples, 2.99%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,374 samples, 0.47%)join (polars/dataframe/frame.py:6927) (1,132 samples, 0.39%)collect (polars/lazyframe/frame.py:2027) (1,132 samples, 0.39%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (568 samples, 0.19%)join (polars/dataframe/frame.py:6927) (462 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (462 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (563 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (564 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (568 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (568 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (568 samples, 0.19%)wrapper (polars/series/utils.py:107) (567 samples, 0.19%)pos (mesa_frames/abstract/agents.py:1071) (572 samples, 0.20%)move (sugarscape_ig/ss_polars/agents.py:51) (11,269 samples, 3.86%)move.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (591 samples, 0.20%)pos (mesa_frames/concrete/polars/agentset.py:536) (591 samples, 0.20%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (1,008 samples, 0.34%)unique (polars/dataframe/frame.py:9533) (1,006 samples, 0.34%)collect (polars/lazyframe/frame.py:2027) (1,006 samples, 0.34%)move (sugarscape_ig/ss_polars/agents.py:52) (1,054 samples, 0.36%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (945 samples, 0.32%)sort (polars/dataframe/frame.py:4939) (943 samples, 0.32%)collect (polars/lazyframe/frame.py:2027) (942 samples, 0.32%)move (sugarscape_ig/ss_polars/agents.py:53) (1,684 samples, 0.58%)agg (polars/dataframe/group_by.py:231) (1,171 samples, 0.40%)collect (polars/lazyframe/frame.py:2027) (1,171 samples, 0.40%)get_best_moves (sugarscape_ig/ss_polars/agents.py:126) (1,175 samples, 0.40%)first (polars/dataframe/group_by.py:527) (1,175 samples, 0.40%)get_best_moves (sugarscape_ig/ss_polars/agents.py:142) (918 samples, 0.31%)filter (polars/dataframe/frame.py:4554) (918 samples, 0.31%)collect (polars/lazyframe/frame.py:2027) (918 samples, 0.31%)get_best_moves (sugarscape_ig/ss_polars/agents.py:147) (3,296 samples, 1.13%)filter (polars/dataframe/frame.py:4554) (3,250 samples, 1.11%)collect (polars/lazyframe/frame.py:2027) (3,250 samples, 1.11%)move (sugarscape_ig/ss_polars/agents.py:54) (5,786 samples, 1.98%)m..select_seq (polars/dataframe/frame.py:8742) (679 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (678 samples, 0.23%)_place_or_move_agents (mesa_frames/abstract/space.py:1709) (681 samples, 0.23%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (681 samples, 0.23%)wrapper (polars/series/utils.py:107) (680 samples, 0.23%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (585 samples, 0.20%)contains (mesa_frames/concrete/agents.py:144) (576 samples, 0.20%)wrapper (polars/series/utils.py:107) (574 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (574 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (574 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (599 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (604 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (604 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (603 samples, 0.21%)wrapper (polars/series/utils.py:107) (601 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (600 samples, 0.21%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (610 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (540 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (539 samples, 0.18%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (543 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (543 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (543 samples, 0.19%)wrapper (polars/series/utils.py:107) (542 samples, 0.19%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (550 samples, 0.19%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (878 samples, 0.30%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,321 samples, 0.79%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (858 samples, 0.29%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,204 samples, 0.41%)join (polars/dataframe/frame.py:6927) (1,203 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (1,202 samples, 0.41%)do (mesa_frames/abstract/agents.py:825) (28,308 samples, 9.69%)do (mesa_frame..move (sugarscape_ig/ss_polars/agents.py:55) (5,718 samples, 1.96%)m..move_agents (mesa_frames/abstract/space.py:139) (5,718 samples, 1.96%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,407 samples, 0.48%)step (sugarscape_ig/ss_polars/agents.py:47) (28,504 samples, 9.75%)step (sugarsca..remove (mesa_frames/concrete/agents.py:245) (671 samples, 0.23%)_discard (mesa_frames/concrete/polars/agentset.py:445) (549 samples, 0.19%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (549 samples, 0.19%)wrapper (polars/series/utils.py:107) (548 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (548 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (548 samples, 0.19%)contains (mesa_frames/concrete/agents.py:144) (296 samples, 0.10%)wrapper (polars/series/utils.py:107) (295 samples, 0.10%)select_seq (polars/dataframe/frame.py:8742) (295 samples, 0.10%)collect (polars/lazyframe/frame.py:2027) (294 samples, 0.10%)remove_agents (mesa_frames/abstract/space.py:1473) (302 samples, 0.10%)remove (mesa_frames/concrete/agents.py:254) (526 samples, 0.18%)discard (mesa_frames/abstract/agents.py:787) (1,594 samples, 0.55%)discard (mesa_frames/abstract/agents.py:100) (1,594 samples, 0.55%)remove (mesa_frames/abstract/agents.py:879) (1,335 samples, 0.46%)run_model (sugarscape_ig/ss_polars/model.py:41) (30,122 samples, 10.31%)run_model (suga..step (mesa_frames/concrete/model.py:134) (30,122 samples, 10.31%)step (mesa_fram..step (mesa_frames/concrete/agents.py:340) (30,122 samples, 10.31%)step (mesa_fram..step (sugarscape_ig/ss_polars/agents.py:48) (1,618 samples, 0.55%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (592 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,042 samples, 0.70%)empty_cells (mesa_frames/abstract/space.py:1064) (2,034 samples, 0.70%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,432 samples, 0.49%)run_model (sugarscape_ig/ss_polars/model.py:43) (596 samples, 0.20%)full_cells (mesa_frames/abstract/space.py:1090) (596 samples, 0.20%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (584 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,415 samples, 0.48%)join (polars/dataframe/frame.py:6927) (1,263 samples, 0.43%)collect (polars/lazyframe/frame.py:2027) (1,263 samples, 0.43%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (10,321 samples, 3.53%)_df..join (polars/dataframe/frame.py:6927) (10,321 samples, 3.53%)joi..collect (polars/lazyframe/frame.py:2027) (10,321 samples, 3.53%)col.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (536 samples, 0.18%)sort (polars/dataframe/frame.py:4939) (493 samples, 0.17%)collect (polars/lazyframe/frame.py:2027) (493 samples, 0.17%)run_model (sugarscape_ig/ss_polars/model.py:49) (11,155 samples, 3.82%)run_..set_cells (mesa_frames/abstract/space.py:763) (11,141 samples, 3.81%)set_.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (15,692 samples, 5.37%)_df_com..join (polars/dataframe/frame.py:6927) (15,692 samples, 5.37%)join (p..collect (polars/lazyframe/frame.py:2027) (15,692 samples, 5.37%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (856 samples, 0.29%)sort (polars/dataframe/frame.py:4939) (819 samples, 0.28%)collect (polars/lazyframe/frame.py:2027) (818 samples, 0.28%)set_cells (mesa_frames/abstract/space.py:763) (17,084 samples, 5.85%)set_cel..mesa_frames_polars_loop_DF (sugarscape_ig/performance_comparison.py:53) (62,580 samples, 21.41%)mesa_frames_polars_loop_DF (sugars..run_model (sugarscape_ig/ss_polars/model.py:50) (17,093 samples, 5.85%)run_mod.._place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (320 samples, 0.11%)sample_cells (mesa_frames/abstract/space.py:703) (320 samples, 0.11%)mesa_frames_polars_loop_no_vec (sugarscape_ig/performance_comparison.py:57) (436 samples, 0.15%)__init__ (sugarscape_ig/ss_polars/model.py:35) (368 samples, 0.13%)place_to_empty (mesa_frames/abstract/space.py:651) (368 samples, 0.13%)collect (polars/lazyframe/frame.py:2027) (538 samples, 0.18%)set (mesa_frames/concrete/polars/agentset.py:190) (540 samples, 0.18%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (540 samples, 0.18%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (540 samples, 0.18%)wrapper (polars/series/utils.py:107) (540 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (539 samples, 0.18%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (625 samples, 0.21%)wrapper (polars/series/utils.py:107) (625 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (625 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (625 samples, 0.21%)set (mesa_frames/concrete/polars/agentset.py:191) (643 samples, 0.22%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,207 samples, 0.41%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,206 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (606 samples, 0.21%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (608 samples, 0.21%)wrapper (polars/series/utils.py:107) (608 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (607 samples, 0.21%)get (mesa_frames/concrete/polars/agentset.py:173) (630 samples, 0.22%)eat (sugarscape_ig/ss_polars/agents.py:41) (636 samples, 0.22%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (636 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:1026) (636 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:456) (636 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (604 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (605 samples, 0.21%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (607 samples, 0.21%)wrapper (polars/series/utils.py:107) (606 samples, 0.21%)get (mesa_frames/concrete/polars/agentset.py:173) (615 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (620 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (620 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (620 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (680 samples, 0.23%)_get_df_coords (mesa_frames/abstract/space.py:1640) (568 samples, 0.19%)contains (mesa_frames/concrete/agents.py:144) (562 samples, 0.19%)wrapper (polars/series/utils.py:107) (562 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (560 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (559 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (542 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (542 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1647) (544 samples, 0.19%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (543 samples, 0.19%)wrapper (polars/series/utils.py:107) (543 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (554 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (554 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (554 samples, 0.19%)wrapper (polars/series/utils.py:107) (553 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (552 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (552 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1657) (561 samples, 0.19%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,734 samples, 0.59%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,580 samples, 2.25%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,580 samples, 2.25%)_..join (polars/dataframe/frame.py:6927) (6,580 samples, 2.25%)j..collect (polars/lazyframe/frame.py:2027) (6,580 samples, 2.25%)c..get_neighborhood (mesa_frames/abstract/space.py:1363) (381 samples, 0.13%)__le__ (polars/series/series.py:833) (379 samples, 0.13%)_comp (polars/series/series.py:753) (378 samples, 0.13%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (9,245 samples, 3.16%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,612 samples, 0.55%)join (polars/dataframe/frame.py:6927) (1,330 samples, 0.46%)collect (polars/lazyframe/frame.py:2027) (1,329 samples, 0.45%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (629 samples, 0.22%)join (polars/dataframe/frame.py:6927) (474 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (474 samples, 0.16%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (626 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (626 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (626 samples, 0.21%)wrapper (polars/series/utils.py:107) (626 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (625 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (625 samples, 0.21%)pos (mesa_frames/abstract/agents.py:1071) (638 samples, 0.22%)move (sugarscape_ig/ss_polars/agents.py:51) (12,142 samples, 4.15%)move .._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (651 samples, 0.22%)pos (mesa_frames/concrete/polars/agentset.py:536) (651 samples, 0.22%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (1,093 samples, 0.37%)unique (polars/dataframe/frame.py:9533) (1,093 samples, 0.37%)collect (polars/lazyframe/frame.py:2027) (1,093 samples, 0.37%)move (sugarscape_ig/ss_polars/agents.py:52) (1,128 samples, 0.39%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:103) (358 samples, 0.12%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (1,150 samples, 0.39%)sort (polars/dataframe/frame.py:4939) (1,147 samples, 0.39%)collect (polars/lazyframe/frame.py:2027) (1,147 samples, 0.39%)move (sugarscape_ig/ss_polars/agents.py:53) (2,097 samples, 0.72%)select_seq (polars/dataframe/frame.py:8742) (684 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (684 samples, 0.23%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (685 samples, 0.23%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (685 samples, 0.23%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (685 samples, 0.23%)wrapper (polars/series/utils.py:107) (685 samples, 0.23%)pos (mesa_frames/abstract/agents.py:1071) (690 samples, 0.24%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:213) (815 samples, 0.28%)pos (mesa_frames/concrete/polars/agentset.py:536) (701 samples, 0.24%)__add__ (polars/series/series.py:1048) (645 samples, 0.22%)_arithmetic (polars/series/series.py:997) (645 samples, 0.22%)get_best_moves (sugarscape_ig/ss_polars/agents.py:167) (2,360 samples, 0.81%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:224) (1,378 samples, 0.47%)__mul__ (polars/series/series.py:1118) (683 samples, 0.23%)_arithmetic (polars/series/series.py:1030) (683 samples, 0.23%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:243) (10,533 samples, 3.60%)inne..__iter__ (polars/series/series.py:1224) (6,433 samples, 2.20%)_..to_list (polars/series/series.py:4039) (1,590 samples, 0.54%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:244) (5,348 samples, 1.83%)i..inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:245) (7,095 samples, 2.43%)in..__getitem__ (polars/series/series.py:1236) (1,324 samples, 0.45%)get_series_item_by_key (polars/_utils/getitem.py:52) (1,097 samples, 0.38%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:246) (1,154 samples, 0.39%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:248) (1,984 samples, 0.68%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:250) (1,766 samples, 0.60%)<lambda> (sugarscape_ig/ss_polars/agents.py:174) (29,272 samples, 10.02%)<lambda> (suga..inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:251) (1,392 samples, 0.48%)__call__ (polars/expr/expr.py:4267) (29,290 samples, 10.02%)__call__ (pola..get_best_moves (sugarscape_ig/ss_polars/agents.py:196) (29,386 samples, 10.05%)get_best_moves ..select (polars/dataframe/frame.py:8717) (29,295 samples, 10.02%)select (polars..collect (polars/lazyframe/frame.py:2027) (29,295 samples, 10.02%)collect (polar..move (sugarscape_ig/ss_polars/agents.py:54) (31,793 samples, 10.88%)move (sugarscape.._place_or_move_agents (mesa_frames/abstract/space.py:1709) (635 samples, 0.22%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (635 samples, 0.22%)wrapper (polars/series/utils.py:107) (635 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (635 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (635 samples, 0.22%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (621 samples, 0.21%)contains (mesa_frames/concrete/agents.py:144) (615 samples, 0.21%)wrapper (polars/series/utils.py:107) (614 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (614 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (614 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (634 samples, 0.22%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (636 samples, 0.22%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (636 samples, 0.22%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (636 samples, 0.22%)wrapper (polars/series/utils.py:107) (636 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (635 samples, 0.22%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (641 samples, 0.22%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (642 samples, 0.22%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (642 samples, 0.22%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (642 samples, 0.22%)wrapper (polars/series/utils.py:107) (642 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (642 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (642 samples, 0.22%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (647 samples, 0.22%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (915 samples, 0.31%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,505 samples, 0.86%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (911 samples, 0.31%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,205 samples, 0.41%)join (polars/dataframe/frame.py:6927) (1,205 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (1,205 samples, 0.41%)do (mesa_frames/abstract/agents.py:825) (56,036 samples, 19.17%)do (mesa_frames/abstract/agent..move (sugarscape_ig/ss_polars/agents.py:55) (5,903 samples, 2.02%)m..move_agents (mesa_frames/abstract/space.py:139) (5,903 samples, 2.02%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,393 samples, 0.48%)step (sugarscape_ig/ss_polars/agents.py:47) (56,225 samples, 19.24%)step (sugarscape_ig/ss_polars/..collect (polars/lazyframe/frame.py:2027) (548 samples, 0.19%)remove (mesa_frames/concrete/agents.py:245) (693 samples, 0.24%)_discard (mesa_frames/concrete/polars/agentset.py:445) (552 samples, 0.19%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (552 samples, 0.19%)wrapper (polars/series/utils.py:107) (550 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (550 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (307 samples, 0.11%)remove_agents (mesa_frames/abstract/space.py:1473) (308 samples, 0.11%)contains (mesa_frames/concrete/agents.py:144) (308 samples, 0.11%)wrapper (polars/series/utils.py:107) (308 samples, 0.11%)select_seq (polars/dataframe/frame.py:8742) (308 samples, 0.11%)remove (mesa_frames/concrete/agents.py:254) (518 samples, 0.18%)discard (mesa_frames/abstract/agents.py:787) (1,656 samples, 0.57%)discard (mesa_frames/abstract/agents.py:100) (1,656 samples, 0.57%)remove (mesa_frames/abstract/agents.py:879) (1,363 samples, 0.47%)run_model (sugarscape_ig/ss_polars/model.py:41) (57,898 samples, 19.81%)run_model (sugarscape_ig/ss_pol..step (mesa_frames/concrete/model.py:134) (57,898 samples, 19.81%)step (mesa_frames/concrete/mode..step (mesa_frames/concrete/agents.py:340) (57,898 samples, 19.81%)step (mesa_frames/concrete/agen..step (sugarscape_ig/ss_polars/agents.py:48) (1,673 samples, 0.57%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (574 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,105 samples, 0.72%)empty_cells (mesa_frames/abstract/space.py:1064) (2,096 samples, 0.72%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,516 samples, 0.52%)run_model (sugarscape_ig/ss_polars/model.py:43) (639 samples, 0.22%)full_cells (mesa_frames/abstract/space.py:1090) (639 samples, 0.22%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (619 samples, 0.21%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,352 samples, 0.46%)join (polars/dataframe/frame.py:6927) (1,174 samples, 0.40%)collect (polars/lazyframe/frame.py:2027) (1,173 samples, 0.40%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (11,226 samples, 3.84%)_df_..join (polars/dataframe/frame.py:6927) (11,225 samples, 3.84%)join..collect (polars/lazyframe/frame.py:2027) (11,224 samples, 3.84%)coll.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (539 samples, 0.18%)sort (polars/dataframe/frame.py:4939) (510 samples, 0.17%)collect (polars/lazyframe/frame.py:2027) (510 samples, 0.17%)run_model (sugarscape_ig/ss_polars/model.py:49) (12,107 samples, 4.14%)run_m..set_cells (mesa_frames/abstract/space.py:763) (12,075 samples, 4.13%)set_c.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (15,635 samples, 5.35%)_df_com..join (polars/dataframe/frame.py:6927) (15,634 samples, 5.35%)join (p..collect (polars/lazyframe/frame.py:2027) (15,634 samples, 5.35%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (858 samples, 0.29%)sort (polars/dataframe/frame.py:4939) (817 samples, 0.28%)collect (polars/lazyframe/frame.py:2027) (817 samples, 0.28%)set_cells (mesa_frames/abstract/space.py:763) (17,055 samples, 5.84%)set_cel..mesa_frames_polars_loop_no_vec (sugarscape_ig/performance_comparison.py:64) (91,305 samples, 31.24%)mesa_frames_polars_loop_no_vec (sugarscape_ig/perf..run_model (sugarscape_ig/ss_polars/model.py:50) (17,064 samples, 5.84%)run_mod.._place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (329 samples, 0.11%)sample_cells (mesa_frames/abstract/space.py:703) (329 samples, 0.11%)mesa_frames_polars_numba_cpu (sugarscape_ig/performance_comparison.py:68) (433 samples, 0.15%)__init__ (sugarscape_ig/ss_polars/model.py:35) (375 samples, 0.13%)place_to_empty (mesa_frames/abstract/space.py:651) (375 samples, 0.13%)collect (polars/lazyframe/frame.py:2027) (612 samples, 0.21%)set (mesa_frames/concrete/polars/agentset.py:190) (613 samples, 0.21%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (613 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (613 samples, 0.21%)wrapper (polars/series/utils.py:107) (613 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (613 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (539 samples, 0.18%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (544 samples, 0.19%)wrapper (polars/series/utils.py:107) (543 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (542 samples, 0.19%)set (mesa_frames/concrete/polars/agentset.py:191) (562 samples, 0.19%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,209 samples, 0.41%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,204 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (629 samples, 0.22%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (631 samples, 0.22%)wrapper (polars/series/utils.py:107) (631 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (630 samples, 0.22%)get (mesa_frames/concrete/polars/agentset.py:173) (642 samples, 0.22%)eat (sugarscape_ig/ss_polars/agents.py:41) (651 samples, 0.22%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (651 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:1026) (651 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:456) (651 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (587 samples, 0.20%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (590 samples, 0.20%)wrapper (polars/series/utils.py:107) (589 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (588 samples, 0.20%)get (mesa_frames/concrete/polars/agentset.py:173) (606 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (610 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (610 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (610 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (674 samples, 0.23%)_get_df_coords (mesa_frames/abstract/space.py:1640) (607 samples, 0.21%)contains (mesa_frames/concrete/agents.py:144) (605 samples, 0.21%)wrapper (polars/series/utils.py:107) (604 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (603 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (603 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (565 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1647) (571 samples, 0.20%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (571 samples, 0.20%)wrapper (polars/series/utils.py:107) (568 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (568 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (637 samples, 0.22%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (637 samples, 0.22%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (637 samples, 0.22%)wrapper (polars/series/utils.py:107) (637 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (637 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (637 samples, 0.22%)_get_df_coords (mesa_frames/abstract/space.py:1657) (642 samples, 0.22%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,875 samples, 0.64%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,537 samples, 2.24%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,537 samples, 2.24%)_..join (polars/dataframe/frame.py:6927) (6,536 samples, 2.24%)j..collect (polars/lazyframe/frame.py:2027) (6,536 samples, 2.24%)c..get_neighborhood (mesa_frames/abstract/space.py:1363) (320 samples, 0.11%)__le__ (polars/series/series.py:833) (320 samples, 0.11%)_comp (polars/series/series.py:753) (320 samples, 0.11%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (9,281 samples, 3.18%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,567 samples, 0.54%)join (polars/dataframe/frame.py:6927) (1,274 samples, 0.44%)collect (polars/lazyframe/frame.py:2027) (1,274 samples, 0.44%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (699 samples, 0.24%)join (polars/dataframe/frame.py:6927) (545 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (545 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (541 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (541 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (541 samples, 0.19%)wrapper (polars/series/utils.py:107) (541 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (540 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (540 samples, 0.18%)pos (mesa_frames/abstract/agents.py:1071) (545 samples, 0.19%)move (sugarscape_ig/ss_polars/agents.py:51) (12,125 samples, 4.15%)move .._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (570 samples, 0.20%)pos (mesa_frames/concrete/polars/agentset.py:536) (569 samples, 0.19%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (995 samples, 0.34%)unique (polars/dataframe/frame.py:9533) (995 samples, 0.34%)collect (polars/lazyframe/frame.py:2027) (995 samples, 0.34%)move (sugarscape_ig/ss_polars/agents.py:52) (1,037 samples, 0.35%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:103) (357 samples, 0.12%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (1,096 samples, 0.37%)sort (polars/dataframe/frame.py:4939) (1,094 samples, 0.37%)collect (polars/lazyframe/frame.py:2027) (1,094 samples, 0.37%)move (sugarscape_ig/ss_polars/agents.py:53) (2,046 samples, 0.70%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (673 samples, 0.23%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (673 samples, 0.23%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (673 samples, 0.23%)wrapper (polars/series/utils.py:107) (673 samples, 0.23%)select_seq (polars/dataframe/frame.py:8742) (673 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (673 samples, 0.23%)pos (mesa_frames/abstract/agents.py:1071) (682 samples, 0.23%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:213) (809 samples, 0.28%)pos (mesa_frames/concrete/polars/agentset.py:536) (693 samples, 0.24%)__add__ (polars/series/series.py:1048) (631 samples, 0.22%)_arithmetic (polars/series/series.py:997) (631 samples, 0.22%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:224) (1,318 samples, 0.45%)__mul__ (polars/series/series.py:1118) (640 samples, 0.22%)_arithmetic (polars/series/series.py:1030) (640 samples, 0.22%)get_best_moves (sugarscape_ig/ss_polars/agents.py:167) (2,301 samples, 0.79%)lower (numba/core/lowering.py:187) (357 samples, 0.12%)lower_normal_function (numba/core/lowering.py:226) (346 samples, 0.12%)lower_function_body (numba/core/lowering.py:256) (344 samples, 0.12%)lower_block (numba/core/lowering.py:270) (337 samples, 0.12%)run_pass (numba/core/typed_passes.py:468) (595 samples, 0.20%)get_executable (numba/core/cpu.py:239) (321 samples, 0.11%)get_pointer_to_function (numba/core/codegen.py:989) (321 samples, 0.11%)_ensure_finalized (numba/core/codegen.py:567) (321 samples, 0.11%)run_pass (numba/core/typed_passes.py:497) (323 samples, 0.11%)_runPass (numba/core/compiler_machinery.py:311) (1,432 samples, 0.49%)check (numba/core/compiler_machinery.py:273) (1,432 samples, 0.49%)wrap (numba/np/ufunc/decorators.py:203) (1,550 samples, 0.53%)add (numba/np/ufunc/gufunc.py:137) (1,550 samples, 0.53%)add (numba/np/ufunc/ufuncbuilder.py:257) (1,550 samples, 0.53%)_compile_element_wise_function (numba/np/ufunc/ufuncbuilder.py:175) (1,550 samples, 0.53%)compile (numba/np/ufunc/ufuncbuilder.py:123) (1,549 samples, 0.53%)_compile_core (numba/np/ufunc/ufuncbuilder.py:156) (1,546 samples, 0.53%)compile_extra (numba/core/compiler.py:744) (1,535 samples, 0.53%)compile_extra (numba/core/compiler.py:438) (1,530 samples, 0.52%)_compile_bytecode (numba/core/compiler.py:506) (1,530 samples, 0.52%)_compile_core (numba/core/compiler.py:472) (1,527 samples, 0.52%)run (numba/core/compiler_machinery.py:356) (1,527 samples, 0.52%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (1,526 samples, 0.52%)build_ufunc (numba/np/ufunc/ufuncbuilder.py:376) (630 samples, 0.22%)build (numba/np/ufunc/ufuncbuilder.py:406) (383 samples, 0.13%)get_pointer_to_function (numba/core/codegen.py:989) (383 samples, 0.13%)_ensure_finalized (numba/core/codegen.py:567) (383 samples, 0.13%)get_best_moves (sugarscape_ig/ss_polars/agents.py:168) (2,190 samples, 0.75%)_get_best_moves (sugarscape_ig/ss_polars/agents.py:259) (2,190 samples, 0.75%)wrap (numba/np/ufunc/decorators.py:206) (632 samples, 0.22%)build_ufunc (numba/np/ufunc/gufunc.py:140) (632 samples, 0.22%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (632 samples, 0.22%)<lambda> (polars/series/series.py:1411) (2,759 samples, 0.94%)<lambda> (sugarscape_ig/ss_polars/agents.py:185) (2,762 samples, 0.95%)__call__ (numba/np/ufunc/gufunc.py:252) (2,762 samples, 0.95%)__array_ufunc__ (polars/series/series.py:1410) (2,760 samples, 0.94%)get_best_moves (sugarscape_ig/ss_polars/agents.py:196) (2,868 samples, 0.98%)select (polars/dataframe/frame.py:8717) (2,763 samples, 0.95%)collect (polars/lazyframe/frame.py:2027) (2,763 samples, 0.95%)__call__ (polars/expr/expr.py:4267) (2,763 samples, 0.95%)move (sugarscape_ig/ss_polars/agents.py:54) (7,417 samples, 2.54%)mo.._df_contains (mesa_frames/concrete/polars/mixin.py:206) (597 samples, 0.20%)wrapper (polars/series/utils.py:107) (597 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (596 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1709) (598 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (582 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (595 samples, 0.20%)contains (mesa_frames/concrete/agents.py:144) (585 samples, 0.20%)wrapper (polars/series/utils.py:107) (584 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (584 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (624 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (624 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (624 samples, 0.21%)wrapper (polars/series/utils.py:107) (624 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (622 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (621 samples, 0.21%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (630 samples, 0.22%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (578 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (578 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (578 samples, 0.20%)wrapper (polars/series/utils.py:107) (578 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (578 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (577 samples, 0.20%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (584 samples, 0.20%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (884 samples, 0.30%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,489 samples, 0.85%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (980 samples, 0.34%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,297 samples, 0.44%)join (polars/dataframe/frame.py:6927) (1,295 samples, 0.44%)collect (polars/lazyframe/frame.py:2027) (1,295 samples, 0.44%)do (mesa_frames/abstract/agents.py:825) (31,510 samples, 10.78%)do (mesa_frames/..move (sugarscape_ig/ss_polars/agents.py:55) (5,942 samples, 2.03%)m..move_agents (mesa_frames/abstract/space.py:139) (5,942 samples, 2.03%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,526 samples, 0.52%)step (sugarscape_ig/ss_polars/agents.py:47) (31,688 samples, 10.84%)step (sugarscape.._get_masked_df (mesa_frames/concrete/polars/agentset.py:397) (309 samples, 0.11%)wrapper (polars/series/utils.py:107) (308 samples, 0.11%)select_seq (polars/dataframe/frame.py:8742) (307 samples, 0.11%)collect (polars/lazyframe/frame.py:2027) (307 samples, 0.11%)remove (mesa_frames/abstract/agents.py:878) (316 samples, 0.11%)remove (mesa_frames/concrete/agents.py:245) (751 samples, 0.26%)_discard (mesa_frames/concrete/polars/agentset.py:445) (613 samples, 0.21%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (613 samples, 0.21%)wrapper (polars/series/utils.py:107) (613 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (612 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (612 samples, 0.21%)remove_agents (mesa_frames/abstract/space.py:1473) (330 samples, 0.11%)contains (mesa_frames/concrete/agents.py:144) (327 samples, 0.11%)wrapper (polars/series/utils.py:107) (327 samples, 0.11%)select_seq (polars/dataframe/frame.py:8742) (327 samples, 0.11%)collect (polars/lazyframe/frame.py:2027) (326 samples, 0.11%)remove (mesa_frames/concrete/agents.py:254) (552 samples, 0.19%)discard (mesa_frames/abstract/agents.py:100) (1,764 samples, 0.60%)remove (mesa_frames/abstract/agents.py:879) (1,448 samples, 0.50%)discard (mesa_frames/abstract/agents.py:787) (1,765 samples, 0.60%)run_model (sugarscape_ig/ss_polars/model.py:41) (33,464 samples, 11.45%)run_model (sugars..step (mesa_frames/concrete/model.py:134) (33,464 samples, 11.45%)step (mesa_frames..step (mesa_frames/concrete/agents.py:340) (33,464 samples, 11.45%)step (mesa_frames..step (sugarscape_ig/ss_polars/agents.py:48) (1,776 samples, 0.61%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (576 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,068 samples, 0.71%)empty_cells (mesa_frames/abstract/space.py:1064) (2,062 samples, 0.71%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,472 samples, 0.50%)run_model (sugarscape_ig/ss_polars/model.py:43) (669 samples, 0.23%)full_cells (mesa_frames/abstract/space.py:1090) (669 samples, 0.23%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (657 samples, 0.22%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,367 samples, 0.47%)join (polars/dataframe/frame.py:6927) (1,193 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (1,193 samples, 0.41%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (11,378 samples, 3.89%)_df_..join (polars/dataframe/frame.py:6927) (11,378 samples, 3.89%)join..collect (polars/lazyframe/frame.py:2027) (11,378 samples, 3.89%)coll.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (522 samples, 0.18%)sort (polars/dataframe/frame.py:4939) (479 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (479 samples, 0.16%)set_cells (mesa_frames/abstract/space.py:763) (12,297 samples, 4.21%)set_c..run_model (sugarscape_ig/ss_polars/model.py:49) (12,314 samples, 4.21%)run_m.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (16,027 samples, 5.48%)_df_com..join (polars/dataframe/frame.py:6927) (16,026 samples, 5.48%)join (p..collect (polars/lazyframe/frame.py:2027) (16,026 samples, 5.48%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (889 samples, 0.30%)sort (polars/dataframe/frame.py:4939) (848 samples, 0.29%)collect (polars/lazyframe/frame.py:2027) (848 samples, 0.29%)set_cells (mesa_frames/abstract/space.py:763) (17,478 samples, 5.98%)set_cell..mesa_frames_polars_numba_cpu (sugarscape_ig/performance_comparison.py:75) (67,489 samples, 23.09%)mesa_frames_polars_numba_cpu (sugarsc..run_model (sugarscape_ig/ss_polars/model.py:50) (17,485 samples, 5.98%)run_mode.._place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (305 samples, 0.10%)sample_cells (mesa_frames/abstract/space.py:703) (305 samples, 0.10%)mesa_frames_polars_numba_parallel (sugarscape_ig/performance_comparison.py:90) (415 samples, 0.14%)__init__ (sugarscape_ig/ss_polars/model.py:35) (357 samples, 0.12%)place_to_empty (mesa_frames/abstract/space.py:651) (357 samples, 0.12%)set (mesa_frames/concrete/polars/agentset.py:190) (535 samples, 0.18%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (535 samples, 0.18%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (535 samples, 0.18%)wrapper (polars/series/utils.py:107) (535 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (534 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (533 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (552 samples, 0.19%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (554 samples, 0.19%)wrapper (polars/series/utils.py:107) (554 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (554 samples, 0.19%)set (mesa_frames/concrete/polars/agentset.py:191) (571 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,143 samples, 0.39%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,139 samples, 0.39%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (560 samples, 0.19%)wrapper (polars/series/utils.py:107) (560 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (558 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (556 samples, 0.19%)get (mesa_frames/concrete/polars/agentset.py:173) (575 samples, 0.20%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (579 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:1026) (579 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:456) (579 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:41) (580 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (595 samples, 0.20%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (597 samples, 0.20%)wrapper (polars/series/utils.py:107) (597 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)get (mesa_frames/concrete/polars/agentset.py:173) (605 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (614 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (614 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (614 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (682 samples, 0.23%)_get_df_coords (mesa_frames/abstract/space.py:1640) (527 samples, 0.18%)contains (mesa_frames/concrete/agents.py:144) (520 samples, 0.18%)wrapper (polars/series/utils.py:107) (519 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (518 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (518 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (575 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (576 samples, 0.20%)_get_df_coords (mesa_frames/abstract/space.py:1647) (580 samples, 0.20%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (580 samples, 0.20%)wrapper (polars/series/utils.py:107) (579 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (596 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (596 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (596 samples, 0.20%)wrapper (polars/series/utils.py:107) (595 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (594 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (594 samples, 0.20%)_get_df_coords (mesa_frames/abstract/space.py:1657) (604 samples, 0.21%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,761 samples, 0.60%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,505 samples, 2.23%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,505 samples, 2.23%)_..join (polars/dataframe/frame.py:6927) (6,505 samples, 2.23%)j..collect (polars/lazyframe/frame.py:2027) (6,504 samples, 2.23%)c.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (9,077 samples, 3.11%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,514 samples, 0.52%)join (polars/dataframe/frame.py:6927) (1,215 samples, 0.42%)collect (polars/lazyframe/frame.py:2027) (1,215 samples, 0.42%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (737 samples, 0.25%)join (polars/dataframe/frame.py:6927) (577 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (577 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (595 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (595 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (595 samples, 0.20%)wrapper (polars/series/utils.py:107) (595 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (595 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (595 samples, 0.20%)pos (mesa_frames/abstract/agents.py:1071) (597 samples, 0.20%)move (sugarscape_ig/ss_polars/agents.py:51) (11,945 samples, 4.09%)move.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (613 samples, 0.21%)pos (mesa_frames/concrete/polars/agentset.py:536) (613 samples, 0.21%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (1,128 samples, 0.39%)unique (polars/dataframe/frame.py:9533) (1,128 samples, 0.39%)collect (polars/lazyframe/frame.py:2027) (1,128 samples, 0.39%)move (sugarscape_ig/ss_polars/agents.py:52) (1,175 samples, 0.40%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:103) (337 samples, 0.12%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (1,121 samples, 0.38%)sort (polars/dataframe/frame.py:4939) (1,116 samples, 0.38%)collect (polars/lazyframe/frame.py:2027) (1,116 samples, 0.38%)move (sugarscape_ig/ss_polars/agents.py:53) (2,077 samples, 0.71%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (596 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (596 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (596 samples, 0.20%)wrapper (polars/series/utils.py:107) (596 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (596 samples, 0.20%)pos (mesa_frames/abstract/agents.py:1071) (604 samples, 0.21%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:213) (741 samples, 0.25%)pos (mesa_frames/concrete/polars/agentset.py:536) (622 samples, 0.21%)__add__ (polars/series/series.py:1048) (650 samples, 0.22%)_arithmetic (polars/series/series.py:997) (650 samples, 0.22%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:224) (1,297 samples, 0.44%)__mul__ (polars/series/series.py:1118) (603 samples, 0.21%)_arithmetic (polars/series/series.py:1030) (602 samples, 0.21%)get_best_moves (sugarscape_ig/ss_polars/agents.py:167) (2,237 samples, 0.77%)lower (numba/core/lowering.py:187) (359 samples, 0.12%)lower_normal_function (numba/core/lowering.py:226) (348 samples, 0.12%)lower_function_body (numba/core/lowering.py:256) (348 samples, 0.12%)lower_block (numba/core/lowering.py:270) (333 samples, 0.11%)run_pass (numba/core/typed_passes.py:468) (574 samples, 0.20%)get_executable (numba/core/cpu.py:239) (347 samples, 0.12%)get_pointer_to_function (numba/core/codegen.py:989) (347 samples, 0.12%)_ensure_finalized (numba/core/codegen.py:567) (347 samples, 0.12%)run_pass (numba/core/typed_passes.py:497) (348 samples, 0.12%)_runPass (numba/core/compiler_machinery.py:311) (1,467 samples, 0.50%)check (numba/core/compiler_machinery.py:273) (1,467 samples, 0.50%)_compile_core (numba/np/ufunc/ufuncbuilder.py:156) (1,567 samples, 0.54%)compile_extra (numba/core/compiler.py:744) (1,558 samples, 0.53%)compile_extra (numba/core/compiler.py:438) (1,555 samples, 0.53%)_compile_bytecode (numba/core/compiler.py:506) (1,555 samples, 0.53%)_compile_core (numba/core/compiler.py:472) (1,551 samples, 0.53%)run (numba/core/compiler_machinery.py:356) (1,550 samples, 0.53%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (1,546 samples, 0.53%)_compile_element_wise_function (numba/np/ufunc/ufuncbuilder.py:175) (1,572 samples, 0.54%)compile (numba/np/ufunc/ufuncbuilder.py:123) (1,570 samples, 0.54%)wrap (numba/np/ufunc/decorators.py:203) (1,573 samples, 0.54%)add (numba/np/ufunc/ufuncbuilder.py:257) (1,573 samples, 0.54%)build_gufunc_wrapper (numba/np/ufunc/parallel.py:264) (303 samples, 0.10%)build_gufunc_wrapper (numba/np/ufunc/wrappers.py:504) (303 samples, 0.10%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (303 samples, 0.10%)build (numba/np/ufunc/wrappers.py:456) (303 samples, 0.10%)_compile_wrapper (numba/np/ufunc/wrappers.py:447) (299 samples, 0.10%)build_gufunc_kernel (numba/np/ufunc/parallel.py:152) (412 samples, 0.14%)add_linking_library (numba/core/codegen.py:720) (412 samples, 0.14%)_ensure_finalized (numba/core/codegen.py:567) (412 samples, 0.14%)build (numba/np/ufunc/parallel.py:233) (746 samples, 0.26%)build_gufunc_wrapper (numba/np/ufunc/parallel.py:271) (443 samples, 0.15%)get_pointer_to_function (numba/core/codegen.py:989) (416 samples, 0.14%)_ensure_finalized (numba/core/codegen.py:567) (416 samples, 0.14%)get_best_moves (sugarscape_ig/ss_polars/agents.py:168) (2,741 samples, 0.94%)_get_best_moves (sugarscape_ig/ss_polars/agents.py:259) (2,741 samples, 0.94%)wrap (numba/np/ufunc/decorators.py:206) (1,163 samples, 0.40%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (1,163 samples, 0.40%)build_ufunc (numba/np/ufunc/ufuncbuilder.py:376) (1,163 samples, 0.40%)build (numba/np/ufunc/parallel.py:237) (417 samples, 0.14%)<lambda> (polars/series/series.py:1411) (2,955 samples, 1.01%)<lambda> (sugarscape_ig/ss_polars/agents.py:185) (2,957 samples, 1.01%)__array_ufunc__ (polars/series/series.py:1410) (2,957 samples, 1.01%)get_best_moves (sugarscape_ig/ss_polars/agents.py:196) (3,087 samples, 1.06%)select (polars/dataframe/frame.py:8717) (2,960 samples, 1.01%)collect (polars/lazyframe/frame.py:2027) (2,960 samples, 1.01%)__call__ (polars/expr/expr.py:4267) (2,958 samples, 1.01%)move (sugarscape_ig/ss_polars/agents.py:54) (8,156 samples, 2.79%)mo..collect (polars/lazyframe/frame.py:2027) (578 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1709) (580 samples, 0.20%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (580 samples, 0.20%)wrapper (polars/series/utils.py:107) (580 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (579 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (640 samples, 0.22%)contains (mesa_frames/concrete/agents.py:144) (629 samples, 0.22%)wrapper (polars/series/utils.py:107) (626 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (626 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (626 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (609 samples, 0.21%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (612 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (611 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (611 samples, 0.21%)wrapper (polars/series/utils.py:107) (610 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (610 samples, 0.21%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (616 samples, 0.21%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (624 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (624 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (624 samples, 0.21%)wrapper (polars/series/utils.py:107) (624 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (624 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (624 samples, 0.21%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (636 samples, 0.22%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (889 samples, 0.30%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,499 samples, 0.86%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (944 samples, 0.32%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,222 samples, 0.42%)join (polars/dataframe/frame.py:6927) (1,221 samples, 0.42%)collect (polars/lazyframe/frame.py:2027) (1,220 samples, 0.42%)do (mesa_frames/abstract/agents.py:825) (32,055 samples, 10.97%)do (mesa_frames/..move (sugarscape_ig/ss_polars/agents.py:55) (5,859 samples, 2.00%)m..move_agents (mesa_frames/abstract/space.py:139) (5,859 samples, 2.00%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,420 samples, 0.49%)step (sugarscape_ig/ss_polars/agents.py:47) (32,226 samples, 11.03%)step (sugarscape..select_seq (polars/dataframe/frame.py:8742) (322 samples, 0.11%)collect (polars/lazyframe/frame.py:2027) (322 samples, 0.11%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:397) (323 samples, 0.11%)wrapper (polars/series/utils.py:107) (323 samples, 0.11%)remove (mesa_frames/abstract/agents.py:878) (334 samples, 0.11%)remove (mesa_frames/concrete/agents.py:245) (713 samples, 0.24%)_discard (mesa_frames/concrete/polars/agentset.py:445) (566 samples, 0.19%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (566 samples, 0.19%)wrapper (polars/series/utils.py:107) (566 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (565 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (565 samples, 0.19%)remove (mesa_frames/concrete/agents.py:254) (482 samples, 0.16%)discard (mesa_frames/abstract/agents.py:787) (1,651 samples, 0.56%)discard (mesa_frames/abstract/agents.py:100) (1,651 samples, 0.56%)remove (mesa_frames/abstract/agents.py:879) (1,317 samples, 0.45%)run_model (sugarscape_ig/ss_polars/model.py:41) (33,903 samples, 11.60%)run_model (sugars..step (mesa_frames/concrete/model.py:134) (33,903 samples, 11.60%)step (mesa_frames..step (mesa_frames/concrete/agents.py:340) (33,903 samples, 11.60%)step (mesa_frames..step (sugarscape_ig/ss_polars/agents.py:48) (1,677 samples, 0.57%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (513 samples, 0.18%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,057 samples, 0.70%)empty_cells (mesa_frames/abstract/space.py:1064) (2,052 samples, 0.70%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,534 samples, 0.52%)run_model (sugarscape_ig/ss_polars/model.py:43) (602 samples, 0.21%)full_cells (mesa_frames/abstract/space.py:1090) (601 samples, 0.21%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (591 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,390 samples, 0.48%)join (polars/dataframe/frame.py:6927) (1,222 samples, 0.42%)collect (polars/lazyframe/frame.py:2027) (1,222 samples, 0.42%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (11,266 samples, 3.85%)_df_..join (polars/dataframe/frame.py:6927) (11,263 samples, 3.85%)join..collect (polars/lazyframe/frame.py:2027) (11,262 samples, 3.85%)coll.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (569 samples, 0.19%)sort (polars/dataframe/frame.py:4939) (522 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (522 samples, 0.18%)set_cells (mesa_frames/abstract/space.py:763) (12,174 samples, 4.17%)set_c..run_model (sugarscape_ig/ss_polars/model.py:49) (12,192 samples, 4.17%)run_m.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (15,813 samples, 5.41%)_df_com..join (polars/dataframe/frame.py:6927) (15,812 samples, 5.41%)join (p..collect (polars/lazyframe/frame.py:2027) (15,812 samples, 5.41%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (945 samples, 0.32%)sort (polars/dataframe/frame.py:4939) (907 samples, 0.31%)collect (polars/lazyframe/frame.py:2027) (906 samples, 0.31%)set_cells (mesa_frames/abstract/space.py:763) (17,327 samples, 5.93%)set_cell..bench (perfplot/_main.py:521) (290,664 samples, 99.45%)bench (perfplot/_main.py:521)__next__ (perfplot/_main.py:253) (290,651 samples, 99.45%)__next__ (perfplot/_main.py:253)mesa_frames_polars_numba_parallel (sugarscape_ig/performance_comparison.py:97) (67,604 samples, 23.13%)mesa_frames_polars_numba_parallel (su..run_model (sugarscape_ig/ss_polars/model.py:50) (17,331 samples, 5.93%)run_mode..plot_and_print_benchmark (sugarscape_ig/performance_comparison.py:101) (290,665 samples, 99.45%)plot_and_print_benchmark (sugarscape_ig/performance_comparison.py:101)<module> (sugarscape_ig/performance_comparison.py:164) (290,672 samples, 99.45%)<module> (sugarscape_ig/performance_comparison.py:164)main (sugarscape_ig/performance_comparison.py:160) (290,671 samples, 99.45%)main (sugarscape_ig/performance_comparison.py:160)_check_buffer (rich/console.py:2060) (305 samples, 0.10%)refresh (rich/live.py:241) (380 samples, 0.13%)__exit__ (rich/console.py:865) (376 samples, 0.13%)_exit_buffer (rich/console.py:823) (373 samples, 0.13%)render (rich/console.py:1332) (363 samples, 0.12%)split_and_crop_lines (rich/segment.py:291) (395 samples, 0.14%)render_lines (rich/console.py:1373) (437 samples, 0.15%)render (rich/console.py:1332) (501 samples, 0.17%)__rich_console__ (rich/padding.py:97) (456 samples, 0.16%)split_and_crop_lines (rich/segment.py:291) (544 samples, 0.19%)render_lines (rich/console.py:1373) (587 samples, 0.20%)_render (rich/table.py:822) (604 samples, 0.21%)render (rich/console.py:1332) (853 samples, 0.29%)__rich_console__ (rich/table.py:509) (812 samples, 0.28%)split_and_crop_lines (rich/segment.py:291) (866 samples, 0.30%)render (rich/console.py:1336) (861 samples, 0.29%)__rich_console__ (rich/live_render.py:87) (890 samples, 0.30%)render_lines (rich/console.py:1373) (883 samples, 0.30%)render (rich/console.py:1332) (931 samples, 0.32%)print (rich/console.py:1700) (943 samples, 0.32%)all (292,271 samples, 100%)_bootstrap (threading.py:1002) (1,509 samples, 0.52%)_bootstrap_inner (threading.py:1045) (1,509 samples, 0.52%)run (rich/live.py:32) (1,489 samples, 0.51%)refresh (rich/live.py:242) (1,089 samples, 0.37%) \ No newline at end of file From ca9a7f7c436534f07a08c6979c263efe198cab22 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 14:37:34 +0000 Subject: [PATCH 09/37] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- README.md | 1 + examples/sugarscape_ig/performance_comparison.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e7a9c88..750ec30 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ The following is a performance graph showing execution time using mesa and mesa- ## Installation ### Install from PyPI + ```bash pip install mesa-frames ``` diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index b772dbc..110c1fc 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -142,7 +142,7 @@ def main(): "mesa-frames (pl loop no vec)", "mesa-frames (pl numba CPU)", "mesa-frames (pl numba parallel)", - #"mesa-frames (pl numba GPU)", + # "mesa-frames (pl numba GPU)", ] # Polars best_moves (non-vectorized loop vs DF loop vs numba loop) kernels_1 = [ @@ -151,7 +151,7 @@ def main(): mesa_frames_polars_loop_no_vec, mesa_frames_polars_numba_cpu, mesa_frames_polars_numba_parallel, - #mesa_frames_polars_numba_gpu, + # mesa_frames_polars_numba_gpu, ] n_range_1 = [k for k in range(1, 2 * 10**6 + 2, 10**6)] # n_range_1 = [k for k in range(10000, 100002, 10000)] From 01663c63970fdc871d878420091ea050879e140f Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:37:48 +0200 Subject: [PATCH 10/37] correcting dtypes --- examples/sugarscape_ig/ss_polars/agents.py | 36 ++++++++++------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 5908f81..d3250c0 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -2,7 +2,7 @@ import numpy as np import polars as pl -from numba import b1, guvectorize, int64 +from numba import b1, guvectorize, int32 from mesa_frames import AgentSetPolars, ModelDF @@ -155,15 +155,10 @@ def get_best_moves(self, neighborhood, agent_order): return best_moves.select(["dim_0", "dim_1"]) -import numpy as np -import polars as pl -from numba import guvectorize, int64 - - class AntPolarsLoop(AntPolarsBase): numba_target = None - def get_best_moves(self, neighborhood, agent_order): + def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): occupied_cells, free_cells, target_cells = self._prepare_cells(neighborhood) best_moves_func = self._get_best_moves() @@ -178,14 +173,14 @@ def get_best_moves(self, neighborhood, agent_order): df.struct.field("agent_order"), df.struct.field("blocking_agent_order"), processed_agents, - best_moves=np.full(len(self.agents), -1, dtype=np.int64), + best_moves=np.full(len(self.agents), -1, dtype=np.int32), ) else: # Vectorized case: Polars will create the output array (best_moves) automatically map_batches_func = lambda df: best_moves_func( - occupied_cells, - free_cells, - target_cells, + occupied_cells.astype(np.int32), + free_cells.astype(np.bool_), + target_cells.astype(np.int32), df.struct.field("agent_order"), df.struct.field("blocking_agent_order"), processed_agents, @@ -193,6 +188,7 @@ def get_best_moves(self, neighborhood, agent_order): best_moves = ( neighborhood.fill_null(-1) +.cast({"agent_order": pl.Int32, "blocking_agent_order": pl.Int32}) .select( pl.struct(["agent_order", "blocking_agent_order"]).map_batches( map_batches_func @@ -242,7 +238,7 @@ def inner_get_best_moves( ) -> np.ndarray: for i, agent in enumerate(agent_id_center): if not processed_agents[agent]: - if free_cells[target_cells[i]] or blocking_agent[i] == agent: + if free_cells[target_cells[i]] or (blocking_agent[i] == agent): best_moves[agent] = target_cells[i] # Free current cell free_cells[occupied_cells[agent]] = True @@ -259,13 +255,13 @@ def _get_best_moves(self): @guvectorize( [ ( - int64[:], - int64[:], - int64[:], - int64[:], - int64[:], - int64[:], - int64[:], + int32[:], + b1[:], + int32[:], + int32[:], + int32[:], + int32[:], + int32[:], ) ], "(n), (m), (p), (p), (p), (n)->(n)", @@ -283,7 +279,7 @@ def vectorized_get_best_moves( ): for i, agent in enumerate(agent_id_center): if not processed_agents[agent]: - if free_cells[target_cells[i]] or blocking_agent[i] == agent: + if free_cells[target_cells[i]] or (blocking_agent[i] == agent): best_moves[agent] = target_cells[i] # Free current cell free_cells[occupied_cells[agent]] = True From 1dff9bbf8c07c86bab6baffb5994d55ae7aa3af3 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:38:33 +0200 Subject: [PATCH 11/37] adding writable_args (see https://numba.readthedocs.io/en/stable/user/vectorize.html#overwriting-input-values) --- examples/sugarscape_ig/ss_polars/agents.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index d3250c0..e953771 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -267,6 +267,10 @@ def _get_best_moves(self): "(n), (m), (p), (p), (p), (n)->(n)", nopython=True, target=self.numba_target, +writable_args=( + "free_cells", + "processed_agents", + ), # Writable inputs have to be declared ) def vectorized_get_best_moves( occupied_cells, From ec2437b2428c474104527033aa2e7d6046acb329 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Fri, 20 Sep 2024 10:02:09 +0200 Subject: [PATCH 12/37] processed_agents is of type bool --- examples/sugarscape_ig/ss_polars/agents.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index e953771..46dffe8 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -183,7 +183,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): target_cells.astype(np.int32), df.struct.field("agent_order"), df.struct.field("blocking_agent_order"), - processed_agents, + processed_agents.astype(np.bool_), ) best_moves = ( @@ -260,7 +260,7 @@ def _get_best_moves(self): int32[:], int32[:], int32[:], - int32[:], + b1[:], int32[:], ) ], From 845aa61f7e867adc770d88d39b60e06404a1bd1b Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:44:09 +0200 Subject: [PATCH 13/37] fix: occupied cells sorted by agent_order, assertion to verify best moves aren't duplicated --- examples/sugarscape_ig/ss_polars/agents.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 46dffe8..c0b6840 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -200,16 +200,20 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): ) .drop("agent_order") ) +assert best_moves.n_unique() == len( + best_moves + ), "Duplicates found in best_moves" return best_moves def _prepare_cells(self, neighborhood: pl.DataFrame): occupied_cells = ( - neighborhood[["agent_id_center"]] + neighborhood[["agent_id_center", "agent_order"]] .unique() .join(self.pos, left_on="agent_id_center", right_on="unique_id") .with_columns( flattened=(pl.col("dim_0") * self.space.dimensions[1] + pl.col("dim_1")) - )["flattened"] + ).sort("agent_order") +["flattened"] .to_numpy() ) free_cells = np.ones( From ced1d1632e46da711ac52050e932cd9a4f2ea9b2 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:52:51 +0200 Subject: [PATCH 14/37] adding fixed initial positions (to assert equality between simulations) --- .../sugarscape_ig/performance_comparison.py | 49 +++++++++++++++---- examples/sugarscape_ig/ss_polars/model.py | 4 ++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 110c1fc..9706d17 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -3,6 +3,7 @@ import matplotlib.pyplot as plt import numpy as np import perfplot +import polars as pl import seaborn as sns from ss_mesa.model import SugarscapeMesa from ss_pandas.model import SugarscapePandas @@ -28,6 +29,24 @@ def __init__(self, n: int): self.initial_sugar = np.random.randint(6, 25, n) self.metabolism = np.random.randint(2, 4, n) self.vision = np.random.randint(1, 6, n) +self.initial_positions = pl.DataFrame( + schema={"dim_0": pl.Int64, "dim_1": pl.Int64} + ) + while self.initial_positions.shape[0] < n: + initial_pos_0 = np.random.randint( + 0, dimension, n - self.initial_positions.shape[0] + ) + initial_pos_1 = np.random.randint( + 0, dimension, n - self.initial_positions.shape[0] + ) + self.initial_positions = self.initial_positions.vstack( + pl.DataFrame( + { + "dim_0": initial_pos_0, + "dim_1": initial_pos_1, + } + ) + ).unique() def mesa_implementation(setup: SugarScapeSetup): @@ -43,58 +62,68 @@ def mesa_frames_pandas_concise(setup: SugarScapeSetup): def mesa_frames_polars_loop_DF(setup: SugarScapeSetup): - return SugarscapePolars( + model = SugarscapePolars( AntPolarsLoopDF, setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision, - ).run_model(100) + setup.initial_positions, + ) + model.run_model(100) def mesa_frames_polars_loop_no_vec(setup: SugarScapeSetup): - return SugarscapePolars( + model = SugarscapePolars( AntPolarsLoopNoVec, setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision, - ).run_model(100) + setup.initial_positions, + ) + model.run_model(100) def mesa_frames_polars_numba_cpu(setup: SugarScapeSetup): - return SugarscapePolars( + model = SugarscapePolars( AntPolarsNumbaCPU, setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision, - ).run_model(100) + setup.initial_positions, + ) + model.run_model(100) def mesa_frames_polars_numba_gpu(setup: SugarScapeSetup): - return SugarscapePolars( + model = SugarscapePolars( AntPolarsNumbaGPU, setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision, - ).run_model(100) + setup.initial_positions, + ) + model.run_model(100) def mesa_frames_polars_numba_parallel(setup: SugarScapeSetup): - return SugarscapePolars( + model = SugarscapePolars( AntPolarsNumbaParallel, setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision, - ).run_model(100) + setup.initial_positions, + ) + model.run_model(100) def plot_and_print_benchmark(labels, kernels, n_range, title, image_path): diff --git a/examples/sugarscape_ig/ss_polars/model.py b/examples/sugarscape_ig/ss_polars/model.py index 8ddc73c..9f9895f 100644 --- a/examples/sugarscape_ig/ss_polars/model.py +++ b/examples/sugarscape_ig/ss_polars/model.py @@ -15,6 +15,7 @@ def __init__( initial_sugar: np.ndarray | None = None, metabolism: np.ndarray | None = None, vision: np.ndarray | None = None, +initial_positions: pl.DataFrame | None = None, width: int | None = None, height: int | None = None, ): @@ -32,6 +33,9 @@ def __init__( ) self.space.set_cells(sugar_grid) self.agents += agent_type(self, n_agents, initial_sugar, metabolism, vision) +if initial_positions is not None: + self.space.place_agents(self.agents, initial_positions) + else: self.space.place_to_empty(self.agents) def run_model(self, steps: int) -> list[int]: From 67b2803f98d3bc8606c76001e4943c67f51007a4 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:25:22 +0200 Subject: [PATCH 15/37] adding complete reproducibility via seed --- .../sugarscape_ig/performance_comparison.py | 36 ++++++++++++++----- examples/sugarscape_ig/ss_polars/model.py | 3 +- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 9706d17..bb461b2 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -24,19 +24,21 @@ def __init__(self, n: int): else: density = 0.04 # mesa self.n = n +self.seed = 42 dimension = math.ceil(math.sqrt(n / density)) - self.sugar_grid = np.random.randint(0, 4, (dimension, dimension)) - self.initial_sugar = np.random.randint(6, 25, n) - self.metabolism = np.random.randint(2, 4, n) - self.vision = np.random.randint(1, 6, n) +random_gen = np.random.default_rng(self.seed) + self.sugar_grid = random_gen.integers(0, 4, (dimension, dimension)) + self.initial_sugar = random_gen.integers(6, 25, n) + self.metabolism = random_gen.integers(2, 4, n) + self.vision = random_gen.integers(1, 6, n) self.initial_positions = pl.DataFrame( schema={"dim_0": pl.Int64, "dim_1": pl.Int64} ) while self.initial_positions.shape[0] < n: - initial_pos_0 = np.random.randint( + initial_pos_0 = random_gen.integers( 0, dimension, n - self.initial_positions.shape[0] ) - initial_pos_1 = np.random.randint( + initial_pos_1 = random_gen.integers( 0, dimension, n - self.initial_positions.shape[0] ) self.initial_positions = self.initial_positions.vstack( @@ -46,18 +48,29 @@ def __init__(self, n: int): "dim_1": initial_pos_1, } ) - ).unique() + ).unique(maintain_order=True) + return def mesa_implementation(setup: SugarScapeSetup): return SugarscapeMesa( - setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision + setup.n, +setup.sugar_grid, +setup.initial_sugar, +setup.metabolism, +setup.vision, + setup.seed, ).run_model(100) def mesa_frames_pandas_concise(setup: SugarScapeSetup): return SugarscapePandas( - setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision + setup.n, +setup.sugar_grid, +setup.initial_sugar, +setup.metabolism, +setup.vision, + setup.seed, ).run_model(100) @@ -70,6 +83,7 @@ def mesa_frames_polars_loop_DF(setup: SugarScapeSetup): setup.metabolism, setup.vision, setup.initial_positions, +setup.seed, ) model.run_model(100) @@ -83,6 +97,7 @@ def mesa_frames_polars_loop_no_vec(setup: SugarScapeSetup): setup.metabolism, setup.vision, setup.initial_positions, +setup.seed, ) model.run_model(100) @@ -96,6 +111,7 @@ def mesa_frames_polars_numba_cpu(setup: SugarScapeSetup): setup.metabolism, setup.vision, setup.initial_positions, +setup.seed, ) model.run_model(100) @@ -109,6 +125,7 @@ def mesa_frames_polars_numba_gpu(setup: SugarScapeSetup): setup.metabolism, setup.vision, setup.initial_positions, +setup.seed, ) model.run_model(100) @@ -122,6 +139,7 @@ def mesa_frames_polars_numba_parallel(setup: SugarScapeSetup): setup.metabolism, setup.vision, setup.initial_positions, +setup.seed, ) model.run_model(100) diff --git a/examples/sugarscape_ig/ss_polars/model.py b/examples/sugarscape_ig/ss_polars/model.py index 9f9895f..bd02c94 100644 --- a/examples/sugarscape_ig/ss_polars/model.py +++ b/examples/sugarscape_ig/ss_polars/model.py @@ -16,10 +16,11 @@ def __init__( metabolism: np.ndarray | None = None, vision: np.ndarray | None = None, initial_positions: pl.DataFrame | None = None, + seed: int | None = None, width: int | None = None, height: int | None = None, ): - super().__init__() + super().__init__(seed) if sugar_grid is None: sugar_grid = self.random.integers(0, 4, (width, height)) grid_dimensions = sugar_grid.shape From 5d6534593cdaeb306247d305db060ed6dbf3d555 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:27:13 +0200 Subject: [PATCH 16/37] fix: taking into account potential (max) sugar when creating the neighborhood. For both numba and completely vectorized it's easier to reason this way then update the current sugar and "best moves" ranking when agents move --- examples/sugarscape_ig/ss_polars/agents.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index c0b6840..7a36059 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -99,16 +99,23 @@ def _prepare_neighborhood(self, neighborhood, agent_order): how="left", ).rename({"agent_id": "blocking_agent_id"}) - # Filter impossible moves + # Filter possible moves neighborhood = neighborhood.filter( (pl.col("agent_order") >= pl.col("blocking_agent_order")) | pl.col("blocking_agent_order").is_null() ) - # Sort cells by agent_order, sugar and radius (nearest first) - - return neighborhood.sort( - ["agent_order", "sugar", "radius"], descending=[False, True, False] + + # Sort neighborhood by agent_order & max_sugar (max_sugar because we will check anyway if the cell is empty) + # However, we need to make sure that the current agent cell is ordered by current sugar (since it's 0 until agent hasn't moved) + neighborhood = neighborhood.with_columns( + max_sugar=pl.when(pl.col("blocking_agent_id") == pl.col("agent_id_center")) + .then(pl.lit(0)) + .otherwise(pl.col("max_sugar")) + ).sort( + ["agent_order", "max_sugar", "radius", "dim_0"], +descending=[False, True, False, False], ) +return neighborhood def get_best_moves(self, neighborhood, agent_order): raise NotImplementedError("This method should be implemented by subclasses") From 862caa22468d9c61ae1ca50f9e10ea8549ac5139 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:29:19 +0200 Subject: [PATCH 17/37] fix: considering priority (if there are previous order agents that might make the same move and haven't found the optimal move yet). This avoids race conditions. --- examples/sugarscape_ig/ss_polars/agents.py | 29 ++++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 7a36059..03e9a3e 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -122,26 +122,33 @@ def get_best_moves(self, neighborhood, agent_order): class AntPolarsLoopDF(AntPolarsBase): - def get_best_moves(self, neighborhood, agent_order): + def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): best_moves = pl.DataFrame() # While there are agents that do not have a best move, keep looking for one while len(best_moves) < len(self.agents): - # Get the best moves for each agent and if duplicates are found, select the one with the highest order +# Check if there are previous agents that might make the same move + neighborhood = neighborhood.with_columns( + priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"]) + ) + + # Get the best moves for each agent: + # If duplicates are found, select the one with the highest order new_best_moves = ( neighborhood.group_by("agent_id_center", maintain_order=True) .first() - .sort("agent_order") - .unique(subset=["dim_0", "dim_1"], keep="first") + .unique(subset=["dim_0", "dim_1"], keep="first", maintain_order=True) ) # Agents can make the move if: # - There is no blocking agent # - The agent is in its own cell # - The blocking agent has moved before him +# - There isn't a higher priority agent that might make the same move - condition = pl.col("blocking_agent_id").is_null() | ( - pl.col("blocking_agent_id") == pl.col("agent_id_center") - ) + condition = ( +pl.col("blocking_agent_id").is_null() + | (pl.col("blocking_agent_id") == pl.col("agent_id_center")) + ) & (pl.col("priority") == 1) if len(best_moves) > 0: condition = condition | pl.col("blocking_agent_id").is_in( best_moves["agent_id_center"] @@ -154,12 +161,18 @@ def get_best_moves(self, neighborhood, agent_order): neighborhood = neighborhood.filter( ~pl.col("agent_id_center").is_in(best_moves["agent_id_center"]) ) + # Remove cells that have been already selected neighborhood = neighborhood.join( best_moves.select(["dim_0", "dim_1"]), on=["dim_0", "dim_1"], how="anti" ) - return best_moves.select(["dim_0", "dim_1"]) +# Recompute priority + neighborhood = neighborhood.with_columns( + priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"]) + ) + + return best_moves.sort("agent_order").select(["dim_0", "dim_1"]) class AntPolarsLoop(AntPolarsBase): From feb8c6fa97661195a6a9e95916cafc2e51655e2c Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:29:38 +0200 Subject: [PATCH 18/37] fix: formatting --- examples/sugarscape_ig/ss_polars/agents.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 03e9a3e..6ee0568 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -232,14 +232,15 @@ def _prepare_cells(self, neighborhood: pl.DataFrame): .join(self.pos, left_on="agent_id_center", right_on="unique_id") .with_columns( flattened=(pl.col("dim_0") * self.space.dimensions[1] + pl.col("dim_1")) - ).sort("agent_order") -["flattened"] + ) +.sort("agent_order")["flattened"] .to_numpy() ) free_cells = np.ones( self.space.dimensions[0] * self.space.dimensions[1], dtype=np.bool_ ) free_cells[occupied_cells] = False + target_cells = ( neighborhood["dim_0"] * self.space.dimensions[1] + neighborhood["dim_1"] ).to_numpy() From a93a84d6af8c4d560e41c7c0542f467671612d16 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:31:04 +0200 Subject: [PATCH 19/37] clarifying with comments --- examples/sugarscape_ig/ss_polars/agents.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 6ee0568..c428b39 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -262,8 +262,10 @@ def inner_get_best_moves( best_moves: np.ndarray, ) -> np.ndarray: for i, agent in enumerate(agent_id_center): +# If the agent has not moved yet if not processed_agents[agent]: - if free_cells[target_cells[i]] or (blocking_agent[i] == agent): +# If the target cell is free + if free_cells[target_cells[i]] or blocking_agent[i] == agent: best_moves[agent] = target_cells[i] # Free current cell free_cells[occupied_cells[agent]] = True @@ -307,8 +309,10 @@ def vectorized_get_best_moves( best_moves, ): for i, agent in enumerate(agent_id_center): +# If the agent has not moved yet if not processed_agents[agent]: - if free_cells[target_cells[i]] or (blocking_agent[i] == agent): +# If the target cell is free + if free_cells[target_cells[i]] or blocking_agent[i] == agent: best_moves[agent] = target_cells[i] # Free current cell free_cells[occupied_cells[agent]] = True From 801a98c0b51f01efa4acd327ff38e98c30375371 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:32:00 +0200 Subject: [PATCH 20/37] updating actual sugar before executing the step (NOTE: might be unncessary since we prepare the neighborhood looking at potential/max sugar anyway) --- examples/sugarscape_ig/ss_polars/model.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/model.py b/examples/sugarscape_ig/ss_polars/model.py index bd02c94..22df018 100644 --- a/examples/sugarscape_ig/ss_polars/model.py +++ b/examples/sugarscape_ig/ss_polars/model.py @@ -43,13 +43,11 @@ def run_model(self, steps: int) -> list[int]: for _ in range(steps): if len(self.agents) == 0: return - self.step() - empty_cells = self.space.empty_cells + empty_cells = self.space.empty_cells full_cells = self.space.full_cells - max_sugar = self.space.cells.join( empty_cells, on=["dim_0", "dim_1"] ).select(pl.col("max_sugar")) - self.space.set_cells(full_cells, {"sugar": 0}) self.space.set_cells(empty_cells, {"sugar": max_sugar}) +self.step() From dff31aa0e6f5e0abe4ddeb58cd792fb1c41373e2 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:34:22 +0200 Subject: [PATCH 21/37] whitespace fixes --- .../sugarscape_ig/performance_comparison.py | 42 +++++++++---------- examples/sugarscape_ig/ss_polars/agents.py | 32 +++++++------- examples/sugarscape_ig/ss_polars/model.py | 10 ++--- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index bb461b2..23a8273 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -24,14 +24,14 @@ def __init__(self, n: int): else: density = 0.04 # mesa self.n = n -self.seed = 42 + self.seed = 42 dimension = math.ceil(math.sqrt(n / density)) -random_gen = np.random.default_rng(self.seed) + random_gen = np.random.default_rng(self.seed) self.sugar_grid = random_gen.integers(0, 4, (dimension, dimension)) self.initial_sugar = random_gen.integers(6, 25, n) self.metabolism = random_gen.integers(2, 4, n) self.vision = random_gen.integers(1, 6, n) -self.initial_positions = pl.DataFrame( + self.initial_positions = pl.DataFrame( schema={"dim_0": pl.Int64, "dim_1": pl.Int64} ) while self.initial_positions.shape[0] < n: @@ -55,10 +55,10 @@ def __init__(self, n: int): def mesa_implementation(setup: SugarScapeSetup): return SugarscapeMesa( setup.n, -setup.sugar_grid, -setup.initial_sugar, -setup.metabolism, -setup.vision, + setup.sugar_grid, + setup.initial_sugar, + setup.metabolism, + setup.vision, setup.seed, ).run_model(100) @@ -66,10 +66,10 @@ def mesa_implementation(setup: SugarScapeSetup): def mesa_frames_pandas_concise(setup: SugarScapeSetup): return SugarscapePandas( setup.n, -setup.sugar_grid, -setup.initial_sugar, -setup.metabolism, -setup.vision, + setup.sugar_grid, + setup.initial_sugar, + setup.metabolism, + setup.vision, setup.seed, ).run_model(100) @@ -82,8 +82,8 @@ def mesa_frames_polars_loop_DF(setup: SugarScapeSetup): setup.initial_sugar, setup.metabolism, setup.vision, - setup.initial_positions, -setup.seed, + setup.initial_positions, + setup.seed, ) model.run_model(100) @@ -96,8 +96,8 @@ def mesa_frames_polars_loop_no_vec(setup: SugarScapeSetup): setup.initial_sugar, setup.metabolism, setup.vision, - setup.initial_positions, -setup.seed, + setup.initial_positions, + setup.seed, ) model.run_model(100) @@ -110,8 +110,8 @@ def mesa_frames_polars_numba_cpu(setup: SugarScapeSetup): setup.initial_sugar, setup.metabolism, setup.vision, - setup.initial_positions, -setup.seed, + setup.initial_positions, + setup.seed, ) model.run_model(100) @@ -124,8 +124,8 @@ def mesa_frames_polars_numba_gpu(setup: SugarScapeSetup): setup.initial_sugar, setup.metabolism, setup.vision, - setup.initial_positions, -setup.seed, + setup.initial_positions, + setup.seed, ) model.run_model(100) @@ -138,8 +138,8 @@ def mesa_frames_polars_numba_parallel(setup: SugarScapeSetup): setup.initial_sugar, setup.metabolism, setup.vision, - setup.initial_positions, -setup.seed, + setup.initial_positions, + setup.seed, ) model.run_model(100) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index c428b39..08afdc7 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -104,7 +104,7 @@ def _prepare_neighborhood(self, neighborhood, agent_order): (pl.col("agent_order") >= pl.col("blocking_agent_order")) | pl.col("blocking_agent_order").is_null() ) - + # Sort neighborhood by agent_order & max_sugar (max_sugar because we will check anyway if the cell is empty) # However, we need to make sure that the current agent cell is ordered by current sugar (since it's 0 until agent hasn't moved) neighborhood = neighborhood.with_columns( @@ -113,9 +113,9 @@ def _prepare_neighborhood(self, neighborhood, agent_order): .otherwise(pl.col("max_sugar")) ).sort( ["agent_order", "max_sugar", "radius", "dim_0"], -descending=[False, True, False, False], + descending=[False, True, False, False], ) -return neighborhood + return neighborhood def get_best_moves(self, neighborhood, agent_order): raise NotImplementedError("This method should be implemented by subclasses") @@ -127,7 +127,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): # While there are agents that do not have a best move, keep looking for one while len(best_moves) < len(self.agents): -# Check if there are previous agents that might make the same move + # Check if there are previous agents that might make the same move neighborhood = neighborhood.with_columns( priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"]) ) @@ -137,16 +137,16 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): new_best_moves = ( neighborhood.group_by("agent_id_center", maintain_order=True) .first() - .unique(subset=["dim_0", "dim_1"], keep="first", maintain_order=True) + .unique(subset=["dim_0", "dim_1"], keep="first", maintain_order=True) ) # Agents can make the move if: # - There is no blocking agent # - The agent is in its own cell # - The blocking agent has moved before him -# - There isn't a higher priority agent that might make the same move + # - There isn't a higher priority agent that might make the same move condition = ( -pl.col("blocking_agent_id").is_null() + pl.col("blocking_agent_id").is_null() | (pl.col("blocking_agent_id") == pl.col("agent_id_center")) ) & (pl.col("priority") == 1) if len(best_moves) > 0: @@ -167,7 +167,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): best_moves.select(["dim_0", "dim_1"]), on=["dim_0", "dim_1"], how="anti" ) -# Recompute priority + # Recompute priority neighborhood = neighborhood.with_columns( priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"]) ) @@ -208,7 +208,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): best_moves = ( neighborhood.fill_null(-1) -.cast({"agent_order": pl.Int32, "blocking_agent_order": pl.Int32}) + .cast({"agent_order": pl.Int32, "blocking_agent_order": pl.Int32}) .select( pl.struct(["agent_order", "blocking_agent_order"]).map_batches( map_batches_func @@ -220,7 +220,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): ) .drop("agent_order") ) -assert best_moves.n_unique() == len( + assert best_moves.n_unique() == len( best_moves ), "Duplicates found in best_moves" return best_moves @@ -233,7 +233,7 @@ def _prepare_cells(self, neighborhood: pl.DataFrame): .with_columns( flattened=(pl.col("dim_0") * self.space.dimensions[1] + pl.col("dim_1")) ) -.sort("agent_order")["flattened"] + .sort("agent_order")["flattened"] .to_numpy() ) free_cells = np.ones( @@ -262,9 +262,9 @@ def inner_get_best_moves( best_moves: np.ndarray, ) -> np.ndarray: for i, agent in enumerate(agent_id_center): -# If the agent has not moved yet + # If the agent has not moved yet if not processed_agents[agent]: -# If the target cell is free + # If the target cell is free if free_cells[target_cells[i]] or blocking_agent[i] == agent: best_moves[agent] = target_cells[i] # Free current cell @@ -294,7 +294,7 @@ def _get_best_moves(self): "(n), (m), (p), (p), (p), (n)->(n)", nopython=True, target=self.numba_target, -writable_args=( + writable_args=( "free_cells", "processed_agents", ), # Writable inputs have to be declared @@ -309,9 +309,9 @@ def vectorized_get_best_moves( best_moves, ): for i, agent in enumerate(agent_id_center): -# If the agent has not moved yet + # If the agent has not moved yet if not processed_agents[agent]: -# If the target cell is free + # If the target cell is free if free_cells[target_cells[i]] or blocking_agent[i] == agent: best_moves[agent] = target_cells[i] # Free current cell diff --git a/examples/sugarscape_ig/ss_polars/model.py b/examples/sugarscape_ig/ss_polars/model.py index 22df018..be9768c 100644 --- a/examples/sugarscape_ig/ss_polars/model.py +++ b/examples/sugarscape_ig/ss_polars/model.py @@ -15,7 +15,7 @@ def __init__( initial_sugar: np.ndarray | None = None, metabolism: np.ndarray | None = None, vision: np.ndarray | None = None, -initial_positions: pl.DataFrame | None = None, + initial_positions: pl.DataFrame | None = None, seed: int | None = None, width: int | None = None, height: int | None = None, @@ -34,20 +34,20 @@ def __init__( ) self.space.set_cells(sugar_grid) self.agents += agent_type(self, n_agents, initial_sugar, metabolism, vision) -if initial_positions is not None: + if initial_positions is not None: self.space.place_agents(self.agents, initial_positions) else: - self.space.place_to_empty(self.agents) + self.space.place_to_empty(self.agents) def run_model(self, steps: int) -> list[int]: for _ in range(steps): if len(self.agents) == 0: return - empty_cells = self.space.empty_cells + empty_cells = self.space.empty_cells full_cells = self.space.full_cells max_sugar = self.space.cells.join( empty_cells, on=["dim_0", "dim_1"] ).select(pl.col("max_sugar")) self.space.set_cells(full_cells, {"sugar": 0}) self.space.set_cells(empty_cells, {"sugar": max_sugar}) -self.step() + self.step() From bea9770df0b80cf72fd69d343084cb8c339d8822 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:54:20 +0200 Subject: [PATCH 22/37] adding initial_positions and seed to mesa model --- examples/sugarscape_ig/performance_comparison.py | 7 +++++-- examples/sugarscape_ig/ss_mesa/model.py | 13 +++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 23a8273..33c3e47 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -53,14 +53,17 @@ def __init__(self, n: int): def mesa_implementation(setup: SugarScapeSetup): - return SugarscapeMesa( + model = SugarscapeMesa( setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision, + setup.initial_positions, setup.seed, - ).run_model(100) + ) + model.run_model(100) + return model def mesa_frames_pandas_concise(setup: SugarScapeSetup): diff --git a/examples/sugarscape_ig/ss_mesa/model.py b/examples/sugarscape_ig/ss_mesa/model.py index 67336ed..06bad1a 100644 --- a/examples/sugarscape_ig/ss_mesa/model.py +++ b/examples/sugarscape_ig/ss_mesa/model.py @@ -1,5 +1,6 @@ import mesa import numpy as np +import polars as pl from .agents import AntMesa, Sugar @@ -16,6 +17,8 @@ def __init__( initial_sugar: np.ndarray | None = None, metabolism: np.ndarray | None = None, vision: np.ndarray | None = None, + initial_positions: pl.DataFrame | None = None, + seed: int | None = None, width: int | None = None, height: int | None = None, ): @@ -34,6 +37,8 @@ def __init__( metabolism = np.random.randint(2, 4, n_agents) if vision is None: vision = np.random.randint(1, 6, n_agents) + if seed is not None: + self.reset_randomizer(seed) self.width, self.height = sugar_grid.shape self.n_agents = n_agents @@ -51,8 +56,12 @@ def __init__( # Create agent: for i in range(self.n_agents): - x = self.random.randrange(self.width) - y = self.random.randrange(self.height) + if initial_positions is not None: + x = initial_positions["dim_0"][i] + y = initial_positions["dim_1"][i] + else: + x = self.random.randrange(self.width) + y = self.random.randrange(self.height) ssa = AntMesa( agent_id, self, False, initial_sugar[i], metabolism[i], vision[i] ) From 82b4df7207ba9b43defd8a8266298c90a33bc9aa Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:55:07 +0200 Subject: [PATCH 23/37] renaming grid to space for mesa_models --- examples/sugarscape_ig/ss_mesa/agents.py | 12 ++++++------ examples/sugarscape_ig/ss_mesa/model.py | 9 +++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/sugarscape_ig/ss_mesa/agents.py b/examples/sugarscape_ig/ss_mesa/agents.py index 797824f..7577203 100644 --- a/examples/sugarscape_ig/ss_mesa/agents.py +++ b/examples/sugarscape_ig/ss_mesa/agents.py @@ -25,20 +25,20 @@ def __init__(self, unique_id, model, moore=False, sugar=0, metabolism=0, vision= self.vision = vision def get_sugar(self, pos): - this_cell = self.model.grid.get_cell_list_contents([pos]) + this_cell = self.model.space.get_cell_list_contents([pos]) for agent in this_cell: if type(agent) is Sugar: return agent def is_occupied(self, pos): - this_cell = self.model.grid.get_cell_list_contents([pos]) + this_cell = self.model.space.get_cell_list_contents([pos]) return any(isinstance(agent, AntMesa) for agent in this_cell) def move(self): # Get neighborhood within vision neighbors = [ i - for i in self.model.grid.get_neighborhood( + for i in self.model.space.get_neighborhood( self.pos, self.moore, False, radius=self.vision ) if not self.is_occupied(i) @@ -55,7 +55,7 @@ def move(self): pos for pos in candidates if get_distance(self.pos, pos) == min_dist ] self.random.shuffle(final_candidates) - self.model.grid.move_agent(self, final_candidates[0]) + self.model.space.move_agent(self, final_candidates[0]) def eat(self): sugar_patch = self.get_sugar(self.pos) @@ -66,7 +66,7 @@ def step(self): self.move() self.eat() if self.sugar <= 0: - self.model.grid.remove_agent(self) + self.model.space.remove_agent(self) self.model.agents.remove(self) @@ -77,7 +77,7 @@ def __init__(self, unique_id, model, max_sugar): self.max_sugar = max_sugar def step(self): - if self.model.grid.is_cell_empty(self.pos): + if self.model.space.is_cell_empty(self.pos): self.amount = self.max_sugar else: self.amount = 0 diff --git a/examples/sugarscape_ig/ss_mesa/model.py b/examples/sugarscape_ig/ss_mesa/model.py index 06bad1a..076af8e 100644 --- a/examples/sugarscape_ig/ss_mesa/model.py +++ b/examples/sugarscape_ig/ss_mesa/model.py @@ -42,16 +42,17 @@ def __init__( self.width, self.height = sugar_grid.shape self.n_agents = n_agents - self.grid = mesa.space.MultiGrid(self.width, self.height, torus=False) + self.space = mesa.space.MultiGrid(self.width, self.height, torus=False) self.agents: list = [] agent_id = 0 self.sugars = [] - for _, (x, y) in self.grid.coord_iter(): + + for _, (x, y) in self.space.coord_iter(): max_sugar = sugar_grid[x, y] sugar = Sugar(agent_id, self, max_sugar) agent_id += 1 - self.grid.place_agent(sugar, (x, y)) + self.space.place_agent(sugar, (x, y)) self.sugars.append(sugar) # Create agent: @@ -66,7 +67,7 @@ def __init__( agent_id, self, False, initial_sugar[i], metabolism[i], vision[i] ) agent_id += 1 - self.grid.place_agent(ssa, (x, y)) + self.space.place_agent(ssa, (x, y)) self.agents.append(ssa) self.running = True From ac52026ce76dfbadb8d701bf154bc7e938044241 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:58:57 +0200 Subject: [PATCH 24/37] fix: best_moves only uses neighborhood and not agent_order --- examples/sugarscape_ig/ss_polars/agents.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 08afdc7..fba6d14 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -51,7 +51,7 @@ def move(self): neighborhood = self._get_neighborhood() agent_order = self._get_agent_order(neighborhood) neighborhood = self._prepare_neighborhood(neighborhood, agent_order) - best_moves = self.get_best_moves(neighborhood, agent_order) + best_moves = self.get_best_moves(neighborhood) self.space.move_agents(agent_order["agent_id_center"], best_moves) def _get_neighborhood(self): @@ -117,12 +117,12 @@ def _prepare_neighborhood(self, neighborhood, agent_order): ) return neighborhood - def get_best_moves(self, neighborhood, agent_order): - raise NotImplementedError("This method should be implemented by subclasses") + def get_best_moves(self, neighborhood: pl.DataFrame) -> pl.DataFrame: + raise NotImplementedError("Subclasses must implement this method") class AntPolarsLoopDF(AntPolarsBase): - def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): + def get_best_moves(self, neighborhood: pl.DataFrame): best_moves = pl.DataFrame() # While there are agents that do not have a best move, keep looking for one @@ -178,7 +178,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): class AntPolarsLoop(AntPolarsBase): numba_target = None - def get_best_moves(self, neighborhood: pl.DataFrame, agent_order): + def get_best_moves(self, neighborhood: pl.DataFrame): occupied_cells, free_cells, target_cells = self._prepare_cells(neighborhood) best_moves_func = self._get_best_moves() From 0bed775d75ac15001af352122b99a6d1d1a820fe Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:03:18 +0200 Subject: [PATCH 25/37] adding documentation and type hints --- examples/sugarscape_ig/ss_polars/agents.py | 90 +++++++++++++++++++--- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index fba6d14..06b2c91 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -54,7 +54,16 @@ def move(self): best_moves = self.get_best_moves(neighborhood) self.space.move_agents(agent_order["agent_id_center"], best_moves) - def _get_neighborhood(self): + def _get_neighborhood(self) -> pl.DataFrame: + """Get the neighborhood of each agent, completed with the sugar of the cell and the agent_id of the center cell + + NOTE: This method should be unnecessary if get_neighborhood/get_neighbors return the agent_id of the center cell and the properties of the cells + + Returns + ------- + pl.DataFrame + Neighborhood DataFrame + """ neighborhood: pl.DataFrame = self.space.get_neighborhood( radius=self["vision"], agents=self, include_center=True ) @@ -74,7 +83,19 @@ def _get_neighborhood(self): ) return neighborhood - def _get_agent_order(self, neighborhood): + def _get_agent_order(self, neighborhood: pl.DataFrame) -> pl.DataFrame: + """Get the order of agents based on the original order of agents + + Parameters + ---------- + neighborhood : pl.DataFrame + Neighborhood DataFrame + + Returns + ------- + pl.DataFrame + DataFrame with 'agent_id_center' and 'agent_order' columns + """ # Order of agents moves based on the original order of agents. # The agent in his cell has order 0 (highest) @@ -86,7 +107,23 @@ def _get_agent_order(self, neighborhood): .select(["agent_id_center", "agent_order"]) ) - def _prepare_neighborhood(self, neighborhood, agent_order): + def _prepare_neighborhood( + self, neighborhood: pl.DataFrame, agent_order: pl.DataFrame + ) -> pl.DataFrame: + """Prepare the neighborhood DataFrame to find the best moves + + Parameters + ---------- + neighborhood : pl.DataFrame + Neighborhood DataFrame + agent_order : pl.DataFrame + DataFrame with 'agent_id_center' and 'agent_order' columns + + Returns + ------- + pl.DataFrame + Prepared neighborhood DataFrame + """ neighborhood = neighborhood.join(agent_order, on="agent_id_center") # Add blocking agent order @@ -99,7 +136,7 @@ def _prepare_neighborhood(self, neighborhood, agent_order): how="left", ).rename({"agent_id": "blocking_agent_id"}) - # Filter possible moves + # Filter only possible moves (agent is in his cell, blocking agent has moved before him or there is no blocking agent) neighborhood = neighborhood.filter( (pl.col("agent_order") >= pl.col("blocking_agent_order")) | pl.col("blocking_agent_order").is_null() @@ -118,6 +155,18 @@ def _prepare_neighborhood(self, neighborhood, agent_order): return neighborhood def get_best_moves(self, neighborhood: pl.DataFrame) -> pl.DataFrame: + """Get the best moves for each agent + + Parameters + ---------- + neighborhood : pl.DataFrame + Neighborhood DataFrame + + Returns + ------- + pl.DataFrame + DataFrame with the best moves for each agent + """ raise NotImplementedError("Subclasses must implement this method") @@ -127,7 +176,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame): # While there are agents that do not have a best move, keep looking for one while len(best_moves) < len(self.agents): - # Check if there are previous agents that might make the same move + # Check if there are previous agents that might make the same move (priority for the given move is > 1) neighborhood = neighborhood.with_columns( priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"]) ) @@ -167,7 +216,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame): best_moves.select(["dim_0", "dim_1"]), on=["dim_0", "dim_1"], how="anti" ) - # Recompute priority + # Check if there are previous agents that might make the same move (priority for the given move is > 1) neighborhood = neighborhood.with_columns( priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"]) ) @@ -225,7 +274,22 @@ def get_best_moves(self, neighborhood: pl.DataFrame): ), "Duplicates found in best_moves" return best_moves - def _prepare_cells(self, neighborhood: pl.DataFrame): + def _prepare_cells( + self, neighborhood: pl.DataFrame + ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + """Get the occupied and free cells and the target cells for each agent, + based on the neighborhood DataFrame such that the arrays refer to a flattened version of the grid + + Parameters + ---------- + neighborhood : pl.DataFrame + Neighborhood DataFrame + + Returns + ------- + Tuple[np.ndarray, np.ndarray, np.ndarray] + occupied_cells, free_cells, target_cells + """ occupied_cells = ( neighborhood[["agent_id_center", "agent_order"]] .unique() @@ -251,6 +315,7 @@ def _get_best_moves(self): class AntPolarsLoopNoVec(AntPolarsLoop): + # Non-vectorized case def _get_best_moves(self): def inner_get_best_moves( occupied_cells: np.ndarray, @@ -278,6 +343,7 @@ def inner_get_best_moves( class AntPolarsNumba(AntPolarsLoop): + # Vectorized case def _get_best_moves(self): @guvectorize( [ @@ -294,10 +360,12 @@ def _get_best_moves(self): "(n), (m), (p), (p), (p), (n)->(n)", nopython=True, target=self.numba_target, - writable_args=( - "free_cells", - "processed_agents", - ), # Writable inputs have to be declared + # Writable inputs should be declared according to https://numba.pydata.org/numba-doc/dev/user/vectorize.html#overwriting-input-values + # In this case, there doesn't seem to be a difference. I will leave it commented for reference so that we can use CUDA target (which doesn't support writable_args) + # writable_args=( + # "free_cells", + # "processed_agents", + # ), ) def vectorized_get_best_moves( occupied_cells, From e86bb331395dd04931d0f21f2c6b8e25d98bf6ec Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:04:38 +0200 Subject: [PATCH 26/37] fix: logic for the priority condition (right order of parentheses) --- examples/sugarscape_ig/ss_polars/agents.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index 06b2c91..c8de91d 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -173,8 +173,8 @@ def get_best_moves(self, neighborhood: pl.DataFrame) -> pl.DataFrame: class AntPolarsLoopDF(AntPolarsBase): def get_best_moves(self, neighborhood: pl.DataFrame): best_moves = pl.DataFrame() - # While there are agents that do not have a best move, keep looking for one + # While there are agents that do not have a best move, keep looking for one while len(best_moves) < len(self.agents): # Check if there are previous agents that might make the same move (priority for the given move is > 1) neighborhood = neighborhood.with_columns( @@ -194,14 +194,16 @@ def get_best_moves(self, neighborhood: pl.DataFrame): # - The blocking agent has moved before him # - There isn't a higher priority agent that might make the same move - condition = ( - pl.col("blocking_agent_id").is_null() - | (pl.col("blocking_agent_id") == pl.col("agent_id_center")) - ) & (pl.col("priority") == 1) + condition = pl.col("blocking_agent_id").is_null() | ( + pl.col("blocking_agent_id") == pl.col("agent_id_center") + ) if len(best_moves) > 0: condition = condition | pl.col("blocking_agent_id").is_in( best_moves["agent_id_center"] ) + + condition = condition & (pl.col("priority") == 1) + new_best_moves = new_best_moves.filter(condition) best_moves = pl.concat([best_moves, new_best_moves]) @@ -220,7 +222,6 @@ def get_best_moves(self, neighborhood: pl.DataFrame): neighborhood = neighborhood.with_columns( priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"]) ) - return best_moves.sort("agent_order").select(["dim_0", "dim_1"]) From e40b83cffa57381b1ab38498e4e5fd4d80dd3cd8 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:05:24 +0200 Subject: [PATCH 27/37] removing assertion (testing purposes only) --- examples/sugarscape_ig/ss_polars/agents.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/sugarscape_ig/ss_polars/agents.py b/examples/sugarscape_ig/ss_polars/agents.py index c8de91d..78f2558 100644 --- a/examples/sugarscape_ig/ss_polars/agents.py +++ b/examples/sugarscape_ig/ss_polars/agents.py @@ -270,9 +270,6 @@ def get_best_moves(self, neighborhood: pl.DataFrame): ) .drop("agent_order") ) - assert best_moves.n_unique() == len( - best_moves - ), "Duplicates found in best_moves" return best_moves def _prepare_cells( From 79698bdaab38a98f65a1d04e3d29ace748642aa0 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:12:30 +0200 Subject: [PATCH 28/37] adding equality_check on model state --- .../sugarscape_ig/performance_comparison.py | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 33c3e47..9f21893 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -5,6 +5,7 @@ import perfplot import polars as pl import seaborn as sns +from polars.testing import assert_frame_equal from ss_mesa.model import SugarscapeMesa from ss_pandas.model import SugarscapePandas from ss_polars.agents import ( @@ -67,14 +68,17 @@ def mesa_implementation(setup: SugarScapeSetup): def mesa_frames_pandas_concise(setup: SugarScapeSetup): - return SugarscapePandas( + model = SugarscapePandas( setup.n, setup.sugar_grid, setup.initial_sugar, setup.metabolism, setup.vision, + setup.initial_positions, setup.seed, - ).run_model(100) + ) + model.run_model(100) + return model def mesa_frames_polars_loop_DF(setup: SugarScapeSetup): @@ -89,6 +93,7 @@ def mesa_frames_polars_loop_DF(setup: SugarScapeSetup): setup.seed, ) model.run_model(100) + return model def mesa_frames_polars_loop_no_vec(setup: SugarScapeSetup): @@ -103,6 +108,7 @@ def mesa_frames_polars_loop_no_vec(setup: SugarScapeSetup): setup.seed, ) model.run_model(100) + return model def mesa_frames_polars_numba_cpu(setup: SugarScapeSetup): @@ -117,6 +123,7 @@ def mesa_frames_polars_numba_cpu(setup: SugarScapeSetup): setup.seed, ) model.run_model(100) + return model def mesa_frames_polars_numba_gpu(setup: SugarScapeSetup): @@ -131,6 +138,7 @@ def mesa_frames_polars_numba_gpu(setup: SugarScapeSetup): setup.seed, ) model.run_model(100) + return model def mesa_frames_polars_numba_parallel(setup: SugarScapeSetup): @@ -145,16 +153,24 @@ def mesa_frames_polars_numba_parallel(setup: SugarScapeSetup): setup.seed, ) model.run_model(100) + return model -def plot_and_print_benchmark(labels, kernels, n_range, title, image_path): +def plot_and_print_benchmark( + labels: list[str], + kernels: list[callable], + n_range: list[int], + title: str, + image_path: str, + equality_check: callable | None = None, +): out = perfplot.bench( setup=SugarScapeSetup, kernels=kernels, labels=labels, n_range=n_range, xlabel="Number of agents", - equality_check=None, + equality_check=equality_check, title=title, ) plt.ylabel("Execution time (s)") @@ -167,6 +183,12 @@ def plot_and_print_benchmark(labels, kernels, n_range, title, image_path): print("---------------") +def polars_equality_check(a: SugarscapePolars, b: SugarscapePolars): + assert_frame_equal(a.agents, b.agents, check_row_order=False) + assert_frame_equal(a.space, b.space, check_row_order=False) + return True + + def main(): # Mesa comparison sns.set_theme(style="whitegrid") @@ -192,7 +214,7 @@ def main(): "mesa-frames (pl loop no vec)", "mesa-frames (pl numba CPU)", "mesa-frames (pl numba parallel)", - # "mesa-frames (pl numba GPU)", + "mesa-frames (pl numba GPU)", ] # Polars best_moves (non-vectorized loop vs DF loop vs numba loop) kernels_1 = [ @@ -201,13 +223,20 @@ def main(): mesa_frames_polars_loop_no_vec, mesa_frames_polars_numba_cpu, mesa_frames_polars_numba_parallel, - # mesa_frames_polars_numba_gpu, + mesa_frames_polars_numba_gpu, ] n_range_1 = [k for k in range(1, 2 * 10**6 + 2, 10**6)] # n_range_1 = [k for k in range(10000, 100002, 10000)] title_1 = "100 steps of the SugarScape IG model:\n" + " vs ".join(labels_1) image_path_1 = "polars_comparison.png" - plot_and_print_benchmark(labels_1, kernels_1, n_range_1, title_1, image_path_1) + plot_and_print_benchmark( + labels_1, + kernels_1, + n_range_1, + title_1, + image_path_1, + equality_check=polars_equality_check, + ) if __name__ == "__main__": From 2dedbece8eed08f5cb6f08106306e4187e8d34e4 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:13:27 +0200 Subject: [PATCH 29/37] changing n_range to reflect million of agents --- examples/sugarscape_ig/performance_comparison.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 9f21893..2e3d7c9 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -225,8 +225,7 @@ def main(): mesa_frames_polars_numba_parallel, mesa_frames_polars_numba_gpu, ] - n_range_1 = [k for k in range(1, 2 * 10**6 + 2, 10**6)] - # n_range_1 = [k for k in range(10000, 100002, 10000)] + n_range_1 = [k for k in range(10**6, 3 * 10**6 + 2, 10**6)] title_1 = "100 steps of the SugarScape IG model:\n" + " vs ".join(labels_1) image_path_1 = "polars_comparison.png" plot_and_print_benchmark( From ef664aeccc3b957694eb0a0bd9432921c1cc5c3c Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:16:21 +0200 Subject: [PATCH 30/37] fix: changing callable to typing.Callable --- examples/sugarscape_ig/performance_comparison.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 2e3d7c9..c593498 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -16,7 +16,7 @@ AntPolarsNumbaParallel, ) from ss_polars.model import SugarscapePolars - +from typing_extensions import Callable class SugarScapeSetup: def __init__(self, n: int): @@ -158,11 +158,11 @@ def mesa_frames_polars_numba_parallel(setup: SugarScapeSetup): def plot_and_print_benchmark( labels: list[str], - kernels: list[callable], + kernels: list[Callable], n_range: list[int], title: str, image_path: str, - equality_check: callable | None = None, + equality_check: Callable | None = None, ): out = perfplot.bench( setup=SugarScapeSetup, From cbc14b36457dc18aeb43347db528f2f5938ceff1 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:21:00 +0200 Subject: [PATCH 31/37] removing extra requirement --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ce4b2f6..ae8a1c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,6 @@ dev = [ "mesa_frames[test, docs]", "mesa", "numba", - "py-spy", ] [tool.hatch.envs.test] From 284163be380e6ac169cb8a7a7ce33ef9c4c66111 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:22:16 +0200 Subject: [PATCH 32/37] removing flame_graph (it was just a one-off, we can add memory-profiling in the future) --- examples/sugarscape_ig/polars_comparison.svg | 415 ------------------- 1 file changed, 415 deletions(-) delete mode 100644 examples/sugarscape_ig/polars_comparison.svg diff --git a/examples/sugarscape_ig/polars_comparison.svg b/examples/sugarscape_ig/polars_comparison.svg deleted file mode 100644 index 278892b..0000000 --- a/examples/sugarscape_ig/polars_comparison.svg +++ /dev/null @@ -1,415 +0,0 @@ -py-spy record -o polars_comparison.svg -- python performance_comparison.py Reset ZoomSearch _place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (301 samples, 0.10%)sample_cells (mesa_frames/abstract/space.py:703) (301 samples, 0.10%)mesa_frames_polars_loop_DF (sugarscape_ig/performance_comparison.py:46) (389 samples, 0.13%)__init__ (sugarscape_ig/ss_polars/model.py:35) (348 samples, 0.12%)place_to_empty (mesa_frames/abstract/space.py:651) (348 samples, 0.12%)set (mesa_frames/concrete/polars/agentset.py:190) (545 samples, 0.19%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (545 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (545 samples, 0.19%)wrapper (polars/series/utils.py:107) (545 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (543 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (543 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (568 samples, 0.19%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (571 samples, 0.20%)wrapper (polars/series/utils.py:107) (571 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (570 samples, 0.20%)set (mesa_frames/concrete/polars/agentset.py:191) (584 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,161 samples, 0.40%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,159 samples, 0.40%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (552 samples, 0.19%)wrapper (polars/series/utils.py:107) (550 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (547 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (546 samples, 0.19%)get (mesa_frames/concrete/polars/agentset.py:173) (573 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:41) (580 samples, 0.20%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (580 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:1026) (580 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:456) (580 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (596 samples, 0.20%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (600 samples, 0.21%)wrapper (polars/series/utils.py:107) (599 samples, 0.20%)get (mesa_frames/concrete/polars/agentset.py:173) (617 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (622 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (622 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (622 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (682 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (569 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1640) (576 samples, 0.20%)contains (mesa_frames/concrete/agents.py:144) (572 samples, 0.20%)wrapper (polars/series/utils.py:107) (571 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (571 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (533 samples, 0.18%)_get_df_coords (mesa_frames/abstract/space.py:1647) (534 samples, 0.18%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (534 samples, 0.18%)wrapper (polars/series/utils.py:107) (534 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (534 samples, 0.18%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (518 samples, 0.18%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (518 samples, 0.18%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (518 samples, 0.18%)wrapper (polars/series/utils.py:107) (517 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (517 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (517 samples, 0.18%)_get_df_coords (mesa_frames/abstract/space.py:1657) (523 samples, 0.18%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,686 samples, 0.58%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,314 samples, 2.16%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,314 samples, 2.16%)_..join (polars/dataframe/frame.py:6927) (6,313 samples, 2.16%)j..collect (polars/lazyframe/frame.py:2027) (6,313 samples, 2.16%)c.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (8,732 samples, 2.99%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,374 samples, 0.47%)join (polars/dataframe/frame.py:6927) (1,132 samples, 0.39%)collect (polars/lazyframe/frame.py:2027) (1,132 samples, 0.39%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (568 samples, 0.19%)join (polars/dataframe/frame.py:6927) (462 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (462 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (563 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (564 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (568 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (568 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (568 samples, 0.19%)wrapper (polars/series/utils.py:107) (567 samples, 0.19%)pos (mesa_frames/abstract/agents.py:1071) (572 samples, 0.20%)move (sugarscape_ig/ss_polars/agents.py:51) (11,269 samples, 3.86%)move.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (591 samples, 0.20%)pos (mesa_frames/concrete/polars/agentset.py:536) (591 samples, 0.20%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (1,008 samples, 0.34%)unique (polars/dataframe/frame.py:9533) (1,006 samples, 0.34%)collect (polars/lazyframe/frame.py:2027) (1,006 samples, 0.34%)move (sugarscape_ig/ss_polars/agents.py:52) (1,054 samples, 0.36%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (945 samples, 0.32%)sort (polars/dataframe/frame.py:4939) (943 samples, 0.32%)collect (polars/lazyframe/frame.py:2027) (942 samples, 0.32%)move (sugarscape_ig/ss_polars/agents.py:53) (1,684 samples, 0.58%)agg (polars/dataframe/group_by.py:231) (1,171 samples, 0.40%)collect (polars/lazyframe/frame.py:2027) (1,171 samples, 0.40%)get_best_moves (sugarscape_ig/ss_polars/agents.py:126) (1,175 samples, 0.40%)first (polars/dataframe/group_by.py:527) (1,175 samples, 0.40%)get_best_moves (sugarscape_ig/ss_polars/agents.py:142) (918 samples, 0.31%)filter (polars/dataframe/frame.py:4554) (918 samples, 0.31%)collect (polars/lazyframe/frame.py:2027) (918 samples, 0.31%)get_best_moves (sugarscape_ig/ss_polars/agents.py:147) (3,296 samples, 1.13%)filter (polars/dataframe/frame.py:4554) (3,250 samples, 1.11%)collect (polars/lazyframe/frame.py:2027) (3,250 samples, 1.11%)move (sugarscape_ig/ss_polars/agents.py:54) (5,786 samples, 1.98%)m..select_seq (polars/dataframe/frame.py:8742) (679 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (678 samples, 0.23%)_place_or_move_agents (mesa_frames/abstract/space.py:1709) (681 samples, 0.23%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (681 samples, 0.23%)wrapper (polars/series/utils.py:107) (680 samples, 0.23%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (585 samples, 0.20%)contains (mesa_frames/concrete/agents.py:144) (576 samples, 0.20%)wrapper (polars/series/utils.py:107) (574 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (574 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (574 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (599 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (604 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (604 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (603 samples, 0.21%)wrapper (polars/series/utils.py:107) (601 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (600 samples, 0.21%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (610 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (540 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (539 samples, 0.18%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (543 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (543 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (543 samples, 0.19%)wrapper (polars/series/utils.py:107) (542 samples, 0.19%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (550 samples, 0.19%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (878 samples, 0.30%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,321 samples, 0.79%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (858 samples, 0.29%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,204 samples, 0.41%)join (polars/dataframe/frame.py:6927) (1,203 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (1,202 samples, 0.41%)do (mesa_frames/abstract/agents.py:825) (28,308 samples, 9.69%)do (mesa_frame..move (sugarscape_ig/ss_polars/agents.py:55) (5,718 samples, 1.96%)m..move_agents (mesa_frames/abstract/space.py:139) (5,718 samples, 1.96%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,407 samples, 0.48%)step (sugarscape_ig/ss_polars/agents.py:47) (28,504 samples, 9.75%)step (sugarsca..remove (mesa_frames/concrete/agents.py:245) (671 samples, 0.23%)_discard (mesa_frames/concrete/polars/agentset.py:445) (549 samples, 0.19%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (549 samples, 0.19%)wrapper (polars/series/utils.py:107) (548 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (548 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (548 samples, 0.19%)contains (mesa_frames/concrete/agents.py:144) (296 samples, 0.10%)wrapper (polars/series/utils.py:107) (295 samples, 0.10%)select_seq (polars/dataframe/frame.py:8742) (295 samples, 0.10%)collect (polars/lazyframe/frame.py:2027) (294 samples, 0.10%)remove_agents (mesa_frames/abstract/space.py:1473) (302 samples, 0.10%)remove (mesa_frames/concrete/agents.py:254) (526 samples, 0.18%)discard (mesa_frames/abstract/agents.py:787) (1,594 samples, 0.55%)discard (mesa_frames/abstract/agents.py:100) (1,594 samples, 0.55%)remove (mesa_frames/abstract/agents.py:879) (1,335 samples, 0.46%)run_model (sugarscape_ig/ss_polars/model.py:41) (30,122 samples, 10.31%)run_model (suga..step (mesa_frames/concrete/model.py:134) (30,122 samples, 10.31%)step (mesa_fram..step (mesa_frames/concrete/agents.py:340) (30,122 samples, 10.31%)step (mesa_fram..step (sugarscape_ig/ss_polars/agents.py:48) (1,618 samples, 0.55%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (592 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,042 samples, 0.70%)empty_cells (mesa_frames/abstract/space.py:1064) (2,034 samples, 0.70%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,432 samples, 0.49%)run_model (sugarscape_ig/ss_polars/model.py:43) (596 samples, 0.20%)full_cells (mesa_frames/abstract/space.py:1090) (596 samples, 0.20%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (584 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,415 samples, 0.48%)join (polars/dataframe/frame.py:6927) (1,263 samples, 0.43%)collect (polars/lazyframe/frame.py:2027) (1,263 samples, 0.43%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (10,321 samples, 3.53%)_df..join (polars/dataframe/frame.py:6927) (10,321 samples, 3.53%)joi..collect (polars/lazyframe/frame.py:2027) (10,321 samples, 3.53%)col.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (536 samples, 0.18%)sort (polars/dataframe/frame.py:4939) (493 samples, 0.17%)collect (polars/lazyframe/frame.py:2027) (493 samples, 0.17%)run_model (sugarscape_ig/ss_polars/model.py:49) (11,155 samples, 3.82%)run_..set_cells (mesa_frames/abstract/space.py:763) (11,141 samples, 3.81%)set_.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (15,692 samples, 5.37%)_df_com..join (polars/dataframe/frame.py:6927) (15,692 samples, 5.37%)join (p..collect (polars/lazyframe/frame.py:2027) (15,692 samples, 5.37%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (856 samples, 0.29%)sort (polars/dataframe/frame.py:4939) (819 samples, 0.28%)collect (polars/lazyframe/frame.py:2027) (818 samples, 0.28%)set_cells (mesa_frames/abstract/space.py:763) (17,084 samples, 5.85%)set_cel..mesa_frames_polars_loop_DF (sugarscape_ig/performance_comparison.py:53) (62,580 samples, 21.41%)mesa_frames_polars_loop_DF (sugars..run_model (sugarscape_ig/ss_polars/model.py:50) (17,093 samples, 5.85%)run_mod.._place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (320 samples, 0.11%)sample_cells (mesa_frames/abstract/space.py:703) (320 samples, 0.11%)mesa_frames_polars_loop_no_vec (sugarscape_ig/performance_comparison.py:57) (436 samples, 0.15%)__init__ (sugarscape_ig/ss_polars/model.py:35) (368 samples, 0.13%)place_to_empty (mesa_frames/abstract/space.py:651) (368 samples, 0.13%)collect (polars/lazyframe/frame.py:2027) (538 samples, 0.18%)set (mesa_frames/concrete/polars/agentset.py:190) (540 samples, 0.18%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (540 samples, 0.18%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (540 samples, 0.18%)wrapper (polars/series/utils.py:107) (540 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (539 samples, 0.18%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (625 samples, 0.21%)wrapper (polars/series/utils.py:107) (625 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (625 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (625 samples, 0.21%)set (mesa_frames/concrete/polars/agentset.py:191) (643 samples, 0.22%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,207 samples, 0.41%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,206 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (606 samples, 0.21%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (608 samples, 0.21%)wrapper (polars/series/utils.py:107) (608 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (607 samples, 0.21%)get (mesa_frames/concrete/polars/agentset.py:173) (630 samples, 0.22%)eat (sugarscape_ig/ss_polars/agents.py:41) (636 samples, 0.22%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (636 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:1026) (636 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:456) (636 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (604 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (605 samples, 0.21%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (607 samples, 0.21%)wrapper (polars/series/utils.py:107) (606 samples, 0.21%)get (mesa_frames/concrete/polars/agentset.py:173) (615 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (620 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (620 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (620 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (680 samples, 0.23%)_get_df_coords (mesa_frames/abstract/space.py:1640) (568 samples, 0.19%)contains (mesa_frames/concrete/agents.py:144) (562 samples, 0.19%)wrapper (polars/series/utils.py:107) (562 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (560 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (559 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (542 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (542 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1647) (544 samples, 0.19%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (543 samples, 0.19%)wrapper (polars/series/utils.py:107) (543 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (554 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (554 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (554 samples, 0.19%)wrapper (polars/series/utils.py:107) (553 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (552 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (552 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1657) (561 samples, 0.19%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,734 samples, 0.59%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,580 samples, 2.25%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,580 samples, 2.25%)_..join (polars/dataframe/frame.py:6927) (6,580 samples, 2.25%)j..collect (polars/lazyframe/frame.py:2027) (6,580 samples, 2.25%)c..get_neighborhood (mesa_frames/abstract/space.py:1363) (381 samples, 0.13%)__le__ (polars/series/series.py:833) (379 samples, 0.13%)_comp (polars/series/series.py:753) (378 samples, 0.13%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (9,245 samples, 3.16%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,612 samples, 0.55%)join (polars/dataframe/frame.py:6927) (1,330 samples, 0.46%)collect (polars/lazyframe/frame.py:2027) (1,329 samples, 0.45%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (629 samples, 0.22%)join (polars/dataframe/frame.py:6927) (474 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (474 samples, 0.16%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (626 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (626 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (626 samples, 0.21%)wrapper (polars/series/utils.py:107) (626 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (625 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (625 samples, 0.21%)pos (mesa_frames/abstract/agents.py:1071) (638 samples, 0.22%)move (sugarscape_ig/ss_polars/agents.py:51) (12,142 samples, 4.15%)move .._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (651 samples, 0.22%)pos (mesa_frames/concrete/polars/agentset.py:536) (651 samples, 0.22%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (1,093 samples, 0.37%)unique (polars/dataframe/frame.py:9533) (1,093 samples, 0.37%)collect (polars/lazyframe/frame.py:2027) (1,093 samples, 0.37%)move (sugarscape_ig/ss_polars/agents.py:52) (1,128 samples, 0.39%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:103) (358 samples, 0.12%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (1,150 samples, 0.39%)sort (polars/dataframe/frame.py:4939) (1,147 samples, 0.39%)collect (polars/lazyframe/frame.py:2027) (1,147 samples, 0.39%)move (sugarscape_ig/ss_polars/agents.py:53) (2,097 samples, 0.72%)select_seq (polars/dataframe/frame.py:8742) (684 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (684 samples, 0.23%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (685 samples, 0.23%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (685 samples, 0.23%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (685 samples, 0.23%)wrapper (polars/series/utils.py:107) (685 samples, 0.23%)pos (mesa_frames/abstract/agents.py:1071) (690 samples, 0.24%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:213) (815 samples, 0.28%)pos (mesa_frames/concrete/polars/agentset.py:536) (701 samples, 0.24%)__add__ (polars/series/series.py:1048) (645 samples, 0.22%)_arithmetic (polars/series/series.py:997) (645 samples, 0.22%)get_best_moves (sugarscape_ig/ss_polars/agents.py:167) (2,360 samples, 0.81%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:224) (1,378 samples, 0.47%)__mul__ (polars/series/series.py:1118) (683 samples, 0.23%)_arithmetic (polars/series/series.py:1030) (683 samples, 0.23%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:243) (10,533 samples, 3.60%)inne..__iter__ (polars/series/series.py:1224) (6,433 samples, 2.20%)_..to_list (polars/series/series.py:4039) (1,590 samples, 0.54%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:244) (5,348 samples, 1.83%)i..inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:245) (7,095 samples, 2.43%)in..__getitem__ (polars/series/series.py:1236) (1,324 samples, 0.45%)get_series_item_by_key (polars/_utils/getitem.py:52) (1,097 samples, 0.38%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:246) (1,154 samples, 0.39%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:248) (1,984 samples, 0.68%)inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:250) (1,766 samples, 0.60%)<lambda> (sugarscape_ig/ss_polars/agents.py:174) (29,272 samples, 10.02%)<lambda> (suga..inner_get_best_moves (sugarscape_ig/ss_polars/agents.py:251) (1,392 samples, 0.48%)__call__ (polars/expr/expr.py:4267) (29,290 samples, 10.02%)__call__ (pola..get_best_moves (sugarscape_ig/ss_polars/agents.py:196) (29,386 samples, 10.05%)get_best_moves ..select (polars/dataframe/frame.py:8717) (29,295 samples, 10.02%)select (polars..collect (polars/lazyframe/frame.py:2027) (29,295 samples, 10.02%)collect (polar..move (sugarscape_ig/ss_polars/agents.py:54) (31,793 samples, 10.88%)move (sugarscape.._place_or_move_agents (mesa_frames/abstract/space.py:1709) (635 samples, 0.22%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (635 samples, 0.22%)wrapper (polars/series/utils.py:107) (635 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (635 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (635 samples, 0.22%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (621 samples, 0.21%)contains (mesa_frames/concrete/agents.py:144) (615 samples, 0.21%)wrapper (polars/series/utils.py:107) (614 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (614 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (614 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (634 samples, 0.22%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (636 samples, 0.22%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (636 samples, 0.22%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (636 samples, 0.22%)wrapper (polars/series/utils.py:107) (636 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (635 samples, 0.22%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (641 samples, 0.22%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (642 samples, 0.22%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (642 samples, 0.22%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (642 samples, 0.22%)wrapper (polars/series/utils.py:107) (642 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (642 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (642 samples, 0.22%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (647 samples, 0.22%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (915 samples, 0.31%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,505 samples, 0.86%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (911 samples, 0.31%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,205 samples, 0.41%)join (polars/dataframe/frame.py:6927) (1,205 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (1,205 samples, 0.41%)do (mesa_frames/abstract/agents.py:825) (56,036 samples, 19.17%)do (mesa_frames/abstract/agent..move (sugarscape_ig/ss_polars/agents.py:55) (5,903 samples, 2.02%)m..move_agents (mesa_frames/abstract/space.py:139) (5,903 samples, 2.02%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,393 samples, 0.48%)step (sugarscape_ig/ss_polars/agents.py:47) (56,225 samples, 19.24%)step (sugarscape_ig/ss_polars/..collect (polars/lazyframe/frame.py:2027) (548 samples, 0.19%)remove (mesa_frames/concrete/agents.py:245) (693 samples, 0.24%)_discard (mesa_frames/concrete/polars/agentset.py:445) (552 samples, 0.19%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (552 samples, 0.19%)wrapper (polars/series/utils.py:107) (550 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (550 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (307 samples, 0.11%)remove_agents (mesa_frames/abstract/space.py:1473) (308 samples, 0.11%)contains (mesa_frames/concrete/agents.py:144) (308 samples, 0.11%)wrapper (polars/series/utils.py:107) (308 samples, 0.11%)select_seq (polars/dataframe/frame.py:8742) (308 samples, 0.11%)remove (mesa_frames/concrete/agents.py:254) (518 samples, 0.18%)discard (mesa_frames/abstract/agents.py:787) (1,656 samples, 0.57%)discard (mesa_frames/abstract/agents.py:100) (1,656 samples, 0.57%)remove (mesa_frames/abstract/agents.py:879) (1,363 samples, 0.47%)run_model (sugarscape_ig/ss_polars/model.py:41) (57,898 samples, 19.81%)run_model (sugarscape_ig/ss_pol..step (mesa_frames/concrete/model.py:134) (57,898 samples, 19.81%)step (mesa_frames/concrete/mode..step (mesa_frames/concrete/agents.py:340) (57,898 samples, 19.81%)step (mesa_frames/concrete/agen..step (sugarscape_ig/ss_polars/agents.py:48) (1,673 samples, 0.57%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (574 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,105 samples, 0.72%)empty_cells (mesa_frames/abstract/space.py:1064) (2,096 samples, 0.72%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,516 samples, 0.52%)run_model (sugarscape_ig/ss_polars/model.py:43) (639 samples, 0.22%)full_cells (mesa_frames/abstract/space.py:1090) (639 samples, 0.22%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (619 samples, 0.21%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,352 samples, 0.46%)join (polars/dataframe/frame.py:6927) (1,174 samples, 0.40%)collect (polars/lazyframe/frame.py:2027) (1,173 samples, 0.40%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (11,226 samples, 3.84%)_df_..join (polars/dataframe/frame.py:6927) (11,225 samples, 3.84%)join..collect (polars/lazyframe/frame.py:2027) (11,224 samples, 3.84%)coll.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (539 samples, 0.18%)sort (polars/dataframe/frame.py:4939) (510 samples, 0.17%)collect (polars/lazyframe/frame.py:2027) (510 samples, 0.17%)run_model (sugarscape_ig/ss_polars/model.py:49) (12,107 samples, 4.14%)run_m..set_cells (mesa_frames/abstract/space.py:763) (12,075 samples, 4.13%)set_c.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (15,635 samples, 5.35%)_df_com..join (polars/dataframe/frame.py:6927) (15,634 samples, 5.35%)join (p..collect (polars/lazyframe/frame.py:2027) (15,634 samples, 5.35%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (858 samples, 0.29%)sort (polars/dataframe/frame.py:4939) (817 samples, 0.28%)collect (polars/lazyframe/frame.py:2027) (817 samples, 0.28%)set_cells (mesa_frames/abstract/space.py:763) (17,055 samples, 5.84%)set_cel..mesa_frames_polars_loop_no_vec (sugarscape_ig/performance_comparison.py:64) (91,305 samples, 31.24%)mesa_frames_polars_loop_no_vec (sugarscape_ig/perf..run_model (sugarscape_ig/ss_polars/model.py:50) (17,064 samples, 5.84%)run_mod.._place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (329 samples, 0.11%)sample_cells (mesa_frames/abstract/space.py:703) (329 samples, 0.11%)mesa_frames_polars_numba_cpu (sugarscape_ig/performance_comparison.py:68) (433 samples, 0.15%)__init__ (sugarscape_ig/ss_polars/model.py:35) (375 samples, 0.13%)place_to_empty (mesa_frames/abstract/space.py:651) (375 samples, 0.13%)collect (polars/lazyframe/frame.py:2027) (612 samples, 0.21%)set (mesa_frames/concrete/polars/agentset.py:190) (613 samples, 0.21%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (613 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (613 samples, 0.21%)wrapper (polars/series/utils.py:107) (613 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (613 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (539 samples, 0.18%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (544 samples, 0.19%)wrapper (polars/series/utils.py:107) (543 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (542 samples, 0.19%)set (mesa_frames/concrete/polars/agentset.py:191) (562 samples, 0.19%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,209 samples, 0.41%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,204 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (629 samples, 0.22%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (631 samples, 0.22%)wrapper (polars/series/utils.py:107) (631 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (630 samples, 0.22%)get (mesa_frames/concrete/polars/agentset.py:173) (642 samples, 0.22%)eat (sugarscape_ig/ss_polars/agents.py:41) (651 samples, 0.22%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (651 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:1026) (651 samples, 0.22%)__getitem__ (mesa_frames/abstract/agents.py:456) (651 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (587 samples, 0.20%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (590 samples, 0.20%)wrapper (polars/series/utils.py:107) (589 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (588 samples, 0.20%)get (mesa_frames/concrete/polars/agentset.py:173) (606 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (610 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (610 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (610 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (674 samples, 0.23%)_get_df_coords (mesa_frames/abstract/space.py:1640) (607 samples, 0.21%)contains (mesa_frames/concrete/agents.py:144) (605 samples, 0.21%)wrapper (polars/series/utils.py:107) (604 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (603 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (603 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (565 samples, 0.19%)_get_df_coords (mesa_frames/abstract/space.py:1647) (571 samples, 0.20%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (571 samples, 0.20%)wrapper (polars/series/utils.py:107) (568 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (568 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (637 samples, 0.22%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (637 samples, 0.22%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (637 samples, 0.22%)wrapper (polars/series/utils.py:107) (637 samples, 0.22%)select_seq (polars/dataframe/frame.py:8742) (637 samples, 0.22%)collect (polars/lazyframe/frame.py:2027) (637 samples, 0.22%)_get_df_coords (mesa_frames/abstract/space.py:1657) (642 samples, 0.22%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,875 samples, 0.64%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,537 samples, 2.24%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,537 samples, 2.24%)_..join (polars/dataframe/frame.py:6927) (6,536 samples, 2.24%)j..collect (polars/lazyframe/frame.py:2027) (6,536 samples, 2.24%)c..get_neighborhood (mesa_frames/abstract/space.py:1363) (320 samples, 0.11%)__le__ (polars/series/series.py:833) (320 samples, 0.11%)_comp (polars/series/series.py:753) (320 samples, 0.11%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (9,281 samples, 3.18%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,567 samples, 0.54%)join (polars/dataframe/frame.py:6927) (1,274 samples, 0.44%)collect (polars/lazyframe/frame.py:2027) (1,274 samples, 0.44%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (699 samples, 0.24%)join (polars/dataframe/frame.py:6927) (545 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (545 samples, 0.19%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (541 samples, 0.19%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (541 samples, 0.19%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (541 samples, 0.19%)wrapper (polars/series/utils.py:107) (541 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (540 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (540 samples, 0.18%)pos (mesa_frames/abstract/agents.py:1071) (545 samples, 0.19%)move (sugarscape_ig/ss_polars/agents.py:51) (12,125 samples, 4.15%)move .._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (570 samples, 0.20%)pos (mesa_frames/concrete/polars/agentset.py:536) (569 samples, 0.19%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (995 samples, 0.34%)unique (polars/dataframe/frame.py:9533) (995 samples, 0.34%)collect (polars/lazyframe/frame.py:2027) (995 samples, 0.34%)move (sugarscape_ig/ss_polars/agents.py:52) (1,037 samples, 0.35%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:103) (357 samples, 0.12%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (1,096 samples, 0.37%)sort (polars/dataframe/frame.py:4939) (1,094 samples, 0.37%)collect (polars/lazyframe/frame.py:2027) (1,094 samples, 0.37%)move (sugarscape_ig/ss_polars/agents.py:53) (2,046 samples, 0.70%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (673 samples, 0.23%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (673 samples, 0.23%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (673 samples, 0.23%)wrapper (polars/series/utils.py:107) (673 samples, 0.23%)select_seq (polars/dataframe/frame.py:8742) (673 samples, 0.23%)collect (polars/lazyframe/frame.py:2027) (673 samples, 0.23%)pos (mesa_frames/abstract/agents.py:1071) (682 samples, 0.23%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:213) (809 samples, 0.28%)pos (mesa_frames/concrete/polars/agentset.py:536) (693 samples, 0.24%)__add__ (polars/series/series.py:1048) (631 samples, 0.22%)_arithmetic (polars/series/series.py:997) (631 samples, 0.22%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:224) (1,318 samples, 0.45%)__mul__ (polars/series/series.py:1118) (640 samples, 0.22%)_arithmetic (polars/series/series.py:1030) (640 samples, 0.22%)get_best_moves (sugarscape_ig/ss_polars/agents.py:167) (2,301 samples, 0.79%)lower (numba/core/lowering.py:187) (357 samples, 0.12%)lower_normal_function (numba/core/lowering.py:226) (346 samples, 0.12%)lower_function_body (numba/core/lowering.py:256) (344 samples, 0.12%)lower_block (numba/core/lowering.py:270) (337 samples, 0.12%)run_pass (numba/core/typed_passes.py:468) (595 samples, 0.20%)get_executable (numba/core/cpu.py:239) (321 samples, 0.11%)get_pointer_to_function (numba/core/codegen.py:989) (321 samples, 0.11%)_ensure_finalized (numba/core/codegen.py:567) (321 samples, 0.11%)run_pass (numba/core/typed_passes.py:497) (323 samples, 0.11%)_runPass (numba/core/compiler_machinery.py:311) (1,432 samples, 0.49%)check (numba/core/compiler_machinery.py:273) (1,432 samples, 0.49%)wrap (numba/np/ufunc/decorators.py:203) (1,550 samples, 0.53%)add (numba/np/ufunc/gufunc.py:137) (1,550 samples, 0.53%)add (numba/np/ufunc/ufuncbuilder.py:257) (1,550 samples, 0.53%)_compile_element_wise_function (numba/np/ufunc/ufuncbuilder.py:175) (1,550 samples, 0.53%)compile (numba/np/ufunc/ufuncbuilder.py:123) (1,549 samples, 0.53%)_compile_core (numba/np/ufunc/ufuncbuilder.py:156) (1,546 samples, 0.53%)compile_extra (numba/core/compiler.py:744) (1,535 samples, 0.53%)compile_extra (numba/core/compiler.py:438) (1,530 samples, 0.52%)_compile_bytecode (numba/core/compiler.py:506) (1,530 samples, 0.52%)_compile_core (numba/core/compiler.py:472) (1,527 samples, 0.52%)run (numba/core/compiler_machinery.py:356) (1,527 samples, 0.52%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (1,526 samples, 0.52%)build_ufunc (numba/np/ufunc/ufuncbuilder.py:376) (630 samples, 0.22%)build (numba/np/ufunc/ufuncbuilder.py:406) (383 samples, 0.13%)get_pointer_to_function (numba/core/codegen.py:989) (383 samples, 0.13%)_ensure_finalized (numba/core/codegen.py:567) (383 samples, 0.13%)get_best_moves (sugarscape_ig/ss_polars/agents.py:168) (2,190 samples, 0.75%)_get_best_moves (sugarscape_ig/ss_polars/agents.py:259) (2,190 samples, 0.75%)wrap (numba/np/ufunc/decorators.py:206) (632 samples, 0.22%)build_ufunc (numba/np/ufunc/gufunc.py:140) (632 samples, 0.22%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (632 samples, 0.22%)<lambda> (polars/series/series.py:1411) (2,759 samples, 0.94%)<lambda> (sugarscape_ig/ss_polars/agents.py:185) (2,762 samples, 0.95%)__call__ (numba/np/ufunc/gufunc.py:252) (2,762 samples, 0.95%)__array_ufunc__ (polars/series/series.py:1410) (2,760 samples, 0.94%)get_best_moves (sugarscape_ig/ss_polars/agents.py:196) (2,868 samples, 0.98%)select (polars/dataframe/frame.py:8717) (2,763 samples, 0.95%)collect (polars/lazyframe/frame.py:2027) (2,763 samples, 0.95%)__call__ (polars/expr/expr.py:4267) (2,763 samples, 0.95%)move (sugarscape_ig/ss_polars/agents.py:54) (7,417 samples, 2.54%)mo.._df_contains (mesa_frames/concrete/polars/mixin.py:206) (597 samples, 0.20%)wrapper (polars/series/utils.py:107) (597 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (596 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1709) (598 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (582 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (595 samples, 0.20%)contains (mesa_frames/concrete/agents.py:144) (585 samples, 0.20%)wrapper (polars/series/utils.py:107) (584 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (584 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (624 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (624 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (624 samples, 0.21%)wrapper (polars/series/utils.py:107) (624 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (622 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (621 samples, 0.21%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (630 samples, 0.22%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (578 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (578 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (578 samples, 0.20%)wrapper (polars/series/utils.py:107) (578 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (578 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (577 samples, 0.20%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (584 samples, 0.20%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (884 samples, 0.30%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,489 samples, 0.85%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (980 samples, 0.34%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,297 samples, 0.44%)join (polars/dataframe/frame.py:6927) (1,295 samples, 0.44%)collect (polars/lazyframe/frame.py:2027) (1,295 samples, 0.44%)do (mesa_frames/abstract/agents.py:825) (31,510 samples, 10.78%)do (mesa_frames/..move (sugarscape_ig/ss_polars/agents.py:55) (5,942 samples, 2.03%)m..move_agents (mesa_frames/abstract/space.py:139) (5,942 samples, 2.03%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,526 samples, 0.52%)step (sugarscape_ig/ss_polars/agents.py:47) (31,688 samples, 10.84%)step (sugarscape.._get_masked_df (mesa_frames/concrete/polars/agentset.py:397) (309 samples, 0.11%)wrapper (polars/series/utils.py:107) (308 samples, 0.11%)select_seq (polars/dataframe/frame.py:8742) (307 samples, 0.11%)collect (polars/lazyframe/frame.py:2027) (307 samples, 0.11%)remove (mesa_frames/abstract/agents.py:878) (316 samples, 0.11%)remove (mesa_frames/concrete/agents.py:245) (751 samples, 0.26%)_discard (mesa_frames/concrete/polars/agentset.py:445) (613 samples, 0.21%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (613 samples, 0.21%)wrapper (polars/series/utils.py:107) (613 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (612 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (612 samples, 0.21%)remove_agents (mesa_frames/abstract/space.py:1473) (330 samples, 0.11%)contains (mesa_frames/concrete/agents.py:144) (327 samples, 0.11%)wrapper (polars/series/utils.py:107) (327 samples, 0.11%)select_seq (polars/dataframe/frame.py:8742) (327 samples, 0.11%)collect (polars/lazyframe/frame.py:2027) (326 samples, 0.11%)remove (mesa_frames/concrete/agents.py:254) (552 samples, 0.19%)discard (mesa_frames/abstract/agents.py:100) (1,764 samples, 0.60%)remove (mesa_frames/abstract/agents.py:879) (1,448 samples, 0.50%)discard (mesa_frames/abstract/agents.py:787) (1,765 samples, 0.60%)run_model (sugarscape_ig/ss_polars/model.py:41) (33,464 samples, 11.45%)run_model (sugars..step (mesa_frames/concrete/model.py:134) (33,464 samples, 11.45%)step (mesa_frames..step (mesa_frames/concrete/agents.py:340) (33,464 samples, 11.45%)step (mesa_frames..step (sugarscape_ig/ss_polars/agents.py:48) (1,776 samples, 0.61%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (576 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,068 samples, 0.71%)empty_cells (mesa_frames/abstract/space.py:1064) (2,062 samples, 0.71%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,472 samples, 0.50%)run_model (sugarscape_ig/ss_polars/model.py:43) (669 samples, 0.23%)full_cells (mesa_frames/abstract/space.py:1090) (669 samples, 0.23%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (657 samples, 0.22%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,367 samples, 0.47%)join (polars/dataframe/frame.py:6927) (1,193 samples, 0.41%)collect (polars/lazyframe/frame.py:2027) (1,193 samples, 0.41%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (11,378 samples, 3.89%)_df_..join (polars/dataframe/frame.py:6927) (11,378 samples, 3.89%)join..collect (polars/lazyframe/frame.py:2027) (11,378 samples, 3.89%)coll.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (522 samples, 0.18%)sort (polars/dataframe/frame.py:4939) (479 samples, 0.16%)collect (polars/lazyframe/frame.py:2027) (479 samples, 0.16%)set_cells (mesa_frames/abstract/space.py:763) (12,297 samples, 4.21%)set_c..run_model (sugarscape_ig/ss_polars/model.py:49) (12,314 samples, 4.21%)run_m.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (16,027 samples, 5.48%)_df_com..join (polars/dataframe/frame.py:6927) (16,026 samples, 5.48%)join (p..collect (polars/lazyframe/frame.py:2027) (16,026 samples, 5.48%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (889 samples, 0.30%)sort (polars/dataframe/frame.py:4939) (848 samples, 0.29%)collect (polars/lazyframe/frame.py:2027) (848 samples, 0.29%)set_cells (mesa_frames/abstract/space.py:763) (17,478 samples, 5.98%)set_cell..mesa_frames_polars_numba_cpu (sugarscape_ig/performance_comparison.py:75) (67,489 samples, 23.09%)mesa_frames_polars_numba_cpu (sugarsc..run_model (sugarscape_ig/ss_polars/model.py:50) (17,485 samples, 5.98%)run_mode.._place_or_move_agents_to_cells (mesa_frames/abstract/space.py:889) (305 samples, 0.10%)sample_cells (mesa_frames/abstract/space.py:703) (305 samples, 0.10%)mesa_frames_polars_numba_parallel (sugarscape_ig/performance_comparison.py:90) (415 samples, 0.14%)__init__ (sugarscape_ig/ss_polars/model.py:35) (357 samples, 0.12%)place_to_empty (mesa_frames/abstract/space.py:651) (357 samples, 0.12%)set (mesa_frames/concrete/polars/agentset.py:190) (535 samples, 0.18%)_get_bool_mask (mesa_frames/concrete/polars/agentset.py:369) (535 samples, 0.18%)bool_mask_from_series (mesa_frames/concrete/polars/agentset.py:364) (535 samples, 0.18%)wrapper (polars/series/utils.py:107) (535 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (534 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (533 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (552 samples, 0.19%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (554 samples, 0.19%)wrapper (polars/series/utils.py:107) (554 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (554 samples, 0.19%)set (mesa_frames/concrete/polars/agentset.py:191) (571 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:40) (1,143 samples, 0.39%)__setitem__ (mesa_frames/abstract/agents.py:537) (1,139 samples, 0.39%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (560 samples, 0.19%)wrapper (polars/series/utils.py:107) (560 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (558 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (556 samples, 0.19%)get (mesa_frames/concrete/polars/agentset.py:173) (575 samples, 0.20%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (579 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:1026) (579 samples, 0.20%)__getitem__ (mesa_frames/abstract/agents.py:456) (579 samples, 0.20%)eat (sugarscape_ig/ss_polars/agents.py:41) (580 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (595 samples, 0.20%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:405) (597 samples, 0.20%)wrapper (polars/series/utils.py:107) (597 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)get (mesa_frames/concrete/polars/agentset.py:173) (605 samples, 0.21%)__getitem__ (mesa_frames/concrete/polars/agentset.py:495) (614 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:1026) (614 samples, 0.21%)__getitem__ (mesa_frames/abstract/agents.py:456) (614 samples, 0.21%)eat (sugarscape_ig/ss_polars/agents.py:43) (682 samples, 0.23%)_get_df_coords (mesa_frames/abstract/space.py:1640) (527 samples, 0.18%)contains (mesa_frames/concrete/agents.py:144) (520 samples, 0.18%)wrapper (polars/series/utils.py:107) (519 samples, 0.18%)select_seq (polars/dataframe/frame.py:8742) (518 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (518 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (575 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (576 samples, 0.20%)_get_df_coords (mesa_frames/abstract/space.py:1647) (580 samples, 0.20%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (580 samples, 0.20%)wrapper (polars/series/utils.py:107) (579 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (596 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (596 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (596 samples, 0.20%)wrapper (polars/series/utils.py:107) (595 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (594 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (594 samples, 0.20%)_get_df_coords (mesa_frames/abstract/space.py:1657) (604 samples, 0.21%)get_neighborhood (mesa_frames/abstract/space.py:1234) (1,761 samples, 0.60%)get_neighborhood (mesa_frames/abstract/space.py:1357) (6,505 samples, 2.23%)g.._df_join (mesa_frames/concrete/polars/mixin.py:370) (6,505 samples, 2.23%)_..join (polars/dataframe/frame.py:6927) (6,505 samples, 2.23%)j..collect (polars/lazyframe/frame.py:2027) (6,504 samples, 2.23%)c.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:58) (9,077 samples, 3.11%)_ge.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:63) (1,514 samples, 0.52%)join (polars/dataframe/frame.py:6927) (1,215 samples, 0.42%)collect (polars/lazyframe/frame.py:2027) (1,215 samples, 0.42%)_get_neighborhood (sugarscape_ig/ss_polars/agents.py:69) (737 samples, 0.25%)join (polars/dataframe/frame.py:6927) (577 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (577 samples, 0.20%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (595 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (595 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (595 samples, 0.20%)wrapper (polars/series/utils.py:107) (595 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (595 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (595 samples, 0.20%)pos (mesa_frames/abstract/agents.py:1071) (597 samples, 0.20%)move (sugarscape_ig/ss_polars/agents.py:51) (11,945 samples, 4.09%)move.._get_neighborhood (sugarscape_ig/ss_polars/agents.py:70) (613 samples, 0.21%)pos (mesa_frames/concrete/polars/agentset.py:536) (613 samples, 0.21%)_get_agent_order (sugarscape_ig/ss_polars/agents.py:82) (1,128 samples, 0.39%)unique (polars/dataframe/frame.py:9533) (1,128 samples, 0.39%)collect (polars/lazyframe/frame.py:2027) (1,128 samples, 0.39%)move (sugarscape_ig/ss_polars/agents.py:52) (1,175 samples, 0.40%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:103) (337 samples, 0.12%)_prepare_neighborhood (sugarscape_ig/ss_polars/agents.py:109) (1,121 samples, 0.38%)sort (polars/dataframe/frame.py:4939) (1,116 samples, 0.38%)collect (polars/lazyframe/frame.py:2027) (1,116 samples, 0.38%)move (sugarscape_ig/ss_polars/agents.py:53) (2,077 samples, 0.71%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (596 samples, 0.20%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (596 samples, 0.20%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (596 samples, 0.20%)wrapper (polars/series/utils.py:107) (596 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (596 samples, 0.20%)collect (polars/lazyframe/frame.py:2027) (596 samples, 0.20%)pos (mesa_frames/abstract/agents.py:1071) (604 samples, 0.21%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:213) (741 samples, 0.25%)pos (mesa_frames/concrete/polars/agentset.py:536) (622 samples, 0.21%)__add__ (polars/series/series.py:1048) (650 samples, 0.22%)_arithmetic (polars/series/series.py:997) (650 samples, 0.22%)_prepare_cells (sugarscape_ig/ss_polars/agents.py:224) (1,297 samples, 0.44%)__mul__ (polars/series/series.py:1118) (603 samples, 0.21%)_arithmetic (polars/series/series.py:1030) (602 samples, 0.21%)get_best_moves (sugarscape_ig/ss_polars/agents.py:167) (2,237 samples, 0.77%)lower (numba/core/lowering.py:187) (359 samples, 0.12%)lower_normal_function (numba/core/lowering.py:226) (348 samples, 0.12%)lower_function_body (numba/core/lowering.py:256) (348 samples, 0.12%)lower_block (numba/core/lowering.py:270) (333 samples, 0.11%)run_pass (numba/core/typed_passes.py:468) (574 samples, 0.20%)get_executable (numba/core/cpu.py:239) (347 samples, 0.12%)get_pointer_to_function (numba/core/codegen.py:989) (347 samples, 0.12%)_ensure_finalized (numba/core/codegen.py:567) (347 samples, 0.12%)run_pass (numba/core/typed_passes.py:497) (348 samples, 0.12%)_runPass (numba/core/compiler_machinery.py:311) (1,467 samples, 0.50%)check (numba/core/compiler_machinery.py:273) (1,467 samples, 0.50%)_compile_core (numba/np/ufunc/ufuncbuilder.py:156) (1,567 samples, 0.54%)compile_extra (numba/core/compiler.py:744) (1,558 samples, 0.53%)compile_extra (numba/core/compiler.py:438) (1,555 samples, 0.53%)_compile_bytecode (numba/core/compiler.py:506) (1,555 samples, 0.53%)_compile_core (numba/core/compiler.py:472) (1,551 samples, 0.53%)run (numba/core/compiler_machinery.py:356) (1,550 samples, 0.53%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (1,546 samples, 0.53%)_compile_element_wise_function (numba/np/ufunc/ufuncbuilder.py:175) (1,572 samples, 0.54%)compile (numba/np/ufunc/ufuncbuilder.py:123) (1,570 samples, 0.54%)wrap (numba/np/ufunc/decorators.py:203) (1,573 samples, 0.54%)add (numba/np/ufunc/ufuncbuilder.py:257) (1,573 samples, 0.54%)build_gufunc_wrapper (numba/np/ufunc/parallel.py:264) (303 samples, 0.10%)build_gufunc_wrapper (numba/np/ufunc/wrappers.py:504) (303 samples, 0.10%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (303 samples, 0.10%)build (numba/np/ufunc/wrappers.py:456) (303 samples, 0.10%)_compile_wrapper (numba/np/ufunc/wrappers.py:447) (299 samples, 0.10%)build_gufunc_kernel (numba/np/ufunc/parallel.py:152) (412 samples, 0.14%)add_linking_library (numba/core/codegen.py:720) (412 samples, 0.14%)_ensure_finalized (numba/core/codegen.py:567) (412 samples, 0.14%)build (numba/np/ufunc/parallel.py:233) (746 samples, 0.26%)build_gufunc_wrapper (numba/np/ufunc/parallel.py:271) (443 samples, 0.15%)get_pointer_to_function (numba/core/codegen.py:989) (416 samples, 0.14%)_ensure_finalized (numba/core/codegen.py:567) (416 samples, 0.14%)get_best_moves (sugarscape_ig/ss_polars/agents.py:168) (2,741 samples, 0.94%)_get_best_moves (sugarscape_ig/ss_polars/agents.py:259) (2,741 samples, 0.94%)wrap (numba/np/ufunc/decorators.py:206) (1,163 samples, 0.40%)_acquire_compile_lock (numba/core/compiler_lock.py:35) (1,163 samples, 0.40%)build_ufunc (numba/np/ufunc/ufuncbuilder.py:376) (1,163 samples, 0.40%)build (numba/np/ufunc/parallel.py:237) (417 samples, 0.14%)<lambda> (polars/series/series.py:1411) (2,955 samples, 1.01%)<lambda> (sugarscape_ig/ss_polars/agents.py:185) (2,957 samples, 1.01%)__array_ufunc__ (polars/series/series.py:1410) (2,957 samples, 1.01%)get_best_moves (sugarscape_ig/ss_polars/agents.py:196) (3,087 samples, 1.06%)select (polars/dataframe/frame.py:8717) (2,960 samples, 1.01%)collect (polars/lazyframe/frame.py:2027) (2,960 samples, 1.01%)__call__ (polars/expr/expr.py:4267) (2,958 samples, 1.01%)move (sugarscape_ig/ss_polars/agents.py:54) (8,156 samples, 2.79%)mo..collect (polars/lazyframe/frame.py:2027) (578 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1709) (580 samples, 0.20%)_df_contains (mesa_frames/concrete/polars/mixin.py:206) (580 samples, 0.20%)wrapper (polars/series/utils.py:107) (580 samples, 0.20%)select_seq (polars/dataframe/frame.py:8742) (579 samples, 0.20%)_place_or_move_agents (mesa_frames/abstract/space.py:1716) (640 samples, 0.22%)contains (mesa_frames/concrete/agents.py:144) (629 samples, 0.22%)wrapper (polars/series/utils.py:107) (626 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (626 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (626 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (609 samples, 0.21%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (612 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:301) (611 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (611 samples, 0.21%)wrapper (polars/series/utils.py:107) (610 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (610 samples, 0.21%)_place_or_move_agents (mesa_frames/abstract/space.py:1726) (616 samples, 0.21%)_df_get_masked_df (mesa_frames/concrete/polars/mixin.py:333) (624 samples, 0.21%)_df_get_bool_mask (mesa_frames/concrete/polars/mixin.py:304) (624 samples, 0.21%)bool_mask_from_series (mesa_frames/concrete/polars/mixin.py:290) (624 samples, 0.21%)wrapper (polars/series/utils.py:107) (624 samples, 0.21%)select_seq (polars/dataframe/frame.py:8742) (624 samples, 0.21%)collect (polars/lazyframe/frame.py:2027) (624 samples, 0.21%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:168) (636 samples, 0.22%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:175) (889 samples, 0.30%)_place_or_move_agents (mesa_frames/abstract/space.py:1745) (2,499 samples, 0.86%)_update_capacity_agents (mesa_frames/concrete/polars/space.py:179) (944 samples, 0.32%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (1,222 samples, 0.42%)join (polars/dataframe/frame.py:6927) (1,221 samples, 0.42%)collect (polars/lazyframe/frame.py:2027) (1,220 samples, 0.42%)do (mesa_frames/abstract/agents.py:825) (32,055 samples, 10.97%)do (mesa_frames/..move (sugarscape_ig/ss_polars/agents.py:55) (5,859 samples, 2.00%)m..move_agents (mesa_frames/abstract/space.py:139) (5,859 samples, 2.00%)m.._place_or_move_agents (mesa_frames/abstract/space.py:1748) (1,420 samples, 0.49%)step (sugarscape_ig/ss_polars/agents.py:47) (32,226 samples, 11.03%)step (sugarscape..select_seq (polars/dataframe/frame.py:8742) (322 samples, 0.11%)collect (polars/lazyframe/frame.py:2027) (322 samples, 0.11%)_get_masked_df (mesa_frames/concrete/polars/agentset.py:397) (323 samples, 0.11%)wrapper (polars/series/utils.py:107) (323 samples, 0.11%)remove (mesa_frames/abstract/agents.py:878) (334 samples, 0.11%)remove (mesa_frames/concrete/agents.py:245) (713 samples, 0.24%)_discard (mesa_frames/concrete/polars/agentset.py:445) (566 samples, 0.19%)_update_mask (mesa_frames/concrete/polars/agentset.py:457) (566 samples, 0.19%)wrapper (polars/series/utils.py:107) (566 samples, 0.19%)select_seq (polars/dataframe/frame.py:8742) (565 samples, 0.19%)collect (polars/lazyframe/frame.py:2027) (565 samples, 0.19%)remove (mesa_frames/concrete/agents.py:254) (482 samples, 0.16%)discard (mesa_frames/abstract/agents.py:787) (1,651 samples, 0.56%)discard (mesa_frames/abstract/agents.py:100) (1,651 samples, 0.56%)remove (mesa_frames/abstract/agents.py:879) (1,317 samples, 0.45%)run_model (sugarscape_ig/ss_polars/model.py:41) (33,903 samples, 11.60%)run_model (sugars..step (mesa_frames/concrete/model.py:134) (33,903 samples, 11.60%)step (mesa_frames..step (mesa_frames/concrete/agents.py:340) (33,903 samples, 11.60%)step (mesa_frames..step (sugarscape_ig/ss_polars/agents.py:48) (1,677 samples, 0.57%)_sample_cells (mesa_frames/concrete/polars/space.py:102) (513 samples, 0.18%)run_model (sugarscape_ig/ss_polars/model.py:42) (2,057 samples, 0.70%)empty_cells (mesa_frames/abstract/space.py:1064) (2,052 samples, 0.70%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (1,534 samples, 0.52%)run_model (sugarscape_ig/ss_polars/model.py:43) (602 samples, 0.21%)full_cells (mesa_frames/abstract/space.py:1090) (601 samples, 0.21%)_sample_cells (mesa_frames/concrete/polars/space.py:99) (591 samples, 0.20%)run_model (sugarscape_ig/ss_polars/model.py:45) (1,390 samples, 0.48%)join (polars/dataframe/frame.py:6927) (1,222 samples, 0.42%)collect (polars/lazyframe/frame.py:2027) (1,222 samples, 0.42%)_df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (11,266 samples, 3.85%)_df_..join (polars/dataframe/frame.py:6927) (11,263 samples, 3.85%)join..collect (polars/lazyframe/frame.py:2027) (11,262 samples, 3.85%)coll.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (569 samples, 0.19%)sort (polars/dataframe/frame.py:4939) (522 samples, 0.18%)collect (polars/lazyframe/frame.py:2027) (522 samples, 0.18%)set_cells (mesa_frames/abstract/space.py:763) (12,174 samples, 4.17%)set_c..run_model (sugarscape_ig/ss_polars/model.py:49) (12,192 samples, 4.17%)run_m.._df_combine_first (mesa_frames/concrete/polars/mixin.py:114) (15,813 samples, 5.41%)_df_com..join (polars/dataframe/frame.py:6927) (15,812 samples, 5.41%)join (p..collect (polars/lazyframe/frame.py:2027) (15,812 samples, 5.41%)collect.._df_combine_first (mesa_frames/concrete/polars/mixin.py:121) (945 samples, 0.32%)sort (polars/dataframe/frame.py:4939) (907 samples, 0.31%)collect (polars/lazyframe/frame.py:2027) (906 samples, 0.31%)set_cells (mesa_frames/abstract/space.py:763) (17,327 samples, 5.93%)set_cell..bench (perfplot/_main.py:521) (290,664 samples, 99.45%)bench (perfplot/_main.py:521)__next__ (perfplot/_main.py:253) (290,651 samples, 99.45%)__next__ (perfplot/_main.py:253)mesa_frames_polars_numba_parallel (sugarscape_ig/performance_comparison.py:97) (67,604 samples, 23.13%)mesa_frames_polars_numba_parallel (su..run_model (sugarscape_ig/ss_polars/model.py:50) (17,331 samples, 5.93%)run_mode..plot_and_print_benchmark (sugarscape_ig/performance_comparison.py:101) (290,665 samples, 99.45%)plot_and_print_benchmark (sugarscape_ig/performance_comparison.py:101)<module> (sugarscape_ig/performance_comparison.py:164) (290,672 samples, 99.45%)<module> (sugarscape_ig/performance_comparison.py:164)main (sugarscape_ig/performance_comparison.py:160) (290,671 samples, 99.45%)main (sugarscape_ig/performance_comparison.py:160)_check_buffer (rich/console.py:2060) (305 samples, 0.10%)refresh (rich/live.py:241) (380 samples, 0.13%)__exit__ (rich/console.py:865) (376 samples, 0.13%)_exit_buffer (rich/console.py:823) (373 samples, 0.13%)render (rich/console.py:1332) (363 samples, 0.12%)split_and_crop_lines (rich/segment.py:291) (395 samples, 0.14%)render_lines (rich/console.py:1373) (437 samples, 0.15%)render (rich/console.py:1332) (501 samples, 0.17%)__rich_console__ (rich/padding.py:97) (456 samples, 0.16%)split_and_crop_lines (rich/segment.py:291) (544 samples, 0.19%)render_lines (rich/console.py:1373) (587 samples, 0.20%)_render (rich/table.py:822) (604 samples, 0.21%)render (rich/console.py:1332) (853 samples, 0.29%)__rich_console__ (rich/table.py:509) (812 samples, 0.28%)split_and_crop_lines (rich/segment.py:291) (866 samples, 0.30%)render (rich/console.py:1336) (861 samples, 0.29%)__rich_console__ (rich/live_render.py:87) (890 samples, 0.30%)render_lines (rich/console.py:1373) (883 samples, 0.30%)render (rich/console.py:1332) (931 samples, 0.32%)print (rich/console.py:1700) (943 samples, 0.32%)all (292,271 samples, 100%)_bootstrap (threading.py:1002) (1,509 samples, 0.52%)_bootstrap_inner (threading.py:1045) (1,509 samples, 0.52%)run (rich/live.py:32) (1,489 samples, 0.51%)refresh (rich/live.py:242) (1,089 samples, 0.37%) \ No newline at end of file From 2806466b0bc545a790c89bc95b11f14ee5ef3af4 Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:32:10 +0200 Subject: [PATCH 33/37] fix: comparing DFs --- examples/sugarscape_ig/performance_comparison.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index c593498..1a27bcb 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -184,8 +184,8 @@ def plot_and_print_benchmark( def polars_equality_check(a: SugarscapePolars, b: SugarscapePolars): - assert_frame_equal(a.agents, b.agents, check_row_order=False) - assert_frame_equal(a.space, b.space, check_row_order=False) + assert_frame_equal(a.space.agents, b.space.agents, check_row_order=False) + assert_frame_equal(a.space.cells, b.space.cells, check_row_order=False) return True From 511f08d4529754e9a86c7d8fca561681b4e9d8ab Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:52:32 +0200 Subject: [PATCH 34/37] removing outdated picture --- examples/sugarscape_ig/benchmark_plot_1.png | Bin 32040 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/sugarscape_ig/benchmark_plot_1.png diff --git a/examples/sugarscape_ig/benchmark_plot_1.png b/examples/sugarscape_ig/benchmark_plot_1.png deleted file mode 100644 index 198d50ac6390d26aaa81133f5997d031c5316cb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32040 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 CC~^G& From 6644381807423086bd5ad4566927dc4e01a4d98d Mon Sep 17 00:00:00 2001 From: Adam Amer <136176500+adamamer20@users.noreply.github.com> Date: Wed, 2 Oct 2024 09:00:44 +0200 Subject: [PATCH 35/37] adding mesa_comparison.png --- docs/general/user-guide/4_benchmarks.md | 2 +- examples/sugarscape_ig/benchmark_plot_0.png | Bin 31211 -> 0 bytes examples/sugarscape_ig/mesa_comparison.png | Bin 0 -> 31762 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 examples/sugarscape_ig/benchmark_plot_0.png create mode 100644 examples/sugarscape_ig/mesa_comparison.png diff --git a/docs/general/user-guide/4_benchmarks.md b/docs/general/user-guide/4_benchmarks.md index e20aac9..61fca87 100644 --- a/docs/general/user-guide/4_benchmarks.md +++ b/docs/general/user-guide/4_benchmarks.md @@ -18,4 +18,4 @@ mesa-frames offers significant performance improvements over the original mesa f [View the benchmark script](https://github.com/projectmesa/mesa-frames/blob/main/examples/sugarscape_ig/performance_comparison.py) -![Performance Graph SS IG](https://github.com/projectmesa/mesa-frames/raw/main/examples/sugarscape_ig/benchmark_plot_0.png) +![Performance Graph SS IG](https://github.com/projectmesa/mesa-frames/raw/main/examples/sugarscape_ig/mesa_comparison.png) diff --git a/examples/sugarscape_ig/benchmark_plot_0.png b/examples/sugarscape_ig/benchmark_plot_0.png deleted file mode 100644 index 92408c49ed0a63a4f914085b53cd115852a1835c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31211 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 diff --git a/examples/sugarscape_ig/mesa_comparison.png b/examples/sugarscape_ig/mesa_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..c619ae281ba9601f5a1d659c9a1a5348e0a81f44 GIT binary patch literal 31762 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

fS zKBxrKqDb;l=-zaa^pm>Uf}$S_&q}u>O+Eaus3>0InfZy_abtd@L9c1UPR_HHT^^M3 zx-${a#oZ*sFuf*CoFm@8xI;Z?ugGnbyYKqFx((n4OkJ2<*MzHELD#K9ftTFn5%seg zU#|>S0?2xLWP& zbeOEqK33-v$Im%~Q-ZH|UM`fga;KoZ7Mq!Qa0AL;xgY=v?JsRNgp2jqJO7#SEDhMG z@bpaGa!f|-ta-)atl69CZ3iq2;GU2b=>xR6mGzWk)Rmz&y;VjXN2^o17c1FOwGamo z5jkzTEI`?KSn(0x=U*gN8or)F=l9=&`6&O|eL^rM%Wcv#!Np^+~jrLdBlZtyHT$shgI71;>N9U-fADN zMyWRSqBn{w^;zG)!3knXGBs#+3p(oHgQe1tr6+i9ie{V=EmV1A@j{e+)Y++5>JFj( zJ)J(byR&|)8#?bbLE+b>IS(JKbNzx)=dQw+s5z8(-hlKKJ+5qTn#(}2w{sh_n06|8 zYUgx#>w~z|j0pc!6}6j!SnRq<6{b+@V{8?!Kf~fvYh8IyLMBm?LQ;YQZrPm$Vj|5O*6hAz=clK!V$=wI{&9%Aqr+%0_ zx_`p!*=7{0P6GaP_TajG#cfq}U&bC*ZO5U)Mp_jyDAev8OFk6JM~(MyA-KjH^^k8n w{8tOT8ik@=qv22}3*H|YYw&0k>fV^Nr$Bw+F Date: Wed, 2 Oct 2024 09:00:58 +0200 Subject: [PATCH 36/37] adding polars_cocmparison.png --- examples/sugarscape_ig/polars_comparison.png | Bin 60352 -> 70235 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/sugarscape_ig/polars_comparison.png b/examples/sugarscape_ig/polars_comparison.png index 235a52e9703934932454278358f4620c6363b672..1b2112611683af0c288097b8c03fc8290546262c 100644 GIT binary patch literal 70235 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 literal 60352 zcmeFZdpy(s8$UdA%9(P?u}G9TC1Yk(DoUsnD`5_$GKb80*j71|kP69=PC7Vj5jl)S z4ke@1EM_LLFy;_TGk$NM&*yvJ|J;Ax|J;wq{eC<=%-j2QcwevUb-kX~^SZ9xIPT^o zC#@k30)ga?I3GL-0*N6&Ah6*k3E)oQCA}8l7cA-!GRhplOpM2ltW+I}3va-s>hALL z1Qp~ z=dY%B>gmZCZcHNq#$o=TexOcJFHrYT2`s_TgEKe;I}&A#l9*GEc*I{DYFaun5Y}*8A#W09U(|jw^Dx~QDXzN z`kp4frQWMDd_P{3fD^gG*5RDH%U^3Yea_FJ#!^Flj(d`Yn~_^=zG876#?zJARu@Yo z?Wb6mt)`Dc*f}Dz5*I||8RA_5@3M8eVRg`$V{YPM@0Q1QQ^N@!WZ}@X4TmO5Yqfto z)H()2866kZ!fR*f>FH(2{v*Z~Gs5X6z8{POeW!7)2PUd6CcDJKf!Rc?N}RO1I8!lC z2o5>uGe&W+g)~aViM)Lei*4a2$5>NJQa;}ty^?5Q{8^P&pG(5`XR-us3&n7qX+)ns zj3a@f+;yXZV>IJ=4m9uJ_5)Qu3>fDn3Gaj;;e7F%IZP==vXYY0nI}fSw(EWAj^~w$ z`n|cbBsO=^l&$2uUW1uMpu5`T{I6(fE<}U|QFd~e>TDg94EyN>^as&<>sv*JNXWr; zP?NM4hq7+;vl3}pKBVlse3hS!MAq VJ>i0x6{`N4oCfcY1_qoy(Xioa9m{fE5> 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 Date: Wed, 2 Oct 2024 09:02:21 +0200 Subject: [PATCH 37/37] updating kernels for comparison --- .../sugarscape_ig/performance_comparison.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/sugarscape_ig/performance_comparison.py b/examples/sugarscape_ig/performance_comparison.py index 1a27bcb..1d2ed56 100644 --- a/examples/sugarscape_ig/performance_comparison.py +++ b/examples/sugarscape_ig/performance_comparison.py @@ -192,22 +192,22 @@ def polars_equality_check(a: SugarscapePolars, b: SugarscapePolars): def main(): # Mesa comparison sns.set_theme(style="whitegrid") - """labels_0 = [ + labels_0 = [ + # "mesa-frames (pd concise)", # Pandas to be removed because of performance + "mesa-frames (pl numba parallel)", "mesa", - # "mesa-frames (pd concise)", - "mesa-frames (pl concise)", ] kernels_0 = [ - mesa_implementation, # mesa_frames_pandas_concise, - mesa_frames_polars_concise, + mesa_frames_polars_numba_parallel, + mesa_implementation, ] - n_range_0 = [k for k in range(1, 100002, 10000)] + n_range_0 = [k for k in range(10**5, 5*10**5 + 2, 10**5)] title_0 = "100 steps of the SugarScape IG model:\n" + " vs ".join(labels_0) - image_path_0 = "benchmark_plot_0.png" - plot_and_print_benchmark(labels_0, kernels_0, n_range_0, title_0, image_path_0)""" + image_path_0 = "mesa_comparison.png" + plot_and_print_benchmark(labels_0, kernels_0, n_range_0, title_0, image_path_0) - # FLAME2-GPU comparison + # mesa-frames comparison labels_1 = [ # "mesa-frames (pd concise)", "mesa-frames (pl loop DF)", @@ -218,7 +218,6 @@ def main(): ] # Polars best_moves (non-vectorized loop vs DF loop vs numba loop) kernels_1 = [ - # mesa_frames_pandas_concise, mesa_frames_polars_loop_DF, mesa_frames_polars_loop_no_vec, mesa_frames_polars_numba_cpu,