Skip to content

Actor (Agent)

abses.agents.actor.Actor

Actor(model, observer=True, **kwargs)

Bases: GeoAgent, _LinkNodeActor, BaseModelElement, ActorProtocol

Base actor class for agent-based models in ABSESpy.

An Actor represents an autonomous agent in a social-ecological system. It combines geospatial capabilities (from mesa-geo), network functionality (links), and ABSESpy-specific features like perception and movement. Actors can be located on spatial cells, form networks with other actors, and interact with their environment through perceptions and actions.

Actors maintain their own state including position, alive status, age, and custom attributes. They can move between cells, perceive their environment, form links with other actors, and execute custom behaviors through overridable methods.

The Actor class serves as a base class for creating custom agent types. Users should inherit from Actor and override methods like setup() and initialize() to define agent-specific behaviors.

Attributes:

Name Type Description
breed

The breed (type) of this actor, defaults to class name.

layer Optional[PatchModule]

The spatial layer where the actor is located.

indices Optional[Pos]

The grid indices of the cell where the actor is located.

pos Optional[Pos]

The position of the cell where the actor is located.

on_earth bool

Whether the actor is positioned on a spatial cell.

at PatchCell | None

The specific cell where the actor is located.

link _LinkProxy

Proxy for managing network links with other actors.

move _Movements

Proxy for manipulating actor's spatial location.

geometry Optional[BaseGeometry]

The shapely geometry representing the actor's spatial form.

alive bool

Whether the actor is alive (not removed from the model).

unique_id UniqueID

Unique identifier automatically assigned by Mesa.

crs CRS

Coordinate reference system for the actor's geometry.

Example
class Farmer(Actor):
    def setup(self):
        self.wealth = 100

    def initialize(self):
        # Called at the start of simulation
        self.plant_crops()

Parameters:

Name Type Description Default
model MainModel

The ABSESpy model this actor belongs to.

required
observer bool

Whether this actor should be observed in data collection. Defaults to True.

True
**kwargs

Additional keyword arguments: - crs: Coordinate reference system. Defaults to model's CRS. - geometry: Shapely geometry for the actor. Defaults to None.

{}
Source code in abses/agents/actor.py
def __init__(self, model: MainModel, observer: bool = True, **kwargs) -> None:
    """Initialize an actor instance.

    Parameters:
        model: The ABSESpy model this actor belongs to.
        observer: Whether this actor should be observed in data collection.
            Defaults to True.
        **kwargs: Additional keyword arguments:
            - crs: Coordinate reference system. Defaults to model's CRS.
            - geometry: Shapely geometry for the actor. Defaults to None.
    """
    BaseModelElement.__init__(self, model)
    crs = kwargs.pop("crs", model.nature.crs)
    geometry = kwargs.pop("geometry", None)
    mg.GeoAgent.__init__(self, model=model, geometry=geometry, crs=crs)
    _LinkNodeActor.__init__(self)
    self._cell: Optional[PatchCell] = None
    self._alive: bool = True
    self._birth_tick: int = self.time.tick
    self._setup()

geo_type property

geo_type

The type of the geo info.

geometry property writable

geometry

The shapely geometry of the actor.

If the actor is located on a cell, returns a Point at the cell's coordinate. Otherwise, returns the actor's custom geometry if one was assigned.

alive property

alive

Whether the actor is alive.

layer property

layer

Get the layer where the actor is located.

on_earth property

on_earth

Whether agent stands on a cell.

at deletable property writable

at

Get the cell where the agent is located.

pos property writable

pos

Position of the actor.

indices property

indices

Indices of the actor.

move cached property

move

A proxy for manipulating actor's location.

  1. move.to(): moves the actor to another cell.
  2. move.off(): removes the actor from the current layer.
  3. move.by(): moves the actor by a distance.
  4. move.random(): moves the actor to a random cell.

age

age()

Get the age of the actor in simulation ticks.

Returns:

Type Description
int

The number of ticks since the actor was born (created).

Source code in abses/agents/actor.py
@alive_required
def age(self) -> int:
    """Get the age of the actor in simulation ticks.

    Returns:
        The number of ticks since the actor was born (created).
    """
    return self.time.tick - self._birth_tick

get

get(attr, target=None, default=...)

Gets attribute value from target.

Parameters:

Name Type Description Default
attr str

The name of the attribute to get.

required
target Optional[TargetName]

The target to get the attribute from. If None, the agent itself is the target. If the target is an agent, get the attribute from the agent. If the target is a cell, get the attribute from the cell.

