Skip to main content

Agent-based urban planning simulator with closed-form, hybrid, and full-LLM decision engines

Project description

agent-urban-planning

PyPI Documentation Status License: MIT Python 3.9+

Open-source Python library for agent-based urban planning simulation with closed-form, hybrid, and full-LLM decision engines. Companion to the NeurIPS Datasets & Benchmarks 2026 paper:

TBD — paper title

Workflow

workflow

The simulator is organized as a five-stage pipeline. (1) Environment — a city is described by zones, transportation graphs, land-use parameters, housing, amenities, and wages; an optional policy shock perturbs this state (e.g., a new rapid-transit line). (2) Agents — a population of heterogeneous household types (young professionals, families with kids, retirees, …) with demographic and preference attributes. (3) Decision — each agent picks a (residence, workplace) pair via one of three swappable engines: a closed-form UtilityEngine (V1–V3), a HybridDecisionEngine that elicits LLM-side preferences and resolves choice in closed form (V4), or a full LLMDecisionEngine that consults a language model end-to-end (V5 — the paper headline). (4) Market & Allocation — the macro layer aggregates choices, clears the housing/labor markets via tâtonnement (rents, wages, congestion), and allocates agents to zones. (5) Equilibrium — a fixed-point solver iterates 1→4 until prices and choices stop moving. Output is a bundle of welfare metrics, choropleth maps, and per-agent traces with a recorded seed for replay.

What it is

A modular ABM framework for simulating spatial-equilibrium urban policies. Five reference decision-engine variants ship as first-class API classes, configurable via kwargs:

Paper variant One-line description API call
V1 Baseline-softmax Closed-form Cobb-Douglas + Fréchet softmax aup.UtilityEngine(mode="softmax")
V2 Baseline-ABM argmax ABM with Fréchet idiosyncratic shocks aup.UtilityEngine(mode="argmax", noise="frechet")
V3 Normal-ABM argmax ABM with Gaussian shocks aup.UtilityEngine(mode="argmax", noise="normal")
V4 Hybrid-ABM LLM-elicited preferences + closed-form choice aup.HybridDecisionEngine(elicitor=...)
V5 LLM-ABM (paper headline) Full LLM-as-decision-maker, score-all-96 aup.LLMDecisionEngine(response_format="score_all", rebalance_instruction=True, stage2_top_k_residences=10)

Quickstart

git clone https://github.com/MASE-eLab/agent-urban-planning.git
cd agent-urban-planning
pip install -e ".[llm,plot,berlin]"
python examples/01_quickstart.py

The quickstart script walks through the five-stage pipeline (Environment → Agents → Decision → Market → Equilibrium) and runs a baseline simulation with V1 (closed-form softmax). Wall-clock <1 minute, no LLM credits required.

import agent_urban_planning as aup
from agent_urban_planning.data.loaders import load_scenario, load_agents

# Stage 1+2 — Environment + Agents
scenario = load_scenario("data/berlin/scenarios/berlin_2006_ortsteile.yaml")
agent_config = load_agents("data/berlin/agents/berlin_ortsteile_richer_10k.yaml")

# Stage 3 — Decision engine (V1; swap to V2/V3/V4/V5 with one constructor change)
engine = aup.UtilityEngine(scenario.ahlfeldt_params, mode="softmax")

# Stage 4 — SimulationEngine + market clearing (Stage 5 = result.metrics)
sim = aup.SimulationEngine(scenario=scenario, agent_config=agent_config,
                           engine=engine, seed=42)
result = sim.run(policy=None)

print(result.metrics.avg_utility, result.metrics.gini_coefficient)

The other 4 paper variants (V2, V3, V4, V5) swap only the decision engine — see the variant table below.

Berlin replication results

We benchmark all five variants on a 96-zone Berlin scenario (Ahlfeldt et al. 2015 calibration) under a hypothetical East–West Express rapid-transit shock (4 stations, 5-min between adjacent).

