def makeTargetMfig(Rfree, DiscFac, CRRA, permShkStd, TranShkStd):
    inf_hor = IndShockConsumerType(quietly=True, **base_params)
    inf_hor.Rfree = Rfree
    inf_hor.DiscFac = DiscFac
    inf_hor.CRRA = CRRA
    inf_hor.permShkStd = [permShkStd]
    inf_hor.TranShkStd = [TranShkStd]
    inf_hor.update_income_process()
    mPlotMin = 0
    mPlotMax = 250
    inf_hor.aXtraMax = mPlotMax
    inf_hor.solve(quietly=True, messaging_level=logging.CRITICAL)
    soln = inf_hor.solution[0]
    Bilt, cFunc = soln.Bilt, soln.cFunc
    cPlotMin = 0, cFunc(mPlotMax)

    if Bilt.GICNrm:  # tattle
        soln.check_GICNrm(soln, quietly=False, messaging_level=logging.WARNING)

    mBelwStE = np.linspace(mPlotMin, mPlotMax, 1000)
    EPermGroFac = inf_hor.PermGroFac[0]

    def EmDelEq0(mVec):
        return (EPermGroFac / Rfree) + (1.0 - EPermGroFac / Rfree) * mVec

    cBelwStE_Best = cFunc(mBelwStE)  # "best" = optimal c
    cBelwStE_Sstn = EmDelEq0(mBelwStE)  # "sustainable" c
    mNrmStE = Bilt.mNrmStE

    plt.figure(figsize=(12, 8))
    plt.plot(mBelwStE, cBelwStE_Best, label="$c(m_{t})$")
    plt.plot(mBelwStE,
             cBelwStE_Sstn,
             label="$\mathsf{E}_{t}[\Delta m_{t+1}] = 0$")
    plt.xlim(mPlotMin, mPlotMax)
    plt.ylim(cPlotMin, cFunc(mPlotMax))
    plt.plot(
        [mNrmStE, mNrmStE],
        [0, 2.5],
        color="black",
        linestyle="--",
    )
    plt.tick_params(
        #        labelbottom=False,
        #        labelleft=False,
        #        left="off",
        right="off",
        #        bottom="off",
        top="off",
    )
    plt.text(0, 1.47, r"$c$", fontsize=26)
    plt.text(3.02, 0, r"$m$", fontsize=26)
    plt.text(mNrmStE - 0.05, -0.1, "m̌", fontsize=26)
    plt.legend(fontsize='x-large')
    plt.show()
    return None
def makeTargetMfig(Rfree, DiscFac, CRRA, PermShkStd, TranShkStd):
    baseAgent_Inf = IndShockConsumerType(verbose=0, cycles=0, **base_params)
    baseAgent_Inf.Rfree = Rfree
    baseAgent_Inf.DiscFac = DiscFac
    baseAgent_Inf.CRRA = CRRA
    baseAgent_Inf.PermShkStd = [PermShkStd]
    baseAgent_Inf.TranShkStd = [TranShkStd]
    baseAgent_Inf.updateIncomeProcess()
    baseAgent_Inf.checkConditions()
    mPlotMin = 0
    mPlotMax = 250
    baseAgent_Inf.aXtraMax = mPlotMax
    baseAgent_Inf.solve()
    baseAgent_Inf.unpack('cFunc')
    cPlotMin = 0
    cPlotMax = baseAgent_Inf.cFunc[0](mPlotMax)

    if (baseAgent_Inf.GPFInd >= 1):
        baseAgent_Inf.checkGICInd(verbose=3)

    mBelwTrg = np.linspace(mPlotMin, mPlotMax, 1000)
    EPermGroFac = baseAgent_Inf.PermGroFac[0]
    EmDelEq0 = lambda m: (EPermGroFac / Rfree) + (1.0 - EPermGroFac / Rfree
                                                  ) * m
    cBelwTrg_Best = baseAgent_Inf.cFunc[0](mBelwTrg)  # "best" = optimal c
    cBelwTrg_Sstn = EmDelEq0(mBelwTrg)  # "sustainable" c
    mNrmTrg = baseAgent_Inf.solution[0].mNrmSS

    plt.figure(figsize=(12, 8))
    plt.plot(mBelwTrg, cBelwTrg_Best, label="$c(m_{t})$")
    plt.plot(mBelwTrg,
             cBelwTrg_Sstn,
             label="$\mathsf{E}_{t}[\Delta m_{t+1}] = 0$")
    plt.xlim(mPlotMin, mPlotMax)
    plt.ylim(cPlotMin, cPlotMax)
    plt.plot(
        [mNrmTrg, mNrmTrg],
        [0, 2.5],
        color="black",
        linestyle="--",
    )
    plt.tick_params(
        #        labelbottom=False,
        #        labelleft=False,
        #        left="off",
        right="off",
        #        bottom="off",
        top="off",
    )
    plt.text(0, 1.47, r"$c$", fontsize=26)
    plt.text(3.02, 0, r"$m$", fontsize=26)
    plt.text(mNrmTrg - 0.05, -0.1, "m̌", fontsize=26)
    plt.legend(fontsize='x-large')
    plt.show()
    return None
