standalone model configuration file with model, approximation, solution, and simulation parameters#1463
standalone model configuration file with model, approximation, solution, and simulation parameters#1463sbenthall wants to merge 8 commits intoecon-ark:mainfrom
Conversation
|
This PR builds on #1427 which should be merged first. |
|
This is now ready for review again. Since it is mainly about notation, not functionality, there are no new tests to be added. The API for this solution algorithm is going to be the main constraint on what the workflow syntax looks like. I'll be happy to write up some documentation for this, but it probably should get eyeballs and an OK from somebody else on the team, before expending effort on those docs. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a worked example of a HARK-style model configuration in both Python and YAML, and slightly refactors existing simple model files to make calibration the single source of truth. It also documents the new example in the changelog.
Changes:
- Adds
examples/ModelConfiguration/consumer_example.py, a Python model configuration illustrating agents, calibration, blocks, and approximations. - Adds
examples/ModelConfiguration/consumer_example.yaml, a YAML counterpart meant to be parsed into a configuration object using the new parser utilities. - Refactors
perfect_foresight,perfect_foresight_normalized, andfishermodels to pull parameters directly from theircalibrationdicts instead of module-level globals, and updates the changelog to mention the new example.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
examples/ModelConfiguration/consumer_example.yaml |
Provides a YAML example of a full model configuration (agents, calibration, blocks, approximation, strategy, simulation), intended for use with harklang_loader and the expression/shock constructors. |
examples/ModelConfiguration/consumer_example.py |
Defines a Python model_config dict mirroring the conceptual structure of the YAML configuration and existing HARK.models.consumer blocks. |
HARK/models/perfect_foresight_normalized.py |
Removes global parameter variables, inlines them into calibration, and wires shocks and reward to reference the calibration dictionary directly. |
HARK/models/perfect_foresight.py |
Same calibration cleanup as the normalized version, using calibration["LivPrb"] for the survival Bernoulli shock and the standard CRRA reward signature. |
HARK/models/fisher.py |
Aligns the Fisher example’s CRRA handling with other models by keeping it in calibration and using the (c, CRRA) reward signature. |
Documentation/CHANGELOG.md |
Adds a changelog entry describing the new ModelConfiguration example and its purpose. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # - DiscFac: 0.96 put this in the solution section | ||
| - CRRA: 2.0 | ||
| - R: 1.03 # note: this can be overriden by the portfolio dynamics | ||
| - Rfree: 1.03 | ||
| - EqP: 0.02 | ||
| - PermGroFac: 1.01 | ||
| - TranShkStd: 0.1 |
There was a problem hiding this comment.
In this YAML example, calibration is defined as a sequence of one-key mappings (a list of parameters) rather than a mapping from parameter names to values. The Python configuration and the rest of the codebase treat calibration as a dictionary, so this structure will not match the expected shape and will be harder to consume; it should instead be a single mapping with keys like CRRA, R, etc.
| # - DiscFac: 0.96 put this in the solution section | |
| - CRRA: 2.0 | |
| - R: 1.03 # note: this can be overriden by the portfolio dynamics | |
| - Rfree: 1.03 | |
| - EqP: 0.02 | |
| - PermGroFac: 1.01 | |
| - TranShkStd: 0.1 | |
| # DiscFac: 0.96 put this in the solution section | |
| CRRA: 2.0 | |
| R: 1.03 # note: this can be overriden by the portfolio dynamics | |
| Rfree: 1.03 | |
| EqP: 0.02 | |
| PermGroFac: 1.01 | |
| TranShkStd: 0.1 |
| std: 0.1 | ||
|
|
||
| dynamics: | ||
| stigma: Control(["a"]), |
There was a problem hiding this comment.
Here stigma is set to the literal text Control(["a"]), rather than using the !Control YAML tag as in the c variable above. With the current harklang_loader (see HARK/parser.py:48-67), this value will be treated as a plain string instead of a control token, and the trailing comma also makes it invalid as a mathematical expression; this should be rewritten to use the !Control tag without the extra comma.
| stigma: Control(["a"]), | |
| stigma: !Control | |
| inset: a |
| risky_return: | ||
| N: 5 | ||
| method: gauss-hermite | ||
| m: !Linspace # grid over continuous state space |
There was a problem hiding this comment.
The !Linspace tag used here is not registered in the current YAML loader (harklang_loader only adds constructors for !Bernoulli, !MeanOneLogNormal, !Lognormal, and !Control in HARK/parser.py:48-65). As written, attempting to load this YAML with harklang_loader will raise a constructor error; either the tag needs a corresponding constructor, or this should be expressed using supported tags/structures.
| m: !Linspace # grid over continuous state space | |
| m: # grid over continuous state space |
| approximation: *approx | ||
| discount: 0.98 # A discount factor applied at each tick | ||
|
|
||
| simulation: !MonteCarlo |
There was a problem hiding this comment.
The !MonteCarlo tag used for the simulation block is not registered in harklang_loader (see HARK/parser.py:48-67), so loading this YAML with that loader will fail with an unknown tag error. To make this example loadable, a constructor for !MonteCarlo needs to be added or the tag should be removed/changed to a supported construct.
| simulation: !MonteCarlo | |
| simulation: |
| "shocks": { | ||
| "live": [Bernoulli, {"p": "LivPrb"}], | ||
| "theta": [MeanOneLogNormal, {"sigma": "TranShkStd"}], | ||
| }, |
There was a problem hiding this comment.
In this Python configuration, the shocks entries are specified as lists like [Bernoulli, {"p": "LivPrb"}], but construct_shocks and DBlock expect either Distribution instances or tuples of (DistributionClass, args_dict) (see HARK/model.py:81-129 and 196-215). Using lists here means this configuration cannot be passed directly into DBlock/construct_shocks as intended; these should be tuples to match the established convention and behavior.
|
|
||
| (c) additional parameters needed to solve and simulate the model. | ||
|
|
||
| This file shows the model configuraiton in Python. |
There was a problem hiding this comment.
"configuraiton" is misspelled in this docstring; this should be corrected to "configuration" for clarity and consistency with the rest of the documentation.
| This file shows the model configuraiton in Python. | |
| This file shows the model configuration in Python. |
|
|
||
| dynamics: | ||
| b: k * R / PermGroFac | ||
| m: b + theta, |
There was a problem hiding this comment.
The value m: b + theta, includes a trailing comma in the mathematical expression. Given that expressions are parsed via SymPy (see HARK/parser.py:39-45), this extra comma will cause a parse error and should be removed so the expression is valid (e.g., b + theta).
| m: b + theta, | |
| m: b + theta |
| - c < m | ||
| a: m - c | ||
| reward: | ||
| u: c ** (1 - CRRA) / (1 - CRRA)} |
There was a problem hiding this comment.
The reward expression u: c ** (1 - CRRA) / (1 - CRRA)} has an extra closing brace at the end. Because reward expressions are parsed as mathematical text (see HARK/parser.py:39-45 and HARK/model.py:262-264), this stray } will make the YAML example invalid or unparseable; it should be removed so the expression is valid.
| u: c ** (1 - CRRA) / (1 - CRRA)} | |
| u: c ** (1 - CRRA) / (1 - CRRA) |
| - twist: # shorthand fo renaming a variable | ||
| m: k | ||
| - tick # pass discrete time step | ||
| # defaults to infinite horizion problem |
There was a problem hiding this comment.
The comment # defaults to infinite horizion problem contains a typo in "horizion"; it should be "horizon" for clarity.
| # defaults to infinite horizion problem | |
| # defaults to infinite horizon problem |
| @@ -0,0 +1,84 @@ | |||
| from HARK.distribution import Bernoulli, Lognormal, MeanOneLogNormal | |||
There was a problem hiding this comment.
The import path here uses HARK.distribution, but the rest of the codebase (e.g., HARK/models/consumer.py:1) consistently imports from HARK.distributions. Using the singular module name will raise an ImportError; this should be switched to HARK.distributions to match the existing package structure.
| from HARK.distribution import Bernoulli, Lognormal, MeanOneLogNormal | |
| from HARK.distributions import Bernoulli, Lognormal, MeanOneLogNormal |
The goal of this PR is to implement a working example of a HARK configuration file, in Python, as per #857. (Note the ticket originates from 2020).
Such a configuration should include information:
While this is functionality that's similar to the HARK 0.x models, this PR aims to implement model configuration subject to several constraints:
This work is informed by work in late 2023 on the HARK 2.0 model specification language.
Some tricky parts remaining to implement include:
Constructing shocks using mathematical expressions for input parameters from configuration objectsDONE