Ejemplo n.º 1
0
    def usePointsForInterpolation(self, cNrm, mNrm, interpolator):
        '''
        Make a basic solution object with a consumption function and marginal
        value function (unconditional on the preference shock).
        
        Parameters
        ----------
        cNrm : np.array
            Consumption points for interpolation.
        mNrm : np.array
            Corresponding market resource points for interpolation.
        interpolator : function
            A function that constructs and returns a consumption function.
            
        Returns
        -------
        solution_now : ConsumerSolution
            The solution to this period's consumption-saving problem, with a
            consumption function, marginal value function, and minimum m.
        '''
        # Make the preference-shock specific consumption functions
        PrefShkCount = self.PrefShkVals.size
        cFunc_list = []
        for j in range(PrefShkCount):
            MPCmin_j = self.MPCminNow * self.PrefShkVals[j]**(1.0 / self.CRRA)
            cFunc_this_shock = LowerEnvelope(
                LinearInterp(mNrm[j, :],
                             cNrm[j, :],
                             intercept_limit=self.hNrmNow * MPCmin_j,
                             slope_limit=MPCmin_j), self.cFuncNowCnst)
            cFunc_list.append(cFunc_this_shock)

        # Combine the list of consumption functions into a single interpolation
        cFuncNow = LinearInterpOnInterp1D(cFunc_list, self.PrefShkVals)

        # Make the ex ante marginal value function (before the preference shock)
        m_grid = self.aXtraGrid + self.mNrmMinNow
        vP_vec = np.zeros_like(m_grid)
        for j in range(
                PrefShkCount):  # numeric integration over the preference shock
            vP_vec += self.uP(cFunc_list[j](
                m_grid)) * self.PrefShkPrbs[j] * self.PrefShkVals[j]
        vPnvrs_vec = self.uPinv(vP_vec)
        vPfuncNow = MargValueFunc(LinearInterp(m_grid, vPnvrs_vec), self.CRRA)

        # Store the results in a solution object and return it
        solution_now = ConsumerSolution(cFunc=cFuncNow,
                                        vPfunc=vPfuncNow,
                                        mNrmMin=self.mNrmMinNow)
        return solution_now
Ejemplo n.º 2
0
def c_future_wealth(fut_period = 1, coh = 1, exo = True):
    c_list = []
    rebate_fut_vals = np.linspace(0, 1, num=11)
    rebate_curr_vals = rebate_fut_vals[1:]
    for rebate_fut in rebate_fut_vals:
        settings.rebate_size = rebate_fut
        settings.init()
        if exo:
            IndShockExample = Model.IndShockConsumerType(**baseline_params)
        else :
            IndShockExample = Model.IndShockConsumerType(**init_natural_borrowing_constraint)
        IndShockExample.solve()
        IndShockExample.unpack_cFunc()
        IndShockExample.timeFwd()
        c_list = np.append(c_list,IndShockExample.cFunc[t_eval-fut_period](coh))
    for rebate_cur in rebate_curr_vals:
        c_list = np.append(c_list,IndShockExample.cFunc[t_eval-fut_period](coh+rebate_cur))
    c_func = LinearInterp(np.linspace(0, 2, num=21),np.array(c_list))             
    return(c_func)
Ejemplo n.º 3
0
 def updateSolutionTerminal(self):
     '''
     Update the terminal period solution.  
     
     Parameters
     ----------
     none
     
     Returns
     -------
     none
     '''
     #self.solution_terminal.vFunc   = ValueFunc(self.cFunc_terminal_,self.CRRA)
     terminal_instance = LinearInterp(np.array([0.0, 100.0]),
                                      np.array([0.01, 0.0]),
                                      lower_extrap=True)
     self.solution_terminal.vPfunc = BilinearInterpOnInterp1D(
         [[terminal_instance, terminal_instance],
          [terminal_instance, terminal_instance]], np.array([0.0, 2.0]),
         np.array([0.0, 2.0]))
Ejemplo n.º 4
0
def solveConsAggShock(solution_next, IncomeDstn, LivPrb, DiscFac, CRRA,
                      PermGroFac, aXtraGrid, kGrid, kNextFunc, Rfunc, wFunc):
    '''
    Solve one period of a consumption-saving problem with idiosyncratic and 
    aggregate shocks (transitory and permanent).  This is a basic solver that
    can't handle borrowing (assumes liquidity constraint) or cubic splines, nor
    can it calculate a value function.
    
    Parameters
    ----------
    solution_next : ConsumerSolution
        The solution to the succeeding one period problem.
    IncomeDstn : [np.array]
        A list containing five arrays of floats, representing a discrete
        approximation to the income process between the period being solved
        and the one immediately following (in solution_next). Order: event
        probabilities, idisyncratic permanent shocks, idiosyncratic transitory
        shocks, aggregate permanent shocks, aggregate transitory shocks.
    LivPrb : float
        Survival probability; likelihood of being alive at the beginning of
        the succeeding period.    
    DiscFac : float
        Intertemporal discount factor for future utility.        
    CRRA : float
        Coefficient of relative risk aversion.
    PermGroFac : float
        Expected permanent income growth factor at the end of this period.
    aXtraGrid : np.array
        Array of "extra" end-of-period asset values-- assets above the
        absolute minimum acceptable level.
    kGrid : np.array
        A grid of capital-to-labor ratios in the economy.
    kNextFunc : function
        Next period's capital-to-labor ratio as a function of this period's ratio.
    Rfunc : function
        The net interest factor on assets as a function of capital ratio k.
    wFunc : function
        The wage rate for labor as a function of capital-to-labor ratio k.
                    
    Returns
    -------
    solution_now : ConsumerSolution
        The solution to the single period consumption-saving problem.  Includes
        a consumption function cFunc (linear interpolation over linear interpola-
        tions) and marginal value function vPfunc.
    '''
    # Unpack next period's solution
    vPfuncNext = solution_next.vPfunc

    # Unpack the income shocks
    ShkPrbsNext = IncomeDstn[0]
    PermShkValsNext = IncomeDstn[1]
    TranShkValsNext = IncomeDstn[2]
    PermShkAggValsNext = IncomeDstn[3]
    TranShkAggValsNext = IncomeDstn[4]
    ShkCount = ShkPrbsNext.size

    # Make the grid of end-of-period asset values, and a tiled version
    aNrmNow = np.insert(aXtraGrid, 0, 0.0)
    aNrmNow_tiled = np.tile(aNrmNow, (ShkCount, 1))
    aCount = aNrmNow.size

    # Make tiled versions of the income shocks
    ShkPrbsNext_tiled = (np.tile(ShkPrbsNext, (aCount, 1))).transpose()
    PermShkValsNext_tiled = (np.tile(PermShkValsNext, (aCount, 1))).transpose()
    TranShkValsNext_tiled = (np.tile(TranShkValsNext, (aCount, 1))).transpose()
    PermShkAggValsNext_tiled = (np.tile(PermShkAggValsNext,
                                        (aCount, 1))).transpose()
    TranShkAggValsNext_tiled = (np.tile(TranShkAggValsNext,
                                        (aCount, 1))).transpose()

    # Loop through the values in kGrid and calculate a linear consumption function for each
    cFuncByK_list = []
    for j in range(kGrid.size):
        kNow = kGrid[j]
        kNext = kNextFunc(kNow)

        # Calculate returns to capital and labor in the next period
        kNextEff_array = kNext / TranShkAggValsNext_tiled
        Reff_array = Rfunc(kNextEff_array) / LivPrb  # Effective interest rate
        wEff_array = wFunc(
            kNextEff_array
        ) * TranShkAggValsNext_tiled  # Effective wage rate (accounts for labor supply)

        # Calculate market resources next period (and a constant array of capital-to-labor ratio)
        PermShkTotal_array = PermGroFac * PermShkValsNext_tiled * PermShkAggValsNext_tiled  # total / combined permanent shock
        mNrmNext_array = Reff_array * aNrmNow_tiled / PermShkTotal_array + TranShkValsNext_tiled * wEff_array
        kNext_array = kNext * np.ones_like(mNrmNext_array)

        # Find marginal value next period at every income shock realization and every asset gridpoint
        vPnext_array = Reff_array * PermShkTotal_array**(-CRRA) * vPfuncNext(
            mNrmNext_array, kNext_array)

        # Calculate expectated marginal value at the end of the period at every asset gridpoint
        EndOfPrdvP = DiscFac * LivPrb * PermGroFac**(-CRRA) * np.sum(
            vPnext_array * ShkPrbsNext_tiled, axis=0)

        # Calculate optimal consumption from each asset gridpoint, and construct a linear interpolation
        cNrmNow = EndOfPrdvP**(-1.0 / CRRA)
        mNrmNow = aNrmNow + cNrmNow
        c_for_interpolation = np.insert(
            cNrmNow, 0, 0.0)  # Add liquidity constrained portion
        m_for_interpolation = np.insert(mNrmNow, 0, 0.0)
        cFuncNow_j = LinearInterp(m_for_interpolation, c_for_interpolation)

        # Add the k-specific consumption function to the list
        cFuncByK_list.append(cFuncNow_j)

    # Construct the overall consumption function by combining the k-specific functions
    cFuncNow = LinearInterpOnInterp1D(cFuncByK_list, kGrid)

    # Construct the marginal value function using the envelope condition
    vPfuncNow = MargValueFunc2D(cFuncNow, CRRA)

    # Pack up and return the solution
    solution_now = ConsumerSolution(cFunc=cFuncNow, vPfunc=vPfuncNow)
    return solution_now
