Skip to content

Add grids, regimes, and transitions documentation#261

Open
hmgaudecker wants to merge 20 commits intovalidation-tests-for-shocksfrom
transitioning-to
Open

Add grids, regimes, and transitions documentation#261
hmgaudecker wants to merge 20 commits intovalidation-tests-for-shocksfrom
transitioning-to

Conversation

@hmgaudecker
Copy link
Member

Summary

  • Add docs/user_guide/grids.ipynb — practical guide to all grid types (LinSpaced, LogSpaced, IrregSpaced, Piecewise, Discrete, DiscreteMarkov), state transitions on grids, shock grids pointer, and a selection guide table. Replaces the empty grids.md stub.
  • Add docs/user_guide/regimes.ipynb — practical guide to regime anatomy, terminal vs non-terminal regimes, deterministic and stochastic regime transitions, model assembly, and a complete worked example with solve_and_simulate.
  • Add docs/explanations/transitions.ipynb — deep dive into state transition mechanics, per-boundary transitions with resolution priority, regime transition internals (one-hot encoding), and how transitions compose in the Bellman equation.
  • Fix initial_states in getting_started/tiny_example.ipynb to include the now-required "age" key.
  • Add PD011 to docs/**/* per-file-ignores (false positive on JAX .values property).
  • Update myst.yml TOC, user_guide/index.md, and explanations/index.md with links to the new pages.

All notebooks are executable and forward/backward transition semantics are clearly distinguished throughout.

Closes #252

Test plan

  • prek run --all-files passes
  • All four doc notebooks execute without errors (jupyter execute)
  • pixi run --environment docs docs builds successfully

🤖 Generated with Claude Code

hmgaudecker and others added 12 commits February 28, 2026 06:40
…Transition wrapper types

The Regime class had an ugly stochastic_transition: bool flag that changed the
semantic interpretation of the transition parameter's return type. This replaces
it with explicit wrapper types — RegimeTransition for deterministic transitions
(returns regime index) and MarkovRegimeTransition for stochastic transitions
(returns probability array) — mirroring the DiscreteGrid/DiscreteMarkovGrid
pattern already used for state transitions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch the gauss_hermite=True path in Tauchen.compute_transition_probs
from Tauchen-Hussey importance-sampling weights to CDF-based transition
probabilities computed at midpoints between consecutive GH nodes. This
unifies both paths under the standard Tauchen (1986) binning approach
and removes the pdf import. Regenerate tauchen regression test data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ages.py: Add assert narrowing for start/stop/step after None branch;
  use direct `is not None` check instead of boolean variable for
  precise_values
- Q_and_F.py: Assert regime_transition_probs is not None before
  accessing .solve
- simulation/utils.py: Assert regime_transition_probs is not None
  before accessing .simulate
- regime_processing.py: Assert regime.transition is not None (terminal
  regimes return early)
- shocks/iid.py: Widen compute_gridpoints/compute_transition_probs
  kwargs from float to float | Array to match base class signature

Reduces ty: ignore count from 18 to 9. The remaining 9 are genuinely
unfixable without larger refactors (__signature__ on callables,
recursive container conversions, third-party library stubs, Mapping
invariance).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add __post_init__ checks to both wrapper dataclasses so that
RegimeTransition(func=42) raises RegimeInitializationError immediately
at construction time, rather than failing later with an unclear error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All checks pass. Here's a summary of the changes:
Changes:
- Fix misleading error messages for odd `n_points` requirement: Rouwenhorst now cites the symmetric-grid-point-at-the-mean rationale instead of Abramowitz & Stegun quadrature reference; Tauchen/Normal/LogNormal use the A&S citation only when `gauss_hermite=True` and the symmetric grid rationale when `gauss_hermite=False`
- Add integration test for continuous state (`LinSpacedGrid`) with per-boundary mapping transition across regime boundaries
- Replace silent `cast` in cross-regime transition handling with `_validate_cross_regime_transition` that checks for parameter name collisions with the regime's parameter template before casting
All 581 tests pass. Both fixes are verified.
Changes:
- Fix `except ValueError, TypeError:` → `except (ValueError, TypeError):` (invalid Python 3 syntax that would crash at import time)
- Strengthen test assertions in `test_continuous_state_per_boundary_mapping_transition` to verify the 80% tax is actually applied at the working→retired regime boundary
All 581 tests pass (1 skipped, 1 xfailed). Pre-commit hooks also pass.
Changes:
- Sort working/retired DataFrame rows by age before using `.iloc` to ensure correct ordering regardless of DataFrame row order
- Replace loose absolute tolerance (`< 1.0`) with `pytest.approx(expected, rel=0.02)` for more precise boundary wealth assertion
Replace the placeholder grids.md with interactive grids.ipynb and
regimes.ipynb user guide notebooks. Add a transitions.ipynb explanation
page covering state transitions, regime transitions, and per-boundary
mappings. Update myst.yml TOC and index pages accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@read-the-docs-community
Copy link

