Skip to content
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

Fix cons bequest #1392

Merged
merged 3 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_ + [

Check warning on line 38 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L38

Added line #L38 was not covered by tests
"BeqCRRA",
"BeqFac",
"BeqShift",
]

time_vary_ = IndShockConsumerType.time_vary_ + [

Check warning on line 43 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L43

Added line #L43 was not covered by tests
"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(

Check warning on line 53 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L53

Added line #L53 was not covered by tests
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.")

Check warning on line 63 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L62-L63

Added lines #L62 - L63 were not covered by tests

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.")

Check warning on line 75 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L74-L75

Added lines #L74 - L75 were not covered by tests

def update_solution_terminal(self):
if self.TermBeqFac == 0.0: # No terminal bequest
Expand All @@ -90,7 +81,9 @@
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 @@
self.solution_terminal.mNrmMin = 0.0


class BequestWarmGlowPortfolioType(PortfolioConsumerType, BequestWarmGlowConsumerType):
class BequestWarmGlowPortfolioType(PortfolioConsumerType):
time_inv_ = IndShockConsumerType.time_inv_ + [

Check warning on line 114 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L113-L114

Added lines #L113 - L114 were not covered by tests
"BeqCRRA",
"BeqShift",
]

time_vary_ = IndShockConsumerType.time_vary_ + [

Check warning on line 119 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L119

Added line #L119 was not covered by tests
"BeqFac",
]

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

self.solve_one_period = make_one_period_oo_solver(
BequestWarmGlowPortfolioSolver
BequestWarmGlowPortfolioSolver,
)

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

Check warning on line 136 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L136

Added line #L136 was not covered by tests
self.update_parameters()

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

Check warning on line 141 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L139-L141

Added lines #L139 - L141 were not covered by tests

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(

Check warning on line 148 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L143-L148

Added lines #L143 - L148 were not covered by tests
"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.")

Check warning on line 153 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L152-L153

Added lines #L152 - L153 were not covered by tests

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()

Check warning on line 157 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L156-L157

Added lines #L156 - L157 were not covered by tests
else:
utility = UtilityFuncCRRA(self.CRRA)

Check warning on line 159 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L159

Added line #L159 was not covered by tests

warm_glow = UtilityFuncStoneGeary(

Check warning on line 161 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L161

Added line #L161 was not covered by tests
self.TermBeqCRRA,
factor=self.TermBeqFac,
shifter=self.TermBeqShift,
)

aNrmGrid = (

Check warning on line 167 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L167

Added line #L167 was not covered by tests
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))

Check warning on line 176 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L172-L176

Added lines #L172 - L176 were not covered by tests

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)

Check warning on line 182 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L178-L182

Added lines #L178 - L182 were not covered by tests

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

Check warning on line 188 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L184-L188

Added lines #L184 - L188 were not covered by tests

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

Check warning on line 192 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L191-L192

Added lines #L191 - L192 were not covered by tests

# 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)

Check warning on line 196 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L195-L196

Added lines #L195 - L196 were not covered by tests

# 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)

Check warning on line 200 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L199-L200

Added lines #L199 - L200 were not covered by tests

# 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)

Check warning on line 204 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L203-L204

Added lines #L203 - L204 were not covered by tests
# No future, no marg value of Share
dvdsFuncFxd_terminal = ConstantFunction(0.0)

Check warning on line 206 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L206

Added line #L206 was not covered by tests

# Construct the terminal period solution
self.solution_terminal = PortfolioSolution(

Check warning on line 209 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L209

Added line #L209 was not covered by tests
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 @@

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

def def_BoroCnst(self, BoroCnstArt):
self.BoroCnstNat = (

Check warning on line 266 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L265-L266

Added lines #L265 - L266 were not covered by tests
(self.solution_next.mNrmMin - self.TranShkMinNext)
* (self.PermGroFac * self.PermShkMinNext)
/ self.Rfree
)

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

Check warning on line 272 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L272

Added line #L272 was not covered by tests

if BoroCnstArt is None:
self.mNrmMinNow = self.BoroCnstNat

Check warning on line 275 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L274-L275

Added lines #L274 - L275 were not covered by tests
else:
self.mNrmMinNow = np.max([self.BoroCnstNat, BoroCnstArt])
if self.BoroCnstNat < self.mNrmMinNow:
self.MPCmaxEff = 1.0

Check warning on line 279 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L277-L279

Added lines #L277 - L279 were not covered by tests
else:
self.MPCmaxEff = self.MPCmaxNow

Check warning on line 281 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L281

Added line #L281 was not covered by tests

self.cFuncNowCnst = LinearInterp(

Check warning on line 283 in HARK/ConsumptionSaving/ConsBequestModel.py

View check run for this annotation

Codecov / codecov/patch

HARK/ConsumptionSaving/ConsBequestModel.py#L283

Added line #L283 was not covered by tests
np.array([self.mNrmMinNow, self.mNrmMinNow + 1]), np.array([0.0, 1.0])
)

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

Expand Down
28 changes: 14 additions & 14 deletions HARK/ConsumptionSaving/ConsIndShockModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,10 @@
See NARK https://github.com/econ-ark/HARK/blob/master/Documentation/NARK/NARK.pdf for information on variable naming conventions.
See HARK documentation for mathematical descriptions of the models being solved.
"""

from copy import copy, deepcopy

import numpy as np
from scipy import sparse as sp
from scipy.optimize import newton

from HARK import (
AgentType,
NullFunc,
_log,
make_one_period_oo_solver,
set_verbosity_level,
)
from HARK.Calibration.Income.IncomeTools import (
Cagetti_income,
parse_income_spec,
Expand All @@ -43,7 +34,6 @@
combine_indep_dstns,
expected,
)
from HARK.interpolation import CubicHermiteInterp as CubicInterp
from HARK.interpolation import (
CubicInterp,
LinearInterp,
Expand Down Expand Up @@ -71,6 +61,16 @@
jump_to_grid_2D,
make_grid_exp_mult,
)
from scipy import sparse as sp
from scipy.optimize import newton

from HARK import (
AgentType,
NullFunc,
_log,
make_one_period_oo_solver,
set_verbosity_level,
)

__all__ = [
"ConsumerSolution",
Expand Down Expand Up @@ -2221,8 +2221,8 @@ def check_conditions(self, verbose=None):


# Make a dictionary to specify an idiosyncratic income shocks consumer
init_idiosyncratic_shocks = dict(
init_perfect_foresight,
init_idiosyncratic_shocks = {
**init_perfect_foresight,
**{ # assets above grid parameters
"aXtraMin": 0.001, # Minimum end-of-period "assets above minimum" value
"aXtraMax": 20, # Maximum end-of-period "assets above minimum" value
Expand Down Expand Up @@ -2255,7 +2255,7 @@ def check_conditions(self, verbose=None):
# Whether Newborns have transitory shock. The default is False.
"NewbornTransShk": False,
},
)
}


class IndShockConsumerType(PerfForesightConsumerType):
Expand Down
117 changes: 62 additions & 55 deletions examples/ConsBequestModel/example_AccidentalBequest.ipynb

Large diffs are not rendered by default.

Loading
Loading