Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move constructLogNormalIncomeProcess into model as method, fixes #538 #661

Merged
merged 3 commits into from
Apr 30, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 122 additions & 117 deletions HARK/ConsumptionSaving/ConsIndShockModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2092,7 +2092,7 @@ def updateIncomeProcess(self):
-----------
none
'''
IncomeDstn, PermShkDstn, TranShkDstn = constructLognormalIncomeProcessUnemployment(self)
IncomeDstn, PermShkDstn, TranShkDstn = self.constructLognormalIncomeProcessUnemployment()
self.IncomeDstn = IncomeDstn
self.PermShkDstn = PermShkDstn
self.TranShkDstn = TranShkDstn
Expand Down Expand Up @@ -2537,6 +2537,127 @@ def calcTargets(self,verbose=False):
# The target level of m, mTarg, will be the value such that
# cSust[m] = cFunc[m]



# ========================================================
# = Functions for generating discrete income processes and
# simulated income shocks =
# ========================================================

def constructLognormalIncomeProcessUnemployment(self):
'''
Generates a list of discrete approximations to the income process for each
life period, from end of life to beginning of life. Permanent shocks are mean
one lognormally distributed with standard deviation PermShkStd[t] during the
working life, and degenerate at 1 in the retirement period. Transitory shocks
are mean one lognormally distributed with a point mass at IncUnemp with
probability UnempPrb while working; they are mean one with a point mass at
IncUnempRet with probability UnempPrbRet. Retirement occurs
after t=T_retire periods of working.

Note 1: All time in this function runs forward, from t=0 to t=T

Note 2: All parameters are passed as attributes of the input parameters.

Parameters (passed as attributes of the input parameters)
----------
PermShkStd : [float]
List of standard deviations in log permanent income uncertainty during
the agent's life.
PermShkCount : int
The number of approximation points to be used in the discrete approxima-
tion to the permanent income shock distribution.
TranShkStd : [float]
List of standard deviations in log transitory income uncertainty during
the agent's life.
TranShkCount : int
The number of approximation points to be used in the discrete approxima-
tion to the permanent income shock distribution.
UnempPrb : float
The probability of becoming unemployed during the working period.
UnempPrbRet : float
The probability of not receiving typical retirement income when retired.
T_retire : int
The index value for the final working period in the agent's life.
If T_retire <= 0 then there is no retirement.
IncUnemp : float
Transitory income received when unemployed.
IncUnempRet : float
Transitory income received while "unemployed" when retired.
T_cycle : int
Total number of non-terminal periods in the consumer's sequence of periods.

Returns
-------
IncomeDstn : [[np.array]]
A list with T_cycle elements, each of which is a list of three arrays
representing a discrete approximation to the income process in a period.
Order: probabilities, permanent shocks, transitory shocks.
PermShkDstn : [[np.array]]
A list with T_cycle elements, each of which is a list of two arrays
representing a discrete approximation to the permanent income shocks.
TranShkDstn : [[np.array]]
A list with T_cycle elements, each of which is a list of two arrays
representing a discrete approximation to the transitory income shocks.
'''
# Unpack the parameters from the input
PermShkStd = self.PermShkStd
PermShkCount = self.PermShkCount
TranShkStd = self.TranShkStd
TranShkCount = self.TranShkCount
T_cycle = self.T_cycle
T_retire = self.T_retire
UnempPrb = self.UnempPrb
IncUnemp = self.IncUnemp
UnempPrbRet = self.UnempPrbRet
IncUnempRet = self.IncUnempRet

IncomeDstn = [] # Discrete approximations to income process in each period
PermShkDstn = [] # Discrete approximations to permanent income shocks
TranShkDstn = [] # Discrete approximations to transitory income shocks

# Fill out a simple discrete RV for retirement, with value 1.0 (mean of shocks)
# in normal times; value 0.0 in "unemployment" times with small prob.
if T_retire > 0:
if UnempPrbRet > 0:
PermShkValsRet = np.array([1.0, 1.0]) # Permanent income is deterministic in retirement (2 states for temp income shocks)
TranShkValsRet = np.array([IncUnempRet,
(1.0-UnempPrbRet*IncUnempRet)/(1.0-UnempPrbRet)])
ShkPrbsRet = np.array([UnempPrbRet, 1.0-UnempPrbRet])
else:
PermShkValsRet = np.array([1.0])
TranShkValsRet = np.array([1.0])
ShkPrbsRet = np.array([1.0])
IncomeDstnRet = DiscreteDistribution(ShkPrbsRet,
[PermShkValsRet,
TranShkValsRet])

# Loop to fill in the list of IncomeDstn random variables.
for t in range(T_cycle): # Iterate over all periods, counting forward

if T_retire > 0 and t >= T_retire:
# Then we are in the "retirement period" and add a retirement income object.
IncomeDstn.append(deepcopy(IncomeDstnRet))
PermShkDstn.append([np.array([1.0]),np.array([1.0])])
TranShkDstn.append([ShkPrbsRet,TranShkValsRet])
else:
# We are in the "working life" periods.
TranShkDstn_t = MeanOneLogNormal(
sigma=TranShkStd[t]
).approx(TranShkCount, tail_N=0)
if UnempPrb > 0:
TranShkDstn_t = addDiscreteOutcomeConstantMean(TranShkDstn_t, p=UnempPrb, x=IncUnemp)
PermShkDstn_t = MeanOneLogNormal(
sigma=PermShkStd[t]
).approx(PermShkCount, tail_N=0)
### REPLACE
###REPLACE
IncomeDstn.append(combineIndepDstns(PermShkDstn_t,TranShkDstn_t)) # mix the independent distributions
PermShkDstn.append(PermShkDstn_t)
TranShkDstn.append(TranShkDstn_t)
return IncomeDstn, PermShkDstn, TranShkDstn


# Make a dictionary to specify a "kinked R" idiosyncratic shock consumer
init_kinked_R = dict(init_idiosyncratic_shocks,
**{
Expand Down Expand Up @@ -2702,122 +2823,6 @@ def checkConditions(self,verbose=False):
'''
raise NotImplementedError()