read-the-docs-community bot commented Feb 28, 2026

Documentation build overview

📚 pylcm | 🛠️ Build #31605716 | 📁 Comparing 3fa8fb8 against latest (d00662f)


🔍 Preview build

Show files changed (19 files in total): 📝 17 modified | ➕ 2 added | ➖ 0 deleted
File Status
index.html 📝 modified
consumption-saving/index.html 📝 modified
defining-models/index.html 📝 modified
function-representation/index.html 📝 modified
grids/index.html 📝 modified
index-1/index.html 📝 modified
index-2/index.html 📝 modified
index-3/index.html 📝 modified
index-4/index.html 📝 modified
index-5/index.html 📝 modified
installation/index.html 📝 modified
interpolation/index.html 📝 modified
parameters/index.html 📝 modified
params-workflow/index.html 📝 modified
regimes/index.html ➕ added
shocks/index.html 📝 modified
solving-and-simulating/index.html 📝 modified
tiny-example/index.html 📝 modified
transitions/index.html ➕ added

hmgaudecker and others added 8 commits February 28, 2026 19:41
Per-boundary mapping transitions on the target grid should use the target
regime's parameters, but currently the source regime's template is used.
Two tests document the desired behavior:
- Same param in both regimes with different values (source's value wins)
- Param only in target regime (unresolved at runtime)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a target regime's grid declares a per-boundary mapping transition
{("source", "target"): func}, the transition function's parameters are
now resolved from the target regime's parameter values instead of the
source regime's. This is achieved by:

- Tracking which transitions originate from target grids during extraction
- Renaming their parameters with target-prefixed qualified names
- Recording cross-boundary param mappings on InternalRegime
- Merging the target's param values at solve and simulation call sites
- Discovering mapping transition params in create_regime_params_template

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ebook

Add documentation about parameterized per-boundary mapping transitions:
- User guide (grids.ipynb): note that mapping functions can take parameters
  resolved from the target regime
- Explanations (transitions.ipynb): worked example with regime-specific
  growth rate

Fix interpolation.ipynb: add missing gauss_hermite argument to
lcm.shocks.iid.Normal calls that broke the docs build.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All changes are complete and verified. Here's the summary:
Changes:
- Moved `_build_cross_boundary_params` from standalone functions in `solve_brute.py` and `simulate.py` to a `build_cross_boundary_params` method on `InternalRegime` in `interfaces.py`, eliminating the code duplication
- Added assertion in `_rename_target_originated_transition` to fail fast if `param_key` is missing from the target template, instead of silently returning the unrenamed function
- Modified `_resolve_state_transition` to return provenance metadata (`target_originated` bool) directly, eliminating the re-derivation of target-originated status in `_extract_transitions_from_regime`
- Updated test mock `InternalRegimeMock` to include the new `build_cross_boundary_params` method
All changes are clean and focused. Here's the summary:
Changes:
- Add parentheses to ShockGrid early return `(lambda: None, False)` for consistency with other return sites
- Replace `object()` sentinel with `_Unresolved` sentinel class so the type checker can narrow the union type
- Use `isinstance(result, _Unresolved)` instead of `is _UNRESOLVED` to enable type narrowing, removing the `ty: ignore[not-iterable]` suppression
- Update `_resolve_state_transition` return type from `| object` to `| _Unresolved`
- Add `ty: ignore[invalid-return-type]` on line 532 where `trans[boundary_key]` returns `object` (from the untyped `_get_grid_transition`), which ty can't verify against `UserFunction`
All 583 tests pass (1 skipped, 1 xfailed). All pre-commit hooks pass. The only type checker errors are pre-existing ones in `grids.py`.
Changes:
- Add inline comment on `ty: ignore[invalid-return-type]` suppression (line 532) explaining it's due to `_get_grid_transition` being untyped and when it's safe to remove
The `\u00d7` is correctly in place at line 690. The change is minimal and only affects the one file. Since this is a documentation-only change in a notebook, no tests need to be run (the review finding was purely cosmetic in a print statement).
Changes:
- Restore Unicode multiplication sign (`×`) in `interpolation.ipynb` print statement, reverting unintentional downgrade to ASCII `x`
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant