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

293 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-25 05:22 +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 approximation to the income shocks between the period being 

138 solved and the one immediately following (in solution_next). 

139 LivPrb : float 

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

141 the succeeding period. 

142 DiscFac : float 

143 Intertemporal discount factor for future utility. 

144 CRRA : float 

145 Coefficient of relative risk aversion. 

146 Rfree : float 

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

148 pLvlNextFunc : float 

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

150 BoroCnstArt: float or None 

151 Borrowing constraint for the minimum allowable assets to end the 

152 period with. 

153 aXtraGrid: np.array 

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

155 above the absolute minimum acceptable level. 

156 pLvlGrid: np.array 

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

158 vFuncBool: boolean 

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

160 included in the reported solution. 

161 CubicBool: boolean 

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

163 

164 Returns 

165 ------- 

166 solution_now : ConsumerSolution 

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

168 """ 

169 # Define the utility function for this period 

170 uFunc = UtilityFuncCRRA(CRRA) 

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

172 

173 # Unpack next period's income shock distribution 

174 ShkPrbsNext = IncShkDstn.pmv 

175 PermShkValsNext = IncShkDstn.atoms[0] 

176 TranShkValsNext = IncShkDstn.atoms[1] 

177 PermShkMinNext = np.min(PermShkValsNext) 

178 TranShkMinNext = np.min(TranShkValsNext) 

179 

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

181 IncNext = PermShkValsNext * TranShkValsNext 

182 WorstIncNext = PermShkMinNext * TranShkMinNext 

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

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

185 

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

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

188 vPfuncNext = solution_next.vPfunc 

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

190 

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

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

193 try: 

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

195 except: 

196 MPCminNow = 0.0 

197 mLvlMinNext = solution_next.mLvlMin 

198 

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

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

201 # hNrmNow = 0.0 

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

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

204 

205 # Define some functions for calculating future expectations 

206 def calc_pLvl_next(S, p): 

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

208 

209 def calc_mLvl_next(S, a, p_next): 

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

211 

212 def calc_hLvl(S, p): 

213 pLvl_next = calc_pLvl_next(S, p) 

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

215 return hLvl 

216 

217 def calc_v_next(S, a, p): 

218 pLvl_next = calc_pLvl_next(S, p) 

219 mLvl_next = calc_mLvl_next(S, a, pLvl_next) 

220 v_next = vFuncNext(mLvl_next, pLvl_next) 

221 return v_next 

222 

223 def calc_vP_next(S, a, p): 

224 pLvl_next = calc_pLvl_next(S, p) 

225 mLvl_next = calc_mLvl_next(S, a, pLvl_next) 

226 vP_next = vPfuncNext(mLvl_next, pLvl_next) 

227 return vP_next 

228 

229 def calc_vPP_next(S, a, p): 

230 pLvl_next = calc_pLvl_next(S, p) 

231 mLvl_next = calc_mLvl_next(S, a, pLvl_next) 

232 vPP_next = vPPfuncNext(mLvl_next, pLvl_next) 

233 return vPP_next 

234 

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

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

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

238 

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

240 ShkCount = TranShkValsNext.size 

241 pLvlCount = pLvlGrid.size 

242 PermShkVals_temp = np.tile( 

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

244 ) 

245 TranShkVals_temp = np.tile( 

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

247 ) 

248 pLvlNext_temp = ( 

249 np.tile( 

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

251 (1, ShkCount), 

252 ) 

253 * PermShkVals_temp 

254 ) 

255 

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

257 aLvlMin_candidates = ( 

258 mLvlMinNext(pLvlNext_temp) - TranShkVals_temp * pLvlNext_temp 

259 ) / Rfree 

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

261 BoroCnstNat = LinearInterp( 

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

263 ) 

264 

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

266 if BoroCnstArt is not None: 

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

268 mLvlMinNow = UpperEnvelope(BoroCnstArt, BoroCnstNat) 

269 else: 

270 mLvlMinNow = BoroCnstNat 

271 

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

273 cFuncNowCnstBase = BilinearInterp( 

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

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

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

277 ) 

278 cFuncNowCnst = VariableLowerBoundFunc2D(cFuncNowCnstBase, mLvlMinNow) 

279 

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

281 pLvlCount = pLvlGrid.size 

282 aNrmCount = aXtraGrid.size 

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

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

285 # shape = (pLvlCount,aNrmCount) 

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

287 aLvlNow[0, :] = aXtraGrid 

288 

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

290 EndOfPrd_vP = ( 

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

292 ) 

293 

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

295 if vFuncBool: 

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

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

298 EndOfPrd_v *= DiscFacEff 

299 

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

301 EndOfPrd_vNvrs = uFunc.inv(EndOfPrd_v) 

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

303 

304 # Add points at mLvl=zero 

305 EndOfPrd_vNvrs = np.concatenate( 

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

307 ) 

308 EndOfPrd_vNvrsP = np.concatenate( 

309 ( 

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

311 EndOfPrd_vNvrsP, 

312 ), 

313 axis=1, 

314 ) 

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

316 

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

318 aLvl_temp = np.concatenate( 

319 ( 

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

321 aLvlNow, 

322 ), 

323 axis=1, 

324 ) 

325 

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

327 EndOfPrd_vNvrsFunc_list = [] 

328 for p in range(pLvlCount): 

329 EndOfPrd_vNvrsFunc_list.append( 

330 CubicInterp( 

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

332 EndOfPrd_vNvrs[p, :], 

333 EndOfPrd_vNvrsP[p, :], 

334 ) 

335 ) 

336 EndOfPrd_vNvrsFuncBase = LinearInterpOnInterp1D( 

337 EndOfPrd_vNvrsFunc_list, pLvlGrid 

338 ) 

339 

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

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

342 EndOfPrd_vNvrsFunc = VariableLowerBoundFunc2D( 

343 EndOfPrd_vNvrsFuncBase, BoroCnstNat 

344 ) 

345 EndOfPrd_vFunc = ValueFuncCRRA(EndOfPrd_vNvrsFunc, CRRA) 

346 

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

348 # endogenous gridpoints 

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

350 mLvlNow = cLvlNow + aLvlNow 

351 

352 # Limiting consumption is zero as m approaches mNrmMin 

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

354 m_for_interpolation = np.concatenate( 

355 ( 

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

357 mLvlNow, 

358 ), 

359 axis=-1, 

360 ) 

361 

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

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

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

365 c_for_interpolation = np.concatenate( 

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

367 ) 

368 

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

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

371 p_for_interpolation = np.concatenate( 

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

373 ) 

374 p_for_interpolation = np.concatenate( 

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

376 ) 

377 

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

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

380 if CubicBool: 

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

382 vPP_fac = DiscFacEff * Rfree * Rfree 

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

384 EndOfPrd_vPP *= vPP_fac 

385 

386 # Calculate the MPC at each gridpoint 

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

388 MPC = dcda / (dcda + 1.0) 

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

390 

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

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

393 

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

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

396 pLvl_j = p_for_interpolation[j, 0] 

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

398 

399 # Make a cubic consumption function for this pLvl 

400 c_temp = c_for_interpolation[j, :] 

401 MPC_temp = MPC[j, :] 

402 if pLvl_j > 0: 

403 cFunc_by_pLvl_list.append( 

404 CubicInterp( 

405 m_temp, 

406 c_temp, 

407 MPC_temp, 

408 lower_extrap=True, 

409 slope_limit=MPCminNow, 

410 intercept_limit=MPCminNow * hLvlNow(pLvl_j), 

411 ) 

412 ) 

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

414 cFunc_by_pLvl_list.append( 

415 LinearInterp(m_temp, c_temp, lower_extrap=True) 

416 ) 

417 

418 # Basic version: use linear interpolation within a pLvl 

419 else: 

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

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

422 pLvl_j = p_for_interpolation[j, 0] 

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

424 

425 # Make a linear consumption function for this pLvl 

426 c_temp = c_for_interpolation[j, :] 

427 if pLvl_j > 0: 

428 cFunc_by_pLvl_list.append( 

429 LinearInterp( 

430 m_temp, 

431 c_temp, 

432 lower_extrap=True, 

433 slope_limit=MPCminNow, 

434 intercept_limit=MPCminNow * hLvlNow(pLvl_j), 

435 ) 

436 ) 

437 else: 

438 cFunc_by_pLvl_list.append( 

439 LinearInterp(m_temp, c_temp, lower_extrap=True) 

440 ) 

441 

442 # Combine all linear cFuncs into one function 

443 pLvl_list = p_for_interpolation[:, 0] 

444 cFuncUncBase = LinearInterpOnInterp1D(cFunc_by_pLvl_list, pLvl_list) 

445 cFuncNowUnc = VariableLowerBoundFunc2D(cFuncUncBase, BoroCnstNat) 

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

447 

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

449 cFuncNow = LowerEnvelope2D(cFuncNowUnc, cFuncNowCnst) 

450 

451 # Make the marginal value function 

452 vPfuncNow = MargValueFuncCRRA(cFuncNow, CRRA) 

453 

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

455 if CubicBool: 

456 vPPfuncNow = MargMargValueFuncCRRA(cFuncNow, CRRA) 

457 else: 

458 vPPfuncNow = NullFunc() 

459 

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

461 if vFuncBool: 

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

463 # Tile pLvl across m values 

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

465 mLvl_temp = ( 

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

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

468 ) 

469 cLvl_temp = cFuncNow(mLvl_temp, pLvl_temp) 

470 aLvl_temp = mLvl_temp - cLvl_temp 

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

472 vP_temp = uFunc.der(cLvl_temp) 

473 

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

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

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

477 

478 # Add data at the lower bound of m 

479 mLvl_temp = np.concatenate( 

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

481 ) 

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

483 vNvrsP_temp = np.concatenate( 

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

485 axis=0, 

486 ) 

487 

488 # Add data at the lower bound of p 

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

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

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

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

493 vNvrsP_temp = np.concatenate( 

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

495 ) 

496 

497 # Construct the pseudo-inverse value function 

498 vNvrsFunc_list = [] 

499 for j in range(pLvlCount + 1): 

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

501 vNvrsFunc_list.append( 

502 CubicInterp( 

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

504 vNvrs_temp[:, j], 

505 vNvrsP_temp[:, j], 

506 MPCminNvrs * hLvlNow(pLvl), 

507 MPCminNvrs, 

508 ) 

509 ) 

510 # Value function "shifted" 

511 vNvrsFuncBase = LinearInterpOnInterp1D( 

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

513 ) 

514 vNvrsFuncNow = VariableLowerBoundFunc2D(vNvrsFuncBase, mLvlMinNow) 

515 

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

517 vFuncNow = ValueFuncCRRA(vNvrsFuncNow, CRRA) 

518 

519 else: 

520 vFuncNow = NullFunc() 

521 

522 # Package and return the solution object 

523 solution_now = ConsumerSolution( 

524 cFunc=cFuncNow, 

525 vFunc=vFuncNow, 

526 vPfunc=vPfuncNow, 

527 vPPfunc=vPPfuncNow, 

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

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

530 MPCmin=MPCminNow, 

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

532 ) 

533 solution_now.hLvl = hLvlNow 

534 solution_now.mLvlMin = mLvlMinNow 

535 return solution_now 

536 

537 

538############################################################################### 

539 

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

541GenIncProcessConsumerType_constructors_default = { 

542 "IncShkDstn": construct_lognormal_income_process_unemployment, 

543 "PermShkDstn": get_PermShkDstn_from_IncShkDstn, 

544 "TranShkDstn": get_TranShkDstn_from_IncShkDstn, 

545 "aXtraGrid": make_assets_grid, 

546 "pLvlPctiles": make_basic_pLvlPctiles, 

547 "pLvlGrid": make_pLvlGrid_by_simulation, 

548 "pLvlNextFunc": make_trivial_pLvlNextFunc, 

549 "solution_terminal": make_2D_CRRA_solution_terminal, 

550 "kNrmInitDstn": make_lognormal_kNrm_init_dstn, 

551 "pLvlInitDstn": make_lognormal_pLvl_init_dstn, 

552} 

553 

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

555GenIncProcessConsumerType_kNrmInitDstn_default = { 

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

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

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

559} 

560 

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

562GenIncProcessConsumerType_pLvlInitDstn_default = { 

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

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

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

566} 

567 

568# Default parameters to make IncShkDstn using construct_lognormal_income_process_unemployment 

569GenIncProcessConsumerType_IncShkDstn_default = { 

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

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

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

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

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

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

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

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

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

579} 

580 

581# Default parameters to make aXtraGrid using make_assets_grid 

582GenIncProcessConsumerType_aXtraGrid_default = { 

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

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

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

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

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

588} 

589GenIncProcessConsumerType_pLvlNextFunc_default = {} # Trivial function has no parameters 

590 

591# Default parameters to make pLvlGrid using make_basic_pLvlPctiles 

592GenIncProcessConsumerType_pLvlPctiles_default = { 

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

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

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

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

597} 

598 

599# Default parameters to make pLvlGrid using make_pLvlGrid_by_simulation 

600GenIncProcessConsumerType_pLvlGrid_default = { 

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

602} 

603 

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

605GenIncProcessConsumerType_solving_default = { 

606 # BASIC HARK PARAMETERS REQUIRED TO SOLVE THE MODEL 

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

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

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

610 "constructors": GenIncProcessConsumerType_constructors_default, # See dictionary above 

611 # PRIMITIVE RAW PARAMETERS REQUIRED TO SOLVE THE MODEL 

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

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

614 "DiscFac": 0.96, # Intertemporal discount factor 

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

616 "BoroCnstArt": 0.0, # Artificial borrowing constraint 

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

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

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

620} 

621GenIncProcessConsumerType_simulation_default = { 

622 # PARAMETERS REQUIRED TO SIMULATE THE MODEL 

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

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

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

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

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

628 # ADDITIONAL OPTIONAL PARAMETERS 

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

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

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

632} 

633GenIncProcessConsumerType_default = {} 

634GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_kNrmInitDstn_default) 

635GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlInitDstn_default) 

636GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_IncShkDstn_default) 

637GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_aXtraGrid_default) 

638GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlNextFunc_default) 

639GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlGrid_default) 

640GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_pLvlPctiles_default) 

641GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_solving_default) 

642GenIncProcessConsumerType_default.update(GenIncProcessConsumerType_simulation_default) 

643init_general_inc = GenIncProcessConsumerType_default 

644 

645 

646class GenIncProcessConsumerType(IndShockConsumerType): 

647 r""" 

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

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

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

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

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

