diff --git a/examples/aco_tsp/aco_tsp/model.py b/examples/aco_tsp/aco_tsp/model.py index 0b08ba93..1c41aff5 100644 --- a/examples/aco_tsp/aco_tsp/model.py +++ b/examples/aco_tsp/aco_tsp/model.py @@ -79,14 +79,10 @@ def from_tsp_file(cls, file_path: str) -> "TSPGraph": class AntTSP(CellAgent): - """ - An agent - """ + """An agent""" def __init__(self, model, alpha: float = 1.0, beta: float = 5.0): - """ - Customize the agent - """ + """Customize the agent""" super().__init__(model) self.alpha = alpha self.beta = beta @@ -141,11 +137,9 @@ def decide_next_city(self): return new_city def step(self): - """ - Modify this method to change what an individual agent will do during each step. + """Modify this method to change what an individual agent will do during each step. Can include logic based on neighbors states. """ - for _ in range(self.model.num_cities - 1): # Pick a random city that isn't in the list of cities visited new_city = self.decide_next_city() @@ -158,8 +152,7 @@ def step(self): class AcoTspModel(mesa.Model): - """ - The model class holds the model-level attributes, manages the agents, and generally handles + """The model class holds the model-level attributes, manages the agents, and generally handles the global level of our model. There is only one model-level parameter: how many agents the model contains. When a new model @@ -168,12 +161,16 @@ class AcoTspModel(mesa.Model): def __init__( self, + tsp_graph: TSPGraph | None, num_agents: int = 20, - tsp_graph: TSPGraph = TSPGraph.from_random(20), max_steps: int = int(1e6), ant_alpha: float = 1.0, ant_beta: float = 5.0, ): + # Don't create the TSPGraph.from_random as argument default: https://docs.astral.sh/ruff/rules/function-call-in-default-argument/ + if tsp_graph is None: + tsp_graph = TSPGraph.from_random(20) + super().__init__() self.num_agents = num_agents self.tsp_graph = tsp_graph @@ -224,15 +221,13 @@ def update_pheromone(self, q: float = 100, ro: float = 0.5): # Evaporate tau_ij = (1 - ro) * self.grid.G[i][j]["pheromone"] # Add ant's contribution - for k, delta_tau_ij_k in delta_tau_ij.items(): + for _, delta_tau_ij_k in delta_tau_ij.items(): tau_ij += delta_tau_ij_k.get((i, j), 0.0) self.grid.G[i][j]["pheromone"] = tau_ij def step(self): - """ - A model step. Used for activating the agents and collecting data. - """ + """A model step. Used for activating the agents and collecting data.""" self.agents.shuffle_do("step") self.update_pheromone() diff --git a/examples/aco_tsp/app.py b/examples/aco_tsp/app.py index 7a4ede59..155d5f8d 100644 --- a/examples/aco_tsp/app.py +++ b/examples/aco_tsp/app.py @@ -1,6 +1,4 @@ -""" -Configure visualization elements and instantiate a server -""" +"""Configure visualization elements and instantiate a server""" import networkx as nx import solara diff --git a/examples/bank_reserves/bank_reserves/agents.py b/examples/bank_reserves/bank_reserves/agents.py index eb953ab3..93a49292 100644 --- a/examples/bank_reserves/bank_reserves/agents.py +++ b/examples/bank_reserves/bank_reserves/agents.py @@ -1,5 +1,4 @@ -""" -The following code was adapted from the Bank Reserves model included in Netlogo +"""The following code was adapted from the Bank Reserves model included in Netlogo Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves Accessed on: November 2, 2017 @@ -18,7 +17,8 @@ class Bank: class. This is because there is only one bank in this model, and it does not use any Mesa-specific features like the scheduler or the grid, and doesn't have a step method. It is just used to keep track of the bank's reserves and - the amount it can loan out, for Person agents to interact with.""" + the amount it can loan out, for Person agents to interact with. + """ def __init__(self, model, reserve_percent=50): self.model = model @@ -63,8 +63,9 @@ def __init__(self, model, moore, bank, rich_threshold): self.bank = bank def do_business(self): - """check if person has any savings, any money in wallet, or if the - bank can loan them any money""" + """Check if person has any savings, any money in wallet, or if the + bank can loan them any money + """ if (self.savings > 0 or self.wallet > 0 or self.bank.bank_to_loan > 0) and len( self.cell.agents ) > 1: @@ -164,8 +165,9 @@ def repay_a_loan(self, amount): # part of balance_books() def take_out_loan(self, amount): - """borrow from the bank to put money in my wallet, and increase my - outstanding loans""" + """Borrow from the bank to put money in my wallet, and increase my + outstanding loans + """ self.loans += amount self.wallet += amount # decresae the amount the bank can loan right now diff --git a/examples/bank_reserves/bank_reserves/model.py b/examples/bank_reserves/bank_reserves/model.py index 2671980d..58a79b6f 100644 --- a/examples/bank_reserves/bank_reserves/model.py +++ b/examples/bank_reserves/bank_reserves/model.py @@ -1,5 +1,4 @@ -""" -The following code was adapted from the Bank Reserves model included in Netlogo +"""The following code was adapted from the Bank Reserves model included in Netlogo Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves Accessed on: November 2, 2017 @@ -25,22 +24,19 @@ def get_num_rich_agents(model): - """return number of rich agents""" - + """Return number of rich agents""" rich_agents = [a for a in model.agents if a.savings > model.rich_threshold] return len(rich_agents) def get_num_poor_agents(model): - """return number of poor agents""" - + """Return number of poor agents""" poor_agents = [a for a in model.agents if a.loans > 10] return len(poor_agents) def get_num_mid_agents(model): - """return number of middle class agents""" - + """Return number of middle class agents""" mid_agents = [ a for a in model.agents if a.loans < 10 and a.savings < model.rich_threshold ] @@ -48,16 +44,14 @@ def get_num_mid_agents(model): def get_total_savings(model): - """sum of all agents' savings""" - + """Sum of all agents' savings""" agent_savings = [a.savings for a in model.agents] # return the sum of agents' savings return np.sum(agent_savings) def get_total_wallets(model): - """sum of amounts of all agents' wallets""" - + """Sum of amounts of all agents' wallets""" agent_wallets = [a.wallet for a in model.agents] # return the sum of all agents' wallets return np.sum(agent_wallets) @@ -80,8 +74,7 @@ def get_total_loans(model): class BankReservesModel(mesa.Model): - """ - This model is a Mesa implementation of the Bank Reserves model from NetLogo. + """This model is a Mesa implementation of the Bank Reserves model from NetLogo. It is a highly abstracted, simplified model of an economy, with only one type of agent and a single bank representing all banks in an economy. People (represented by circles) move randomly within the grid. If two or more people @@ -160,5 +153,5 @@ def step(self): self.datacollector.collect(self) def run_model(self): - for i in range(self.run_time): + for _ in range(self.run_time): self.step() diff --git a/examples/bank_reserves/batch_run.py b/examples/bank_reserves/batch_run.py index 2903fd59..7ed01d3b 100644 --- a/examples/bank_reserves/batch_run.py +++ b/examples/bank_reserves/batch_run.py @@ -1,5 +1,4 @@ -""" -The following code was adapted from the Bank Reserves model included in Netlogo +"""The following code was adapted from the Bank Reserves model included in Netlogo Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves Accessed on: November 2, 2017 diff --git a/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/model.py b/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/model.py index 62f69475..a2b4e8b4 100644 --- a/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/model.py +++ b/examples/boltzmann_wealth_model_network/boltzmann_wealth_model_network/model.py @@ -40,6 +40,6 @@ def step(self): def compute_gini(self): agent_wealths = [agent.wealth for agent in self.agents] x = sorted(agent_wealths) - N = self.num_agents - B = sum(xi * (N - i) for i, xi in enumerate(x)) / (N * sum(x)) - return 1 + (1 / N) - 2 * B + num_agents = self.num_agents + B = sum(xi * (num_agents - i) for i, xi in enumerate(x)) / (num_agents * sum(x)) # noqa: N806 + return 1 + (1 / num_agents) - 2 * B diff --git a/examples/caching_and_replay/cacheablemodel.py b/examples/caching_and_replay/cacheablemodel.py index 3d739ddf..90c1d895 100644 --- a/examples/caching_and_replay/cacheablemodel.py +++ b/examples/caching_and_replay/cacheablemodel.py @@ -3,8 +3,7 @@ class CacheableSchelling(CacheableModel): - """ - A wrapper around the original Schelling model to make the simulation cacheable + """A wrapper around the original Schelling model to make the simulation cacheable and replay-able. Uses CacheableModel from the Mesa-Replay library, which is a wrapper that can be put around any regular mesa model to make it "cacheable". diff --git a/examples/caching_and_replay/model.py b/examples/caching_and_replay/model.py index d04c818d..55536b2b 100644 --- a/examples/caching_and_replay/model.py +++ b/examples/caching_and_replay/model.py @@ -5,13 +5,10 @@ class SchellingAgent(CellAgent): - """ - Schelling segregation agent - """ + """Schelling segregation agent""" def __init__(self, model, agent_type): - """ - Create a new Schelling agent. + """Create a new Schelling agent. Args: x, y: Agent initial location. @@ -34,9 +31,7 @@ def step(self): class Schelling(mesa.Model): - """ - Model class for the Schelling segregation model. - """ + """Model class for the Schelling segregation model.""" def __init__( self, @@ -48,8 +43,7 @@ def __init__( minority_pc=0.3, seed=None, ): - """ - Create a new Schelling model. + """Create a new Schelling model. Args: width, height: Size of the space. @@ -59,7 +53,6 @@ def __init__( radius: Search radius for checking similarity seed: Seed for Reproducibility """ - super().__init__(seed=seed) self.height = height self.width = width @@ -88,9 +81,7 @@ def __init__( self.datacollector.collect(self) def step(self): - """ - Run one step of the model. - """ + """Run one step of the model.""" self.happy = 0 # Reset counter of happy agents self.agents.shuffle_do("step") diff --git a/examples/caching_and_replay/run.py b/examples/caching_and_replay/run.py index d2b5dc3d..bf972a34 100644 --- a/examples/caching_and_replay/run.py +++ b/examples/caching_and_replay/run.py @@ -10,9 +10,7 @@ def get_cache_file_status(_): - """ - Display an informational text about caching and the status of the cache file (existing versus not existing) - """ + """Display an informational text about caching and the status of the cache file (existing versus not existing)""" cache_file = Path(model_params["cache_file_path"]) return ( f"Only activate the 'Replay cached run?' switch when a cache file already exists, otherwise it will fail. " diff --git a/examples/caching_and_replay/server.py b/examples/caching_and_replay/server.py index f4963c52..40f965f7 100644 --- a/examples/caching_and_replay/server.py +++ b/examples/caching_and_replay/server.py @@ -5,16 +5,12 @@ def get_happy_agents(model): - """ - Display a text count of how many happy agents there are. - """ + """Display a text count of how many happy agents there are.""" return f"Happy agents: {model.happy}" def schelling_draw(agent): - """ - Portrayal Method for canvas - """ + """Portrayal Method for canvas""" if agent is None: return portrayal = {"Shape": "circle", "r": 0.5, "Filled": "true", "Layer": 0} diff --git a/examples/charts/charts/agents.py b/examples/charts/charts/agents.py index 64dc0d91..a6a9f5d5 100644 --- a/examples/charts/charts/agents.py +++ b/examples/charts/charts/agents.py @@ -1,5 +1,4 @@ -""" -The following code was adapted from the Bank Reserves model included in Netlogo +"""The following code was adapted from the Bank Reserves model included in Netlogo Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves Accessed on: November 2, 2017 @@ -18,7 +17,8 @@ class Bank: class. This is because there is only one bank in this model, and it does not use any Mesa-specific features like the scheduler or the grid, and doesn't have a step method. It is just used to keep track of the bank's reserves and - the amount it can loan out, for Person agents to interact with.""" + the amount it can loan out, for Person agents to interact with. + """ def __init__(self, model, reserve_percent=50): self.model = model @@ -63,8 +63,9 @@ def __init__(self, model, bank, rich_threshold): self.bank = bank def do_business(self): - """check if person has any savings, any money in wallet, or if the - bank can loan them any money""" + """Check if person has any savings, any money in wallet, or if the + bank can loan them any money + """ if self.savings > 0 or self.wallet > 0 or self.bank.bank_to_loan > 0: # create list of people at my location (includes self) my_cell = [a for a in self.cell.agents if a != self] @@ -167,8 +168,9 @@ def repay_a_loan(self, amount): # part of balance_books() def take_out_loan(self, amount): - """borrow from the bank to put money in my wallet, and increase my - outstanding loans""" + """Borrow from the bank to put money in my wallet, and increase my + outstanding loans + """ self.loans += amount self.wallet += amount # decresae the amount the bank can loan right now diff --git a/examples/charts/charts/model.py b/examples/charts/charts/model.py index 6785c55f..26582940 100644 --- a/examples/charts/charts/model.py +++ b/examples/charts/charts/model.py @@ -1,5 +1,4 @@ -""" -The following code was adapted from the Bank Reserves model included in Netlogo +"""The following code was adapted from the Bank Reserves model included in Netlogo Model information can be found at: http://ccl.northwestern.edu/netlogo/models/BankReserves Accessed on: November 2, 2017 @@ -25,22 +24,19 @@ def get_num_rich_agents(model): - """return number of rich agents""" - + """Return number of rich agents""" rich_agents = [a for a in model.agents if a.savings > model.rich_threshold] return len(rich_agents) def get_num_poor_agents(model): - """return number of poor agents""" - + """Return number of poor agents""" poor_agents = [a for a in model.agents if a.loans > 10] return len(poor_agents) def get_num_mid_agents(model): - """return number of middle class agents""" - + """Return number of middle class agents""" mid_agents = [ a for a in model.agents if a.loans < 10 and a.savings < model.rich_threshold ] @@ -48,16 +44,14 @@ def get_num_mid_agents(model): def get_total_savings(model): - """sum of all agents' savings""" - + """Sum of all agents' savings""" agent_savings = [a.savings for a in model.agents] # return the sum of agents' savings return np.sum(agent_savings) def get_total_wallets(model): - """sum of amounts of all agents' wallets""" - + """Sum of amounts of all agents' wallets""" agent_wallets = [a.wallet for a in model.agents] # return the sum of all agents' wallets return np.sum(agent_wallets) @@ -143,5 +137,5 @@ def step(self): self.datacollector.collect(self) def run_model(self): - for i in range(self.run_time): + for _ in range(self.run_time): self.step() diff --git a/examples/color_patches/app.py b/examples/color_patches/app.py index d7c6741b..17a265ae 100644 --- a/examples/color_patches/app.py +++ b/examples/color_patches/app.py @@ -1,5 +1,4 @@ -""" -handles the definition of the canvas parameters and +"""handles the definition of the canvas parameters and the drawing of the model representation on the canvas """ @@ -38,8 +37,7 @@ def color_patch_draw(cell): - """ - This function is registered with the visualization server to be called + """This function is registered with the visualization server to be called each tick to indicate how to draw the cell in its current state. :param cell: the cell in the simulation diff --git a/examples/el_farol/el_farol.ipynb b/examples/el_farol/el_farol.ipynb index b043c98b..79a97a79 100644 --- a/examples/el_farol/el_farol.ipynb +++ b/examples/el_farol/el_farol.ipynb @@ -24,7 +24,7 @@ " for m in memory_sizes\n", "]\n", "for model in models:\n", - " for i in range(100):\n", + " for _ in range(100):\n", " model.step()" ] }, @@ -99,7 +99,7 @@ " for ns in num_strategies_list\n", "]\n", "for model in models:\n", - " for i in range(100):\n", + " for _ in range(100):\n", " model.step()" ] }, diff --git a/examples/el_farol/el_farol/model.py b/examples/el_farol/el_farol/model.py index a57d5de5..4c927f00 100644 --- a/examples/el_farol/el_farol/model.py +++ b/examples/el_farol/el_farol/model.py @@ -10,11 +10,11 @@ def __init__( crowd_threshold=60, num_strategies=10, memory_size=10, - N=100, + num_agents=100, ): super().__init__() self.running = True - self.num_agents = N + self.num_agents = num_agents # Initialize the previous attendance randomly so the agents have a history # to work with from the start. diff --git a/examples/forest_fire/Forest Fire Model.ipynb b/examples/forest_fire/Forest Fire Model.ipynb index c1f96a4c..ff812173 100644 --- a/examples/forest_fire/Forest Fire Model.ipynb +++ b/examples/forest_fire/Forest Fire Model.ipynb @@ -82,8 +82,7 @@ "\n", "\n", "class TreeCell(FixedAgent):\n", - " \"\"\"\n", - " A tree cell.\n", + " \"\"\"A tree cell.\n", "\n", " Attributes:\n", " condition: Can be \"Fine\", \"On Fire\", or \"Burned Out\"\n", @@ -91,8 +90,8 @@ " \"\"\"\n", "\n", " def __init__(self, model, cell):\n", - " \"\"\"\n", - " Create a new tree.\n", + " \"\"\"Create a new tree.\n", + "\n", " Args:\n", " model: standard model reference for agent.\n", " \"\"\"\n", @@ -101,9 +100,7 @@ " self.cell = cell\n", "\n", " def step(self):\n", - " \"\"\"\n", - " If the tree is on fire, spread it to fine trees nearby.\n", - " \"\"\"\n", + " \"\"\"If the tree is on fire, spread it to fine trees nearby.\"\"\"\n", " if self.condition == \"On Fire\":\n", " for neighbor in self.cell.neighborhood.agents:\n", " if neighbor.condition == \"Fine\":\n", @@ -136,13 +133,10 @@ "\n", "\n", "class ForestFire(Model):\n", - " \"\"\"\n", - " Simple Forest Fire model.\n", - " \"\"\"\n", + " \"\"\"Simple Forest Fire model.\"\"\"\n", "\n", " def __init__(self, width=100, height=100, density=0.65, seed=None):\n", - " \"\"\"\n", - " Create a new forest fire model.\n", + " \"\"\"Create a new forest fire model.\n", "\n", " Args:\n", " width, height: The size of the grid to model\n", @@ -174,9 +168,7 @@ " self.datacollector.collect(self)\n", "\n", " def step(self):\n", - " \"\"\"\n", - " Advance the model by one step.\n", - " \"\"\"\n", + " \"\"\"Advance the model by one step.\"\"\"\n", " self.agents.shuffle_do(\"step\")\n", " # collect data\n", " self.datacollector.collect(self)\n", @@ -187,9 +179,7 @@ "\n", " @staticmethod\n", " def count_type(model, tree_condition):\n", - " \"\"\"\n", - " Helper method to count trees in a given condition in a given model.\n", - " \"\"\"\n", + " \"\"\"Helper method to count trees in a given condition in a given model.\"\"\"\n", " return len(model.agents.select(lambda x: x.condition == tree_condition))" ] }, diff --git a/examples/forest_fire/forest_fire/agent.py b/examples/forest_fire/forest_fire/agent.py index 125f42f8..0eeb12d0 100644 --- a/examples/forest_fire/forest_fire/agent.py +++ b/examples/forest_fire/forest_fire/agent.py @@ -2,8 +2,7 @@ class TreeCell(FixedAgent): - """ - A tree cell. + """A tree cell. Attributes: condition: Can be "Fine", "On Fire", or "Burned Out" @@ -11,8 +10,8 @@ class TreeCell(FixedAgent): """ def __init__(self, model, cell): - """ - Create a new tree. + """Create a new tree. + Args: model: standard model reference for agent. """ @@ -21,9 +20,7 @@ def __init__(self, model, cell): self.cell = cell def step(self): - """ - If the tree is on fire, spread it to fine trees nearby. - """ + """If the tree is on fire, spread it to fine trees nearby.""" if self.condition == "On Fire": for neighbor in self.cell.neighborhood.agents: if neighbor.condition == "Fine": diff --git a/examples/forest_fire/forest_fire/model.py b/examples/forest_fire/forest_fire/model.py index 45366de2..273b0c1f 100644 --- a/examples/forest_fire/forest_fire/model.py +++ b/examples/forest_fire/forest_fire/model.py @@ -5,13 +5,10 @@ class ForestFire(mesa.Model): - """ - Simple Forest Fire model. - """ + """Simple Forest Fire model.""" def __init__(self, width=100, height=100, density=0.65, seed=None): - """ - Create a new forest fire model. + """Create a new forest fire model. Args: width, height: The size of the grid to model @@ -43,9 +40,7 @@ def __init__(self, width=100, height=100, density=0.65, seed=None): self.datacollector.collect(self) def step(self): - """ - Advance the model by one step. - """ + """Advance the model by one step.""" self.agents.shuffle_do("step") # collect data self.datacollector.collect(self) @@ -56,7 +51,5 @@ def step(self): @staticmethod def count_type(model, tree_condition): - """ - Helper method to count trees in a given condition in a given model. - """ + """Helper method to count trees in a given condition in a given model.""" return len(model.agents.select(lambda x: x.condition == tree_condition)) diff --git a/examples/hex_snowflake/hex_snowflake/cell.py b/examples/hex_snowflake/hex_snowflake/cell.py index f68223a7..17d52291 100644 --- a/examples/hex_snowflake/hex_snowflake/cell.py +++ b/examples/hex_snowflake/hex_snowflake/cell.py @@ -8,9 +8,7 @@ class Cell(FixedAgent): ALIVE = 1 def __init__(self, cell, model, init_state=DEAD): - """ - Create a cell, in the given state, at the given x, y position. - """ + """Create a cell, in the given state, at the given x, y position.""" super().__init__(model) self.cell = cell self.state = init_state @@ -26,8 +24,7 @@ def considered(self): return self.is_considered is True def determine_state(self): - """ - Compute if the cell will be dead or alive at the next tick. A dead + """Compute if the cell will be dead or alive at the next tick. A dead cell will become alive if it has only one neighbor. The state is not changed here, but is just computed and stored in self._next_state, because our current state may still be necessary for our neighbors @@ -52,7 +49,5 @@ def determine_state(self): a.is_considered = True def assume_state(self): - """ - Set the state to the new computed state - """ + """Set the state to the new computed state""" self.state = self._next_state diff --git a/examples/hex_snowflake/hex_snowflake/model.py b/examples/hex_snowflake/hex_snowflake/model.py index fd2bd312..48201f74 100644 --- a/examples/hex_snowflake/hex_snowflake/model.py +++ b/examples/hex_snowflake/hex_snowflake/model.py @@ -5,15 +5,12 @@ class HexSnowflake(mesa.Model): - """ - Represents the hex grid of cells. The grid is represented by a 2-dimensional array + """Represents the hex grid of cells. The grid is represented by a 2-dimensional array of cells with adjacency rules specific to hexagons. """ def __init__(self, width=50, height=50, seed=None): - """ - Create a new playing area of (width, height) cells. - """ + """Create a new playing area of (width, height) cells.""" super().__init__(seed=seed) # Use a hexagonal grid, where edges wrap around. self.grid = HexGrid((width, height), capacity=1, torus=True, random=self.random) @@ -31,8 +28,7 @@ def __init__(self, width=50, height=50, seed=None): self.running = True def step(self): - """ - Perform the model step in two stages: + """Perform the model step in two stages: - First, all cells assume their next state (whether they will be dead or alive) - Then, all cells change state to their next state """ diff --git a/examples/hex_snowflake/hex_snowflake/portrayal.py b/examples/hex_snowflake/hex_snowflake/portrayal.py index a0a4020e..621baf79 100644 --- a/examples/hex_snowflake/hex_snowflake/portrayal.py +++ b/examples/hex_snowflake/hex_snowflake/portrayal.py @@ -1,6 +1,5 @@ def portrayCell(cell): - """ - This function is registered with the visualization server to be called + """This function is registered with the visualization server to be called each tick to indicate how to draw the cell in its current state. :param cell: the cell in the simulation :return: the portrayal dictionary. diff --git a/examples/hotelling_law/hotelling_law/agents.py b/examples/hotelling_law/hotelling_law/agents.py index 34657aa8..36694241 100644 --- a/examples/hotelling_law/hotelling_law/agents.py +++ b/examples/hotelling_law/hotelling_law/agents.py @@ -7,7 +7,8 @@ class StoreAgent(CellAgent): """An agent representing a store with a price and ability to move - and adjust prices.""" + and adjust prices. + """ def __init__(self, model, cell, price=10, can_move=True, strategy="Budget"): # Initializes the store agent with a unique ID, @@ -128,7 +129,8 @@ def identify_competitors(self): def estimate_market_overlap(self, other_store): """Estimate market overlap between this store and another store. - This could be based on shared consumer base or other factors.""" + This could be based on shared consumer base or other factors. + """ overlap = 0 for consumer in self.model.agents_by_type[ConsumerAgent]: @@ -156,7 +158,8 @@ def step(self): class ConsumerAgent(CellAgent): """A consumer agent that chooses a store - based on price and distance.""" + based on price and distance. + """ def __init__(self, model, cell, consumer_preferences): super().__init__(model) diff --git a/examples/hotelling_law/hotelling_law/model.py b/examples/hotelling_law/hotelling_law/model.py index 0ebde89b..ca6960fa 100644 --- a/examples/hotelling_law/hotelling_law/model.py +++ b/examples/hotelling_law/hotelling_law/model.py @@ -10,15 +10,14 @@ # The main model class that sets up and runs the simulation. class HotellingModel(Model): - """ - A model simulating competition and pricing strategies among stores + """A model simulating competition and pricing strategies among stores within a defined environment. This simulation explores the dynamics of market competition, specifically focusing on how pricing and location strategies affect market outcomes in accordance with Hotelling's Law. Parameters: - N_stores (int): The number of store agents participating + n_stores (int): The number of store agents participating in the simulation.Each agent acts as an individual store competing in the market. width (int), height (int): The dimensions of the simulation grid. @@ -67,8 +66,8 @@ class HotellingModel(Model): def __init__( self, - N_stores=20, - N_consumers=100, + n_stores=20, + n_consumers=100, width=50, height=50, mode="default", @@ -82,9 +81,9 @@ def __init__( # and mobility rate. super().__init__(seed=seed) # Total number of store agents in the model. - self.num_agents = N_stores + self.num_agents = n_stores # Total number of consumers - self.num_consumers = N_consumers + self.num_consumers = n_consumers # Percentage of agents that can move. self.mobility_rate = mobility_rate # Operational mode of the simulation affects agents' behavior @@ -111,18 +110,18 @@ def __init__( # Dynamically generate store-specific price collectors store_price_collectors = { - f"Store_{i}_Price": self.get_store_price_lambda(i) for i in range(N_stores) + f"Store_{i}_Price": self.get_store_price_lambda(i) for i in range(n_stores) } # Dynamically generate store-specific market_share collectors store_market_share_collectors = { f"Store_{i}_Market Share": self.get_market_share_lambda(i) - for i in range(N_stores) + for i in range(n_stores) } # Dynamically generate store-specific revenue collectors store_revenue_collectors = { - f"Store_{i}_Revenue": self.get_revenue_lambda(i) for i in range(N_stores) + f"Store_{i}_Revenue": self.get_revenue_lambda(i) for i in range(n_stores) } # Combine the dictionaries and pass them to DataCollector @@ -137,7 +136,8 @@ def __init__( @staticmethod def get_store_price_lambda(unique_id): """Return a lambda function that gets the - price of a store by its unique ID.""" + price of a store by its unique ID. + """ return lambda m: next( ( agent.price @@ -150,7 +150,8 @@ def get_store_price_lambda(unique_id): @staticmethod def get_market_share_lambda(unique_id): """Return a lambda function that gets the - market_share of a store by its unique ID.""" + market_share of a store by its unique ID. + """ return lambda m: next( ( agent.market_share @@ -163,7 +164,8 @@ def get_market_share_lambda(unique_id): @staticmethod def get_revenue_lambda(unique_id): """Return a lambda function that calculates the - revenue of a store by its unique ID.""" + revenue of a store by its unique ID. + """ return lambda m: next( ( agent.market_share * agent.price @@ -224,7 +226,7 @@ def recalculate_market_share(self): # Utility method to run the model for a specified number of steps. def run_model(self, step_count=200): """Run the model for a certain number of steps.""" - for i in range(step_count): + for _ in range(step_count): self.step() # Method to export collected data to CSV files for further analysis. diff --git a/examples/hotelling_law/tests.py b/examples/hotelling_law/tests.py index 7787fa8a..75f2aefc 100644 --- a/examples/hotelling_law/tests.py +++ b/examples/hotelling_law/tests.py @@ -5,7 +5,8 @@ def check_slope(data, increasing=True): """Checks the slope of a dataset to determine - if it's increasing or decreasing.""" + if it's increasing or decreasing. + """ slope = get_slope(data) return (slope > 0) if increasing else (slope < 0) @@ -18,7 +19,8 @@ def get_slope(data): def test_decreasing_price_variance(): """Test to ensure the price variance decreases over time, - in line with Hotelling's law.""" + in line with Hotelling's law. + """ model = HotellingModel( N_stores=5, width=20, @@ -39,7 +41,8 @@ def test_decreasing_price_variance(): def test_constant_price_variance(): """Test to ensure the price variance constant over time, - with Rules location_only without changing price""" + with Rules location_only without changing price + """ model = HotellingModel( N_stores=5, width=20, diff --git a/examples/shape_example/shape_example/model.py b/examples/shape_example/shape_example/model.py index 728f8266..d279e490 100644 --- a/examples/shape_example/shape_example/model.py +++ b/examples/shape_example/shape_example/model.py @@ -10,9 +10,9 @@ def __init__(self, model, heading=(1, 0)): class ShapeExample(mesa.Model): - def __init__(self, N=2, width=20, height=10): + def __init__(self, num_agents=2, width=20, height=10): super().__init__() - self.N = N # num of agents + self.num_agents = num_agents # num of agents self.headings = ((1, 0), (0, 1), (-1, 0), (0, -1)) # tuples are fast self.grid = OrthogonalMooreGrid((width, height), torus=True, random=self.random) @@ -20,7 +20,7 @@ def __init__(self, N=2, width=20, height=10): self.running = True def make_walker_agents(self): - for _ in range(self.N): + for _ in range(self.num_agents): x = self.random.randrange(self.grid.dimensions[0]) y = self.random.randrange(self.grid.dimensions[1]) cell = self.grid[(x, y)] diff --git a/examples/termites/termites/agents.py b/examples/termites/termites/agents.py index 4bcdcaa3..fbcc5fef 100644 --- a/examples/termites/termites/agents.py +++ b/examples/termites/termites/agents.py @@ -2,18 +2,16 @@ class Termite(CellAgent): - """ - A Termite agent that has ability to carry woodchip. + """A Termite agent that has ability to carry woodchip. Attributes: has_woodchip(bool): True if the agent is carrying a wood chip. """ def __init__(self, model, cell): - """ - Args: - model: The model instance. - cell: The starting cell (position) of the agent. + """Args: + model: The model instance. + cell: The starting cell (position) of the agent. """ super().__init__(model) self.cell = cell @@ -71,11 +69,10 @@ def get_away(self): break def step(self): - """ - Protocol which termite agent follows: - 1. Search for a wood chip if not carrying one. - 2. Find a new pile (a cell with a wood chip) if carrying a chip. - 3. Put down the chip if a suitable location is found. + """Protocol which termite agent follows: + 1. Search for a wood chip if not carrying one. + 2. Find a new pile (a cell with a wood chip) if carrying a chip. + 3. Put down the chip if a suitable location is found. """ if not self.has_woodchip: while not self.search_for_chip(): diff --git a/examples/termites/termites/model.py b/examples/termites/termites/model.py index 32ba4d89..1d9da107 100644 --- a/examples/termites/termites/model.py +++ b/examples/termites/termites/model.py @@ -5,9 +5,7 @@ class TermiteModel(Model): - """ - A simulation that shows behavior of termite agents gathering wood chips into piles. - """ + """A simulation that shows behavior of termite agents gathering wood chips into piles.""" def __init__( self, num_termites=100, width=100, height=100, wood_chip_density=0.1, seed=42 diff --git a/examples/warehouse/app.py b/examples/warehouse/app.py index 2015878a..c24c57c4 100644 --- a/examples/warehouse/app.py +++ b/examples/warehouse/app.py @@ -20,8 +20,7 @@ def prepare_agent_data(model, agent_type, agent_label): - """ - Prepare data for agents of a specific type. + """Prepare data for agents of a specific type. Args: model: The WarehouseModel instance. @@ -44,8 +43,7 @@ def prepare_agent_data(model, agent_type, agent_label): @solara.component def plot_warehouse(model): - """ - Visualize the warehouse model in a 3D scatter plot. + """Visualize the warehouse model in a 3D scatter plot. Args: model: The WarehouseModel instance. diff --git a/examples/warehouse/warehouse/agents.py b/examples/warehouse/warehouse/agents.py index 06b088b7..7bdf2ac8 100644 --- a/examples/warehouse/warehouse/agents.py +++ b/examples/warehouse/warehouse/agents.py @@ -5,9 +5,7 @@ class InventoryAgent(FixedAgent): - """ - Represents an inventory item in the warehouse. - """ + """Represents an inventory item in the warehouse.""" def __init__(self, model, cell, item: str): super().__init__(model) @@ -17,8 +15,7 @@ def __init__(self, model, cell, item: str): class RouteAgent(mesa.Agent): - """ - Handles path finding for agents in the warehouse. + """Handles path finding for agents in the warehouse. Intended to be a pseudo onboard GPS system for robots. """ @@ -27,9 +24,7 @@ def __init__(self, model): super().__init__(model) def find_path(self, start, goal) -> list[tuple[int, int, int]] | None: - """ - Determines the path for a robot to take using the A* algorithm. - """ + """Determines the path for a robot to take using the A* algorithm.""" def heuristic(a, b) -> int: dx = abs(a[0] - b[0]) @@ -75,8 +70,7 @@ def heuristic(a, b) -> int: class SensorAgent(mesa.Agent): - """ - Detects entities in the area and handles movement along a path. + """Detects entities in the area and handles movement along a path. Intended to be a pseudo onboard sensor system for robot. """ @@ -87,9 +81,7 @@ def __init__(self, model): def move( self, coord: tuple[int, int, int], path: list[tuple[int, int, int]] ) -> str: - """ - Moves the agent along the given path. - """ + """Moves the agent along the given path.""" if coord not in path: raise ValueError("Current coordinate not in path.") @@ -117,9 +109,7 @@ def move( class WorkerAgent(mesa.Agent): - """ - Represents a robot worker responsible for collecting and loading items. - """ + """Represents a robot worker responsible for collecting and loading items.""" def __init__(self, model, ld, cs): super().__init__(model) @@ -130,16 +120,12 @@ def __init__(self, model, ld, cs): self.item: InventoryAgent | None = None def initiate_task(self, item: InventoryAgent): - """ - Initiates a task for the robot to perform. - """ + """Initiates a task for the robot to perform.""" self.item = item self.path = self.find_path(self.cell, item.cell) def continue_task(self): - """ - Continues the task if the robot is able to perform it. - """ + """Continues the task if the robot is able to perform it.""" status = self.meta_agent.get_constituting_agent_instance(SensorAgent).move( self.cell.coordinate, self.path ) diff --git a/examples/warehouse/warehouse/make_warehouse.py b/examples/warehouse/warehouse/make_warehouse.py index bbd5a8d3..d87bd2d7 100644 --- a/examples/warehouse/warehouse/make_warehouse.py +++ b/examples/warehouse/warehouse/make_warehouse.py @@ -21,8 +21,7 @@ def generate_item_code() -> str: def make_warehouse( rows: int = DEFAULT_ROWS, cols: int = DEFAULT_COLS, height: int = DEFAULT_HEIGHT ) -> np.ndarray: - """ - Generate a warehouse layout with designated LD, CS, and storage rows as a NumPy array. + """Generate a warehouse layout with designated LD, CS, and storage rows as a NumPy array. Args: rows (int): Number of rows in the warehouse. diff --git a/examples/warehouse/warehouse/model.py b/examples/warehouse/warehouse/model.py index 158c7028..1d912483 100644 --- a/examples/warehouse/warehouse/model.py +++ b/examples/warehouse/warehouse/model.py @@ -24,15 +24,13 @@ class WarehouseModel(mesa.Model): - """ - Model for simulating warehouse management with autonomous systems where + """Model for simulating warehouse management with autonomous systems where each autonomous system (e.g., robot) is made of numerous smaller agents (e.g., routing, sensors, etc.). """ def __init__(self, seed=42): - """ - Initialize the model. + """Initialize the model. Args: seed (int): Random seed. @@ -87,8 +85,7 @@ def __init__(self, seed=42): ) def central_move(self, robot): - """ - Consolidates meta-agent behavior in the model class. + """Consolidates meta-agent behavior in the model class. Args: robot: The robot meta-agent to move. @@ -96,9 +93,7 @@ def central_move(self, robot): robot.move(robot.cell.coordinate, robot.path) def step(self): - """ - Advance the model by one step. - """ + """Advance the model by one step.""" for robot in self.agents_by_type[type(self.RobotAgent)]: if robot.status == "open": # Assign a task to the robot item = self.random.choice(self.agents_by_type[InventoryAgent]) diff --git a/gis/agents_and_networks/src/space/road_network.py b/gis/agents_and_networks/src/space/road_network.py index 4c260afa..2f70cac4 100644 --- a/gis/agents_and_networks/src/space/road_network.py +++ b/gis/agents_and_networks/src/space/road_network.py @@ -19,7 +19,7 @@ class RoadNetwork: def __init__(self, lines: gpd.GeoSeries): segmented_lines = gpd.GeoDataFrame(geometry=segmented(lines)) - G = momepy.gdf_to_nx(segmented_lines, approach="primal", length="length") + G = momepy.gdf_to_nx(segmented_lines, approach="primal", length="length") # noqa: N806 self.nx_graph = G.subgraph(max(nx.connected_components(G), key=len)) self.crs = lines.crs @@ -70,7 +70,7 @@ def __init__(self, campus, lines, output_dir) -> None: self._path_cache_result = f"{output_dir}/{campus}_path_cache_result.pkl" try: with open(self._path_cache_result, "rb") as cached_result: - self._path_select_cache = pickle.load(cached_result) + self._path_select_cache = pickle.load(cached_result) # noqa: S301 except FileNotFoundError: self._path_select_cache = {} diff --git a/gis/agents_and_networks/src/space/utils.py b/gis/agents_and_networks/src/space/utils.py index 2f458845..8cb8de66 100644 --- a/gis/agents_and_networks/src/space/utils.py +++ b/gis/agents_and_networks/src/space/utils.py @@ -22,7 +22,7 @@ def get_coord_matrix( def get_affine_transform( from_coord: np.ndarray, to_coord: np.ndarray ) -> tuple[float, float, float, float, float, float]: - A, res, rank, s = np.linalg.lstsq(from_coord, to_coord, rcond=None) + A, res, rank, s = np.linalg.lstsq(from_coord, to_coord, rcond=None) # noqa: N806 np.testing.assert_array_almost_equal(res, np.zeros_like(res), decimal=15) np.testing.assert_array_almost_equal(A[:, 2], np.array([0.0, 0.0, 1.0]), decimal=15) @@ -57,7 +57,7 @@ def _segmented(linestring: LineString) -> list[LineString]: # reference: https://gis.stackexchange.com/questions/367228/using-shapely-interpolate-to-evenly-re-sample-points-on-a-linestring-geodatafram def redistribute_vertices(geom, distance): if isinstance(geom, LineString): - if (num_vert := int(round(geom.length / distance))) == 0: + if (num_vert := round(geom.length / distance)) == 0: num_vert = 1 return LineString( [ @@ -78,9 +78,13 @@ class UnitTransformer: _degree2meter: pyproj.Transformer _meter2degree: pyproj.Transformer - def __init__( - self, degree_crs=pyproj.CRS("EPSG:4326"), meter_crs=pyproj.CRS("EPSG:3857") - ): + def __init__(self, degree_crs: pyproj.CRS | None, meter_crs: pyproj.CRS | None): + if degree_crs is None: + degree_crs = pyproj.CRS("EPSG:4326") + + if meter_crs is None: + meter_crs = pyproj.CRS("EPSG:3857") + self._degree2meter = pyproj.Transformer.from_crs( degree_crs, meter_crs, always_xy=True ) diff --git a/gis/geo_schelling/app.py b/gis/geo_schelling/app.py index f19a99c7..091dce73 100644 --- a/gis/geo_schelling/app.py +++ b/gis/geo_schelling/app.py @@ -16,9 +16,7 @@ def make_plot_happiness(model): def schelling_draw(agent): - """ - Portrayal Method for canvas - """ + """Portrayal Method for canvas""" portrayal = {} if agent.atype is None: portrayal["color"] = "Grey" diff --git a/gis/geo_schelling/model.py b/gis/geo_schelling/model.py index 81568fc2..810da1d6 100644 --- a/gis/geo_schelling/model.py +++ b/gis/geo_schelling/model.py @@ -12,11 +12,11 @@ def get_largest_connected_components(gdf): """Get the largest connected component of a GeoDataFrame.""" # create spatial weights matrix - W = libpysal.weights.Queen.from_dataframe( + w = libpysal.weights.Queen.from_dataframe( gdf, use_index=True, silence_warnings=True ) # get component labels - gdf["component"] = W.component_labels + gdf["component"] = w.component_labels # get the largest component largest_component = gdf["component"].value_counts().idxmax() # subset the GeoDataFrame diff --git a/gis/geo_schelling_points/geo_schelling_points/model.py b/gis/geo_schelling_points/geo_schelling_points/model.py index 0f2b3f34..54b13d58 100644 --- a/gis/geo_schelling_points/geo_schelling_points/model.py +++ b/gis/geo_schelling_points/geo_schelling_points/model.py @@ -15,11 +15,11 @@ def get_largest_connected_components(gdf): """Get the largest connected component of a GeoDataFrame.""" # create spatial weights matrix - W = libpysal.weights.Queen.from_dataframe( + w = libpysal.weights.Queen.from_dataframe( gdf, use_index=True, silence_warnings=True ) # get component labels - gdf["component"] = W.component_labels + gdf["component"] = w.component_labels # get the largest component largest_component = gdf["component"].value_counts().idxmax() # subset the GeoDataFrame diff --git a/gis/geo_sir/app.py b/gis/geo_sir/app.py index 5628212d..6407735d 100644 --- a/gis/geo_sir/app.py +++ b/gis/geo_sir/app.py @@ -11,9 +11,7 @@ def infected_draw(agent): - """ - Portrayal Method for canvas - """ + """Portrayal Method for canvas""" portrayal = {} if isinstance(agent, PersonAgent): portrayal["radius"] = "2" diff --git a/gis/geo_sir/geo_sir/agents.py b/gis/geo_sir/geo_sir/agents.py index f7f5e858..0cae6487 100644 --- a/gis/geo_sir/geo_sir/agents.py +++ b/gis/geo_sir/geo_sir/agents.py @@ -16,8 +16,7 @@ def __init__( death_risk=0.1, init_infected=0.1, ): - """ - Create a new person agent. + """Create a new person agent. :param model: Model in which the agent runs :param geometry: Shape object for the agent :param agent_type: Indicator if agent is infected @@ -38,8 +37,7 @@ def __init__( self.model.counts["susceptible"] -= 1 def move_point(self, dx, dy): - """ - Move a point by creating a new one + """Move a point by creating a new one :param dx: Distance to move in x-axis :param dy: Distance to move in y-axis """ @@ -83,8 +81,7 @@ class NeighbourhoodAgent(mg.GeoAgent): """Neighbourhood agent. Changes color according to number of infected inside it.""" def __init__(self, model, geometry, crs, agent_type="safe", hotspot_threshold=1): - """ - Create a new Neighbourhood agent. + """Create a new Neighbourhood agent. :param unique_id: Unique identifier for the agent :param model: Model in which the agent runs :param geometry: Shape object for the agent diff --git a/gis/geo_sir/geo_sir/model.py b/gis/geo_sir/geo_sir/model.py index a9c77ea0..53f58364 100644 --- a/gis/geo_sir/geo_sir/model.py +++ b/gis/geo_sir/geo_sir/model.py @@ -19,8 +19,7 @@ class GeoSir(mesa.Model): def __init__( self, pop_size=30, init_infected=0.2, exposure_distance=500, infection_risk=0.2 ): - """ - Create a new InfectedModel + """Create a new InfectedModel :param pop_size: Size of population :param init_infected: Probability of a person agent to start as infected :param exposure_distance: Proximity distance between agents @@ -63,7 +62,7 @@ def __init__( agent_kwargs={"init_infected": init_infected}, ) # Generate random location and add agent to grid - for i in range(pop_size): + for _ in range(pop_size): this_neighbourhood = self.random.randint( 0, len(neighbourhood_agents) - 1 ) # Region where agent starts diff --git a/pyproject.toml b/pyproject.toml index 589075ce..ace798cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,20 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] + packages = ["examples", "gis", "rl"] + [project] name = "mesa-models" -version = "0.1.0" description = "Importable Mesa models." +license = {file = "LICENSE"} +requires-python = ">=3.8" authors = [ - {name = "Project Mesa Team", email = "projectmesa@googlegroups.com"} + {name = "Project Mesa Team", email = "maintainers@projectmesa.dev"} ] -license = {file = "LICENSE"} +version = "0.1.0" readme = "README.md" -requires-python = ">=3.8" [project.optional-dependencies] test = [ @@ -25,16 +32,12 @@ rl_example = [ "tensorboard" ] -[build-system] -requires = [ - "setuptools", - "wheel", -] -build-backend = "setuptools.build_meta" - [tool.ruff] +extend-include = ["*.ipynb"] + +[tool.ruff.lint] # See https://github.com/charliermarsh/ruff#rules for error code definitions. -lint.select = [ +select = [ # "ANN", # annotations TODO "B", # bugbear "C4", # comprehensions @@ -58,36 +61,29 @@ lint.select = [ "UP", # upgrade "W", # style warnings "YTT", # sys.version +# "D", # docstring TODO ] # Ignore list taken from https://github.com/psf/black/blob/master/.flake8 # E203 Whitespace before ':' # E266 Too many leading '#' for block comment -# E501 Line too long (82 > 79 characters) # W503 Line break occurred before a binary operator -# But we don't specify them because ruff's Black already +# But we don't specify them because ruff's formatter # checks for it. # See https://github.com/charliermarsh/ruff/issues/1842#issuecomment-1381210185 -lint.extend-ignore = [ - "E501", - "S101", # Use of `assert` detected - "B017", # `assertRaises(Exception)` should be considered evil TODO - "PGH004", # Use specific rule codes when using `noqa` TODO - "B905", # `zip()` without an explicit `strict=` parameter - "N802", # Function name should be lowercase - "N999", # Invalid module name. We should revisit this in the future, TODO - "B007", # Loop control variable `i` not used within loop body - "N806", # Variable `N` in function should be lowercase - "N803", # Argument name `N` should be lowercase - "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` TODO - "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes TODO - "B008", # Do not perform function call `pyproj.CRS` in argument defaults TODO - "S301", # `pickle` and modules that wrap it can be unsafe when used to deserialize untrusted data, possible security issue TODO - "ISC001", # conflict with ruff format +extend-ignore = [ + "E501", + "S101", # Use of `assert` detected + "B017", # `assertRaises(Exception)` should be considered evil TODO + "PGH004", # Use specific rule codes when using `noqa` TODO + "B905", # `zip()` without an explicit `strict=` parameter + "N802", # Function name should be lowercase + "N999", # Invalid module name. We should revisit this in the future, TODO + "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` TODO + "S310", # Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. + "S603", # `subprocess` call: check for execution of untrusted input + "ISC001", # ruff format asks to disable this feature + "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes ] -# Hardcode to Python 3.8. -target-version = "py38" -extend-include = ["*.ipynb"] -[tool.isort] -profile = "black" -sections = ['FUTURE', 'STDLIB', 'THIRDPARTY', 'LOCALFOLDER'] +[tool.ruff.lint.pydocstyle] +convention = "google" \ No newline at end of file diff --git a/rl/boltzmann_money/model.py b/rl/boltzmann_money/model.py index fdee254a..a7a891ee 100644 --- a/rl/boltzmann_money/model.py +++ b/rl/boltzmann_money/model.py @@ -1,5 +1,4 @@ -""" -This code implements a multi-agent model called MoneyModel using the Mesa library. +"""This code implements a multi-agent model called MoneyModel using the Mesa library. The model simulates the distribution of wealth among agents in a grid environment. Each agent has a randomly assigned wealth and can move to neighboring cells. Agents can also give money to other agents in the same cell if they have greater wealth. @@ -141,7 +140,7 @@ def reset(self, *, seed=None, options=None): super().reset() self.grid = mesa.space.MultiGrid(self.grid.width, self.grid.height, True) self.remove_all_agents() - for i in range(self.num_agents): + for _ in range(self.num_agents): # Create MoneyAgentRL instances and add them to the schedule a = MoneyAgentRL(self) x = self.random.randrange(self.grid.width) diff --git a/rl/epstein_civil_violence/model.py b/rl/epstein_civil_violence/model.py index 78b21e30..e6d9ab2e 100644 --- a/rl/epstein_civil_violence/model.py +++ b/rl/epstein_civil_violence/model.py @@ -8,8 +8,7 @@ class EpsteinCivilViolenceRL(EpsteinCivilViolence, MultiAgentEnv): - """ - Custom environment class for the Epstein Civil Violence model with reinforcement learning. + """Custom environment class for the Epstein Civil Violence model with reinforcement learning. Inherits from EpsteinCivilViolence and MultiAgentEnv. """ @@ -27,8 +26,7 @@ def __init__( movement=True, max_iters=200, ): - """ - Initialize the EpsteinCivilViolenceRL environment. + """Initialize the EpsteinCivilViolenceRL environment. Parameters: - width: Width of the grid. @@ -43,7 +41,6 @@ def __init__( - movement: Flag indicating whether agents can move or not. - max_iters: Maximum number of iterations for the model. """ - super().__init__( width, height, @@ -70,8 +67,7 @@ def __init__( ) def step(self, action_dict): - """ - Perform a step in the environment. + """Perform a step in the environment. Parameters: - action_dict: Dictionary containing actions for each agent. @@ -135,8 +131,7 @@ def cal_reward(self): return rewards def reset(self, *, seed=None, options=None): - """ - Reset the environment after each episode. + """Reset the environment after each episode. Parameters: - seed: Seed for random number generation. @@ -146,12 +141,11 @@ def reset(self, *, seed=None, options=None): - observation: Initial observation of the environment. - info: Additional information about the reset. """ - super().reset() self.grid = mesa.space.SingleGrid(self.width, self.height, torus=True) create_intial_agents(self, CitizenRL, CopRL) grid_to_observation(self, CitizenRL) - # Intialize action dictionary with no action + # Initialize action dictionary with no action self.action_dict = {a.unique_id: (0, 0) for a in self.agents} # Update neighbors for observation space for agent in self.agents: diff --git a/rl/wolf_sheep/agents.py b/rl/wolf_sheep/agents.py index 90e8ee81..0d1eed5f 100644 --- a/rl/wolf_sheep/agents.py +++ b/rl/wolf_sheep/agents.py @@ -4,8 +4,7 @@ class SheepRL(Sheep): def step(self): - """ - The code is exactly same as mesa-example with the only difference being the move function and new sheep creation class. + """The code is exactly same as mesa-example with the only difference being the move function and new sheep creation class. Link : https://github.com/projectmesa/mesa-examples/blob/main/examples/wolf_sheep/wolf_sheep/agents.py """ action = self.model.action_dict[self.unique_id] @@ -42,8 +41,7 @@ def step(self): class WolfRL(Wolf): def step(self): - """ - The code is exactly same as mesa-example with the only difference being the move function and new wolf creation class. + """The code is exactly same as mesa-example with the only difference being the move function and new wolf creation class. Link : https://github.com/projectmesa/mesa-examples/blob/main/examples/wolf_sheep/wolf_sheep/agents.py """ action = self.model.action_dict[self.unique_id] diff --git a/rl/wolf_sheep/model.py b/rl/wolf_sheep/model.py index ec09ff59..ece04847 100644 --- a/rl/wolf_sheep/model.py +++ b/rl/wolf_sheep/model.py @@ -10,12 +10,9 @@ class WolfSheepRL(WolfSheep, MultiAgentEnv): - """ - WolfRL-Sheep Predation Model - """ - def __init__( self, + simulator: ABMSimulator | None, width=20, height=20, initial_sheep=100, @@ -27,12 +24,13 @@ def __init__( grass_regrowth_time=30, sheep_gain_from_food=4, seed=42, - simulator=ABMSimulator(), vision=4, ): - """ - Create a new WolfRL-Sheep model with the given parameters. - """ + """Create a new WolfRL-Sheep model with the given parameters.""" + # Don't create the ABMSimulator as argument default: https://docs.astral.sh/ruff/rules/function-call-in-default-argument/ + if simulator is None: + simulator = ABMSimulator() + super().__init__( width, height, @@ -74,6 +72,8 @@ def __init__( } ) + """WolfRL-Sheep Predation Model""" + def step(self, action_dict): self.action_dict = action_dict self.agents.shuffle_do("step") diff --git a/test_examples.py b/test_examples.py index 41de5eb1..1926dfff 100644 --- a/test_examples.py +++ b/test_examples.py @@ -7,7 +7,7 @@ def get_models(directory): models = [] - for root, dirs, files in os.walk(directory): + for root, _, files in os.walk(directory): for file in files: if file == "model.py": module_name = os.path.relpath(os.path.join(root, file[:-3])).replace( diff --git a/test_gis_examples.py b/test_gis_examples.py index 39015ecd..2b127b87 100644 --- a/test_gis_examples.py +++ b/test_gis_examples.py @@ -7,7 +7,7 @@ def get_models(directory): models = [] - for root, dirs, files in os.walk(directory): + for root, _, files in os.walk(directory): for file in files: if file == "model.py": module_name = os.path.relpath(os.path.join(root, file[:-3])).replace(