def use_points_for_interpolation(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 = MargValueFuncCRRA(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
Esempio n. 2
0
    def post_solve(self):
        self.solution_fast = deepcopy(self.solution)

        if self.cycles == 0:
            cycles = 1
        else:
            cycles = self.cycles
            self.solution[-1] = self.solution_terminal_cs

        for i in range(cycles):
            for j in range(self.T_cycle):
                solution = self.solution[i * self.T_cycle + j]

                # Define the borrowing constraint (limiting consumption function)
                cFuncNowCnst = LinearInterp(
                    np.array([solution.mNrmMin, solution.mNrmMin + 1]),
                    np.array([0.0, 1.0]),
                )

                """
                Constructs a basic solution for this period, including the consumption
                function and marginal value function.
                """

                if self.CubicBool:
                    # Makes a cubic spline interpolation of the unconstrained consumption
                    # function for this period.
                    cFuncNowUnc = CubicInterp(
                        solution.mNrm,
                        solution.cNrm,
                        solution.MPC,
                        solution.cFuncLimitIntercept,
                        solution.cFuncLimitSlope,
                    )
                else:
                    # Makes a linear interpolation to represent the (unconstrained) consumption function.
                    # Construct the unconstrained consumption function
                    cFuncNowUnc = LinearInterp(
                        solution.mNrm,
                        solution.cNrm,
                        solution.cFuncLimitIntercept,
                        solution.cFuncLimitSlope,
                    )

                # Combine the constrained and unconstrained functions into the true consumption function
                cFuncNow = LowerEnvelope(cFuncNowUnc, cFuncNowCnst)

                # Make the marginal value function and the marginal marginal value function
                vPfuncNow = MargValueFuncCRRA(cFuncNow, self.CRRA)

                # Pack up the solution and return it
                consumer_solution = ConsumerSolution(
                    cFunc=cFuncNow,
                    vPfunc=vPfuncNow,
                    mNrmMin=solution.mNrmMin,
                    hNrm=solution.hNrm,
                    MPCmin=solution.MPCmin,
                    MPCmax=solution.MPCmax,
                )

                if self.vFuncBool:
                    vNvrsFuncNow = CubicInterp(
                        solution.mNrmGrid,
                        solution.vNvrs,
                        solution.vNvrsP,
                        solution.MPCminNvrs * solution.hNrm,
                        solution.MPCminNvrs,
                    )
                    vFuncNow = ValueFuncCRRA(vNvrsFuncNow, self.CRRA)

                    consumer_solution.vFunc = vFuncNow

                if self.CubicBool or self.vFuncBool:
                    _searchFunc = (
                        _find_mNrmStECubic if self.CubicBool else _find_mNrmStELinear
                    )
                    # Add mNrmStE to the solution and return it
                    consumer_solution.mNrmStE = _add_mNrmStEIndNumba(
                        self.PermGroFac[j],
                        self.Rfree,
                        solution.Ex_IncNext,
                        solution.mNrmMin,
                        solution.mNrm,
                        solution.cNrm,
                        solution.MPC,
                        solution.MPCmin,
                        solution.hNrm,
                        _searchFunc,
                    )

                self.solution[i * self.T_cycle + j] = consumer_solution
Esempio n. 3
0
def solveConsMarkovALT(solution_next,IncomeDstn,LivPrb,DiscFac,CRRA,Rfree,PermGroFac,uPfac,
                                 MrkvArray,BoroCnstArt,aXtraGrid,vFuncBool,CubicBool):
    '''
    Solves a single period consumption-saving problem with risky income and
    stochastic transitions between discrete states, in a Markov fashion.  Has
    identical inputs as solveConsIndShock, except for a discrete
    Markov transitionrule MrkvArray.  Markov states can differ in their interest
    factor, permanent growth factor, and income distribution, so the inputs Rfree,
    PermGroFac, and IncomeDstn are arrays or lists specifying those values in each
    (succeeding) Markov state.

    Parameters
    ----------
    solution_next : ConsumerSolution
        The solution to next period's one period problem.
    IncomeDstn : DiscreteDistribution
        A representation of permanent and transitory income shocks that might
        arrive at the beginning of next period.
    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.
    Rfree : np.array
        Risk free interest factor on end-of-period assets for each Markov
        state in the succeeding period.
    PermGroFac : np.array
        Expected permanent income growth factor at the end of this period
        for each Markov state in the succeeding period.
    uPfac : np.array
        Scaling factor for (marginal) utility in each current Markov state.
    MrkvArray : np.array
        An NxN array representing a Markov transition matrix between discrete
        states.  The i,j-th element of MrkvArray is the probability of
        moving from state i in period t to state j in period t+1.
    BoroCnstArt: float or None
        Borrowing constraint for the minimum allowable assets to end the
        period with.  If it is less than the natural borrowing constraint,
        then it is irrelevant; BoroCnstArt=None indicates no artificial bor-
        rowing constraint.
    aXtraGrid: np.array
        Array of "extra" end-of-period asset values-- assets above the
        absolute minimum acceptable level.
    vFuncBool: boolean
        An indicator for whether the value function should be computed and
        included in the reported solution.  Not used.
    CubicBool: boolean
        An indicator for whether the solver should use cubic or linear inter-
        polation.  Not used.

    Returns
    -------
    solution : ConsumerSolution
        The solution to the single period consumption-saving problem. Includes
        a consumption function cFunc (using cubic or linear splines), a marg-
        inal value function vPfunc, a minimum acceptable level of normalized
        market resources mNrmMin.  All of these attributes are lists or arrays, 
        with elements corresponding to the current Markov state.  E.g.
        solution.cFunc[0] is the consumption function when in the i=0 Markov
        state this period.
    '''
    # Get sizes of grids
    aCount = aXtraGrid.size
    StateCount = MrkvArray.shape[0]

    # Loop through next period's states, assuming we reach each one at a time.
    # Construct EndOfPrdvP_cond functions for each state.
    BoroCnstNat_cond = []
    EndOfPrdvPfunc_cond = []
    for j in range(StateCount):
        # Unpack next period's solution
        vPfuncNext = solution_next.vPfunc[j]
        mNrmMinNext = solution_next.mNrmMin[j]

        # Unpack the income shocks
        ShkPrbsNext = IncomeDstn[j].pmf
        PermShkValsNext = IncomeDstn[j].X[0]
        TranShkValsNext = IncomeDstn[j].X[1]
        ShkCount = ShkPrbsNext.size
        aXtra_tiled = np.tile(np.reshape(aXtraGrid, (aCount, 1)), (1, ShkCount))

        # Make tiled versions of the income shocks
        # Dimension order: aNow, Shk
        ShkPrbsNext_tiled = np.tile(np.reshape(ShkPrbsNext, (1, ShkCount)), (aCount, 1))
        PermShkValsNext_tiled = np.tile(np.reshape(PermShkValsNext, (1, ShkCount)), (aCount, 1))
        TranShkValsNext_tiled = np.tile(np.reshape(TranShkValsNext, (1, ShkCount)), (aCount, 1))

        # Find the natural borrowing constraint
        aNrmMin_candidates = PermGroFac[j]*PermShkValsNext_tiled/Rfree[j]*(mNrmMinNext - TranShkValsNext_tiled[0, :])
        aNrmMin = np.max(aNrmMin_candidates)
        BoroCnstNat_cond.append(aNrmMin)

        # Calculate market resources next period (and a constant array of capital-to-labor ratio)
        aNrmNow_tiled = aNrmMin + aXtra_tiled
        mNrmNext_array = Rfree[j]*aNrmNow_tiled/PermShkValsNext_tiled + TranShkValsNext_tiled

        # Find marginal value next period at every income shock realization and every aggregate market resource gridpoint
        vPnext_array = Rfree[j]*PermShkValsNext_tiled**(-CRRA)*vPfuncNext(mNrmNext_array)

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

        # Make the conditional end-of-period marginal value function
        EndOfPrdvPnvrs = EndOfPrdvP**(-1./CRRA)
        EndOfPrdvPnvrsFunc = LinearInterp(np.insert(aNrmMin + aXtraGrid, 0, aNrmMin), np.insert(EndOfPrdvPnvrs, 0, 0.0))
        EndOfPrdvPfunc_cond.append(MargValueFunc(EndOfPrdvPnvrsFunc, CRRA))

    # Now loop through *this* period's discrete states, calculating end-of-period
    # marginal value (weighting across state transitions), then construct consumption
    # and marginal value function for each state.
    cFuncNow = []
    vPfuncNow = []
    mNrmMinNow = []
    for i in range(StateCount):
        # Find natural borrowing constraint for this state
        aNrmMin_candidates = np.zeros(StateCount) + np.nan
        for j in range(StateCount):
            if MrkvArray[i, j] > 0.:  # Irrelevant if transition is impossible
                aNrmMin_candidates[j] = BoroCnstNat_cond[j]
        aNrmMin = np.nanmax(aNrmMin_candidates)
        
        # Find the minimum allowable market resources
        if BoroCnstArt is not None:
            mNrmMin = np.maximum(BoroCnstArt, aNrmMin)
        else:
            mNrmMin = aNrmMin
        mNrmMinNow.append(mNrmMin)

        # Make tiled grid of aNrm
        aNrmNow = aNrmMin + aXtraGrid
        
        # Loop through feasible transitions and calculate end-of-period marginal value
        EndOfPrdvP = np.zeros(aCount)
        for j in range(StateCount):
            if MrkvArray[i, j] > 0.:
                temp = MrkvArray[i, j]*EndOfPrdvPfunc_cond[j](aNrmNow)
                EndOfPrdvP += temp
        EndOfPrdvP *= LivPrb[i] # Account for survival out of the current state

        # Calculate consumption and the endogenous mNrm gridpoints for this state
        cNrmNow = (EndOfPrdvP/uPfac[i])**(-1./CRRA)
        mNrmNow = aNrmNow + cNrmNow

        # Make a piecewise linear consumption function
        c_temp = np.insert(cNrmNow, 0, 0.0)  # Add point at bottom
        m_temp = np.insert(mNrmNow, 0, aNrmMin)
        cFuncUnc = LinearInterp(m_temp, c_temp)
        cFuncCnst = LinearInterp(np.array([mNrmMin, mNrmMin+1.0]), np.array([0.0, 1.0]))
        cFuncNow.append(LowerEnvelope(cFuncUnc,cFuncCnst))

        # Construct the marginal value function using the envelope condition
        m_temp = aXtraGrid + mNrmMin
        c_temp = cFuncNow[i](m_temp)
        uP = uPfac[i]*c_temp**(-CRRA)
        vPnvrs = uP**(-1./CRRA)
        vPnvrsFunc = LinearInterp(np.insert(m_temp, 0, mNrmMin), np.insert(vPnvrs, 0, 0.0))
        vPfuncNow.append(MargValueFunc(vPnvrsFunc, CRRA))
        
    # Pack up and return the solution
    solution_now = ConsumerSolution(cFunc=cFuncNow, vPfunc=vPfuncNow, mNrmMin=mNrmMinNow)
    return solution_now
Esempio n. 4
0
    def make_solution(self, cNrm, mNrm):
        """
        Construct an object representing the solution to this period's problem.

        Parameters
        ----------
        cNrm : np.array
            Array of normalized consumption values for interpolation.  Each row
            corresponds to a Markov state for this period.
        mNrm : np.array
            Array of normalized market resource values for interpolation.  Each
            row corresponds to a Markov state for this period.

        Returns
        -------
        solution : ConsumerSolution
            The solution to the single period consumption-saving problem. Includes
            a consumption function cFunc (using cubic or linear splines), a marg-
            inal value function vPfunc, a minimum acceptable level of normalized
            market resources mNrmMin, normalized human wealth hNrm, and bounding
            MPCs MPCmin and MPCmax.  It might also have a value function vFunc
            and marginal marginal value function vPPfunc.  All of these attributes
            are lists or arrays, with elements corresponding to the current
            Markov state.  E.g. solution.cFunc[0] is the consumption function
            when in the i=0 Markov state this period.
        """
        solution = (
            ConsumerSolution()
        )  # An empty solution to which we'll add state-conditional solutions
        # Calculate the MPC at each market resource gridpoint in each state (if desired)
        if self.CubicBool:
            dcda = self.EndOfPrdvPP / self.uPP(np.array(self.cNrmNow))
            MPC = dcda / (dcda + 1.0)
            self.MPC_temp = np.hstack(
                (np.reshape(self.MPCmaxNow, (self.StateCount, 1)), MPC)
            )
            interpfunc = self.make_cubic_cFunc
        else:
            interpfunc = self.make_linear_cFunc

        # Loop through each current period state and add its solution to the overall solution
        for i in range(self.StateCount):
            # Set current-period-conditional human wealth and MPC bounds
            self.hNrmNow_j = self.hNrmNow[i]
            self.MPCminNow_j = self.MPCminNow[i]
            if self.CubicBool:
                self.MPC_temp_j = self.MPC_temp[i, :]

            # Construct the consumption function by combining the constrained and unconstrained portions
            self.cFuncNowCnst = LinearInterp(
                [self.mNrmMin_list[i], self.mNrmMin_list[i] + 1.0], [0.0, 1.0]
            )
            cFuncNowUnc = interpfunc(mNrm[i, :], cNrm[i, :])
            cFuncNow = LowerEnvelope(cFuncNowUnc, self.cFuncNowCnst)

            # Make the marginal value function and pack up the current-state-conditional solution
            vPfuncNow = MargValueFuncCRRA(cFuncNow, self.CRRA)
            solution_cond = ConsumerSolution(
                cFunc=cFuncNow, vPfunc=vPfuncNow, mNrmMin=self.mNrmMinNow
            )
            if (
                self.CubicBool
            ):  # Add the state-conditional marginal marginal value function (if desired)
                solution_cond = self.add_vPPfunc(solution_cond)

            # Add the current-state-conditional solution to the overall period solution
            solution.append_solution(solution_cond)

        # Add the lower bounds of market resources, MPC limits, human resources,
        # and the value functions to the overall solution
        solution.mNrmMin = self.mNrmMin_list
        solution = self.add_MPC_and_human_wealth(solution)
        if self.vFuncBool:
            vFuncNow = self.make_vFunc(solution)
            solution.vFunc = vFuncNow

        # Return the overall solution to this period
        return solution
Esempio n. 5
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