Coverage for HARK / ConsumptionSaving / ConsGenIncProcessModel.py: 97%

309 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-07 05:16 +0000

1""" 

2Classes to solve consumption-saving models with idiosyncratic shocks to income 

3in which shocks are not necessarily fully transitory or fully permanent. Extends 

4ConsIndShockModel by explicitly tracking persistent income as a state variable, 

5and allows (log) persistent income to follow an AR1 process rather than random walk. 

6""" 

7 

8import numpy as np 

9 

10from HARK import AgentType, NullFunc 

11from HARK.Calibration.Income.IncomeProcesses import ( 

12 construct_lognormal_income_process_unemployment, 

13 get_PermShkDstn_from_IncShkDstn, 

14 get_TranShkDstn_from_IncShkDstn, 

15 pLvlFuncAR1, 

16 make_trivial_pLvlNextFunc, 

17 make_explicit_perminc_pLvlNextFunc, 

18 make_AR1_style_pLvlNextFunc, 

19 make_pLvlGrid_by_simulation, 

20 make_basic_pLvlPctiles, 

21) 

22from HARK.ConsumptionSaving.ConsIndShockModel import ( 

23 ConsumerSolution, 

24 IndShockConsumerType, 

25 make_lognormal_kNrm_init_dstn, 

26 make_lognormal_pLvl_init_dstn, 

27) 

28from HARK.distributions import expected 

29from HARK.interpolation import ( 

30 BilinearInterp, 

31 ConstantFunction, 

32 CubicInterp, 

33 IdentityFunction, 

34 LinearInterp, 

35 LinearInterpOnInterp1D, 

36 LowerEnvelope2D, 

37 MargMargValueFuncCRRA, 

38 MargValueFuncCRRA, 

39 UpperEnvelope, 

40 ValueFuncCRRA, 

41 VariableLowerBoundFunc2D, 

42) 

43from HARK.rewards import ( 

44 CRRAutility, 

45 CRRAutility_inv, 

46 CRRAutility_invP, 

47 CRRAutilityP, 

48 CRRAutilityP_inv, 

49 CRRAutilityP_invP, 

50 CRRAutilityPP, 

51 UtilityFuncCRRA, 

52) 

53from HARK.utilities import make_assets_grid 

54 

55__all__ = [ 

56 "pLvlFuncAR1", 

57 "GenIncProcessConsumerType", 

58 "IndShockExplicitPermIncConsumerType", 

59 "PersistentShockConsumerType", 

60 "init_explicit_perm_inc", 

61 "init_persistent_shocks", 

62] 

63 

64utility = CRRAutility 

65utilityP = CRRAutilityP 

66utilityPP = CRRAutilityPP 

67utilityP_inv = CRRAutilityP_inv 

68utility_invP = CRRAutility_invP 

69utility_inv = CRRAutility_inv 

70utilityP_invP = CRRAutilityP_invP 

71 

72 

73############################################################################### 

74 

75 

76def make_2D_CRRA_solution_terminal(CRRA): 

77 """ 

78 Construct the terminal period solution for a consumption-saving model with CRRA 

79 utility and two state variables: levels of market resources and permanent income. 

80 

81 Parameters 

82 ---------- 

83 CRRA : float 

84 Coefficient of relative risk aversion. This is the only relevant parameter. 

85 

86 Returns 

87 ------- 

88 solution_terminal : ConsumerSolution 

89 Terminal period solution for someone with the given CRRA. 

90 """ 

91 cFunc_terminal = IdentityFunction(i_dim=0, n_dims=2) 

92 vFunc_terminal = ValueFuncCRRA(cFunc_terminal, CRRA) 

93 vPfunc_terminal = MargValueFuncCRRA(cFunc_terminal, CRRA) 

94 vPPfunc_terminal = MargMargValueFuncCRRA(cFunc_terminal, CRRA) 

95 solution_terminal = ConsumerSolution( 

96 cFunc=cFunc_terminal, 

97 vFunc=vFunc_terminal, 

98 vPfunc=vPfunc_terminal, 

99 vPPfunc=vPPfunc_terminal, 

100 mNrmMin=ConstantFunction(0.0), 

101 hNrm=ConstantFunction(0.0), 

102 MPCmin=1.0, 

103 MPCmax=1.0, 

104 ) 

105 solution_terminal.hLvl = solution_terminal.hNrm 

106 solution_terminal.mLvlMin = solution_terminal.mNrmMin 

107 return solution_terminal 

108 

109 

110def solve_one_period_ConsGenIncProcess( 

111 solution_next, 

112 IncShkDstn, 

113 LivPrb, 

114 DiscFac, 

115 CRRA, 

116 Rfree, 

117 pLvlNextFunc, 

118 BoroCnstArt, 

119 aXtraGrid, 

120 pLvlGrid, 

121 vFuncBool, 

122 CubicBool, 

123): 

124 """ 

125 Solves one one period problem of a consumer who experiences persistent and 

126 transitory shocks to his income. Unlike in ConsIndShock, consumers do not 

127 necessarily have the same predicted level of p next period as this period 

128 (after controlling for growth). Instead, they have a function that translates 

129 current persistent income into expected next period persistent income (subject 

130 to shocks). 

131 

132 Parameters 

133 ---------- 

134 solution_next : ConsumerSolution 

135 The solution to next period's one period problem. 

136 IncShkDstn : distribution.Distribution 

137 A discrete 

138 approximation to the income process between the period being solved 

139 and the one immediately following (in solution_next). Order: event 

140 probabilities, persistent shocks, transitory shocks. 

141 LivPrb : float 

142 Survival probability; likelihood of being alive at the beginning of 

143 the succeeding period. 

144 DiscFac : float 

145 Intertemporal discount factor for future utility. 

146 CRRA : float 

147 Coefficient of relative risk aversion. 

148 Rfree : float 

149 Risk free interest factor on end-of-period assets. 

150 pLvlNextFunc : float 

151 Expected persistent income next period as a function of current pLvl. 

152 BoroCnstArt: float or None 

153 Borrowing constraint for the minimum allowable assets to end the 

154 period with. 

155 aXtraGrid: np.array 

156 Array of "extra" end-of-period (normalized) asset values-- assets 

157 above the absolute minimum acceptable level. 

158 pLvlGrid: np.array 

159 Array of persistent income levels at which to solve the problem. 

160 vFuncBool: boolean 

161 An indicator for whether the value function should be computed and 

162 included in the reported solution. 

163 CubicBool: boolean 

164 An indicator for whether the solver should use cubic or linear interpolation. 

165 

166 Returns 

167 ------- 

168 solution_now : ConsumerSolution 

169 Solution to this period's consumption-saving problem. 

170 """ 

171 # Define the utility function for this period 

172 uFunc = UtilityFuncCRRA(CRRA) 

173 DiscFacEff = DiscFac * LivPrb # "effective" discount factor 

174 

175 # Unpack next period's income shock distribution 

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 

182 # Calculate the probability that we get the worst possible income draw 

183 IncNext = PermShkValsNext * TranShkValsNext 

184 WorstIncNext = PermShkMinNext * TranShkMinNext 

185 WorstIncPrb = np.sum(ShkPrbsNext[IncNext == WorstIncNext]) 

186 # WorstIncPrb is the "Weierstrass p" concept: the odds we get the WORST thing 

187 

188 # Unpack next period's (marginal) value function 

189 vFuncNext = solution_next.vFunc # This is None when vFuncBool is False 

190 vPfuncNext = solution_next.vPfunc 

191 vPPfuncNext = solution_next.vPPfunc # This is None when CubicBool is False 

192 

193 # Update the bounding MPCs and PDV of human wealth: 

194 PatFac = ((Rfree * DiscFacEff) ** (1.0 / CRRA)) / Rfree 

195 try: 

196 MPCminNow = 1.0 / (1.0 + PatFac / solution_next.MPCmin) 

197 except: 

198 MPCminNow = 0.0 

199 mLvlMinNext = solution_next.mLvlMin 

200 

201 # TODO: Deal with this unused code for the upper bound of MPC (should be a function now) 

202 # Ex_IncNext = np.dot(ShkPrbsNext, TranShkValsNext * PermShkValsNext) 

203 # hNrmNow = 0.0 

