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.

Nested endogenous-grid methods

A model with liquid wealth and a durable or illiquid stock has two continuous choices. pylcm’s nested solvers exploit a particular structure: conditional on the outer post-decision stock, the remaining problem is a one-dimensional consumption-saving problem.

Let dd' denote the outer post-decision choice. A nested solve computes

Wt(x,d)=maxc{ut(x,c,d)+βE[Vt+1(x)]}W_t(x,d') = \max_c \left\{ u_t(x,c,d') + \beta\mathbb{E}[V_{t+1}(x')] \right\}

with a liquid EGM step, then compares the outer candidates:

Vt(x)=max{Wtkeep(x),maxdDWt(x,d)}.V_t(x) = \max\left\{ W_t^{\mathrm{keep}}(x), \max_{d' \in \mathcal D} W_t(x,d') \right\}.

The keeper branch represents no adjustment; the adjuster branch searches candidate outer levels. This is nesting, not a coupled two-dimensional Euler inversion Druedahl (2021).

NEGM

NEGM(inner=DCEGM(...), outer_grid=...) performs one complete inner DCEGM solve for each outer-grid node and compares those candidates with the keeper. The outer solution is exact relative to that finite candidate set. outer_batch_size limits how many candidate values are evaluated at once. It can reduce temporary evaluation memory, but it does not cap the candidate bank retained for the exact later comparison. Peak memory can therefore still grow with the complete outer candidate set.

Use it when the liquid problem has ordinary discrete-continuous non-concavity and the outer action can be represented by a fixed grid.

NNBEGM

NNBEGM(inner=NBEGM(...), outer_search=...) preserves declared kinks, jumps, and hard constraints inside every outer candidate. Its outer search is itself configurable:

How keeper and adjuster values aggregate is declared on the margin, as OuterContinuousMargin.adjustment_cost, not on the solver. Leaving it unset takes the hard maximum; the solver only states whether its configured outer search can execute the implied aggregation. UniformObservedFixedCost analytically integrates a narrowly specified observed uniform adjustment-cost shock.

Simulation replays that solve-time candidate bank. Current NNBEGM therefore requires every declaration affecting replay to be phase-invariant by object identity: a bare declaration or identical-object Phased(solve=f, simulate=f) is accepted, while genuine phase variation requires GridSearch. This is a candidate-set restriction, not a general restriction on Phased; see NNBEGM replay capability.

What the model must declare

A NestedConsumptionSavingsRegime supplies:

Use outer_unchanged when the no-adjustment map is literally the identity. Use NetOfAdjustmentCost when resources are the difference between a before-cost node and an adjustment-cost node. These declarations eliminate identity wrapper functions whose only purpose would be renaming.

NNBEGM additionally restricts the outer post-decision map itself. It searches over the outer stock a candidate reaches and recovers the action that reached it by exact inversion, so the action must enter that map affinely with a constant power-of-two coefficient; the offset may be any function of states and parameters. This rules out a state-dependent conversion technology — a scale economy in durable investment, a portfolio-size-dependent transaction cost, increasing-returns installation — which is a modelling loss rather than a notational one. Such models solve under GridSearch, which searches the outer action directly. The accepted and refused forms are enumerated in NNBEGM.

The exact fields and composition rules are in Consumption-saving regimes and margins. Outer strategy contracts are in Outer search and branch aggregation.

Computational implication

If the inner solve costs CinnerC_{\text{inner}} and the finite outer search has NdN_d candidates, the leading work is proportional to NdCinnerN_d C_{\text{inner}}.

Under AdaptiveOuterMesh the candidate count is data-dependent rather than declared, so no single NdN_d describes it. The work is the initial mesh, plus up to max_refinement_rounds rounds of midpoint insertion capped by max_nodes exact inner solves, plus golden_iterations evaluations inside each retained bracket. The budget is therefore what bounds the cost, not the declaration. State cells, discrete branches, stochastic nodes, and envelope candidates live inside CinnerC_{\text{inner}}; a values-only retention (ResultRetention.VALUES) removes the replay banks and, under the adaptive search, the nested policy from every inner solve. This multiplication is why streaming and accelerator occupancy matter, and why a large GPU should be fed concurrent independent work where memory permits.

See Scaling, memory, and hardware. Empirical break-even points remain model- and hardware-dependent; the external benchmark suite is the evolving evidence source.

References
  1. Druedahl, J. (2021). A Guide on Solving Non-convex Consumption-Saving Models. Computational Economics, 58(3), 747–775. 10.1007/s10614-020-10045-x