-
-
Notifications
You must be signed in to change notification settings - Fork 210
a not-too-general value backwards induction algorithm built on DBlocks #1438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
d529a44
431fc80
fd603b5
b1daaff
510acaf
219b03c
7b0bf4f
0e9300c
1770ab0
aba2c55
e676627
3e90f64
32eb4c1
7fb5553
6ec5d5e
8b43ca2
7040c44
1e22c86
61fd2f7
8f45b79
4f83723
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ API Reference | |
| :caption: Tools | ||
| :maxdepth: 1 | ||
|
|
||
| tools/algos | ||
| tools/core | ||
| tools/dcegm | ||
| tools/distribution | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| algos | ||
| -------- | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 3 | ||
|
|
||
| algos/vbi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| algos.vbi | ||
| ---------- | ||
|
|
||
| .. automodule:: HARK.algos.vbi | ||
| :members: | ||
| :undoc-members: | ||
| :show-inheritance: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| :orphan: | ||
|
|
||
| Tools | ||
| ===== | ||
|
|
||
| <<<<<<< HEAD | ||
| .. toctree:: | ||
| :maxdepth: 3 | ||
|
|
||
| algos | ||
| core | ||
| dcegm | ||
| distribution | ||
| econforgeinterp | ||
| estimation | ||
| frame | ||
| helpers | ||
| interpolation | ||
| numba | ||
| parallel | ||
| rewards | ||
| simulation | ||
| utilities | ||
| validators | ||
| ======= | ||
| See :doc:`../index`. | ||
| >>>>>>> master | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,34 @@ | ||||||||||||||||||||||||||||||
| import HARK.algos.vbi as vbi | ||||||||||||||||||||||||||||||
| from HARK.distribution import Bernoulli | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
| from HARK.distribution import Bernoulli | |
| from HARK.distributions import Bernoulli |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The class name test_vbi does not follow Python naming conventions for test classes, which should use PascalCase (e.g., TestVbi or TestVBI). This inconsistency may cause issues with some test discovery tools.
| class test_vbi(unittest.TestCase): | |
| class TestVbi(unittest.TestCase): |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment appears to contain commented-out code.
| # def setUp(self): | |
| # pass | |
| def test_solve_block_1(self): | |
| state_grid = {"m": np.linspace(0, 2, 10)} | |
| dr, dec_vf, arr_vf = vbi.solve(block_1, lambda a: a, state_grid) | |
| def test_solve_block_1(self): | |
| state_grid = {"m": np.linspace(0, 2, 10)} | |
| dr, dec_vf, arr_vf = vbi.solve(block_1, lambda a: a, state_grid) | |
| dr, dec_vf, arr_vf = vbi.solve(block_1, lambda a: a, state_grid) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,162 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Use backwards induction to derive the arrival value function | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from a continuation value function and stage dynamics. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from HARK.model import DBlock | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import itertools | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import numpy as np | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from scipy.optimize import minimize | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Mapping, Sequence | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import xarray as xr | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_action_rule(action): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Produce a function from any inputs to a given value. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This is useful for constructing decision rules with fixed actions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def ar(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return action | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ar | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def ar_from_data(da): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Produce a function from any inputs to a given value. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This is useful for constructing decision rules with fixed actions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def ar(**args): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return da.interp(**args).values.tolist() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ar | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Grid = Mapping[str, Sequence] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def grid_to_data_array( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| grid: Grid = {}, ## TODO: Better data structure here. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Construct a zero-valued DataArray with the coordinates | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| based on the Grid passed in. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Parameters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ---------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| grid: Grid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A mapping from variable labels to a sequence of numerical values. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| da xarray.DataArray | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| An xarray.DataArray with coordinates given by both grids. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| coords = {**grid} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| da = xr.DataArray( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| np.empty([len(v) for v in coords.values()]), dims=coords.keys(), coords=coords | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return da | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def vbi_solve( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| block: DBlock, continuation, state_grid: Grid, disc_params={}, calibration={} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Solve a DBlock using backwards induction on the value function. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Parameters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ----------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| block | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continuation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state_grid: Grid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This is a grid over all variables that the optimization will range over. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This should be just the information set of the decision variables. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disc_params | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| calibration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+76
to
+85
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ----------- | |
| block | |
| continuation | |
| state_grid: Grid | |
| This is a grid over all variables that the optimization will range over. | |
| This should be just the information set of the decision variables. | |
| disc_params | |
| calibration | |
| ---------- | |
| block : DBlock | |
| The dynamic block to be solved. Provides the stage dynamics and | |
| methods for constructing value and policy functions. | |
| continuation | |
| The continuation (arrival) value object used for backward induction, | |
| typically a function or rule mapping future states to a value. | |
| state_grid : Grid | |
| A grid over all state variables that the optimization will range | |
| over. This should correspond to the information set of the | |
| decision variables. | |
| disc_params : Mapping, optional | |
| Discounting and/or preference parameters used in the value | |
| calculation (for example, discount factors or risk aversion | |
| parameters). Passed through to the block as needed. | |
| calibration : Mapping, optional | |
| Model calibration parameters (such as structural or environment | |
| parameters) that are required to evaluate the block's dynamics. |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "# pseudo" on line 95 is cryptic and doesn't explain what "pseudo" means in this context. Consider clarifying what these data arrays represent, e.g., "# Initialize empty arrays for policy and value function data".
| # pseudo | |
| # Initialize empty DataArrays over the state grid for policy and value function data |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "old! (should be negative)" is unclear and potentially confusing. If this is outdated information, it should be removed. If it's meant to explain why the function is negated, consider clarifying the comment to say something like "negated for use with minimization optimizer".
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment indicates this code "maybe needs to be more sensitive to the information set" (line 175), which suggests incomplete implementation. This should be addressed or documented as a known limitation if it's acceptable for the initial implementation.
| dr_from_data = { | |
| c: ar_from_data( | |
| policy_data | |
| ) # maybe needs to be more sensitive to the information set | |
| for i, c in enumerate(controls) | |
| } | |
| # Note: This implementation assumes that each control's decision rule | |
| # depends only on the coordinates in `state_grid`. Any additional | |
| # information-set dependence must be handled by extending this logic. | |
| dr_from_data = {c: ar_from_data(policy_data) for c in controls} |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All controls share the same policy_data array in the decision rule construction. For problems with multiple controls, each control should have its own policy array. This will cause issues when the code is extended to handle multiple controls (currently it raises an exception for len(controls) > 1).
| dr_from_data = { | |
| c: ar_from_data( | |
| policy_data | |
| ) # maybe needs to be more sensitive to the information set | |
| for i, c in enumerate(controls) | |
| } | |
| if len(controls) == 0: | |
| # no controls: empty decision rule | |
| dr_from_data = {} | |
| elif len(controls) == 1: | |
| # single control: construct rule from the corresponding policy data | |
| dr_from_data = {controls[0]: ar_from_data(policy_data)} | |
| else: | |
| # multiple controls are not yet supported in value backup iteration | |
| raise Exception( | |
| f"Value backup iteration is not yet implemented for stages with {len(controls)} > 1 control variables." | |
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,7 +52,7 @@ | |
| "dynamics": { | ||
| "b": lambda k, R, PermGroFac: k * R / PermGroFac, | ||
| "m": lambda b, theta: b + theta, | ||
| "c": Control(["m"]), | ||
| "c": Control(["m"], upper_bound=lambda m: m), | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mnwhite @alanlujan91 I wonder what you think about this way of introducing upper/lower bound information on control variables.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this looks good. If we wanted to differentiate between a fixed (real number) upper bound, and a functional upper bound, we could use the term |
||
| "a": lambda m, c: m - c, | ||
| }, | ||
| "reward": {"u": lambda c, CRRA: c ** (1 - CRRA) / (1 - CRRA)}, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file contains unresolved merge conflict markers (<<<<<<< HEAD, =======, >>>>>>> master). These should be resolved before merging. This file appears to be a .orig backup file that should likely be removed from the repository entirely.