653 

654 .. math:: 

655 \begin{eqnarray*} 

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

657 A_t &=& M_t - C_t, \\ 

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

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

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

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

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

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

664 \end{eqnarray*} 

665 

666 

667 Constructors 

668 ------------ 

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

670 The agent's income shock distributions. 

671 

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

673 aXtraGrid: Constructor 

674 The agent's asset grid. 

675 

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

677 pLvlNextFunc: Constructor 

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

679 

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

681 pLvlGrid: Constructor 

682 The agent's pLvl grid 

683 

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

685 pLvlPctiles: Constructor 

686 The agents income level percentile grid 

687 

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

689 

690 Solving Parameters 

691 ------------------ 

692 cycles: int 

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

694 T_cycle: int 

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

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

697 Coefficient of Relative Risk Aversion. 

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

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

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

701 Intertemporal discount factor. 

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

703 Survival probability after each period. 

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

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

706 vFuncBool: bool 

707 Whether to calculate the value function during solution. 

708 CubicBool: bool 

709 Whether to use cubic spline interpoliation. 

710 

711 Simulation Parameters 

712 --------------------- 

713 AgentCount: int 

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

715 T_age: int 

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

717 T_sim: int, required for simulation 

718 Number of periods to simulate. 

719 track_vars: list[strings] 

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

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

