Million-worker equilibrium wealth search¶
examples/optimize_equilibrium.py uses EquilibriumOptimizer to search for
the highest average wealth found while household wealth, consumption, prices, and finances
settle together. The search is deterministic and local; its result does not
establish a global maximum.
Scenario and inputs¶
The worker cap is 1,000,000, and the workforce ratio is 0.4, allowing
up to 2,500,000 people including dependents. Actual employment may be lower.
The scenario excludes DEFAULT_BANNED_BGS from examples/__init__.py, and uses
min_goods_balance=None.
Infrastructure is unconstrained (min_net_infrastructure=None); usage remains
visible in reports as a diagnostic, and the summary records an empty minimum.
Fixed throughput multipliers are all 1.0, and level-dependent economy-of-scale bonuses are disabled. Trade, resource limits, arable-land limits, and era restrictions retain their defaults. Household demand is endogenous, calculated from household wealth and population composition.
The script loads the production table, goods, professions, population needs,
and buy packages from the existing artifact datasets. It restricts production
to the union of active building/production-method configurations in the saved
era_5_automation/*/processes.csv supply-chain reports. Other configurations
are excluded from both the initial mix and the optimizer's search. Generate
the datasets and supply-chain reports first:
uv run python -m examples.parse
uv run python -m examples.production_analysis
uv run python -m examples.supply_chain_compare
The initial mix starts with equal levels of every allowed configuration and scales to one million workers without balancing infrastructure. A mix with infrastructure consumption and no supplier is permitted. Missing reports, an empty active set, or configurations absent from the production table raise an error. The optimizer checks scenario feasibility before starting its search.
Run the search¶
The default hard trial budget is 20,000 per local search:
Proportional income tax funds operating losses by default. Disable it with:
The enabled policy taxes cooperative and dependent income without guaranteeing
payroll, and applies to saved baselines and every restart. --resume uses the
current invocation's policy, which defaults to enabled; summary.csv records it
in subsidize_operating_losses. Imported calls also default to enabled; use
run(..., subsidize_operating_losses=False) to disable it. If the initial or saved
mix cannot fund its losses, the example still starts the optimizer. Rejected
trials receive a penalty based on their funding shortfall; only verified, funded
equilibria can become the best solution. An unfunded saved mix is not retained as
a baseline. The summary records initial_equilibrium_status=insufficient_income
and leaves its initial wealth/GDP metrics empty. If no valid result is found
within the trial budget, the search fails without overwriting exports. Other
initialization errors still propagate. See
tax-funded operating losses.
Direct-file execution is also supported. A short run can validate the pipeline and regenerate reviewable snapshots:
The CLI enables timestamped INFO progress on stderr by default, with periodic summaries every 100 trials. Use a shorter interval for a small-budget run:
--log-level DEBUG adds individual trial outcomes, new incumbents, and concise
inner-solver start/finish/failure messages. --log-level WARNING suppresses
the progress logs while retaining the printed result summary. --log-every
must be positive. Imported calls to run(..., log_every=100) leave logging
configuration to their caller. Standard logging stream handlers flush each
record, so progress appears as the search runs; redirect stderr to save it.
Progress reports distinguish initialization from subsequent search, show uncached trials used versus budget, current and best unscaled objective values in weekly units, scenario feasibility, inner-solver iteration counts, failures, and elapsed seconds. See the progress-field reference. The CSV schemas and annualization rules are unaffected by logging options.
After each completed search, the example reduces materially loss-making
building configurations by --loss-reduction (default 0.5) and restarts with
a fresh trial budget. Profitability uses all output revenue, including
coproducts, minus input costs at the returned equilibrium prices, with the
same absolute/relative loss tolerance as the supply-chain example. Other levels
are unchanged, and employment is not scaled back up. The adjusted mix must
remain feasible under the scenario's worker cap and building exclusions.
Iteration stops when the returned objective is strictly lower than the preceding
search's objective. The scenario maximizes average wealth; GDP remains a
reported metric. Equal objectives continue, and the earliest result wins ties.
--max-iterations optionally caps completed local searches. Omission means
unlimited searches, so an equal-objective plateau can continue indefinitely.
--loss-reduction 0 disables reductions for all restarts.
To start from the saved solution:
Resume aligns buildings.csv by building and production method, restores
omitted zero configurations, and validates the saved levels against the current
scenario. Duplicate or unknown configurations are rejected. The saved levels
are re-evaluated, then adjusted for the first local search. The saved baseline
remains eligible as the best solution; if the first new result is worse,
iteration stops and exports that baseline. Use
--resume --loss-reduction 0 --max-iterations 1 for one local search from the
unchanged saved levels.
The budget limits optimizer trials. Evaluation of the initial baseline and fresh verification of the returned state are additional equilibrium solves. A very small budget can end during search initialization and retain the initial mix. Larger budgets can take tens of minutes or longer.
The console reports each search's initial and returned objective, the best
objective, annual GDP, actual workers and population, and iteration termination.
A budget-limited search retains
its best verified equilibrium with search_success=False and an explicit
search_message; equilibrium_status is still converged. Invalid inputs or
a search without a feasible converged state raise an error before writing new
outputs. Financial flags remain visible on successful household equilibria.
Summary and solution¶
The summary has one row per completed local search, including the worse attempt
that triggers stopping. A resumed invocation also has an iteration-zero row for
the re-evaluated saved baseline with empty search diagnostics. Each row records
scenario settings, starting and returned metrics, search diagnostics,
financial-flag counts, applied reduction, objective change, UTC start time, and
elapsed seconds. is_best selects the row whose solution is exported. Every row
also records invocation totals, the selected best iteration, optional iteration
cap, and stop reason (objective_worsened or max_iterations).
Monetary totals use equilibrium market
prices; annual GDP is weekly GDP multiplied by 52. See the
summary dictionary
for all columns.
| annual_gdp | employment | population | average_wealth | trial_evaluations | search_success | equilibrium_status |
|---|---|---|---|---|---|---|
| 15198211.216975441 | 954868.326364183 | 2387170.815910457 | 21.666096016339544 | 1732 | True | converged |
Download artifacts/analyses/optimization/equilibrium/summary.csv
The solution uses the existing building registry report: nonzero configuration levels, sorted by level descending. Configuration keys identify building and production-method combinations in the source table.
| building | production_method | level | construction_cost |
|---|---|---|---|
| building_oil_rig | pm_combustion_derricks+pm_tanker_cars | 29.692470427944457 | 11876.988171177783 |
| building_railway | pm_diesel_trains_principle_transport_3+pm_wooden_passenger_carr… | 28.339219916246392 | 22671.375932997114 |
| building_power_plant | pm_oil-fired_plant | 19.03149068754308 | 7612.596275017232 |
| building_tooling_workshop | pm_rubber_grips+pm_assembly_lines_building_tooling_workshop | 14.038314482141365 | 8422.988689284819 |
| building_iron_mine | pm_diesel_pump_building_iron_mine+pm_dynamite_building_iron_min… | 13.978474355367108 | 5591.389742146844 |
| building_tea_plantation | automatic_irrigation_building_tea_plantation+slave_exploitation… | 13.938106222211609 | 2787.6212444423218 |
| building_railway | pm_diesel_trains_principle_transport_3+pm_no_passenger_trains | 11.887933191544667 | 9510.346553235733 |
| building_silk_plantation | automatic_irrigation_building_silk_plantation+pm_steam_rail_tra… | 11.75066731929551 | 2350.133463859102 |
| building_urban_center | pm_arcades+pm_electric_streetlights+pm_public_motor_carriages+p… | 11.74521647653587 | 0.0 |
| building_motor_industry | pm_diesel_engines+pm_assembly_lines_building_motor_industry | 11.425075845028694 | 9140.060676022955 |
Download artifacts/analyses/optimization/equilibrium/buildings.csv
· View examples/optimize_equilibrium.py
The script also exports market.csv, pop.csv, and goods_buy_packages.csv
from the other three Economy.df_ reports for the same verified state. The
goods buy-package export preserves the wealth index as a wealth column.
After iteration ends, the best retained solution is written once to the four
solution CSVs; summary.csv contains the full search history. Validation and
equilibrium errors propagate before any files are overwritten.
Read the recorded budgets and search status
when comparing results. See the optimization guide
for solver behavior and the optimization API.