204 # temp_fac = (WorstIncPrb ** (1.0 / CRRA)) * PatFac 

205 # MPCmaxNow = 1.0 / (1.0 + temp_fac / solution_next.MPCmax) 

206 

207 # Define some functions for calculating future expectations 

208 def calc_pLvl_next(S, p): 

209 return pLvlNextFunc(p) * S["PermShk"] 

210 

211 def calc_mLvl_next(S, a, p_next): 

212 return Rfree * a + p_next * S["TranShk"] 

213 

214 def calc_hLvl(S, p): 

215 pLvl_next = calc_pLvl_next(S, p) 

216 hLvl = S["TranShk"] * pLvl_next + solution_next.hLvl(pLvl_next) 

217 return hLvl 

218 

219 def calc_v_next(S, a, p): 

220 pLvl_next = calc_pLvl_next(S, p) 

221 mLvl_next = calc_mLvl_next(S, a, pLvl_next) 

222 v_next = vFuncNext(mLvl_next, pLvl_next) 

223 return v_next 

224 

225 def calc_vP_next(S, a, p): 

226 pLvl_next = calc_pLvl_next(S, p) 

227 mLvl_next = calc_mLvl_next(S, a, pLvl_next) 

228 vP_next = vPfuncNext(mLvl_next, pLvl_next) 

229 return vP_next 

230 

231 def calc_vPP_next(S, a, p): 

232 pLvl_next = calc_pLvl_next(S, p) 

233 mLvl_next = calc_mLvl_next(S, a, pLvl_next) 

234 vPP_next = vPPfuncNext(mLvl_next, pLvl_next) 

235 return vPP_next 

236 

237 # Construct human wealth level as a function of productivity pLvl 

238 hLvlGrid = 1.0 / Rfree * expected(calc_hLvl, IncShkDstn, args=(pLvlGrid)) 

239 hLvlNow = LinearInterp(np.insert(pLvlGrid, 0, 0.0), np.insert(hLvlGrid, 0, 0.0)) 

240 

241 # Make temporary grids of income shocks and next period income values 

242 ShkCount = TranShkValsNext.size 

243 pLvlCount = pLvlGrid.size 

244 PermShkVals_temp = np.tile( 

245 np.reshape(PermShkValsNext, (1, ShkCount)), (pLvlCount, 1) 

246 ) 

247 TranShkVals_temp = np.tile( 

248 np.reshape(TranShkValsNext, (1, ShkCount)), (pLvlCount, 1) 

249 ) 

250 pLvlNext_temp = ( 

251 np.tile( 

252 np.reshape(pLvlNextFunc(pLvlGrid), (pLvlCount, 1)), 

253 (1, ShkCount), 

254 ) 

255 * PermShkVals_temp 

256 ) 

257 

258 # Find the natural borrowing constraint for each persistent income level 

259 aLvlMin_candidates = ( 

260 mLvlMinNext(pLvlNext_temp) - TranShkVals_temp * pLvlNext_temp 

261 ) / Rfree 

262 aLvlMinNow = np.max(aLvlMin_candidates, axis=1) 

263 BoroCnstNat = LinearInterp( 

264 np.insert(pLvlGrid, 0, 0.0), np.insert(aLvlMinNow, 0, 0.0) 

265 ) 

266 

267 # Define the minimum allowable mLvl by pLvl as the greater of the natural and artificial borrowing constraints 

268 if BoroCnstArt is not None: 

269 BoroCnstArt = LinearInterp(np.array([0.0, 1.0]), np.array([0.0, BoroCnstArt])) 

270 mLvlMinNow = UpperEnvelope(BoroCnstArt, BoroCnstNat) 

271 else: 

272 mLvlMinNow = BoroCnstNat 

273 

274 # Define the constrained consumption function as "consume all" shifted by mLvlMin 

275 cFuncNowCnstBase = BilinearInterp( 

276 np.array([[0.0, 0.0], [1.0, 1.0]]), 

277 np.array([0.0, 1.0]), 

278 np.array([0.0, 1.0]), 

279 ) 

280 cFuncNowCnst = VariableLowerBoundFunc2D(cFuncNowCnstBase, mLvlMinNow) 

281 

282 # Define grids of pLvl and aLvl on which to compute future expectations 

283 pLvlCount = pLvlGrid.size 

284 aNrmCount = aXtraGrid.size 

285 pLvlNow = np.tile(pLvlGrid, (aNrmCount, 1)).transpose() 

286 aLvlNow = np.tile(aXtraGrid, (pLvlCount, 1)) * pLvlNow + BoroCnstNat(pLvlNow) 

287 # shape = (pLvlCount,aNrmCount) 

288 if pLvlGrid[0] == 0.0: # aLvl turns out badly if pLvl is 0 at bottom 

289 aLvlNow[0, :] = aXtraGrid 

290 

291 # Calculate end-of-period marginal value of assets 

292 EndOfPrd_vP = ( 

293 DiscFacEff * Rfree * expected(calc_vP_next, IncShkDstn, args=(aLvlNow, pLvlNow)) 

294 ) 

295 

296 # If the value function has been requested, construct the end-of-period vFunc 

297 if vFuncBool: 

298 # Compute expected value from end-of-period states 

299 EndOfPrd_v = expected(calc_v_next, IncShkDstn, args=(aLvlNow, pLvlNow)) 

300 EndOfPrd_v *= DiscFacEff 

301 

302 # Transformed value through inverse utility function to "decurve" it 

303 EndOfPrd_vNvrs = uFunc.inv(EndOfPrd_v) 

304 EndOfPrd_vNvrsP = EndOfPrd_vP * uFunc.derinv(EndOfPrd_v, order=(0, 1)) 

305 

306 # Add points at mLvl=zero 

307 EndOfPrd_vNvrs = np.concatenate( 

308 (np.zeros((pLvlCount, 1)), EndOfPrd_vNvrs), axis=1 

309 ) 

310 EndOfPrd_vNvrsP = np.concatenate( 

311 ( 

312 np.reshape(EndOfPrd_vNvrsP[:, 0], (pLvlCount, 1)), 

313 EndOfPrd_vNvrsP, 

314 ), 

315 axis=1, 

316 ) 

317 # This is a very good approximation, vNvrsPP = 0 at the asset minimum 

318 

319 # Make a temporary aLvl grid for interpolating the end-of-period value function 

320 aLvl_temp = np.concatenate( 

321 ( 

322 np.reshape(BoroCnstNat(pLvlGrid), (pLvlGrid.size, 1)), 

323 aLvlNow, 

324 ), 

325 axis=1, 

326 ) 

327 

328 # Make an end-of-period value function for each persistent income level in the grid 

329 EndOfPrd_vNvrsFunc_list = [] 

330 for p in range(pLvlCount): 

331 EndOfPrd_vNvrsFunc_list.append( 

332 CubicInterp( 

333 aLvl_temp[p, :] - BoroCnstNat(pLvlGrid[p]), 

334 EndOfPrd_vNvrs[p, :], 

335 EndOfPrd_vNvrsP[p, :], 

336 ) 

337 ) 

338 EndOfPrd_vNvrsFuncBase = LinearInterpOnInterp1D( 

339 EndOfPrd_vNvrsFunc_list, pLvlGrid 

340 ) 

341 

342 # Re-adjust the combined end-of-period value function to account for the 

343 # natural borrowing constraint shifter and "re-curve" it 

344 EndOfPrd_vNvrsFunc = VariableLowerBoundFunc2D( 

345 EndOfPrd_vNvrsFuncBase, BoroCnstNat 

346 ) 

347 EndOfPrd_vFunc = ValueFuncCRRA(EndOfPrd_vNvrsFunc, CRRA) 

348 

349 # Solve the first order condition to get optimal consumption, then find the 

350 # endogenous gridpoints 

351 cLvlNow = uFunc.derinv(EndOfPrd_vP, order=(1, 0)) 

352 mLvlNow = cLvlNow + aLvlNow 

353 

354 # Limiting consumption is zero as m approaches mNrmMin 

355 c_for_interpolation = np.concatenate((np.zeros((pLvlCount, 1)), cLvlNow), axis=-1) 