None
default Any

Default value if attribute not found.

...

Returns:

Type Description
Any

The value of the attribute.

Source code in abses/agents/actor.py
@alive_required
def get(
    self, attr: str, target: Optional[TargetName] = None, default: Any = ...
) -> Any:
    """
    Gets attribute value from target.

    Args:
        attr: The name of the attribute to get.
        target: The target to get the attribute from.
            If None, the agent itself is the target.
            If the target is an agent, get the attribute from the agent.
            If the target is a cell, get the attribute from the cell.
        default: Default value if attribute not found.

    Returns:
        The value of the attribute.
    """
    # if attr in self.dynamic_variables:
    #     return self.dynamic_var(attr)
    return super().get(attr=attr, target=target, default=default)

set

set(*args, **kwargs)

Sets the value of an attribute.

Parameters:

Name Type Description Default
attr

The name of the attribute to set.

required
value

The value to set the attribute to.

required
target

The target to set the attribute on. If None, the agent itself is the target. 1. If the target is an agent, set the attribute on the agent. 2. If the target is a cell, set the attribute on the cell.

required

Raises:

Type Description
TypeError

If the attribute is not a string.

ABSESpyError

If the attribute is protected.

Source code in abses/agents/actor.py
@alive_required
def set(self, *args, **kwargs) -> None:
    """
    Sets the value of an attribute.

    Args:
        attr: The name of the attribute to set.
        value: The value to set the attribute to.
        target: The target to set the attribute on. If None, the agent itself is the target.
            1. If the target is an agent, set the attribute on the agent.
            2. If the target is a cell, set the attribute on the cell.

    Raises:
        TypeError: If the attribute is not a string.
        ABSESpyError: If the attribute is protected.
    """
    super().set(*args, **kwargs)

remove

remove()

Remove the actor from the model.

This is an alias for the die() method, providing a more generic interface for removing actors from the simulation.

Source code in abses/agents/actor.py
def remove(self) -> None:
    """Remove the actor from the model.

    This is an alias for the `die()` method, providing a more generic interface
    for removing actors from the simulation.
    """
    self.die()

move_to

move_to(to='random', layer=None)

Move actor to a location (wrapper for move.to).

This method allows shuffle_do to be used with move operations.

Parameters:

Name Type Description Default
to Any

Position to move to. Can be a PatchCell, Coordinate tuple, or "random".

'random'
layer Any

Layer to move to. If None, uses actor's current layer if available.

None
Source code in abses/agents/actor.py
def move_to(self, to: Any = "random", layer: Any = None) -> None:
    """Move actor to a location (wrapper for move.to).

    This method allows shuffle_do to be used with move operations.

    Args:
        to: Position to move to. Can be a PatchCell, Coordinate tuple, or "random".
        layer: Layer to move to. If None, uses actor's current layer if available.
    """
    self.move.to(to=to, layer=layer)

die

die()

Kill the actor and remove it from the simulation.

This method performs a complete cleanup of the actor by: 1. Removing all network links with other actors 2. Removing the actor from its spatial cell (if positioned) 3. Removing the actor from the model's agent registry 4. Setting the actor's alive status to False

After calling this method, the actor should no longer be used.

Source code in abses/agents/actor.py
@alive_required
def die(self) -> None:
    """Kill the actor and remove it from the simulation.

    This method performs a complete cleanup of the actor by:
    1. Removing all network links with other actors
    2. Removing the actor from its spatial cell (if positioned)
    3. Removing the actor from the model's agent registry
    4. Setting the actor's alive status to False

    After calling this method, the actor should no longer be used.
    """
    self.link.clean()  # 从链接中移除
    if self.on_earth:  # 如果在地上,那么从地块上移除
        self.move.off()
    super().remove()  # 从总模型里移除
    self._alive = False  # 设置为死亡状态
    del self

setup

setup()

Setup method called when the actor is initialized.

Override this method to define actor-specific initialization behavior. This method is called automatically when the actor is created, before the simulation starts. Use it to set initial attributes and state.

Example
class Farmer(Actor):
    def setup(self):
        self.wealth = 100
        self.crops = []
Source code in abses/agents/actor.py
def setup(self) -> None:
    """Setup method called when the actor is initialized.

    Override this method to define actor-specific initialization behavior.
    This method is called automatically when the actor is created, before
    the simulation starts. Use it to set initial attributes and state.

    Example:
        ```python
        class Farmer(Actor):
            def setup(self):
                self.wealth = 100
                self.crops = []
        ```
    """

