You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 2c33451
Browse filesBrowse the repository at this point in the historyBrowse files
feat(numeric): formalize Space hierarchy, Approximator operators, and DecisionRule.fit() API
- Introduce Space hierarchy (CartesianSpace, DiscreteSpace/GridSpace, ProductSpace, EmptySpace)
separating mathematical domain from discretization grids
- Introduce Approximator hierarchy (LinearApproximator, CubicSplineApproximator, SmolyakApproximator,
ProductApproximator) with canonical get_approximator() factory
- Add DecisionRule.fit() returning self for fluent chaining (parity with Julia fit!), aliasing set_values
- Make CartesianDomain inherit from CartesianSpace, connecting model.domain to Space
- Expose dmodel.space, dmodel.approximator, and dmodel.decision_rule() on DiscretizedModel
- Update documentation in docs/model_representation.md and docs/api.md
- Add comprehensive test suite in tests/test_spaces_approximators.py (9/9 passed)
Copy file name to clipboardExpand all lines: docs/model_representation.md
+68-51Lines changed: 68 additions & 51 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,32 +25,51 @@ layered abstractions that perform this conversion:
25
25
26
26
## 1. Spaces and Grids
27
27
28
-
### The notion of a *space*
28
+
### The `Space` Hierarchy
29
+
30
+
In economic modeling, variables live on a **mathematical space** (the continuous or discrete domain) rather than a computational grid. The **`Space`** hierarchy in `dolo.numeric.spaces` provides first-class objects for these domains:
31
+
32
+
-**`CartesianSpace`**: A continuous bounded hypercube $[\underline{s}, \overline{s}] \subset \mathbb{R}^d$.
33
+
- In a `CartesianSpace`, location and continuous coordinates coincide (`loc = val = coords`).
34
+
- Supports domain membership checks (`pt in space`), random sampling (`space.draw()`), and discretization (`space.discretize(n=20)`).
35
+
- Preserves dict-like indexing `space['k']` for backward compatibility with `model.domain`.
36
+
-**`DiscreteSpace`** (alias **`GridSpace`**): A finite discrete set of points $\{p_1, \dots, p_N\}$ (e.g. Markov states).
37
+
- In a `DiscreteSpace`, `loc` is the integer regime index $i \in \{0, \dots, N-1\}$, while `val = points[i]`.
38
+
- Discretizes to an `UnstructuredGrid`.
39
+
-**`ProductSpace`**: The Cartesian product of multiple spaces (e.g. $S_{exo} \times S_{endo}$).
40
+
-`loc` is a composite tuple `(loc_exo, loc_endo)`, and `val` is concatenated $[m, s]$.
41
+
- Discretizes to a `ProductGrid`.
42
+
-**`EmptySpace`**: The neutral empty space for models without discrete exogenous states (discretizes to `EmptyGrid`).
29
43
30
-
Almost every economic model solved by Dolo mixes two kinds of dimensions:
44
+
```python
45
+
from dolo.numeric import CartesianSpace, DiscreteSpace, ProductSpace
The *space* of the model is the product of these two parts. In the current
38
-
implementation the space is **not** a standalone object: it is concretely
39
-
realized by a **grid** — more precisely a `ProductGrid`, the Cartesian product
40
-
of an *exogenous* grid and an *endogenous* grid:
61
+
A **`Grid`** represents a concrete, discrete set of nodes sampling a `Space`:
41
62
42
63
$$\mathcal{G} = \mathcal{M} \times \mathcal{S}$$
43
64
44
-
- $\mathcal{M}$ is the grid of the discretized exogenous process (regimes /
45
-
shock nodes);
46
-
- $\mathcal{S}$ is the grid of endogenous states (a Cartesian product of
47
-
intervals).
65
+
- $\mathcal{M}$ is the grid of the discretized exogenous process (regimes / shock nodes);
66
+
- $\mathcal{S}$ is the grid of endogenous states (a Cartesian product of intervals).
48
67
49
68
A `ProductGrid` bundles the two sub-grids and supports lookup by name:
50
69
51
70
```python
52
71
grid.grids # -> [exo_grid, endo_grid]
53
-
grid["states"]# -> the endogenous sub-grid
72
+
grid["endo"] # -> the endogenous sub-grid
54
73
```
55
74
56
75
### Grid types
@@ -255,54 +274,52 @@ x0.norm() # L_infinity norm
255
274
256
275
## 6. Approximators
257
276
258
-
The solution algorithms do not return raw point values on the grid; they
259
-
return a decision rule $x = \varphi(S)$ that can be evaluated *anywhere*. The
260
-
objects that interpolate (or otherwise approximate) the policy over the space
261
-
are collectively the **approximators**. In the current implementation these
262
-
live in `dolo.numeric.decision_rule`:
277
+
The solution algorithms do not return raw point values on the grid; they return a decision rule $x = \varphi(S)$ that can be evaluated *anywhere* in the continuous space. The objects that interpolate or approximate the policy are collectively the **approximators** in `dolo.numeric.approximators`:
263
278
264
-
-**`DecisionRule`** — interpolates a control field stored on an
265
-
`(exo_grid, endo_grid)` product grid, with an interpolation method selected
266
-
from `interp_methods`:
279
+
-**`LinearApproximator`**: Piecewise multilinear interpolation on Cartesian grids.
280
+
-**`CubicSplineApproximator`**: Prefiltered cubic spline interpolation on Cartesian grids.
281
+
-**`SmolyakApproximator`**: Multivariate Chebyshev polynomial approximation on Smolyak grids.
282
+
-**`ProductApproximator`**: Regime-wise composite approximator over `ProductGrid` / `ProductSpace` (delegating to continuous approximators per discrete regime).
-`app.fit(values)`: Fits coefficients from field values on the grid.
287
+
-`app.evaluate_coords(coeffs, s)`: Evaluates approximation at continuous coordinate matrix.
288
+
-`app.evaluate(coeffs, qp)`: Evaluates approximation at a `QualifiedPoint`.
289
+
-`app.evaluate_batch(coeffs, batch)`: Evaluates approximation over a `QualifiedBatch` / `SliceQP`.
273
290
274
-
-**`ConstantDecisionRule`** — a trivial constant policy (used as a starting
275
-
point).
276
-
-**`CustomDR`** — a user-supplied closed-form decision rule.
291
+
### DecisionRule and `fit()`
277
292
278
-
A `DecisionRule` is callable like a `gufunc`, accepting either a `QP` /
279
-
`SliceQP`, `(m, s)` economic coordinates, or `(i, s)` regime indexing:
293
+
A **`DecisionRule`** bundles the space, grid, approximator, and fitted coefficients into a callable object:
280
294
281
295
```python
282
-
dr = DecisionRule(exo_grid, endo_grid, interp_method="cubic")
283
-
dr.set_values(x) # x : GArray or raw array of control values
284
-
dr(i_m, s) # evaluate in regime i_m at states s
296
+
from dolo.numeric import DecisionRule
297
+
298
+
# Fluent construction and fitting (matching Julia's fit!):
299
+
dr = DecisionRule(exo_grid, endo_grid, interp_method="cubic").fit(controls_ga)
300
+
301
+
# dr.set_values is preserved as an alias for backwards compatibility:
302
+
dr.set_values(controls_ga)
303
+
304
+
# Callable over QP, SliceQP, or regime + continuous coordinates:
305
+
dr(qp)
306
+
dr(slice_qp)
307
+
dr(i_m, s)
285
308
```
286
309
287
-
Smolyak interpolation is available through `SmolyakGrid` (and the
288
-
`interpolation` dependency); higher-dimensional and Taylor-based
289
-
approximators (as in Dolo.jl) are planned but not yet wired into the solve
290
-
routines.
310
+
You can also construct a `DecisionRule` directly from a `DiscretizedModel`:
311
+
312
+
```python
313
+
dr = dmodel.decision_rule(controls_ga, interp_method="cubic")
314
+
```
291
315
292
316
---
293
317
294
318
## 7. Roadmap
295
319
296
-
The following pieces of the redesign are still outstanding; this chapter will
297
-
be updated as they land:
320
+
With first-class **`Space`** and **`Approximator`** hierarchies now landed, the remaining items on the redesign roadmap are:
298
321
299
-
- a first-class **`Space`** object (separating the *domain* from its *node
300
-
set*), making non-Cartesian and mixed discrete/continuous domains
301
-
first-class citizens;
302
-
- a unified **`Approximator`** interface (Smolyak, spline, Chebyshev, Taylor)
303
-
shared by all solution routines;
304
-
-`tau`-based simulation and quadrature (currently `tau_fit` is the reference).
322
+
-**`tau`-based simulation and ergodic analysis**: using $\tau$ directly inside time-series simulation loops (replacing ad-hoc process branching);
323
+
-**Higher-order Taylor approximators**: local perturbation expansions around the steady state implementing the unified `Approximator` interface.
305
324
306
-
The stable, algorithm-facing `DiscretizedModel` / `tau` / `GArray` / `QP`
307
-
abstractions are already used by the global solvers (see the "Time Iteration"
308
-
chapter).
325
+
The stable, algorithm-facing `DiscretizedModel` / `tau` / `GArray` / `QP` / `Space` / `Approximator` abstractions are used by the global solvers (see the "Time Iteration" chapter).
0 commit comments