agent_urban_planning.UtilityEngine

class UtilityEngine(params, *, mode='softmax', noise='frechet', **kwargs)[source]

Bases: object

Closed-form Cobb-Douglas + Fréchet utility decision engine.

Configure via constructor kwargs to reproduce V1 (Baseline-softmax), V2 (Baseline-ABM argmax with Fréchet noise), or V3 (Normal-ABM argmax with Gaussian noise) from the paper.

Parameters:
  • params (Any) – An AhlfeldtParams instance from agent_urban_planning.data.loaders carrying the model’s structural elasticities (alpha, beta, epsilon, kappa_eps, etc.).

  • mode (Literal['softmax', 'argmax']) – "softmax" for the deterministic V1 pattern (closed-form softmax over Fréchet utility). "argmax" for the V2/V3 ABM pattern (per-agent draw + argmax). Default "softmax".

  • noise (Literal['frechet', 'normal']) – When mode="argmax", selects the per-agent shock distribution. "frechet" for V2; "normal" for V3. Ignored when mode="softmax". Default "frechet".

  • **kwargs (Any) – Forwarded to the underlying implementation (AhlfeldtUtilityEngine for softmax, AhlfeldtABMEngine for argmax). Common kwargs: num_agents, batch_size, seed, dtype.

Raises:

ValueError – If mode is not one of {"softmax", "argmax"}, or if noise is not one of {"frechet", "normal"}.

Examples

V1 reproduction (Baseline-softmax):

>>> import agent_urban_planning as aup
>>> engine = aup.UtilityEngine(params, mode="softmax")
>>> # Use as you would any DecisionEngine.
>>> # sim = aup.SimulationEngine(scenario=sc, agent_config=ag, engine=engine)
>>> # results = sim.run()

V2 reproduction (Baseline-ABM argmax, Fréchet shocks):

>>> engine = aup.UtilityEngine(
...     params, mode="argmax", noise="frechet",
...     num_agents=1_000_000, seed=42,
... )

V3 reproduction (Normal-ABM argmax, Gaussian shocks):

>>> engine = aup.UtilityEngine(
...     params, mode="argmax", noise="normal",
...     num_agents=1_000_000, seed=42,
... )

Notes

Internally this class is a dispatch wrapper around two implementation classes (AhlfeldtUtilityEngine and AhlfeldtABMEngine). All other attribute and method access is forwarded transparently to the underlying implementation via __getattr__, so any feature documented on those classes is usable on a UtilityEngine instance.

See also

agent_urban_planning.HybridDecisionEngine — V4 (LLM elicits per-agent preference weights, then closed-form choice). agent_urban_planning.LLMDecisionEngine — V5 (full LLM-as-decision-maker hierarchical 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.

property mode: str

"softmax" or "argmax".

Type:

The configured mode

property noise: str

The configured per-agent noise distribution (only relevant for argmax mode).

decide_batch(*args, **kwargs)[source]

Forward to the underlying implementation’s decide_batch.

Transparently forwards to either AhlfeldtUtilityEngine.decide_batch() (softmax) or AhlfeldtABMEngine.decide_batch() (argmax) depending on the configured mode.

Parameters:
  • *args (Any) – Positional arguments forwarded unchanged.

  • **kwargs (Any) – Keyword arguments forwarded unchanged.

Return type:

Any

Returns:

List of agent_urban_planning.LocationChoice, one per input agent and in the same order.

Examples

>>> import agent_urban_planning as aup
>>> # engine = aup.UtilityEngine(params)
>>> # choices = engine.decide_batch(agents, env, zones, prices)