def main_test(self): Markov_vFuncBool_example = MarkovConsumerType(**Markov_Dict) TranShkDstn_e = MeanOneLogNormal( Markov_vFuncBool_example.TranShkStd[0], 123).approx(Markov_vFuncBool_example.TranShkCount) TranShkDstn_u = DiscreteDistribution(np.ones(1), np.ones(1) * .2) PermShkDstn = MeanOneLogNormal( Markov_vFuncBool_example.PermShkStd[0], 123).approx(Markov_vFuncBool_example.PermShkCount) #employed Income shock distribution employed_IncShkDstn = combine_indep_dstns(PermShkDstn, TranShkDstn_e) #unemployed Income shock distribution unemployed_IncShkDstn = combine_indep_dstns(PermShkDstn, TranShkDstn_u) # Specify list of IncShkDstns for each state Markov_vFuncBool_example.IncShkDstn = [[ employed_IncShkDstn, unemployed_IncShkDstn ]] #solve the consumer's problem Markov_vFuncBool_example.solve() self.assertAlmostEqual( Markov_vFuncBool_example.solution[0].vFunc[1](0.4), -4.127935542867632)
def setUp(self): # Set up and solve TBS base_primitives = { "UnempPrb": 0.015, "DiscFac": 0.9, "Rfree": 1.1, "PermGroFac": 1.05, "CRRA": 0.95, } TBSType = TractableConsumerType(**base_primitives) TBSType.solve() # Set up and solve Markov MrkvArray = [ np.array([ [ 1.0 - base_primitives["UnempPrb"], base_primitives["UnempPrb"] ], [0.0, 1.0], ]) ] Markov_primitives = { "CRRA": base_primitives["CRRA"], "Rfree": np.array(2 * [base_primitives["Rfree"]]), "PermGroFac": [ np.array(2 * [ base_primitives["PermGroFac"] / (1.0 - base_primitives["UnempPrb"]) ]) ], "BoroCnstArt": None, "PermShkStd": [0.0], "PermShkCount": 1, "TranShkStd": [0.0], "TranShkCount": 1, "T_total": 1, "UnempPrb": 0.0, "UnempPrbRet": 0.0, "T_retire": 0, "IncUnemp": 0.0, "IncUnempRet": 0.0, "aXtraMin": 0.001, "aXtraMax": TBSType.mUpperBnd, "aXtraCount": 48, "aXtraExtra": [None], "aXtraNestFac": 3, "LivPrb": [ np.array([1.0, 1.0]), ], "DiscFac": base_primitives["DiscFac"], "Nagents": 1, "psi_seed": 0, "xi_seed": 0, "unemp_seed": 0, "tax_rate": 0.0, "vFuncBool": False, "CubicBool": True, "MrkvArray": MrkvArray, "T_cycle": 1, } MarkovType = MarkovConsumerType(**Markov_primitives) MarkovType.cycles = 0 employed_income_dist = DiscreteDistribution(np.ones(1), np.array([[1.0], [1.0]])) unemployed_income_dist = DiscreteDistribution(np.ones(1), np.array([[1.0], [0.0]])) MarkovType.IncShkDstn = [[ employed_income_dist, unemployed_income_dist ]] MarkovType.solve() MarkovType.unpack("cFunc") self.TBSType = TBSType self.MarkovType = MarkovType
def setUp(self): # Set up and solve TBS base_primitives = {'UnempPrb': .015, 'DiscFac': 0.9, 'Rfree': 1.1, 'PermGroFac': 1.05, 'CRRA': .95} TBSType = TractableConsumerType(**base_primitives) TBSType.solve() # Set up and solve Markov MrkvArray = [np.array([[1.0-base_primitives['UnempPrb'], base_primitives['UnempPrb']],[0.0, 1.0]])] Markov_primitives = {"CRRA": base_primitives['CRRA'], "Rfree": np.array(2*[base_primitives['Rfree']]), "PermGroFac": [np.array(2*[base_primitives['PermGroFac'] / (1.0-base_primitives['UnempPrb'])])], "BoroCnstArt": None, "PermShkStd": [0.0], "PermShkCount": 1, "TranShkStd": [0.0], "TranShkCount": 1, "T_total": 1, "UnempPrb": 0.0, "UnempPrbRet": 0.0, "T_retire": 0, "IncUnemp": 0.0, "IncUnempRet": 0.0, "aXtraMin": 0.001, "aXtraMax": TBSType.mUpperBnd, "aXtraCount": 48, "aXtraExtra": [None], "aXtraNestFac": 3, "LivPrb":[np.array([1.0,1.0]),], "DiscFac": base_primitives['DiscFac'], 'Nagents': 1, 'psi_seed': 0, 'xi_seed': 0, 'unemp_seed': 0, 'tax_rate': 0.0, 'vFuncBool': False, 'CubicBool': True, 'MrkvArray': MrkvArray, 'T_cycle':1 } MarkovType = MarkovConsumerType(**Markov_primitives) MarkovType.cycles = 0 employed_income_dist = DiscreteDistribution(np.ones(1), [np.ones(1), np.ones(1)]) unemployed_income_dist = DiscreteDistribution(np.ones(1), [np.ones(1), np.zeros(1)]) MarkovType.IncomeDstn = [[employed_income_dist, unemployed_income_dist]] MarkovType.solve() MarkovType.unpackcFunc() self.TBSType = TBSType self.MarkovType = MarkovType
class test_ConsMarkovSolver(unittest.TestCase): def setUp(self): # Define the Markov transition matrix for serially correlated unemployment unemp_length = 5 # Averange length of unemployment spell urate_good = 0.05 # Unemployment rate when economy is in good state urate_bad = 0.12 # Unemployment rate when economy is in bad state bust_prob = 0.01 # Probability of economy switching from good to bad recession_length = 20 # Averange length of bad state p_reemploy = 1.0 / unemp_length p_unemploy_good = p_reemploy * urate_good / (1 - urate_good) p_unemploy_bad = p_reemploy * urate_bad / (1 - urate_bad) boom_prob = 1.0 / recession_length MrkvArray = np.array([ [ (1 - p_unemploy_good) * (1 - bust_prob), p_unemploy_good * (1 - bust_prob), (1 - p_unemploy_good) * bust_prob, p_unemploy_good * bust_prob, ], [ p_reemploy * (1 - bust_prob), (1 - p_reemploy) * (1 - bust_prob), p_reemploy * bust_prob, (1 - p_reemploy) * bust_prob, ], [ (1 - p_unemploy_bad) * boom_prob, p_unemploy_bad * boom_prob, (1 - p_unemploy_bad) * (1 - boom_prob), p_unemploy_bad * (1 - boom_prob), ], [ p_reemploy * boom_prob, (1 - p_reemploy) * boom_prob, p_reemploy * (1 - boom_prob), (1 - p_reemploy) * (1 - boom_prob), ], ]) init_serial_unemployment = copy(init_idiosyncratic_shocks) init_serial_unemployment["MrkvArray"] = [MrkvArray] init_serial_unemployment[ "UnempPrb"] = 0.0 # to make income distribution when employed init_serial_unemployment["global_markov"] = False self.model = MarkovConsumerType(**init_serial_unemployment) self.model.cycles = 0 self.model.vFuncBool = False # for easy toggling here # Replace the default (lognormal) income distribution with a custom one employed_income_dist = DiscreteDistribution( np.ones(1), np.array([[1.0], [1.0]])) # Definitely get income unemployed_income_dist = DiscreteDistribution( np.ones(1), np.array([[1.0], [0.0]])) # Definitely don't self.model.IncShkDstn = [[ employed_income_dist, unemployed_income_dist, employed_income_dist, unemployed_income_dist, ]] def test_check_markov_inputs(self): # check Rfree self.assertRaises(ValueError, self.model.check_markov_inputs) # fix Rfree self.model.Rfree = np.array(4 * [self.model.Rfree]) # check MrkvArray, first mess up the setup self.MrkvArray = self.model.MrkvArray self.model.MrkvArray = np.random.rand(3, 3) self.assertRaises(ValueError, self.model.check_markov_inputs) # then fix it back self.model.MrkvArray = self.MrkvArray # check LivPrb self.assertRaises(ValueError, self.model.check_markov_inputs) # fix LivPrb self.model.LivPrb = [np.array(4 * self.model.LivPrb)] # check PermGroFac self.assertRaises(ValueError, self.model.check_markov_inputs) # fix PermGroFac self.model.PermGroFac = [np.array(4 * self.model.PermGroFac)] def test_solve(self): self.model.Rfree = np.array(4 * [self.model.Rfree]) self.model.LivPrb = [np.array(4 * self.model.LivPrb)] self.model.PermGroFac = [np.array(4 * self.model.PermGroFac)] self.model.solve() def test_simulation(self): self.model.Rfree = np.array(4 * [self.model.Rfree]) self.model.LivPrb = [np.array(4 * self.model.LivPrb)] self.model.PermGroFac = [np.array(4 * self.model.PermGroFac)] self.model.solve() self.model.T_sim = 120 self.model.MrkvPrbsInit = [0.25, 0.25, 0.25, 0.25] self.model.track_vars = ["mNrm", 'cNrm'] self.model.make_shock_history() # This is optional self.model.initialize_sim() self.model.simulate()
# %% [markdown] # Note that $\texttt{MarkovConsumerType}$ currently has no method to automatically construct a valid IncomeDstn - $\texttt{IncomeDstn}$ is manually constructed in each case. Writing a method to supersede $\texttt{IndShockConsumerType.updateIncomeProcess}$ for the “Markov model” would be a welcome contribution! # %% # Interest factor, permanent growth rates, and survival probabilities are constant arrays SerialUnemploymentExample.Rfree = np.array(4 * [SerialUnemploymentExample.Rfree]) SerialUnemploymentExample.PermGroFac = [ np.array(4 * SerialUnemploymentExample.PermGroFac) ] SerialUnemploymentExample.LivPrb = [SerialUnemploymentExample.LivPrb * np.ones(4)] # %% # Solve the serial unemployment consumer's problem and display solution start_time = process_time() SerialUnemploymentExample.solve() end_time = process_time() print( "Solving a Markov consumer with serially correlated unemployment took " + mystr(end_time - start_time) + " seconds." ) print("Consumption functions for each discrete state:") plotFuncs(SerialUnemploymentExample.solution[0].cFunc, 0, 50) if SerialUnemploymentExample.vFuncBool: print("Value functions for each discrete state:") plotFuncs(SerialUnemploymentExample.solution[0].vFunc, 5, 50) # %% # Simulate some data; results stored in cHist, mNrmNow_hist, cNrmNow_hist, and MrkvNow_hist if do_simulation:
employed_income_dist = [ np.ones(1), np.ones(1), np.ones(1), ] # Income distribution when employed unemployed_income_dist = [ np.ones(1), np.ones(1), np.zeros(1), ] # Income distribution when permanently unemployed MarkovType.IncomeDstn = [[employed_income_dist, unemployed_income_dist] ] # set the income distribution in each state MarkovType.cycles = 0 # %% # Solve the "Markov TBS" model t_start = process_time() MarkovType.solve() t_end = process_time() MarkovType.unpackcFunc() # %% print('Solving the same model "the long way" took ' + str(t_end - t_start) + " seconds.") # plotFuncs([ExampleType.solution[0].cFunc,ExampleType.solution[0].cFunc_U],0,m_upper) plotFuncs(MarkovType.cFunc[0], 0, m_upper) diffFunc = lambda m: ExampleType.solution[0].cFunc(m) - MarkovType.cFunc[0][0]( m) print("Difference between the (employed) consumption functions:") plotFuncs(diffFunc, 0, m_upper)
def main(): # Import the HARK library. The assumption is that this code is in a folder # contained in the HARK folder. Also import the ConsumptionSavingModel import numpy as np # numeric Python from HARK.utilities import plotFuncs # basic plotting tools from HARK.ConsumptionSaving.ConsMarkovModel import MarkovConsumerType # An alternative, much longer way to solve the TBS model from time import clock # timing utility do_simulation = True # Define the model primitives base_primitives = { 'UnempPrb': .00625, # Probability of becoming unemployed 'DiscFac': 0.975, # Intertemporal discount factor 'Rfree': 1.01, # Risk-free interest factor on assets 'PermGroFac': 1.0025, # Permanent income growth factor (uncompensated) 'CRRA': 1.0 } # Coefficient of relative risk aversion # Define a dictionary to be used in case of simulation simulation_values = { 'aLvlInitMean': 0.0, # Mean of log initial assets for new agents 'aLvlInitStd': 1.0, # Stdev of log initial assets for new agents 'AgentCount': 10000, # Number of agents to simulate 'T_sim': 120, # Number of periods to simulate 'T_cycle': 1 } # Number of periods in the cycle # Make and solve a tractable consumer type ExampleType = TractableConsumerType(**base_primitives) t_start = clock() ExampleType.solve() t_end = clock() print('Solving a tractable consumption-savings model took ' + str(t_end - t_start) + ' seconds.') # Plot the consumption function and whatnot m_upper = 1.5 * ExampleType.mTarg conFunc_PF = lambda m: ExampleType.h * ExampleType.PFMPC + ExampleType.PFMPC * m #plotFuncs([ExampleType.solution[0].cFunc,ExampleType.mSSfunc,ExampleType.cSSfunc],0,m_upper) plotFuncs([ExampleType.solution[0].cFunc, ExampleType.solution[0].cFunc_U], 0, m_upper) if do_simulation: ExampleType(** simulation_values) # Set attributes needed for simulation ExampleType.track_vars = ['mLvlNow'] ExampleType.makeShockHistory() ExampleType.initializeSim() ExampleType.simulate() # Now solve the same model using backward induction rather than the analytic method of TBS. # The TBS model is equivalent to a Markov model with two states, one of them absorbing (permanent unemployment). MrkvArray = np.array( [[1.0 - base_primitives['UnempPrb'], base_primitives['UnempPrb']], [0.0, 1.0]]) # Define the two state, absorbing unemployment Markov array init_consumer_objects = { "CRRA": base_primitives['CRRA'], "Rfree": np.array(2 * [base_primitives['Rfree'] ]), # Interest factor (same in both states) "PermGroFac": [ np.array(2 * [ base_primitives['PermGroFac'] / (1.0 - base_primitives['UnempPrb']) ]) ], # Unemployment-compensated permanent growth factor "BoroCnstArt": None, # Artificial borrowing constraint "PermShkStd": [0.0], # Permanent shock standard deviation "PermShkCount": 1, # Number of shocks in discrete permanent shock distribution "TranShkStd": [0.0], # Transitory shock standard deviation "TranShkCount": 1, # Number of shocks in discrete permanent shock distribution "T_cycle": 1, # Number of periods in cycle "UnempPrb": 0.0, # Unemployment probability (not used, as the unemployment here is *permanent*, not transitory) "UnempPrbRet": 0.0, # Unemployment probability when retired (irrelevant here) "T_retire": 0, # Age at retirement (turned off) "IncUnemp": 0.0, # Income when unemployed (irrelevant) "IncUnempRet": 0.0, # Income when unemployed and retired (irrelevant) "aXtraMin": 0.001, # Minimum value of assets above minimum in grid "aXtraMax": ExampleType.mUpperBnd, # Maximum value of assets above minimum in grid "aXtraCount": 48, # Number of points in assets grid "aXtraExtra": [None], # Additional points to include in assets grid "aXtraNestFac": 3, # Degree of exponential nesting when constructing assets grid "LivPrb": [np.array([1.0, 1.0])], # Survival probability "DiscFac": base_primitives['DiscFac'], # Intertemporal discount factor 'AgentCount': 1, # Number of agents in a simulation (irrelevant) 'tax_rate': 0.0, # Tax rate on labor income (irrelevant) 'vFuncBool': False, # Whether to calculate the value function 'CubicBool': True, # Whether to use cubic splines (False --> linear splines) 'MrkvArray': [MrkvArray] # State transition probabilities } MarkovType = MarkovConsumerType( **init_consumer_objects) # Make a basic consumer type employed_income_dist = [np.ones(1), np.ones(1), np.ones(1)] # Income distribution when employed unemployed_income_dist = [ np.ones(1), np.ones(1), np.zeros(1) ] # Income distribution when permanently unemployed MarkovType.IncomeDstn = [[employed_income_dist, unemployed_income_dist] ] # set the income distribution in each state MarkovType.cycles = 0 # Solve the "Markov TBS" model t_start = clock() MarkovType.solve() t_end = clock() MarkovType.unpackcFunc() print('Solving the same model "the long way" took ' + str(t_end - t_start) + ' seconds.') #plotFuncs([ExampleType.solution[0].cFunc,ExampleType.solution[0].cFunc_U],0,m_upper) plotFuncs(MarkovType.cFunc[0], 0, m_upper) diffFunc = lambda m: ExampleType.solution[0].cFunc(m) - MarkovType.cFunc[ 0][0](m) print('Difference between the (employed) consumption functions:') plotFuncs(diffFunc, 0, m_upper)