356 m_for_interpolation = np.concatenate( 

357 ( 

358 BoroCnstNat(np.reshape(pLvlGrid, (pLvlCount, 1))), 

359 mLvlNow, 

360 ), 

361 axis=-1, 

362 ) 

363 

364 # Limiting consumption is MPCmin*mLvl as p approaches 0 

365 m_temp = np.reshape(m_for_interpolation[0, :], (1, m_for_interpolation.shape[1])) 

366 m_for_interpolation = np.concatenate((m_temp, m_for_interpolation), axis=0) 

367 c_for_interpolation = np.concatenate( 

368 (MPCminNow * m_temp, c_for_interpolation), axis=0 

369 ) 

370 

371 # Make an array of corresponding pLvl values, adding an additional column for 

372 # the mLvl points at the lower boundary *and* an extra row for pLvl=0. 

373 p_for_interpolation = np.concatenate( 

374 (np.reshape(pLvlGrid, (pLvlCount, 1)), pLvlNow), axis=-1 

375 ) 

376 p_for_interpolation = np.concatenate( 

377 (np.zeros((1, m_for_interpolation.shape[1])), p_for_interpolation) 

378 ) 

379 

380 # Build the set of cFuncs by pLvl, gathered in a list 

381 cFunc_by_pLvl_list = [] # list of consumption functions for each pLvl 

382 if CubicBool: 

383 # Calculate end-of-period marginal marginal value of assets 

384 vPP_fac = DiscFacEff * Rfree * Rfree 

385 EndOfPrd_vPP = expected(calc_vPP_next, IncShkDstn, args=(aLvlNow, pLvlNow)) 

386 EndOfPrd_vPP *= vPP_fac 

387 

388 # Calculate the MPC at each gridpoint 

389 dcda = EndOfPrd_vPP / uFunc.der(np.array(c_for_interpolation[1:, 1:]), order=2) 

390 MPC = dcda / (dcda + 1.0) 

391 MPC = np.concatenate((np.reshape(MPC[:, 0], (MPC.shape[0], 1)), MPC), axis=1) 

392 

393 # Stick an extra row of MPC values at pLvl=zero 

394 MPC = np.concatenate((MPCminNow * np.ones((1, aNrmCount + 1)), MPC), axis=0) 

395 

396 # Make cubic consumption function with respect to mLvl for each persistent income level 

397 for j in range(p_for_interpolation.shape[0]): 

398 pLvl_j = p_for_interpolation[j, 0] 

399 m_temp = m_for_interpolation[j, :] - BoroCnstNat(pLvl_j) 

400 

401 # Make a cubic consumption function for this pLvl 

402 c_temp = c_for_interpolation[j, :] 

403 MPC_temp = MPC[j, :] 

404 if pLvl_j > 0: 

405 cFunc_by_pLvl_list.append( 

406 CubicInterp( 

407 m_temp, 

408 c_temp, 

409 MPC_temp, 

410 lower_extrap=True, 

411 slope_limit=MPCminNow, 

412 intercept_limit=MPCminNow * hLvlNow(pLvl_j), 

413 ) 

414 ) 

415 else: # When pLvl=0, cFunc is linear 

416 cFunc_by_pLvl_list.append( 

417 LinearInterp(m_temp, c_temp, lower_extrap=True) 

418 ) 

419 

420 # Basic version: use linear interpolation within a pLvl 

421 else: 

422 # Loop over pLvl values and make an mLvl for each one 

423 for j in range(p_for_interpolation.shape[0]): 

424 pLvl_j = p_for_interpolation[j, 0] 

425 m_temp = m_for_interpolation[j, :] - BoroCnstNat(pLvl_j) 

426 

427 # Make a linear consumption function for this pLvl 

428 c_temp = c_for_interpolation[j, :] 

429 if pLvl_j > 0: 

430 cFunc_by_pLvl_list.append( 

431 LinearInterp( 

432 m_temp, 

433 c_temp, 

434 lower_extrap=True, 

435 slope_limit=MPCminNow, 

436 intercept_limit=MPCminNow * hLvlNow(pLvl_j), 

437 ) 

438 ) 

439 else: 

440 cFunc_by_pLvl_list.append( 

441 LinearInterp(m_temp, c_temp, lower_extrap=True) 

442 ) 

443 

444 # Combine all linear cFuncs into one function 

445 pLvl_list = p_for_interpolation[:, 0] 

446 cFuncUncBase = LinearInterpOnInterp1D(cFunc_by_pLvl_list, pLvl_list) 

447 cFuncNowUnc = VariableLowerBoundFunc2D(cFuncUncBase, BoroCnstNat) 

448 # Re-adjust for lower bound of natural borrowing constraint 

449 

450 # Combine the constrained and unconstrained functions into the true consumption function 

451 cFuncNow = LowerEnvelope2D(cFuncNowUnc, cFuncNowCnst) 

452 

453 # Make the marginal value function 

454 vPfuncNow = MargValueFuncCRRA(cFuncNow, CRRA) 

455 

456 # If using cubic spline interpolation, construct the marginal marginal value function 

457 if CubicBool: 

458 vPPfuncNow = MargMargValueFuncCRRA(cFuncNow, CRRA) 

459 else: 

460 vPPfuncNow = NullFunc() 

461 

462 # If the value function has been requested, construct it now 

463 if vFuncBool: 

464 # Compute expected value and marginal value on a grid of market resources 

465 # Tile pLvl across m values 

466 pLvl_temp = np.tile(pLvlGrid, (aNrmCount, 1)) 

467 mLvl_temp = ( 

468 np.tile(mLvlMinNow(pLvlGrid), (aNrmCount, 1)) 

469 + np.tile(np.reshape(aXtraGrid, (aNrmCount, 1)), (1, pLvlCount)) * pLvl_temp 

470 ) 

471 cLvl_temp = cFuncNow(mLvl_temp, pLvl_temp) 

472 aLvl_temp = mLvl_temp - cLvl_temp 

473 v_temp = uFunc(cLvl_temp) + EndOfPrd_vFunc(aLvl_temp, pLvl_temp) 

474 vP_temp = uFunc.der(cLvl_temp) 

475 

476 # Calculate pseudo-inverse value and its first derivative (wrt mLvl) 

477 vNvrs_temp = uFunc.inv(v_temp) # value transformed through inverse utility 

478 vNvrsP_temp = vP_temp * uFunc.derinv(v_temp, order=(0, 1)) 

479 

480 # Add data at the lower bound of m 

481 mLvl_temp = np.concatenate( 

482 (np.reshape(mLvlMinNow(pLvlGrid), (1, pLvlCount)), mLvl_temp), axis=0 

483 ) 

484 vNvrs_temp = np.concatenate((np.zeros((1, pLvlCount)), vNvrs_temp), axis=0) 

485 vNvrsP_temp = np.concatenate( 

486 (np.reshape(vNvrsP_temp[0, :], (1, vNvrsP_temp.shape[1])), vNvrsP_temp), 

487 axis=0, 

488 ) 

489 

490 # Add data at the lower bound of p 

491 MPCminNvrs = MPCminNow ** (-CRRA / (1.0 - CRRA)) 

492 m_temp = np.reshape(mLvl_temp[:, 0], (aNrmCount + 1, 1)) 

493 mLvl_temp = np.concatenate((m_temp, mLvl_temp), axis=1) 

494 vNvrs_temp = np.concatenate((MPCminNvrs * m_temp, vNvrs_temp), axis=1) 

495 vNvrsP_temp = np.concatenate( 

496 (MPCminNvrs * np.ones((aNrmCount + 1, 1)), vNvrsP_temp), axis=1 

497 ) 

498 

499 # Construct the pseudo-inverse value function 

500 vNvrsFunc_list = [] 

501 for j in range(pLvlCount + 1): 

502 pLvl = np.insert(pLvlGrid, 0, 0.0)[j] 

503 vNvrsFunc_list.append( 

504 CubicInterp( 

505 mLvl_temp[:, j] - mLvlMinNow(pLvl), 

506 vNvrs_temp[:, j], 

507 vNvrsP_temp[:, j], 

508 MPCminNvrs * hLvlNow(pLvl), 

509 MPCminNvrs, 

510 ) 

511 ) 

