Economy dependencies¶
These graphs describe the current economy model. An arrow means the source is needed to calculate the target; it does not imply that every solve mode runs that calculation. Dashed arrows carry wealth into the next iteration. Repeated node names refer to the same value across graphs. Wide diagrams scroll horizontally to preserve readable labels.
For usage, see the economy guide. The API reference describes the public interfaces, and the economy data dictionary defines report units and accounting boundaries.
Storage legend¶
- E
Economy: game tables and model coefficients. - C
EconomyContext: fixed inputs shared by snapshots. - M
MarketState: prices and building finances. - P
PopState: household wealth, demand, and finances. - S
EconomyState: the composed snapshot and combined reports. - V A separate argument, returned value, constant, or solver working variable.
An asterisk (*) marks a cached property. Methods ending in () calculate
their return values on demand without caching them. Textual owner prefixes
remain meaningful without color.
EconomyState holds context, market, and households references. Its flat
properties, such as state.building_goods_flow and state.pop_income, forward
to the component owners shown here; they do not duplicate the arrays.
Production preparation¶
Building levels, production coefficients, and effective throughput determine realized weekly goods flows. Employment scales with building levels, while throughput changes goods inputs and outputs without scaling worker counts. Effective throughput adds the economy-of-scale bonus to the supplied multiplier.
---
config:
flowchart:
useMaxWidth: false
nodeSpacing: 20
rankSpacing: 35
themeCSS: |
.node.model rect { fill: var(--vic3-owner-economy) !important; }
.node.context rect { fill: var(--vic3-owner-context) !important; }
.node.variable rect { fill: var(--vic3-owner-variable) !important; }
.node rect { stroke: var(--vic3-owner-border) !important; }
.nodeLabel { color: var(--vic3-owner-text) !important; }
.flowchart-link { stroke: var(--vic3-owner-edge) !important; }
marker path { fill: var(--vic3-owner-edge) !important; stroke: var(--vic3-owner-edge) !important; }
.edgeLabel, .edgeLabel p { color: var(--vic3-owner-text) !important; background: var(--md-default-bg-color) !important; }
---
flowchart TD
DP["[E] df_production"]:::model
PC["[E] Unscaled goods matrices *"]:::model
EM["[E] employment_matrix *"]:::model
DP --> PC
DP --> EM
L["[C] building_levels"]:::context
CAP["[V] economy_of_scale_level_cap"]:::variable
TM["[V] throughput_multipliers"]:::variable
L --> EOS["[V] Economy-of-scale bonuses"]:::variable
CAP --> EOS
DP --> EOS
EOS --> T["[V] Effective throughput"]:::variable
TM --> T
L --> F["[C] building_goods_flow"]:::context
PC --> F
T --> F
F --> GI["[C] building_goods_input *"]:::context
F --> GO["[C] building_goods_output *"]:::context
GO --> SELL["[C] sell_orders *"]:::context
IM["[C] goods_import"]:::context --> TF["[C] goods_trade_flow *"]:::context
IM --> SELL
GI --> NP["[C] non_pop_buy_orders *"]:::context
EX["[C] goods_export"]:::context --> TF
EX --> NP
L --> N["[C] pops"]:::context
EM --> N
Flows retain the production table's signed-net convention within each configuration. Splitting signs before aggregation preserves opposing orders between different configurations. No separate gross-flow parsing is implied.
Consumption and market prices¶
Economy.df_buy_packages contains raw need-category budgets at base prices.
Prepared EconomyContext.goods_buy_packages is a GoodsBuyPackages object containing goods
quantities by wealth tier and wealth row labels. These are different
representations.
---
config:
flowchart:
useMaxWidth: false
nodeSpacing: 20
rankSpacing: 35
themeCSS: |
.node.model rect { fill: var(--vic3-owner-economy) !important; }
.node.context rect { fill: var(--vic3-owner-context) !important; }
.node.market rect { fill: var(--vic3-owner-market) !important; }
.node.household rect { fill: var(--vic3-owner-pop) !important; }
.node.snapshot rect { fill: var(--vic3-owner-state) !important; }
.node.variable rect { fill: var(--vic3-owner-variable) !important; }
.node rect { stroke: var(--vic3-owner-border) !important; }
.nodeLabel { color: var(--vic3-owner-text) !important; }
.flowchart-link { stroke: var(--vic3-owner-edge) !important; }
marker path { fill: var(--vic3-owner-edge) !important; stroke: var(--vic3-owner-edge) !important; }
.edgeLabel, .edgeLabel p { color: var(--vic3-owner-text) !important; background: var(--md-default-bg-color) !important; }
---
flowchart TD
N["[C] pops"]:::context --> SC["[C] consumption_scales"]:::context
R["[C] workforce_ratio"]:::context --> D["[C] dependents_per_worker *"]:::context
D --> SC
CM["[E] _pop_consumption_multipliers *"]:::model --> SC
SELL["[C] sell_orders *"]:::context --> ES["[V] Effective substitution supply"]:::variable
NP["[C] non_pop_buy_orders *"]:::context --> ES
ES --> SH["[V] Substitution shares"]:::variable
PN["[E] df_pop_needs"]:::model --> SH
SH --> Q["[C] goods_buy_packages<br/>wealth + quantities"]:::context
RAW["[E] df_buy_packages<br/>Raw category budgets"]:::model --> Q
BASE["[E] base_prices *"]:::model --> Q
Q --> QR["[V] df_goods_buy_packages()<br/>DataFrame export"]:::variable
Q --> NEEDS["[P] pop_buy_orders"]:::household
SC --> NEEDS
W["[P] pop_wealth"]:::household --> NEEDS
NEEDS --> BUY["[S] buy_orders *"]:::snapshot
NP --> BUY
BUY --> PRICE["[M] market_prices"]:::market
SELL --> PRICE
BASE --> PRICE
Prepared baskets and scales are optional context fields. prepare_context()
computes only missing fields; supplied fields are authoritative. Baskets stay
fixed while production, trade, and substitution assumptions are fixed. Scales
stay fixed while worker counts, workforce ratio, and profession multipliers
are fixed. Changing wealth selects different basket rows; changing prices
changes their monetary cost rather than their quantities.
goods_buy_packages() returns immutable GoodsBuyPackages, reusing prepared
baskets when present. Explicit, prepared, and freshly calculated baskets share
one selection path in consumption calculations. df_goods_buy_packages()
exports an independent DataFrame from a state, context, or basket object.
pop_consumption_scales(), pop_buy_orders(), and
pop_expenses() return arrays without updating a snapshot.
Preparation and wealth evaluation attach the appropriate results to their
owners. The evaluator calculates total buy orders as a working array; the
composed snapshot exposes the same quantity through cached buy_orders.
Household finances and iteration¶
Cooperative income distributes each configuration's positive value added according to worker counts and profession wage weights. Dependent earnings are added separately. Expenses value the selected baskets at the same market prices. Basket costs, income coefficients, and transitions are solver working values, rather than additional public state fields.
---
config:
flowchart:
useMaxWidth: false
nodeSpacing: 20
rankSpacing: 35
themeCSS: |
.node.model rect { fill: var(--vic3-owner-economy) !important; }
.node.context rect { fill: var(--vic3-owner-context) !important; }
.node.market rect { fill: var(--vic3-owner-market) !important; }
.node.household rect { fill: var(--vic3-owner-pop) !important; }
.node.variable rect { fill: var(--vic3-owner-variable) !important; }
.node rect { stroke: var(--vic3-owner-border) !important; }
.nodeLabel { color: var(--vic3-owner-text) !important; }
.flowchart-link { stroke: var(--vic3-owner-edge) !important; }
marker path { fill: var(--vic3-owner-edge) !important; stroke: var(--vic3-owner-edge) !important; }
.edgeLabel, .edgeLabel p { color: var(--vic3-owner-text) !important; background: var(--md-default-bg-color) !important; }
---
flowchart TD
F["[C] building_goods_flow"]:::context --> SUR["[M] building_surplus *"]:::market
PRICE["[M] market_prices"]:::market --> SUR
SUR --> DEF["[M] building_deficit *"]:::market
N["[C] pops"]:::context --> SH["[V] Cooperative allocation shares"]:::variable
WW["[E] pop_wage_weights *"]:::model --> SH
SUR --> CI["[V] Cooperative income<br/>Positive surplus only"]:::variable
SH --> CI
N --> DI["[V] Dependent income"]:::variable
D["[C] dependents_per_worker *"]:::context --> DI
DW["[E] df_pop_types.dependent_wage"]:::model --> DI
CI --> INC["[P] pop_income"]:::household
DI --> INC
Q["[C] goods_buy_packages<br/>wealth + quantities"]:::context --> BC["[V] Basket costs by wealth"]:::variable
PRICE --> BC
BC --> EXP["[P] pop_expenses"]:::household
W["[P] pop_wealth at t"]:::household --> EXP
SC["[C] consumption_scales"]:::context --> EXP
INC --> BAL["[P] pop_balance *"]:::household
EXP --> BAL
BC --> COSTS["[V] Current- and next-tier<br/>household costs"]:::variable
W --> COSTS
SC --> COSTS
COSTS --> RULE["[V] Wealth transition"]:::variable
INC --> RULE
W --> RULE
TH["[V] 0.98 / 1.02 constants<br/>+ rtol / atol"]:::variable --> RULE
RULE --> NW["[P] pop_wealth at t + 1"]:::household
NW -. "Next evaluation" .-> W
evaluate_wealth(context, pop_wealth) evaluates one assignment without changing
wealth and returns matching MarketState and PopState components. iterate()
trusts consistent evaluated inputs, applies simultaneous one-tier changes using
the previous prices and income, and evaluates the new assignment. It shares the
fixed context and returns the original components when wealth is unchanged.
The transition decreases wealth below 98% of current-tier cost; otherwise it
increases wealth at or above 102% of next-tier cost, within configured numerical
tolerances. Decreases take precedence, and minimum/maximum tiers bound movement.
solve(method="equilibrium") repeats evaluation and transition, detects cycles
and iteration limits, and independently verifies a stationary result. Numerical
convergence does not guarantee affordability at the minimum tier or funded
building losses; equilibrium_diagnostics records these flags on EconomyState.
pop_income and pop_expenses are optional PopState fields. Nominal and market
solves leave them unevaluated, and pop_balance is None until both are supplied.
When evaluated, balance is the signed weekly difference between income and
expenses; it is not an accumulated savings stock.
Derived reports¶
Fixed population metrics belong to the context, price-valued production metrics belong to the market, and reports combining wealth with fixed population data belong to the composed economy snapshot.
---
config:
flowchart:
useMaxWidth: false
nodeSpacing: 20
rankSpacing: 35
themeCSS: |
.node.context rect { fill: var(--vic3-owner-context) !important; }
.node.market rect { fill: var(--vic3-owner-market) !important; }
.node.household rect { fill: var(--vic3-owner-pop) !important; }
.node.snapshot rect { fill: var(--vic3-owner-state) !important; }
.node rect { stroke: var(--vic3-owner-border) !important; }
.nodeLabel { color: var(--vic3-owner-text) !important; }
.flowchart-link { stroke: var(--vic3-owner-edge) !important; }
marker path { fill: var(--vic3-owner-edge) !important; stroke: var(--vic3-owner-edge) !important; }
.edgeLabel, .edgeLabel p { color: var(--vic3-owner-text) !important; background: var(--md-default-bg-color) !important; }
---
flowchart TD
F["[C] building_goods_flow"]:::context --> GDP["[M] gdp_weekly *"]:::market
PRICE["[M] market_prices"]:::market --> GDP
GDP --> AGDP["[M] gdp(annual=True)"]:::market
N["[C] pops"]:::context --> EMP["[C] total_employment *"]:::context
EMP --> POP["[C] total_population *"]:::context
R["[C] workforce_ratio"]:::context --> POP
GDP --> GDPC["[S] gdp_per_capita()"]:::snapshot
POP --> GDPC
N --> EP["[C] employment_by_profession *"]:::context
EP --> PS["[C] profession_shares *"]:::context
EMP --> PS
W["[P] pop_wealth"]:::household --> WT["[S] total_wealth_by_profession *"]:::snapshot
N --> WT
WT --> AW["[S] average_wealth *"]:::snapshot
EMP --> AW
WT --> WP["[S] average_wealth_by_profession *"]:::snapshot
EP --> WP
W --> WS["[S] wealth_distribution *"]:::snapshot
N --> WS
AW --> WS
W --> GW["[S] gini_wealth *"]:::snapshot
N --> GW
WT --> TW["[S] total_wealth *"]:::snapshot
R --> TW
Wealth statistics describe integer consumption tiers rather than monetary assets. GDP is production value added; it does not include the exogenous dependent earnings added to household income. Employment-weighted profession totals are cached once and shared by the wealth summaries and population report. The uniform workforce ratio makes per-capita wealth equal to average wealth.