diff --git a/HARK/ConsumptionSaving/ConsAggShockModel.py b/HARK/ConsumptionSaving/ConsAggShockModel.py index 24bde222f..b6159f6be 100644 --- a/HARK/ConsumptionSaving/ConsAggShockModel.py +++ b/HARK/ConsumptionSaving/ConsAggShockModel.py @@ -24,7 +24,7 @@ __all__ = ['MargValueFunc2D', 'AggShockConsumerType', 'AggShockMarkovConsumerType', 'CobbDouglasEconomy', 'SmallOpenEconomy', 'CobbDouglasMarkovEconomy', - 'SmallOpenMarkovEconomy', 'CobbDouglasAggVars', 'AggregateSavingRule', 'AggShocksDynamicRule','init_agg_shocks','init_agg_mrkv_shocks', 'init_cobb_douglas','init_mrkv_cobb_douglas'] + 'SmallOpenMarkovEconomy', 'AggregateSavingRule', 'AggShocksDynamicRule','init_agg_shocks','init_agg_mrkv_shocks', 'init_cobb_douglas','init_mrkv_cobb_douglas'] utility = CRRAutility utilityP = CRRAutilityP @@ -616,7 +616,7 @@ def getEconomyData(self, Economy): ''' self.T_sim = Economy.act_T # Need to be able to track as many periods as economy runs self.kInit = Economy.KSS # Initialize simulation assets to steady state - self.MrkvInit = Economy.MrkvNow_init # Starting Markov state for the macroeconomy + self.MrkvInit = Economy.sow_init['MrkvNow'] # Starting Markov state for the macroeconomy self.Mgrid = Economy.MSS*self.MgridBase # Aggregate market resources grid adjusted around SS capital ratio self.AFunc = Economy.AFunc # Next period's aggregate savings function self.DeprFac = Economy.DeprFac # Rate of capital depreciation @@ -818,7 +818,7 @@ def getShocks(self): # Get boolean arrays for current employment states employed = self.EmpNow.copy() unemployed = np.logical_not(employed) - + # Transition some agents between unemployment and employment emp_permute = self.emp_permute[self.MrkvPrev][self.MrkvNow] unemp_permute = self.unemp_permute[self.MrkvPrev][self.MrkvNow] @@ -1377,11 +1377,12 @@ def __init__(self, ''' agents = agents if agents is not None else list() params = init_cobb_douglas.copy() + params['sow_vars'] = ['MaggNow', 'AaggNow', 'RfreeNow', + 'wRteNow', 'PermShkAggNow', + 'TranShkAggNow', 'KtoLnow'] params.update(kwds) Market.__init__(self, agents=agents, - sow_vars=['MaggNow', 'AaggNow', 'RfreeNow', - 'wRteNow', 'PermShkAggNow', 'TranShkAggNow', 'KtoLnow'], reap_vars=['aLvlNow', 'pLvlNow'], track_vars=['MaggNow', 'AaggNow'], dyn_vars=['AFunc'], @@ -1442,13 +1443,14 @@ def update(self): self.convertKtoY = lambda KtoY: KtoY**(1.0/(1.0 - self.CapShare)) # converts K/Y to K/L self.Rfunc = lambda k: (1.0 + self.CapShare*k**(self.CapShare-1.0) - self.DeprFac) self.wFunc = lambda k: ((1.0-self.CapShare)*k**(self.CapShare)) - self.KtoLnow_init = self.kSS - self.MaggNow_init = self.kSS - self.AaggNow_init = self.kSS - self.RfreeNow_init = self.Rfunc(self.kSS) - self.wRteNow_init = self.wFunc(self.kSS) - self.PermShkAggNow_init = 1.0 - self.TranShkAggNow_init = 1.0 + + self.sow_init['KtoLnow'] = self.kSS + self.sow_init['MaggNow'] = self.kSS + self.sow_init['AaggNow'] = self.kSS + self.sow_init['RfreeNow'] = self.Rfunc(self.kSS) + self.sow_init['wRteNow'] = self.wFunc(self.kSS) + self.sow_init['PermShkAggNow'] = 1.0 + self.sow_init['TranShkAggNow'] = 1.0 self.makeAggShkDstn() self.AFunc = AggregateSavingRule(self.intercept_prev, self.slope_prev) @@ -1545,10 +1547,20 @@ def calcRandW(self, aLvlNow, pLvlNow): Returns ------- - AggVarsNow : CobbDouglasAggVars - An object containing the aggregate variables for the upcoming period: - capital-to-labor ratio, interest factor, (normalized) wage rate, - aggregate permanent and transitory shocks. + MaggNow : float + Aggregate market resources for this period normalized by mean permanent income + AaggNow : float + Aggregate savings for this period normalized by mean permanent income + RfreeNow : float + Interest factor on assets in the economy this period. + wRteNow : float + Wage rate for labor in the economy this period. + PermShkAggNow : float + Permanent shock to aggregate labor productivity this period. + TranShkAggNow : float + Transitory shock to aggregate labor productivity this period. + KtoLnow : float + Capital-to-labor ratio in the economy this period. ''' # Calculate aggregate savings AaggPrev = np.mean(np.array(aLvlNow))/np.mean(pLvlNow) # End-of-period savings from last period @@ -1575,9 +1587,8 @@ def calcRandW(self, aLvlNow, pLvlNow): self.KtoLnow = KtoLnow # Need to store this as it is a sow variable # Package the results into an object and return it - AggVarsNow = CobbDouglasAggVars(MaggNow, AaggPrev, KtoLnow, RfreeNow, wRteNow, PermShkAggNow, TranShkAggNow) - return AggVarsNow - + return MaggNow, AaggPrev, RfreeNow, wRteNow, PermShkAggNow, TranShkAggNow, KtoLnow + def calcAFunc(self, MaggNow, AaggNow): ''' Calculate a new aggregate savings rule based on the history @@ -1662,7 +1673,8 @@ def __init__(self, agents=None, tolerance=0.0001, act_T=1000, **kwds): def update(self): ''' - Use primitive parameters to set basic objects. This is an extremely stripped-down version + Use primitive parameters to set basic objects. + This is an extremely stripped-down version of update for CobbDouglasEconomy. Parameters @@ -1675,15 +1687,15 @@ def update(self): ''' self.kSS = 1.0 self.MSS = 1.0 - self.KtoLnow_init = self.kSS + self.sow_init['KtoLnow_init'] = self.kSS self.Rfunc = ConstantFunction(self.Rfree) self.wFunc = ConstantFunction(self.wRte) - self.RfreeNow_init = self.Rfunc(self.kSS) - self.wRteNow_init = self.wFunc(self.kSS) - self.MaggNow_init = self.kSS - self.AaggNow_init = self.kSS - self.PermShkAggNow_init = 1.0 - self.TranShkAggNow_init = 1.0 + self.sow_init['RfreeNow'] = self.Rfunc(self.kSS) + self.sow_init['wRteNow'] = self.wFunc(self.kSS) + self.sow_init['MaggNow'] = self.kSS + self.sow_init['AaggNow'] = self.kSS + self.sow_init['PermShkAggNow'] = 1.0 + self.sow_init['TranShkAggNow'] = 1.0 self.makeAggShkDstn() self.AFunc = ConstantFunction(1.0) @@ -1779,8 +1791,21 @@ def getAggShocks(self): Returns ------- - AggVarsNow : CobbDouglasAggVars - Aggregate state and shock variables for this period. + MaggNow : float + Aggregate market resources for this period normalized by mean permanent income + AaggNow : float + Aggregate savings for this period normalized by mean permanent income + RfreeNow : float + Interest factor on assets in the economy this period. + wRteNow : float + Wage rate for labor in the economy this period. + PermShkAggNow : float + Permanent shock to aggregate labor productivity this period. + TranShkAggNow : float + Transitory shock to aggregate labor productivity this period. + KtoLnow : float + Capital-to-labor ratio in the economy this period. + ''' # Get this period's aggregate shocks PermShkAggNow = self.PermShkAggHist[self.Shk_idx] @@ -1796,9 +1821,7 @@ def getAggShocks(self): MaggNow = 1.0 KtoLnow = 1.0/PermShkAggNow - # Package the results into an object and return it - AggVarsNow = CobbDouglasAggVars(MaggNow, AaggNow, KtoLnow, RfreeNow, wRteNow, PermShkAggNow, TranShkAggNow) - return AggVarsNow + return MaggNow, AaggNow, RfreeNow, wRteNow, PermShkAggNow, TranShkAggNow, KtoLnow # Make a dictionary to specify a Markov Cobb-Douglas economy init_mrkv_cobb_douglas = init_cobb_douglas.copy() @@ -1825,6 +1848,15 @@ def __init__(self, agents=None, tolerance=0.0001, act_T=1200, + sow_vars=['MaggNow', + 'AaggNow', + 'RfreeNow', + 'wRteNow', + 'PermShkAggNow', + 'TranShkAggNow', + 'KtoLnow', + 'MrkvNow' # This one is new + ], **kwds): ''' Make a new instance of CobbDouglasMarkovEconomy by filling in attributes @@ -1849,8 +1881,14 @@ def __init__(self, params = init_mrkv_cobb_douglas.copy() params.update(kwds) - CobbDouglasEconomy.__init__(self, agents=agents, tolerance=tolerance, act_T=act_T, **params) - self.sow_vars.append('MrkvNow') + CobbDouglasEconomy.__init__(self, + agents=agents, + tolerance=tolerance, + act_T=act_T, + sow_vars = sow_vars, + **params) + + self.sow_init['MrkvNow'] = params['MrkvNow_init'] def update(self): ''' @@ -2011,7 +2049,7 @@ def makeMrkvHist(self): cutoffs = np.cumsum(self.MrkvArray, axis=1) loops = 0 go = True - MrkvNow = self.MrkvNow_init + MrkvNow = self.sow_init['MrkvNow'] t = 0 StateCount = self.MrkvArray.shape[0] @@ -2068,11 +2106,26 @@ def millRule(self, aLvlNow, pLvlNow): and adds the Markov state index. See documentation for calcRandW for more information. + + Returns + ------- + Mnow : float + Aggregate market resources for this period. + Aprev : float + Aggregate savings for the prior period. + KtoLnow : float + Capital-to-labor ratio in the economy this period. + Rnow : float + Interest factor on assets in the economy this period. + Wnow : float + Wage rate for labor in the economy this period. + MrkvNow : int + Binary indicator for bad (0) or good (1) macroeconomic state. ''' MrkvNow = self.MrkvNow_hist[self.Shk_idx] temp = self.calcRandW(aLvlNow, pLvlNow) - temp(MrkvNow=MrkvNow) - return temp + + return temp + (MrkvNow,) def calcAFunc(self, MaggNow, AaggNow): ''' @@ -2247,14 +2300,14 @@ def update(self): self.convertKtoY = lambda KtoY: KtoY**(1.0/(1.0 - self.CapShare)) # converts K/Y to K/L self.rFunc = lambda k: self.CapShare*k**(self.CapShare-1.0) self.Wfunc = lambda k: ((1.0-self.CapShare)*k**(self.CapShare)) - self.KtoLnow_init = self.KtoLSS - self.Mnow_init = self.MSS - self.Aprev_init = self.KSS - self.Rnow_init = self.RSS - self.Wnow_init = self.WSS + self.sow_init['KtoLnow'] = self.KtoLSS + self.sow_init['Mnow'] = self.MSS + self.sow_init['Aprev'] = self.KSS + self.sow_init['Rnow'] = self.RSS + self.sow_init['Wnow'] = self.WSS self.PermShkAggNow_init = 1.0 self.TranShkAggNow_init = 1.0 - self.Mrkv_init = 0 + self.sow_init['MrkvNow'] = 0 self.makeMrkvArray() def reset(self): @@ -2339,7 +2392,21 @@ def millRule(self, aNow, EmpNow): wage rate based on each agent's current state. Just calls calcRandW(). See documentation for calcRandW for more information. + + Returns + ------- + Mnow : float + Aggregate market resources for this period. + Aprev : float + Aggregate savings for the prior period. + MrkvNow : int + Binary indicator for bad (0) or good (1) macroeconomic state. + Rnow : float + Interest factor on assets in the economy this period. + Wnow : float + Wage rate for labor in the economy this period. ''' + return self.calcRandW(aNow, EmpNow) def calcDynamics(self, Mnow, Aprev): @@ -2366,10 +2433,16 @@ def calcRandW(self, aNow, EmpNow): Returns ------- - AggVarsNow : CobbDouglasAggVars - An object containing the aggregate variables for the upcoming period: - capital-to-labor ratio, interest factor, (normalized) wage rate, - aggregate permanent and transitory shocks. + Mnow : float + Aggregate market resources for this period. + Aprev : float + Aggregate savings for the prior period. + MrkvNow : int + Binary indicator for bad (0) or good (1) macroeconomic state. + Rnow : float + Interest factor on assets in the economy this period. + Wnow : float + Wage rate for labor in the economy this period. ''' # Calculate aggregate savings Aprev = np.mean(np.array(aNow)) # End-of-period savings from last period @@ -2397,9 +2470,8 @@ def calcRandW(self, aNow, EmpNow): Mnow = Rnow*AggK + Wnow*AggL self.KtoLnow = KtoLnow # Need to store this as it is a sow variable - # Package the results into an object and return it - AggVarsNow = KrusellSmithAggVars(Mnow, Aprev, KtoLnow, Rnow, Wnow, MrkvNow) - return AggVarsNow + # Returns a tuple of these values + return Mnow, Aprev, MrkvNow, Rnow, Wnow def calcAFunc(self, Mnow, Aprev): ''' @@ -2455,81 +2527,6 @@ def calcAFunc(self, Mnow, Aprev): return AggShocksDynamicRule(AFunc_list) -class CobbDouglasAggVars(HARKobject): - ''' - A simple class for holding the relevant aggregate variables that should be - passed from the market to each type. Includes the capital-to-labor ratio, - the interest factor, the wage rate, and the aggregate permanent and tran- - sitory shocks. - ''' - def __init__(self, MaggNow, AaggNow, KtoLnow, RfreeNow, wRteNow, PermShkAggNow, TranShkAggNow): - ''' - Make a new instance of CobbDouglasAggVars. - - Parameters - ---------- - MaggNow : float - Aggregate market resources for this period normalized by mean permanent income - AaggNow : float - Aggregate savings for this period normalized by mean permanent income - KtoLnow : float - Capital-to-labor ratio in the economy this period. - RfreeNow : float - Interest factor on assets in the economy this period. - wRteNow : float - Wage rate for labor in the economy this period. - PermShkAggNow : float - Permanent shock to aggregate labor productivity this period. - TranShkAggNow : float - Transitory shock to aggregate labor productivity this period. - - Returns - ------- - None - ''' - self.MaggNow = MaggNow - self.AaggNow = AaggNow - self.KtoLnow = KtoLnow - self.RfreeNow = RfreeNow - self.wRteNow = wRteNow - self.PermShkAggNow = PermShkAggNow - self.TranShkAggNow = TranShkAggNow - - -class KrusellSmithAggVars(): - ''' - Just a container class for aggregate data in the Krusell-Smith model. - ''' - def __init__(self, Mnow, Aprev, KtoLnow, Rnow, Wnow, MrkvNow): - ''' - Make a new instance of KrusellSmithAggVars. - - Parameters - ---------- - Mnow : float - Aggregate market resources for this period. - Aprev : float - Aggregate savings for the prior period. - KtoLnow : float - Capital-to-labor ratio in the economy this period. - Rnow : float - Interest factor on assets in the economy this period. - Wnow : float - Wage rate for labor in the economy this period. - MrkvNow : int - Binary indicator for bad (0) or good (1) macroeconomic state. - - Returns - ------- - None - ''' - self.Mnow = Mnow - self.Aprev = Aprev - self.KtoLnow = KtoLnow - self.Rnow = Rnow - self.Wnow = Wnow - self.MrkvNow = MrkvNow - class AggregateSavingRule(HARKobject): ''' diff --git a/HARK/core.py b/HARK/core.py index 5ef288543..eea1001f9 100644 --- a/HARK/core.py +++ b/HARK/core.py @@ -918,8 +918,7 @@ def __init__(self, agents=None, sow_vars=None, reap_vars=None, const_vars=None, dyn_vars : [string] Names of variables that constitute a "dynamic rule". millRule : function - A function that takes inputs named in reap_vars and returns an object - with attributes named in sow_vars. The "aggregate market process" that + A function that takes inputs named in reap_vars and returns a tuple the same size and order as sow_vars. The "aggregate market process" that transforms individual agent actions/states/data into aggregate data to be sent back to agents. calcDynamics : function @@ -939,11 +938,22 @@ def __init__(self, agents=None, sow_vars=None, reap_vars=None, const_vars=None, None ''' self.agents = agents if agents is not None else list() # NOQA - self.reap_vars = reap_vars if reap_vars is not None else list() # NOQA + + reap_vars = reap_vars if reap_vars is not None else list() # NOQA + self.reap_state = dict([(var, []) for var in reap_vars]) + self.sow_vars = sow_vars if sow_vars is not None else list() # NOQA - self.const_vars = const_vars if const_vars is not None else list() # NOQA + # dictionaries for tracking initial and current values + # of the sow variables. + self.sow_init = dict([(var, None) for var in self.sow_vars]) + self.sow_state = dict([(var, None) for var in self.sow_vars]) + + const_vars = const_vars if const_vars is not None else list() # NOQA + self.const_vars = dict([(var, None) for var in const_vars]) + self.track_vars = track_vars if track_vars is not None else list() # NOQA self.dyn_vars = dyn_vars if dyn_vars is not None else list() # NOQA + if millRule is not None: # To prevent overwriting of method-based millRules self.millRule = millRule if calcDynamics is not None: # Ditto for calcDynamics @@ -959,6 +969,7 @@ def __init__(self, agents=None, sow_vars=None, reap_vars=None, const_vars=None, # "solveAgents" one time. If set to false, the error will never # print. See "solveAgents" for why this prints once or never. + def solveAgents(self): ''' Solves the microeconomic problem for all AgentTypes in this market. @@ -1033,11 +1044,11 @@ def reap(self): ------- none ''' - for var_name in self.reap_vars: - harvest = [] - for this_type in self.agents: - harvest.append(getattr(this_type, var_name)) - setattr(self, var_name, harvest) + for var_name in self.reap_state: + harvest = [getattr(this_type, var_name) + for this_type + in self.agents] + self.reap_state[var_name] = harvest def sow(self): ''' @@ -1052,10 +1063,11 @@ def sow(self): ------- none ''' - for var_name in self.sow_vars: - this_seed = getattr(self, var_name) + for sow_var in self.sow_state: for this_type in self.agents: - setattr(this_type, var_name, this_seed) + setattr(this_type, + sow_var, + self.sow_state[sow_var]) def mill(self): ''' @@ -1071,20 +1083,14 @@ def mill(self): none ''' # Make a dictionary of inputs for the millRule - reap_vars_string = '' - for name in self.reap_vars: - reap_vars_string += ' \'' + name + '\' : self.' + name + ',' - const_vars_string = '' - for name in self.const_vars: - const_vars_string += ' \'' + name + '\' : self.' + name + ',' - mill_dict = eval('{' + reap_vars_string + const_vars_string + '}') + mill_dict = copy(self.reap_state) + mill_dict.update(self.const_vars) # Run the millRule and store its output in self product = self.millRule(**mill_dict) - for j in range(len(self.sow_vars)): - this_var = self.sow_vars[j] - this_product = getattr(product, this_var) - setattr(self, this_var, this_product) + + for i, sow_var in enumerate(self.sow_state): + self.sow_state[sow_var] = product[i] def cultivate(self): ''' @@ -1117,12 +1123,15 @@ def reset(self): ------- none ''' - for var_name in self.track_vars: # Reset the history of tracked variables - self.history[var_name] = [] - for var_name in self.sow_vars: # Set the sow variables to their initial levels - initial_val = getattr(self, var_name + '_init') - setattr(self, var_name, initial_val) - for this_type in self.agents: # Reset each AgentType in the market + # Reset the history of tracked variables + self.history = {var_name : [] for var_name in self.track_vars} + + # Set the sow variables to their initial levels + for var_name in self.sow_state: + self.sow_state[var_name] = self.sow_init[var_name] + + # Reset each AgentType in the market + for this_type in self.agents: this_type.reset() def store(self): @@ -1139,7 +1148,15 @@ def store(self): none ''' for var_name in self.track_vars: - value_now = getattr(self, var_name) + if var_name in self.sow_state: + value_now = self.sow_state[var_name] + elif var_name in self.reap_state: + value_now = self.reap_state[var_name] + elif var_name in self.const_vars: + value_now = self.const_vars[var_name] + else: + value_now = getattr(self, var_name) + self.history[var_name].append(value_now) def makeHistory(self):