0.4 Periods and models¶
This section defines how stages are assembled into periods and models at the syntax level.
The underlying theory is developed in Composition as Twister, which adopts a Backus-style "algebra of programs" viewpoint:
- Stages and periods are programs (operators on state spaces)
- Composition is the combining form
- Twisters are not auxiliary wiring — they are the composition operation
In Dolang+ terms: a period is stage-composition (intra-period), a model is period-composition (inter-period), both governed by interface-compatibility.
0.4.0 Composition as twister (foundation)¶
We write the typed composition of two modules \(S_1, S_2\) as \(\langle S_1, S_2 \rangle\).
Interfaces and typing¶
Let:
- \(X_{\mathrm{arvl}}(S)\) denote the arrival field of \(S\) (inputs \(S\) expects)
- \(X_{\mathrm{cntn}}(S)\) denote the continuation field of \(S\) (outputs \(S\) provides) Composition is defined when interfaces match (up to bijective rename):
Informally, we will also say a period is defined by uniquely valid compositions such as \(\langle S_1, S_2 \rangle\).
Terminology (fields). We use field to denote an economic quantity defined over an underlying probability space—formally, an element of \(L^{2}(\Omega)\), for example. for example. For instance, assets \(a \in L^{2}(\Omega)\) is a field. In contrast, "variable" often connotes a scalar \(a \in \mathbb{R}\), which is not a fixed mathematical object but a placeholder. Fields are fixed objects admitting well-defined logical and algebraic operations.
Why fields matter for composition. Defining composition \(\langle S_1, S_2 \rangle\) requires that continuation and arrival interfaces refer to the same underlying object. Defining composition as "the continuation variable name equals the arrival variable name" is ill-posed: label names are not primitives in an MDP. Fields (random variables over a common filtration) are. Stage compositions is thus unambiguously defined through an isomorphism of a field, not a string equality.
Identity vs explicit twisters¶
When names match, the twister is identity and may be omitted:
When names differ but interfaces are isomorphic, insert an explicit adapter \(\tau\):
Notation¶
| Syntax | Meaning |
|---|---|
| \(\langle S_1, S_2 \rangle\) | Compose with implicit identity twister |
| \(\langle S_1, \tau, S_2 \rangle\) | Compose with explicit twister \(\tau\) |
| \(P = \langle S_1, S_2, S_3 \rangle\) | Period as composition of stages |
| \(M = \langle P_0, \tau_0, P_1, \tau_1, \ldots, P_T \rangle\) | Model as composition of periods |
Default inter-stage wiring (v0.1 convention)¶
At the surface syntax level, a stage is a stage-local module: it declares perch-local fields and equations without explicit global time subscripts. Time enters only through composition (periods/nests).
In v0.1, the default sequential wiring between adjacent stage occurrences \(S_1\) (earlier) and \(S_2\) (later) is:
- Forward (state) interface: the continuation perch of \(S_1\) supplies the arrival perch of \(S_2\) (up to rename).
In perch-slot notation, with an explicit adapter \(\tau\):
When interfaces match by name, \(\tau\) is identity and is omitted.
Value-function wiring (backward interface)¶
Backward induction wires value objects in the opposite direction:
- Backward (value) interface: the arrival value produced by the successor stage is the continuation value consumed by the predecessor stage (up to pullback by the same adapter).
Schematically:
The same wiring applies to any shadow / marginal value objects (e.g. dV).
Stationary fixed-point special case. In a single-stage stationary model, the “successor” is the stage itself, so the recursion identifies output with input:
MDP well-formedness guarantee (typing first)¶
At the syntax level, a composed period/nest is well-formed if each adjacent interface match is witnessed by an identity or a rename isomorphism. Under this condition, the composition defines a valid Bellman problem (the remaining analytic assumptions—measurability, integrability, etc.—belong to the semantic layer, not the wiring layer).
This is a declarative specification: it says what the model is. Solving (backward induction, fixed-point iteration) is an interpreter concern.
0.4.1 Period templates¶
A period template is a timeless syntax directive. It declares:
| Field | Description |
|---|---|
name |
Template identifier |
stages |
Ordered list of stage objects (not references) |
connectors |
(optional) Intra-period adapters for name mismatches |
Key principle: The stages: list contains nested stage objects, not symbolic references via a ddsl syntax (although in practice, one may nest stages into a period in a variety of ways, via links for example or dicts). Each entry is either an inline stage definition or a YAML anchor/file inclusion that resolves to a complete stage. The period is defined by the stages it contains, not by names pointing elsewhere.
Rule (v0.1h): If adjacent stage interfaces have matching names, the connector is identity and must be omitted. Connectors exist only for name mismatches; inter-period wiring is handled by twisters, not by period templates.
Example: single-stage period¶
The tag !stage indicates that the value is a stage object (resolved from a file, anchor, or inline definition). The key cons_stage is an occurrence name scoped to this period—it is not a global reference.
Example: multi-stage period with rename connector¶
name: cons_port_period
stages:
- cons_stage: !stage # first stage occurrence
- port_stage: !stage # second stage occurrence
connectors:
- from: cons_stage
to: port_stage
rename: {a: k}
Here cons_stage and port_stage are local occurrence names within this period. The connector's from/to fields refer to these local names, not to external templates.
Branching (deferred)¶
v0.1h treats stages: as an ordered list. Within-period graphs with branching or merging are deferred to a future layer.
0.4.2 Nest¶
A nest declares a sequential composition of period objects together with inter-period twisters.
| Field | Description |
|---|---|
name |
Nest identifier |
periods |
Ordered list of period objects (not references) |
twisters |
Position-aligned list of inter-period adapters |
Key principle: The periods: list contains nested period objects. A nest is not a list of template names; it is a collection of period instances (each containing its own stage objects). The nest is the composition structure.
Convention (v0.1h): twisters[i] connects periods[i] to periods[i+1] in forward time. Hence twisters carry no from/to fields — position determines adjacency.
Example: minimal nest template¶
name: lifecycle_cons_example
periods:
- !period # period object at position 0
- !period # period object at position 1
- !period # period object at position 2
- !period # period object at position 3
- !period # period object at position 4
twisters:
- {a: k}
- {a: k}
- {a: k}
Each !period tag resolves to a complete period object. The nest contains four period instances; their identity is determined by their position in the list, not by any name field.
Example: explicit period nesting¶
name: lifecycle_cons_example
periods:
- !period
name: p0
stages:
- cons_stage: {!stage}
- !period
name: p1
stages:
- cons_stage: !stage
- !period
name: p2
stages:
- cons_stage: !stage
twisters:
- rename: {a: k}
- rename: {a: k}
The name: fields within periods are optional labels for documentation; they do not affect composition semantics. Composition is determined by list position and twister alignment.
Optional repeat: sugar¶
name: lifecycle_cons_example
periods:
- period: cons_period
repeat: 4
twisters:
- rename: {a: k}
repeat: 3
This is builder-level sugar; v0.1h does not require it.
Critical constraint: Time indices (age, \(t\), horizon counters) do not appear in stage or period templates. They belong to the builder/orchestration layer.
0.4.3 Connectors and twisters¶
Connectors (intra-period)¶
A connector is an adapter between adjacent stages within a period. Semantically it is an intra-period twister.
If upstream output names equal downstream input names, the connector is identity and should be omitted.
Twisters (inter-period)¶
A twister specifies how adjacent periods are connected. In v0.1h it is typically a pure rename (possibly empty for identity).
Identity twister (omit rename or use empty map):
Abstractly, a twister is a state-space map
This map induces:
- Pullback on value objects: \((g_{ca}^* V)(x) = V(g_{ca}(x))\)
- Pushforward on distributions: \((g_{ca})_* \mu\)
In v0.1h most twisters are pure renames. Richer "computed" twisters (aging counters, regime switches) are possible but the wiring-only principle remains: do not embed discounting or economics in twisters.
0.4.4 Model as bindings (semantic contract)¶
A model is a collection of: 1. Stages — possibly with attached calibration, methodization, settings 2. Periods — ordered compositions of stages 3. Twisters — inter-period adapters This definition is representation-agnostic. Valid materializations include:
- A folder tree with YAML files
- Python dicts built incrementally
- A single serialized object
- Any form preserving the semantic contract
DDSL specifies what bindings must exist, not how they are produced.
Binding types¶
For a fully instantiated (solvable) model, each stage is expected to have:
| Binding | Description |
|---|---|
| SYM | Mathematical content: ADC perches, equations, symbol declarations |
| Calibration | Parameter values |
| Methodization | Scheme/method pairings for operators |
| Settings | Numerical settings (grid sizes, tolerances) |
| ### Degrees of instantiation |
Stages (and models) exist at increasing "status" levels:
- Mathematized: SYM only
- Calibrated: SYM + parameter bindings
- Methodized/configured: SYM + calibration + methodization + settings
- Solved: computational artifacts attached
This is a conceptual ladder, not a prescribed class hierarchy.
0.4.5 Stage-level bindings¶
Calibration, methodization, and settings are bound at the stage level, not the period level.
Consequences: - Each stage is self-contained at every instantiation level - A period is the union of its constituent stages - There is no "period-level calibration" that overrides stage calibrations
Benefits:
- Modularity: stages reusable across periods
- Clarity: parameters, methods, settings co-located
- Testability: stages validated in isolation If multiple stages share a parameter (e.g., \(\gamma\) for risk aversion), the orchestration layer ensures consistent values — DDSL does not prescribe how.
0.4.6 Syntax collection vs instantiated model¶
Syntax collection (template library)¶
A syntax collection is a set of reusable syntactic artifacts:
- Stage SYM files
- Period templates
- Default calibration/methodization templates A syntax collection is not yet a model: it does not commit to a time index set, a period family, or per-stage calibrations.
Directory layout is not part of the specification
syntax-rules #file-organisation¶
dolo-plus specifies the content of the YAML files (stage structure, symbol
declarations, equation blocks, methodization schemes, calibration bindings)
but not how those files are organised on disk. A "library" directory
grouping stage YAMLs, methods YAMLs, calibration.yaml, and settings.yaml
together is a useful convention — not a language requirement. A different
project may scatter files across directories, generate them programmatically,
or embed them inline. What matters is that the orchestration layer can locate
and load the correct artifacts; the folder layout is an implementation choice,
not a semantic one.
Instantiated model¶
An instantiated model is a concrete sequential decision process created by orchestration: 1. Select templates from a syntax collection 2. Bind calibration to each stage 3. Bind methodization and settings 4. Construct periods as compositions of bound stages 5. Construct twisters connecting consecutive periods
The result is a model: a sequence of fully-bound periods with inter-period wiring.
0.4.7 Scope boundaries¶
| Scope | Description |
|---|---|
| Stage | Reusable intra-period module with ADC perches and equation blocks |
| Period | Namespace + ordered composition of stages |
| Model | Sequence of periods with twisters |
Rule: syntactic stages remain reusable templates; the orchestration layer handles instantiation, calibration binding, and inter-period wiring.
0.4.8 Relationship to future extensions¶
The v0.1h construction is the sequential (path) special case:
- Periods totally ordered: \(P_0 \to P_1 \to \cdots \to P_T\)
- Twisters position-aligned
Future extensions may support:
- Branching scenario trees (DAGs with nonanticipativity)
- Explicit loop-closure for infinite-horizon recursion
- Richer connector types beyond pure renames
The key invariant: the syntax collection vs instantiation boundary. Templates remain reusable; orchestration handles time-indexing, branching, and binding.
0.4.9 Summary¶
| Concept | Definition |
|---|---|
| Period template | name:, stages: [...], optional connectors: [...] |
| Nest template | name:, periods: [...], twisters: [...] (position-aligned) |
| Stage template | Reusable stage file (timeless) |
| Bindings | Calibration/methodization/settings at stage level |
| Connector | Intra-period adapter {from, to, rename} |
| Twister | Inter-period adapter; v0.1h: positional, typically {rename: {...}} |
| Repeat | Optional builder sugar repeat: N |