Skip to content

Commit

Permalink
Merge pull request #117 from mariuzka/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
mariuzka authored Oct 30, 2024
2 parents 211c78f + 38a0659 commit 60481df
Show file tree
Hide file tree
Showing 24 changed files with 799 additions and 147 deletions.
1 change: 0 additions & 1 deletion docs/Introduction/introduction_creator.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,6 @@
" overcrowding: bool | None = None\n",
" only_exact_n_agents: bool = False\n",
" n_locations: int | None = None\n",
" static_weight: bool = False\n",
" recycle: bool = True\n",
"\n",
" def filter(self, agent: p2n.Agent) -> bool:\n",
Expand Down
63 changes: 32 additions & 31 deletions docs/Introduction/introduction_simulations.ipynb

Large diffs are not rendered by default.

44 changes: 35 additions & 9 deletions src/pop2net/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,26 @@ def shared_locations(self, agent, location_classes: list | None = None):
location_classes=location_classes,
)

def add_location(self, location: _location.Location) -> None:
def add_location(self, location: _location.Location, weight: float | None = None) -> None:
"""Add this Agent to a given location.
Args:
location: Add agent to this location.
weight (float | None): The edge weight between the agent and the location.
Defaults to None.
"""
self.model.add_agent_to_location(self, location)
self.model.add_agent_to_location(agent=self, location=location, weight=weight)

def add_locations(self, locations: list) -> None:
def add_locations(self, locations: list, weight: float | None = None) -> None:
"""Add this agent to multiple locations.
Args:
locations (list): Add the agent to these locations.
weight (float | None): The edge weight between the agent and the location.
Defaults to None.
"""
for location in locations:
self.add_location(location)
self.add_location(location=location, weight=weight)

