def test_Harmenberg_mtd(self): example = IndShockConsumerType(**dict_harmenberg, verbose=0) example.cycles = 0 example.track_vars = ['aNrm', 'mNrm', 'cNrm', 'pLvl', 'aLvl'] example.T_sim = 20000 example.solve() example.neutral_measure = True example.update_income_process() example.initialize_sim() example.simulate() Asset_list = [] Consumption_list = [] M_list = [] for i in range(example.T_sim): Assetagg = np.mean(example.history['aNrm'][i]) Asset_list.append(Assetagg) ConsAgg = np.mean(example.history['cNrm'][i]) Consumption_list.append(ConsAgg) Magg = np.mean(example.history['mNrm'][i]) M_list.append(Magg) ######################################################### example2 = IndShockConsumerType(**dict_harmenberg, verbose=0) example2.cycles = 0 example2.track_vars = ['aNrm', 'mNrm', 'cNrm', 'pLvl', 'aLvl'] example2.T_sim = 20000 example2.solve() example2.initialize_sim() example2.simulate() Asset_list2 = [] Consumption_list2 = [] M_list2 = [] for i in range(example2.T_sim): Assetagg = np.mean(example2.history['aLvl'][i]) Asset_list2.append(Assetagg) ConsAgg = np.mean(example2.history['cNrm'][i] * example2.history['pLvl'][i]) Consumption_list2.append(ConsAgg) Magg = np.mean(example2.history['mNrm'][i] * example2.history['pLvl'][i]) M_list2.append(Magg) c_std2 = np.std(Consumption_list2) c_std1 = np.std(Consumption_list) c_std_ratio = c_std2 / c_std1 self.assertAlmostEqual(c_std2, 0.03768819564871894) self.assertAlmostEqual(c_std1, 0.004411745897568616) self.assertAlmostEqual(c_std_ratio, 8.542694099741672)
def perturbParameterToGetcPlotList(base_dictionary, param_name, param_min, param_max, N=20, time_vary=False): param_vec = np.linspace( param_min, param_max, num=N, endpoint=True ) # vector of alternative values of the parameter to examine thisConsumer = IndShockConsumerType( **my_dictionary) # create an instance of the consumer type thisConsumer.cycles = 0 # Make this type have an infinite horizon x = np.linspace( mMinVal, mMaxVal, xPoints, endpoint=True ) # Define a vector of x values that span the range from the minimum to the maximum values of m for j in range( N): # loop from the first to the last values of the parameter if time_vary: # Some parameters are time-varying; others are not setattr(thisConsumer, param_name, [param_vec[j]]) else: setattr(thisConsumer, param_name, param_vec[j]) thisConsumer.update( ) # set up the preliminaries required to solve the problem thisConsumer.solve() # solve the problem y = thisConsumer.solution[0].cFunc( x ) # Get the values of the consumption function at the points in the vector of x points pylab.plot( x, y, label=str(round(param_vec[j], 3)) ) # plot it and generate a label indicating the rounded value of the parameter pylab.legend(loc='upper right') # put the legend in the upper right return pylab # return the figure
def test_ConsIndShockSolverBasic(self): LifecycleExample = IndShockConsumerType(**init_lifecycle) LifecycleExample.cycles = 1 LifecycleExample.solve() solver = ConsIndShockSolverBasic( LifecycleExample.solution[1], LifecycleExample.IncomeDstn[0], LifecycleExample.LivPrb[0], LifecycleExample.DiscFac, LifecycleExample.CRRA, LifecycleExample.Rfree, LifecycleExample.PermGroFac[0], LifecycleExample.BoroCnstArt, LifecycleExample.aXtraGrid, LifecycleExample.vFuncBool, LifecycleExample.CubicBool) solver.prepareToSolve() self.assertAlmostEqual(solver.DiscFacEff, 0.9503999999999999) self.assertAlmostEqual(solver.PermShkMinNext, 0.850430160026919) self.assertAlmostEqual(solver.cFuncNowCnst(4).tolist(), 4.0) self.assertAlmostEqual(solver.prepareToCalcEndOfPrdvP()[0], -0.2491750859108316) self.assertAlmostEqual(solver.prepareToCalcEndOfPrdvP()[-1], 19.74982491408914) EndOfPrdvP = solver.calcEndOfPrdvP() self.assertAlmostEqual(EndOfPrdvP[0], 6622.251864311334) self.assertAlmostEqual(EndOfPrdvP[-1], 0.026301061207747087) solution = solver.makeBasicSolution(EndOfPrdvP, solver.aNrmNow, solver.makeLinearcFunc) solver.addMPCandHumanWealth(solution) self.assertAlmostEqual(solution.cFunc(4).tolist(), 1.7391265696400773)
def test_cyclical(self): CyclicalExample = IndShockConsumerType(**CyclicalDict) CyclicalExample.cycles = 0 # Make this consumer type have an infinite horizon CyclicalExample.solve() self.assertAlmostEqual(CyclicalExample.solution[3].cFunc(3).tolist(), 1.5958390056965004)
def setUp(self): """ Prepare to compare the models by initializing and solving them """ # Set up and solve infinite type # Define a test dictionary that should have the same solution in the # perfect foresight and idiosyncratic shocks models. test_dictionary = deepcopy(init_idiosyncratic_shocks) test_dictionary["LivPrb"] = [1.0] test_dictionary["DiscFac"] = 0.955 test_dictionary["PermGroFac"] = [1.0] test_dictionary["PermShkStd"] = [0.0] test_dictionary["TranShkStd"] = [0.0] test_dictionary["UnempPrb"] = 0.0 test_dictionary["T_cycle"] = 1 test_dictionary["T_retire"] = 0 test_dictionary["BoroCnstArt"] = None InfiniteType = IndShockConsumerType(**test_dictionary) InfiniteType.cycles = 0 InfiniteType.update_income_process() InfiniteType.solve() InfiniteType.unpack("cFunc") # Make and solve a perfect foresight consumer type with the same parameters PerfectForesightType = PerfForesightConsumerType(**test_dictionary) PerfectForesightType.cycles = 0 PerfectForesightType.solve() PerfectForesightType.unpack("cFunc") self.InfiniteType = InfiniteType self.PerfectForesightType = PerfectForesightType
def makeConvergencePlot(DiscFac, CRRA, Rfree, PermShkStd): # Construct finite horizon agent with baseline parameters baseAgent_Fin = IndShockConsumerType(verbose=0, **base_params) baseAgent_Fin.DiscFac = DiscFac baseAgent_Fin.CRRA = CRRA baseAgent_Fin.Rfree = Rfree baseAgent_Fin.PermShkStd = [PermShkStd] baseAgent_Fin.cycles = 100 baseAgent_Fin.updateIncomeProcess() baseAgent_Fin.solve() baseAgent_Fin.unpack('cFunc') # figure limits mMax = 6 # 11 mMin = 0 cMin = 0 cMax = 4 # 7 mPlotMin = 0 mLocCLabels = 5.6 # 9.6 # Defines horizontal limit of figure mPlotTop = 3.5 # 6.5 # Defines maximum m value where functions are plotted mPts = 1000 # Number of points at which functions are evaluated plt.figure(figsize=(12, 8)) plt.ylim([cMin, cMax]) plt.xlim([mMin, mMax]) mBelwLabels = np.linspace(mPlotMin, mLocCLabels - 0.1, mPts) # Range of m below loc of labels m_FullRange = np.linspace(mPlotMin, mPlotTop, mPts) # Full plot range c_Tm0 = m_FullRange # c_Tm0 defines the last period consumption rule (c=m) c_Tm1 = baseAgent_Fin.cFunc[-2]( mBelwLabels ) # c_Tm1 defines the second-to-last period consumption rule c_Tm5 = baseAgent_Fin.cFunc[-6]( mBelwLabels) # c_Tm5 defines the T-5 period consumption rule c_Tm10 = baseAgent_Fin.cFunc[-11]( mBelwLabels) # c_Tm10 defines the T-10 period consumption rule c_Limt = baseAgent_Fin.cFunc[0]( mBelwLabels ) # c_Limt defines limiting infinite-horizon consumption rule plt.plot(mBelwLabels, c_Limt, label="$c(m)$") plt.plot(mBelwLabels, c_Tm1, label="$c_{T-1}(m)$") plt.plot(mBelwLabels, c_Tm5, label="$c_{T-5}(m)$") plt.plot(mBelwLabels, c_Tm10, label="$c_{T-10}(m)$") plt.plot(m_FullRange, c_Tm0, label="$c_{T}(m) = 45$ degree line") plt.legend(fontsize='x-large') plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) plt.show() return None
def test_ConsIndShockSolverBasic(self): LifecycleExample = IndShockConsumerType(**init_lifecycle) LifecycleExample.cycles = 1 LifecycleExample.solve() # test the solution_terminal self.assertAlmostEqual(LifecycleExample.solution[-1].cFunc(2).tolist(), 2) self.assertAlmostEqual(LifecycleExample.solution[9].cFunc(1), 0.79429538) self.assertAlmostEqual(LifecycleExample.solution[8].cFunc(1), 0.79391692) self.assertAlmostEqual(LifecycleExample.solution[7].cFunc(1), 0.79253095) self.assertAlmostEqual(LifecycleExample.solution[0].cFunc(1).tolist(), 0.7506184692092213) self.assertAlmostEqual(LifecycleExample.solution[1].cFunc(1).tolist(), 0.7586358637239385) self.assertAlmostEqual(LifecycleExample.solution[2].cFunc(1).tolist(), 0.7681247572911291) solver = ConsIndShockSolverBasic( LifecycleExample.solution[1], LifecycleExample.IncShkDstn[0], LifecycleExample.LivPrb[0], LifecycleExample.DiscFac, LifecycleExample.CRRA, LifecycleExample.Rfree, LifecycleExample.PermGroFac[0], LifecycleExample.BoroCnstArt, LifecycleExample.aXtraGrid, LifecycleExample.vFuncBool, LifecycleExample.CubicBool, ) solver.prepare_to_solve() self.assertAlmostEqual(solver.DiscFacEff, 0.9586233599999999) self.assertAlmostEqual(solver.PermShkMinNext, 0.6554858756904397) self.assertAlmostEqual(solver.cFuncNowCnst(4).tolist(), 4.0) self.assertAlmostEqual(solver.prepare_to_calc_EndOfPrdvP()[0], -0.19792871012285213) self.assertAlmostEqual(solver.prepare_to_calc_EndOfPrdvP()[-1], 19.801071289877118) EndOfPrdvP = solver.calc_EndOfPrdvP() self.assertAlmostEqual(EndOfPrdvP[0], 6657.839372100613) self.assertAlmostEqual(EndOfPrdvP[-1], 0.2606075215645896) solution = solver.make_basic_solution(EndOfPrdvP, solver.aNrmNow, solver.make_linear_cFunc) solver.add_MPC_and_human_wealth(solution) self.assertAlmostEqual(solution.cFunc(4).tolist(), 1.0028005137373956)
def test_lifecyle(self): LifecycleExample = IndShockConsumerType(**LifecycleDict) LifecycleExample.cycles = 1 LifecycleExample.solve() self.assertEquals(len(LifecycleExample.solution), 11) mMin = np.min([LifecycleExample.solution[t].mNrmMin for t in range(LifecycleExample.T_cycle)]) self.assertAlmostEqual(LifecycleExample.solution[5].cFunc(3).tolist(), 2.129983771775666)
def create_agents(CRRA, TranShkStd): # Copy base dictionaries un_dict = copy(IdiosyncDict) pf_dict = copy(PFDict) # Update CRRA un_dict['CRRA'] = CRRA pf_dict['CRRA'] = CRRA # Update transitory shock sd un_dict["TranShkStd"] = [TranShkStd] IndShockConsumer = IndShockConsumerType(**un_dict) IndShockConsumer.cycles = 2 # Make this type have a two-period horizon IndShockConsumer.solve() PFConsumer = IndShockConsumerType(**pf_dict) PFConsumer.cycles = 2 PFConsumer.solve() return ((IndShockConsumer, PFConsumer))
def test_cyclical(self): CyclicalExample = IndShockConsumerType(**CyclicalDict) CyclicalExample.cycles = 0 # Make this consumer type have an infinite horizon CyclicalExample.solve() self.assertAlmostEqual(CyclicalExample.solution[3].cFunc(3).tolist(), 1.5958390056965004) CyclicalExample.initialize_sim() CyclicalExample.simulate() self.assertAlmostEqual(CyclicalExample.state_now['aLvl'][1], 0.41839957)
def test_infinite_horizon(self): IndShockExample = IndShockConsumerType(**IdiosyncDict) IndShockExample.cycles = 0 # Make this type have an infinite horizon IndShockExample.solve() self.assertAlmostEqual(IndShockExample.solution[0].mNrmSS, 1.5488165705077026) self.assertAlmostEqual(IndShockExample.solution[0].cFunc.functions[0].x_list[0], -0.25017509) IndShockExample.track_vars = ['aNrmNow','mNrmNow','cNrmNow','pLvlNow'] IndShockExample.initializeSim() IndShockExample.simulate() self.assertAlmostEqual(IndShockExample.mNrmNow_hist[0][0], 1.0170176090252379)
def test_baseEx(self): baseEx = IndShockConsumerType(**self.base_params) baseEx.cycles = 100 # Make this type have a finite horizon (Set T = 100) baseEx.solve() baseEx.unpack("cFunc") m = np.linspace(0, 9.5, 1000) c_m = baseEx.cFunc[0](m) c_t1 = baseEx.cFunc[-2](m) c_t5 = baseEx.cFunc[-6](m) c_t10 = baseEx.cFunc[-11](m) self.assertAlmostEqual(c_m[500], 1.4008090582203356) self.assertAlmostEqual(c_t1[500], 2.9227437159255216) self.assertAlmostEqual(c_t5[500], 1.7350607327187664) self.assertAlmostEqual(c_t10[500], 1.4991390649979213) self.assertAlmostEqual(c_t10[600], 1.6101476268581576) self.assertAlmostEqual(c_t10[700], 1.7196531041366991)
def setUp(self): """ Prepare to compare the models by initializing and solving them """ # Set up and solve infinite type import HARK.ConsumptionSaving.ConsumerParameters as Params # Define a test dictionary that should have the same solution in the # perfect foresight and idiosyncratic shocks models. test_dictionary = deepcopy(Params.init_idiosyncratic_shocks) test_dictionary['LivPrb'] = [1.] test_dictionary['DiscFac'] = 0.955 test_dictionary['PermGroFac'] = [1.] test_dictionary['PermShkStd'] = [0.] test_dictionary['TranShkStd'] = [0.] test_dictionary['UnempPrb'] = 0. test_dictionary['T_cycle'] = 1 test_dictionary['T_retire'] = 0 test_dictionary['BoroCnstArt'] = None InfiniteType = IndShockConsumerType(**test_dictionary) InfiniteType.cycles = 0 InfiniteType.updateIncomeProcess() InfiniteType.solve() InfiniteType.timeFwd() InfiniteType.unpackcFunc() # Make and solve a perfect foresight consumer type with the same parameters PerfectForesightType = PerfForesightConsumerType(**test_dictionary) PerfectForesightType.cycles = 0 PerfectForesightType.solve() PerfectForesightType.unpackcFunc() PerfectForesightType.timeFwd() self.InfiniteType = InfiniteType self.PerfectForesightType = PerfectForesightType
# Under the given parameter values, [the paper's first figure](https://econ-ark.github.io/BufferStockTheory/#Convergence-of-the-Consumption-Rules) depicts the successive consumption rules that apply in the last period of life $(c_{T}(m))$, the second-to-last period, and earlier periods $(c_{T-n})$. The consumption function to which these converge is $c(m)$: # # $$ # c(m) = \lim_{n \uparrow \infty} c_{T-n}(m) \notag # $$ # # %% # Create a buffer stock consumer instance by invoking the IndShockConsumerType class # %% {"jupyter": {"source_hidden": true}, "tags": []} # with the built-in parameter dictionary "base_params" # Construct finite horizon agent with baseline parameters baseAgent_Fin = IndShockConsumerType(**base_params) baseAgent_Fin.cycles = 100 # Set finite horizon (T = 100) baseAgent_Fin.solve(verbose=0) # Solve the model baseAgent_Fin.unpack('cFunc') # Make the consumption function easily accessible # %% # Plot the different consumption rules for the different periods # %% {"jupyter": {"source_hidden": true, "outputs_hidden": true}, "tags": []} mPlotMin = 0 mLocCLabels = 9.6 # Defines horizontal limit of figure mPlotTop = 6.5 # Defines maximum m value where functions are plotted mPts = 1000 # Number of points at which functions are evaluated
# Optionally, the user can specify the period when the individual retires and escapes essentially all income risk as $\texttt{T_retire}$; this can be turned off by setting the parameter to $0$. In retirement, all permanent income shocks are turned off, and the only transitory shock is an "unemployment" shock, likely with small probability; this prevents the retired problem from degenerating into a perfect foresight model. # # The grid of assets above minimum $\texttt{aXtraGrid}$ is specified by its minimum and maximum level, the number of gridpoints, and the extent of exponential nesting. The greater the (integer) value of $\texttt{aXtraNestFac}$, the more dense the gridpoints will be at the bottom of the grid (and more sparse near the top); setting $\texttt{aXtraNestFac}$ to $0$ will generate an evenly spaced grid of $a_t$. # # The artificial borrowing constraint $\texttt{BoroCnstArt}$ can be set to $\texttt{None}$ to turn it off. # # It is not necessary to compute the value function in this model, and it is not computationally free to do so. You can choose whether the value function should be calculated and returned as part of the solution of the model with $\texttt{vFuncBool}$. The consumption function will be constructed as a piecewise linear interpolation when $\texttt{CubicBool}$ is \texttt{False}, and will be a piecewise cubic spline interpolator if $\texttt{True}$. # %% [markdown] {"heading_collapsed": true} # ## Solving and examining the solution of the idiosyncratic income shocks model # # The cell below creates an infinite horizon instance of $\texttt{IndShockConsumerType}$ and solves its model by calling its $\texttt{solve}$ method. # %% {"hidden": true} IndShockExample = IndShockConsumerType(**IdiosyncDict) IndShockExample.cycles = 0 # Make this type have an infinite horizon IndShockExample.solve() # %% [markdown] {"hidden": true} # After solving the model, we can examine an element of this type's $\texttt{solution}$: # %% {"hidden": true} print(vars(IndShockExample.solution[0])) # %% [markdown] {"hidden": true} # The single-period solution to an idiosyncratic shocks consumer's problem has all of the same attributes as in the perfect foresight model, with a couple additions. The solution can include the marginal marginal value of market resources function $\texttt{vPPfunc}$, but this is only constructed if $\texttt{CubicBool}$ is $\texttt{True}$, so that the MPC can be accurately computed; when it is $\texttt{False}$, then $\texttt{vPPfunc}$ merely returns $\texttt{NaN}$ everywhere. # # The $\texttt{solveConsIndShock}$ function calculates steady state market resources and stores it in the attribute $\texttt{mNrmSS}$. This represents the steady state level of $m_t$ if *this period* were to occur indefinitely, but with income shocks turned off. This is relevant in a "one period infinite horizon" model like we've specified here, but is less useful in a lifecycle model. # # Let's take a look at the consumption function by plotting it, along with its derivative (the MPC):
from HARK.ConsumptionSaving.ConsIndShockModel import \ IndShockConsumerType, ConsIndShockSolverBasic import HARK.ConsumptionSaving.ConsumerParameters as Params LifecycleExample = IndShockConsumerType(**Params.init_lifecycle) LifecycleExample.cycles = 1 LifecycleExample.solve() # test the solution_terminal assert (LifecycleExample.solution[10].cFunc(2).tolist() == 2) print(LifecycleExample.solution[9].cFunc(1)) assert (LifecycleExample.solution[9].cFunc(1) == 0.97769632) self.assertAlmostEqual(LifecycleExample.solution[8].cFunc(1), 0.96624445) self.assertAlmostEqual(LifecycleExample.solution[7].cFunc(1), 0.95691449) self.assertAlmostEqual(LifecycleExample.solution[0].cFunc(1).tolist(), 0.87362789) self.assertAlmostEqual(LifecycleExample.solution[1].cFunc(1).tolist(), 0.9081621) self.assertAlmostEqual(LifecycleExample.solution[2].cFunc(1).tolist(), 0.9563899)
## There is one more parameter value we need to change. This one is more complicated than the rest. ## We could solve the problem for a consumer with an infinite horizon of periods that (ex-ante) ## are all identical. We could also solve the problem for a consumer with a fininite lifecycle, ## or for a consumer who faces an infinite horizon of periods that cycle (e.g., a ski instructor ## facing an infinite series of winters, with lots of income, and summers, with very little income.) ## The way to differentiate is through the "cycles" attribute, which indicates how often the ## sequence of periods needs to be solved. The default value is 1, for a consumer with a finite ## lifecycle that is only experienced 1 time. A consumer who lived that life twice in a row, and ## then died, would have cycles = 2. But neither is what we want. Here, we need to set cycles = 0, ## to tell HARK that we are solving the model for an infinite horizon consumer. ## Note that another complication with the cycles attribute is that it does not come from ## Params.init_idiosyncratic_shocks. Instead it is a keyword argument to the __init__() method of ## IndShockConsumerType. BaselineExample.cycles = 0 # + {"cell_marker": "\"\"\"", "cell_type": "markdown"} # Now, create another consumer to compare the BaselineExample to. # + {} # The easiest way to begin creating the comparison example is to just copy the baseline example. # We can change the parameters we want to change later. from copy import deepcopy XtraCreditExample = deepcopy(BaselineExample) # Now, change whatever parameters we want. # Here, we want to see what happens if we give the consumer access to more credit. # Remember, parameters are stored as attributes of the consumer they are used for. # So, to give the consumer more credit, we just need to relax their borrowing constraint a tiny bit. # Declare how much we want to increase credit by
"AgentCount": 4000000, # Number of agents of this type "T_sim": 2000, # Number of periods to simulate "aNrmInitMean": np.log(1.25) - (.5**2) / 2, # Mean of log initial assets "aNrmInitStd": .5, # Standard deviation of log initial assets "pLvlInitMean": 0, # Mean of log initial permanent income "pLvlInitStd": 0, # Standard deviation of log initial permanent income "PermGroFacAgg": 1.0, # Aggregate permanent income growth factor "T_age": None, # Age after which simulated agents are automatically killed } # %% [markdown] # # Solve # %% collapsed=true jupyter={"outputs_hidden": true, "source_hidden": true} fast = IndShockConsumerType(**Harmenberg_Dict, verbose=1) fast.cycles = 0 fast.Rfree = 1.2**.25 fast.PermGroFac = [1.02] fast.tolerance = fast.tolerance / 100 fast.track_vars = ['cNrm', 'pLvl'] fast.solve(verbose=False) # %% [markdown] # # Calculate Patience Conditions # %% collapsed=true jupyter={"outputs_hidden": true} fast.check_conditions(verbose=True) # %% jupyter={"source_hidden": true} # Simulate a population
# #### Add MPC and human wealth `addMPCandHumanWealth` # Add values calculated in `defBoroCnst` now that we have a solution object to put them in. # # #### Special to the non-Basic solver # We are now done, but in the `ConsIndShockSolver` (non-`Basic`!) solver there are a few extra steps. We add steady state m, and depending on the values of `vFuncBool` and `CubicBool` we also add the value function and the marginal marginal value function. # %% [markdown] # # Let's try it in action! # First, we define a standard lifecycle model, solve it and then # %% from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType, init_lifecycle import numpy as np import matplotlib.pyplot as plt LifecycleExample = IndShockConsumerType(init_lifecycle) LifecycleExample.cycles = 1 # Make this consumer live a sequence of periods exactly once LifecycleExample.solve() # %% [markdown] # Let's have a look at the solution in time period second period. We should then be able to # %% from HARK.utilities import plotFuncs plotFuncs([LifecycleExample.solution[0].cFunc],LifecycleExample.solution[0].mNrmMin,10) # %% [markdown] # Let us then create a solver for the first period. # %% from HARK.ConsumptionSaving.ConsIndShockModel import ConsIndShockSolverBasic solver = ConsIndShockSolverBasic(LifecycleExample.solution[1],
# ## Convergence of the Consumption Rules # # Under the given parameter values, [the paper's first figure](https://econ-ark.github.io/BufferStockTheory/#Convergence-of-the-Consumption-Rules) depicts the successive consumption rules that apply in the last period of life $(c_{T}(m))$, the second-to-last period, and earlier periods $(c_{T-n})$. The consumption function to which these converge is $c(m)$: # # $$ # c(m) = \lim_{n \uparrow \infty} c_{T-n}(m) \notag # $$ # # %% # Create a buffer stock consumer instance by invoking the IndShockConsumerType class # with the built-in parameter dictionary "base_params" # Construct finite horizon agent with baseline parameters baseAgent_Fin = IndShockConsumerType(**base_params) baseAgent_Fin.cycles = 100 # Set finite horizon (T = 100) baseAgent_Fin.solve() # Solve the model baseAgent_Fin.unpack('cFunc') # Make the consumption function easily accessible # %% # Plot the different consumption rules for the different periods mPlotMin = 0 mLocCLabels = 9.6 # Defines horizontal limit of figure mPlotTop = 6.5 # Defines maximum m value where functions are plotted mPts = 1000 # Number of points at which functions are evaluated mBelwLabels = np.linspace(mPlotMin,mLocCLabels-0.1,mPts) # Range of m below loc of labels m_FullRange = np.linspace(mPlotMin,mPlotTop,mPts) # Full plot range
base_params['T_cycle'] = 1 # No 'seasonal' cycles base_params['BoroCnstArt'] = None # No artificial borrowing constraint # %% [markdown] {"hidden": true} # ## Convergence of the Consumption Rules # # Under the given parameter values, [the paper's first figure](http://econ.jhu.edu/people/ccarroll/papers/BufferStockTheory/#Convergence-of-the-Consumption-Rules) depicts the successive consumption rules that apply in the last period of life $(c_{T}(m))$, the second-to-last period, and earlier periods $(c_{T-n})$. $c(m)$ is the consumption function to which these converge as # # \[ # c(m) = \lim_{n \uparrow \infty} c_{T-n}(m) # \] # # %% {"hidden": true} # Create a buffer stock consumer instance by passing the dictionary to the class. baseEx = IndShockConsumerType(**base_params) baseEx.cycles = 100 # Make this type have a finite horizon (Set T = 100) baseEx.solve() # Solve the model baseEx.unpackcFunc() # Make the consumption function easily accessible # %% {"hidden": true} # Plot the different periods' consumption rules. m1 = np.linspace(0,9.5,1000) # Set the plot range of m m2 = np.linspace(0,6.5,500) c_m = baseEx.cFunc[0](m1) # c_m can be used to define the limiting infinite-horizon consumption rule here c_t1 = baseEx.cFunc[-2](m1) # c_t1 defines the second-to-last period consumption rule c_t5 = baseEx.cFunc[-6](m1) # c_t5 defines the T-5 period consumption rule c_t10 = baseEx.cFunc[-11](m1) # c_t10 defines the T-10 period consumption rule c_t0 = m2 # c_t0 defines the last period consumption rule
1, # Standard deviation of log initial assets (only for simulation),not used here 'pLvlInitMean': 0, # Mean of log initial permanent income (only matters for simulation), not used here 'pLvlInitStd': 0, # Standard deviation of log initial permanent income (only matters for simulation), not used here 'PermGroFacAgg': 1, # Aggregate permanent income growth factor (only matters for simulation), not used here 'T_age': None, # Age after which simulated agents are automatically killed 'T_cycle': 1 # Number of periods in the cycle for this agent type } # In[ ]: # Create the baseline instance by passing the dictionary to the class. BaselineExample = IndShockConsumerType(**baseline_bufferstock_dictionary) BaselineExample.cycles = 100 # Make this type have an finite horizon (Set T = 100) start_time = clock() BaselineExample.solve() end_time = clock() print('Solving a baseline buffer stock saving model (100 periods) took ' + mystr(end_time - start_time) + ' seconds.') BaselineExample.unpackcFunc() BaselineExample.timeFwd() # In[ ]: # Now we start plotting the different periods' consumption rules. m1 = np.linspace(0, 9.5, 1000) # Set the plot range of m m2 = np.linspace(0, 6.5, 500)
# Plot the perfect foresight consumption function print("Perfect foresight consumption function:") mMin = PFexample.solution[0].mNrmMin plotFuncs(PFexample.cFunc[0], mMin, mMin + 10) # %% if do_simulation: PFexample.T_sim = 120 # Set number of simulation periods PFexample.track_vars = ["mNrmNow"] PFexample.initializeSim() PFexample.simulate() # %% # Make and solve an example consumer with idiosyncratic income shocks IndShockExample = IndShockConsumerType() IndShockExample.cycles = 0 # Make this type have an infinite horizon # %% start_time = time() IndShockExample.solve() end_time = time() print("Solving a consumer with idiosyncratic shocks took " + mystr(end_time - start_time) + " seconds.") IndShockExample.unpackcFunc() IndShockExample.timeFwd() # %% # Plot the consumption function and MPC for the infinite horizon consumer print("Concave consumption function:") plotFuncs(IndShockExample.cFunc[0], IndShockExample.solution[0].mNrmMin, 5) print("Marginal consumption function:")
def make_cons_func(in_BoroCnstArt, in_TranShkStd): """ This figure illustrates how the effect of risk is greater if there already exists a constraint. Initialize four types: unconstrained perfect foresight, unconstrained with risk, constrained perfect foresight, and constrained with risk. """ WwCR_unconstr = IndShockConsumerType(**init_lifecycle) WwCR_unconstr.delFromTimeInv("BoroCnstArt") WwCR_unconstr.addToTimeVary("BoroCnstArt") WwCR_unconstr.solve() WwCR_unconstr.unpack("cFunc") init_lifecycle_risk2["TranShkStd"] = [0, in_TranShkStd, 0, 0, 0, 0, 0, 0, 0, 0, 0] WwCR_risk = IndShockConsumerType(**init_lifecycle_risk2) WwCR_risk.delFromTimeInv("BoroCnstArt") WwCR_risk.addToTimeVary("BoroCnstArt") WwCR_risk.solve() WwCR_risk.unpack("cFunc") WwCR_constr = IndShockConsumerType(**init_lifecycle) WwCR_constr.cycles = 1 # Make this consumer live a sequence of periods exactly once WwCR_constr.delFromTimeInv("BoroCnstArt") WwCR_constr.addToTimeVary("BoroCnstArt") WwCR_constr.BoroCnstArt = [ None, None, in_BoroCnstArt, None, None, None, None, None, None, None, ] WwCR_constr.solve() WwCR_constr.unpack("cFunc") WwCR_constr_risk = IndShockConsumerType(**init_lifecycle_risk2) WwCR_constr_risk.delFromTimeInv("BoroCnstArt") WwCR_constr_risk.addToTimeVary("BoroCnstArt") WwCR_constr_risk.BoroCnstArt = [ None, None, in_BoroCnstArt, None, None, None, None, None, None, None, ] WwCR_constr_risk.solve() WwCR_constr_risk.unpack("cFunc") x = np.linspace(-8, -4, 1000, endpoint=True) y = WwCR_unconstr.cFunc[1](x) y2 = WwCR_risk.cFunc[1](x) y3 = WwCR_constr.cFunc[1](x) y4 = WwCR_constr_risk.cFunc[1](x) where_close = np.isclose(y, y3, atol=1e-05) where_close_risk = np.isclose(y2, y4, atol=1e-05) x0 = x[where_close][0] x1 = x[where_close_risk][0] y0 = y[where_close][0] y1 = y2[where_close_risk][0] # Display the figure # print('Figure 3: Consumption Functions With and Without a Constraint and a Risk') f = plt.figure() plt.plot(x, y, color="black", linewidth=3, label="${c}_{t,0}$") plt.plot( x, y2, color="black", linestyle="--", linewidth=3, label=r"$\tilde{c}_{t,0}$" ) plt.plot(x, y3, color="red", label="${c}_{t,1}$") plt.plot(x, y4, color="red", linestyle="--", label=r"$\tilde{c}_{t,1}$") plt.xlim(left=-8, right=-4.5) plt.ylim(0, 0.30) plt.text(-8.15, 0.305, "$c$", fontsize=14) plt.text(-4.5, -0.02, "$w$", fontsize=14) # plt.plot([-6.15,-6.15],[0,0.05],color="black",linestyle=":") plt.plot([x0, x0], [0, y0], color="black", linestyle=":") plt.plot([x1, x1], [0, y1], color="black", linestyle=":") # plt.text(-6.2,-0.02,r"$\underline{w}_{t,1}$",fontsize=14) plt.text(x0, -0.02, r"${w}_{t,1}$", fontsize=14) plt.text(x1, -0.02, r"$\bar{w}_{t,1}$", fontsize=14) plt.tick_params( labelbottom=False, labelleft=False, left="off", right="off", bottom="off", top="off", ) plt.legend() plt.show() return None
# %% [markdown] # We now configure and solve a buffer-stock agent with a default parametrization. # %% Create and simulate agent tags=[] # Create and solve agent popn = IndShockConsumerType(**init_idiosyncratic_shocks) # Modify default parameters popn.T_sim = max(sample_periods_lvl) + 1 popn.AgentCount = max_agents popn.track_vars = ['mNrm', 'cNrm', 'pLvl'] popn.LivPrb = [1.0] popn.cycles = 0 # Solve (but do not yet simulate) popn.solve() # %% [markdown] # Under the basic simulation strategy, we have to de-normalize market resources and consumption multiplying them by permanent income. Only then we construct our statistics of interest. # # Note that our time-sampling strategy requires that, after enough time has passed, the economy settles on a stable distribution of its agents across states. How can we know this will be the case? [Szeidl (2013)](http://www.personal.ceu.hu/staff/Adam_Szeidl/papers/invariant.pdf) and [Harmenberg (2021)](https://www.sciencedirect.com/science/article/pii/S0165188921001202?via%3Dihub) provide conditions that can give us some reassurance.$\newcommand{\Rfree}{\mathsf{R}}$ # # 1. [Szeidl (2013)](http://www.personal.ceu.hu/staff/Adam_Szeidl/papers/invariant.pdf) shows that if $$\log \left[\frac{(\Rfree\beta)^{1/\rho}}{\PermGroFac} # \right] < \Ex[\log \PermShk],$$ then there is a stable invariant distribution of normalized market resources $\mNrm$. # 2. [Harmenberg (2021)](https://www.sciencedirect.com/science/article/pii/S0165188921001202?via%3Dihub) repurposes the Szeidl proof to argue that if the same condition is satisfied when the expectation is taken with respect to the permanent-income-neutral measure ($\pShkNeutDstn$), then there is a stable invariant permanent-income-weighted distribution ($\mWgtDstnMarg$) # # We now check both conditions with our parametrization.
# Parameters only used in simulation "AgentCount": 1, # Number of agents of this type "T_sim": 5000, # Number of periods to simulate "aNrmInitMean": -6.0, # Mean of log initial assets "aNrmInitStd": 1.0, # Standard deviation of log initial assets "pLvlInitMean": 0.0, # Mean of log initial permanent income "pLvlInitStd": 0.0, # Standard deviation of log initial permanent income "PermGroFacAgg": 1.0, # Aggregate permanent income growth factor "T_age": None, # Age after which simulated agents are automatically killed } # %% slideshow={"slide_type": "slide"} from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType IndShockSimExample = IndShockConsumerType(**IdiosyncDict) IndShockSimExample.cycles = 0 # Make this type have an infinite horizon IndShockSimExample.solve() plot_funcs(IndShockSimExample.solution[0].cFunc, IndShockSimExample.solution[0].mNrmMin, 5) # simulation IndShockSimExample.track_vars = ['aNrm', 'mNrm', 'cNrm', 'pLvl'] IndShockSimExample.initialize_sim() IndShockSimExample.simulate() # %% slideshow={"slide_type": "slide"} # distribution of cash on hand density = np.histogram(IndShockSimExample.history['mNrm'], density=True) #print(density) n, bins, patches = plt.hist(IndShockSimExample.history['mNrm'], density=True)
WwCR_unconstr = IndShockConsumerType(**init_lifecycle) WwCR_unconstr.delFromTimeInv('BoroCnstArt') WwCR_unconstr.addToTimeVary('BoroCnstArt') WwCR_unconstr.solve() WwCR_unconstr.unpackcFunc() WwCR_unconstr.timeFwd() WwCR_risk = IndShockConsumerType(**init_lifecycle_risk2) WwCR_risk.delFromTimeInv('BoroCnstArt') WwCR_risk.addToTimeVary('BoroCnstArt') WwCR_risk.solve() WwCR_risk.unpackcFunc() WwCR_risk.timeFwd() WwCR_constr = IndShockConsumerType(**init_lifecycle) WwCR_constr.cycles = 1 # Make this consumer live a sequence of periods exactly once WwCR_constr.delFromTimeInv('BoroCnstArt') WwCR_constr.addToTimeVary('BoroCnstArt') WwCR_constr( BoroCnstArt=[None, None, -6, None, None, None, None, None, None, None]) WwCR_constr.solve() WwCR_constr.unpackcFunc() WwCR_constr.timeFwd() WwCR_constr_risk = IndShockConsumerType(**init_lifecycle_risk2) WwCR_constr_risk.delFromTimeInv('BoroCnstArt') WwCR_constr_risk.addToTimeVary('BoroCnstArt') WwCR_constr_risk( BoroCnstArt=[None, None, -6, None, None, None, None, None, None, None]) WwCR_constr_risk.solve() WwCR_constr_risk.unpackcFunc()
# For transitory shocks, to illustrate the problem, we want two possible # values: a good and a bad one. This is most easily achieved by setting # a large standard deviation (3) and telling HARK to approximate the # distribution using only two points. IdiosyncDict["TranShkStd"] = [3] IdiosyncDict["TranShkCount"] = 2 # Create a copy with income uncertainty turned off, for comparison PFDict = copy(IdiosyncDict) PFDict["TranShkStd"] = [0] PFDict["TranShkCount"] = 1 # %% {"code_folding": []} # Create and solve problems for the two consumers IndShockConsumer = IndShockConsumerType(**IdiosyncDict) IndShockConsumer.cycles = 2 # Make this type have a two-period horizon IndShockConsumer.solve() PFConsumer = IndShockConsumerType(**PFDict) PFConsumer.cycles = 2 PFConsumer.solve() # %% [markdown] # ## Figure 1: Marginal Utility of Assets and Consumption # %% [markdown] # Consider an agent facing the following dynamic problem expressed in recursive form: # # \begin{equation} # \begin{split} # v_t(m_t) =& \max_{c_t} u(c_t) + \beta \mathbb{E}_t[v_{t+1}(R a_t + \tilde{y}_{t+1})] \\
# Optionally, the user can specify the period when the individual retires and escapes essentially all income risk as $\texttt{T_retire}$; this can be turned off by setting the parameter to $0$. In retirement, all permanent income shocks are turned off, and the only transitory shock is an "unemployment" shock, likely with small probability; this prevents the retired problem from degenerating into a perfect foresight model. # # The grid of assets above minimum $\texttt{aXtraGrid}$ is specified by its minimum and maximum level, the number of gridpoints, and the extent of exponential nesting. The greater the (integer) value of $\texttt{aXtraNestFac}$, the more dense the gridpoints will be at the bottom of the grid (and more sparse near the top); setting $\texttt{aXtraNestFac}$ to $0$ will generate an evenly spaced grid of $a_t$. # # The artificial borrowing constraint $\texttt{BoroCnstArt}$ can be set to $\texttt{None}$ to turn it off. # # It is not necessary to compute the value function in this model, and it is not computationally free to do so. You can choose whether the value function should be calculated and returned as part of the solution of the model with $\texttt{vFuncBool}$. The consumption function will be constructed as a piecewise linear interpolation when $\texttt{CubicBool}$ is \texttt{False}, and will be a piecewise cubic spline interpolator if $\texttt{True}$. # %% [markdown] # ## Solving and examining the solution of the idiosyncratic income shocks model # # The cell below creates an infinite horizon instance of $\texttt{IndShockConsumerType}$ and solves its model by calling its $\texttt{solve}$ method. # %% IndShockExample = IndShockConsumerType(**IdiosyncDict) IndShockExample.cycles = 0 # Make this type have an infinite horizon IndShockExample.solve() # %% [markdown] # After solving the model, we can examine an element of this type's $\texttt{solution}$: # %% print(vars(IndShockExample.solution[0])) # %% [markdown] # The single-period solution to an idiosyncratic shocks consumer's problem has all of the same attributes as in the perfect foresight model, with a couple additions. The solution can include the marginal marginal value of market resources function $\texttt{vPPfunc}$, but this is only constructed if $\texttt{CubicBool}$ is $\texttt{True}$, so that the MPC can be accurately computed; when it is $\texttt{False}$, then $\texttt{vPPfunc}$ merely returns $\texttt{NaN}$ everywhere. # # The $\texttt{solveConsIndShock}$ function calculates steady state market resources and stores it in the attribute $\texttt{mNrmSS}$. This represents the steady state level of $m_t$ if *this period* were to occur indefinitely, but with income shocks turned off. This is relevant in a "one period infinite horizon" model like we've specified here, but is less useful in a lifecycle model. # # Let's take a look at the consumption function by plotting it, along with its derivative (the MPC):