722 

723 PermShk is the agent's permanent income shock 

724 

725 TranShk is the agent's transitory income shock 

726 

727 aLvl is the nominal asset level 

728 

729 cLvl is the nominal consumption level 

730 

731 mLvl is the nominal market resources 

732 

733 pLvl is the permanent income level 

734 

735 who_dies is the array of which agents died 

736 aNrmInitMean: float 

737 Mean of Log initial Normalized Assets. 

738 aNrmInitStd: float 

739 Std of Log initial Normalized Assets. 

740 pLvlInitMean: float 

741 Mean of Log initial permanent income. 

742 pLvlInitStd: float 

743 Std of Log initial permanent income. 

744 PermGroFacAgg: float 

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

746 PerfMITShk: boolean 

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

748 NewbornTransShk: boolean 

749 Whether Newborns have transitory shock. 

750 

751 Attributes 

752 ---------- 

753 solution: list[Consumer solution object] 

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

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

756 

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

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

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

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

761 

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

763 

764 history: Dict[Array] 

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

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

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

768 """ 

769 

770 IncShkDstn_default = GenIncProcessConsumerType_IncShkDstn_default 

771 aXtraGrid_default = GenIncProcessConsumerType_aXtraGrid_default 

772 pLvlNextFunc_default = GenIncProcessConsumerType_pLvlNextFunc_default 

773 pLvlGrid_default = GenIncProcessConsumerType_pLvlGrid_default 

774 pLvlPctiles_default = GenIncProcessConsumerType_pLvlPctiles_default 

775 solving_default = GenIncProcessConsumerType_solving_default 

776 simulation_default = GenIncProcessConsumerType_simulation_default 

777 

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

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

780 default_ = { 

781 "params": GenIncProcessConsumerType_default, 

782 "solver": solve_one_period_ConsGenIncProcess, 

783 "model": "ConsGenIncProcess.yaml", 

784 "track_vars": ["aLvl", "cLvl", "mLvl", "pLvl"], 

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 RportNow = self.get_Rport() 

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 = RportNow * 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() # pragma: nocover 

911 

912 def calc_limiting_values(self): 

913 raise NotImplementedError() # pragma: nocover 

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 default_ = { 

1126 "params": init_explicit_perm_inc, 

1127 "solver": solve_one_period_ConsGenIncProcess, 

1128 "model": "ConsGenIncProcess.yaml", 

1129 "track_vars": ["aLvl", "cLvl", "mLvl", "pLvl"], 

1130 } 

1131 

1132 

1133############################################################################### 

1134 

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

1136 

1137PersistentShockConsumerType_constructors_default = ( 

1138 GenIncProcessConsumerType_constructors_default.copy() 

1139) 

1140PersistentShockConsumerType_constructors_default["pLvlNextFunc"] = ( 

1141 make_AR1_style_pLvlNextFunc 

1142) 

1143PersistentShockConsumerType_kNrmInitDstn_default = ( 

1144 IndShockExplicitPermIncConsumerType_kNrmInitDstn_default.copy() 

1145) 

1146PersistentShockConsumerType_pLvlInitDstn_default = ( 

1147 IndShockExplicitPermIncConsumerType_pLvlInitDstn_default.copy() 

1148) 

1149PersistentShockConsumerType_IncShkDstn_default = ( 

1150 IndShockExplicitPermIncConsumerType_IncShkDstn_default.copy() 

1151) 

1152PersistentShockConsumerType_aXtraGrid_default = ( 

1153 IndShockExplicitPermIncConsumerType_aXtraGrid_default.copy() 

1154) 

1155PersistentShockConsumerType_pLvlNextFunc_default = ( 

1156 IndShockExplicitPermIncConsumerType_pLvlNextFunc_default.copy() 

1157) 

1158PersistentShockConsumerType_pLvlGrid_default = ( 

1159 IndShockExplicitPermIncConsumerType_pLvlGrid_default.copy() 

1160) 

1161PersistentShockConsumerType_pLvlPctiles_default = ( 

1162 IndShockExplicitPermIncConsumerType_pLvlPctiles_default.copy() 

1163) 

1164PersistentShockConsumerType_solving_default = ( 

1165 IndShockExplicitPermIncConsumerType_solving_default.copy() 

1166) 

1167PersistentShockConsumerType_solving_default["constructors"] = ( 

1168 PersistentShockConsumerType_constructors_default 

1169) 

1170PersistentShockConsumerType_pLvlNextFunc_default["PrstIncCorr"] = 0.98 

1171PersistentShockConsumerType_simulation_default = ( 

1172 IndShockExplicitPermIncConsumerType_simulation_default.copy() 

1173) 

1174 

1175PersistentShockConsumerType_default = {} 

1176PersistentShockConsumerType_default.update( 

1177 PersistentShockConsumerType_IncShkDstn_default 

1178) 

1179PersistentShockConsumerType_default.update( 

1180 PersistentShockConsumerType_kNrmInitDstn_default 

1181) 

1182PersistentShockConsumerType_default.update( 

1183 PersistentShockConsumerType_pLvlInitDstn_default 

1184) 

1185PersistentShockConsumerType_default.update( 

1186 PersistentShockConsumerType_aXtraGrid_default 

1187) 

1188PersistentShockConsumerType_default.update( 

1189 PersistentShockConsumerType_pLvlNextFunc_default 

1190) 

1191PersistentShockConsumerType_default.update(PersistentShockConsumerType_pLvlGrid_default) 

1192PersistentShockConsumerType_default.update( 

1193 PersistentShockConsumerType_pLvlPctiles_default 

1194) 

1195PersistentShockConsumerType_default.update(PersistentShockConsumerType_solving_default) 

1196PersistentShockConsumerType_default.update( 

1197 PersistentShockConsumerType_simulation_default 

1198) 

1199init_persistent_shocks = PersistentShockConsumerType_default 

1200 

1201 

1202class PersistentShockConsumerType(GenIncProcessConsumerType): 

1203 r""" 

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

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

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

