def solveWorkingDeaton(solution_next, aXtraGrid, mGrid, EGMVector, par, Util, UtilP, UtilP_inv, TranInc, TranIncWeights): choice = 2 choiceCount = len(solution_next.ChoiceSols) # Next-period initial wealth given exogenous aXtraGrid # This needs to be made more general like the rest of the code mrs_tp1 = par.Rfree * numpy.expand_dims(aXtraGrid, axis=1) + par.YWork * TranInc.T mws_tp1 = par.Rfree * numpy.expand_dims(aXtraGrid, axis=1) + par.YWork * TranInc.T m_tp1s = (mrs_tp1, mws_tp1) # Prepare variables for EGM step C_tp1s = tuple(solution_next.ChoiceSols[d].CFunc(m_tp1s[d]) for d in range(choiceCount)) Vs = tuple( numpy.divide(-1.0, solution_next.ChoiceSols[d].V_TFunc(m_tp1s[d])) for d in range(choiceCount)) # Due to the transformation on V being monotonic increasing, we can just as # well use the transformed values to do this discrete envelope step. V, ChoiceProb_tp1 = calcLogSumChoiceProbs(numpy.stack(Vs), par.sigma) # Calculate the expected marginal utility and expected value function PUtilPsum = sum(ChoiceProb_tp1[i, :] * UtilP(C_tp1s[i], i + 1) for i in range(choiceCount)) EUtilP_tp1 = par.Rfree * numpy.dot(PUtilPsum, TranIncWeights.T) EV_tp1 = numpy.squeeze( numpy.dot(numpy.expand_dims(V, axis=1), TranIncWeights.T)) # EGM step m_t, C_t, Ev = calcEGMStep(EGMVector, aXtraGrid, EV_tp1, EUtilP_tp1, par, Util, UtilP, UtilP_inv, choice) V_T = numpy.divide(-1.0, Util(C_t, choice) + par.DiscFac * Ev) # We do the envelope step in transformed value space for accuracy. The values # keep their monotonicity under our transformation. m_t, C_t, V_T = calcMultilineEnvelope(m_t, C_t, V_T, mGrid) # The solution is the working specific consumption function and value function # specifying lower_extrap=True for C is easier than explicitly adding a 0, # as it'll be linear in the constrained interval anyway. CFunc = LinearInterp(m_t, C_t, lower_extrap=True) V_TFunc = LinearInterp(m_t, V_T, lower_extrap=True) return ChoiceSpecificSolution(m_t, C_t, CFunc, V_T, V_TFunc)
def calcExtraSaves(saveCommon, rs, ws, par, mGrid): if saveCommon: # To save the pre-discrete choice expected consumption and value function, # we need to interpolate onto the same grid between the two. We know that # ws.C and ws.V_T are on the ws.m grid, so we use that to interpolate. Crs = LinearInterp(rs.m, rs.C)(mGrid) V_rs = numpy.divide(-1, LinearInterp(rs.m, rs.V_T)(mGrid)) Cws = ws.C V_ws = numpy.divide(-1, ws.V_T) V, P = calcLogSumChoiceProbs(numpy.stack((V_rs, V_ws)), par.sigma) C = (P * numpy.stack((Crs, Cws))).sum(axis=0) else: C, V_T, P = None, None, None return C, numpy.divide(-1.0, V), P
def test_noShock3DBoth(self): # Test the value functions and policies of the 3D case sigma = 0.0 V, P = interpolation.calcLogSumChoiceProbs(self.Vs3D, sigma) self.assertTrue((V == self.Vref3D).all) self.assertTrue((P == self.Pref3D).all)
# \end{equation} # # \begin{equation} # c_2(m_2) = c_2(m_2|w=w^*(m_2)) # \end{equation} # # We now construct these objects. # %% # We use HARK's 'calcLogSumchoiceProbs' to compute the optimal # will decision over our grid of market resources. # The function also returns the unconditional value function # Use transformed values since -given sigma=0- magnitudes are unimportant. This # avoids NaNs at m \approx 0. vTGrid2, willChoice2 = calcLogSumChoiceProbs(np.stack( (vT2_cond_wi(mGrid), vT2_cond_no(mGrid))), sigma=0) vGrid2 = vUntransf(vTGrid2) # Plot the optimal decision rule plt.plot(mGrid, willChoice2[0]) plt.title('$w^*(m)$') plt.ylabel('Write will (1) or not (0)') plt.xlabel('Market resources: m') plt.show() # With the decision rule we can get the unconditional consumption function cGrid2 = (willChoice2 * np.stack( (c2_cond_wi(mGrid), c2_cond_no(mGrid)))).sum(axis=0) vT2 = LinearInterp(mGrid, vTransf(vGrid2), lower_extrap=True)