Choropleth: log-change in housing prices Δlog Q under the shock

Berlin Δlog Q

The structural family (V1, V2, V4) produces a visibly focal response — price effects concentrate at the four station catchments. LLM-ABM (V5) instead spreads the response broadly across the city, picking up the gradient-flattening + agglomeration effects that exogenous-productivity models forbid.

Choropleth: log-change in wages Δlog w under the shock

Berlin Δlog w

The wage maps tell the same story at the workplace side: structural variants forbid the agglomeration channel by construction (productivity A_i is exogenous), while LLM-ABM produces a coherent compensating-differential pattern via its training-data priors on urban economics.

Cross-variant moments

Distribution-shape moments across the 96 zones (baseline → shock):

Variant μ ΔlogQ σ ΔlogQ p95 |ΔlogQ| ΔY% Δ Q̄ Δ⟨U⟩
V1 Baseline-softmax +0.0004 0.0070 0.0083 +0.0007 +0.0008 −0.0032
V2 Baseline-ABM argmax +0.0004 0.0071 0.0080 −0.0000 +0.0007 −0.0031
V3 Normal-ABM argmax +0.0004 0.0042 0.0048 +0.0132 +0.0001 −0.0027
V4 Hybrid-ABM +0.0004 0.0068 0.0077 +0.0002 +0.0007 −0.0031
V5 LLM-ABM +0.0016 0.0083 0.0172 +0.0299 +0.0111 −0.0056

Full table + interpretation: figures/comparison_moments.csv.

Three takeaways.

  1. The structural family agrees. V1, V2, V4 (and V3 modulo Gaussian-vs-Fréchet tail differences) cluster tightly on μ ≈ +0.0004, σ ≈ 0.007, Δ⟨U⟩ ≈ −0.0031. They share the Cobb-Douglas + Fréchet architecture; the noise model and clustering wash out at zone-level moments. Architecturally distinct simulators give the same answer to a small policy shock — a useful sanity check for the structural family.
  2. LLM-ABM is qualitatively different. Its mean log-change in housing price is 4× the structural consensus; spread (σ, p95) is 1.2–2× larger; mean rent change is 14× larger; aggregate productivity gain (+3%) is the only sizable positive value. Welfare drop is ~2× the structural family's.
  3. All five agree on welfare direction. Δ⟨U⟩ < 0 across the board under the Baseline-softmax welfare ruler — the shock is a (small) net welfare loss. The mechanisms differ: structural variants attribute the drop to commute/wage compensation; LLM-ABM picks up the same direction at ~2× magnitude because its equilibrium reroutes more agents to lower-utility configurations under the structural ruler's lens.

The full paper §6 discusses why LLM-ABM diverges (gradient-flattening + agglomeration, both forbidden in exogenous-productivity structural models).

Reproduce the paper results

The paper's V1–V5 Berlin runs (baseline + East-West Express shock) reproduce end-to-end from a git clone. Pick a path:

git clone https://github.com/MASE-eLab/agent-urban-planning.git
cd agent-urban-planning
pip install -e ".[llm,plot,berlin]"

# Tier 1+2 — quickstart pipeline walkthrough (<1 min, V1 baseline only)
python examples/01_quickstart.py

# Tier 3 — V1/V2/V3 closed-form + ABM variants (~3 hr each, no LLM credits)
python examples/02_berlin_replication/run_v1_softmax.py
python examples/02_berlin_replication/run_v2_argmax_frechet.py
python examples/02_berlin_replication/run_v3_argmax_normal.py

# Tier 3d — V4 hybrid (~3 hr, ~$5 in LLM credits)
python examples/02_berlin_replication/run_v4_hybrid.py --llm-provider codex-cli

# Tier 4 — V5 LLM-ABM, paper headline. Two paths:
#   Path A: replay the bundled cache (~5–10 min, no credits, recommended for reviewers)
curl -L -o llm_cache_v5.tar.gz \
  https://github.com/MASE-eLab/agent-urban-planning/releases/download/v0.1.0-data/llm_cache_v5.tar.gz
