Sequences

The sequences module defines AMBER’s vectorized view API. The full population lives at model.agents; filtered and scatter views are produced by where / indexing / at[...]. All three view types share the same attribute/assignment protocol — column reads return Polars Series sourced from model.agents_df on CPU, and column writes go through Model._set_frame (contract-observed when enabled).

Under model.gpu().run() (0.4.4), numeric columns are device-resident for the vectorized step body; the same where / column assign / scatter_add idiom applies. Host Polars is synced at step boundaries when the contract or reporters need a CPU snapshot. agents.array(...) is flagged as uncertified_mutable_borrow when the contract is on.

Canonical operations on a view:

  • Readview.col, view.numpy('x', 'y'), view.frame / view.ids

  • Writeview.col = values, view.set(x=…, y=…) (atomic multi-column)

  • Reduceview.scatter_add(col=delta) (duplicate ids sum)

  • Tensorview.borrow(col) / view.commit(**cols)

Prefer these over Model.update_agent_data / batch_update_agents and Population.set_agent_value / batch_update* (deprecated aliases).

AgentList

class ambr.AgentList(model: Model, agents_or_n: List[Agent] | int = None, agent_type: Type[Agent] | None = None)[source]

Bases: _BaseView

Full view over a model’s population. Lives at model.agents.

__getitem__(idx)[source]

Index by position (int/slice), id list, boolean mask, or pl.Expr.

property agent_ids

Deprecated alias for ids.

property agents: List[Agent]

iterate model.agents directly, or use by_id / ids.

Type:

Deprecated

append(agent: Agent) None[source]
borrow(column: str)[source]

Zero-copy, read-only borrow of a numeric column for tensor kernels.

Returns (array, is_view); pair with commit(). See ambr.tensor_lane for the snapshot-view contract on borrow/commit.

by_id(agent_id) Agent[source]

Return the tracked Agent object with this id (the per-agent / OOP lane).

Lets per-agent code reach another agent without a hand-rolled id->object dict (add_agents(n, agent_class=...) tracks the objects for you).

clear() None[source]
commit(**columns: Any) None[source]

Atomically write back derived columns (the tensor-lane commit path).

agents.commit(x=nx, y=ny). Routes through commit_columns so the snapshot-view contract observes the writes.

copy() AgentList[source]
count(agent: Agent) int[source]
extend(agents: List[Agent]) None[source]
property frame: DataFrame

Read-only snapshot of the full agent table (alias for model.agents_df).

get_data() DataFrame[source]
group_by(by: str) Dict[Any, FilteredAgentList][source]
index(agent: Agent) int[source]
insert(idx: int, agent: Agent) None[source]
pop(idx: int = -1) Agent[source]
remove(agent: Agent) None[source]
reverse() None[source]
sort(key=None, reverse: bool = False) None[source]

The full population view. Lives at model.agents and acts as both the entry point for vectorized queries and a legacy list of Agent objects.

Vectorized usage (preferred):

# Filter by predicate and update columnar state
rich = model.agents.where(model.agents.wealth > 100)
rich.tag = 'rich'

# Scatter-add deltas for random id draws (duplicates sum correctly)
recipients = model.rng.choice(model.agents.ids.to_numpy(), size=50)
model.agents.at[recipients].scatter_add(wealth=1)

Legacy list usage (still supported):

# Indexing, iteration, append/remove — works as before
first = model.agents[0]
for agent in model.agents:
    agent.step()
model.agents.append(new_agent)

FilteredAgentList

class ambr.sequences.FilteredAgentList(model: Model, ids: Series, parent: AgentList)[source]

Bases: _SubView

Subset view produced by agents.where(...) / agents[mask].

Returned from model.agents.where(...) or model.agents[mask]. Operates on the subset of rows matching a predicate. Writing to a column on this view touches only the filtered agents.

ScatterAgentList

class ambr.sequences.ScatterAgentList(model: Model, ids: Series, parent: AgentList)[source]

Bases: _SubView

Id-indexed view produced by agents.at[ids] (ids may repeat).

Returned from model.agents.at[ids]. Unlike a filtered view, a scatter view can contain duplicate ids — which is the whole point for “random recipient” style updates. Use scatter_add to accumulate deltas when ids repeat; plain assignment falls back to last-write-wins semantics.

Features

  • DataFrame-backed attribute reads and writes — no sync gotchas.

  • Predicate filtering via where(...) with attribute predicates or raw Polars expressions.

  • Scatter-add for flow-of-resources updates.

  • Full back-compat with legacy list-style access (indexing, iteration, append/remove, call/apply).