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

312 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-02 05:14 +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 (1-\mathsf{D}_{t+1}) \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 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} [F_{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}` 

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:`1-\mathsf{D}` 

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 update_income_process(self): 

791 self.update( 

792 "IncShkDstn", 

793 "PermShkDstn", 

794 "TranShkDstn", 

795 "pLvlPctiles", 

796 "pLvlNextFunc", 

797 "pLvlGrid", 

798 ) 

799 

800 def update_pLvlNextFunc(self): 

801 """ 

802 Update the function that maps this period's permanent income level to next 

803 period's expected permanent income level. 

804 

805 Parameters 

806 ---------- 

807 None 

808 

809 Returns 

810 ------- 

811 None 

812 """ 

813 self.construct("pLvlNextFunc") 

814 

815 def install_retirement_func(self): 

816 """ 

817 Installs a special pLvlNextFunc representing retirement in the correct 

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

819 pLvlNextFuncRet. If T_retire is zero or pLvlNextFuncRet does not 

820 exist, this method does nothing. Should only be called from within the 

821 method update_pLvlNextFunc, which ensures that time is flowing forward. 

822 

823 Parameters 

824 ---------- 

825 None 

826 

827 Returns 

828 ------- 

829 None 

830 """ 

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

832 return 

833 t = self.T_retire 

834 self.pLvlNextFunc[t] = self.pLvlNextFuncRet 

835 

836 def update_pLvlGrid(self): 

837 """ 

838 Update the grid of persistent income levels. 

839 

840 Parameters 

841 ---------- 

842 None 

843 

844 Returns 

845 ------- 

846 None 

847 """ 

848 self.construct("pLvlPctiles", "pLvlGrid") 

849 self.add_to_time_vary("pLvlGrid") 

850 

851 def sim_birth(self, which_agents): 

852 """ 

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

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

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

856 

857 Parameters 

858 ---------- 

859 which_agents : np.array(Bool) 

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

861 

862 Returns 

863 ------- 

864 None 

865 """ 

866 super().sim_birth(which_agents) 

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

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

869 ) 

870 

871 def transition(self): 

872 """ 

873 Calculates updated values of normalized market resources 

874 and persistent income level for each 

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

876 

877 Parameters 

878 ---------- 

879 None 

880 

881 Returns 

882 ------- 

883 kLvlNow 

884 pLvlNow 

885 mLvlNow 

886 """ 

887 kLvlNow = self.state_prev["aLvl"] 

888 pLvlNow = np.zeros_like(kLvlNow) 

889 RfreeNow = self.get_Rfree() 

890 

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

892 for t in range(self.T_cycle): 

893 these = t == self.t_cycle 

894 pLvlNow[these] = ( 

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

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

897 ) 

898 

899 # state value 

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

901 

902 # Market resources after income - state value 

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

904 

905 return (kLvlNow, pLvlNow, mLvlNow) 

906 

907 def get_controls(self): 

908 """ 

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

910 

911 Parameters 

912 ---------- 

913 None 

914 

915 Returns 

916 ------- 

917 None 

918 """ 

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

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

921 

922 for t in range(self.T_cycle): 

923 these = t == self.t_cycle 

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

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

926 ) 

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

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

929 ) 

930 self.controls["cLvl"] = cLvlNow 

931 self.MPCnow = MPCnow 

932 

933 def get_poststates(self): 

934 """ 

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

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

937 

938 Parameters 

939 ---------- 

940 None 

941 

942 Returns 

943 ------- 

944 None 

945 """ 

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

947 # moves now to prev 

948 AgentType.get_poststates(self) 

949 

950 

951############################################################################### 

952 

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

954IndShockExplicitPermIncConsumerType_constructors_default = ( 

955 GenIncProcessConsumerType_constructors_default.copy() 

956) 

957IndShockExplicitPermIncConsumerType_constructors_default["pLvlNextFunc"] = ( 

958 make_explicit_perminc_pLvlNextFunc 

959) 

960IndShockExplicitPermIncConsumerType_IncShkDstn_default = ( 

961 GenIncProcessConsumerType_IncShkDstn_default.copy() 

962) 

963IndShockExplicitPermIncConsumerType_kNrmInitDstn_default = ( 

964 GenIncProcessConsumerType_kNrmInitDstn_default.copy() 

965) 

966IndShockExplicitPermIncConsumerType_pLvlInitDstn_default = ( 

967 GenIncProcessConsumerType_pLvlInitDstn_default.copy() 

968) 

969IndShockExplicitPermIncConsumerType_aXtraGrid_default = ( 

970 GenIncProcessConsumerType_aXtraGrid_default.copy() 

971) 

972IndShockExplicitPermIncConsumerType_pLvlNextFunc_default = ( 

973 GenIncProcessConsumerType_pLvlNextFunc_default.copy() 

974) 

975IndShockExplicitPermIncConsumerType_pLvlGrid_default = ( 

976 GenIncProcessConsumerType_pLvlGrid_default.copy() 

977) 

978IndShockExplicitPermIncConsumerType_pLvlPctiles_default = ( 

979 GenIncProcessConsumerType_pLvlPctiles_default.copy() 

980) 

981IndShockExplicitPermIncConsumerType_solving_default = ( 

982 GenIncProcessConsumerType_solving_default.copy() 

983) 

984IndShockExplicitPermIncConsumerType_solving_default["constructors"] = ( 

985 IndShockExplicitPermIncConsumerType_constructors_default 

986) 

987IndShockExplicitPermIncConsumerType_pLvlNextFunc_default["PermGroFac"] = [1.0] 

988IndShockExplicitPermIncConsumerType_simulation_default = ( 

989 GenIncProcessConsumerType_simulation_default.copy() 

990) 

991 

992IndShockExplicitPermIncConsumerType_default = {} 

993IndShockExplicitPermIncConsumerType_default.update( 

994 IndShockExplicitPermIncConsumerType_IncShkDstn_default 

995) 

996IndShockExplicitPermIncConsumerType_default.update( 

997 IndShockExplicitPermIncConsumerType_kNrmInitDstn_default 

998) 

999IndShockExplicitPermIncConsumerType_default.update( 

1000 IndShockExplicitPermIncConsumerType_pLvlInitDstn_default 

1001) 

1002IndShockExplicitPermIncConsumerType_default.update( 

1003 IndShockExplicitPermIncConsumerType_aXtraGrid_default 

1004) 

1005IndShockExplicitPermIncConsumerType_default.update( 

1006 IndShockExplicitPermIncConsumerType_pLvlNextFunc_default 

1007) 

1008IndShockExplicitPermIncConsumerType_default.update( 

1009 IndShockExplicitPermIncConsumerType_pLvlGrid_default 

1010) 

1011IndShockExplicitPermIncConsumerType_default.update( 

1012 IndShockExplicitPermIncConsumerType_pLvlPctiles_default 

1013) 

1014IndShockExplicitPermIncConsumerType_default.update( 

1015 IndShockExplicitPermIncConsumerType_solving_default 

1016) 

1017IndShockExplicitPermIncConsumerType_default.update( 

1018 IndShockExplicitPermIncConsumerType_simulation_default 

1019) 

1020init_explicit_perm_inc = IndShockExplicitPermIncConsumerType_default 

1021 

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

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

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

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

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

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

1028 

1029 

1030class IndShockExplicitPermIncConsumerType(GenIncProcessConsumerType): 

1031 r""" 

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

1033 describing the path of permanent income multiplies the current permanent 

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

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

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

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

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

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

1040 

1041 .. math:: 

1042 \begin{eqnarray*} 

1043 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}) ], \\ 

1044 A_t &=& M_t - C_t, \\ 

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

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

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

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

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

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

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

1052 \end{eqnarray*} 

1053 

1054 

1055 Constructors 

1056 ------------ 

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

1058 The agent's income shock distributions. 

1059 

1060 It's default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.construct_lognormal_income_process_unemployment` 

1061 aXtraGrid: Constructor 

1062 The agent's asset grid. 

1063 

1064 It's default constructor is :func:`HARK.utilities.make_assets_grid` 

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

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

1067 

1068 It's default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_explicit_perminc_pLvlNextFunc` 

1069 pLvlGrid: Constructor 

1070 The agent's pLvl grid 

1071 

1072 It's default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_pLvlGrid_by_simulation` 

1073 pLvlPctiles: Constructor 

1074 The agents income level percentile grid 

1075 

1076 It's default constructor is :func:`HARK.Calibration.Income.IncomeProcesses.make_basic_pLvlPctiles` 

1077 

1078 Solving Parameters 

1079 ------------------ 

1080 cycles: int 

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

1082 T_cycle: int 

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

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

1085 Coefficient of Relative Risk Aversion. 

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

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

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

1089 Intertemporal discount factor. 

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

1091 Survival probability after each period. 

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

1093 Permanent income growth factor. 

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

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

1096 vFuncBool: bool 

1097 Whether to calculate the value function during solution. 

1098 CubicBool: bool 

1099 Whether to use cubic spline interpoliation. 

1100 

1101 Simulation Parameters 

1102 --------------------- 

1103 AgentCount: int 

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

1105 T_age: int 

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

1107 T_sim: int, required for simulation 

1108 Number of periods to simulate. 

1109 track_vars: list[strings] 

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

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

1112 

1113 PermShk is the agent's permanent income shock 

1114 

1115 TranShk is the agent's transitory income shock 

1116 

1117 aLvl is the nominal asset level 

1118 

1119 cLvl is the nominal consumption level 

1120 

1121 mLvl is the nominal market resources 

1122 

1123 pLvl is the permanent income level 

1124 

1125 who_dies is the array of which agents died 

1126 aNrmInitMean: float 

1127 Mean of Log initial Normalized Assets. 

1128 aNrmInitStd: float 

1129 Std of Log initial Normalized Assets. 

1130 pLvlInitMean: float 

1131 Mean of Log initial permanent income. 

1132 pLvlInitStd: float 

1133 Std of Log initial permanent income. 

1134 PermGroFacAgg: float 

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

1136 PerfMITShk: boolean 

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

1138 NewbornTransShk: boolean 

1139 Whether Newborns have transitory shock. 

1140 

1141 Attributes 

1142 ---------- 

1143 solution: list[Consumer solution object] 

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

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

1146 

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

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

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

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

1151 

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

1153 

1154 history: Dict[Array] 

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

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

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

1158 """ 

1159 

1160 IncShkDstn_default = GenIncProcessConsumerType_IncShkDstn_default 

1161 aXtraGrid_default = GenIncProcessConsumerType_aXtraGrid_default 

1162 pLvlNextFunc_default = GenIncProcessConsumerType_pLvlNextFunc_default 

1163 pLvlGrid_default = GenIncProcessConsumerType_pLvlGrid_default 

1164 pLvlPctiles_default = GenIncProcessConsumerType_pLvlPctiles_default 

1165 solving_default = GenIncProcessConsumerType_solving_default 

1166 simulation_default = GenIncProcessConsumerType_simulation_default 

1167 

1168 default_ = { 

1169 "params": init_explicit_perm_inc, 

1170 "solver": solve_one_period_ConsGenIncProcess, 

1171 } 

1172 

1173 

1174############################################################################### 

1175 

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

1177 

1178PersistentShockConsumerType_constructors_default = ( 

1179 GenIncProcessConsumerType_constructors_default.copy() 

1180) 

1181PersistentShockConsumerType_constructors_default["pLvlNextFunc"] = ( 

1182 make_AR1_style_pLvlNextFunc 

1183) 

1184PersistentShockConsumerType_kNrmInitDstn_default = ( 

1185 IndShockExplicitPermIncConsumerType_kNrmInitDstn_default.copy() 

1186) 

1187PersistentShockConsumerType_pLvlInitDstn_default = ( 

1188 IndShockExplicitPermIncConsumerType_pLvlInitDstn_default.copy() 

1189) 

1190PersistentShockConsumerType_IncShkDstn_default = ( 

1191 IndShockExplicitPermIncConsumerType_IncShkDstn_default.copy() 

1192) 

1193PersistentShockConsumerType_aXtraGrid_default = ( 

1194 IndShockExplicitPermIncConsumerType_aXtraGrid_default.copy() 

1195) 

1196PersistentShockConsumerType_pLvlNextFunc_default = ( 

1197 IndShockExplicitPermIncConsumerType_pLvlNextFunc_default.copy() 

1198) 

1199PersistentShockConsumerType_pLvlGrid_default = ( 

1200 IndShockExplicitPermIncConsumerType_pLvlGrid_default.copy() 

1201) 

1202PersistentShockConsumerType_pLvlPctiles_default = ( 

1203 IndShockExplicitPermIncConsumerType_pLvlPctiles_default.copy() 

1204) 

1205PersistentShockConsumerType_solving_default = ( 

1206 IndShockExplicitPermIncConsumerType_solving_default.copy() 

1207) 

1208PersistentShockConsumerType_solving_default["constructors"] = ( 

1209 PersistentShockConsumerType_constructors_default 

1210) 

1211PersistentShockConsumerType_pLvlNextFunc_default["PrstIncCorr"] = 0.98 

1212PersistentShockConsumerType_simulation_default = ( 

1213 IndShockExplicitPermIncConsumerType_simulation_default.copy() 

1214) 

1215 

1216PersistentShockConsumerType_default = {} 

1217PersistentShockConsumerType_default.update( 

1218 PersistentShockConsumerType_IncShkDstn_default 

1219) 

1220PersistentShockConsumerType_default.update( 

1221 PersistentShockConsumerType_kNrmInitDstn_default 

1222) 

1223PersistentShockConsumerType_default.update( 

1224 PersistentShockConsumerType_pLvlInitDstn_default 

1225) 

1226PersistentShockConsumerType_default.update( 

1227 PersistentShockConsumerType_aXtraGrid_default 

1228) 

1229PersistentShockConsumerType_default.update( 

1230 PersistentShockConsumerType_pLvlNextFunc_default 

1231) 

1232PersistentShockConsumerType_default.update(PersistentShockConsumerType_pLvlGrid_default) 

1233PersistentShockConsumerType_default.update( 

1234 PersistentShockConsumerType_pLvlPctiles_default 

1235) 

1236PersistentShockConsumerType_default.update(PersistentShockConsumerType_solving_default) 

1237PersistentShockConsumerType_default.update( 

1238 PersistentShockConsumerType_simulation_default 

1239) 

1240init_persistent_shocks = PersistentShockConsumerType_default 

1241 

1242 

1243class PersistentShockConsumerType(GenIncProcessConsumerType): 

1244 r""" 

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

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

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

1248 

1249 .. math:: 

1250 \begin{eqnarray*} 

1251 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}) ], \\ 