512 vNvrsFuncBase = LinearInterpOnInterp1D( 

513 vNvrsFunc_list, np.insert(pLvlGrid, 0, 0.0) 

514 ) # Value function "shifted" 

515 vNvrsFuncNow = VariableLowerBoundFunc2D(vNvrsFuncBase, mLvlMinNow) 

516 

517 # "Re-curve" the pseudo-inverse value function into the value function 

518 vFuncNow = ValueFuncCRRA(vNvrsFuncNow, CRRA) 

519 

520 else: 

521 vFuncNow = NullFunc() 

522 

523 # Package and return the solution object 

524 solution_now = ConsumerSolution( 

525 cFunc=cFuncNow, 

526 vFunc=vFuncNow, 

527 vPfunc=vPfuncNow, 

528 vPPfunc=vPPfuncNow, 

529 mNrmMin=0.0, # Not a normalized model, mLvlMin will be added below 

530 hNrm=0.0, # Not a normalized model, hLvl will be added below 

531 MPCmin=MPCminNow, 

532 MPCmax=0.0, # This should be a function, need to make it 

533 ) 

534 solution_now.hLvl = hLvlNow 

535 solution_now.mLvlMin = mLvlMinNow 

536 return solution_now 

537 

538 

539############################################################################### 

540 

541# Make a constructor dictionary for the general income process consumer type 

542GenIncProcessConsumerType_constructors_default = { 

543 "IncShkDstn": construct_lognormal_income_process_unemployment, 

544 "PermShkDstn": get_PermShkDstn_from_IncShkDstn, 

545 "TranShkDstn": get_TranShkDstn_from_IncShkDstn, 

546 "aXtraGrid": make_assets_grid, 

547 "pLvlPctiles": make_basic_pLvlPctiles, 

548 "pLvlGrid": make_pLvlGrid_by_simulation, 

549 "pLvlNextFunc": make_trivial_pLvlNextFunc, 

550 "solution_terminal": make_2D_CRRA_solution_terminal, 

551 "kNrmInitDstn": make_lognormal_kNrm_init_dstn, 

552 "pLvlInitDstn": make_lognormal_pLvl_init_dstn, 

553} 

554 

555# Make a dictionary with parameters for the default constructor for kNrmInitDstn 

556GenIncProcessConsumerType_kNrmInitDstn_default = { 

557 "kLogInitMean": -12.0, # Mean of log initial capital 

558 "kLogInitStd": 0.0, # Stdev of log initial capital 

559 "kNrmInitCount": 15, # Number of points in initial capital discretization 

560} 

561 

562# Make a dictionary with parameters for the default constructor for pLvlInitDstn 

563GenIncProcessConsumerType_pLvlInitDstn_default = { 

564 "pLogInitMean": 0.0, # Mean of log permanent income 

565 "pLogInitStd": 0.4, # Stdev of log permanent income 

566 "pLvlInitCount": 15, # Number of points in initial capital discretization 

567} 

568 

569# Default parameters to make IncShkDstn using construct_lognormal_income_process_unemployment 

570GenIncProcessConsumerType_IncShkDstn_default = { 

571 "PermShkStd": [0.1], # Standard deviation of log permanent income shocks 

572 "PermShkCount": 7, # Number of points in discrete approximation to permanent income shocks 

573 "TranShkStd": [0.1], # Standard deviation of log transitory income shocks 

574 "TranShkCount": 7, # Number of points in discrete approximation to transitory income shocks 

575 "UnempPrb": 0.05, # Probability of unemployment while working 

576 "IncUnemp": 0.3, # Unemployment benefits replacement rate while working 

577 "T_retire": 0, # Period of retirement (0 --> no retirement) 

578 "UnempPrbRet": 0.005, # Probability of "unemployment" while retired 

579 "IncUnempRet": 0.0, # "Unemployment" benefits when retired 

580} 

581 

582# Default parameters to make aXtraGrid using make_assets_grid 

583GenIncProcessConsumerType_aXtraGrid_default = { 

584 "aXtraMin": 0.001, # Minimum end-of-period "assets above minimum" value 

585 "aXtraMax": 30, # Maximum end-of-period "assets above minimum" value 

586 "aXtraNestFac": 3, # Exponential nesting factor for aXtraGrid 

587 "aXtraCount": 48, # Number of points in the grid of "assets above minimum" 

588 "aXtraExtra": [0.005, 0.01], # Additional other values to add in grid (optional) 

589} 

590GenIncProcessConsumerType_pLvlNextFunc_default = {} # Trivial function has no parameters 

591 

592# Default parameters to make pLvlGrid using make_basic_pLvlPctiles 

593GenIncProcessConsumerType_pLvlPctiles_default = { 

594 "pLvlPctiles_count": 19, # Number of points in the "body" of the grid 

595 "pLvlPctiles_bound": [0.05, 0.95], # Percentile bounds of the "body" 

596 "pLvlPctiles_tail_count": 4, # Number of points in each tail of the grid 

597 "pLvlPctiles_tail_order": np.e, # Scaling factor for points in each tail 

598} 

599 

600# Default parameters to make pLvlGrid using make_pLvlGrid_by_simulation 

601GenIncProcessConsumerType_pLvlGrid_default = { 

602 "pLvlExtra": None, # Additional permanent income points to automatically add to the grid, optional 

603} 

604 

605# Make a dictionary to specify a general income process consumer type 

606GenIncProcessConsumerType_solving_default = { 

607 # BASIC HARK PARAMETERS REQUIRED TO SOLVE THE MODEL 

608 "cycles": 1, # Finite, non-cyclic model 

609 "T_cycle": 1, # Number of periods in the cycle for this agent type 

610 "pseudo_terminal": False, # Terminal period really does exist 

611 "constructors": GenIncProcessConsumerType_constructors_default, # See dictionary above 

612 # PRIMITIVE RAW PARAMETERS REQUIRED TO SOLVE THE MODEL 

613 "CRRA": 2.0, # Coefficient of relative risk aversion 

614 "Rfree": [1.03], # Interest factor on retained assets 

615 "DiscFac": 0.96, # Intertemporal discount factor 

616 "LivPrb": [0.98], # Survival probability after each period 

617 "BoroCnstArt": 0.0, # Artificial borrowing constraint 

618 "vFuncBool": False, # Whether to calculate the value function during solution 

619 "CubicBool": False, # Whether to use cubic spline interpolation when True 

620 # (Uses linear spline interpolation for cFunc when False) 

621} 

622GenIncProcessConsumerType_simulation_default = { 

623 # PARAMETERS REQUIRED TO SIMULATE THE MODEL 

624 "AgentCount": 10000, # Number of agents of this type 

625 "T_age": None, # Age after which simulated agents are automatically killed 

626 "PermGroFacAgg": 1.0, # Aggregate permanent income growth factor 

627 # (The portion of PermGroFac attributable to aggregate productivity growth) 

628 "NewbornTransShk": False, # Whether Newborns have transitory shock 

629 # ADDITIONAL OPTIONAL PARAMETERS 

630 "PerfMITShk": False, # Do Perfect Foresight MIT Shock 

631 # (Forces Newborns to follow solution path of the agent they replaced if True) 

632 "neutral_measure": False, # Whether to use permanent income neutral measure (see Harmenberg 2021) 

633} 

634GenIncProcessConsumerType_default = {} 

635GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_kNrmInitDstn_default) 

636GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlInitDstn_default) 

637GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_IncShkDstn_default) 

638GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_aXtraGrid_default) 

639GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlNextFunc_default) 

640GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlGrid_default) 

641GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlPctiles_default) 

642GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_solving_default) 

643GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_simulation_default) 

644init_general_inc = GenIncProcessConsumerType_default 

645 

646 

647class GenIncProcessConsumerType(IndShockConsumerType): 

