Appendix A: dolo-plus Recipe Specifications (v0.1)¶
This appendix defines the recipe signatures for dolo-plus equation blocks. These recipes specify how the dolo-plus compiler (or a future native dolo-plus solver) should interpret each equation block's inputs, outputs, and slot indices.
These signatures are a specification target for a dolo-plus loader/compiler (and for the dolo-plus → Dolo “horse” translator). Vanilla Dolo does not currently consume these recipe definitions directly.
A.1 Recipe Structure (Background)¶
In Dolo, a recipe entry has the following structure:
block_name:
optional: True/False # Is this block required?
recursive: True/False # Does it reference its own output?
target: [group, slot, binder] # Output: what the equation computes
eqs: # Inputs: function arguments
- [group, slot, binder]
- [group, slot, binder]
- ...
Where:
- group: symbol group name (e.g., states, controls, poststates, prestate, values, shadow_value, exogenous, parameters)
- slot: perch index (-1 = arrival, 0 = decision, +1 = continuation)
- binder: internal argument name used by the compiler (e.g., s, x, p)
Conventions (v0.1):
- In recipes, we write continuation as slot +1 (internally stored as integer 1).
- In stage-mode equations, we prefer perch tags [<] (arrival), unmarked (decision), [>] (continuation). Aliases [_arvl], [_dcsn], [_cntn] are also accepted. The loader normalizes all forms (and also accepts numeric spellings like [1] / [+1]) to canonical slot integers -1/0/1 before dolang parsing/translation (per index_aliases).
- Shocks are recorded as edge events in information_timing; when shocks appear as recipe inputs, we attach them to the perch where they are observed (the observed_at_slot).
A.2 New Symbol Groups in dolo-plus¶
dolo-plus introduces or formalizes the following symbol groups:
| Group | Canonical Slot | Description |
|---|---|---|
prestate |
-1 |
Arrival perch state (ante-state) |
states |
0 |
Decision perch state |
poststates |
+1 |
Continuation perch state |
controls |
0 |
Decision variable(s) |
values |
-1, 0, +1 |
Perch value objects (V[<], V, V[>]) |
shadow_value |
-1, 0, +1 |
Perch shadow-value objects (dV[<], dV, dV[>]) |
exogenous |
(edge) | Shocks; timing via information_timing |
parameters |
0 |
Model parameters |
A.3 Transition Recipes (\(\mathrm{g}_{**}\))¶
These define the within-stage state transitions between perches.
A.3.1 \(\mathrm{g}_{\prec\sim}\) — Arrival-to-Decision Transition¶
dolo-plus label: arvl_to_dcsn_transition
Dolo equivalent: half_transition
Equation example: w = exp(y) + b[<]*r
arvl_to_dcsn_transition:
optional: True
recursive: False
target: ['states', 0, 's'] # Output: decision state w
eqs:
- ['prestate', -1, 'b'] # Input: arrival state b[<]
- ['exogenous', 0, 'y'] # Input: shock y (realized at slot 0)
- ['parameters', 0, 'p']
Signature: \(s_{\sim} = \mathrm{g}_{\prec\sim}(b_{\prec}, y_{\sim}, p)\)
Notes:
- The shock y appears at slot 0 because it is observed at the decision perch (per information_timing).
- In Dolo horse, this maps to half_transition with signature (exog[-1], poststates[-1], exog[0], p) → states[0].
A.3.2 \(\mathrm{g}_{\sim\succ}\) — Decision-to-Continuation Transition¶
dolo-plus label: dcsn_to_cntn_transition
Dolo equivalent: auxiliary_direct_egm
Equation example: a[>] = w - c
dcsn_to_cntn_transition:
optional: True
recursive: False
target: ['poststates', 1, 'a'] # Output: poststate a[>]
eqs:
- ['states', 0, 's'] # Input: decision state w
- ['controls', 0, 'x'] # Input: control c
- ['parameters', 0, 'p']
Signature: \(a_{\succ} = \mathrm{g}_{\sim\succ}(s_{\sim}, x_{\sim}, p)\)
Notes:
- In Dolo horse, auxiliary_direct_egm has the same inputs but targets poststates[0] (Dolo uses slot 0 for current-period poststate). The dolo-plus translator must handle slot normalization.
A.3.3 \(\mathrm{g}_{\sim\succ}^{-1}\) — Continuation-to-Decision Transition (Inverse)¶
dolo-plus label: cntn_to_dcsn_transition
Dolo equivalent: reverse_state
Equation example: w = a[>] + c
cntn_to_dcsn_transition:
optional: True
recursive: False
target: ['states', 0, 's'] # Output: decision state w
eqs:
- ['poststates', 1, 'a'] # Input: poststate a[>]
- ['controls', 0, 'x'] # Input: control c
- ['parameters', 0, 'p']
Signature: \(s_{\sim} = \mathrm{g}_{\sim\succ}^{-1}(a_{\succ}, x_{\sim}, p)\)
Notes: - This is the inverse of \(\mathrm{g}_{\sim\succ}\), used by EGM to map from the continuation grid back to the decision grid.
A.4 Mover Recipes (\(\mathbb{B}\), \(\mathbb{I}\))¶
Movers are backward operators that carry value/shadow-value objects between perches. In dolo-plus v0.1, movers can have multiple sub-equations. Each sub-equation gets its own recipe entry.
Recipe naming convention (v0.1): in the YAML surface syntax, movers may be mapping-valued (e.g. cntn_to_dcsn_mover: {Bellman: | ...}). For recipes (and for translation), each mover sub-equation is treated as a distinct block with a flattened name of the form <mover>_<SubEq> (e.g. cntn_to_dcsn_mover_Bellman).
A.4.1 \(\mathbb{B}\) — Continuation-to-Decision Mover¶
dolo-plus label: cntn_to_dcsn_mover
Sub-equations: Bellman, InvEuler, ShadowBellman
A.4.1.1 \(\mathbb{B}\)[Bellman] — Value Recursion¶
Equation example: V = max_c{(c^(1-γ))/(1-γ) + β*V[>]}
cntn_to_dcsn_mover_Bellman:
optional: True
recursive: True
target: ['values', 0, 'V0'] # Output: decision value V
eqs:
- ['states', 0, 's'] # w
- ['controls', 0, 'x'] # c
- ['values', 1, 'V1'] # V[>] (continuation value input)
- ['parameters', 0, 'p']
Signature: \(\mathrm{V}_{\sim} = \mathbb{B}.\text{Bellman}(s_{\sim}, x_{\sim}, \mathrm{V}_{\succ}, p)\)
Notes:
- Contains implicit maximization operator max_c{...}.
- In Dolo EGM, this is not an explicit equation block; value recursion is handled algorithmically.
A.4.1.2 \(\mathbb{B}\)[InvEuler] — Inverse Euler / Direct Response¶
Dolo equivalent: direct_response_egm
Equation example: c[>] = (β*dV[>])^(-1/γ)
cntn_to_dcsn_mover_InvEuler:
optional: True
recursive: True
target: ['controls', 1, 'x1'] # Output: policy on continuation grid c[>]
eqs:
- ['poststates', 1, 'a'] # a[>] (continuation state)
- ['shadow_value', 1, 'dV1'] # dV[>] (expected marginal value)
- ['parameters', 0, 'p']
Signature: \(x_{\succ} = \mathbb{B}.\text{InvEuler}(a_{\succ}, \mathrm{dV}_{\succ}, p)\)
Notes:
- This is the EGM inversion step: given expected marginal value dV[>], compute optimal control.
- The control is represented on the continuation grid (c[>]), which is the endogenous grid idea.
- controls[1] (and c[>] in equations) is a representation slot (EGM: policy parameterized on the continuation grid), not a semantic claim that the decision is chosen at perch 1 (semantically, controls are chosen at perch 0).
- In Dolo horse, direct_response_egm takes (exog[0], poststates[0], expectations[0], p) → controls[0]. Under the v0.1 convention, the object Dolo calls expectations[0] (often mr) corresponds to the discounted continuation shadow value β*dV[>] (with dV[>] linked to dV[<] across stages). The dolo-plus translator must:
- Map β*shadow_value[>] to Dolo's expectations[0].
- Handle the slot difference (Dolo uses 0, dolo-plus uses [>] / slot +1 for continuation).
A.4.1.3 \(\mathbb{B}\)[ShadowBellman] — Shadow Value at Decision Perch¶
Dolo equivalent: (contributes to RHS of) expectation
Equation example: dV = (c)^(-γ)
cntn_to_dcsn_mover_ShadowBellman:
optional: True
recursive: False
target: ['shadow_value', 0, 'dV0'] # Output: shadow value dV
eqs:
- ['states', 0, 's'] # w
- ['controls', 0, 'x'] # c
- ['parameters', 0, 'p']
Signature: \(\mathrm{dV}_{\sim} = \mathbb{B}.\text{ShadowBellman}(s_{\sim}, x_{\sim}, p)\)
Notes:
- This is the integrand that will be integrated by the \(\mathbb{I}\) mover's expectation operator.
- In the horse, the expectation block typically combines integrand + expectation + discount/return factors into one equation (e.g. mr[t] = β*(c[t+1])^(-γ)*r). In dolo-plus, we split these: dV (at the decision perch) is the integrand, r appears in \(\mathbb{I}\)[ShadowBellman], and β is applied in \(\mathbb{B}\)[InvEuler] via β*dV[>].
A.4.2 \(\mathbb{I}\) — Decision-to-Arrival Mover (Expectation Location)¶
dolo-plus label: dcsn_to_arvl_mover
Sub-equations: Bellman, ShadowBellman
A.4.2.1 \(\mathbb{I}\)[Bellman] — Value Expectation¶
Equation example: V[<] = E_y(V)
dcsn_to_arvl_mover_Bellman:
optional: True
recursive: False
target: ['values', -1, 'Vm1'] # Output: arrival value V[<]
eqs:
- ['exogenous', 0, 'y'] # Shock to integrate over
- ['values', 0, 'V0'] # V (post-shock value)
- ['parameters', 0, 'p']
Signature: \(\mathrm{V}_{\prec} = \mathbb{I}.\text{Bellman}(y, \mathrm{V}_{\sim}, p) = \mathbb{E}_y[\mathrm{V}_{\sim}]\)
Notes:
- Contains explicit expectation operator E_y(·).
- In Dolo EGM, this is not an explicit equation block; value expectation is handled algorithmically.
A.4.2.2 \(\mathbb{I}\)[ShadowBellman] — Shadow Value Expectation¶
Dolo equivalent: expectation (LHS / output side)
Equation example: dV[<] = r * E_y(dV)
dcsn_to_arvl_mover_ShadowBellman:
optional: True
recursive: False
target: ['shadow_value', -1, 'dVm1'] # Output: arrival shadow value dV[<]
eqs:
- ['exogenous', 0, 'y'] # Shock to integrate over
- ['shadow_value', 0, 'dV0'] # dV (post-shock shadow value)
- ['parameters', 0, 'p']
Signature: \(\mathrm{dV}_{\prec} = \mathbb{I}.\text{ShadowBellman}(y, \mathrm{dV}_{\sim}, p) = r \cdot \mathbb{E}_y[\mathrm{dV}_{\sim}]\)
Notes:
- Contains explicit expectation operator E_y(·).
- In Dolo horse, this maps to expectation: | mr[t] = β*(c[t+1])^(-γ)*r. The Dolo horse combines:
- The integrand (from \(\mathbb{B}\).ShadowBellman)
- The expectation (performed algorithmically)
- The output (mr[t] = expectations[0])
- and it typically includes the discount factor β as part of mr; under the v0.1 convention, mr ≈ β*dV[<] (equivalently β*dV[>] after inter-stage linking).
A.5 Mapping to Dolo Horse Recipes (Translation Reference)¶
When translating dolo-plus to vanilla Dolo for the horse solver, use this mapping:
| dolo-plus Recipe | Dolo Horse Block | Notes |
|---|---|---|
arvl_to_dcsn_transition |
half_transition |
Slot normalization: Dolo uses poststates[-1], dolo-plus uses prestate[-1] |
dcsn_to_cntn_transition |
auxiliary_direct_egm |
Slot normalization: Dolo targets poststates[0], dolo-plus targets poststates[+1] |
cntn_to_dcsn_transition |
reverse_state |
Direct mapping |
cntn_to_dcsn_mover[InvEuler] |
direct_response_egm |
Map β*shadow_value[>] → expectations[0] |
cntn_to_dcsn_mover[ShadowBellman] + dcsn_to_arvl_mover[ShadowBellman] |
expectation |
Combine integrand and expectation output |
cntn_to_dcsn_mover[Bellman] |
(implicit) | Not explicit in Dolo EGM YAML |
dcsn_to_arvl_mover[Bellman] |
(implicit) | Not explicit in Dolo EGM YAML |
A.6 Slot Normalization Notes¶
Dolo and dolo-plus use slightly different slot conventions:
| Concept | Dolo Slot | dolo-plus Slot |
|---|---|---|
| Previous-period poststate | -1 |
-1 (via prestate group) |
| Current-period state | 0 |
0 |
| Current-period poststate | 0 |
+1 |
| Next-period state | +1 (or 1) |
— (inter-stage link) |
The dolo-plus translator must normalize slots when generating Dolo horse YAML:
- poststates[+1] in dolo-plus → poststates[0] in Dolo (for auxiliary_direct_egm)
- prestate[-1] in dolo-plus → poststates[-1] in Dolo (for half_transition)
A.7 Full dolo-plus Recipe YAML (for recipes_doloplus.yaml)¶
doloplus_adc_stage:
model_spec: doloplus_adc_stage
symbols: ['exogenous', 'prestate', 'states', 'poststates', 'controls',
'values', 'shadow_value', 'parameters']
specs:
# ========== Transitions (g) ==========
arvl_to_dcsn_transition: # g_{<o}
optional: True
recursive: False
target: ['states', 0, 's']
eqs:
- ['prestate', -1, 'b']
- ['exogenous', 0, 'y']
- ['parameters', 0, 'p']
dcsn_to_cntn_transition: # g_{o>}
optional: True
recursive: False
target: ['poststates', 1, 'a']
eqs:
- ['states', 0, 's']
- ['controls', 0, 'x']
- ['parameters', 0, 'p']
cntn_to_dcsn_transition: # g_{o>}^{-1}
optional: True
recursive: False
target: ['states', 0, 's']
eqs:
- ['poststates', 1, 'a']
- ['controls', 0, 'x']
- ['parameters', 0, 'p']
# ========== Mover B sub-equations ==========
cntn_to_dcsn_mover_Bellman: # B[Bellman]
optional: True
recursive: True
target: ['values', 0, 'V0']
eqs:
- ['states', 0, 's']
- ['controls', 0, 'x']
- ['values', 1, 'V1']
- ['parameters', 0, 'p']
cntn_to_dcsn_mover_InvEuler: # B[InvEuler]
optional: True
recursive: True
target: ['controls', 1, 'x1']
eqs:
- ['poststates', 1, 'a']
- ['shadow_value', 1, 'dV1']
- ['parameters', 0, 'p']
cntn_to_dcsn_mover_ShadowBellman: # B[ShadowBellman]
optional: True
recursive: False
target: ['shadow_value', 0, 'dV0']
eqs:
- ['states', 0, 's']
- ['controls', 0, 'x']
- ['parameters', 0, 'p']
# ========== Mover I sub-equations ==========
dcsn_to_arvl_mover_Bellman: # I[Bellman]
optional: True
recursive: False
target: ['values', -1, 'Vm1']
eqs:
- ['exogenous', 0, 'y']
- ['values', 0, 'V0']
- ['parameters', 0, 'p']
dcsn_to_arvl_mover_ShadowBellman: # I[ShadowBellman]
optional: True
recursive: False
target: ['shadow_value', -1, 'dVm1']
eqs:
- ['exogenous', 0, 'y']
- ['shadow_value', 0, 'dV0']
- ['parameters', 0, 'p']