1252 A_t &=& M_t - C_t, \\ 

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

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

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

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

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

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

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

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

1261 \end{eqnarray*} 

1262 

1263 

1264 Constructors 

1265 ------------ 

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

1267 The agent's income shock distributions. 

1268 

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

1270 aXtraGrid: Constructor 

1271 The agent's asset grid. 

1272 

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

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

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

1276 

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

1278 pLvlGrid: Constructor 

1279 The agent's pLvl grid 

1280 

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

1282 pLvlPctiles: Constructor 

1283 The agents income level percentile grid 

1284 

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

1286 

1287 Solving Parameters 

1288 ------------------ 

1289 cycles: int 

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

1291 T_cycle: int 

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

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

1294 Coefficient of Relative Risk Aversion. 

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

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

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

1298 Intertemporal discount factor. 

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

1300 Survival probability after each period. 

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

1302 Permanent income growth factor. 

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

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

1305 vFuncBool: bool 

1306 Whether to calculate the value function during solution. 

1307 CubicBool: bool 

1308 Whether to use cubic spline interpoliation. 

1309 

1310 Simulation Parameters 

1311 --------------------- 

1312 AgentCount: int 

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

1314 T_age: int 

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

1316 T_sim: int, required for simulation 

1317 Number of periods to simulate. 