def remove_location(self, location: _location.Location) -> None:
"""Remove this Agent from a given location.
Expand All @@ -86,6 +95,11 @@ def remove_location(self, location: _location.Location) -> None:
self.model.remove_agent_from_location(self, location)

def remove_locations(self, locations: list) -> None:
"""Remove this Agent from the given locations.
Args:
locations (list): A list of location instances.
"""
for location in locations:
self.remove_location(location)

Expand All @@ -99,12 +113,14 @@ def locations(self) -> _sequences.LocationList:
return self.model.locations_of_agent(self)

def get_agent_weight(self, agent: Agent, location_classes: list | None = None) -> float:
"""Return the contact weight between this agent and a given other agent.
"""Return the edge weight between this agent and a given other agent.
This is summed over all shared locations.
Args:
agent_v: The other agent.
agent: The other agent.
location_classes (list): A list of location classes to specify the type of locations
which are considered.
Returns:
A weight of the contact between the two agents.
Expand All @@ -115,16 +131,26 @@ def get_agent_weight(self, agent: Agent, location_classes: list | None = None) -
return weight

def get_location_weight(self, location) -> float:
"""Return the edge weight between this agent and a given location.
Args:
location (_type_): A location.
Returns:
float: The edge weight.
"""
return self.model.get_weight(agent=self, location=location)

def connect(self, agent: Agent, location_cls: type):
def connect(self, agent: Agent, location_cls: type, weight: float | None = None):
"""Connects this agent with a given other agent via an instance of a given location class.
Args:
agents (list): An agent to connect with.
agent (list): An agent to connect with.
location_cls (type): The location class that is used to create a location instance.
weight(float | None): The edge weight between the agents and the location.
Defaults to None.
"""
self.model.connect_agents(agents=[self, agent], location_cls=location_cls)
self.model.connect_agents(agents=[self, agent], location_cls=location_cls, weight=weight)

def disconnect(
self,
Expand Down
56 changes: 55 additions & 1 deletion src/pop2net/creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,36 +453,59 @@ def create_locations(
location_classes: list,
agents: list | p2n.AgentList | None = None,
clear: bool = False,
# TODO: delete_magic_location_attributes: bool = True,
delete_magic_agent_attributes: bool = True,
) -> p2n.LocationList:
"""Creates location instances and connects them with the given agent population.
Args:
location_classes (list): A list of location classes.
agents (list | p2n.AgentList): A list of agents.
clear (bool): Should the locations already included in the model be removed?
delete_magic_location_attributes (bool): If True, all magic location attributes will be
removed after the creation of the location instances.
delete_magic_agent_attribtues (book): If True, all magic agent attributes will be
removed after the creation of the location instances.
Returns:
p2n.LocationList: A list of locations.
"""
if clear:
# Remove all locations
self.model.remove_locations(self.model.locations)

if agents is None:
# Use the existing agents in the model if no agents are given
agents = self.model.agents

# self._dummy_model = p2n.Model()
# Create a list containing the names of all special location attributes
# to delete those attributes later
magic_agent_attributes = []

# Add the agents to the dummy model
self._dummy_model.add_agents(agents)

for location_cls in location_classes:
dummy_location = self._create_dummy_location(location_cls)
str_location_cls = dummy_location.type
for agent in agents:
setattr(agent, str_location_cls, None)
magic_agent_attributes.append(str_location_cls)

setattr(agent, str_location_cls + "_assigned", False)
magic_agent_attributes.append(str_location_cls + "_assigned")

setattr(agent, str_location_cls + "_id", None)
magic_agent_attributes.append(str_location_cls + "_id")

setattr(agent, str_location_cls + "_position", None)
magic_agent_attributes.append(str_location_cls + "_position")

setattr(agent, str_location_cls + "_head", None)
magic_agent_attributes.append(str_location_cls + "_head")

setattr(agent, str_location_cls + "_tail", None)
magic_agent_attributes.append(str_location_cls + "_tail")

locations = []

Expand Down Expand Up @@ -730,6 +753,31 @@ def melt(self):
if hasattr(agent, attr):
delattr(agent, attr)

# delete magic location attributes
magic_location_attributes = [
"filter",
"setup",
"bridge",
"split",
"weight",
"stick_together",
"nest",
"melt",
"refine",
]
# TODO: delete magic location attributes
if False: # delete_magic_location_attributes:
for cls in location_classes:
del cls.stick_together
del cls.setup

magic_agent_attributes = set(magic_agent_attributes)
if delete_magic_agent_attributes:
for attr in magic_agent_attributes:
for agent in agents:
# if hasattr(agent, attr):
delattr(agent, attr)

return locations

def create(
Expand All @@ -744,6 +792,7 @@ def create(
sample_weight: str | None = None,
replace_sample_level_column: bool = True,
clear: bool = False,
delete_magic_agent_attributes: bool = True,
) -> tuple:
"""Creates agents and locations based on a given dataset.
Expand All @@ -770,6 +819,10 @@ def create(
replace_sample_level_column (bool): Should the original values of the sample level be
overwritten by unique values after sampling to avoid duplicates?
clear (bool): Should the agents and locations already included in the model be removed?
delete_magic_location_attributes (bool): If True, all magic location attributes will be
removed after the creation of the location instances.
delete_magic_agent_attributes (bool): If True, all magic agent attributes will be
removed after the creation of the location instances.
Returns:
tuple: A list of agents and a list of locations.
Expand Down Expand Up @@ -797,6 +850,7 @@ def create(
agents=agents,
location_classes=location_classes,
clear=clear,
delete_magic_agent_attributes=delete_magic_agent_attributes,
)

return agents, locations
Expand Down
64 changes: 30 additions & 34 deletions src/pop2net/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,29 @@ def agents(self) -> AgentList:
"""
return self.model.agents_of_location(self)

def add_agent(self, agent: _agent.Agent) -> None:
def add_agent(self, agent: _agent.Agent, weight: float | None = None) -> None:
"""Assigns the given agent to this location.
Args:
agent: The agent that should be added to the location.
weight: The edge weight between the agent and the location.
Defaults to None. If weight is set to None, the weight is generated by
location.weight(), which returns 1 by default.
"""
self.model.add_agent_to_location(self, agent)
self.model.add_agent_to_location(self, agent=agent, weight=weight)

def add_agents(self, agents: list) -> None:
def add_agents(self, agents: list, weight: float | None = None) -> None:
"""Add multiple agents at once.
Args:
agents (list): An iterable over agents.
weight(float | None): The edge weight between the agents and the location.
Defaults to None. If weight is set to None, the weight is generated by
location.weight(), which returns 1 by default.
"""
for agent in agents:
self.add_agent(agent)
self.add_agent(agent=agent, weight=weight)

def remove_agent(self, agent: _agent.Agent) -> None:
"""Removes the given agent from this location.
Expand Down Expand Up @@ -84,14 +91,20 @@ def neighbors(self, agent: _agent.Agent) -> AgentList:
agents.remove(agent)
return agents

def set_weight(self, agent, weight) -> None:
def set_weight(self, agent, weight: float | None = None) -> None:
"""Set the weight of an agent at the current location.
If weight is None the method location.weight() will be used to generate a weight.
Args:
agent (Agent): The agent.
weight (float): The weight.
"""
self.model.set_weight(agent=agent, location=self, weight=weight)
self.model.set_weight(
agent=agent,
location=self,
weight=weight,
)

def get_weight(self, agent: _agent.Agent) -> float:
"""Return the edge weight between an agent and the location.
Expand All @@ -104,6 +117,17 @@ def get_weight(self, agent: _agent.Agent) -> float:
"""
return self.model.get_weight(agent=agent, location=self)

def weight(self, agent) -> float: # noqa: ARG002
"""Generates the edge weight between a given agent and the location instance.
Args:
agent (_type_): An agent.
Returns:
float: The weight between the given agent and the location.
"""
return 1

def project_weights(self, agent1: _agent.Agent, agent2: _agent.Agent) -> float:
"""Calculates the edge weight between two agents assigned to the same location instance.
Expand Down Expand Up @@ -194,21 +218,6 @@ def split(self, agent: _agent.Agent) -> float | str | list | None: # noqa: ARG0
"""
return None

def weight(self, agent: _agent.Agent) -> float | None: # noqa: ARG002
"""Defines the edge weight between the agent and the location instance.
Defines how the edge weight between an agent and the location is determined.
This is a boilerplate implementation of this method which always returns 1; i.e. all
edge weights will be 1. Override this method in your own implementations as you seem fit.
Args:
agent: The agent that is currently processed by the Creator.
Returns:
The edge weight.
"""
return None

def stick_together(self, agent: _agent.Agent) -> float | str:
"""Assigns agents with a shared value on an attribute to the same location instance.
Expand Down Expand Up @@ -246,19 +255,6 @@ def refine(self):
"""An action that is performed after all location instances have been created."""
pass

def _update_weight(self, agent: _agent.Agent) -> None:
"""Create or update the agent-speific weight.
Args:
agent: The agent to be updated.
"""
self.set_weight(agent, self.weight(agent))

def _update_weights(self) -> None:
"""Update the weight of every agent on this location."""
for agent_ in self.agents:
self._update_weight(agent_)

def _subsplit(self, agent: _agent.Agent) -> str | float | list | None: # noqa: ARG002
"""Splits a location instance into sub-instances to create a certain network structure.
Expand Down
Loading

0 comments on commit 60481df

Please sign in to comment.