agent_urban_planning.AhlfeldtMarket¶
- class AhlfeldtMarket(ahlfeldt_params, initial_damping=0.3, convergence_threshold=0.01, stall_threshold=1e-06, stall_window=10, max_iterations=1000, max_price_change_pct=0.5, max_price_change_pct_wage=None, verbose=False)[source]¶
Bases:
HousingMarketTwo-market tatonnement clearing Q (residential floor) AND w (wages).
For Berlin / Ahlfeldt scenarios only. Selected by
SimulationEnginewhenscenario.ahlfeldt_params is not None. Supersedes the HDB/private segmentation inHousingMarket.clear; Berlin has one unified floor market per zone with the commercial / residential split fixed from observed 2006 values (Decision: fixed θ_i).Per-market elasticities are computed from the Ahlfeldt parameters as
eta_floor = (1 - beta) * epsilonandeta_wage = 1 / (1 - alpha) + epsilon, and can be overridden via scenario-leveleta_floor_override/eta_wage_overridefields.- Parameters:
ahlfeldt_params – Structural parameters loaded from the scenario YAML. Drives elasticities, agglomeration toggle, and the chosen clearing method.
initial_damping (
float) – Initial Walrasian step dampinglambda. Adapts each iteration. Defaults to0.3.convergence_threshold (
float) – Maximum absolute excess demand at which both markets are declared converged. Defaults to0.01.stall_threshold (
float) – Minimum iter-to-iter change in residual to avoid being flagged as stalled. Defaults to1e-6.stall_window (
int) – Consecutive stalled iterations before damping is boosted (and ultimately, the run terminates). Defaults to10.max_iterations (
int) – Iteration budget. Defaults to1000.max_price_change_pct (
float) – Per-iteration cap on relative price moves for floor prices. Defaults to0.5(50%).max_price_change_pct_wage (
float|None) – Per-iteration wage cap. Defaults tomax_price_change_pctifNone.verbose (
bool) – WhenTrue, prints per-iteration diagnostics.
Examples
>>> import agent_urban_planning as aup >>> # Typically obtained from the SimulationEngine, not constructed >>> # directly. See SimulationEngine.run() for end-to-end usage. >>> # market = aup.AhlfeldtMarket(scenario.ahlfeldt_params) >>> # result = market.clear(population, environment, engine)
References
Ahlfeldt, G. M., Redding, S. J., Sturm, D. M., Wolf, N. (2015). The economics of density: Evidence from the Berlin Wall. Econometrica, 83(6), 2127-2189.
- set_iteration_callback(fn)[source]¶
Install or clear a per-iteration progress callback.
Called after every tatonnement iteration with
fn(iter_idx, max_floor_excess, max_labor_excess, elapsed_seconds). Exceptions raised by the callback are suppressed so progress rendering cannot break market clearing. PassNoneto clear a previously installed callback.- Parameters:
fn (
Optional[Callable[[int,float,float,float],None]]) – Callable accepting(iter_idx, max_floor_excess, max_labor_excess, elapsed_seconds), orNoneto disable.- Return type:
- Returns:
None.
Examples
>>> import agent_urban_planning as aup >>> # market = aup.AhlfeldtMarket(scenario.ahlfeldt_params) >>> # market.set_iteration_callback(lambda i, f, l, t: print(i, f, l, t))
- clear(population, environment, engine, resume_state=None, checkpoint_callback=None, cache_path=None)[source]¶
Run joint Q/w tatonnement and return an Ahlfeldt
MarketResult.Iterates: inject current wages into the engine, run
decide_batchto get joint (residence, workplace) choices, compute floor and labor excess demand, optionally update endogenous productivity / amenity from current density, and update prices either via tatonnement or the closed-form FOC update (whenclearing_method='foc_direct'andendogenous_land_use=True). Returns at convergence or after the iteration cap.resume_stateandcheckpoint_callbackare accepted for protocol compatibility withHousingMarketbut ignored — Ahlfeldt runs are typically short enough (<= 200 iterations at Ortsteile resolution) that in-process execution is sufficient.- Parameters:
population (
AgentPopulation) – TheAgentPopulationto clear over.environment (
Environment) – TheEnvironmentcarrying zones and their Ahlfeldt fundamentals.engine (
DecisionEngine) – A decision engine implementingdecide_batch. Engines exposingset_current_wages/set_current_productivity/set_current_amenityreceive per-iteration injection of those state vectors.resume_state (
Optional[dict]) – Ignored. Accepted for protocol compatibility.checkpoint_callback (
Optional[Callable[[dict],None]]) – Ignored. Accepted for protocol compatibility.cache_path (
Optional[str]) – Optional path to a disk-backed LLM cache passed to engines that accept caches viaset_cache.
- Return type:
- Returns:
A
MarketResultcarrying equilibrium pricesQ, wages, joint allocations, convergence flags for each market, and the full per-iterationhistory.
Examples
>>> import agent_urban_planning as aup >>> # market = aup.AhlfeldtMarket(scenario.ahlfeldt_params) >>> # result = market.clear(population, environment, engine) >>> # max(result.prices.values()) 7.42