# ==================================================================================
# = Functions for generating discrete income processes and simulated income shocks =
# ==================================================================================

def constructLognormalIncomeProcessUnemployment(parameters):
'''
Generates a list of discrete approximations to the income process for each
life period, from end of life to beginning of life. Permanent shocks are mean
one lognormally distributed with standard deviation PermShkStd[t] during the
working life, and degenerate at 1 in the retirement period. Transitory shocks
are mean one lognormally distributed with a point mass at IncUnemp with
probability UnempPrb while working; they are mean one with a point mass at
IncUnempRet with probability UnempPrbRet. Retirement occurs
after t=T_retire periods of working.

Note 1: All time in this function runs forward, from t=0 to t=T

Note 2: All parameters are passed as attributes of the input parameters.

Parameters (passed as attributes of the input parameters)
----------
PermShkStd : [float]
List of standard deviations in log permanent income uncertainty during
the agent's life.
PermShkCount : int
The number of approximation points to be used in the discrete approxima-
tion to the permanent income shock distribution.
TranShkStd : [float]
List of standard deviations in log transitory income uncertainty during
the agent's life.
TranShkCount : int
The number of approximation points to be used in the discrete approxima-
tion to the permanent income shock distribution.
UnempPrb : float
The probability of becoming unemployed during the working period.
UnempPrbRet : float
The probability of not receiving typical retirement income when retired.
T_retire : int
The index value for the final working period in the agent's life.
If T_retire <= 0 then there is no retirement.
IncUnemp : float
Transitory income received when unemployed.
IncUnempRet : float
Transitory income received while "unemployed" when retired.
T_cycle : int
Total number of non-terminal periods in the consumer's sequence of periods.

Returns
-------
IncomeDstn : [[np.array]]
A list with T_cycle elements, each of which is a list of three arrays
representing a discrete approximation to the income process in a period.
Order: probabilities, permanent shocks, transitory shocks.
PermShkDstn : [[np.array]]
A list with T_cycle elements, each of which is a list of two arrays
representing a discrete approximation to the permanent income shocks.
TranShkDstn : [[np.array]]
A list with T_cycle elements, each of which is a list of two arrays
representing a discrete approximation to the transitory income shocks.
'''
# Unpack the parameters from the input
PermShkStd = parameters.PermShkStd
PermShkCount = parameters.PermShkCount
TranShkStd = parameters.TranShkStd
TranShkCount = parameters.TranShkCount
T_cycle = parameters.T_cycle
T_retire = parameters.T_retire
UnempPrb = parameters.UnempPrb
IncUnemp = parameters.IncUnemp
UnempPrbRet = parameters.UnempPrbRet
IncUnempRet = parameters.IncUnempRet

IncomeDstn = [] # Discrete approximations to income process in each period
PermShkDstn = [] # Discrete approximations to permanent income shocks
TranShkDstn = [] # Discrete approximations to transitory income shocks

# Fill out a simple discrete RV for retirement, with value 1.0 (mean of shocks)
# in normal times; value 0.0 in "unemployment" times with small prob.
if T_retire > 0:
if UnempPrbRet > 0:
PermShkValsRet = np.array([1.0, 1.0]) # Permanent income is deterministic in retirement (2 states for temp income shocks)
TranShkValsRet = np.array([IncUnempRet,
(1.0-UnempPrbRet*IncUnempRet)/(1.0-UnempPrbRet)])
ShkPrbsRet = np.array([UnempPrbRet, 1.0-UnempPrbRet])
else:
PermShkValsRet = np.array([1.0])
TranShkValsRet = np.array([1.0])
ShkPrbsRet = np.array([1.0])
IncomeDstnRet = DiscreteDistribution(ShkPrbsRet,
[PermShkValsRet,
TranShkValsRet])

# Loop to fill in the list of IncomeDstn random variables.
for t in range(T_cycle): # Iterate over all periods, counting forward

if T_retire > 0 and t >= T_retire:
# Then we are in the "retirement period" and add a retirement income object.
IncomeDstn.append(deepcopy(IncomeDstnRet))
PermShkDstn.append([np.array([1.0]),np.array([1.0])])
TranShkDstn.append([ShkPrbsRet,TranShkValsRet])
else:
# We are in the "working life" periods.
TranShkDstn_t = MeanOneLogNormal(
sigma=TranShkStd[t]
).approx(TranShkCount, tail_N=0)
if UnempPrb > 0:
TranShkDstn_t = addDiscreteOutcomeConstantMean(TranShkDstn_t, p=UnempPrb, x=IncUnemp)
PermShkDstn_t = MeanOneLogNormal(
sigma=PermShkStd[t]
).approx(PermShkCount, tail_N=0)
IncomeDstn.append(combineIndepDstns(PermShkDstn_t,TranShkDstn_t)) # mix the independent distributions
PermShkDstn.append(PermShkDstn_t)
TranShkDstn.append(TranShkDstn_t)
return IncomeDstn, PermShkDstn, TranShkDstn


def applyFlatIncomeTax(IncomeDstn,tax_rate,T_retire,unemployed_indices=[],transitory_index=2):
'''
Applies a flat income tax rate to all employed income states during the working
Expand Down