648 r""" 

649 A consumer type with idiosyncratic shocks to persistent and transitory income. 

650 Their problem is defined by a sequence of income distributions, survival prob- 

651 abilities, and persistent income growth functions, as well as time invariant 

652 values for risk aversion, discount factor, the interest rate, the grid of 

653 end-of-period assets, and an artificial borrowing constraint. 

654 

655 .. math:: 

656 \begin{eqnarray*} 

657 V_t(M_t,P_t) &=& \max_{C_t} U(C_t) + \beta \mathsf{S}_{t} \mathbb{E} [V_{t+1}(M_{t+1}, P_{t+1}) ], \\ 

658 A_t &=& M_t - C_t, \\ 

659 A_t/P_t &\geq& \underline{a}, \\ 

660 M_{t+1} &=& R_{t+1} A_t + \theta_{t+1}, \\ 

661 P_{t+1} &=& G_{t+1}(P_t)\psi_{t+1}, \\ 

662 (\psi_{t+1},\theta_{t+1}) &\sim& F_{t+1}, \\ 

663 \mathbb{E} [\psi_{t+1}] &=& 1, \\ 

664 U(C) &=& \frac{C^{1-\rho}}{1-\rho}. \\ 

665 \end{eqnarray*} 

666 

667 

668 Constructors 

669 ------------ 

670 IncShkDstn: Constructor, :math:`\psi`, :math:`\theta` 

671 The agent's income shock distributions. 

672 

673 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.construct_lognormal_income_process_unemployment` 

674 aXtraGrid: Constructor 

675 The agent's asset grid. 

676 

677 Its default constructor is :func:`HARK.utilities.make_assets_grid` 

678 pLvlNextFunc: Constructor 

679 An arbitrary function used to evolve the GenIncShockConsumerType's permanent income 

680 

681 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_trivial_pLvlNextFunc` 

682 pLvlGrid: Constructor 

683 The agent's pLvl grid 

684 

685 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_pLvlGrid_by_simulation` 

686 pLvlPctiles: Constructor 

687 The agents income level percentile grid 

688 

689 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_basic_pLvlPctiles` 

690 

691 Solving Parameters 

692 ------------------ 

693 cycles: int 

694 0 specifies an infinite horizon model, 1 specifies a finite model. 

695 T_cycle: int 

696 Number of periods in the cycle for this agent type. 

697 CRRA: float, :math:`\rho` 

698 Coefficient of Relative Risk Aversion. 

699 Rfree: float or list[float], time varying, :math:`\mathsf{R}_t` 

700 Risk Free interest rate. Pass a list of floats to make Rfree time varying. 

701 DiscFac: float, :math:`\beta` 

702 Intertemporal discount factor. 

703 LivPrb: list[float], time varying, :math:`\mathsf{S}_t` 

704 Survival probability after each period. 

705 BoroCnstArt: float, :math:`\underline{a}` 

706 The minimum Asset/Perminant Income ratio, None to ignore. 

707 vFuncBool: bool 

708 Whether to calculate the value function during solution. 

709 CubicBool: bool 

710 Whether to use cubic spline interpoliation. 

711 

712 Simulation Parameters 

713 --------------------- 

714 AgentCount: int 

715 Number of agents of this kind that are created during simulations. 

716 T_age: int 

717 Age after which to automatically kill agents, None to ignore. 

718 T_sim: int, required for simulation 

719 Number of periods to simulate. 

720 track_vars: list[strings] 

721 List of variables that should be tracked when running the simulation. 

722 For this agent, the options are 'PermShk', 'TranShk', 'aLvl', 'cLvl', 'mLvl', 'pLvl', and 'who_dies'. 

723 

724 PermShk is the agent's permanent income shock 

725 

726 TranShk is the agent's transitory income shock 

727 

728 aLvl is the nominal asset level 

729 

730 cLvl is the nominal consumption level 

731 

732 mLvl is the nominal market resources 

733 

734 pLvl is the permanent income level 

735 

736 who_dies is the array of which agents died 

737 aNrmInitMean: float 

738 Mean of Log initial Normalized Assets. 

739 aNrmInitStd: float 

740 Std of Log initial Normalized Assets. 

741 pLvlInitMean: float 

742 Mean of Log initial permanent income. 

743 pLvlInitStd: float 

744 Std of Log initial permanent income. 

745 PermGroFacAgg: float 

746 Aggregate permanent income growth factor (The portion of PermGroFac attributable to aggregate productivity growth). 

747 PerfMITShk: boolean 

748 Do Perfect Foresight MIT Shock (Forces Newborns to follow solution path of the agent they replaced if True). 

749 NewbornTransShk: boolean 

750 Whether Newborns have transitory shock. 

751 

752 Attributes 

753 ---------- 

754 solution: list[Consumer solution object] 

755 Created by the :func:`.solve` method. Finite horizon models create a list with T_cycle+1 elements, for each period in the solution. 

756 Infinite horizon solutions return a list with T_cycle elements for each period in the cycle. 

757 

758 Unlike other models with this solution type, this model's variables are NOT normalized. 

759 The solution functions also depend on the permanent income level. For example, :math:`C=\text{cFunc}(M,P)`. 

760 hNrm has been replaced by hLvl which is a function of permanent income. 

761 MPC max has not yet been implemented for this class. It will be a function of permanent income. 

762 

763 Visit :class:`HARK.ConsumptionSaving.ConsIndShockModel.ConsumerSolution` for more information about the solution. 

764 

765 history: Dict[Array] 

766 Created by running the :func:`.simulate()` method. 

767 Contains the variables in track_vars. Each item in the dictionary is an array with the shape (T_sim,AgentCount). 

768 Visit :class:`HARK.core.AgentType.simulate` for more information. 

769 """ 

770 

771 IncShkDstn_default = GenIncProcessConsumerType_IncShkDstn_default 

772 aXtraGrid_default = GenIncProcessConsumerType_aXtraGrid_default 

773 pLvlNextFunc_default = GenIncProcessConsumerType_pLvlNextFunc_default 

774 pLvlGrid_default = GenIncProcessConsumerType_pLvlGrid_default 

775 pLvlPctiles_default = GenIncProcessConsumerType_pLvlPctiles_default 

776 solving_default = GenIncProcessConsumerType_solving_default 

777 simulation_default = GenIncProcessConsumerType_simulation_default 

778 

779 state_vars = ["kLvl", "pLvl", "mLvl", "aLvl", "aNrm"] 

780 time_vary_ = IndShockConsumerType.time_vary_ + ["pLvlNextFunc", "pLvlGrid"] 

781 default_ = { 

782 "params": GenIncProcessConsumerType_default, 

783 "solver": solve_one_period_ConsGenIncProcess, 

784 "model": "ConsGenIncProcess.yaml", 

785 } 

786 

787 def pre_solve(self): 

788 self.construct("solution_terminal") 

789 

790 def install_retirement_func(self): 

791 """ 

792 Installs a special pLvlNextFunc representing retirement in the correct 

793 element of self.pLvlNextFunc. Draws on the attributes T_retire and 

794 pLvlNextFuncRet. If T_retire is zero or pLvlNextFuncRet does not 

795 exist, this method does nothing. 

796 

797 Parameters 

798 ---------- 

799 None 

800 

801 Returns 

802 ------- 

803 None 

804 """ 

805 if (not hasattr(self, "pLvlNextFuncRet")) or self.T_retire == 0: 

806 return 

807 t = self.T_retire 

808 self.pLvlNextFunc[t] = self.pLvlNextFuncRet 

809 

810 def sim_birth(self, which_agents): 

811 """ 

812 Makes new consumers for the given indices. Initialized variables include aNrm and pLvl, as 

813 well as time variables t_age and t_cycle. Normalized assets and persistent income levels 

814 are drawn from lognormal distributions given by aNrmInitMean and aNrmInitStd (etc). 

815 

816 Parameters 

817 ---------- 

818 which_agents : np.array(Bool) 

819 Boolean array of size self.AgentCount indicating which agents should be "born". 

820 

821 Returns 

822 ------- 

823 None 

824 """ 

825 super().sim_birth(which_agents) 

826 self.state_now["aLvl"][which_agents] = ( 

827 self.state_now["aNrm"][which_agents] * self.state_now["pLvl"][which_agents] 

828 ) 

829 

830 def transition(self): 

831 """ 

832 Calculates updated values of normalized market resources 

833 and persistent income level for each 

834 agent. Uses pLvlNow, aLvlNow, PermShkNow, TranShkNow. 

835 

836 Parameters 

837 ---------- 

838 None 

839 

840 Returns 

841 ------- 

842 kLvlNow 

843 pLvlNow 

844 mLvlNow 

845 """ 

846 kLvlNow = self.state_prev["aLvl"] 