tar -xzf llm_cache_v5.tar.gz -C data/berlin/
python examples/02_berlin_replication/run_v5_score_all.py --no-llm

#   Path B: rerun from scratch with live LLM (~10 hr, ~$30–50 credits)
python examples/02_berlin_replication/run_v5_score_all.py --llm-provider codex-cli
Tier What Wall-clock LLM credits
1 pip install + import agent_urban_planning <30 s No
2 examples/01_quickstart.py <10 s No
3a-c V1, V2, V3 Berlin baseline + shock ~3 hr each No
3d V4 Berlin baseline + shock (hybrid) ~3 hr ~$5
4 V5 Berlin baseline + shock (cache replay) ~5–10 min No
4 V5 Berlin baseline + shock (live LLM) ~10 hr ~$30–50

Detailed instructions (real-run params, smoke testing, all 6 LLM provider options, cross-variant analysis snippets, numerical-reproducibility expectations) are in examples/02_berlin_replication/README.md. The full reproducibility tier ladder lives at docs/reproducibility/berlin_v1_v5.md (also rendered at https://agent-urban-planning.readthedocs.io/en/latest/reproducibility/berlin_v1_v5.html).

Documentation

Comprehensive API reference, tutorials, and concept guides:

https://agent-urban-planning.readthedocs.io

Repository layout

agent-urban-planning/
├── src/agent_urban_planning/      Library source
│   ├── core/                       Environment / Agents / Market / Engine / Metrics
│   ├── decisions/                  UtilityEngine / HybridDecisionEngine / LLMDecisionEngine
│   ├── data/                       Loaders + builtin scenarios
│   ├── analysis/                   Welfare + plotting
│   ├── llm/                        LLM client wrappers
│   └── research/                   Paper-specific helpers (Berlin)
├── examples/
│   ├── 01_quickstart.py   Full V1 pipeline walkthrough (<1 min)
│   └── 02_berlin_replication/      End-to-end V1–V5 Berlin runs
├── data/                           Bundled Berlin + Singapore data (git, not PyPI sdist)
├── docs/                           Sphinx documentation source
├── figures/                        README assets (workflow, choropleths, tables)
└── pyproject.toml

Citation

If you use this software in your research, please cite the accompanying paper (see CITATION.cff).

License

MIT License © 2026 The agent-urban-planning Authors

Acknowledgements

The Berlin replication is built on the Ahlfeldt, Redding, Sturm, Wolf (2015) "The Economics of Density: Evidence from the Berlin Wall" Econometrica 83(6) data and methodology. We are grateful for the authors' public release of the replication package; the data files in data/berlin/ and data/shapefiles/ derive from that release. See data/README.md for full attribution.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_urban_planning-0.1.0.tar.gz (179.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_urban_planning-0.1.0-py3-none-any.whl (204.0 kB view details)

Uploaded Python 3

File details

Details for the file agent_urban_planning-0.1.0.tar.gz.

File metadata

  • Download URL: agent_urban_planning-0.1.0.tar.gz
  • Upload date:
  • Size: 179.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for agent_urban_planning-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8ddf1b1e81d59f982fb1185435add5dd3f6f6131499e7abcc36e4510e1ffd804
MD5 b8e041ee7016c11d0a15746c376547f5
BLAKE2b-256 5330be0e5893c8831b20de83a060b24befbb8ad0fbed8c6875055372fd9e1b0b

See more details on using hashes here.

File details

Details for the file agent_urban_planning-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_urban_planning-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 38a14314fb24aec7dd2e4055d29117ed6a3dfe43bdccb5699f66f291df1761ec
MD5 a97f1540b1dd1ae3bbf3552c0c7de35d
BLAKE2b-256 d2fde195e45a60e5df4f03da8f98e5c8b0b0fdf48f7552a410bea7e051a27957

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page