1207 

1208 .. math:: 

1209 \begin{eqnarray*} 

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

1211 A_t &=& M_t - C_t, \\ 

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

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

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

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

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

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

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

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

1220 \end{eqnarray*} 

1221 

1222 Constructors 

1223 ------------ 

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

1225 The agent's income shock distributions. 

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

1227 aXtraGrid: Constructor 

1228 The agent's asset grid. 

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

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

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

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

1233 pLvlGrid: Constructor 

1234 The agent's pLvl grid 

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

1236 pLvlPctiles: Constructor 

1237 The agents income level percentile grid 

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

1239 

1240 Solving Parameters 

1241 ------------------ 

1242 cycles: int 

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

1244 T_cycle: int 

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

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

1247 Coefficient of Relative Risk Aversion. 

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

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

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

1251 Intertemporal discount factor. 

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

1253 Survival probability after each period. 

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

1255 Permanent income growth factor. 

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

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

1258 vFuncBool: bool 

1259 Whether to calculate the value function during solution. 

1260 CubicBool: bool 

1261 Whether to use cubic spline interpoliation. 

1262 

1263 Simulation Parameters 

1264 --------------------- 

1265 AgentCount: int 

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

1267 T_age: int 

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

1269 T_sim: int, required for simulation 

1270 Number of periods to simulate. 