GICNrmFailsButGICRawHolds.solve(quietly=True)  # Suppress output

# Because we are trying to solve a problem very close to the critical patience
# values, we want to do it with extra precision to be sure we've gotten the
# answer right.  We can retrieve the distance between the last two solutions:

distance_original = GICNrmFailsButGICRawHolds.solution[0].distance_last

# But high precision would have slowed things down if we used it from the start

# Instead, we can take the solution obtained above, and continue it but with
# parameters that will yield a more precise answer:

# Solve with quadruple the normal range
GICNrmFailsButGICRawHolds.aXtraMax = GICNrmFailsButGICRawHolds.aXtraMax * 10

# Solve over four times as many gridpoints
GICNrmFailsButGICRawHolds.aXtraCount = GICNrmFailsButGICRawHolds.aXtraCount * 4

GICNrmFailsButGICRawHolds.update_assets_grid()

# Solve to a 10 times tighter degree of error tolerance
GICNrmFailsButGICRawHolds.tolerance = GICNrmFailsButGICRawHolds.tolerance/10

# When the solver reaches its tolerance threshold, it changes the solver
# attribute stge_kind to have 'iter_status' of 'finished'
# If we want to continue the solution (having changed something, as above)
# To continue the solution from where we left off, we just change the
# 'iter_status' to 'iterator' and tell it to ".solve()" again
def makeBoundsFigure(UnempPrb, permShkStd, TranShkStd, DiscFac, CRRA):
    inf_hor = IndShockConsumerType(quietly=True,
                                   messaging_level=logging.CRITICAL,
                                   **base_params)
    inf_hor.UnempPrb = UnempPrb
    inf_hor.permShkStd = [permShkStd]
    inf_hor.TranShkStd = [TranShkStd]
    inf_hor.DiscFac = DiscFac
    inf_hor.CRRA = CRRA
    inf_hor.update_income_process()

    inf_hor.solve(quietly=True, messaging_level=logging.CRITICAL)
    soln = inf_hor.solution[0]
    Bilt, Pars = soln.Bilt, soln.Pars

    cFunc = soln.cFunc
    mPlotMin, mPlotMax = 0, 25
    inf_hor.aXtraMax = mPlotMax

    # Retrieve parameters (makes code more readable)
    Rfree, EPermGroFac = Pars.Rfree, Pars.PermGroFac

    κ_Min = 1.0 - (Rfree**(-1.0)) * (Rfree * DiscFac)**(1.0 / CRRA)
    h_inf = (1.0 / (1.0 - EPermGroFac / Rfree))

    def cFunc_Uncnst(mVec):
        return (h_inf - 1) * κ_Min + κ_Min * mVec

    def cFunc_TopBnd(mVec):
        return (1 - UnempPrb**(1.0 / CRRA) *
                (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) * mVec

    def cFunc_BotBnd(mVec):
        return (1 - (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) * mVec

    # Plot the consumption function and its bounds
    cPlotMaxLabel = r"c̅$(m) = (m-1+h)κ̲$"  # Use unicode kludge
    cPlotMinLabel = r"c̲$(m)= (1-\Phi_{R})m = κ̲ m$"

    # mKnk is point where the two upper bounds meet
    mKnk = ((h_inf - 1) * κ_Min) / (
        (1 - UnempPrb**(1.0 / CRRA) *
         (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) - κ_Min)
    mBelwKnkPts, mAbveKnkPts = 50, 100
    mBelwKnk = np.linspace(mPlotMin, mKnk, mBelwKnkPts)
    mAbveKnk = np.linspace(mKnk, mPlotMax, mAbveKnkPts)
    mFullPts = np.linspace(mPlotMin, mPlotMax, mBelwKnkPts + mAbveKnkPts)

    plt.figure(figsize=(12, 8))
    plt.plot(mFullPts, cFunc(mFullPts), label=r'$c(m)$')
    plt.plot(mBelwKnk,
             cFunc_Uncnst(mBelwKnk),
             label=cPlotMaxLabel,
             linestyle="--")
    plt.plot(
        mAbveKnk,
        cFunc_Uncnst(mAbveKnk),
        label=
        r'Upper Bound $ = $ Min $[\overline{\overline{c}}(m),\overline{c}(m)]$',
        linewidth=2.5,
        color='black')
    plt.plot(mBelwKnk, cFunc_TopBnd(mBelwKnk), linewidth=2.5, color='black')
    plt.plot(mAbveKnk,
             cFunc_TopBnd(mAbveKnk),
             linestyle="--",
             label=r"$\overline{\overline{c}}(m) = κ̅m = (1 - ℘^{1/ρ}Φᵣ)m$")
    plt.plot(mBelwKnk, cFunc_BotBnd(mBelwKnk), color='red', linewidth=2.5)
    plt.plot(mAbveKnk,
             cFunc_BotBnd(mAbveKnk),
             color='red',
             label=cPlotMinLabel,
             linewidth=2.5)
    plt.tick_params(labelbottom=False,
                    labelleft=False,
                    left='off',
                    right='off',
                    bottom='off',
                    top='off')
    plt.xlim(mPlotMin, mPlotMax)
    plt.ylim(mPlotMin, 1.12 * cFunc_Uncnst(mPlotMax))
    plt.text(mPlotMin,
             1.12 * cFunc_Uncnst(mPlotMax) + 0.05,
             "$c$",
             fontsize=22)
    plt.text(mPlotMax + 0.1, mPlotMin, "$m$", fontsize=22)
    plt.legend(fontsize='x-large')
    plt.show()
    return None
def makeBoundsFigure(UnempPrb, PermShkStd, TranShkStd, DiscFac, CRRA):
    baseAgent_Inf = IndShockConsumerType(verbose=0, cycles=0, **base_params)
    baseAgent_Inf.UnempPrb = UnempPrb
    baseAgent_Inf.PermShkStd = [PermShkStd]
    baseAgent_Inf.TranShkStd = [TranShkStd]
    baseAgent_Inf.DiscFac = DiscFac
    baseAgent_Inf.CRRA = CRRA
    baseAgent_Inf.updateIncomeProcess()
    baseAgent_Inf.checkConditions()
    mPlotMin = 0
    mPlotMax = 2500
    baseAgent_Inf.tolerance = 1e-09
    baseAgent_Inf.aXtraMax = mPlotMax
    baseAgent_Inf.solve(verbose=0)
    baseAgent_Inf.unpack('cFunc')
    cPlotMin = 0
    cPlotMax = 1.2 * baseAgent_Inf.cFunc[0](mPlotMax)
    # Retrieve parameters (makes code more readable)
    Rfree = baseAgent_Inf.Rfree
    CRRA = baseAgent_Inf.CRRA
    EPermGroFac = baseAgent_Inf.PermGroFac[0]
    mNrmTrg = baseAgent_Inf.solution[0].mNrmSS
    UnempPrb = baseAgent_Inf.UnempPrb

    κ_Min = 1.0 - (Rfree**(-1.0)) * (Rfree * DiscFac)**(1.0 / CRRA)
    h_inf = (1.0 / (1.0 - EPermGroFac / Rfree))
    cFunc_Uncnst = lambda m: (h_inf - 1) * κ_Min + κ_Min * m
    cFunc_TopBnd = lambda m: (1 - UnempPrb**(1.0 / CRRA) *
                              (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) * m
    cFunc_BotBnd = lambda m: (1 - (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) * m

    # Plot the consumption function and its bounds
    cMaxLabel = r"c̅$(m) = (m-1+h)κ̲$"  # Use unicode kludge
    cMinLabel = r"c̲$(m)= (1-\Phi_{R})m = κ̲ m$"

    # mKnk is point where the two upper bounds meet
    mKnk = ((h_inf - 1) * κ_Min) / (
        (1 - UnempPrb**(1.0 / CRRA) *
         (Rfree * DiscFac)**(1.0 / CRRA) / Rfree) - κ_Min)
    mBelwKnkPts = 300
    mAbveKnkPts = 700
    mBelwKnk = np.linspace(mPlotMin, mKnk, mBelwKnkPts)
    mAbveKnk = np.linspace(mKnk, mPlotMax, mAbveKnkPts)
    mFullPts = np.linspace(mPlotMin, mPlotMax, mBelwKnkPts + mAbveKnkPts)

    plt.figure(figsize=(12, 8))
    plt.plot(mFullPts, baseAgent_Inf.cFunc[0](mFullPts), label=r'$c(m)$')
    plt.plot(mBelwKnk, cFunc_Uncnst(mBelwKnk), label=cMaxLabel, linestyle="--")
    plt.plot(
        mAbveKnk,
        cFunc_Uncnst(mAbveKnk),
        label=
        r'Upper Bound $ = $ Min $[\overline{\overline{c}}(m),\overline{c}(m)]$',
        linewidth=2.5,
        color='black')
    plt.plot(mBelwKnk, cFunc_TopBnd(mBelwKnk), linewidth=2.5, color='black')
    plt.plot(mAbveKnk,
             cFunc_TopBnd(mAbveKnk),
             linestyle="--",
             label=r"$\overline{\overline{c}}(m) = κ̅m = (1 - ℘^{1/ρ}Φᵣ)m$")
    plt.plot(mBelwKnk, cFunc_BotBnd(mBelwKnk), color='red', linewidth=2.5)
    plt.plot(mAbveKnk,
             cFunc_BotBnd(mAbveKnk),
             color='red',
             label=cMinLabel,
             linewidth=2.5)
    plt.tick_params(labelbottom=False,
                    labelleft=False,
                    left='off',
                    right='off',
                    bottom='off',
                    top='off')
    plt.xlim(mPlotMin, mPlotMax)
    plt.ylim(mPlotMin, 1.12 * cFunc_Uncnst(mPlotMax))
    plt.text(mPlotMin,
             1.12 * cFunc_Uncnst(mPlotMax) + 0.05,
             "$c$",
             fontsize=22)
    plt.text(mPlotMax + 0.1, mPlotMin, "$m$", fontsize=22)
    plt.legend(fontsize='x-large')
    plt.show()
    return None
def makeGrowthplot(PermGroFac, DiscFac):
    # cycles=0 tells the solver to find the infinite horizon solution
    baseAgent_Inf = IndShockConsumerType(verbose=0, cycles=0, **base_params)
    baseAgent_Inf.PermGroFac = [PermGroFac]
    baseAgent_Inf.DiscFac = DiscFac
    baseAgent_Inf.updateIncomeProcess()
    baseAgent_Inf.checkConditions()
    mPlotMin = 0
    mPlotMax = 3500.5
    baseAgent_Inf.mPlotMax = 3500.5
    baseAgent_Inf.aXtraMax = mPlotMax
    baseAgent_Inf.tolerance = 1e-09
    baseAgent_Inf.solve()
    baseAgent_Inf.unpack('cFunc')
    numPts = 500
    if (baseAgent_Inf.GPFInd >= 1):
        baseAgent_Inf.checkGICInd(verbose=3)
    elif baseAgent_Inf.solution[0].mNrmSS > mPlotMax:
        print('Target exists but is outside the plot range.')
    else:

        def EcLev_tp1_Over_p_t(a):
            '''
            Taking end-of-period assets a as input, return ratio of expectation 
            of next period's consumption to this period's permanent income 

            Inputs:
               a: end-of-period assets
            Returns:
               EcLev_tp1_Over_p_{t}: next period's expected c level / current p
            '''
            # Extract parameter values to make code more readable
            permShkVals = baseAgent_Inf.PermShkDstn[0].X
            tranShkVals = baseAgent_Inf.TranShkDstn[0].X
            permShkPrbs = baseAgent_Inf.PermShkDstn[0].pmf
            tranShkPrbs = baseAgent_Inf.TranShkDstn[0].pmf
            Rfree = baseAgent_Inf.Rfree
            EPermGroFac = baseAgent_Inf.PermGroFac[0]

            PermGrowFac_tp1 = EPermGroFac * permShkVals  # Nonstochastic growth times idiosyncratic permShk
            RNrmFac_tp1 = Rfree / PermGrowFac_tp1  # Growth-normalized interest factor
            # 'bank balances' b = end-of-last-period assets times normalized return factor
            b_tp1 = RNrmFac_tp1 * a
            # expand dims of b_tp1 and use broadcasted sum of a column and a row vector
            # to obtain a matrix of possible market resources next period
            # because matrix mult is much much faster than looping to calc E
            m_tp1_GivenTranAndPermShks = np.expand_dims(b_tp1,
                                                        axis=1) + tranShkVals
            # List of possible values of $\mathbf{c}_{t+1}$ (Transposed by .T)
            cRat_tp1_GivenTranAndPermShks = baseAgent_Inf.cFunc[0](
                m_tp1_GivenTranAndPermShks).T
            cLev_tp1_GivenTranAndPermShks = cRat_tp1_GivenTranAndPermShks * PermGrowFac_tp1
            # compute expectation over perm shocks by right multiplying with probs
            EOverPShks_cLev_tp1_GivenTranShkShks = np.dot(
                cLev_tp1_GivenTranAndPermShks, permShkPrbs)
            # finish expectation over trans shocks by right multiplying with probs
            EcLev_tp1_Over_p_t = np.dot(EOverPShks_cLev_tp1_GivenTranShkShks,
                                        tranShkPrbs)
            # return expected consumption
            return EcLev_tp1_Over_p_t

        # Calculate the expected consumption growth factor
        # mBelwTrg defines the plot range on the left of target m value (e.g. m <= target m)
        mNrmTrg = baseAgent_Inf.solution[0].mNrmSS
        mPlotMin = 0
        mPlotMax = 200
        mBelwTrg = np.linspace(mPlotMin, mNrmTrg, numPts)
        c_For_mBelwTrg = baseAgent_Inf.cFunc[0](mBelwTrg)
        a_For_mBelwTrg = mBelwTrg - c_For_mBelwTrg
        EcLev_tp1_Over_p_t_For_mBelwTrg = [
            EcLev_tp1_Over_p_t(i) for i in a_For_mBelwTrg
        ]

        # mAbveTrg defines the plot range on the right of target m value (e.g. m >= target m)
        mAbveTrg = np.linspace(mNrmTrg, mPlotMax, numPts)

        # EcGro_For_mAbveTrg: E [consumption growth factor] when m_{t} is below target m
        EcGro_For_mBelwTrg = np.array(
            EcLev_tp1_Over_p_t_For_mBelwTrg) / c_For_mBelwTrg

        c_For_mAbveTrg = baseAgent_Inf.cFunc[0](mAbveTrg)
        a_For_mAbveTrg = mAbveTrg - c_For_mAbveTrg
        EcLev_tp1_Over_p_t_For_mAbveTrg = [
            EcLev_tp1_Over_p_t(i) for i in a_For_mAbveTrg
        ]

        # EcGro_For_mAbveTrg: E [consumption growth factor] when m_{t} is bigger than target m_{t}
        EcGro_For_mAbveTrg = np.array(
            EcLev_tp1_Over_p_t_For_mAbveTrg) / c_For_mAbveTrg

        Rfree = 1.0
        EPermGroFac = 1.0
        mNrmTrg = baseAgent_Inf.solution[0].mNrmSS

        # Calculate Absolute Patience Factor Phi = lower bound of consumption growth factor
        APF = (Rfree * DiscFac)**(1.0 / CRRA)

        plt.figure(figsize=(12, 8))
        # Plot the Absolute Patience Factor line
        plt.plot([mPlotMin, mPlotMax], [APF, APF],
                 label="\u03A6 = [(\u03B2 R)^(1/ \u03C1)]/R")

        # Plot the Permanent Income Growth Factor line
        plt.plot([mPlotMin, mPlotMax], [EPermGroFac, EPermGroFac],
                 label="\u0393")

        # Plot the expected consumption growth factor on the left side of target m
        plt.plot(mBelwTrg, EcGro_For_mBelwTrg, color="black")

        # Plot the expected consumption growth factor on the right side of target m
        plt.plot(mAbveTrg,
                 EcGro_For_mAbveTrg,
                 color="black",
                 label="$\mathsf{E}_{t}[c_{t+1}/c_{t}]$")

        # Plot the target m
        plt.plot(
            [mNrmTrg, mNrmTrg],
            [mPlotMin, mPlotMax],
            color="black",
            linestyle="--",
            label="",
        )
        plt.xlim(1, mPlotMax)
        plt.ylim(0.94, 1.10)
        plt.text(2.105, 0.930, "$m_{t}$", fontsize=26, fontweight="bold")
        plt.text(
            mNrmTrg - 0.02,
            0.930,
            "m̌",
            fontsize=26,
            fontweight="bold",
        )
        plt.tick_params(
            labelbottom=False,
            labelleft=False,
            left="off",
            right="off",
            bottom="off",
            top="off",
        )
        plt.legend(fontsize='x-large')
        plt.show()
        return None