Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into pr/1389
Browse files Browse the repository at this point in the history
  • Loading branch information
alanlujan91 committed Mar 11, 2024
2 parents de17841 + bbb07a5 commit c11703b
Show file tree
Hide file tree
Showing 57 changed files with 788 additions and 965 deletions.
44 changes: 6 additions & 38 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,17 @@ exclude: Documentation/example_notebooks/

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.4
rev: v0.3.2
hooks:
- id: ruff
types_or: [jupyter]
types_or: [ python, pyi, jupyter ]
args:
- --fix
- id: ruff-format
args: [--check]
types_or: [jupyter]

- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
exclude: ^examples/

- repo: https://github.com/asottile/pyupgrade
rev: v3.10.1
hooks:
- id: pyupgrade
args: ["--py38-plus"]
exclude: ^examples/

- repo: https://github.com/asottile/blacken-docs
rev: 1.15.0
hooks:
- id: blacken-docs
exclude: ^examples/

- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
name: isort (python)
args: ["--profile", "black", "--filter-files", "--skip", "__init__.py"]
exclude: ^examples/

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.1
hooks:
- id: prettier
exclude: ^examples/
types_or: [ python, pyi, jupyter ]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
Expand Down
32 changes: 28 additions & 4 deletions Documentation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,41 @@ For more information on HARK, see [our Github organization](https://github.com/e

## Changes

### 0.15.0

Release Date: TBA

### Major Changes

### Minor Changes

- Add option to pass pre-built grid to `LinearFast`. [1388](https://github.com/econ-ark/HARK/pull/1388)
- Moves calculation of stable points out of ConsIndShock solver, into method called by post_solve [#1349](https://github.com/econ-ark/HARK/pull/1349)

### 0.14.1

Release date: February 28, 2024

#### Major Changes

none

#### Minor Changes

- Fixes a bug in make_figs arising from the metadata argument being incompatible with jpg. [#1386](https://github.com/econ-ark/HARK/pull/1386)
- Reverts behavior of the repr method of the Model class, so that long strings aren't generated. Full description is available with describe(). [#1390](https://github.com/econ-ark/HARK/pull/1390)

### 0.14.0

Release Date: February 12, 2024

### Major Changes
#### Major Changes

- Adds `HARK.core.AgentPopulation` class to represent a population of agents with ex-ante heterogeneous parametrizations as distributions. [#1237](https://github.com/econ-ark/HARK/pull/1237)
- Adds `HARK.core.Parameters` class to represent a collection of time varying and time invariant parameters in a model. [#1240](https://github.com/econ-ark/HARK/pull/1240)
- Adds `HARK.simulation.monte_carlo` module for generic Monte Carlo simulation functions using Python model configurations. [1296](https://github.com/econ-ark/HARK/pull/1296)

### Minor Changes
#### Minor Changes

- Adds option `sim_common_Rrisky` to control whether risky-asset models draw common or idiosyncratic returns in simulation. [#1250](https://github.com/econ-ark/HARK/pull/1250),[#1253](https://github.com/econ-ark/HARK/pull/1253)
- Addresses [#1255](https://github.com/econ-ark/HARK/issues/1255). Makes age-varying stochastic returns possible and draws from their discretized version. [#1262](https://github.com/econ-ark/HARK/pull/1262)
Expand All @@ -35,7 +59,7 @@ Release Date: February 12, 2024

Release Date: February 16, 2023

### Major Changes
#### Major Changes

- Updates the DCEGM tools to address the flaws identified in [issue #1062](https://github.com/econ-ark/HARK/issues/1062). PR: [1100](https://github.com/econ-ark/HARK/pull/1100).
- Updates `IndexDstn`, introducing the option to use an existing RNG instead of creating a new one, and creating and storing all the conditional distributions at initialization. [1104](https://github.com/econ-ark/HARK/pull/1104)
Expand All @@ -62,7 +86,7 @@ Release Date: February 16, 2023
- Reorganizes `HARK.distribution`. All distributions now inherit all features from `scipy.stats`. New `ContinuousFrozenDistribution` and `DiscreteFrozenDistribution` to use `scipy.stats` distributions not yet implemented in HARK. New `Distribution.discretize(N, method = "***")` replaces `Distribution.approx(N)`. New `DiscreteDistribution.limit` attribute describes continuous origin and discretization method. [#1197](https://github.com/econ-ark/HARK/pull/1197).
- Creates new class of _labeled_ models under `ConsLabeledModel` that use xarray for more expressive modeling of underlying mathematical and economics variables. [#1177](https://github.com/econ-ark/HARK/pull/1177)

### Minor Changes
#### Minor Changes

- Updates the lognormal-income-process constructor from `ConsIndShockModel.py` to use `IndexDistribution`. [#1024](https://github.com/econ-ark/HARK/pull/1024), [#1115](https://github.com/econ-ark/HARK/pull/1115)
- Allows for age-varying unemployment probabilities and replacement incomes with the lognormal income process constructor. [#1112](https://github.com/econ-ark/HARK/pull/1112)
Expand Down
1 change: 1 addition & 0 deletions HARK/ConsumptionSaving/ConsAggShockModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
basic solver. Also includes a subclass of Market called CobbDouglas economy,
used for solving "macroeconomic" models with aggregate shocks.
"""

from copy import deepcopy

import numpy as np
Expand Down
190 changes: 131 additions & 59 deletions HARK/ConsumptionSaving/ConsBequestModel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""
Classes to solve consumption-saving models with a bequest motive and
"""Classes to solve consumption-saving models with a bequest motive and
idiosyncratic shocks to income and wealth. All models here assume
separable CRRA utility of consumption and Stone-Geary utility of
savings with geometric discounting of the continuation value and
Expand All @@ -11,7 +10,6 @@
"""

import numpy as np

from HARK.ConsumptionSaving.ConsIndShockModel import (
ConsIndShockSolver,
IndShockConsumerType,
Expand All @@ -37,51 +35,44 @@


class BequestWarmGlowConsumerType(IndShockConsumerType):
time_vary_ = IndShockConsumerType.time_vary_ + [
time_inv_ = IndShockConsumerType.time_inv_ + [
"BeqCRRA",
"BeqFac",
"BeqShift",
]

time_vary_ = IndShockConsumerType.time_vary_ + [
"BeqFac",
]

def __init__(self, **kwds):
params = init_wealth_in_utility.copy()
params.update(kwds)

super().__init__(**params)

self.solve_one_period = make_one_period_oo_solver(BequestWarmGlowConsumerSolver)
self.solve_one_period = make_one_period_oo_solver(
BequestWarmGlowConsumerSolver,
)

def update(self):
super().update()
self.update_parameters()

def update_parameters(self):
if isinstance(self.BeqCRRA, (int, float)):
self.BeqCRRA = [self.BeqCRRA] * self.T_cycle
elif len(self.BeqCRRA) == 1:
self.BeqCRRA *= self.T_cycle
elif len(self.BeqCRRA) != self.T_cycle:
raise ValueError(
"Bequest CRRA parameter must be a single value or a list of length T_cycle"
)
if not isinstance(self.BeqCRRA, (int, float)):
raise ValueError("Bequest CRRA parameter must be a single value.")

if isinstance(self.BeqFac, (int, float)):
self.BeqFac = [self.BeqFac] * self.T_cycle
elif len(self.BeqFac) == 1:
self.BeqFac *= self.T_cycle
elif len(self.BeqFac) != self.T_cycle:
raise ValueError(
"Bequest relative value parameter must be a single value or a list of length T_cycle"
"Bequest relative value parameter must be a single value or a list of length T_cycle",
)

if isinstance(self.BeqShift, (int, float)):
self.BeqShift = [self.BeqShift] * self.T_cycle
elif len(self.BeqShift) == 1:
self.BeqShift *= self.T_cycle
elif len(self.BeqShift) != self.T_cycle:
raise ValueError(
"Bequest Stone-Geary parameter must be a single value or a list of length T_cycle"
)
if not isinstance(self.BeqShift, (int, float)):
raise ValueError("Bequest Stone-Geary parameter must be a single value.")

def update_solution_terminal(self):
if self.TermBeqFac == 0.0: # No terminal bequest
Expand All @@ -90,7 +81,9 @@ def update_solution_terminal(self):
utility = UtilityFuncCRRA(self.CRRA)

warm_glow = UtilityFuncStoneGeary(
self.TermBeqCRRA, factor=self.TermBeqFac, shifter=self.TermBeqShift
self.TermBeqCRRA,
factor=self.TermBeqFac,
shifter=self.TermBeqShift,
)

aNrmGrid = (
Expand All @@ -117,7 +110,16 @@ def update_solution_terminal(self):
self.solution_terminal.mNrmMin = 0.0


class BequestWarmGlowPortfolioType(PortfolioConsumerType, BequestWarmGlowConsumerType):
class BequestWarmGlowPortfolioType(PortfolioConsumerType):
time_inv_ = IndShockConsumerType.time_inv_ + [
"BeqCRRA",
"BeqShift",
]

time_vary_ = IndShockConsumerType.time_vary_ + [
"BeqFac",
]

def __init__(self, **kwds):
params = init_portfolio_bequest.copy()
params.update(kwds)
Expand All @@ -127,46 +129,94 @@ def __init__(self, **kwds):
super().__init__(**params)

self.solve_one_period = make_one_period_oo_solver(
BequestWarmGlowPortfolioSolver
BequestWarmGlowPortfolioSolver,
)

def update(self):
PortfolioConsumerType.update(self)
super().update()
self.update_parameters()

def update_parameters(self):
if not isinstance(self.BeqCRRA, (int, float)):
raise ValueError("Bequest CRRA parameter must be a single value.")

if isinstance(self.BeqFac, (int, float)):
self.BeqFac = [self.BeqFac] * self.T_cycle
elif len(self.BeqFac) == 1:
self.BeqFac *= self.T_cycle
elif len(self.BeqFac) != self.T_cycle:
raise ValueError(
"Bequest relative value parameter must be a single value or a list of length T_cycle",
)

if not isinstance(self.BeqShift, (int, float)):
raise ValueError("Bequest Stone-Geary parameter must be a single value.")

def update_solution_terminal(self):
BequestWarmGlowConsumerType.update_solution_terminal(self)

# Consume all market resources: c_T = m_T
cFuncAdj_terminal = self.solution_terminal.cFunc
cFuncFxd_terminal = lambda m, s: self.solution_terminal.cFunc(m)

# Risky share is irrelevant-- no end-of-period assets; set to zero
ShareFuncAdj_terminal = ConstantFunction(0.0)
ShareFuncFxd_terminal = IdentityFunction(i_dim=1, n_dims=2)

# Value function is simply utility from consuming market resources
vFuncAdj_terminal = self.solution_terminal.vFunc
vFuncFxd_terminal = lambda m, s: self.solution_terminal.vFunc(m)

# Marginal value of market resources is marg utility at the consumption function
vPfuncAdj_terminal = self.solution_terminal.vPfunc
dvdmFuncFxd_terminal = lambda m, s: self.solution_terminal.vPfunc(m)
# No future, no marg value of Share
dvdsFuncFxd_terminal = ConstantFunction(0.0)

# Construct the terminal period solution
self.solution_terminal = PortfolioSolution(
cFuncAdj=cFuncAdj_terminal,
ShareFuncAdj=ShareFuncAdj_terminal,
vFuncAdj=vFuncAdj_terminal,
vPfuncAdj=vPfuncAdj_terminal,
cFuncFxd=cFuncFxd_terminal,
ShareFuncFxd=ShareFuncFxd_terminal,
vFuncFxd=vFuncFxd_terminal,
dvdmFuncFxd=dvdmFuncFxd_terminal,
dvdsFuncFxd=dvdsFuncFxd_terminal,
)
if self.TermBeqFac == 0.0: # No terminal bequest
super().update_solution_terminal()
else:
utility = UtilityFuncCRRA(self.CRRA)

warm_glow = UtilityFuncStoneGeary(
self.TermBeqCRRA,
factor=self.TermBeqFac,
shifter=self.TermBeqShift,
)

aNrmGrid = (
np.append(0.0, self.aXtraGrid)
if self.TermBeqShift != 0.0
else self.aXtraGrid
)
cNrmGrid = utility.derinv(warm_glow.der(aNrmGrid))
vGrid = utility(cNrmGrid) + warm_glow(aNrmGrid)
cNrmGridW0 = np.append(0.0, cNrmGrid)
mNrmGridW0 = np.append(0.0, aNrmGrid + cNrmGrid)
vNvrsGridW0 = np.append(0.0, utility.inv(vGrid))

cFunc_term = LinearInterp(mNrmGridW0, cNrmGridW0)
vNvrsFunc_term = LinearInterp(mNrmGridW0, vNvrsGridW0)
vFunc_term = ValueFuncCRRA(vNvrsFunc_term, self.CRRA)
vPfunc_term = MargValueFuncCRRA(cFunc_term, self.CRRA)
vPPfunc_term = MargMargValueFuncCRRA(cFunc_term, self.CRRA)

self.solution_terminal.cFunc = cFunc_term
self.solution_terminal.vFunc = vFunc_term
self.solution_terminal.vPfunc = vPfunc_term
self.solution_terminal.vPPfunc = vPPfunc_term
self.solution_terminal.mNrmMin = 0.0

# Consume all market resources: c_T = m_T
cFuncAdj_terminal = self.solution_terminal.cFunc
cFuncFxd_terminal = lambda m, s: self.solution_terminal.cFunc(m)

# Risky share is irrelevant-- no end-of-period assets; set to zero
ShareFuncAdj_terminal = ConstantFunction(0.0)
ShareFuncFxd_terminal = IdentityFunction(i_dim=1, n_dims=2)

# Value function is simply utility from consuming market resources
vFuncAdj_terminal = self.solution_terminal.vFunc
vFuncFxd_terminal = lambda m, s: self.solution_terminal.vFunc(m)

# Marginal value of market resources is marg utility at the consumption function
vPfuncAdj_terminal = self.solution_terminal.vPfunc
dvdmFuncFxd_terminal = lambda m, s: self.solution_terminal.vPfunc(m)
# No future, no marg value of Share
dvdsFuncFxd_terminal = ConstantFunction(0.0)

# Construct the terminal period solution
self.solution_terminal = PortfolioSolution(
cFuncAdj=cFuncAdj_terminal,
ShareFuncAdj=ShareFuncAdj_terminal,
vFuncAdj=vFuncAdj_terminal,
vPfuncAdj=vPfuncAdj_terminal,
cFuncFxd=cFuncFxd_terminal,
ShareFuncFxd=ShareFuncFxd_terminal,
vFuncFxd=vFuncFxd_terminal,
dvdmFuncFxd=dvdmFuncFxd_terminal,
dvdsFuncFxd=dvdsFuncFxd_terminal,
)


class BequestWarmGlowConsumerSolver(ConsIndShockSolver):
Expand Down Expand Up @@ -212,6 +262,28 @@ def def_utility_funcs(self):

self.warm_glow = UtilityFuncStoneGeary(self.BeqCRRA, BeqFacEff, self.BeqShift)

def def_BoroCnst(self, BoroCnstArt):
self.BoroCnstNat = (
(self.solution_next.mNrmMin - self.TranShkMinNext)
* (self.PermGroFac * self.PermShkMinNext)
/ self.Rfree
)

self.BoroCnstNat = np.max([self.BoroCnstNat, -self.BeqShift])

if BoroCnstArt is None:
self.mNrmMinNow = self.BoroCnstNat
else:
self.mNrmMinNow = np.max([self.BoroCnstNat, BoroCnstArt])
if self.BoroCnstNat < self.mNrmMinNow:
self.MPCmaxEff = 1.0
else:
self.MPCmaxEff = self.MPCmaxNow

self.cFuncNowCnst = LinearInterp(
np.array([self.mNrmMinNow, self.mNrmMinNow + 1]), np.array([0.0, 1.0])
)

def calc_EndOfPrdvP(self):
EndofPrdvP = super().calc_EndOfPrdvP()

Expand Down
Loading

0 comments on commit c11703b

Please sign in to comment.