1271 track_vars: list[strings] 

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

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

1274 

1275 PermShk is the agent's permanent income shock 

1276 

1277 TranShk is the agent's transitory income shock 

1278 

1279 aLvl is the nominal asset level 

1280 

1281 cLvl is the nominal consumption level 

1282 

1283 mLvl is the nominal market resources 

1284 

1285 pLvl is the permanent income level 

1286 

1287 who_dies is the array of which agents died 

1288 kLogInitMean: float 

1289 Mean of Log initial Normalized Assets. 

1290 kLogInitStd: float 

1291 Std of Log initial Normalized Assets. 

1292 pLogInitMean: float 

1293 Mean of Log initial permanent income. 

1294 pLogInitStd: float 

1295 Std of Log initial permanent income. 

1296 PermGroFacAgg: float 

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

1298 PerfMITShk: boolean 

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

1300 NewbornTransShk: boolean 

1301 Whether Newborns have transitory shock. 

1302 

1303 Attributes 

1304 ---------- 

1305 solution: list[Consumer solution object] 

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

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

1308 

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

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

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

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

1313 

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

1315 

1316 history: Dict[Array] 

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

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

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

1320 """ 

1321 

1322 default_ = { 

1323 "params": init_persistent_shocks, 

1324 "solver": solve_one_period_ConsGenIncProcess, 

1325 "model": "ConsGenIncProcess.yaml", 

1326 "track_vars": ["aLvl", "cLvl", "mLvl", "pLvl"], 

1327 }