RECURSIVE PROBLEM DEFINITION¶
Stages and Their Structure: - A stage is defined by three fundamental components: 1. Static Perches: Three static collections of state spaces and functions: - Arrival perch: State space π§β and arrival value function π(xβ) - Decision perch: State space π§α΅₯, decision value function π±(xα΅₯), and policy function - Continuation perch: State space π§β and continuation value function β°(xβ)
-
Transition Functions: Mappings between perch state spaces:
- Arrival β Decision: gβα΅₯ maps xβ (and possibly ΞΆ) to xα΅₯
- Decision β Continuation: gα΅₯β maps (xα΅₯, π) (and possibly ΞΆ) to xβ
-
Operational Processes: Mathematical operators that use the transitions:
- Expectation operator for arrival: E_ΞΆ[Β·] applied to π±(gβα΅₯(xβ, ΞΆ))
- Maximization operator for decision: max_π{Β·} applied to r(xα΅₯, π) + Ξ²(xα΅₯)β°(gα΅₯β(xα΅₯, π))
-
The stage is fully defined only when all three components (perches, transitions, and operators) are specified
- The sequential flow through a stage involves applying these operators along with transitions:
- At arrival: Agent has state xβ β π§β, then shock ΞΆ realizes
- At decision: Agent observes state xα΅₯ = gβα΅₯(xβ,ΞΆ) and makes choice π β Ξ (xα΅₯)
- At continuation: Stage concludes with state xβ = gα΅₯β(xα΅₯, π)
- Each perch has an associated state space
- Within-stage perch transitions (with directional mapping functions):
- Arrival β Decision: gβα΅₯ maps (xβ, ΞΆ) to xα΅₯
- Decision β Continuation: gα΅₯β maps (xα΅₯, π) to xβ
- Each stage is defined independently of its position in any period sequence
- Within a stage:
- Parameters π have fixed values
- The continuation value function β° is taken as given
- All functions and variables are defined solely in terms of internal structure
- Only within-stage perch transitions (gβα΅₯ and gα΅₯β) are specified
- Connector functions (gβββ and gα΅₯ββ) are defined at period level
Shock Spaces and Timing: Each stage has two shock spaces, one for each within-stage transition: - π΅βα΅₯: Shock space for the arvlβdcsn transition (may be trivial: π΅βα΅₯ = {β }) - π΅α΅₯β: Shock space for the dcsnβcntn transition (may be trivial: π΅α΅₯β = {β })
The general transition function signatures are: - gβα΅₯: π§β Γ π΅βα΅₯ β π§α΅₯ (arrival to decision, with pre-decision shocks ΞΆβα΅₯) - gα΅₯β: π§α΅₯ Γ Ξ Γ π΅α΅₯β β π§β (decision to continuation, with post-decision shocks ΞΆα΅₯β)
When a shock space is trivial, the corresponding argument is omitted from notation.
Common Shock Configurations:
| Configuration | π΅βα΅₯ | π΅α΅₯β | Example | Value Function Structure |
|---|---|---|---|---|
| Pre-decision only | non-trivial | trivial | Standard cons | π(xβ) = E_{ΞΆβα΅₯}[π±(gβα΅₯(xβ, ΞΆβα΅₯))] |
| Post-decision only | trivial | non-trivial | port-with-shocks | π±(xα΅₯) = max_π E_{ΞΆα΅₯β}[r + Ξ² β°(gα΅₯β(xα΅₯, π, ΞΆα΅₯β))] |
| Both transitions | non-trivial | non-trivial | (general case) | π(xβ) = E_{ΞΆβα΅₯}[max_π E_{ΞΆα΅₯β}[...]] |
| Deterministic | trivial | trivial | Pure computation | π±(xα΅₯) = max_π{r + Ξ² β°(gα΅₯β(xα΅₯, π))} |
Unless otherwise specified, the default notation in this document uses pre-decision timing (π΅βα΅₯ non-trivial, π΅α΅₯β trivial). Specific examples will note their shock configuration explicitly in their Rosetta Stone tables.
Period and Stage Notation Rules: - Use πβ and β°β to denote the terminal period and its value function - these are special cases that serve as anchors for backward induction - Subscript plus (β) denotes the next stage relative to the current stage: - For states: xββ denotes the arrival state of the next stage - For periods: πβ denotes the stages of the next period - For value functions: β°β denotes the continuation value for the next stage - Stage positions [i] are shown only when emphasizing specific positions in a sequence: - [0] for the first stage of a period - [-1] for the last stage of a period - When describing period structure: π[0], π[1], β¦, π[-1] - Stage kind ΞΊ is shown only when emphasizing transitions between different kinds - Time period t is shown only when emphasizing inter-period relationships - Otherwise these indices are omitted for clarity when discussing a stage's internal structure - Value function notation: - General form: π±β(s, xα΅₯) shows dependence on time and stage - Stage-specific forms: - π(xβ): Value at arrival state, before shock realization - π±(xα΅₯): Value at decision state, after shock but before choice - β°(xβ): Value at continuation state, after choice but before transition - Value function relationships: - At arrival states: π(xβ) = E_ΞΆ[π±(gβα΅₯(xβ, ΞΆ))] - At decision states: - Sequential within period: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)β°(gα΅₯β(xα΅₯, π))} - Sequential at period end: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)πβ(gβββ(gα΅₯β(xα΅₯, π)))} - Branching stages: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)β_{jβNβ} p(j|xα΅₯,π)πββ±Ό(gα΅₯ββ(xα΅₯, π))} where πββ±Ό is the arrival value function for stage kind j β Nβ - Subscript plus indicates next stage's value function - For terminal period: β°β(xβ) is specified directly - For branching stages: - Each possible next stage j β Nβ has its own arrival value function πββ±Ό - Expected continuation value is probability-weighted sum across branches - Value functions must be compatible with stage kind of each branch
Period Structure: - A period π consists of an ordered sequence of stages: π[0], π[1], β¦, π[-1] - Sequential stages follow this ordering directly - Branching stages can transition to: - Within period: Any stage with higher index in π - Between periods: Any stage in πβ[0], πβ[1], β¦, πβ[-1] - Stage positions [i] are shown when emphasizing sequence position - Time period t is shown when emphasizing inter-period relationships
Modularity Principle: - Stages are independent, reusable modules that define only their internal structure - Stages define only their internal transitions (gβα΅₯ and gα΅₯β) - Connector functions (gβββ and gα΅₯ββ) must be defined at the period or problem-assembly level - This separation ensures stages remain reusable modules, agnostic to how they connect to other stages
Connector Functions:
Terminology note: This document uses the single term connector for all rename/composition adapters that link stages or periods, qualified by scope: within-period connectors map between stages in the same period, while between-period connectors map from one period's continuation to the next period's arrival. Both are structurally identical β bijective maps on the variable namespace. Some other documents in this codebase (notably spec_0.1h-periods-nests.md and the builder code) use the term twister for what this document calls a "between-period connector," reserving "connector" for within-period mappings only. The distinction is purely one of scope, not of mathematical structure.
- Abstract Definition:
- Connector functions map states from one stage to arrival states of the next stage
- Two types based on stage kind:
- Sequential: gβββ: π§β β π§ββ maps from continuation to next arrival
- Branching: gα΅₯ββ: π§α΅₯ Γ Ξ β π§ββ maps from decision to next arrival
-
When the target stage has optional state components (π§βα΅α΅α΅β₯), the connector function may either provide a value in π§βα΅α΅α΅ or map to β₯. This choice is made at the period level when assembling stages.
-
Stage Positions:
- Added when emphasizing sequence position
- Sequential case: gβββ(π[-1]): π§β(π[-1]) β π§ββ(πβ[0])
-
Branching case: gα΅₯ββ(π[-1]): π§α΅₯(π[-1]) Γ Ξ β π§ββ(πβ[j]) for j β Nβ
-
Stage Kinds:
- Sequential case: gβββ maps to unique next stage
- Branching case: gα΅₯ββ maps to possible next stages, selection via p(j|xα΅₯,π)
-
Source stage kind is always understood from context
-
Compatibility:
- Nβ denotes the set of stage kinds that can meaningfully follow the current stage
- For sequential stages:
- |Nβ| = 1 as there is exactly one valid next stage
- Within period: Nβ = {ΞΊ(π[i+1])} where ΞΊ(s) denotes kind of stage s
- Between periods: Nβ = {ΞΊ(πβ[0])} where πβ is the next period
- For branching stages:
- Nβ is constrained by position and period structure:
- Within period: Nβ β {ΞΊ(π[j]) | j > i} where i is current position
- Between periods: Nβ β {ΞΊ(πβ[j]) | j β₯ 0} where πβ is next period
- |Nβ| β₯ 1 with probabilities p(j | xα΅₯, π) for each j β Nβ
- Probabilities must respect Nβ constraints:
- Only assign positive probability to valid next stages
- Conservation: β_{jβNβ} p(j|xα΅₯,π) = 1 ensures all mass transitions
- Connector function gα΅₯ββ must be well-defined for all j β Nβ
Setup: - Define the set of stage kinds Ξ and assign each kind a type (Sequential or Branching) - For each stage kind ΞΊ β Ξ, define the following objects: - State spaces: - π§β: Arrival states - π§α΅₯: Decision states - π§β: Continuation states - Shock spaces (see "Shock Spaces and Timing" above): - π΅βα΅₯: Shock space for arvlβdcsn transition, with measure Pβα΅₯(ΞΆβα΅₯) - π΅α΅₯β: Shock space for dcsnβcntn transition, with measure Pα΅₯β(ΞΆα΅₯β) - Either or both may be trivial (π΅ = {β }) - Within-stage perch transitions (with directional mapping functions): - gβα΅₯: π§β Γ π΅βα΅₯ β π§α΅₯ maps arrival and shock to decision state - gα΅₯β: π§α΅₯ Γ Ξ Γ π΅α΅₯β β π§β maps decision, choice, and shock to continuation state - Economic primitives: - Choice set Ξ (xα΅₯) for each decision state - Reward function r(xα΅₯, π) - Discount factor Ξ²(xα΅₯) - For branching stages only: - Branching probabilities p(j | xα΅₯, π) for each j β Nβ
Branching Probabilities: - Individual Level (Decision-Making): - Each agent in decision state xα΅₯ choosing π: - Can only transition to stages j β Nβ - Faces transition probabilities p(j|xα΅₯,π) for each eligible j - Probabilities must respect stage ordering: - Within period: Only to higher-index stages to prevent loops - Between periods: Only to stages present in next period - Must satisfy β_{jβNβ} p(j|xα΅₯,π) = 1 for all xα΅₯, π
- Population Level (Aggregation):
- Same probabilities determine population distribution:
- For all branching transitions: Via gα΅₯ββ for each branch j β Nβ
- Conservation properties:
- Preserves population mass: β_{jβNβ} ΞΌβββ±Ό(π§β) = ΞΌα΅₯(π§α΅₯)
- Preserves measure normalization: If E_ΞΌα΅₯[1] = 1 then E_ΞΌββ[1] = 1
Dispatch (deterministic routing by inherited state):
When the branch is determined by an inherited discrete state component ΞΉ β π₯ (rather than by optimization or exogenous randomness), the branching probability degenerates to:
p(j | xα΅₯, Ο) = π[j = ΞΉ]
where ΞΉ is a component of xα΅₯. The decision value function becomes:
π±(xα΅₯) = π±_{succ,ΞΉ}(g_ΞΉ(xα΅₯))
This is the "dispatch" mode β deterministic routing based on an inherited state component. It arises naturally when a previous period's divergent branching produces tagged union exit states (a, ΞΉ), and the current period must route agents to the appropriate branch based on ΞΉ. The dispatch mode is distinguished from stochastic branching (no probability weighting β each agent goes to exactly one branch with certainty) and from choice/optimization-based branching (the branch selection is not value-maximizing β it is determined by inherited state).
Optional State Components:
A stage's arrival state space may include components that are not always provided by the preceding connector function. Formally, the arrival state space may decompose as:
π§β = π§βΚ³α΅α΅ Γ π§βα΅α΅α΅β₯
where: - π§βΚ³α΅α΅ is the space of required components (always provided by the connector) - π§βα΅α΅α΅β₯ = π§βα΅α΅α΅ βͺ {β₯} is the space of optional components, extended with the sentinel value β₯ ("absent")
Because β₯ is a point in the extended space π§βα΅α΅α΅β₯, the full arrival state space remains a fixed-dimensional product space. All existing mathematical machinery β population measures, bijectivity conditions, contraction arguments β applies to this extended space without modification.
When an optional component equals β₯, the stage determines that component internally. The specific semantics are defined per-stage. Common patterns include: - Optimize when absent: The stage treats the absent component as a choice variable and optimizes over it. When the component is provided, the choice set collapses to the singleton {provided value}. - Default when absent: The stage substitutes a default value. When the component is provided, it uses the given value.
For instance, a portfolio-and-returns stage may accept an optional portfolio share ΟΜ β [0,1] βͺ {β₯} as part of its arrival state. When ΟΜ is provided, the stage uses that fixed share for transitions; when ΟΜ = β₯, the stage optimizes over Ο. In both cases the stage can compute and report the optimal share as auxiliary output.
Although arrival states are the most common case, the same decomposition can apply to any perch state space. When stages have no optional components (the default), π§βα΅α΅α΅ is empty and π§β = π§βΚ³α΅α΅ , reducing to the standard formulation used throughout this document.
State Transitions and Population Dynamics:
The transition functions defined above (gβα΅₯, gα΅₯β, gβββ, gα΅₯ββ) induce a corresponding evolution of population measures through the stage structure. At each transition: - Individual-level state mappings are bijective (for each fixed shock realization) - Population measures evolve via pushforward through the transition functions - Mass and normalization are conserved through all transitions
For the complete specification of measure evolution formulas and conservation properties, see the Population Dynamics section. Key results used here: - Within-stage: ΞΌα΅₯(B) = E_ΞΌβ[P({ΞΆβα΅₯: gβα΅₯(xβ,ΞΆβα΅₯) β B})] and ΞΌβ(C) = E_ΞΌα΅₯[1{gα΅₯β(xα΅₯,π(xα΅₯)) β C}] - Sequential between-stage: ΞΌββ(A) = E_ΞΌβ[1{gβββ(xβ) β A}] - Branching between-stage: ΞΌβββ±Ό(A) = E_ΞΌα΅₯[p(j|xα΅₯,π(xα΅₯))1{gα΅₯ββ(xα΅₯,π*(xα΅₯)) β A}]
Terminal period: No transitions from final stage πβ[-1]; terminal value β°β(xβ) specified directly.
Simulate Forward - Starting from initial population measure ΞΌββ°, iterate through stages: - Apply within-stage perch transitions: 1. Arrival β Decision using gβα΅₯ 2. Decision β Continuation using gα΅₯β - Apply between-stage transitions: - For sequential stages: Use gβββ - For branching stages: Sample j β Nβ, then use gα΅₯ββ - Update population measures according to transition formulas - Continue until reaching termination condition
Construct and Solve Final Period: - Define the stages πβ for the final period - For the final stage πβ[-1]: - Specify terminal value function β°β(xβ) over π§β(πβ[-1]) - Solve backward through stages s β πβ: 1. At each decision state xα΅₯: - For sequential stages within period: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)β°(gα΅₯β(xα΅₯, π))} - For sequential stages at period end: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)πβ(gβββ(gα΅₯β(xα΅₯, π)))} - For branching stages (both within period and between periods): π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)β_{jβNβ} p(j|xα΅₯,π)πββ±Ό(gα΅₯ββ(xα΅₯, π))} 2. At each arrival state: π(xβ) = E_ΞΆ[π±(gβα΅₯(xβ, ΞΆ))]
Construct and Solve Earlier Periods Recursively: - For each period t, working backward from the final period: - Define the stages π for period t (e.g., π[0], π[1], β¦, π[-1]) - Define period-level connector functions: - For sequential stages at period end: gβββ: π§β(π[-1]) β π§β(πβ[0]) Maps continuation states to arrival states of next period's first stage - For branching stages: gα΅₯ββ: π§α΅₯(π[-1]) Γ Ξ β π§β(πβ[j]) for each j β Nβ Maps decision states to arrival states of all possible next stages - Define the stochastic shock distributions for each stage in period t - Solve the problem for period t using backward induction: 1. At each decision state xα΅₯: - For sequential stages within period: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)β°(gα΅₯β(xα΅₯, π))} - For sequential stages at period end: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)πβ(gβββ(gα΅₯β(xα΅₯, π)))} - For branching stages: π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)β_{jβNβ} p(j|xα΅₯,π)πββ±Ό(gα΅₯ββ(xα΅₯, π))} 2. At each arrival state: π(xβ) = E_ΞΆ[π±(gβα΅₯(xβ, ΞΆ))] - Use arrival value functions πβ(xβ) from all possible next stages
Recursive Process: - Continue backward induction until reaching either: - A chosen starting point (e.g., in life-cycle models), or - A steady state determined by convergence criteria: - Value function convergence: Compare successive iterations - Policy function stability: Check for changes in optimal choices - Population measure stability: Track distribution changes - Specific criteria depend on application needs - At each step, ensure: - Sequential transitions preserve stage ordering - Branching transitions respect valid next-stage constraints - Population measures maintain required properties - Value functions properly account for all possible transitions
Specify Initial Conditions: - Define the initial population measure ΞΌββ° over the arrival state space π§β(π[0]) - The measure must be: - Non-negative: ΞΌββ°(A) β₯ 0 for all measurable A - Normalized: E_ΞΌββ°[1] = 1 - Defined on the Borel Ο-algebra β¬(π§β)
Value Function Solution Approaches¶
The decision value function equation:
π±(xα΅₯) = max_π{r(xα΅₯, π) + Ξ²(xα΅₯)β°(gα΅₯β(xα΅₯, π))}
May be solved through different algorithmic approaches:
- Direct maximization: Explicitly search for the optimal π
- First-order conditions: When the problem is differentiable:
- βr/βπ(xα΅₯, π) + Ξ²(xα΅₯)(ββ°/βxβ)(gα΅₯β(xα΅₯, π))β_πgα΅₯β(xα΅₯, π) = 0
- Endogenous grid methods: Work backwards from continuation values to decision states
- Parametric approximation: Approximate the policy function with basis functions
Each approach represents the same mathematical concept but with different computational properties.
Computational Implementation Notes¶
The mathematical recursive problem definition maps to computational objects as follows:
Stage Implementation¶
A mathematical stage maps to a stage instance in code:
# Create a computational representation of a stage
stage = Stage(stage_path="configs/stages/example")
Each stage contains three perch instances representing the three mathematical perches:
# The three perches map to mathematical state spaces and value functions
stage.perch_arvl # Implements π§β and π(xβ)
stage.perch_dcsn # Implements π§α΅₯, π±(xα΅₯), and policy function
stage.perch_cntn # Implements π§β and β°(xβ)
Transition Implementation¶
Mathematical transition functions map to mover instances:
# Transitions between perches in a stage
stage.mover_arvl_to_dcsn # Implements gβα΅₯
stage.mover_dcsn_to_cntn # Implements gα΅₯β
For each mover instance, the purely mathematical information it implements (the transition functions gβα΅₯, gα΅₯β, the pushforward formulas, and any related operator definitions given elsewhere in this document) is that mover's mover-specβthe collection of all mathematical information needed to execute the corresponding forward or backward act of creation.
Transitions, Connectors, and Movers¶
It is important to distinguish three kinds of objects:
- Transitions (gβα΅₯, gα΅₯β): Mathematical functions mapping state variables between perches within a stage.
- Connectors (π / π²): Objects that link stages or periods. The mathematical connector π is a pure namespace mapping (e.g., π(k_{t+1} β a_t)) defined at model-specification time. The computational connector π² is the runtime object carrying the mapping plus bridging metadata. Connectors are passive once created and do not hold value functions.
- Movers (πΌβ, πΌβ): Computational processes (mover-comps) that, when evaluated, use connectors and mover-specs to create new computational objects. The backward mover πΌβ constructs and populates value functions on upstream perches; the forward mover πΌβ propagates distributions forward. Subscripts indicate (source, target) for the flow: between-period backward πΌβ{a+,e}, within-period backward πΌβ; between-period forward πΌβ{e,a+}, within-period forward πΌβ.
Note that backward induction is a sequence of backward mover (πΌβ_prd) invocations, each using a connector and populating perches on the current period. Whether the user's code creates the connector as a separate step or the backward mover creates it implicitly is a design choice (see computational-framework.md).
Contract: Pre/Postconditions for Composability¶
A contract specifies the preconditions that must hold before a mover or connector can operate, and the postconditions it guarantees upon completion. This concept, inspired by Hoare logic ({P} C {Q}), ensures composability: stages and periods can be freely reordered or substituted so long as contracts are satisfied.
Example β Shock-free consumption stage backward mover: - Precondition {P}: Continuation-value function v_cntn(a) exists on the cntn perch. - Postcondition {Q}: Arrival-value function v_arvl(m) and optimal policy c(m) exist on the arvl and dcsn perches respectively, with v_arvl(m) = πΌ[v_dcsn(m)] and c(m) = argmax_c{u(c) + v_cntn(mβc)}.
Computational Functions¶
The computational functions are exposed through the .comp attribute:
# Access mathematical functions in computational form
stage.perch_arvl.comp.value_function(state) # Implements π(xβ)
stage.perch_dcsn.comp.value_function(state) # Implements π±(xα΅₯)
stage.perch_dcsn.comp.dcsn_rule(state) # Implements policy function
stage.perch_cntn.comp.value_function(state) # Implements β°(xβ)
Solution Process vs. Mathematical Structure¶
The mathematical formulation describes operators (maximization, expectation) applied to value functions. In the computational implementation, these operations are handled by the whisperer and horse:
# Mathematical operators are implemented internally by the whisperer/horse
whisperer.solve_stage(stage) # Implements both maximization and expectation
Branching Implementation¶
Mathematical branching (where an agent's state might evolve in multiple possible ways) is implemented using a DAG structure in the computational framework:
# Create period with branching stages
period = Period(period_id="example")
period.add_stage("consumption", consumption_stage)
period.add_stage("portfolio", portfolio_stage)
period.add_stage("work", work_stage)
# Define mathematical branching through connections
period.connect_stages("consumption", "portfolio")
period.connect_stages("consumption", "work")
This implementation note provides a bridge between the abstract mathematical concepts and their concrete computational representations, helping users translate between the mathematical formulation and code implementation.