Coverage for HARK/ConsumptionSaving/ConsPrefShockModel.py: 94%
309 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-02 05:14 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-02 05:14 +0000
1"""
2Extensions to ConsIndShockModel concerning models with preference shocks.
3It currently only two models:
51) An extension of ConsIndShock, but with an iid lognormal multiplicative shock each period.
62) A combination of (1) and ConsKinkedR, demonstrating how to construct a new model
7 by inheriting from multiple classes.
8"""
10import numpy as np
12from HARK import NullFunc
13from HARK.ConsumptionSaving.ConsIndShockModel import (
14 ConsumerSolution,
15 IndShockConsumerType,
16 KinkedRconsumerType,
17 make_assets_grid,
18 make_basic_CRRA_solution_terminal,
19 make_lognormal_kNrm_init_dstn,
20 make_lognormal_pLvl_init_dstn,
21)
22from HARK.Calibration.Income.IncomeProcesses import (
23 construct_lognormal_income_process_unemployment,
24 get_PermShkDstn_from_IncShkDstn,
25 get_TranShkDstn_from_IncShkDstn,
26)
27from HARK.distributions import MeanOneLogNormal, expected
28from HARK.interpolation import (
29 CubicInterp,
30 LinearInterp,
31 LinearInterpOnInterp1D,
32 LowerEnvelope,
33 MargValueFuncCRRA,
34 ValueFuncCRRA,
35)
36from HARK.rewards import UtilityFuncCRRA
38__all__ = [
39 "PrefShockConsumerType",
40 "KinkyPrefConsumerType",
41 "make_lognormal_PrefShkDstn",
42]
45def make_lognormal_PrefShkDstn(
46 T_cycle,
47 PrefShkStd,
48 PrefShkCount,
49 RNG,
50 PrefShk_tail_N=0,
51 PrefShk_tail_order=np.e,
52 PrefShk_tail_bound=[0.02, 0.98],
53):
54 r"""
55 Make a discretized mean one lognormal preference shock distribution for each
56 period of the agent's problem.
58 .. math::
59 \eta_t \sim \mathcal{N}(-\textbf{PrefShkStd}_{t}^{2}/2,\textbf{PrefShkStd}_{t}^2)
61 Parameters
62 ----------
63 T_cycle : int
64 Number of non-terminal periods in the agent's cycle.
65 PrefShkStd : [float]
66 Standard deviation of log preference shocks in each period.
67 PrefShkCount : int
68 Number of equiprobable preference shock nodes in the "body" of the distribution.
69 RNG : RandomState
70 The AgentType's internal random number generator.
71 PrefShk_tail_N : int
72 Number of shock nodes in each "tail" of the distribution (optional).
73 PrefShk_tail_order : float
74 Scaling factor for tail nodes (optional).
75 PrefShk_tail_bound : [float,float]
76 CDF bounds for tail nodes (optional).
78 Returns
79 -------
80 PrefShkDstn : [DiscreteDistribution]
81 List of discretized lognormal distributions for shocks.
82 """
83 PrefShkDstn = [] # discrete distributions of preference shocks
84 for t in range(T_cycle):
85 PrefShkStd = PrefShkStd[t]
86 new_dstn = MeanOneLogNormal(
87 sigma=PrefShkStd, seed=RNG.integers(0, 2**31 - 1)
88 ).discretize(
89 N=PrefShkCount,
90 method="equiprobable",
91 tail_N=PrefShk_tail_N,
92 tail_order=PrefShk_tail_order,
93 tail_bound=PrefShk_tail_bound,
94 )
95 PrefShkDstn.append(new_dstn)
96 return PrefShkDstn
99###############################################################################
102def solve_one_period_ConsPrefShock(
103 solution_next,
104 IncShkDstn,
105 PrefShkDstn,
106 LivPrb,
107 DiscFac,
108 CRRA,
109 Rfree,
110 PermGroFac,
111 BoroCnstArt,
112 aXtraGrid,
113 vFuncBool,
114 CubicBool,
115):
116 """
117 Solves one period of a consumption-saving model with idiosyncratic shocks to
118 permanent and transitory income, with one risk free asset and CRRA utility.
119 The consumer also faces iid preference shocks as a multiplicative shifter to
120 their marginal utility of consumption.
122 Parameters
123 ----------
124 solution_next : ConsumerSolution
125 The solution to the succeeding one period problem.
126 IncShkDstn : distribution.Distribution
127 A discrete approximation to the income process between the period being
128 solved and the one immediately following (in solution_next). Order:
129 permanent shocks, transitory shocks.
130 PrefShkDstn : distribution.Distribution
131 Discrete distribution of the multiplicative utility shifter. Order:
132 probabilities, preference shocks.
133 LivPrb : float
134 Survival probability; likelihood of being alive at the beginning of
135 the succeeding period.
136 DiscFac : float
137 Intertemporal discount factor for future utility.
138 CRRA : float
139 Coefficient of relative risk aversion.
140 Rfree : float
141 Risk free interest factor on end-of-period assets.
142 PermGroGac : float
143 Expected permanent income growth factor at the end of this period.
144 BoroCnstArt: float or None
145 Borrowing constraint for the minimum allowable assets to end the
146 period with. If it is less than the natural borrowing constraint,
147 then it is irrelevant; BoroCnstArt=None indicates no artificial bor-
148 rowing constraint.
149 aXtraGrid: np.array
150 Array of "extra" end-of-period asset values-- assets above the
151 absolute minimum acceptable level.
152 vFuncBool: boolean
153 An indicator for whether the value function should be computed and
154 included in the reported solution.
155 CubicBool: boolean
156 An indicator for whether the solver should use cubic or linear inter-
157 polation.
159 Returns
160 -------
161 solution: ConsumerSolution
162 The solution to the single period consumption-saving problem. Includes
163 a consumption function cFunc (using linear splines), a marginal value
164 function vPfunc, a minimum acceptable level of normalized market re-
165 sources mNrmMin, normalized human wealth hNrm, and bounding MPCs MPCmin
166 and MPCmax. It might also have a value function vFunc. The consumption
167 function is defined over normalized market resources and the preference
168 shock, c = cFunc(m,PrefShk), but the (marginal) value function is defined
169 unconditionally on the shock, just before it is revealed.
170 """
171 # Define the current period utility function and effective discount factor
172 uFunc = UtilityFuncCRRA(CRRA)
173 DiscFacEff = DiscFac * LivPrb # "effective" discount factor
175 # Unpack next period's income and preference shock distributions
176 ShkPrbsNext = IncShkDstn.pmv
177 PermShkValsNext = IncShkDstn.atoms[0]
178 TranShkValsNext = IncShkDstn.atoms[1]
179 PermShkMinNext = np.min(PermShkValsNext)
180 TranShkMinNext = np.min(TranShkValsNext)
181 PrefShkPrbs = PrefShkDstn.pmv
182 PrefShkVals = PrefShkDstn.atoms.flatten()
184 # Calculate the probability that we get the worst possible income draw
185 IncNext = PermShkValsNext * TranShkValsNext
186 WorstIncNext = PermShkMinNext * TranShkMinNext
187 WorstIncPrb = np.sum(ShkPrbsNext[IncNext == WorstIncNext])
188 # WorstIncPrb is the "Weierstrass p" concept: the odds we get the WORST thing
190 # Unpack next period's (marginal) value function
191 vFuncNext = solution_next.vFunc # This is None when vFuncBool is False
192 vPfuncNext = solution_next.vPfunc
193 vPPfuncNext = solution_next.vPPfunc # This is None when CubicBool is False
195 # Update the bounding MPCs and PDV of human wealth:
196 PatFac = ((Rfree * DiscFacEff) ** (1.0 / CRRA)) / Rfree
197 try:
198 MPCminNow = 1.0 / (1.0 + PatFac / solution_next.MPCmin)
199 except:
200 MPCminNow = 0.0
201 Ex_IncNext = np.dot(ShkPrbsNext, TranShkValsNext * PermShkValsNext)
202 hNrmNow = PermGroFac / Rfree * (Ex_IncNext + solution_next.hNrm)
203 temp_fac = (WorstIncPrb ** (1.0 / CRRA)) * PatFac
204 MPCmaxNow = 1.0 / (1.0 + temp_fac / solution_next.MPCmax)
206 # Calculate the minimum allowable value of money resources in this period
207 PermGroFacEffMin = (PermGroFac * PermShkMinNext) / Rfree
208 BoroCnstNat = (solution_next.mNrmMin - TranShkMinNext) * PermGroFacEffMin
210 # Set the minimum allowable (normalized) market resources based on the natural
211 # and artificial borrowing constraints
212 if BoroCnstArt is None:
213 mNrmMinNow = BoroCnstNat
214 else:
215 mNrmMinNow = np.max([BoroCnstNat, BoroCnstArt])
217 # Set the upper limit of the MPC (at mNrmMinNow) based on whether the natural
218 # or artificial borrowing constraint actually binds
219 if BoroCnstNat < mNrmMinNow:
220 MPCmaxEff = 1.0 # If actually constrained, MPC near limit is 1
221 else:
222 MPCmaxEff = MPCmaxNow # Otherwise, it's the MPC calculated above
224 # Define the borrowing-constrained consumption function
225 cFuncNowCnst = LinearInterp(
226 np.array([mNrmMinNow, mNrmMinNow + 1.0]), np.array([0.0, 1.0])
227 )
229 # Construct the assets grid by adjusting aXtra by the natural borrowing constraint
230 aNrmNow = np.asarray(aXtraGrid) + BoroCnstNat
232 # Define local functions for taking future expectations
233 def calc_mNrmNext(S, a, R):
234 return R / (PermGroFac * S["PermShk"]) * a + S["TranShk"]
236 def calc_vNext(S, a, R):
237 return (S["PermShk"] ** (1.0 - CRRA) * PermGroFac ** (1.0 - CRRA)) * vFuncNext(
238 calc_mNrmNext(S, a, R)
239 )
241 def calc_vPnext(S, a, R):
242 return S["PermShk"] ** (-CRRA) * vPfuncNext(calc_mNrmNext(S, a, R))
244 def calc_vPPnext(S, a, R):
245 return S["PermShk"] ** (-CRRA - 1.0) * vPPfuncNext(calc_mNrmNext(S, a, R))
247 # Calculate end-of-period marginal value of assets at each gridpoint
248 vPfacEff = DiscFacEff * Rfree * PermGroFac ** (-CRRA)
249 EndOfPrdvP = vPfacEff * expected(calc_vPnext, IncShkDstn, args=(aNrmNow, Rfree))
251 # Find optimal consumption corresponding to each aNrm, PrefShk combination
252 cNrm_base = uFunc.derinv(EndOfPrdvP, order=(1, 0))
253 PrefShkCount = PrefShkVals.size
254 PrefShk_temp = np.tile(
255 np.reshape(PrefShkVals ** (1.0 / CRRA), (PrefShkCount, 1)),
256 (1, cNrm_base.size),
257 )
258 cNrmNow = np.tile(cNrm_base, (PrefShkCount, 1)) * PrefShk_temp
259 mNrmNow = cNrmNow + np.tile(aNrmNow, (PrefShkCount, 1))
260 # These are the endogenous gridpoints, as usual
262 # Add the bottom point to the c and m arrays
263 m_for_interpolation = np.concatenate(
264 (BoroCnstNat * np.ones((PrefShkCount, 1)), mNrmNow), axis=1
265 )
266 c_for_interpolation = np.concatenate((np.zeros((PrefShkCount, 1)), cNrmNow), axis=1)
268 # Construct the consumption function as a cubic or linear spline interpolation
269 # for each value of PrefShk, interpolated across those values.
270 if CubicBool:
271 # This is not yet supported, not sure why we never got to it
272 raise (
273 ValueError,
274 "Cubic interpolation is not yet supported by the preference shock model!",
275 )
277 # Make the preference-shock specific consumption functions
278 cFuncs_by_PrefShk = []
279 for j in range(PrefShkCount):
280 MPCmin_j = MPCminNow * PrefShkVals[j] ** (1.0 / CRRA)
281 cFunc_this_shk = LowerEnvelope(
282 LinearInterp(
283 m_for_interpolation[j, :],
284 c_for_interpolation[j, :],
285 intercept_limit=hNrmNow * MPCmin_j,
286 slope_limit=MPCmin_j,
287 ),
288 cFuncNowCnst,
289 )
290 cFuncs_by_PrefShk.append(cFunc_this_shk)
292 # Combine the list of consumption functions into a single interpolation
293 cFuncNow = LinearInterpOnInterp1D(cFuncs_by_PrefShk, PrefShkVals)
295 # Make the ex ante marginal value function (before the preference shock)
296 m_grid = aXtraGrid + mNrmMinNow
297 vP_vec = np.zeros_like(m_grid)
298 for j in range(PrefShkCount): # numeric integration over the preference shock
299 vP_vec += (
300 uFunc.der(cFuncs_by_PrefShk[j](m_grid)) * PrefShkPrbs[j] * PrefShkVals[j]
301 )
302 vPnvrs_vec = uFunc.derinv(vP_vec, order=(1, 0))
303 vPfuncNow = MargValueFuncCRRA(LinearInterp(m_grid, vPnvrs_vec), CRRA)
305 # Define this period's marginal marginal value function
306 if CubicBool:
307 pass # This is impossible to reach right now
308 else:
309 vPPfuncNow = NullFunc() # Dummy object
311 # Construct this period's value function if requested
312 if vFuncBool:
313 # Calculate end-of-period value, its derivative, and their pseudo-inverse
314 EndOfPrdv = DiscFacEff * expected(calc_vNext, IncShkDstn, args=(aNrmNow, Rfree))
315 EndOfPrdvNvrs = uFunc.inv(
316 EndOfPrdv
317 ) # value transformed through inverse utility
318 EndOfPrdvNvrsP = EndOfPrdvP * uFunc.derinv(EndOfPrdv, order=(0, 1))
319 EndOfPrdvNvrs = np.insert(EndOfPrdvNvrs, 0, 0.0)
320 EndOfPrdvNvrsP = np.insert(EndOfPrdvNvrsP, 0, EndOfPrdvNvrsP[0])
321 # This is a very good approximation, vNvrsPP = 0 at the asset minimum
323 # Construct the end-of-period value function
324 aNrm_temp = np.insert(aNrmNow, 0, BoroCnstNat)
325 EndOfPrd_vNvrsFunc = CubicInterp(aNrm_temp, EndOfPrdvNvrs, EndOfPrdvNvrsP)
326 EndOfPrd_vFunc = ValueFuncCRRA(EndOfPrd_vNvrsFunc, CRRA)
328 # Compute expected value and marginal value on a grid of market resources,
329 # accounting for all of the discrete preference shocks
330 mNrm_temp = mNrmMinNow + aXtraGrid
331 v_temp = np.zeros_like(mNrm_temp)
332 vP_temp = np.zeros_like(mNrm_temp)
333 for j in range(PrefShkCount):
334 this_shock = PrefShkVals[j]
335 this_prob = PrefShkPrbs[j]
336 cNrm_temp = cFuncNow(mNrm_temp, this_shock * np.ones_like(mNrm_temp))
337 aNrm_temp = mNrm_temp - cNrm_temp
338 v_temp += this_prob * (
339 this_shock * uFunc(cNrm_temp) + EndOfPrd_vFunc(aNrm_temp)
340 )
341 vP_temp += this_prob * this_shock * uFunc.der(cNrm_temp)
343 # Construct the beginning-of-period value function
344 # value transformed through inverse utility
345 vNvrs_temp = uFunc.inv(v_temp)
346 vNvrsP_temp = vP_temp * uFunc.derinv(v_temp, order=(0, 1))
347 mNrm_temp = np.insert(mNrm_temp, 0, mNrmMinNow)
348 vNvrs_temp = np.insert(vNvrs_temp, 0, 0.0)
349 vNvrsP_temp = np.insert(vNvrsP_temp, 0, MPCmaxEff ** (-CRRA / (1.0 - CRRA)))
350 MPCminNvrs = MPCminNow ** (-CRRA / (1.0 - CRRA))
351 vNvrsFuncNow = CubicInterp(
352 mNrm_temp, vNvrs_temp, vNvrsP_temp, MPCminNvrs * hNrmNow, MPCminNvrs
353 )
354 vFuncNow = ValueFuncCRRA(vNvrsFuncNow, CRRA)
356 else:
357 vFuncNow = NullFunc() # Dummy object
359 # Create and return this period's solution
360 solution_now = ConsumerSolution(
361 cFunc=cFuncNow,
362 vFunc=vFuncNow,
363 vPfunc=vPfuncNow,
364 vPPfunc=vPPfuncNow,
365 mNrmMin=mNrmMinNow,
366 hNrm=hNrmNow,
367 MPCmin=MPCminNow,
368 MPCmax=MPCmaxEff,
369 )
370 return solution_now
373###############################################################################
376def solve_one_period_ConsKinkyPref(
377 solution_next,
378 IncShkDstn,
379 PrefShkDstn,
380 LivPrb,
381 DiscFac,
382 CRRA,
383 Rboro,
384 Rsave,
385 PermGroFac,
386 BoroCnstArt,
387 aXtraGrid,
388 vFuncBool,
389 CubicBool,
390):
391 """
392 Solves one period of a consumption-saving model with idiosyncratic shocks to
393 permanent and transitory income, with a risk free asset and CRRA utility.
394 In this variation, the interest rate on borrowing Rboro exceeds the interest
395 rate on saving Rsave. The consumer also faces iid preference shocks as a multi-
396 plicative shifter to their marginal utility of consumption.
398 Parameters
399 ----------
400 solution_next : ConsumerSolution
401 The solution to next period's one period problem.
402 IncShkDstn : distribution.Distribution
403 A discrete approximation to the income process between the period being
404 solved and the one immediately following (in solution_next).
405 PrefShkDstn : distribution.Distribution
406 Discrete distribution of the multiplicative utility shifter. Order:
407 probabilities, preference shocks.
408 LivPrb : float
409 Survival probability; likelihood of being alive at the beginning of
410 the succeeding period.
411 DiscFac : float
412 Intertemporal discount factor for future utility.
413 CRRA : float
414 Coefficient of relative risk aversion.
415 Rboro: float
416 Interest factor on assets between this period and the succeeding
417 period when assets are negative.
418 Rsave: float
419 Interest factor on assets between this period and the succeeding
420 period when assets are positive.
421 PermGroFac : float
422 Expected permanent income growth factor at the end of this period.
423 BoroCnstArt: float or None
424 Borrowing constraint for the minimum allowable assets to end the
425 period with. If it is less than the natural borrowing constraint,
426 then it is irrelevant; BoroCnstArt=None indicates no artificial bor-
427 rowing constraint.
428 aXtraGrid: np.array
429 Array of "extra" end-of-period asset values-- assets above the
430 absolute minimum acceptable level.
431 vFuncBool: boolean
432 An indicator for whether the value function should be computed and
433 included in the reported solution.
434 CubicBool: boolean
435 An indicator for whether the solver should use cubic or linear inter-
436 polation.
438 Returns
439 -------
440 solution_now : ConsumerSolution
441 The solution to the single period consumption-saving problem. Includes
442 a consumption function cFunc (using linear splines), a marginal value
443 function vPfunc, a minimum acceptable level of normalized market re-
444 sources mNrmMin, normalized human wealth hNrm, and bounding MPCs MPCmin
445 and MPCmax. It might also have a value function vFunc. The consumption
446 function is defined over normalized market resources and the preference
447 shock, c = cFunc(m,PrefShk), but the (marginal) value function is defined
448 unconditionally on the shock, just before it is revealed.
449 """
450 # Verifiy that there is actually a kink in the interest factor
451 assert Rboro >= Rsave, (
452 "Interest factor on debt less than interest factor on savings!"
453 )
454 # If the kink is in the wrong direction, code should break here. If there's
455 # no kink at all, then just use the ConsIndShockModel solver.
456 if Rboro == Rsave:
457 solution_now = solve_one_period_ConsPrefShock(
458 solution_next,
459 IncShkDstn,
460 PrefShkDstn,
461 LivPrb,
462 DiscFac,
463 CRRA,
464 Rboro,
465 PermGroFac,
466 BoroCnstArt,
467 aXtraGrid,
468 vFuncBool,
469 CubicBool,
470 )
471 return solution_now
473 # Define the current period utility function and effective discount factor
474 uFunc = UtilityFuncCRRA(CRRA)
475 DiscFacEff = DiscFac * LivPrb # "effective" discount factor
477 # Unpack next period's income and preference shock distributions
478 ShkPrbsNext = IncShkDstn.pmv
479 PermShkValsNext = IncShkDstn.atoms[0]
480 TranShkValsNext = IncShkDstn.atoms[1]
481 PermShkMinNext = np.min(PermShkValsNext)
482 TranShkMinNext = np.min(TranShkValsNext)
483 PrefShkPrbs = PrefShkDstn.pmv
484 PrefShkVals = PrefShkDstn.atoms.flatten()
486 # Calculate the probability that we get the worst possible income draw
487 IncNext = PermShkValsNext * TranShkValsNext
488 WorstIncNext = PermShkMinNext * TranShkMinNext
489 WorstIncPrb = np.sum(ShkPrbsNext[IncNext == WorstIncNext])
490 # WorstIncPrb is the "Weierstrass p" concept: the odds we get the WORST thing
492 # Unpack next period's (marginal) value function
493 vFuncNext = solution_next.vFunc # This is None when vFuncBool is False
494 vPfuncNext = solution_next.vPfunc
495 vPPfuncNext = solution_next.vPPfunc # This is None when CubicBool is False
497 # Update the bounding MPCs and PDV of human wealth:
498 PatFac = ((Rsave * DiscFacEff) ** (1.0 / CRRA)) / Rsave
499 PatFacAlt = ((Rboro * DiscFacEff) ** (1.0 / CRRA)) / Rboro
500 try:
501 MPCminNow = 1.0 / (1.0 + PatFac / solution_next.MPCmin)
502 except:
503 MPCminNow = 0.0
504 Ex_IncNext = np.dot(ShkPrbsNext, TranShkValsNext * PermShkValsNext)
505 hNrmNow = (PermGroFac / Rsave) * (Ex_IncNext + solution_next.hNrm)
506 temp_fac = (WorstIncPrb ** (1.0 / CRRA)) * PatFacAlt
507 MPCmaxNow = 1.0 / (1.0 + temp_fac / solution_next.MPCmax)
509 # Calculate the minimum allowable value of money resources in this period
510 PermGroFacEffMin = (PermGroFac * PermShkMinNext) / Rboro
511 BoroCnstNat = (solution_next.mNrmMin - TranShkMinNext) * PermGroFacEffMin
513 # Set the minimum allowable (normalized) market resources based on the natural
514 # and artificial borrowing constraints
515 if BoroCnstArt is None:
516 mNrmMinNow = BoroCnstNat
517 else:
518 mNrmMinNow = np.max([BoroCnstNat, BoroCnstArt])
520 # Set the upper limit of the MPC (at mNrmMinNow) based on whether the natural
521 # or artificial borrowing constraint actually binds
522 if BoroCnstNat < mNrmMinNow:
523 MPCmaxEff = 1.0 # If actually constrained, MPC near limit is 1
524 else:
525 MPCmaxEff = MPCmaxNow # Otherwise, it's the MPC calculated above
527 # Define the borrowing-constrained consumption function
528 cFuncNowCnst = LinearInterp(
529 np.array([mNrmMinNow, mNrmMinNow + 1.0]), np.array([0.0, 1.0])
530 )
532 # Construct the assets grid by adjusting aXtra by the natural borrowing constraint
533 aNrmNow = np.sort(
534 np.hstack((np.asarray(aXtraGrid) + mNrmMinNow, np.array([0.0, 0.0])))
535 )
537 # Make a 1D array of the interest factor at each asset gridpoint
538 Rfree = Rsave * np.ones_like(aNrmNow)
539 Rfree[aNrmNow < 0] = Rboro
540 i_kink = np.argwhere(aNrmNow == 0.0)[0][0]
541 Rfree[i_kink] = Rboro
543 # Define local functions for taking future expectations
544 def calc_mNrmNext(S, a, R):
545 return R / (PermGroFac * S["PermShk"]) * a + S["TranShk"]
547 def calc_vNext(S, a, R):
548 return (S["PermShk"] ** (1.0 - CRRA) * PermGroFac ** (1.0 - CRRA)) * vFuncNext(
549 calc_mNrmNext(S, a, R)
550 )
552 def calc_vPnext(S, a, R):
553 return S["PermShk"] ** (-CRRA) * vPfuncNext(calc_mNrmNext(S, a, R))
555 def calc_vPPnext(S, a, R):
556 return S["PermShk"] ** (-CRRA - 1.0) * vPPfuncNext(calc_mNrmNext(S, a, R))
558 # Calculate end-of-period marginal value of assets at each gridpoint
559 vPfacEff = DiscFacEff * Rfree * PermGroFac ** (-CRRA)
560 EndOfPrdvP = vPfacEff * expected(calc_vPnext, IncShkDstn, args=(aNrmNow, Rfree))
562 # Find optimal consumption corresponding to each aNrm, PrefShk combination
563 cNrm_base = uFunc.derinv(EndOfPrdvP, order=(1, 0))
564 PrefShkCount = PrefShkVals.size
565 PrefShk_temp = np.tile(
566 np.reshape(PrefShkVals ** (1.0 / CRRA), (PrefShkCount, 1)),
567 (1, cNrm_base.size),
568 )
569 cNrmNow = np.tile(cNrm_base, (PrefShkCount, 1)) * PrefShk_temp
570 mNrmNow = cNrmNow + np.tile(aNrmNow, (PrefShkCount, 1))
571 # These are the endogenous gridpoints, as usual
573 # Add the bottom point to the c and m arrays
574 m_for_interpolation = np.concatenate(
575 (BoroCnstNat * np.ones((PrefShkCount, 1)), mNrmNow), axis=1
576 )
577 c_for_interpolation = np.concatenate((np.zeros((PrefShkCount, 1)), cNrmNow), axis=1)
579 # Construct the consumption function as a cubic or linear spline interpolation
580 # for each value of PrefShk, interpolated across those values.
581 if CubicBool:
582 # This is not yet supported, not sure why we never got to it
583 raise (
584 ValueError,
585 "Cubic interpolation is not yet supported by the preference shock model!",
586 )
588 # Make the preference-shock specific consumption functions
589 cFuncs_by_PrefShk = []
590 for j in range(PrefShkCount):
591 MPCmin_j = MPCminNow * PrefShkVals[j] ** (1.0 / CRRA)
592 cFunc_this_shk = LowerEnvelope(
593 LinearInterp(
594 m_for_interpolation[j, :],
595 c_for_interpolation[j, :],
596 intercept_limit=hNrmNow * MPCmin_j,
597 slope_limit=MPCmin_j,
598 ),
599 cFuncNowCnst,
600 )
601 cFuncs_by_PrefShk.append(cFunc_this_shk)
603 # Combine the list of consumption functions into a single interpolation
604 cFuncNow = LinearInterpOnInterp1D(cFuncs_by_PrefShk, PrefShkVals)
606 # Make the ex ante marginal value function (before the preference shock)
607 m_grid = aXtraGrid + mNrmMinNow
608 vP_vec = np.zeros_like(m_grid)
609 for j in range(PrefShkCount): # numeric integration over the preference shock
610 vP_vec += (
611 uFunc.der(cFuncs_by_PrefShk[j](m_grid)) * PrefShkPrbs[j] * PrefShkVals[j]
612 )
613 vPnvrs_vec = uFunc.derinv(vP_vec, order=(1, 0))
614 vPfuncNow = MargValueFuncCRRA(LinearInterp(m_grid, vPnvrs_vec), CRRA)
616 # Define this period's marginal marginal value function
617 if CubicBool:
618 pass # This is impossible to reach right now
619 else:
620 vPPfuncNow = NullFunc() # Dummy object
622 # Construct this period's value function if requested
623 if vFuncBool:
624 # Calculate end-of-period value, its derivative, and their pseudo-inverse
625 EndOfPrdv = DiscFacEff * expected(calc_vNext, IncShkDstn, args=(aNrmNow, Rfree))
626 EndOfPrdvNvrs = uFunc.inv(
627 EndOfPrdv
628 ) # value transformed through inverse utility
629 EndOfPrdvNvrsP = EndOfPrdvP * uFunc.derinv(EndOfPrdv, order=(0, 1))
630 EndOfPrdvNvrs = np.insert(EndOfPrdvNvrs, 0, 0.0)
631 EndOfPrdvNvrsP = np.insert(EndOfPrdvNvrsP, 0, EndOfPrdvNvrsP[0])
632 # This is a very good approximation, vNvrsPP = 0 at the asset minimum
634 # Construct the end-of-period value function
635 aNrm_temp = np.insert(aNrmNow, 0, BoroCnstNat)
636 EndOfPrd_vNvrsFunc = CubicInterp(aNrm_temp, EndOfPrdvNvrs, EndOfPrdvNvrsP)
637 EndOfPrd_vFunc = ValueFuncCRRA(EndOfPrd_vNvrsFunc, CRRA)
639 # Compute expected value and marginal value on a grid of market resources,
640 # accounting for all of the discrete preference shocks
641 mNrm_temp = mNrmMinNow + aXtraGrid
642 v_temp = np.zeros_like(mNrm_temp)
643 vP_temp = np.zeros_like(mNrm_temp)
644 for j in range(PrefShkCount):
645 this_shock = PrefShkVals[j]
646 this_prob = PrefShkPrbs[j]
647 cNrm_temp = cFuncNow(mNrm_temp, this_shock * np.ones_like(mNrm_temp))
648 aNrm_temp = mNrm_temp - cNrm_temp
649 v_temp += this_prob * (
650 this_shock * uFunc(cNrm_temp) + EndOfPrd_vFunc(aNrm_temp)
651 )
652 vP_temp += this_prob * this_shock * uFunc.der(cNrm_temp)
654 # Construct the beginning-of-period value function
655 # value transformed through inverse utility
656 vNvrs_temp = uFunc.inv(v_temp)
657 vNvrsP_temp = vP_temp * uFunc.derinv(v_temp, order=(0, 1))
658 mNrm_temp = np.insert(mNrm_temp, 0, mNrmMinNow)
659 vNvrs_temp = np.insert(vNvrs_temp, 0, 0.0)
660 vNvrsP_temp = np.insert(vNvrsP_temp, 0, MPCmaxEff ** (-CRRA / (1.0 - CRRA)))
661 MPCminNvrs = MPCminNow ** (-CRRA / (1.0 - CRRA))
662 vNvrsFuncNow = CubicInterp(
663 mNrm_temp, vNvrs_temp, vNvrsP_temp, MPCminNvrs * hNrmNow, MPCminNvrs
664 )
665 vFuncNow = ValueFuncCRRA(vNvrsFuncNow, CRRA)
667 else:
668 vFuncNow = NullFunc() # Dummy object
670 # Create and return this period's solution
671 solution_now = ConsumerSolution(
672 cFunc=cFuncNow,
673 vFunc=vFuncNow,
674 vPfunc=vPfuncNow,
675 vPPfunc=vPPfuncNow,
676 mNrmMin=mNrmMinNow,
677 hNrm=hNrmNow,
678 MPCmin=MPCminNow,
679 MPCmax=MPCmaxEff,
680 )
681 return solution_now
684###############################################################################
686# Make a dictionary of constructors for the preference shock model
687PrefShockConsumerType_constructors_default = {
688 "IncShkDstn": construct_lognormal_income_process_unemployment,
689 "PermShkDstn": get_PermShkDstn_from_IncShkDstn,
690 "TranShkDstn": get_TranShkDstn_from_IncShkDstn,
691 "aXtraGrid": make_assets_grid,
692 "PrefShkDstn": make_lognormal_PrefShkDstn,
693 "solution_terminal": make_basic_CRRA_solution_terminal,
694 "kNrmInitDstn": make_lognormal_kNrm_init_dstn,
695 "pLvlInitDstn": make_lognormal_pLvl_init_dstn,
696}
698# Make a dictionary with parameters for the default constructor for kNrmInitDstn
699PrefShockConsumerType_kNrmInitDstn_default = {
700 "kLogInitMean": -12.0, # Mean of log initial capital
701 "kLogInitStd": 0.0, # Stdev of log initial capital
702 "kNrmInitCount": 15, # Number of points in initial capital discretization
703}
705# Make a dictionary with parameters for the default constructor for pLvlInitDstn
706PrefShockConsumerType_pLvlInitDstn_default = {
707 "pLogInitMean": 0.0, # Mean of log permanent income
708 "pLogInitStd": 0.0, # Stdev of log permanent income
709 "pLvlInitCount": 15, # Number of points in initial capital discretization
710}
712# Default parameters to make IncShkDstn using construct_lognormal_income_process_unemployment
713PrefShockConsumerType_IncShkDstn_default = {
714 "PermShkStd": [0.1], # Standard deviation of log permanent income shocks
715 "PermShkCount": 7, # Number of points in discrete approximation to permanent income shocks
716 "TranShkStd": [0.1], # Standard deviation of log transitory income shocks
717 "TranShkCount": 7, # Number of points in discrete approximation to transitory income shocks
718 "UnempPrb": 0.05, # Probability of unemployment while working
719 "IncUnemp": 0.3, # Unemployment benefits replacement rate while working
720 "T_retire": 0, # Period of retirement (0 --> no retirement)
721 "UnempPrbRet": 0.005, # Probability of "unemployment" while retired
722 "IncUnempRet": 0.0, # "Unemployment" benefits when retired
723}
725# Default parameters to make aXtraGrid using construct_assets_grid
727PrefShockConsumerType_aXtraGrid_default = {
728 "aXtraMin": 0.001, # Minimum end-of-period "assets above minimum" value
729 "aXtraMax": 20, # Maximum end-of-period "assets above minimum" value
730 "aXtraNestFac": 3, # Exponential nesting factor for aXtraGrid
731 "aXtraCount": 48, # Number of points in the grid of "assets above minimum"
732 "aXtraExtra": None, # Additional other values to add in grid (optional)
733}
735# Default parameters to make PrefShkDstn using make_lognormal_PrefShkDstn
737PrefShockConsumerType_PrefShkDstn_default = {
738 "PrefShkCount": 12, # Number of points in discrete approximation to preference shock dist
739 "PrefShk_tail_N": 4, # Number of "tail points" on each end of pref shock dist
740 "PrefShkStd": [0.30], # Standard deviation of utility shocks
741}
743# Make a dictionary to specify an preference shocks consumer type
744PrefShockConsumerType_solving_default = {
745 # BASIC HARK PARAMETERS REQUIRED TO SOLVE THE MODEL
746 "cycles": 1, # Finite, non-cyclic model
747 "T_cycle": 1, # Number of periods in the cycle for this agent type
748 "pseudo_terminal": False, # Terminal period really does exist
749 "constructors": PrefShockConsumerType_constructors_default, # See dictionary above
750 # PRIMITIVE RAW PARAMETERS REQUIRED TO SOLVE THE MODEL
751 "CRRA": 2.0, # Coefficient of relative risk aversion
752 "Rfree": [1.03], # Interest factor on retained assets
753 "DiscFac": 0.96, # Intertemporal discount factor
754 "LivPrb": [0.98], # Survival probability after each period
755 "PermGroFac": [1.01], # Permanent income growth factor
756 "BoroCnstArt": 0.0, # Artificial borrowing constraint
757 "vFuncBool": False, # Whether to calculate the value function during solution
758 "CubicBool": False, # Whether to use cubic spline interpolation when True
759 # (Uses linear spline interpolation for cFunc when False)
760}
761PrefShockConsumerType_simulation_default = {
762 # PARAMETERS REQUIRED TO SIMULATE THE MODEL
763 "AgentCount": 10000, # Number of agents of this type
764 "T_age": None, # Age after which simulated agents are automatically killed
765 "PermGroFacAgg": 1.0, # Aggregate permanent income growth factor
766 # (The portion of PermGroFac attributable to aggregate productivity growth)
767 "NewbornTransShk": False, # Whether Newborns have transitory shock
768 # ADDITIONAL OPTIONAL PARAMETERS
769 "PerfMITShk": False, # Do Perfect Foresight MIT Shock
770 # (Forces Newborns to follow solution path of the agent they replaced if True)
771 "neutral_measure": False, # Whether to use permanent income neutral measure (see Harmenberg 2021)
772}
774PrefShockConsumerType_default = {}
775PrefShockConsumerType_default.update(PrefShockConsumerType_IncShkDstn_default)
776PrefShockConsumerType_default.update(PrefShockConsumerType_aXtraGrid_default)
777PrefShockConsumerType_default.update(PrefShockConsumerType_PrefShkDstn_default)
778PrefShockConsumerType_default.update(PrefShockConsumerType_kNrmInitDstn_default)
779PrefShockConsumerType_default.update(PrefShockConsumerType_pLvlInitDstn_default)
780PrefShockConsumerType_default.update(PrefShockConsumerType_solving_default)
781PrefShockConsumerType_default.update(PrefShockConsumerType_simulation_default)
782init_preference_shocks = (
783 PrefShockConsumerType_default # So models that aren't updated don't break
784)
787class PrefShockConsumerType(IndShockConsumerType):
788 r"""
789 A consumer type based on IndShockConsumerType, with multiplicative shocks to utility each period.
791 .. math::
792 \newcommand{\CRRA}{\rho}
793 \newcommand{\DiePrb}{\mathsf{D}}
794 \newcommand{\PermGroFac}{\Gamma}
795 \newcommand{\Rfree}{\mathsf{R}}
796 \newcommand{\DiscFac}{\beta}
797 \begin{align*}
798 v_t(m_t,\eta_t) &=\max_{c_t} \eta_{t} u(c_t) + \DiscFac (1 - \DiePrb_{t+1}) \mathbb{E}_{t} \left[ (\PermGroFac_{t+1} \psi_{t+1})^{1-\CRRA} v_{t+1}(m_{t+1},\eta_{t+1}) \right], \\
799 & \text{s.t.} \\
800 a_t &= m_t - c_t, \\
801 a_t &\geq \underline{a}, \\
802 m_{t+1} &= a_t \Rfree_{t+1}/(\PermGroFac_{t+1} \psi_{t+1}) + \theta_{t+1}, \\
803 (\psi_{t+1},\theta_{t+1},\eta_{t+1}) &\sim F_{t+1}, \\
804 \mathbb{E}[\psi]=\mathbb{E}[\theta] &= 1, \\
805 u(c) &= \frac{c^{1-\CRRA}}{1-\CRRA} \\
806 \end{align*}
809 Constructors
810 ------------
811 IncShkDstn: Constructor, :math:`\psi`, :math:`\theta`
812 The agent's income shock distributions.
814 It's default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.construct_lognormal_income_process_unemployment`
815 aXtraGrid: Constructor
816 The agent's asset grid.
818 It's default constructor is :func:`HARK.utilities.make_assets_grid`
819 PrefShkDstn: Constructor, :math:`\eta`
820 The agent's preference shock distributions.
822 It's default constuctor is :func:`HARK.ConsumptionSaving.ConsPrefShockModel.make_lognormal_PrefShkDstn`
824 Solving Parameters
825 ------------------
826 cycles: int
827 0 specifies an infinite horizon model, 1 specifies a finite model.
828 T_cycle: int
829 Number of periods in the cycle for this agent type.
830 CRRA: float, :math:`\rho`
831 Coefficient of Relative Risk Aversion.
832 Rfree: float or list[float], time varying, :math:`\mathsf{R}`
833 Risk Free interest rate. Pass a list of floats to make Rfree time varying.
834 DiscFac: float, :math:`\beta`
835 Intertemporal discount factor.
836 LivPrb: list[float], time varying, :math:`1-\mathsf{D}`
837 Survival probability after each period.
838 PermGroFac: list[float], time varying, :math:`\Gamma`
839 Permanent income growth factor.
840 BoroCnstArt: float, :math:`\underline{a}`
841 The minimum Asset/Perminant Income ratio, None to ignore.
842 vFuncBool: bool
843 Whether to calculate the value function during solution.
844 CubicBool: bool
845 Whether to use cubic spline interpoliation.
847 Simulation Parameters
848 ---------------------
849 AgentCount: int
850 Number of agents of this kind that are created during simulations.
851 T_age: int
852 Age after which to automatically kill agents, None to ignore.
853 T_sim: int, required for simulation
854 Number of periods to simulate.
855 track_vars: list[strings]
856 List of variables that should be tracked when running the simulation.
857 For this agent, the options are 'PermShk', 'PrefShk', 'TranShk', 'aLvl', 'aNrm', 'bNrm', 'cNrm', 'mNrm', 'pLvl', and 'who_dies'.
859 PermShk is the agent's permanent income shock
861 PrefShk is the agent's preference shock
863 TranShk is the agent's transitory income shock
865 aLvl is the nominal asset level
867 aNrm is the normalized assets
869 bNrm is the normalized resources without this period's labor income
871 cNrm is the normalized consumption
873 mNrm is the normalized market resources
875 pLvl is the permanent income level
877 who_dies is the array of which agents died
878 aNrmInitMean: float
879 Mean of Log initial Normalized Assets.
880 aNrmInitStd: float
881 Std of Log initial Normalized Assets.
882 pLvlInitMean: float
883 Mean of Log initial permanent income.
884 pLvlInitStd: float
885 Std of Log initial permanent income.
886 PermGroFacAgg: float
887 Aggregate permanent income growth factor (The portion of PermGroFac attributable to aggregate productivity growth).
888 PerfMITShk: boolean
889 Do Perfect Foresight MIT Shock (Forces Newborns to follow solution path of the agent they replaced if True).
890 NewbornTransShk: boolean
891 Whether Newborns have transitory shock.
893 Attributes
894 ----------
895 solution: list[Consumer solution object]
896 Created by the :func:`.solve` method. Finite horizon models create a list with T_cycle+1 elements, for each period in the solution.
897 Infinite horizon solutions return a list with T_cycle elements for each period in the cycle.
899 For this model, cFunc is defined over normalized market resources and :math:`\eta`, cNrm = cFunc(mNrm, :math:`\eta`).
901 Visit :class:`HARK.ConsumptionSaving.ConsIndShockModel.ConsumerSolution` for more information about the solution.
902 history: Dict[Array]
903 Created by running the :func:`.simulate()` method.
904 Contains the variables in track_vars. Each item in the dictionary is an array with the shape (T_sim,AgentCount).
905 Visit :class:`HARK.core.AgentType.simulate` for more information.
906 """
908 IncShkDstn_defaults = PrefShockConsumerType_IncShkDstn_default
909 aXtraGrid_defaults = PrefShockConsumerType_aXtraGrid_default
910 PrefShkDstn_defaults = PrefShockConsumerType_PrefShkDstn_default
911 solving_defaults = PrefShockConsumerType_solving_default
912 simulation_defaults = PrefShockConsumerType_simulation_default
913 default_ = {
914 "params": PrefShockConsumerType_default,
915 "solver": solve_one_period_ConsPrefShock,
916 "model": "ConsMarkov.yaml",
917 }
919 shock_vars_ = IndShockConsumerType.shock_vars_ + ["PrefShk"]
920 time_vary_ = IndShockConsumerType.time_vary_ + ["PrefShkDstn"]
921 distributions = [
922 "IncShkDstn",
923 "PermShkDstn",
924 "TranShkDstn",
925 "kNrmInitDstn",
926 "pLvlInitDstn",
927 "PrefShkDstn",
928 ]
930 def pre_solve(self):
931 self.construct("solution_terminal")
933 def reset_rng(self):
934 """
935 Reset the RNG behavior of this type. This method is called automatically
936 by initialize_sim(), ensuring that each simulation run uses the same sequence
937 of random shocks; this is necessary for structural estimation to work.
938 This method extends IndShockConsumerType.reset_rng() to also reset elements
939 of PrefShkDstn.
941 Parameters
942 ----------
943 None
945 Returns
946 -------
947 None
948 """
949 IndShockConsumerType.reset_rng(self)
951 # Reset PrefShkDstn if it exists (it might not because reset_rng is called at init)
952 if hasattr(self, "PrefShkDstn"):
953 for dstn in self.PrefShkDstn:
954 dstn.reset()
956 def get_shocks(self):
957 """
958 Gets permanent and transitory income shocks for this period as well as preference shocks.
960 Parameters
961 ----------
962 None
964 Returns
965 -------
966 None
967 """
968 IndShockConsumerType.get_shocks(
969 self
970 ) # Get permanent and transitory income shocks
971 PrefShkNow = np.zeros(self.AgentCount) # Initialize shock array
972 for t in range(self.T_cycle):
973 these = t == self.t_cycle
974 N = np.sum(these)
975 if N > 0:
976 PrefShkNow[these] = self.PrefShkDstn[t].draw(N)
977 self.shocks["PrefShk"] = PrefShkNow
979 def get_controls(self):
980 """
981 Calculates consumption for each consumer of this type using the consumption functions.
983 Parameters
984 ----------
985 None
987 Returns
988 -------
989 None
990 """
991 cNrmNow = np.zeros(self.AgentCount) + np.nan
992 for t in range(self.T_cycle):
993 these = t == self.t_cycle
994 cNrmNow[these] = self.solution[t].cFunc(
995 self.state_now["mNrm"][these], self.shocks["PrefShk"][these]
996 )
997 self.controls["cNrm"] = cNrmNow
998 return None
1000 def calc_bounding_values(self):
1001 """
1002 Calculate human wealth plus minimum and maximum MPC in an infinite
1003 horizon model with only one period repeated indefinitely. Store results
1004 as attributes of self. Human wealth is the present discounted value of
1005 expected future income after receiving income this period, ignoring mort-
1006 ality. The maximum MPC is the limit of the MPC as m --> mNrmMin. The
1007 minimum MPC is the limit of the MPC as m --> infty.
1009 NOT YET IMPLEMENTED FOR THIS CLASS
1011 Parameters
1012 ----------
1013 None
1015 Returns
1016 -------
1017 None
1018 """
1019 raise NotImplementedError()
1021 def make_euler_error_func(self, mMax=100, approx_inc_dstn=True):
1022 """
1023 Creates a "normalized Euler error" function for this instance, mapping
1024 from market resources to "consumption error per dollar of consumption."
1025 Stores result in attribute eulerErrorFunc as an interpolated function.
1026 Has option to use approximate income distribution stored in self.IncShkDstn
1027 or to use a (temporary) very dense approximation.
1029 NOT YET IMPLEMENTED FOR THIS CLASS
1031 Parameters
1032 ----------
1033 mMax : float
1034 Maximum normalized market resources for the Euler error function.
1035 approx_inc_dstn : Boolean
1036 Indicator for whether to use the approximate discrete income distri-
1037 bution stored in self.IncShkDstn[0], or to use a very accurate
1038 discrete approximation instead. When True, uses approximation in
1039 IncShkDstn; when False, makes and uses a very dense approximation.
1041 Returns
1042 -------
1043 None
1045 Notes
1046 -----
1047 This method is not used by any other code in the library. Rather, it is here
1048 for expository and benchmarking purposes.
1049 """
1050 raise NotImplementedError()
1053###############################################################################
1055# Specify default parameters that differ in "kinky preference" model compared to base PrefShockConsumerType
1056kinky_pref_different_params = {
1057 "Rboro": 1.20, # Interest factor on assets when borrowing, a < 0
1058 "Rsave": 1.02, # Interest factor on assets when saving, a > 0
1059 "BoroCnstArt": None, # Kinked R only matters if borrowing is allowed
1060}
1061KinkyPrefConsumerType_constructors_default = (
1062 PrefShockConsumerType_constructors_default.copy()
1063)
1064KinkyPrefConsumerType_IncShkDstn_default = (
1065 PrefShockConsumerType_IncShkDstn_default.copy()
1066)
1067KinkyPrefConsumerType_pLvlInitDstn_default = (
1068 PrefShockConsumerType_pLvlInitDstn_default.copy()
1069)
1070KinkyPrefConsumerType_kNrmInitDstn_default = (
1071 PrefShockConsumerType_kNrmInitDstn_default.copy()
1072)
1073KinkyPrefConsumerType_aXtraGrid_default = PrefShockConsumerType_aXtraGrid_default.copy()
1074KinkyPrefConsumerType_PrefShkDstn_default = (
1075 PrefShockConsumerType_PrefShkDstn_default.copy()
1076)
1077KinkyPrefConsumerType_solving_default = PrefShockConsumerType_solving_default.copy()
1078KinkyPrefConsumerType_solving_default["constructors"] = (
1079 KinkyPrefConsumerType_constructors_default
1080)
1081KinkyPrefConsumerType_simulation_default = (
1082 PrefShockConsumerType_simulation_default.copy()
1083)
1084KinkyPrefConsumerType_solving_default.update(kinky_pref_different_params)
1086# Make a dictionary to specify a "kinky preference" consumer
1087KinkyPrefConsumerType_default = {}
1088KinkyPrefConsumerType_default.update(KinkyPrefConsumerType_IncShkDstn_default)
1089KinkyPrefConsumerType_default.update(KinkyPrefConsumerType_aXtraGrid_default)
1090KinkyPrefConsumerType_default.update(KinkyPrefConsumerType_PrefShkDstn_default)
1091KinkyPrefConsumerType_default.update(KinkyPrefConsumerType_kNrmInitDstn_default)
1092KinkyPrefConsumerType_default.update(KinkyPrefConsumerType_pLvlInitDstn_default)
1093KinkyPrefConsumerType_default.update(KinkyPrefConsumerType_solving_default)
1094KinkyPrefConsumerType_default.update(KinkyPrefConsumerType_simulation_default)
1095init_kinky_pref = KinkyPrefConsumerType_default
1098class KinkyPrefConsumerType(PrefShockConsumerType, KinkedRconsumerType):
1099 r"""
1100 A consumer type based on PrefShockConsumerType, with different
1101 interest rates for saving (:math:`\mathsf{R}_{save}`) and borrowing
1102 (:math:`\mathsf{R}_{boro}`).
1104 Solver for this class is currently only compatible with linear spline interpolation.
1106 .. math::
1107 \newcommand{\CRRA}{\rho}
1108 \newcommand{\DiePrb}{\mathsf{D}}
1109 \newcommand{\PermGroFac}{\Gamma}
1110 \newcommand{\Rfree}{\mathsf{R}}
1111 \newcommand{\DiscFac}{\beta}
1112 \begin{align*}
1113 v_t(m_t,\eta_t) &= \max_{c_t} \eta_{t} u(c_t) + \DiscFac (1-\DiePrb_{t+1}) \mathbb{E}_{t} \left[(\PermGroFac_{t+1}\psi_{t+1})^{1-\CRRA} v_{t+1}(m_{t+1},\eta_{t+1}) \right], \\
1114 a_t &= m_t - c_t, \\
1115 a_t &\geq \underline{a}, \\
1116 m_{t+1} &= \Rfree_t/(\PermGroFac_{t+1} \psi_{t+1}) a_t + \theta_{t+1}, \\
1117 \Rfree_t &= \begin{cases}
1118 \Rfree_{boro} & \text{if } a_t < 0\\
1119 \Rfree_{save} & \text{if } a_t \geq 0,
1120 \end{cases}\\
1121 \Rfree_{boro} &> \Rfree_{save}, \\
1122 (\psi_{t+1},\theta_{t+1},\eta_{t+1}) &\sim F_{t+1}, \\
1123 \mathbb{E}[\psi]=\mathbb{E}[\theta] &= 1. \\
1124 u(c) &= \frac{c^{1-\CRRA}}{1-\CRRA} \\
1125 \end{align*}
1128 Constructors
1129 ------------
1130 IncShkDstn: Constructor, :math:`\psi`, :math:`\theta`
1131 The agent's income shock distributions.
1133 It's default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.construct_lognormal_income_process_unemployment`
1134 aXtraGrid: Constructor
1135 The agent's asset grid.
1137 It's default constructor is :func:`HARK.utilities.make_assets_grid`
1138 PrefShkDstn: Constructor, :math:`\eta`
1139 The agent's preference shock distributions.
1141 It's default constuctor is :func:`HARK.ConsumptionSaving.ConsPrefShockModel.make_lognormal_PrefShkDstn`
1143 Solving Parameters
1144 ------------------
1145 cycles: int
1146 0 specifies an infinite horizon model, 1 specifies a finite model.
1147 T_cycle: int
1148 Number of periods in the cycle for this agent type.
1149 CRRA: float, :math:`\rho`
1150 Coefficient of Relative Risk Aversion.
1151 Rfree: float or list[float], time varying, :math:`\mathsf{R}`
1152 Risk Free interest rate. Pass a list of floats to make Rfree time varying.
1153 Rboro: float, :math:`\mathsf{R}_{boro}`
1154 Risk Free interest rate when assets are negative.
1155 Rsave: float, :math:`\mathsf{R}_{save}`
1156 Risk Free interest rate when assets are positive.
1157 DiscFac: float, :math:`\beta`
1158 Intertemporal discount factor.
1159 LivPrb: list[float], time varying, :math:`1-\mathsf{D}`
1160 Survival probability after each period.
1161 PermGroFac: list[float], time varying, :math:`\Gamma`
1162 Permanent income growth factor.
1163 BoroCnstArt: float, :math:`\underline{a}`
1164 The minimum Asset/Perminant Income ratio, None to ignore.
1165 vFuncBool: bool
1166 Whether to calculate the value function during solution.
1167 CubicBool: bool
1168 Whether to use cubic spline interpoliation.
1170 Simulation Parameters
1171 ---------------------
1172 AgentCount: int
1173 Number of agents of this kind that are created during simulations.
1174 T_age: int
1175 Age after which to automatically kill agents, None to ignore.
1176 T_sim: int, required for simulation
1177 Number of periods to simulate.
1178 track_vars: list[strings]
1179 List of variables that should be tracked when running the simulation.
1180 For this agent, the options are 'PermShk', 'PrefShk', 'TranShk', 'aLvl', 'aNrm', 'bNrm', 'cNrm', 'mNrm', 'pLvl', and 'who_dies'.
1182 PermShk is the agent's permanent income shock
1184 PrefShk is the agent's preference shock
1186 TranShk is the agent's transitory income shock
1188 aLvl is the nominal asset level
1190 aNrm is the normalized assets
1192 bNrm is the normalized resources without this period's labor income
1194 cNrm is the normalized consumption
1196 mNrm is the normalized market resources
1198 pLvl is the permanent income level
1200 who_dies is the array of which agents died
1201 aNrmInitMean: float
1202 Mean of Log initial Normalized Assets.
1203 aNrmInitStd: float
1204 Std of Log initial Normalized Assets.
1205 pLvlInitMean: float
1206 Mean of Log initial permanent income.
1207 pLvlInitStd: float
1208 Std of Log initial permanent income.
1209 PermGroFacAgg: float
1210 Aggregate permanent income growth factor (The portion of PermGroFac attributable to aggregate productivity growth).
1211 PerfMITShk: boolean
1212 Do Perfect Foresight MIT Shock (Forces Newborns to follow solution path of the agent they replaced if True).
1213 NewbornTransShk: boolean
1214 Whether Newborns have transitory shock.
1216 Attributes
1217 ----------
1218 solution: list[Consumer solution object]
1219 Created by the :func:`.solve` method. Finite horizon models create a list with T_cycle+1 elements, for each period in the solution.
1220 Infinite horizon solutions return a list with T_cycle elements for each period in the cycle.
1222 For this model, cFunc is defined over normalized market resources and :math:`\eta`, cNrm = cFunc(mNrm, :math:`\eta`).
1224 Visit :class:`HARK.ConsumptionSaving.ConsIndShockModel.ConsumerSolution` for more information about the solution.
1225 history: Dict[Array]
1226 Created by running the :func:`.simulate()` method.
1227 Contains the variables in track_vars. Each item in the dictionary is an array with the shape (T_sim,AgentCount).
1228 Visit :class:`HARK.core.AgentType.simulate` for more information.
1229 """
1231 IncShkDstn_defaults = KinkyPrefConsumerType_IncShkDstn_default
1232 aXtraGrid_defaults = KinkyPrefConsumerType_aXtraGrid_default
1233 PrefShkDstn_defaults = KinkyPrefConsumerType_PrefShkDstn_default
1234 solving_defaults = KinkyPrefConsumerType_solving_default
1235 simulation_defaults = KinkyPrefConsumerType_simulation_default
1236 default_ = {
1237 "params": KinkyPrefConsumerType_default,
1238 "solver": solve_one_period_ConsKinkyPref,
1239 }
1241 time_inv_ = IndShockConsumerType.time_inv_ + ["Rboro", "Rsave"]
1242 distributions = [
1243 "IncShkDstn",
1244 "PermShkDstn",
1245 "TranShkDstn",
1246 "kNrmInitDstn",
1247 "pLvlInitDstn",
1248 "PrefShkDstn",
1249 ]
1251 def pre_solve(self):
1252 self.construct("solution_terminal")
1254 def get_Rfree(self): # Specify which get_Rfree to use
1255 return KinkedRconsumerType.get_Rfree(self)