Source code for swarmsim.Interactions.interaction
from abc import ABC, abstractmethod
from swarmsim.Populations import Population
import numpy as np
import pandas as pd
from typing import Optional
from swarmsim.Utils import get_parameters, load_config
[docs]
class Interaction(ABC):
"""
Abstract base class for modeling interactions between agent populations.
This class provides the framework for implementing various types of inter-agent
interactions such as repulsion, attraction, alignment, and collision avoidance.
It defines how one population (source) influences another population (target)
through force computations.
Parameters
----------
target_population : Population
The population that receives the interaction forces.
source_population : Population
The population that generates the interaction forces.
config_path : str
Path to the YAML configuration file containing interaction parameters.
name : str, optional
Name identifier for the interaction. If None, defaults to the class name.
Attributes
----------
target_population : Population
The population affected by the interaction forces.
source_population : Population
The population generating the interaction forces.
config : dict
Configuration parameters specific to this interaction type.
param_config : dict
Parameter configuration for interaction-specific parameters.
id : str
Identifier for this interaction instance.
params : dict of np.ndarray or None
Dictionary containing interaction-specific parameters.
params_shapes : dict of tuple or None
Dictionary defining expected shapes for interaction parameters.
Config Requirements
-------------------
The YAML configuration file should contain parameters under the interaction's section:
id : str, optional
Identifier for the interaction. Defaults to the class name.
parameters : dict, optional
Configuration for interaction-specific parameters.
Notes
-----
- Subclasses must implement the abstract method `get_interaction()`.
- Interactions are computed at each simulation timestep.
Examples
--------
Example YAML configuration for an interaction:
.. code-block:: yaml
HarmonicRepulsion:
id: "repulsion_interaction"
parameters:
params_mode: "Random"
params_names: ["strength", "range"]
params_limits:
strength: [1.0, 5.0]
range: [0.5, 2.0]
Example of implementing a custom interaction:
.. code-block:: python
class CustomInteraction(Interaction):
def get_interaction(self):
# Compute interaction forces here
return forces
"""
def __init__(self,
target_population: Population,
source_population: Population,
config_path: str,
name: str = None) -> None:
"""
Initialize the Interaction with target and source populations.
Parameters
----------
target_population : Population
The population that will be affected by the interaction forces.
source_population : Population
The population that will generate the interaction forces.
config_path : str
Path to the YAML configuration file containing interaction parameters.
name : str, optional
Name identifier for the interaction. If None, defaults to the class name.
Raises
------
FileNotFoundError
If the configuration file cannot be found.
"""
super().__init__()
self.target_population: Population = target_population # The affected population
self.source_population: Population = source_population # The interacting population
config_file = load_config(config_path)
# Retrieve configuration for the specific population class
if name is None:
name = type(self).__name__
self.config: dict = config_file.get(name)
self.param_config: dict = self.config.get("parameters")
self.id: str = self.config.get("id", name) # Population ID
# Initialize params, state and inputs
self.params: Optional[dict[str, np.ndarray]] = None
self.params_shapes: Optional[dict[str, tuple]] = None
# self.reset()
[docs]
def reset(self) -> None:
"""
Reset the interaction parameters to their initial values.
This method reinitializes interaction-specific parameters based on the
configuration. It should be called before starting a new simulation.
"""
if self.param_config is not None:
self.params = get_parameters(self.param_config, self.params_shapes, self.target_population.N)
[docs]
@abstractmethod
def get_interaction(self) -> np.ndarray:
"""
Compute the interaction forces between source and target populations.
This abstract method must be implemented by subclasses to define the specific
interaction. It calculates the forces that the source population exerts
on the target population based on their current states and interaction parameters.
Returns
-------
np.ndarray
Array of shape (N_target, state_dim) representing the interaction forces
applied to each agent in the target population, where N_target is the number
of agents in the target population and state_dim is the spatial dimension.
Notes
-----
The returned forces will be added to the target population's force accumulator
and integrated by the numerical integrator.
Raises
------
NotImplementedError
If called directly from the base class without implementation.
"""
pass