1318 track_vars: list[strings] 

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

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

1321 

1322 PermShk is the agent's permanent income shock 

1323 

1324 TranShk is the agent's transitory income shock 

1325 

1326 aLvl is the nominal asset level 

1327 

1328 cLvl is the nominal consumption level 

1329 

1330 mLvl is the nominal market resources 

1331 

1332 pLvl is the permanent income level 

1333 

1334 who_dies is the array of which agents died 

1335 aNrmInitMean: float 

1336 Mean of Log initial Normalized Assets. 

1337 aNrmInitStd: float 

1338 Std of Log initial Normalized Assets. 

1339 pLvlInitMean: float 

1340 Mean of Log initial permanent income. 

1341 pLvlInitStd: float 

1342 Std of Log initial permanent income. 

1343 PermGroFacAgg: float 

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

1345 PerfMITShk: boolean 

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

1347 NewbornTransShk: boolean 

1348 Whether Newborns have transitory shock. 

1349 

1350 Attributes 

1351 ---------- 

1352 solution: list[Consumer solution object] 

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

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

1355 

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

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

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

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

1360 

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

1362 

1363 history: Dict[Array] 

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

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

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

1367 """ 

1368 

1369 IncShkDstn_default = PersistentShockConsumerType_IncShkDstn_default 

1370 aXtraGrid_default = PersistentShockConsumerType_aXtraGrid_default 

1371 pLvlNextFunc_default = PersistentShockConsumerType_pLvlNextFunc_default 

1372 pLvlGrid_default = PersistentShockConsumerType_pLvlGrid_default 

1373 pLvlPctiles_default = PersistentShockConsumerType_pLvlPctiles_default 

1374 solving_default = PersistentShockConsumerType_solving_default 

1375 simulation_default = PersistentShockConsumerType_simulation_default 

1376 

1377 default_ = { 

1378 "params": init_persistent_shocks, 

1379 "solver": solve_one_period_ConsGenIncProcess, 

1380 }