Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Dynamic programming and pylcm

pylcm solves finite-horizon dynamic programs. In a single-regime notation, its general period-tt recursion is

Vt(x)=maxaAt(x)Ht(ut(x,a),CEt[Vt+1(x)]).V_t(x) = \max_{a \in A_t(x)} H_t\left(u_t(x, a), \operatorname{CE}_t[V_{t+1}(x')]\right).

With the default LinearAggregator() and LinearExpectation(), this reduces to

Vt(x)=maxaAt(x){ut(x,a)+βtEt[Vt+1(x)]}.V_t(x) = \max_{a \in A_t(x)} \left\{u_t(x, a) + \beta_t\, \mathcal{E}_t[V_{t+1}(x')]\right\}.

The state xx is declared through states, the choice aa through actions, the flow payoff through functions["utility"], and the feasible set through constraints. state_transitions and stochastic-process declarations determine xx'. pylcm composes those named pieces, solves backward over the AgeGrid, and then reuses the solution for forward simulation.

This page maps the dynamic-programming objects to pylcm. It is not an introduction to dynamic programming. For that, use the QuantEcon Dynamic Programming book.

Regimes add a discrete state with changing structure

Many lifecycle models change their equations and available choices across employment, retirement, marriage, or death. pylcm represents each qualitatively distinct problem as a Regime. A regime transition determines the next regime, and each regime supplies its own states, actions, functions, constraints, and transition laws.

The continuation is therefore a weighted or deterministic read from the value functions of reachable target regimes. Per-target transition dictionaries declare structural reachability; omitted targets are not merely assigned zero probability, they are absent from the problem.

See Regimes for the workflow and Model and Regime for exact declaration forms.

Backward induction evaluates values over numerical grids. Simulation evaluates policies for a cohort at realized, potentially off-grid states. Most declarations broadcast to both phases, but Phased(solve=..., simulate=...) permits different implementations where their data topology genuinely differs. A carried state, for example, can be derived during solution and remain a seeded state during simulation.

The exact grammar is in Transitions and phase specialization; the numerical reason is developed in Phase-dependent model structure.

The solver changes the representation of the maximization

GridSearch covers the full represented state-action product. On eligible JIT solve-value routes—ordinary singleton hard max, collective hard max, and singleton EV1 expected max—it evaluates bounded C-order action blocks and reduces them without changing that candidate support. These programs publish only solve-time VALUE, or VALUE plus DISSOLUTION_FLAG for a collective route; replay and policy artifacts are not integrated. Value references and gated targets stream unless they intersect a co-mapped state through a separate reference channel. Ordinary co-mapped routes and eligible singleton hard-max folds also stream; the latter still evaluate the complete fold-node axis before quadrature. Trivial action products, JIT-disabled execution, the co-map/reference intersection, and all simulation-policy construction remain dense. See the canonical GridSearch route matrix for the combinations unsupported by the streamed program. This execution route does not by itself establish a runtime or peak-memory improvement. EGM-family solvers replace one continuous maximization with an Euler-equation inversion and therefore need stronger assumptions and named economic roles.

This is why solver selection belongs before detailed model authoring. The economic problem and the numerical representation have to agree; changing only solver=... cannot turn an arbitrary model into an endogenous-grid problem. Continue with Solver families and Choosing a solver.