Environments & Schelling
AMBER ships three environment types:
GridEnvironment— discrete lattice (Schelling, CA, grids)SpaceEnvironment— continuous 2D spaceNetworkEnvironment— graph / network topologies
Agent attributes stay on the columnar table (model.agents /
agents_df). The environment owns placement (where each agent sits).
Grid occupancy helpers (0.4.1)
On GridEnvironment:
Helper |
Role |
|---|---|
|
Place or move an agent onto a cell |
|
Clear a cell; returns the agent id that left |
|
Occupant id or |
|
Uniform empty cell (uses |
|
Empty Moore neighbourhood |
|
Moore ring of cells (alias of distance-based neighbours) |
|
All unoccupied cells |
Positions are stored on the frame as grid_position (object column of
tuples). Prefer these helpers over hand-rolled occupancy dicts.
Canonical Schelling pattern
Full runnable code: examples/schelling_vectorized.py.
Create the grid and population
self.env = am.GridEnvironment(self, size=self.p.grid_size) self.agents = am.AgentList(self, self.p.n, SchellingAgent) self.agents.set(group=self.rng.integers(0, 2, size=self.p.n))
Place agents once (random unique cells)
cells = list(self.env.positions) self.rng.shuffle(cells) for agent, pos in zip(self.agents, cells[: self.p.n]): self.env.add_agent_from_id(agent.id, pos)
Each step: happiness (per-agent) then filter + relocate
Neighbourhood inspection is irregular → agent methods are fine. Selecting who moves is vectorized:
for a in self.agents: a.update_happiness(self.p.want_similar) for aid in self.agents.where(~self.agents.happy).ids.to_list(): self.agents.by_id(aid).relocate() # uses get_random_empty_cell
Report with model_reporters
model_reporters = { "happy_frac": lambda m: float(m.agents.happy.sum()) / max(len(m.agents), 1), }
When not to force full vectorization
Moore-neighbourhood Schelling happiness is a classic “per-agent is OK”
workload: each agent’s local view is small and sparse. AMBER still wins on
metrics, placement bookkeeping, and filtered selection (where / set /
scatter_add). Dense continuous interactions are a better fit for the
tensor lane (borrow / commit) or ArrayKernelModel —
see Going faster (lanes).