Ejemplo n.º 5
0
    #construct results w default specification for how to set up house prices (neg wealth effect)
    uw_house_params = deepcopy(baseline_params)
    uw_house_params['rebate_amt'], e, uw_house_params['BoroCnstArt'], uw_house_params['HsgPay'] = \
        hsg_wealth(initial_debt =  hamp_params['baseline_debt'], **hamp_params)
    pra_params = deepcopy(baseline_params)
    pra_params['rebate_amt'], e, pra_params['BoroCnstArt'], pra_params['HsgPay'] = \
        hsg_wealth(initial_debt =  hamp_params['baseline_debt'] - hamp_params['pra_forgive'], **hamp_params)
    pra_params['HsgPay'] = pra_pmt(age=45, **hamp_params)

    #slide 3 -- housing equity
    labels = ["Payment Reduction", "Payment & Principal Reduction"]

    def neg(x):
        return -1 * x

    boro_cnst_pre_pra = LinearInterp(
        np.arange(26, 91), list(map(neg, uw_house_params['BoroCnstArt'])))
    boro_cnst_post_pra = LinearInterp(
        np.arange(26, 91), list(map(neg, pra_params['BoroCnstArt'])))

    mpl_funcs([boro_cnst_pre_pra, boro_cnst_post_pra],
              45.001,
              64,
              N=round(64 - 45.001),
              labels=labels,
              title="",
              ser_colors=[
                  "#9ecae1",
                  "#3182bd",
              ],
              loc=(0, 0.7),
              ylab="Borrowing Limit (Years of Income)",
Ejemplo n.º 6
0
def solveFashion(solution_next,DiscFac,conformUtilityFunc,punk_utility,jock_utility,switchcost_J2P,switchcost_P2J,pGrid,pEvolution,pref_shock_mag):
    '''
    Solves a single period of the fashion victim model.
    
    Parameters
    ----------
    solution_next: FashionSolution
        A representation of the solution to the subsequent period's problem.
    DiscFac: float
        The intertemporal discount factor.
    conformUtilityFunc: function
        Utility as a function of the proportion of the population who wears the
        same style as the agent.
    punk_utility: float
        Direct utility from wearing the punk style this period.
    jock_utility: float
        Direct utility from wearing the jock style this period.
    switchcost_J2P: float
        Utility cost of switching from jock to punk this period.
    switchcost_P2J: float
        Utility cost of switching from punk to jock this period.
    pGrid: np.array
        1D array of "proportion of punks" states spanning [0,1], representing
        the fraction of agents *currently* wearing punk style.
    pEvolution: np.array
        2D array representing the distribution of next period's "proportion of
        punks".  The pEvolution[i,:] contains equiprobable values of p for next
        period if p = pGrid[i] today.
    pref_shock_mag: float
        Standard deviation of T1EV preference shocks over style.
           
    Returns
    -------
    solution_now: FashionSolution
        A representation of the solution to this period's problem.
    '''
    # Unpack next period's solution
    VfuncPunkNext = solution_next.VfuncPunk
    VfuncJockNext = solution_next.VfuncJock
    
    # Calculate end-of-period expected value for each style at points on the pGrid
    EndOfPrdVpunk = DiscFac*np.mean(VfuncPunkNext(pEvolution),axis=1)
    EndOfPrdVjock = DiscFac*np.mean(VfuncJockNext(pEvolution),axis=1)
    
    # Get current period utility flow from each style (without switching cost)
    Upunk = punk_utility + conformUtilityFunc(pGrid)
    Ujock = jock_utility + conformUtilityFunc(1.0 - pGrid)
    
    # Calculate choice-conditional value for each combination of current and next styles (at each)
    V_J2J = Ujock                  + EndOfPrdVjock
    V_J2P = Upunk - switchcost_J2P + EndOfPrdVpunk
    V_P2J = Ujock - switchcost_P2J + EndOfPrdVjock
    V_P2P = Upunk                  + EndOfPrdVpunk
    
    # Calculate the beginning-of-period expected value of each p-state when punk
    Vboth_P = np.vstack((V_P2J,V_P2P))
    Vbest_P = np.max(Vboth_P,axis=0)
    Vnorm_P = Vboth_P - np.tile(np.reshape(Vbest_P,(1,pGrid.size)),(2,1))
    ExpVnorm_P = np.exp(Vnorm_P/pref_shock_mag)
    SumExpVnorm_P = np.sum(ExpVnorm_P,axis=0)
    V_P = np.log(SumExpVnorm_P)*pref_shock_mag + Vbest_P
    switch_P = ExpVnorm_P[0,:]/SumExpVnorm_P
    
    # Calculate the beginning-of-period expected value of each p-state when jock
    Vboth_J = np.vstack((V_J2J,V_J2P))
    Vbest_J = np.max(Vboth_J,axis=0)
    Vnorm_J = Vboth_J - np.tile(np.reshape(Vbest_J,(1,pGrid.size)),(2,1))
    ExpVnorm_J = np.exp(Vnorm_J/pref_shock_mag)
    SumExpVnorm_J = np.sum(ExpVnorm_J,axis=0)
    V_J = np.log(SumExpVnorm_J)*pref_shock_mag + Vbest_J
    switch_J = ExpVnorm_J[1,:]/SumExpVnorm_J
    
    # Make value and policy functions for each style
    VfuncPunkNow = LinearInterp(pGrid,V_P)
    VfuncJockNow = LinearInterp(pGrid,V_J)
    switchFuncPunkNow = LinearInterp(pGrid,switch_P)
    switchFuncJockNow = LinearInterp(pGrid,switch_J)
    
    # Make and return this period's solution
    solution_now = FashionSolution(VfuncJock=VfuncJockNow,
                                   VfuncPunk=VfuncPunkNow,
                                   switchFuncJock=switchFuncJockNow,
                                   switchFuncPunk=switchFuncPunkNow)
    return solution_now
Ejemplo n.º 7
0
class FashionVictimType(AgentType):
    '''
    A class for representing types of agents in the fashion victim model.  Agents
    make a binary decision over which style to wear (jock or punk), subject to
    switching costs.  They receive utility directly from their chosen style and
    from the proportion of the population that wears the same style.
    '''
    _solution_terminal = FashionSolution(VfuncJock=LinearInterp(np.array([0.0, 1.0]),np.array([0.0,0.0])),
                                         VfuncPunk=LinearInterp(np.array([0.0, 1.0]),np.array([0.0,0.0])),
                                         switchFuncJock=NullFunc(),
                                         switchFuncPunk=NullFunc())
    
    def __init__(self,**kwds):
        '''
        Instantiate a new FashionVictim with given data.
        
        Parameters
        ----------
        **kwds : keyword arguments
            Any number of keyword arguments key=value; each value will be assigned
            to the attribute key in the new instance.
        
        Returns
        -------
        new instance of FashionVictimType
        '''      
        # Initialize a basic AgentType
        AgentType.__init__(self,solution_terminal=FashionVictimType._solution_terminal,cycles=0,time_flow=True,pseudo_terminal=True,**kwds)
        
        # Add class-specific features
        self.time_inv = ['DiscFac','conformUtilityFunc','punk_utility','jock_utility','switchcost_J2P','switchcost_P2J','pGrid','pEvolution','pref_shock_mag']
        self.time_vary = []
        self.solveOnePeriod = solveFashion
        self.update()
        
    def updateEvolution(self):
        '''
        Updates the "population punk proportion" evolution array.  Fasion victims
        believe that the proportion of punks in the subsequent period is a linear
        function of the proportion of punks this period, subject to a uniform
        shock.  Given attributes of self pNextIntercept, pNextSlope, pNextCount,
        pNextWidth, and pGrid, this method generates a new array for the attri-
        bute pEvolution, representing a discrete approximation of next period
        states for each current period state in pGrid.
        
        Parameters
        ----------
        none
        
        Returns
        -------
        none
        '''
        self.pEvolution = np.zeros((self.pCount,self.pNextCount))
        for j in range(self.pCount):
            pNow = self.pGrid[j]
            pNextMean = self.pNextIntercept + self.pNextSlope*pNow
            dist = approxUniform(N=self.pNextCount,bot=pNextMean-self.pNextWidth,top=pNextMean+self.pNextWidth)[1]
            self.pEvolution[j,:] = dist
        
    def update(self):
        '''
        Updates the non-primitive objects needed for solution, using primitive
        attributes.  This includes defining a "utility from conformity" function
        conformUtilityFunc, a grid of population punk proportions, and an array
        of future punk proportions (for each value in the grid).  Results are
        stored as attributes of self.
        
        Parameters
        ----------
        none
        
        Returns
        -------
        none
        '''
        self.conformUtilityFunc = lambda x : stats.beta.pdf(x,self.uParamA,self.uParamB)
        self.pGrid = np.linspace(0.0001,0.9999,self.pCount)
        self.updateEvolution()
            
    def reset(self):
        '''
        Resets this agent type to prepare it for a new simulation run.  This
        includes resetting the random number generator and initializing the style
        of each agent of this type.
        '''
        self.resetRNG()
        sNow = np.zeros(self.pop_size)
        Shk  = self.RNG.rand(self.pop_size)
        sNow[Shk < self.p_init] = 1
        self.sNow = sNow
        
    def preSolve(self):
        '''
        Updates the punk proportion evolution array by calling self.updateEvolution().
        
        Parameters
        ----------
        none
        
        Returns
        -------
        none
        '''
        # This step is necessary in the general equilibrium framework, where a
        # new evolution rule is calculated after each simulation run, but only
        # the sufficient statistics describing it are sent back to agents.
        self.updateEvolution()
            
    def postSolve(self):
        '''
        Unpack the behavioral and value functions for more parsimonious access.
        
        Parameters
        ----------
        none
        
        Returns
        -------
        none
        '''
        self.switchFuncPunk = self.solution[0].switchFuncPunk
        self.switchFuncJock = self.solution[0].switchFuncJock
        self.VfuncPunk      = self.solution[0].VfuncPunk
        self.VfuncJock      = self.solution[0].VfuncJock
        
    def simOnePrd(self):
        '''
        Simulate one period of the fashion victom model for this type.  Each
        agent receives an idiosyncratic preference shock and chooses whether to
        change styles (using the optimal decision rule).
        
        Parameters
        ----------
        none
        
        Returns
        -------
        none
        '''
        pNow    = self.pNow
        sPrev   = self.sNow
        J2Pprob = self.switchFuncJock(pNow)
        P2Jprob = self.switchFuncPunk(pNow)
        Shks    = self.RNG.rand(self.pop_size)
        J2P     = np.logical_and(sPrev == 0,Shks < J2Pprob)
        P2J     = np.logical_and(sPrev == 1,Shks < P2Jprob)
        sNow    = copy(sPrev)
        sNow[J2P] = 1
        sNow[P2J] = 0
        self.sNow = sNow
        
    def marketAction(self):
        '''
        The "market action" for a FashionType in the general equilibrium setting.
        Simulates a single period using self.simOnePrd().
        
        Parameters
        ----------
        none
        
        Returns
        -------
        none
        '''
        self.simOnePrd()
Ejemplo n.º 8
0
def solveConsAggShock(solution_next, IncomeDstn, LivPrb, DiscFac, CRRA,
                      PermGroFac, aXtraGrid, BoroCnstArt, Mgrid, AFunc, Rfunc,
                      wFunc, DeprFac):
    '''
    Solve one period of a consumption-saving problem with idiosyncratic and 
    aggregate shocks (transitory and permanent).  This is a basic solver that
    can't handle borrowing (assumes liquidity constraint) or cubic splines, nor
    can it calculate a value function.
    
    Parameters
    ----------
    solution_next : ConsumerSolution
        The solution to the succeeding one period problem.
    IncomeDstn : [np.array]
        A list containing five arrays of floats, representing a discrete
        approximation to the income process between the period being solved
        and the one immediately following (in solution_next). Order: event
        probabilities, idisyncratic permanent shocks, idiosyncratic transitory
        shocks, aggregate permanent shocks, aggregate transitory shocks.
    LivPrb : float
        Survival probability; likelihood of being alive at the beginning of
        the succeeding period.    
    DiscFac : float
        Intertemporal discount factor for future utility.        
    CRRA : float
        Coefficient of relative risk aversion.
    PermGroGac : float
        Expected permanent income growth factor at the end of this period.
    aXtraGrid : np.array
        Array of "extra" end-of-period asset values-- assets above the
        absolute minimum acceptable level.
    BoroCnstArt : float
        Artificial borrowing constraint; minimum allowable end-of-period asset-to-
        permanent-income ratio.  Unlike other models, this *can't* be None.
    Mgrid : np.array
        A grid of aggregate market resourses to permanent income in the economy.
    AFunc : function
        Aggregate savings as a function of aggregate market resources.
    Rfunc : function
        The net interest factor on assets as a function of capital ratio k.
    wFunc : function
        The wage rate for labor as a function of capital-to-labor ratio k.
    DeprFac : float
        Capital Depreciation Rate
                    
    Returns
    -------
    solution_now : ConsumerSolution
        The solution to the single period consumption-saving problem.  Includes
        a consumption function cFunc (linear interpolation over linear interpola-
        tions) and marginal value function vPfunc.
    '''
    # Unpack next period's solution
    vPfuncNext = solution_next.vPfunc
    mNrmMinNext = solution_next.mNrmMin

    # Unpack the income shocks
    ShkPrbsNext = IncomeDstn[0]
    PermShkValsNext = IncomeDstn[1]
    TranShkValsNext = IncomeDstn[2]
    PermShkAggValsNext = IncomeDstn[3]
    TranShkAggValsNext = IncomeDstn[4]
    ShkCount = ShkPrbsNext.size

    # Make the grid of end-of-period asset values, and a tiled version
    aNrmNow = np.insert(aXtraGrid, 0, 0.0)
    aNrmNow_tiled = np.tile(aNrmNow, (ShkCount, 1))
    aCount = aNrmNow.size

    # Make tiled versions of the income shocks
    ShkPrbsNext_tiled = (np.tile(ShkPrbsNext, (aCount, 1))).transpose()
    PermShkValsNext_tiled = (np.tile(PermShkValsNext, (aCount, 1))).transpose()
    TranShkValsNext_tiled = (np.tile(TranShkValsNext, (aCount, 1))).transpose()
    PermShkAggValsNext_tiled = (np.tile(PermShkAggValsNext,
                                        (aCount, 1))).transpose()
    TranShkAggValsNext_tiled = (np.tile(TranShkAggValsNext,
                                        (aCount, 1))).transpose()

    # Loop through the values in Mgrid and calculate a linear consumption function for each
    cFuncBaseByM_list = []
    BoroCnstNat_array = np.zeros(Mgrid.size)
    mNrmMinNext_array = mNrmMinNext(AFunc(Mgrid) * (1 - DeprFac))
    for j in range(Mgrid.size):
        MNow = Mgrid[j]
        AaggNow = AFunc(MNow)

        # Calculate returns to capital and labor in the next period
        kNext_array = AaggNow * (1 - DeprFac) / (
            PermGroFac * PermShkAggValsNext_tiled * TranShkAggValsNext_tiled)
        kNextEff_array = kNext_array / TranShkAggValsNext_tiled
        R_array = Rfunc(kNextEff_array)  # Interest factor on aggregate assets
        Reff_array = R_array / LivPrb  # Effective interest factor on individual assets *for survivors*
        wEff_array = wFunc(
            kNextEff_array
        ) * TranShkAggValsNext_tiled  # Effective wage rate (accounts for labor supply)
        PermShkTotal_array = PermGroFac * PermShkValsNext_tiled * PermShkAggValsNext_tiled  # total / combined permanent shock
        Mnext_array = kNext_array * (R_array + DeprFac) + wEff_array

        # Find the natural borrowing constraint for this capital-to-labor ratio
        aNrmMin_candidates = PermGroFac * PermShkValsNext * PermShkAggValsNext / Reff_array[:, 0] * (
            mNrmMinNext_array[j] - wEff_array[:, 0] * TranShkValsNext)
        aNrmMin = np.max(aNrmMin_candidates)
        BoroCnstNat = aNrmMin
        BoroCnstNat_array[j] = BoroCnstNat

        # Calculate market resources next period (and a constant array of capital-to-labor ratio)
        mNrmNext_array = Reff_array * (
            aNrmNow_tiled +
            aNrmMin) / PermShkTotal_array + TranShkValsNext_tiled * wEff_array

        # Find marginal value next period at every income shock realization and every aggregate market resource gridpoint
        vPnext_array = Reff_array * PermShkTotal_array**(-CRRA) * vPfuncNext(
            mNrmNext_array, Mnext_array)

        # Calculate expectated marginal value at the end of the period at every asset gridpoint
        EndOfPrdvP = DiscFac * LivPrb * PermGroFac**(-CRRA) * np.sum(
            vPnext_array * ShkPrbsNext_tiled, axis=0)

        # Calculate optimal consumption from each asset gridpoint, and construct a linear interpolation
        cNrmNow = EndOfPrdvP**(-1.0 / CRRA)
        mNrmNow = (aNrmNow + aNrmMin) + cNrmNow
        c_for_interpolation = np.insert(
            cNrmNow, 0, 0.0)  # Add liquidity constrained portion
        m_for_interpolation = np.insert(mNrmNow - BoroCnstNat, 0, 0.0)
        cFuncBase_j = LinearInterp(m_for_interpolation, c_for_interpolation)

        # Add the M-specific consumption function to the list
        cFuncBaseByM_list.append(cFuncBase_j)

    # Construct the overall unconstrained consumption function by combining the M-specific functions
    BoroCnstNat = LinearInterp(np.insert(Mgrid, 0, 0.0),
                               np.insert(BoroCnstNat_array, 0, 0.0))
    cFuncBase = LinearInterpOnInterp1D(cFuncBaseByM_list, Mgrid)
    cFuncUnc = VariableLowerBoundFunc2D(cFuncBase, BoroCnstNat)

    # Make the constrained consumption function and combine it with the unconstrained component
    cFuncCnst = BilinearInterp(np.array([[0.0, 0.0], [1.0, 1.0]]),
                               np.array([BoroCnstArt, BoroCnstArt + 1.0]),
                               np.array([0.0, 1.0]))
    cFuncNow = LowerEnvelope2D(cFuncUnc, cFuncCnst)

    # Make the minimum m function as the greater of the natural and artificial constraints
    mNrmMinNow = UpperEnvelope(BoroCnstNat, ConstantFunction(BoroCnstArt))

    # Construct the marginal value function using the envelope condition
    vPfuncNow = MargValueFunc2D(cFuncNow, CRRA)

    # Pack up and return the solution
    solution_now = ConsumerSolution(cFunc=cFuncNow,
                                    vPfunc=vPfuncNow,
                                    mNrmMin=mNrmMinNow)
    return solution_now
Ejemplo n.º 9
0
def consumptionSavingSolverLinear(solution_tp1, income_distrib, p_zero_income,
                                  survival_prob, beta, rho, R, Gamma,
                                  constrained, a_grid):
    '''
    Solves a single period of a standard consumption-saving problem, representing
    the consumption function as piecewise linear interpolation.

    Parameters:
    -----------
    solution_tp1: ConsumerSolution
        The solution to the following period, likely generated by another call to SolveAPeriodConsumptionSaving.
    income_distrib: [[float]]
        A list containing three lists of floats, representing a discrete approximation to the income process between
        the period being solved and the one immediately following (in Solution_tp1).  Order: psi, xi, probs
    p_zero_income: float
        The probability of receiving zero income in the succeeding period.
    survival_prob: float
        Probability of surviving to succeeding period.
    beta: float
        Discount factor between this period and the succeeding period.
    rho: float
        The coefficient of relative risk aversion
    R: float
        Interest factor on assets between this period and the succeeding period: w_tp1 = a_t*R
    Gamma: float
        Expected growth factor for permanent income between this period and the succeeding period.
    constrained: bool
        Whether this individual may hold net negative assets at the end of the period.
    a_grid: [float]
        A list of end-of-period asset values (post-decision states) at which to solve for optimal consumption.

    Returns:
    -----------
    Solution_t: ConsumerSolution
        The solution to this period's problem, obtained using the method of endogenous gridpoints.
    '''

    # Define utility functions
    u = lambda c: utility(c, gam=rho
                          )  # currently unused, potentially useful for vFunc
    uP = lambda c: utilityP(c, gam=rho)
    uPinv = lambda u: utilityP_inv(u, gam=rho)

    # Set and update values for this period
    effective_beta = beta * survival_prob
    psi_tp1 = income_distrib[0]
    xi_tp1 = income_distrib[1]
    prob_tp1 = income_distrib[2]
    cFunc_tp1 = solution_tp1.cFunc
    psi_underbar_tp1 = np.min(psi_tp1)
    xi_underbar_tp1 = np.min(xi_tp1)

    # Calculate the minimum allowable value of money resources in this period
    if constrained:
        m_underbar_t = 0.0
    else:
        m_underbar_t = (solution_tp1.m_underbar -
                        xi_underbar_tp1) * (Gamma * psi_underbar_tp1) / R

    # Define the borrowing constraint (limiting consumption function)
    constraint_t = lambda m: m - m_underbar_t

    # Find the unconstrained consumption function one step back
    c_temp = [0.0
              ]  # Limiting consumption is zero as m approaches m lower bound
    m_temp = [m_underbar_t]
    a = np.asarray(a_grid) + m_underbar_t
    a_N = a.size
    shock_N = xi_tp1.size
    a_temp = np.tile(a, (shock_N, 1))
    psi_temp = (np.tile(psi_tp1, (a_N, 1))).transpose()
    xi_temp = (np.tile(xi_tp1, (a_N, 1))).transpose()
    prob_temp = (np.tile(prob_tp1, (a_N, 1))).transpose()
    m_tp1 = R / (Gamma * psi_temp) * a_temp + xi_temp
    c_tp1 = cFunc_tp1(m_tp1)
    C_tp1 = psi_temp * c_tp1
    gothicvP = effective_beta * R * Gamma**(-rho) * np.sum(
        uP(C_tp1) * prob_temp, axis=0)
    c = uPinv(gothicvP)
    m = c + a
    c_temp += c.tolist()
    m_temp += m.tolist()
    cFunc_t_unconstrained = LinearInterp(m_temp, c_temp)

    # Combine the constrained and unconstrained functions into the true consumption function
    cFunc_t = ConstrainedComposite(cFunc_t_unconstrained, constraint_t)

    # Store the results in a solution object and return it
    solution_t = ConsumerSolution(cFunc=cFunc_t, m_underbar=m_underbar_t)
    return solution_t
Ejemplo n.º 10
0
def solveConsRepAgent(solution_next, DiscFac, CRRA, IncomeDstn, CapShare,
                      DeprFac, PermGroFac, aXtraGrid):
    '''
    Solve one period of the simple representative agent consumption-saving model.
    
    Parameters
    ----------
    solution_next : ConsumerSolution
        Solution to the next period's problem (i.e. previous iteration). 
    DiscFac : float
        Intertemporal discount factor for future utility.        
    CRRA : float
        Coefficient of relative risk aversion.
    IncomeDstn : [np.array]
        A list containing three arrays of floats, representing a discrete
        approximation to the income process between the period being solved
        and the one immediately following (in solution_next). Order: event
        probabilities, permanent shocks, transitory shocks.
    CapShare : float
        Capital's share of income in Cobb-Douglas production function.
    DeprFac : float
        Depreciation rate of capital.
    PermGroFac : float
        Expected permanent income growth factor at the end of this period.
    aXtraGrid : np.array
        Array of "extra" end-of-period asset values-- assets above the
        absolute minimum acceptable level.  In this model, the minimum acceptable
        level is always zero.
        
    Returns
    -------
    solution_now : ConsumerSolution
        Solution to this period's problem (new iteration).
    '''
    # Unpack next period's solution and the income distribution
    vPfuncNext = solution_next.vPfunc
    ShkPrbsNext = IncomeDstn[0]
    PermShkValsNext = IncomeDstn[1]
    TranShKValsNext = IncomeDstn[2]

    # Make tiled versions of end-of-period assets, shocks, and probabilities
    aNrmNow = aXtraGrid
    aNrmCount = aNrmNow.size
    ShkCount = ShkPrbsNext.size
    aNrm_tiled = np.tile(np.reshape(aNrmNow, (aNrmCount, 1)), (1, ShkCount))

    # Tile arrays of the income shocks and put them into useful shapes
    PermShkVals_tiled = np.tile(np.reshape(PermShkValsNext, (1, ShkCount)),
                                (aNrmCount, 1))
    TranShkVals_tiled = np.tile(np.reshape(TranShKValsNext, (1, ShkCount)),
                                (aNrmCount, 1))
    ShkPrbs_tiled = np.tile(np.reshape(ShkPrbsNext, (1, ShkCount)),
                            (aNrmCount, 1))

    # Calculate next period's capital-to-permanent-labor ratio under each combination
    # of end-of-period assets and shock realization
    kNrmNext = aNrm_tiled / (PermGroFac * PermShkVals_tiled)

    # Calculate next period's market resources
    KtoLnext = kNrmNext / TranShkVals_tiled
    RfreeNext = 1. - DeprFac + CapShare * KtoLnext**(CapShare - 1.)
    wRteNext = (1. - CapShare) * KtoLnext**CapShare
    mNrmNext = RfreeNext * kNrmNext + wRteNext * TranShkVals_tiled

    # Calculate end-of-period marginal value of assets for the RA
    vPnext = vPfuncNext(mNrmNext)
    EndOfPrdvP = DiscFac * np.sum(
        RfreeNext *
        (PermGroFac * PermShkVals_tiled)**(-CRRA) * vPnext * ShkPrbs_tiled,
        axis=1)

    # Invert the first order condition to get consumption, then find endogenous gridpoints
    cNrmNow = EndOfPrdvP**(-1. / CRRA)
    mNrmNow = aNrmNow + cNrmNow

    # Construct the consumption function and the marginal value function
    cFuncNow = LinearInterp(np.insert(mNrmNow, 0, 0.0),
                            np.insert(cNrmNow, 0, 0.0))
    vPfuncNow = MargValueFunc(cFuncNow, CRRA)

    # Construct and return the solution for this period
    solution_now = ConsumerSolution(cFunc=cFuncNow, vPfunc=vPfuncNow)
    return solution_now
Ejemplo n.º 11
0
def solveConsRepAgentMarkov(solution_next, MrkvArray, DiscFac, CRRA,
                            IncomeDstn, CapShare, DeprFac, PermGroFac,
                            aXtraGrid):
    '''
    Solve one period of the simple representative agent consumption-saving model.
    This version supports a discrete Markov process.
    
    Parameters
    ----------
    solution_next : ConsumerSolution
        Solution to the next period's problem (i.e. previous iteration). 
    MrkvArray : np.array
        Markov transition array between this period and next period.
    DiscFac : float
        Intertemporal discount factor for future utility.        
    CRRA : float
        Coefficient of relative risk aversion.
    IncomeDstn : [[np.array]]
        A list of lists containing three arrays of floats, representing a discrete
        approximation to the income process between the period being solved
        and the one immediately following (in solution_next). Order: event
        probabilities, permanent shocks, transitory shocks.
    CapShare : float
        Capital's share of income in Cobb-Douglas production function.
    DeprFac : float
        Depreciation rate of capital.
    PermGroFac : [float]
        Expected permanent income growth factor for each state we could be in
        next period.
    aXtraGrid : np.array
        Array of "extra" end-of-period asset values-- assets above the
        absolute minimum acceptable level.  In this model, the minimum acceptable
        level is always zero.
        
    Returns
    -------
    solution_now : ConsumerSolution
        Solution to this period's problem (new iteration).
    '''
    # Define basic objects
    StateCount = MrkvArray.shape[0]
    aNrmNow = aXtraGrid
    aNrmCount = aNrmNow.size
    EndOfPrdvP_cond = np.zeros((StateCount, aNrmCount)) + np.nan

    # Loop over *next period* states, calculating conditional EndOfPrdvP
    for j in range(StateCount):
        # Define next-period-state conditional objects
        vPfuncNext = solution_next.vPfunc[j]
        ShkPrbsNext = IncomeDstn[j][0]
        PermShkValsNext = IncomeDstn[j][1]
        TranShKValsNext = IncomeDstn[j][2]

        # Make tiled versions of end-of-period assets, shocks, and probabilities
        ShkCount = ShkPrbsNext.size
        aNrm_tiled = np.tile(np.reshape(aNrmNow, (aNrmCount, 1)),
                             (1, ShkCount))

        # Tile arrays of the income shocks and put them into useful shapes
        PermShkVals_tiled = np.tile(np.reshape(PermShkValsNext, (1, ShkCount)),
                                    (aNrmCount, 1))
        TranShkVals_tiled = np.tile(np.reshape(TranShKValsNext, (1, ShkCount)),
                                    (aNrmCount, 1))
        ShkPrbs_tiled = np.tile(np.reshape(ShkPrbsNext, (1, ShkCount)),
                                (aNrmCount, 1))

        # Calculate next period's capital-to-permanent-labor ratio under each combination
        # of end-of-period assets and shock realization
        kNrmNext = aNrm_tiled / (PermGroFac[j] * PermShkVals_tiled)

        # Calculate next period's market resources
        KtoLnext = kNrmNext / TranShkVals_tiled
        RfreeNext = 1. - DeprFac + CapShare * KtoLnext**(CapShare - 1.)
        wRteNext = (1. - CapShare) * KtoLnext**CapShare
        mNrmNext = RfreeNext * kNrmNext + wRteNext * TranShkVals_tiled

        # Calculate end-of-period marginal value of assets for the RA
        vPnext = vPfuncNext(mNrmNext)
        EndOfPrdvP_cond[j, :] = DiscFac * np.sum(
            RfreeNext * (PermGroFac[j] * PermShkVals_tiled)**(-CRRA) * vPnext *
            ShkPrbs_tiled,
            axis=1)

    # Apply the Markov transition matrix to get unconditional end-of-period marginal value
    EndOfPrdvP = np.dot(MrkvArray, EndOfPrdvP_cond)

    # Construct the consumption function and marginal value function for each discrete state
    cFuncNow_list = []
    vPfuncNow_list = []
    for i in range(StateCount):
        # Invert the first order condition to get consumption, then find endogenous gridpoints
        cNrmNow = EndOfPrdvP[i, :]**(-1. / CRRA)
        mNrmNow = aNrmNow + cNrmNow

        # Construct the consumption function and the marginal value function
        cFuncNow_list.append(
            LinearInterp(np.insert(mNrmNow, 0, 0.0),
                         np.insert(cNrmNow, 0, 0.0)))
        vPfuncNow_list.append(MargValueFunc(cFuncNow_list[-1], CRRA))

    # Construct and return the solution for this period
    solution_now = ConsumerSolution(cFunc=cFuncNow_list, vPfunc=vPfuncNow_list)
    return solution_now
Ejemplo n.º 12
0
for ltv in ltv_rows:
    mtg_params = hsg_params(params_u, ltv=ltv, pra=True)
    agent_nd = solve_unpack(mtg_params)
    m_star, share_default = default_rate_solved(v_def_stig_tmp, agent_nd)
    m_u_pra_list.append(m_star)
    if ltv <= 100: share_default = 0
    def_u_pra_list.append(share_default)

    mtg_params = hsg_params(params_std, ltv=ltv, pra=True)
    agent_nd = solve_unpack(mtg_params)
    m_star, share_default = default_rate_solved(v_def_stig_std, agent_nd)
    m_std_pra_list.append(m_star)
    if ltv <= 100: share_default = 0
    def_std_pra_list.append(share_default)

mstar_u_pra_f = LinearInterp(ltv_rows, np.array(m_u_pra_list))
def_u_pra_f = LinearInterp(ltv_rows, np.array(def_u_pra_list))

mstar_std_pra_f = LinearInterp(ltv_rows, np.array(m_std_pra_list))
def_std_pra_f = LinearInterp(ltv_rows, np.array(def_std_pra_list))

labels = ["Model: Baseline", "Model: Match Xsec Correlation"]
labels_main = ["Baseline"]

g = mpl_funcs([def_u_pra_f],
              min(ltv_rows),
              max(ltv_rows) + 10,
              N=len(ltv_rows),
              ser_colors=["#9ecae1"],
              show_legend=False,
              title="",
Ejemplo n.º 13
0
class PrefLaborConsumerType(IndShockConsumerType):
    '''
    A consumer type with idiosyncratic shocks to permanent and transitory income,
    as well as shocks to preferences
    '''
    # Define some universal values for all consumer types
    cFunc_terminal_ = BilinearInterpOnInterp1D(
        [[
            LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0])),
            LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0]))
        ],
         [
             LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0])),
             LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0]))
         ]], np.array([0.0, 1.0]), np.array([0.0,
                                             1.0]))  # c=m in terminal period
    vFunc_terminal_ = BilinearInterpOnInterp1D(
        [[
            LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0])),
            LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0]))
        ],
         [
             LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0])),
             LinearInterp(np.array([0.0, 1.0]), np.array([0.0, 1.0]))
         ]], np.array([0.0, 1.0]), np.array([0.0, 1.0]))  # This is overwritten
    solution_terminal_ = ConsumerSolution(cFunc=cFunc_terminal_,
                                          vFunc=vFunc_terminal_)
    time_inv_ = PerfForesightConsumerType.time_inv_ + [
        'LaborElas', 'PrefShkVals', 'WageShkVals'
    ]
    shock_vars_ = ['PermShkNow', 'TranShkNow', 'PrefShkNow']

    def __init__(self, cycles=1, time_flow=True, **kwds):
        '''
        Instantiate a new ConsumerType with given data.
        See ConsumerParameters.init_idiosyncratic_shocks for a dictionary of
        the keywords that should be passed to the constructor.
        
        Parameters
        ----------
        cycles : int
            Number of times the sequence of periods should be solved.
        time_flow : boolean
            Whether time is currently "flowing" forward for this instance.
        
        Returns
        -------
        None
        '''
        # Initialize a basic AgentType
        IndShockConsumerType.__init__(self,
                                      cycles=cycles,
                                      time_flow=time_flow,
                                      **kwds)

        # Add consumer-type specific objects, copying to create independent versions
        self.solveOnePeriod = solvePrefLaborShock  # idiosyncratic shocks solver
        self.update()  # Make assets grid, income process, terminal solution

    def reset(self):
        self.initializeSim()
        self.t_age = drawDiscrete(self.AgentCount,
                                  P=self.AgeDstn,
                                  X=np.arange(self.AgeDstn.size),
                                  exact_match=False,
                                  seed=self.RNG.randint(0,
                                                        2**31 - 1)).astype(int)
        self.t_cycle = copy(self.t_age)

    def marketAction(self):
        self.simulate(1)

    def updateIncomeProcess(self):
        '''
        Updates this agent's income process based on his own attributes.  The
        function that generates the discrete income process can be swapped out
        for a different process.
        
        Parameters
        ----------
        none
        
        Returns:
        -----------
        none
        '''
        original_time = self.time_flow
        self.timeFwd()
        IncomeAndPrefDstn, PermShkDstn, TranShkDstn, PrefShkDstn = constructLognormalIncomeAndPreferenceProcess(
            self)
        self.IncomeAndPrefDstn = IncomeAndPrefDstn
        self.PermShkDstn = PermShkDstn
        self.TranShkDstn = TranShkDstn
        self.PrefShkDstn = TranShkDstn
        self.PrefShkVals = PrefShkDstn[0][1]
        self.WageShkVals = TranShkDstn[0][1]
        self.addToTimeVary('IncomeAndPrefDstn', 'PermShkDstn', 'TranShkDstn',
                           'PrefShkDstn')
        if not original_time:
            self.timeRev()

    def updateSolutionTerminal(self):
        '''
        Update the terminal period solution.  
        
        Parameters
        ----------
        none
        
        Returns
        -------
        none
        '''
        #self.solution_terminal.vFunc   = ValueFunc(self.cFunc_terminal_,self.CRRA)
        terminal_instance = LinearInterp(np.array([0.0, 100.0]),
                                         np.array([0.01, 0.0]),
                                         lower_extrap=True)
        self.solution_terminal.vPfunc = BilinearInterpOnInterp1D(
            [[terminal_instance, terminal_instance],
             [terminal_instance, terminal_instance]], np.array([0.0, 2.0]),
            np.array([0.0, 2.0]))
        #self.solution_terminal.vPPfunc = MargMargValueFunc(self.cFunc_terminal_,self.CRRA)

    def getShocks(self):
        '''
        Gets permanent and transitory income shocks for this period.  Samples from IncomeDstn for
        each period in the cycle.
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        '''
        PermShkNow = np.zeros(self.AgentCount)  # Initialize shock arrays
        TranShkNow = np.zeros(self.AgentCount)
        PrefShkNow = np.zeros(self.AgentCount)
        newborn = self.t_age == 0
        for t in range(self.T_cycle):
            these = t == self.t_cycle
            N = np.sum(these)
            if N > 0:
                IncomeDstnNow = self.IncomeAndPrefDstn[
                    t - 1]  # set current income distribution
                PermGroFacNow = self.PermGroFac[
                    t - 1]  # and permanent growth factor
                Indices = np.arange(
                    IncomeDstnNow[0].size)  # just a list of integers
                # Get random draws of income shocks from the discrete distribution
                EventDraws = drawDiscrete(N,
                                          X=Indices,
                                          P=IncomeDstnNow[0],
                                          exact_match=False,
                                          seed=self.RNG.randint(0, 2**31 - 1))
                PermShkNow[these] = IncomeDstnNow[1][
                    EventDraws] * PermGroFacNow  # permanent "shock" includes expected growth
                TranShkNow[these] = IncomeDstnNow[2][EventDraws]
                PrefShkNow[these] = IncomeDstnNow[3][EventDraws]

        # That procedure used the *last* period in the sequence for newborns, but that's not right
        # Redraw shocks for newborns, using the *first* period in the sequence.  Approximation.
        N = np.sum(newborn)
        if N > 0:
            these = newborn
            IncomeDstnNow = self.IncomeAndPrefDstn[
                0]  # set current income distribution
            PermGroFacNow = self.PermGroFac[0]  # and permanent growth factor
            Indices = np.arange(
                IncomeDstnNow[0].size)  # just a list of integers
            # Get random draws of income shocks from the discrete distribution
            EventDraws = drawDiscrete(N,
                                      X=Indices,
                                      P=IncomeDstnNow[0],
                                      exact_match=False,
                                      seed=self.RNG.randint(0, 2**31 - 1))
            PermShkNow[these] = IncomeDstnNow[1][
                EventDraws] * PermGroFacNow  # permanent "shock" includes expected growth
            TranShkNow[these] = IncomeDstnNow[2][EventDraws]
            PrefShkNow[these] = IncomeDstnNow[3][EventDraws]