847 pLvlNow = np.zeros_like(kLvlNow) 

848 RfreeNow = self.get_Rfree() 

849 

850 # Calculate new states: normalized market resources and persistent income level 

851 for t in range(self.T_cycle): 

852 these = t == self.t_cycle 

853 pLvlNow[these] = ( 

854 self.pLvlNextFunc[t - 1](self.state_prev["pLvl"][these]) 

855 * self.shocks["PermShk"][these] 

856 ) 

857 

858 # state value 

859 bLvlNow = RfreeNow * kLvlNow # Bank balances before labor income 

860 

861 # Market resources after income - state value 

862 mLvlNow = bLvlNow + self.shocks["TranShk"] * pLvlNow 

863 

864 return (kLvlNow, pLvlNow, mLvlNow) 

865 

866 def get_controls(self): 

867 """ 

868 Calculates consumption for each consumer of this type using the consumption functions. 

869 

870 Parameters 

871 ---------- 

872 None 

873 

874 Returns 

875 ------- 

876 None 

877 """ 

878 cLvlNow = np.zeros(self.AgentCount) + np.nan 

879 MPCnow = np.zeros(self.AgentCount) + np.nan 

880 

881 for t in range(self.T_cycle): 

882 these = t == self.t_cycle 

883 cLvlNow[these] = self.solution[t].cFunc( 

884 self.state_now["mLvl"][these], self.state_now["pLvl"][these] 

885 ) 

886 MPCnow[these] = self.solution[t].cFunc.derivativeX( 

887 self.state_now["mLvl"][these], self.state_now["pLvl"][these] 

888 ) 

889 self.controls["cLvl"] = cLvlNow 

890 self.MPCnow = MPCnow 

891 

892 def get_poststates(self): 

893 """ 

894 Calculates end-of-period assets for each consumer of this type. 

895 Identical to version in IndShockConsumerType but uses Lvl rather than Nrm variables. 

896 

897 Parameters 

898 ---------- 

899 None 

900 

901 Returns 

902 ------- 

903 None 

904 """ 

905 self.state_now["aLvl"] = self.state_now["mLvl"] - self.controls["cLvl"] 

906 # moves now to prev 

907 AgentType.get_poststates(self) 

908 

909 def check_conditions(self, verbose=None): 

910 raise NotImplementedError() 

911 

912 def calc_limiting_values(self): 

913 raise NotImplementedError() 

914 

915 

916############################################################################### 

917 

918# Make a dictionary for the "explicit permanent income" consumer type; see parent dictionary above. 

919IndShockExplicitPermIncConsumerType_constructors_default = ( 

920 GenIncProcessConsumerType_constructors_default.copy() 

921) 

922IndShockExplicitPermIncConsumerType_constructors_default["pLvlNextFunc"] = ( 

923 make_explicit_perminc_pLvlNextFunc 

924) 

925IndShockExplicitPermIncConsumerType_IncShkDstn_default = ( 

926 GenIncProcessConsumerType_IncShkDstn_default.copy() 

927) 

928IndShockExplicitPermIncConsumerType_kNrmInitDstn_default = ( 

929 GenIncProcessConsumerType_kNrmInitDstn_default.copy() 

930) 

931IndShockExplicitPermIncConsumerType_pLvlInitDstn_default = ( 

932 GenIncProcessConsumerType_pLvlInitDstn_default.copy() 

933) 

934IndShockExplicitPermIncConsumerType_aXtraGrid_default = ( 

935 GenIncProcessConsumerType_aXtraGrid_default.copy() 

936) 

937IndShockExplicitPermIncConsumerType_pLvlNextFunc_default = ( 

938 GenIncProcessConsumerType_pLvlNextFunc_default.copy() 

939) 

940IndShockExplicitPermIncConsumerType_pLvlGrid_default = ( 

941 GenIncProcessConsumerType_pLvlGrid_default.copy() 

942) 

943IndShockExplicitPermIncConsumerType_pLvlPctiles_default = ( 

944 GenIncProcessConsumerType_pLvlPctiles_default.copy() 

945) 

946IndShockExplicitPermIncConsumerType_solving_default = ( 

947 GenIncProcessConsumerType_solving_default.copy() 

948) 

949IndShockExplicitPermIncConsumerType_solving_default["constructors"] = ( 

950 IndShockExplicitPermIncConsumerType_constructors_default 

951) 

952IndShockExplicitPermIncConsumerType_pLvlNextFunc_default["PermGroFac"] = [1.0] 

953IndShockExplicitPermIncConsumerType_simulation_default = ( 

954 GenIncProcessConsumerType_simulation_default.copy() 

955) 

956 

957IndShockExplicitPermIncConsumerType_default = {} 

958IndShockExplicitPermIncConsumerType_default.update( 

959 IndShockExplicitPermIncConsumerType_IncShkDstn_default 

960) 

961IndShockExplicitPermIncConsumerType_default.update( 

962 IndShockExplicitPermIncConsumerType_kNrmInitDstn_default 

963) 

964IndShockExplicitPermIncConsumerType_default.update( 

965 IndShockExplicitPermIncConsumerType_pLvlInitDstn_default 

966) 

967IndShockExplicitPermIncConsumerType_default.update( 

968 IndShockExplicitPermIncConsumerType_aXtraGrid_default 

969) 

970IndShockExplicitPermIncConsumerType_default.update( 

971 IndShockExplicitPermIncConsumerType_pLvlNextFunc_default 

972) 

973IndShockExplicitPermIncConsumerType_default.update( 

974 IndShockExplicitPermIncConsumerType_pLvlGrid_default 

975) 

976IndShockExplicitPermIncConsumerType_default.update( 

977 IndShockExplicitPermIncConsumerType_pLvlPctiles_default 

978) 

979IndShockExplicitPermIncConsumerType_default.update( 

980 IndShockExplicitPermIncConsumerType_solving_default 

981) 

982IndShockExplicitPermIncConsumerType_default.update( 

983 IndShockExplicitPermIncConsumerType_simulation_default 

984) 

985init_explicit_perm_inc = IndShockExplicitPermIncConsumerType_default 

986 

987# NB: Permanent income growth was not in the default dictionary for GenIncProcessConsumerType 

988# because its pLvlNextFunc constructor was *trivial*: no permanent income dynamics at all! 

989# For the "explicit permanent income" model, this parameter is added back into the dictionary. 

990# However, note that if this model is used in an *infinite horizon* setting, it will work 

991# best if the product of PermGroFac (across all periods) is 1. If it is far from 1, then the 

992# pLvlGrid that is constructed by the default method might not be appropriate. 

993 

994 

995class IndShockExplicitPermIncConsumerType(GenIncProcessConsumerType): 

