Quasi hyperbolic pf - #833
Conversation
- Hyperbolic beta modifies current solution discount factor. - Presolve processes generate geometric solution if needed (Hyperbolic_beta !=1)
|
/binder |
|
@Mv77 to look at this as CDC's RA |
|
I did not get to this in my time as Chris's RA this winter and I don't anticipate working on it for now. |
There was a problem hiding this comment.
Pull request overview
This PR implements quasi-hyperbolic discounting for perfect foresight consumer agents in HARK, addressing issue #215 and replacing PR #815. The implementation uses a "beta-delta" approach where naive agents have present-biased preferences.
Changes:
- Modified
solveOneCycleincore.pyto support geometric solutions for backward induction - Added
HyperbolicBetaparameter toPerfForesightConsumerTypeand its solver - Updated discount factor calculation to incorporate hyperbolic discounting
- Added example configurations and a demonstration notebook
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
| HARK/core.py | Modified solveOneCycle to conditionally use geometric_solution attribute for backward induction instead of current solution |
| HARK/ConsumptionSaving/ConsIndShockModel.py | Added HyperbolicBeta parameter to solver and agent type; updated effective discount factor calculation; reformatted init dictionary |
| examples/Journeys/Quickstart_tutorial/Jounery_1_param.py | Added Hyperbolic_beta parameter to example configuration |
| HARK/ConsumptionSaving/ConsIndShockModelDemos/testing_hyperbolic_discounting.ipynb | New Jupyter notebook demonstrating and validating the hyperbolic discounting implementation with algebraic verification |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| PermGroFacAgg = 1.0 # Aggregate permanent income growth factor (only matters for simulation) | ||
| T_age = None # Age after which simulated agents are automatically killed | ||
| T_cycle = 1 # Number of periods in the cycle for this agent type | ||
| Hyperbolic_beta = 1 # Naive hyperbolic discount factor |
There was a problem hiding this comment.
The parameter name "Hyperbolic_beta" in the example file is inconsistent with "HyperbolicBeta" used in the main implementation. Parameter names should be consistent across the codebase. Consider using "HyperbolicBeta" (without underscore) to match the implementation.
|
|
||
| Returns: | ||
| ---------- |
There was a problem hiding this comment.
The docstring is missing a blank line before the "Returns:" section and has inconsistent formatting with an empty line after the description. The formatting should match the project's documentation standards.
| Returns: | |
| ---------- | |
| Returns | |
| ------- |
| "MaxKinks", | ||
| "BoroCnstArt", | ||
| "HyperbolicBeta", | ||
| "geometric_solution", |
There was a problem hiding this comment.
Adding "geometric_solution" to time_inv_ makes it a required parameter that must be provided during initialization. This could break existing code that creates PerfForesightConsumerType instances without this parameter. Consider making this parameter optional by checking for its existence with hasattr() (as already done in core.py line 923) rather than requiring it as a time-invariant parameter.
| "geometric_solution", |
| "cell_type": "markdown", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "I implement hyperbolic discounting by modyfing the `solveOneCycle` function in `core.py`. If a `geometric_solution` attribute is specified, the `solveOneCycle` function uses the solutions specified in this attribute list in its backward induction loop, instead of the current solution. The exponential discount factor is also resized by a factor of the `hyperbolic` discount variable. " |
There was a problem hiding this comment.
The notebook documentation contains a typo: "modyfing" should be "modifying".
| "I implement hyperbolic discounting by modyfing the `solveOneCycle` function in `core.py`. If a `geometric_solution` attribute is specified, the `solveOneCycle` function uses the solutions specified in this attribute list in its backward induction loop, instead of the current solution. The exponential discount factor is also resized by a factor of the `hyperbolic` discount variable. " | |
| "I implement hyperbolic discounting by modifying the `solveOneCycle` function in `core.py`. If a `geometric_solution` attribute is specified, the `solveOneCycle` function uses the solutions specified in this attribute list in its backward induction loop, instead of the current solution. The exponential discount factor is also resized by a factor of the `hyperbolic` discount variable. " |
| solution_t = solveOnePeriod(**temp_dict) | ||
| solution_cycle.insert(0, solution_t) | ||
| solution_next = solution_t | ||
| # solution_next = s/olution_t |
There was a problem hiding this comment.
There is a commented-out line with a typo ("s/olution_t" instead of "solution_t"). This commented code should be removed entirely as it serves no purpose.
| # solution_next = s/olution_t |
| 'T_age' : T_age, | ||
| 'T_cycle' : T_cycle | ||
| 'T_cycle' : T_cycle, | ||
| 'Hyperbolic_beta' : Hyperbolic_beta |
There was a problem hiding this comment.
The parameter name "Hyperbolic_beta" (with underscore) is inconsistent with "HyperbolicBeta" (without underscore) used elsewhere in the code. This should be "HyperbolicBeta" to match the implementation in ConsIndShockModel.py.
| "PermGroFacAgg": 1.0, # Aggregate permanent income growth factor (only matters for simulation) | ||
| "T_age": None, # Age after which simulated agents are automatically killed | ||
| "T_cycle": 1, # Number of periods in the cycle for this agent type | ||
| "HyperbolicBeta": 1, |
There was a problem hiding this comment.
The HyperbolicBeta parameter is added to init_perfect_foresight but lacks a descriptive comment like all other parameters in the dictionary. Add a comment such as "# Quasi-hyperbolic discount factor (naive agents)" to maintain consistency.
| "HyperbolicBeta": 1, | |
| "HyperbolicBeta": 1, # Quasi-hyperbolic discount factor (naive agents) |
| """ | ||
| self.defUtilityFuncs() | ||
| self.DiscFacEff = self.DiscFac * self.LivPrb | ||
| self.DiscFacEff = self.DiscFac * self.LivPrb * self.HyperbolicBeta |
There was a problem hiding this comment.
The new HyperbolicBeta functionality lacks automated test coverage. While there is a Jupyter notebook demonstrating the feature, there are no unit tests in the test_PerfForesightConsumerType.py file that verify the quasi-hyperbolic discounting behavior. Consider adding tests that verify the consumption functions match the expected algebraic solutions when HyperbolicBeta is not equal to 1.
| "geom_solution = deepcopy(PFexample.solution)\n", | ||
| "PFexample_hyperbolic = deepcopy(PFexample)\n", | ||
| "PFexample_hyperbolic.geometric_solution = geom_solution\n", | ||
| "PFexample_hyperbolic.Hyperbolic_beta=0.7\n", |
There was a problem hiding this comment.
The notebook uses "Hyperbolic_beta" (line 223) which is inconsistent with the parameter name "HyperbolicBeta" used in the implementation. This should be "HyperbolicBeta" (without underscore) to match the code.
| "PFexample_hyperbolic.Hyperbolic_beta=0.7\n", | |
| "PFexample_hyperbolic.HyperbolicBeta=0.7\n", |
|
The issue was turned into a discussion. Should I still try to clean this up and sync up with new changes? @mnwhite |
|
No, you don't need to do it. This is still a task for me. I left the PR
open because it's still a new model that I don't want to throw away. It
will probably be moved to a totally new PR when I get around to that,
because it's so out of date.
…On Sun, Mar 8, 2026 at 11:45 AM Mridul Seth ***@***.***> wrote:
*MridulS* left a comment (econ-ark/HARK#833)
<#833 (comment)>
The issue was turned into a discussion. Should I still try to clean this
up and sync up with new changes? @mnwhite <https://github.com/mnwhite>
—
Reply to this email directly, view it on GitHub
<#833 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADKRAFLK2C6UMMMWAOJYD2T4PWITPAVCNFSM6AAAAACTG5K2OGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DAMJZGI4TMNRVHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
implements #215
replaces #815