Model
Core simulation model: population store, write flush, and run loop.
Write architecture (single source of truth = Polars agents_df)
OOP path —
Agent.__setattr__queues into_pending_writes;_flush_pending_writes()applies them (usesambr._id_index).Vectorized path — view API in
ambr.sequencescalls_set_frame()directly (scatter / set / column assign).Tensor path —
ambr.tensor_laneborrow/commit also uses_set_frame().
Id-position caches (_id_pos_cache, _ids_arange_cache) are owned here
but filled by ambr._id_index; _bump_id_version() invalidates them.
- class ambr.model.Model(parameters: Dict[str, Any])[source]
Bases:
BaseModelBase class for all simulation models (Polars-backed agent table).
- add_agent(agent: Agent)[source]
Add a single agent. Prefer
add_agents()for bulk creation.
- add_agents(n: int, *, agent_class: Type | None = None, **columns: Any)[source]
Bulk-create
nagents with columnar initial state:self.add_agents(100, wealth=self.rng.integers(1, 10, 100), status='S')
Scalar kwargs broadcast; list /
np.ndarray/pl.Seriesvalues must have lengthn. Passagent_class=to also spin up Python instances soAgentList.calland per-agent iteration work.
- agent_reporters: List[str] | None = None
Declarative per-agent columns to snapshot each step into the (opt-in)
'agent_vars'long-format results frame. Empty /None= no cost. Override on the subclass; do not mutate the base attribute.
- property agents_df: DataFrame
- approve_fast_path(evidence: str) Model[source]
Allow this instance to use a private optimized GPU loop.
evidencemust be a non-empty provenance label chosen by the caller (for example, a test report or experiment identifier). AMBER records only the explicit declaration; it does not validate the evidence. Without approval,run()uses the general native runner even when private_setup_gpu_fast/_run_gpu_fasthooks are present.
- batch_update_agents(agent_ids: list, data: dict)[source]
Deprecated: use
agents.at[ids].set(**data)(or column assign).Still equivalent to
self.agents.at[agent_ids].set(**data)so multi-column updates stay atomic and contract-observed.
- property contract_certificates: List[ContractCertificate]
- cpu(mode: str | None = None) Model[source]
Place the next
run()on CPU. Returnsselffor chaining.- Parameters:
mode – optional execution style —
'vectorized'(view API, default when omitted on the model) or'oop'(per-agent objects). Same asmodel.cpu().run(mode=...)when passed here.
Examples:
model.cpu().run() model.cpu(mode="vectorized").run() model.cpu(mode="oop").run()
- get_agent_data(agent_id: Any) DataFrame[source]
Return a 1-row DataFrame with the current state of
agent_id.Uses
agents_dfso pending buffered writes are flushed first.
- gpu(mode: str | None = None) Model[source]
Place the next
run()on GPU (device-resident columns). Returnsself.- Parameters:
mode – optional execution style. GPU runs support the
'vectorized'view API; Python Agent objects use CPU OOP mode.
Examples:
model.gpu().run() model.gpu(mode="vectorized").run()
- model_reporters: Dict[str, Any] | None = None
Declarative model-level metrics, evaluated once per step into the
'model'results frame. Maps a column name to acallable(model), the name of a model attribute/method, or a constant. Override on the subclass (do not mutate this class attribute – default isNoneto avoid shared mutable state). Complements imperativerecord_model.
- params: Dict[str, Any] | None = None
Optional typed parameter schema
{'name': (type, default)}. When set on the subclass,self.p.nameis pre-coerced totypeat init (missing -> default). DefaultNoneavoids shared mutable state.
- record(key: str, value: Any)[source]
Deprecated AgentPy alias for
record_model()/model_reporters.
- revoke_fast_path_approval() Model[source]
Remove this instance’s private-fast-path deployment approval.
- property rng
Step RNG — device RNG during
gpu()runs, NumPy otherwise.
- run(steps: int | None = None, contract: str = 'off', mode: str | None = None, device: str | None = None, backend: str | None = None) RunResults[source]
Run the simulation.
Returns a
RunResultsmapping (dict subclass). Useresults['agents']orresults.agentsinterchangeably.Device placement is Keras-style: call
cpu()orgpu()on the model (or passdevice=/ legacybackend=here). Mode can be set on those fluent methods (model.cpu(mode="vectorized")) or here viamode=. On CPU,mode='vectorized'(default) dispatchesstep_vectorized();mode='oop'dispatchesstep_oop()and expects tracked per-agent objects. Models that only implementstep()retain backwards-compatible fallback behavior.- Parameters:
steps – number of steps to run (defaults to
self.p['steps']or 100).contract – snapshot-view conformance checking mode. One of
'off'(default, zero overhead),'check'(record a per-stepContractCertificateinself.contract_certificatesand the'contract'results key),'warn'(also emit a warning per violation), or'raise'(raiseContractViolationErroron the first step with an error-severity violation).mode –
'vectorized'(default) or'oop'. Overridescpu()/gpu()mode=andparameters['mode'].device –
'cpu'or'gpu'. Overridescpu()/gpu(). Legacy alias:backend=.
- run_step() None[source]
Execute one simulation step. The first call also runs
setup.When a contract mode other than
'off'is active (set viarun()), the step body is bracketed by the snapshot-view conformance checker and aContractCertificateis appended toself.contract_certificates.
- step_oop()[source]
Execute one object-oriented step.
Models with tracked
Agentobjects can override this hook. The default preserves backwards compatibility for models that have only a singlestep()implementation.
- step_vectorized()[source]
Execute one vectorized step.
Models with a distinct vectorized implementation can override this hook. The default preserves the pre-mode API, where
step()is the model’s single implementation.
- update()[source]
Per-step hook, called after
step()withtalready advanced.Override to record model metrics imperatively (
self.record_model(...)) or for any post-step bookkeeping. This is a pure hook: overriding it no longer requiressuper().update()– the step counter and step-data lifecycle are owned byrun_step(). Callingsuper().update()remains legal (it is a no-op) so existing models keep working.
- update_agent_data(agent_id: int, data: Dict[str, Any])[source]
Deprecated: use
agent.<col> = valueoragents.at[id].set(...).Still routes through
_queue_write()so the snapshot-view contract can witness the writes.
- property xp
NumPy or CuPy array module for the active run (CPU when idle).
The Model class is the foundation of any AMBER simulation. It provides the framework for:
Managing simulation time and execution
Storing and updating agent data
Recording model-level metrics
Coordinating agent behaviors
Basic Usage
import ambr as am
class MyModel(am.Model):
def setup(self):
# Initialize agents and environment
pass
def step_vectorized(self):
# Columnar / array-native implementation
pass
def step_oop(self):
# Optional tracked-Agent implementation
pass
# Run the model (fluent placement, 0.4.4)
model = MyModel({'steps': 100, 'seed': 42})
results = model.cpu(mode="vectorized").run()
# results = model.gpu().run() # vectorized lane on GPU
Key Methods
Lifecycle Methods:
setup()- Called once at the beginning to initialize the modelstep_vectorized()- Called for vectorized CPU/GPU runsstep_oop()- Called for CPU OOP runs with tracked Agent objectsstep()- Backwards-compatible fallback when a lane hook is not definedupdate()- Called after step() to update model stateend()- Called once at the end of the simulation
Data Management:
add_agent(agent)- Add a new agent to the modelupdate_agent_data(agent_id, data)- Update data for a specific agentget_agent_data(agent_id)- Retrieve data for a specific agentrecord_model(name, value)- Record a model-level metric
Execution / placement (0.4.4):
cpu(mode=None)- Place the nextrunon CPU (optionalmode='vectorized'|'oop'); returnsselffor chaininggpu(mode=None)- Place the nextrunon GPU with device-resident columns; GPU runs are vectorized-onlyapprove_fast_path(evidence)- Explicitly allow a private optimized GPU loop on this model instance and retain the caller-supplied evidence label; AMBER does not verify that label (requirescontract="off")revoke_fast_path_approval()- Return the instance to the general runnerrun(...)- Execute the full simulation and return results. Acceptsdevice=,mode=,contract=; legacybackend=still works but is deprecatedrun_step()- Execute a single time step
Mode defaults to vectorized. Fluent placement and run(mode=...) /
run(device=...) compose: kwargs to run override what
cpu() / gpu() set when both are used.