996 r""" 

997 A consumer type based on GenIncProcessModel, where the general function 

998 describing the path of permanent income multiplies the current permanent 

999 income by the PermGroFac (:math:`\Gamma`). It's behavior is the same as 

1000 :class:`HARK.ConsumptionSaving.ConsIndShockModel.IndShockConsumerType`, except 

1001 that the variables aren't normalized. This makes the result less 

1002 accurate. This Model uses a lognormal random walk income process. 

1003 If you would like to use a different income process, use 

1004 :class:`HARK.ConsumptionSaving.ConsGenIncProcessModel.GenIncProcessConsumerType` 

1005 

1006 .. math:: 

1007 \begin{eqnarray*} 

1008 V_t(M_t,P_t) &=& \max_{C_t} U(C_t) + \beta (1-\mathsf{D}_{t+1}) \mathbb{E} [V_{t+1}(M_{t+1}, P_{t+1}) ], \\ 

1009 A_t &=& M_t - C_t, \\ 

1010 A_t/P_t &\geq& \underline{a}, \\ 

1011 M_{t+1} &=& R A_t + \theta_{t+1}, \\ 

1012 P_{t+1} &=& G_{t+1}(P_t)\psi_{t+1}, \\ 

1013 (\psi_{t+1},\theta_{t+1}) &\sim& F_{t+1}, \\ 

1014 \mathbb{E} [F_{t+1}] &=& 1, \\ 

1015 U(C) &=& \frac{C^{1-\rho}}{1-\rho}. \\ 

1016 G_{t+1} (x) &=&\Gamma_{t+1} x 

1017 \end{eqnarray*} 

1018 

1019 

1020 Constructors 

1021 ------------ 

1022 IncShkDstn: Constructor, :math:`\psi`, :math:`\theta` 

1023 The agent's income shock distributions. 

1024 

1025 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.construct_lognormal_income_process_unemployment` 

1026 aXtraGrid: Constructor 

1027 The agent's asset grid. 

1028 

1029 Its default constructor is :func:`HARK.utilities.make_assets_grid` 

1030 pLvlNextFunc: Constructor, (:math:`\Gamma`) 

1031 An arbitrary function used to evolve the GenIncShockConsumerType's permanent income 

1032 

1033 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_explicit_perminc_pLvlNextFunc` 

1034 pLvlGrid: Constructor 

1035 The agent's pLvl grid 

1036 

1037 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_pLvlGrid_by_simulation` 

1038 pLvlPctiles: Constructor 

1039 The agents income level percentile grid 

1040 

1041 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_basic_pLvlPctiles` 

1042 

1043 Solving Parameters 

1044 ------------------ 

1045 cycles: int 

1046 0 specifies an infinite horizon model, 1 specifies a finite model. 

1047 T_cycle: int 

1048 Number of periods in the cycle for this agent type. 

1049 CRRA: float, :math:`\rho` 

1050 Coefficient of Relative Risk Aversion. 

1051 Rfree: float or list[float], time varying, :math:`\mathsf{R}` 

1052 Risk Free interest rate. Pass a list of floats to make Rfree time varying. 

1053 DiscFac: float, :math:`\beta` 

1054 Intertemporal discount factor. 

1055 LivPrb: list[float], time varying, :math:`1-\mathsf{D}` 

1056 Survival probability after each period. 

1057 PermGroFac: list[float], time varying, :math:`\Gamma` 

1058 Permanent income growth factor. 

1059 BoroCnstArt: float, :math:`\underline{a}` 

1060 The minimum Asset/Perminant Income ratio, None to ignore. 

1061 vFuncBool: bool 

1062 Whether to calculate the value function during solution. 

1063 CubicBool: bool 

1064 Whether to use cubic spline interpoliation. 

1065 

1066 Simulation Parameters 

1067 --------------------- 

1068 AgentCount: int 

1069 Number of agents of this kind that are created during simulations. 

1070 T_age: int 

1071 Age after which to automatically kill agents, None to ignore. 

1072 T_sim: int, required for simulation 

1073 Number of periods to simulate. 

1074 track_vars: list[strings] 

1075 List of variables that should be tracked when running the simulation. 

1076 For this agent, the options are 'PermShk', 'TranShk', 'aLvl', 'cLvl', 'mLvl', 'pLvl', and 'who_dies'. 

1077 

1078 PermShk is the agent's permanent income shock 

1079 

1080 TranShk is the agent's transitory income shock 

1081 

1082 aLvl is the nominal asset level 

1083 

1084 cLvl is the nominal consumption level 

1085 

1086 mLvl is the nominal market resources 

1087 

1088 pLvl is the permanent income level 

1089 

1090 who_dies is the array of which agents died 

1091 aNrmInitMean: float 

1092 Mean of Log initial Normalized Assets. 

1093 aNrmInitStd: float 

1094 Std of Log initial Normalized Assets. 

1095 pLvlInitMean: float 

1096 Mean of Log initial permanent income. 

1097 pLvlInitStd: float 

1098 Std of Log initial permanent income. 

1099 PermGroFacAgg: float 

1100 Aggregate permanent income growth factor (The portion of PermGroFac attributable to aggregate productivity growth). 

1101 PerfMITShk: boolean 

1102 Do Perfect Foresight MIT Shock (Forces Newborns to follow solution path of the agent they replaced if True). 

1103 NewbornTransShk: boolean 

1104 Whether Newborns have transitory shock. 

1105 

1106 Attributes 

1107 ---------- 

1108 solution: list[Consumer solution object] 

1109 Created by the :func:`.solve` method. Finite horizon models create a list with T_cycle+1 elements, for each period in the solution. 

1110 Infinite horizon solutions return a list with T_cycle elements for each period in the cycle. 

1111 

1112 Unlike other models with this solution type, this model's variables are NOT normalized. 

1113 The solution functions also depend on the permanent income level. For example, :math:`C=\text{cFunc}(M,P)`. 

1114 hNrm has been replaced by hLvl which is a function of permanent income. 

1115 MPC max has not yet been implemented for this class. It will be a function of permanent income. 

1116 

1117 Visit :class:`HARK.ConsumptionSaving.ConsIndShockModel.ConsumerSolution` for more information about the solution. 

1118 

1119 history: Dict[Array] 

1120 Created by running the :func:`.simulate()` method. 

1121 Contains the variables in track_vars. Each item in the dictionary is an array with the shape (T_sim,AgentCount). 

1122 Visit :class:`HARK.core.AgentType.simulate` for more information. 

1123 """ 

1124 

1125 IncShkDstn_default = GenIncProcessConsumerType_IncShkDstn_default 

1126 aXtraGrid_default = GenIncProcessConsumerType_aXtraGrid_default 

1127 pLvlNextFunc_default = GenIncProcessConsumerType_pLvlNextFunc_default 

1128 pLvlGrid_default = GenIncProcessConsumerType_pLvlGrid_default 

1129 pLvlPctiles_default = GenIncProcessConsumerType_pLvlPctiles_default 

1130 solving_default = GenIncProcessConsumerType_solving_default 

1131 simulation_default = GenIncProcessConsumerType_simulation_default 

1132 

1133 default_ = { 

1134 "params": init_explicit_perm_inc, 

1135 "solver": solve_one_period_ConsGenIncProcess, 

1136 } 

1137 

1138 

1139############################################################################### 

1140 

1141# Make a dictionary for the "persistent idiosyncratic shocks" consumer type; see parent dictionary above. 

1142 

1143PersistentShockConsumerType_constructors_default = ( 

1144 GenIncProcessConsumerType_constructors_default.copy() 

1145) 

1146PersistentShockConsumerType_constructors_default["pLvlNextFunc"] = ( 

1147 make_AR1_style_pLvlNextFunc 

1148) 

1149PersistentShockConsumerType_kNrmInitDstn_default = ( 

1150 IndShockExplicitPermIncConsumerType_kNrmInitDstn_default.copy() 

1151) 

1152PersistentShockConsumerType_pLvlInitDstn_default = ( 

1153 IndShockExplicitPermIncConsumerType_pLvlInitDstn_default.copy() 

1154) 

1155PersistentShockConsumerType_IncShkDstn_default = ( 

1156 IndShockExplicitPermIncConsumerType_IncShkDstn_default.copy() 

1157) 

1158PersistentShockConsumerType_aXtraGrid_default = ( 

1159 IndShockExplicitPermIncConsumerType_aXtraGrid_default.copy() 

1160) 

1161PersistentShockConsumerType_pLvlNextFunc_default = ( 

1162 IndShockExplicitPermIncConsumerType_pLvlNextFunc_default.copy() 

1163) 

1164PersistentShockConsumerType_pLvlGrid_default = ( 

1165 IndShockExplicitPermIncConsumerType_pLvlGrid_default.copy() 

1166) 

1167PersistentShockConsumerType_pLvlPctiles_default = ( 

1168 IndShockExplicitPermIncConsumerType_pLvlPctiles_default.copy() 

1169) 

1170PersistentShockConsumerType_solving_default = ( 

1171 IndShockExplicitPermIncConsumerType_solving_default.copy() 

1172) 

1173PersistentShockConsumerType_solving_default["constructors"] = ( 

1174 PersistentShockConsumerType_constructors_default 

1175) 

1176PersistentShockConsumerType_pLvlNextFunc_default["PrstIncCorr"] = 0.98 

1177PersistentShockConsumerType_simulation_default = ( 

1178 IndShockExplicitPermIncConsumerType_simulation_default.copy() 

1179) 

1180 

1181PersistentShockConsumerType_default = {} 

1182PersistentShockConsumerType_default.update( 

1183 PersistentShockConsumerType_IncShkDstn_default 

1184) 

1185PersistentShockConsumerType_default.update( 

1186 PersistentShockConsumerType_kNrmInitDstn_default 

1187) 