moving

moving(cell)

Callback called before the actor moves to a new cell.

Override this method to implement movement validation logic. Return False to prevent the move, True to allow it, or None to use default behavior (allow the move).

Parameters:

Name Type Description Default
cell PatchCell

The target cell the actor is attempting to move to.

required

Returns:

Type Description
Optional[bool]
  • True: explicitly allow the move
Optional[bool]
  • False: prevent the move
Optional[bool]
  • None: use default behavior (allow the move)
Example
class Farmer(Actor):
    def moving(self, cell):
        # Only allow moving to farmland cells
        return cell.is_farmland
Source code in abses/agents/actor.py
def moving(self, cell: PatchCell) -> Optional[bool]:
    """Callback called before the actor moves to a new cell.

    Override this method to implement movement validation logic. Return False
    to prevent the move, True to allow it, or None to use default behavior
    (allow the move).

    Parameters:
        cell: The target cell the actor is attempting to move to.

    Returns:
        - True: explicitly allow the move
        - False: prevent the move
        - None: use default behavior (allow the move)

    Example:
        ```python
        class Farmer(Actor):
            def moving(self, cell):
                # Only allow moving to farmland cells
                return cell.is_farmland
        ```
    """

initialize

initialize()

Initialize the actor at the start of simulation.

Override this method to define behavior that should occur when the simulation begins (at tick 0), as opposed to when the actor is created. This is useful for setting up initial conditions that depend on the complete model state.

Example
class Farmer(Actor):
    def initialize(self):
        # Find and establish initial links
        self.find_neighbors()
Source code in abses/agents/actor.py
def initialize(self) -> None:
    """Initialize the actor at the start of simulation.

    Override this method to define behavior that should occur when the
    simulation begins (at tick 0), as opposed to when the actor is created.
    This is useful for setting up initial conditions that depend on the
    complete model state.

    Example:
        ```python
        class Farmer(Actor):
            def initialize(self):
                # Find and establish initial links
                self.find_neighbors()
        ```
    """
    ...

evaluate

evaluate(
    candidates,
    scorer,
    *,
    dtype=float,
    how=None,
    preserve_position=False,
    preserve_attrs=None
)

Evaluate a scorer across candidates and optionally choose the best.

Workflow: 1) Normalize candidates to a sequence (ActorsList stays as-is) 2) For each candidate: score with optional rollback of position/attrs 3) Return scores (ndarray) or the best candidate per 'how' ('max'/'min')

Source code in abses/agents/actor.py
def evaluate(
    self,
    candidates: Any,
    scorer: Callable[["Actor", Any], Any],
    *,
    dtype: Any | None = float,
    how: Optional[str] = None,
    preserve_position: bool = False,
    preserve_attrs: Optional[Sequence[str]] = None,
) -> Any:
    """Evaluate a scorer across candidates and optionally choose the best.

    Workflow:
    1) Normalize candidates to a sequence (ActorsList stays as-is)
    2) For each candidate: score with optional rollback of position/attrs
    3) Return scores (ndarray) or the best candidate per 'how' ('max'/'min')
    """
    from abses.agents.sequences import ActorsList  # local import

    # 1) Normalize candidates to a single representation
    is_actors_list = isinstance(candidates, ActorsList)
    seq = (
        candidates
        if is_actors_list
        else (
            list(candidates)
            if not isinstance(candidates, np.ndarray)
            else candidates
        )
    )

    # 2) Define scoring with rollback
    def _score_with_rollback(candidate: Any) -> Any:
        original_cell = self.at if preserve_position else None
        original_attrs: dict[str, Any] = {}
        if preserve_attrs:
            for attr in preserve_attrs:
                original_attrs[attr] = getattr(self, attr)
        try:
            return scorer(self, candidate)
        finally:
            # restore attributes
            for attr, val in original_attrs.items():
                setattr(self, attr, val)
            # restore position
            if (
                preserve_position
                and original_cell is not None
                and self.at is not original_cell
            ):
                self.move.to(original_cell)

    # 3) Compute scores via a single code path
    if is_actors_list:
        scores = np.asarray(
            seq.apply(lambda c: _score_with_rollback(c)), dtype=dtype
        )
    else:
        scores = np.asarray([_score_with_rollback(c) for c in seq], dtype=dtype)

    if how is None:
        return scores
    if len(scores) == 0:
        return None
    idx = int(np.argmax(scores)) if how == "max" else int(np.argmin(scores))
    return seq[idx] if not is_actors_list else seq[idx]