#        PermShkNow[newborn] = 1.0
        TranShkNow[newborn] = 1.0

        # Store the shocks in self
        self.EmpNow = np.ones(self.AgentCount, dtype=bool)
        self.EmpNow[TranShkNow == self.IncUnemp] = False
        self.PermShkNow = PermShkNow
        self.TranShkNow = TranShkNow
        self.PrefShkNow = PrefShkNow

    def getStates(self):
        '''
        Calculates updated values of normalized market resources and permanent income level for each
        agent.  Uses pLvlNow, aNrmNow, PermShkNow, TranShkNow.
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        '''
        pLvlPrev = self.pLvlNow
        aNrmPrev = self.aNrmNow
        RfreeNow = self.getRfree()

        # Calculate new states: normalized market resources and permanent income level
        self.pLvlNow = pLvlPrev * self.PermShkNow  # Updated permanent income level
        ReffNow = RfreeNow / self.PermShkNow  # "Effective" interest factor on normalized assets
        self.bNrmNow = ReffNow * aNrmPrev  # Bank balances before labor income
        return None

    def getControls(self):
        '''
        Calculates consumption for each consumer of this type using the consumption functions.
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        '''
        cNrmNow = np.zeros(self.AgentCount) + np.nan
        MPCnow = np.zeros(self.AgentCount) + np.nan
        lNow = np.zeros(self.AgentCount) + np.nan
        for t in range(self.T_cycle):
            these = t == self.t_cycle
            cNrmNow[these] = self.solution[t].cFunc(self.bNrmNow[these],
                                                    self.TranShkNow,
                                                    self.PrefShkNow)
            MPCnow[these] = self.solution[t].cFunc.derivativeX(
                self.bNrmNow[these], self.TranShkNow, self.PrefShkNow)
            lNow[these] = self.solution[t].lFunc(self.bNrmNow[these],
                                                 self.TranShkNow,
                                                 self.PrefShkNow)
        self.cNrmNow = cNrmNow
        self.MPCnow = MPCnow
        self.lNow = lNow
        self.lIncomeLvl = lNow * self.TranShkNow * self.pLvlNow
        self.cLvlNow = cNrmNow * self.pLvlNow
        return None

    def getPostStates(self):
        '''
        Calculates end-of-period assets for each consumer of this type.
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        '''
        self.aNrmNow = self.bNrmNow + self.lNow * self.TranShkNow - self.cNrmNow
        self.aLvlNow = self.aNrmNow * self.pLvlNow  # Useful in some cases to precalculate asset level
        return None