1188PersistentShockConsumerType_default.update( 

1189 PersistentShockConsumerType_pLvlInitDstn_default 

1190) 

1191PersistentShockConsumerType_default.update( 

1192 PersistentShockConsumerType_aXtraGrid_default 

1193) 

1194PersistentShockConsumerType_default.update( 

1195 PersistentShockConsumerType_pLvlNextFunc_default 

1196) 

1197PersistentShockConsumerType_default.update(PersistentShockConsumerType_pLvlGrid_default) 

1198PersistentShockConsumerType_default.update( 

1199 PersistentShockConsumerType_pLvlPctiles_default 

1200) 

1201PersistentShockConsumerType_default.update(PersistentShockConsumerType_solving_default) 

1202PersistentShockConsumerType_default.update( 

1203 PersistentShockConsumerType_simulation_default 

1204) 

1205init_persistent_shocks = PersistentShockConsumerType_default 

1206 

1207 

1208class PersistentShockConsumerType(GenIncProcessConsumerType): 

1209 r""" 

1210 A consumer type based on GenIncProcessModel, where the log permanent income follows an AR1 process. 

1211 If you would like to use a different income process, use 

1212 :class:`HARK.ConsumptionSaving.ConsGenIncProcessModel.GenIncProcessConsumerType` 

1213 

1214 .. math:: 

1215 \begin{eqnarray*} 

1216 V_t(M_t,P_t) &=& \max_{C_t} U(C_t) + \beta (1-\mathsf{D}_{t+1}) \mathbb{E} [V_{t+1}(M_{t+1}, P_{t+1}) ], \\ 

1217 A_t &=& M_t - C_t, \\ 

1218 A_t/P_t &\geq& \underline{a}, \\ 

1219 M_{t+1} &=& R A_t + \theta_{t+1}, \\ 

1220 p_{t+1} &=& G_{t+1}(P_t)\psi_{t+1}, \\ 

1221 (\psi_{t+1},\theta_{t+1}) &\sim& F_{t+1}, \\ 

1222 \mathbb{E} [F_{t+1}] &=& 1, \\ 

1223 U(C) &=& \frac{C^{1-\rho}}{1-\rho}, \\ 

1224 log(G_{t+1} (x)) &=&\varphi log(x) + (1-\varphi) log(\overline{P}_{t})+log(\Gamma_{t+1}) + log(\psi_{t+1}), \\ 

1225 \overline{P}_{t+1} &=& \overline{P}_{t} \Gamma_{t+1} \\ 

1226 \end{eqnarray*} 

1227 

1228 

1229 Constructors 

1230 ------------ 

1231 IncShkDstn: Constructor, :math:`\psi`, :math:`\theta` 

1232 The agent's income shock distributions. 

1233 

1234 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.construct_lognormal_income_process_unemployment` 

1235 aXtraGrid: Constructor 

1236 The agent's asset grid. 

1237 

1238 Its default constructor is :func:`HARK.utilities.make_assets_grid` 

1239 pLvlNextFunc: Constructor, (:math:`\Gamma`, :math:`\varphi`) 

1240 An arbitrary function used to evolve the GenIncShockConsumerType's permanent income 

1241 

1242 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_AR1_style_pLvlNextFunc` 

1243 pLvlGrid: Constructor 

1244 The agent's pLvl grid 

1245 

1246 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_pLvlGrid_by_simulation` 

1247 pLvlPctiles: Constructor 

1248 The agents income level percentile grid 

1249 

1250 Its default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_basic_pLvlPctiles` 

1251 

1252 Solving Parameters 

1253 ------------------ 

1254 cycles: int 

1255 0 specifies an infinite horizon model, 1 specifies a finite model. 

1256 T_cycle: int 

1257 Number of periods in the cycle for this agent type. 

1258 CRRA: float, :math:`\rho` 

1259 Coefficient of Relative Risk Aversion. 

1260 Rfree: float or list[float], time varying, :math:`\mathsf{R}` 

1261 Risk Free interest rate. Pass a list of floats to make Rfree time varying. 

1262 DiscFac: float, :math:`\beta` 

1263 Intertemporal discount factor. 

1264 LivPrb: list[float], time varying, :math:`1-\mathsf{D}` 

1265 Survival probability after each period. 

1266 PermGroFac: list[float], time varying, :math:`\Gamma` 

1267 Permanent income growth factor. 

1268 BoroCnstArt: float, :math:`\underline{a}` 

1269 The minimum Asset/Perminant Income ratio, None to ignore. 

1270 vFuncBool: bool 

1271 Whether to calculate the value function during solution. 

1272 CubicBool: bool 

1273 Whether to use cubic spline interpoliation. 

1274 

1275 Simulation Parameters 

1276 --------------------- 

1277 AgentCount: int 

1278 Number of agents of this kind that are created during simulations. 

1279 T_age: int 

1280 Age after which to automatically kill agents, None to ignore. 

1281 T_sim: int, required for simulation 

1282 Number of periods to simulate. 

1283 track_vars: list[strings] 

1284 List of variables that should be tracked when running the simulation. 

1285 For this agent, the options are 'PermShk', 'TranShk', 'aLvl', 'cLvl', 'mLvl', 'pLvl', and 'who_dies'. 

1286 

1287 PermShk is the agent's permanent income shock 

1288 

1289 TranShk is the agent's transitory income shock 

1290 

1291 aLvl is the nominal asset level 

1292 

1293 cLvl is the nominal consumption level 

1294 

1295 mLvl is the nominal market resources 

1296 

1297 pLvl is the permanent income level 

1298 

1299 who_dies is the array of which agents died 

1300 aNrmInitMean: float 

1301 Mean of Log initial Normalized Assets. 

1302 aNrmInitStd: float 

1303 Std of Log initial Normalized Assets. 

1304 pLvlInitMean: float 

1305 Mean of Log initial permanent income. 

1306 pLvlInitStd: float 

1307 Std of Log initial permanent income. 

1308 PermGroFacAgg: float 

1309 Aggregate permanent income growth factor (The portion of PermGroFac attributable to aggregate productivity growth). 

1310 PerfMITShk: boolean 

1311 Do Perfect Foresight MIT Shock (Forces Newborns to follow solution path of the agent they replaced if True). 

1312 NewbornTransShk: boolean 

1313 Whether Newborns have transitory shock. 

1314 

1315 Attributes 

1316 ---------- 

1317 solution: list[Consumer solution object] 

1318 Created by the :func:`.solve` method. Finite horizon models create a list with T_cycle+1 elements, for each period in the solution. 

1319 Infinite horizon solutions return a list with T_cycle elements for each period in the cycle. 

1320 

1321 Unlike other models with this solution type, this model's variables are NOT normalized. 

1322 The solution functions also depend on the permanent income level. For example, :math:`C=\text{cFunc}(M,P)`. 

1323 hNrm has been replaced by hLvl which is a function of permanent income. 

1324 MPC max has not yet been implemented for this class. It will be a function of permanent income. 

1325 

1326 Visit :class:`HARK.ConsumptionSaving.ConsIndShockModel.ConsumerSolution` for more information about the solution. 

1327 

1328 history: Dict[Array] 

1329 Created by running the :func:`.simulate()` method. 

1330 Contains the variables in track_vars. Each item in the dictionary is an array with the shape (T_sim,AgentCount). 

1331 Visit :class:`HARK.core.AgentType.simulate` for more information. 

1332 """ 

1333 

1334 IncShkDstn_default = PersistentShockConsumerType_IncShkDstn_default 

1335 aXtraGrid_default = PersistentShockConsumerType_aXtraGrid_default 

1336 pLvlNextFunc_default = PersistentShockConsumerType_pLvlNextFunc_default 

1337 pLvlGrid_default = PersistentShockConsumerType_pLvlGrid_default 

1338 pLvlPctiles_default = PersistentShockConsumerType_pLvlPctiles_default 

1339 solving_default = PersistentShockConsumerType_solving_default 

1340 simulation_default = PersistentShockConsumerType_simulation_default 

1341 

1342 default_ = { 

1343 "params": init_persistent_shocks, 

1344 "solver": solve_one_period_ConsGenIncProcess, 

1345 }