Ejemplo n.º 14
0
    def makeBasicSolution(self, EndOfPrdvP, aNrm, wageShkVals, prefShkVals):
        '''
        Given end of period assets and end of period marginal value, construct
        the basic solution for this period.
        
        Parameters
        ----------
        EndOfPrdvP : np.array
            Array of end-of-period marginal values.
        aNrm : np.array
            Array of end-of-period asset values that yield the marginal values
            in EndOfPrdvP.
        wageShkVals : np.array
            Array of this period transitory wage shock values.
        prefShkVals : np.array
            Array of this period preference shock values.
            
        Returns
        -------
        solution_now : ConsumerSolution
            The solution to this period's consumption-saving problem, with a
            consumption function, marginal value function.
        '''
        num_pref_shocks = len(prefShkVals)
        num_wage_shocks = len(wageShkVals)
        cFuncBaseByPref_list = []
        vPFuncBaseByPref_list = []
        lFuncBaseByPref_list = []
        for i in range(num_wage_shocks):
            cFuncBaseByPref_list.append([])
            vPFuncBaseByPref_list.append([])
            lFuncBaseByPref_list.append([])
            for j in range(num_pref_shocks):
                c_temp = self.uPinv(EndOfPrdvP / prefShkVals[j])
                l_temp = self.LabSupply(wageShkVals[i] * EndOfPrdvP)
                b_temp = c_temp + aNrm - l_temp * wageShkVals[i]

                if wageShkVals[i] == 0.0:
                    c_temp = np.insert(c_temp, 0, 0., axis=-1)
                    l_temp = np.insert(l_temp, 0, 0.0, axis=-1)
                    b_temp = np.insert(b_temp, 0, 0.0, axis=-1)

                lFuncBaseByPref_list[i].append(
                    LinearInterp(b_temp, l_temp, lower_extrap=True))
                cFunc1 = LinearInterp(b_temp, c_temp, lower_extrap=True)
                cFunc2 = LinearInterp(b_temp,
                                      l_temp * wageShkVals[i] + b_temp,
                                      lower_extrap=True)
                cFuncBaseByPref_list[i].append(LowerEnvelope(cFunc1, cFunc2))

                pseudo_inverse_vPfunc1 = LinearInterp(
                    b_temp,
                    prefShkVals[j]**(-1.0 / self.CRRA) * c_temp,
                    lower_extrap=True)
                pseudo_inverse_vPfunc2 = LinearInterp(
                    b_temp,
                    prefShkVals[j]**(-1.0 / self.CRRA) *
                    (l_temp * wageShkVals[i] + b_temp),
                    lower_extrap=True)
                pseudo_inverse_vPfunc = LowerEnvelope(pseudo_inverse_vPfunc1,
                                                      pseudo_inverse_vPfunc2)

                vPFuncBaseByPref_list[i].append(
                    MargValueFunc(pseudo_inverse_vPfunc, self.CRRA))

        cFuncNow = BilinearInterpOnInterp1D(cFuncBaseByPref_list, wageShkVals,
                                            prefShkVals)
        vPfuncNow = BilinearInterpOnInterp1D(vPFuncBaseByPref_list,
                                             wageShkVals, prefShkVals)
        lFuncNow = BilinearInterpOnInterp1D(lFuncBaseByPref_list, wageShkVals,
                                            prefShkVals)

        # Pack up and return the solution
        solution_now = ConsumerSolution(cFunc=cFuncNow, vPfunc=vPfuncNow)
        solution_now.lFunc = lFuncNow
        return solution_now