::p_load(
pacman
tidyverse,
nleqslv,
pracma,
tictoc )
2 Risk sharing with limited commitment and storage: Numerical solution
Next, I explain the procedure for solving the model numerically and actually solve it. Since it took around 10 hours to solve the model just for one interest rate, which is partly because my R script does not use the symmetry of the states as in Ábrahám and Laczó (2018), I just solve the model once for one interest rate.
2.1 Steps for solving the model
Based on the modeling solution described in the previous page, I explain how to solve the model numerically. First, prepare V_1^0(y, B, x), V_2^0(y, B, x), \underline{x}^0(y, B), \overline{x}^0(y, B), and B'^0(y, B, x), and below I describe the steps in h’th iteration. Note that the updating rule of relative Pareto weight, x'^h(y, B, x) is determined by (\underline{x}^h(y, B), \overline{x}^h(y, B)).
- First, I update \overline{x}(y, B). For this, solve for \overline{x}(y, B) in the equation below such that the household 1’s participation constraint binds with 0 next-period saving: u(c_1(y, B, \overline{x}(y, B))) + \beta \sum_{y'} Pr(y') V_1^{h - 1}(y', 0, \overline{x}(y, B)) = U_1^{aut}(y), where c_1(y, B, \overline{x}(y, B)) = \frac{y + (1 + r)B}{1 + \overline{x}(y, B)}. Then check if the planner’s Euler equation is satisfied at this \overline{x}(y, B), by seeing if the following expression is non-negative or not: u'(c_1(y, B, \overline{x}(y, B))) - \beta (1 + r) \sum_{y'} Pr(y') \frac{u'(c_1(y', 0, \overline{x}(y, B)))}{1 - \nu_1(y', 0, \overline{x}(y, B))}, where, \begin{aligned} c_1(y', 0, \overline{x}(y, B)) &= \frac{y' - B'^{(h - 1)}(y', 0, \overline{x}(y, B))}{1 + x'^{(h - 1)}(y', 0, \overline{x}(y, B))} \\ \nu_1(y', 0, \overline{x}(y, B)) &= \min \left\{ 1 - \frac{x'^{(h - 1)}(y', 0, \overline{x}(y, B))}{\overline{x}(y, B)}, 1 \right\}. \end{aligned} If this is non-negative, update B'^h(y, B, \overline{x}(y, B)) = 0 and \overline{x}^h(y, B) = \overline{x}(y, B). If this is negative, then since the planner’s Euler equation is violated with B' = 0, I solve the following non-linear system of two equations for \overline{x}(y, B) and B': \begin{aligned} &u'(c_1(y, B, \overline{x}(y, B))) - \beta (1 + r) \sum_{y'} Pr(y') \frac{u'(c_1(y', B', \overline{x}(y, B)))}{1 - \nu_1(y', B', \overline{x}(y, B))} = 0 \\ &u(c_1(y, B, \overline{x}(y, B))) + \beta \sum_{y'} Pr(y') V_1^{h - 1}(y', B', \overline{x}(y, B)) = U_1^{aut}(y), \end{aligned} and update B'^h(y, B, \overline{x}(y, B)) and \overline{x}^h(y, B) with the solutions. The value functions are updated such that \begin{aligned} V_1^{h}(y, B, \overline{x}(y, B)) &= U_1^{aut}(y) \\ V_2^{h}(y, B, \overline{x}(y, B)) &= u(c_2(y, B, \overline{x}(y, B))) + \beta \sum_{y'} Pr(y') V_2^{h - 1}(y', B'^h(y, B, \overline{x}(y, B)), \overline{x}(y, B)). \end{aligned}
- Next, I update \underline{x}(y, B) in a similar way. First solve for \underline{x}(y, B) such that the household 2’s participation constraint binds with 0 next-period saving: u(c_2(y, B, \underline{x}(y, B))) + \beta \sum_{y'} Pr(y') V_2^{h - 1}(y', 0, \underline{x}(y, B)) = U_2^{aut}(y), where c_2(y, B, \underline{x}(y, B)) = \frac{y + (1 + r)B}{1 + 1 / \underline{x}(y, B)}. And I check if the planner’s Euler equation is satisfied at \overline{x}(y, B) with B' = 0, by checking if u'(c_1(y, B, \underline{x}(y, B))) - \beta (1 + r) \sum_{y'} Pr(y') \frac{u'(c_1(y', 0, \underline{x}(y, B)))}{1 - \nu_1(y', 0, \underline{x}(y, B))} \ge 0 or not. If this is the case, update B'^h(y, B, \underline{x}(y, B)) = 0 and \underline{x}^h(y, B) = \underline{x}(y, B). Otherwise, since the planner’s Euler equation is violated with B' = 0, I solve the following non-linear system of two equations for B' and \underline{x}(y, B): \begin{aligned} &u'(c_1(y, B, \underline{x}(y, B))) - \beta (1 + r) \sum_{y'} Pr(y') \frac{u'(c_1(y', B', \underline{x}(y, B)))}{1 - \nu_1(y', B', \underline{x}(y, B))} = 0 \\ &u(c_2(y, B, \underline{x}(y, B))) + \beta \sum_{y'} Pr(y') V_2^{h - 1}(y', B', \underline{x}(y, B)) = U_2^{aut}(y), \end{aligned} and update B'^h(y, B, \underline{x}(y, B)) and \underline{x}^h(y, B) with the solutions. The value functions are updated such that \begin{aligned} V_1^{h}(y, B, \underline{x}(y, B)) &= u(c_1(y, B, \underline{x}(y, B))) + \beta \sum_{y'} Pr(y') V_1^{h - 1}(y', B'^h(y, B, \underline{x}(y, B)), \underline{x}(y, B)) \\ V_2^{h}(y, B, \underline{x}(y, B)) &= U_2^{aut}(y). \end{aligned}
- For x \in [\underline{x}(y, B), \overline{x}(y, B)], where no participation constraint binds, first check if B' = 0 satisfied the planner’s Euler equation: u'(c_1(y, B, x)) \ge \beta (1 + r) \sum_{y'} Pr(y') \frac{u'(c_1(y', 0, x))}{1 - \nu_1(y', 0, x)}. If this is violated, I solve for B' such that the planner’s Euler equation holds with equality: u'(c_1(y, B, x)) = \beta (1 + r) \sum_{y'} Pr(y') \frac{u'(c_1(y', B', x))}{1 - \nu_1(y', B', x)}. Then update B'^h(y, B, x) with the solution. The value functions are updated as follows: \begin{aligned} V_1^{h}(y, B, x) &= u(c_1(y, B, x)) + \beta \sum_{y'} Pr(y') V_1^{h - 1}(y', B'^h(y, B, x), x) \\ V_2^{h}(y, B, x) &= u(c_1(y, B, x)) + \beta \sum_{y'} Pr(y') V_1^{h - 1}(y', B'^h(y, B, x), x). \end{aligned}
- For x < \underline{y, B}, update the policy functions and value functions in the following way (remember that these do not depend on x, as discussed in the modeling solution section above): \begin{aligned} V_1^{h}(y, B, x) &= V_1^h(y, B, \underline{x}(y, B)) \\ V_2^{h}(y, B, x) &= U_2^{aut}(y) \\ B^h(y, B, x) &= B^h(y, B, \underline{x}(y, B)). \end{aligned} Similarly, for x > \overline{y, B}, the policy functions and value functions are updated such that \begin{aligned} V_1^{h}(y, B, x) &= U_1^{aut}(y) \\ V_2^{h}(y, B, x) &= V_2^h(y, B, \overline{x}(y, B)) \\ B^h(y, B, x) &= B^h(y, B, \overline{x}(y, B)). \end{aligned}
2.2 Numerical solutions
2.2.1 Global settings
set.seed(123)
<- 3
numStates <- 201
numRelativeParetoWeights <- 0.8
beta <- 1
sigma
<- c(0.353, 0.5, 0.647)
incomeGridPointsHH1 <- 1 - incomeGridPointsHH1
incomeGridPointsHH2 <- incomeGridPointsHH1 + incomeGridPointsHH2
aggregateIncomeGridPoints
<- rep(1 / 3, 3)
incomeTransitionProbVec <- matrix(1 / 3, nrow = 3, ncol = 3)
incomeTransitionMatrix
<- 0.02 returnOnStorage
<- function(cons, sigma) {
calculateUtility if (sigma != 1) {
= (cons^(1 - sigma) - 1) / (1 - sigma)
utility else if (sigma == 1) {
} = log(cons)
utility
}return(utility)
}<- function(cons, sigma) cons^(- sigma) calculateMarginalUtility
<- function(incomeGridPointsHH1) {
createStorageGridPoints <- seq(0, sqrt(max(incomeGridPointsHH1)), by = 1e-2)^2
storageGridPoints <- length(storageGridPoints)
numStorageGridPoints return(list(storageGridPoints, numStorageGridPoints))
}
<- function(
createRelativeParetoWeightGridPoints
returnOnStorage,
storageGridPoints,
incomeGridPointsHH1
) {<- (
maxRelativeParetoWeight 1 + (1 + returnOnStorage) * max(storageGridPoints)) / min(incomeGridPointsHH1) - 1
(
)<- 1 / maxRelativeParetoWeight
minRelativeParetoWeight
<- c(
relativeParetoWeightsGridPoints seq(
1,
minRelativeParetoWeight, by = (1 - minRelativeParetoWeight) / floor(numRelativeParetoWeights / 2)
),rev(1 / seq(
1,
minRelativeParetoWeight, by = (1 - minRelativeParetoWeight) / floor(numRelativeParetoWeights / 2)
1:floor(numRelativeParetoWeights / 2)])
)[
)
return(relativeParetoWeightsGridPoints)
}
2.2.2 Value at autarky with private storage
<- function(
calculateEulerEquationDiffAutarky
consumption,
income,
storage,
beta,
sigma,
returnOnStorage,
incomeProb,
storageGridPoints,
consumptionAutarkyMatrix
) {
<- apply(
interpolatedConsumptionByIncome
consumptionAutarkyMatrix,1,
function(x) {
approx(
storageGridPoints,
x,+ (1 + returnOnStorage) * storage - consumption,
income rule = 2
$y}
)
)
return(
calculateMarginalUtility(consumption, sigma) - (
* (1 + returnOnStorage) * (
beta %*% calculateMarginalUtility(interpolatedConsumptionByIncome, sigma)
incomeProb
)
)
)
}
<- function(
interpolateValueByIncome
consumption,
income,
storage,
valueAutarkyMatrix,
storageGridPoints,
returnOnStorage
) {return(
apply(
valueAutarkyMatrix,1,
function(x) {
approx(
storageGridPoints,
x,+ (1 + returnOnStorage) * storage - consumption,
income rule = 2
$y}
)
)
)
}
<- function(
updateValueAutarky
consumption,
interpolatedValueByIncome,
incomeProb,
beta,
sigma
) {return(
(calculateUtility(consumption, sigma)
+ beta * (
%*% interpolatedValueByIncome
incomeProb
)
)
)
}
<- function(
computeConsumptionAutarky
returnOnStorage,
storageGridPoints,
incomeGridPoints,
beta,
sigma,
incomeProb,
numStates,
numStorageGridPoints,iterationTol = 1e-8,
maxIteration = 100
) {
<- outer(rep(1, numStates), (1 / beta - 1) * storageGridPoints) + 1e-8
consumptionAutarkyMatrix <- matrix(NA, nrow = numStates, numStorageGridPoints)
consumptionAutarkyMatrixNew
<- 1
iter <- 1
diff while ((diff > iterationTol) & (iter < maxIteration)) {
for (stateIndex in seq(1, numStates)) {
for (storageIndex in seq(1, numStorageGridPoints)) {
if (calculateEulerEquationDiffAutarky(
* (1 + returnOnStorage) + incomeGridPoints[stateIndex],
storageGridPoints[storageIndex]
incomeGridPoints[stateIndex],
storageGridPoints[storageIndex],
beta,
sigma,
returnOnStorage,
incomeTransitionMatrix[stateIndex,],
storageGridPoints,
consumptionAutarkyMatrix>= 0) {
) <- (
consumptionAutarkyMatrixNew[stateIndex, storageIndex] * (1 + returnOnStorage) + incomeGridPoints[stateIndex]
storageGridPoints[storageIndex]
)else {
} <- uniroot(
consumptionAutarkyMatrixNew[stateIndex, storageIndex] function(x) {calculateEulerEquationDiffAutarky(
x,
incomeGridPoints[stateIndex],
storageGridPoints[storageIndex],
beta,
sigma,
returnOnStorage,
incomeTransitionMatrix[stateIndex, ],
storageGridPoints,
consumptionAutarkyMatrix
)},c(
1e-12,
* (1 + returnOnStorage) + incomeGridPoints[stateIndex]
storageGridPoints[storageIndex]
)$root
)
}
}
}
<- max(abs(consumptionAutarkyMatrixNew - consumptionAutarkyMatrix))
diff <- consumptionAutarkyMatrixNew
consumptionAutarkyMatrix <- iter + 1
iter
}
return(consumptionAutarkyMatrix)
}
<- function(
computeValueAutarky
consumptionAutarkyMatrix,
returnOnStorage,
storageGridPoints,
incomeGridPoints,
beta,
sigma,
incomeProb,
numStates,
numStorageGridPoints,iterationTol = 1e-8,
maxIteration = 100
) {
<- calculateUtility(consumptionAutarkyMatrix, sigma) / (1 - beta)
valueAutarkyMatrix <- matrix(NA, nrow = numStates, ncol = numStorageGridPoints)
valueAutarkyMatrixNew
<- 1
iter <- 1
diff while ((diff > iterationTol) & (iter < maxIteration)) {
for (stateIndex in seq(1, numStates)) {
for (storageIndex in seq(1, numStorageGridPoints)) {
<- interpolateValueByIncome(
interpolatedValueByIncome
consumptionAutarkyMatrix[stateIndex, storageIndex],
incomeGridPoints[stateIndex],
storageGridPoints[storageIndex],
valueAutarkyMatrix,
storageGridPoints,
returnOnStorage
)<- updateValueAutarky(
valueAutarkyMatrixNew[stateIndex, storageIndex]
consumptionAutarkyMatrix[stateIndex, storageIndex],
interpolatedValueByIncome,
incomeTransitionMatrix[stateIndex,],
beta,
sigma%>% as.numeric
)
}
}
<- max(abs(valueAutarkyMatrixNew - valueAutarkyMatrix))
diff <- valueAutarkyMatrixNew
valueAutarkyMatrix <- iter + 1
iter
}
return(valueAutarkyMatrix)
}
<- function(
solveValueAutarky
returnOnStorage,
storageGridPoints,
incomeGridPoints,
beta,
sigma,
incomeProb,
numStates,
numStorageGridPoints
) {
<- computeConsumptionAutarky(
consumptionAutarkyMatrix
returnOnStorage,
storageGridPoints,
incomeGridPoints,
beta,
sigma,
incomeProb,
numStates,
numStorageGridPoints
)
<- computeValueAutarky(
valueAutarkyMatrix
consumptionAutarkyMatrix,
returnOnStorage,
storageGridPoints,
incomeGridPoints,
beta,
sigma,
incomeProb,
numStates,
numStorageGridPoints
)
<- valueAutarkyMatrix[, 1]
valueAutarkyZeroPrivateSaving
return(valueAutarkyZeroPrivateSaving)
}
2.2.3 Model with storage and limited commitment
<- function(
calculateHH1Consumption
aggregateResources,
relativeParetoWeight,
sigma
) {/ (1 + (relativeParetoWeight^(1 / sigma)))
aggregateResources
}
<- function(
calculateHH2Consumption
aggregateResources,
relativeParetoWeight,
sigma
) {
(
aggregateResources - aggregateResources / (1 + (relativeParetoWeight^(1 / sigma)))
) }
<- function(
calculateEulerEquationDiff
aggregateIncome,
currentStorage,
currentRelativeParetoWeight,
returnOnStorage,
nextPeriodStorage,
aggregateIncomeGridPoints,
relativeParetoWeightsGridPoints,
nextStorageArray,
relativeParetoWeightsBoundsArray,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta
) {
<- map_dbl(
nextRelativeParetoWeight seq(1, numStates),
function(x) {
%>%
currentRelativeParetoWeight pmax(
approx(
storageGridPoints,1, x, ],
relativeParetoWeightsBoundsArray[
nextPeriodStorage,rule = 2
$y
)%>%
) pmin(
approx(
storageGridPoints,2, x, ],
relativeParetoWeightsBoundsArray[
nextPeriodStorage,rule = 2
$y
)
)
}
)
<- (1 - (nextRelativeParetoWeight / currentRelativeParetoWeight)) %>% pmax(0)
nu
return(
calculateMarginalUtility(
calculateHH1Consumption(
aggregateIncome+ (1 + returnOnStorage) * currentStorage - nextPeriodStorage,
currentRelativeParetoWeight,
sigma
),
sigma- (
) * (1 + returnOnStorage) * incomeTransitionProbVec %*% (
beta calculateMarginalUtility(
calculateHH1Consumption(
aggregateIncomeGridPoints + (1 + returnOnStorage) * nextPeriodStorage
- map_dbl(
seq(1, numStates),
function(xx) interp2(
x = storageGridPoints,
y = relativeParetoWeightsGridPoints,
Z = nextStorageArray[xx, , ],
xp = nextPeriodStorage %>%
pmin(max(storageGridPoints)) %>%
pmax(min(storageGridPoints)),
yp = nextRelativeParetoWeight[xx] %>%
pmin(max(relativeParetoWeightsGridPoints)) %>%
pmax(min(relativeParetoWeightsGridPoints)),
method = "linear"
)
),
nextRelativeParetoWeight,
sigma
),
sigma/ (1 - nu)
) %>% as.numeric
)
)
)
}
<- function(
calculateValue
aggregateIncome,
currentStorage,
currentRelativeParetoWeight,
returnOnStorage,
nextPeriodStorage,
relativeParetoWeightsGridPoints,
valueArray,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHouseholdConsumption
) {
return(
calculateUtility(
calculateHouseholdConsumption(
aggregateIncome+ (1 + returnOnStorage) * currentStorage
- nextPeriodStorage,
currentRelativeParetoWeight,
sigma%>% pmax(1e-12)
)
, sigma+ (
)
beta * incomeTransitionProbVec
%*% map_dbl(
seq(1, numStates),
function(xx) {interp2(
x = storageGridPoints,
y = relativeParetoWeightsGridPoints,
Z = valueArray[xx, , ],
xp = nextPeriodStorage %>%
pmin(max(storageGridPoints)) %>%
pmax(min(storageGridPoints)),
yp = currentRelativeParetoWeight %>%
pmin(max(relativeParetoWeightsGridPoints)) %>%
pmax(min(relativeParetoWeightsGridPoints)),
method = "linear"
)}%>% as.numeric)
)
)
}
<- function(
calculatePCDiff
aggregateIncome,
currentStorage,
currentRelativeParetoWeight,
returnOnStorage,
nextPeriodStorage,
relativeParetoWeightsGridPoints,
valueArray,
valueAutarky,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHouseholdConsumption
) {return(
calculateValue(
aggregateIncome,
currentStorage,
currentRelativeParetoWeight,
returnOnStorage,
nextPeriodStorage,
relativeParetoWeightsGridPoints,
valueArray,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHouseholdConsumption- valueAutarky
)
) }
<- function(
solveLCWithStorage
beta,
sigma,
returnOnStorage,
numStates,
incomeGridPointsHH1,
incomeGridPointsHH2,
aggregateIncomeGridPoints,
incomeTransitionProbVec,
incomeTransitionMatrix
) {
<- createStorageGridPoints(incomeGridPointsHH1)
storageGridPointList <- storageGridPointList[[1]]
storageGridPoints <- storageGridPointList[[2]]
numStorageGridPoints
<- createRelativeParetoWeightGridPoints(
relativeParetoWeightsGridPoints
returnOnStorage,
storageGridPoints,
incomeGridPointsHH1
)
<- solveValueAutarky(
valueAutarkyHH1
returnOnStorage,
storageGridPoints,
incomeGridPointsHH1,
beta,
sigma,
incomeProb,
numStates,
numStorageGridPoints
)
<- solveValueAutarky(
valueAutarkyHH2
returnOnStorage,
storageGridPoints,
incomeGridPointsHH2,
beta,
sigma,
incomeProb,
numStates,
numStorageGridPoints
)
# Initial values for value functions:
# No next-period storage and full-risk sharing
<- array(
consumptionOnRelativeParetoWeightAndStorageGridHH1 NA, dim = c(numStates, numRelativeParetoWeights, numStorageGridPoints)
)for (stateIndex in seq(1, numStates)) {
for (weightIndex in seq(1, numRelativeParetoWeights)) {
<- (
consumptionOnRelativeParetoWeightAndStorageGridHH1[stateIndex, weightIndex, ] calculateHH1Consumption(
+ (1 + returnOnStorage) * storageGridPoints,
aggregateIncomeGridPoints[stateIndex]
relativeParetoWeightsGridPoints[weightIndex],
sigma
)
)
}
}<- array(
consumptionOnRelativeParetoWeightAndStorageGridHH2 NA, dim = c(numStates, numRelativeParetoWeights, numStorageGridPoints)
)for (stateIndex in seq(1, numStates)) {
for (weightIndex in seq(1, numRelativeParetoWeights)) {
<- (
consumptionOnRelativeParetoWeightAndStorageGridHH2[stateIndex, weightIndex, ] + (1 + returnOnStorage) * storageGridPoints
aggregateIncomeGridPoints[stateIndex] - consumptionOnRelativeParetoWeightAndStorageGridHH1[stateIndex, weightIndex, ]
)
}
}
<- (
valueArrayHH1 calculateUtility(consumptionOnRelativeParetoWeightAndStorageGridHH1, sigma) / (1 - beta)
)<- (
valueArrayHH2 calculateUtility(consumptionOnRelativeParetoWeightAndStorageGridHH2, sigma) / (1 - beta)
)<- valueArrayHH1
valueArrayHH1New <- valueArrayHH2
valueArrayHH2New
# Initial values for interval bounds:
# equal allocation only
<- array(
relativeParetoWeightsBoundsArray 1, dim = c(2, numStates, numStorageGridPoints)
)<- array(
relativeParetoWeightsBoundsArrayNew NA, dim = c(2, numStates, numStorageGridPoints)
)
# Initial values for next period storage:
# zero storage
<- array(
nextStorageArray 0, dim = c(numStates, numRelativeParetoWeights, numStorageGridPoints)
)<- array(
nextStorageArrayNew 0, dim = c(numStates, numRelativeParetoWeights, numStorageGridPoints)
)
<- 1
diff <- 1
iter while ((diff > 1e-4) & (iter < 120)) {
for (stateIndex in seq(1, numStates)) {
for (storageIndex in seq(1, numStorageGridPoints)) {
# (i) Find upper bound
if (
calculatePCDiff(
aggregateIncomeGridPoints[stateIndex],currentStorage = storageGridPoints[storageIndex],
currentRelativeParetoWeight = max(relativeParetoWeightsGridPoints),
returnOnStorage,nextPeriodStorage = 0,
relativeParetoWeightsGridPoints,valueArray = valueArrayHH1,
valueAutarky = valueAutarkyHH1[stateIndex],
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH1Consumption> 0
)
) {<- max(relativeParetoWeightsGridPoints)
relativeParetoWeightsUpperTmp else {
} <- uniroot(
relativeParetoWeightsUpperTmp function(x) {
calculatePCDiff(
aggregateIncomeGridPoints[stateIndex],currentStorage = storageGridPoints[storageIndex],
currentRelativeParetoWeight = x,
returnOnStorage,nextPeriodStorage = 0,
relativeParetoWeightsGridPoints,valueArray = valueArrayHH1,
valueAutarky = valueAutarkyHH1[stateIndex],
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH1Consumption
)
},c(min(relativeParetoWeightsGridPoints), max(relativeParetoWeightsGridPoints))
$root
)
}
if (
calculateEulerEquationDiff(
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightsUpperTmp,
returnOnStorage,nextPeriodStorage = 0,
aggregateIncomeGridPoints,
relativeParetoWeightsGridPoints,
nextStorageArray,
relativeParetoWeightsBoundsArray,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta>= 0
)
) {
nextStorageArrayNew[
stateIndex, which.min(abs(
- relativeParetoWeightsGridPoints
relativeParetoWeightsUpperTmp
)),
storageIndex<- 0
] 2, stateIndex, storageIndex] <- relativeParetoWeightsUpperTmp
relativeParetoWeightsBoundsArrayNew[else {
} <- nleqslv(
resSolve c(0.5, 1),
function(x) {
<- x[1]
nextPeriodStorage <- x[2]
relativeParetoWeightUpperBound <- numeric(2)
y
1] <- calculateEulerEquationDiff(
y[
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightUpperBound,
returnOnStorage,nextPeriodStorage = nextPeriodStorage,
aggregateIncomeGridPoints,
relativeParetoWeightsGridPoints,
nextStorageArray,
relativeParetoWeightsBoundsArray,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta
)
2] <- calculatePCDiff(
y[
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightUpperBound,
returnOnStorage,nextPeriodStorage = nextPeriodStorage,
relativeParetoWeightsGridPoints,valueArray = valueArrayHH1,
valueAutarky = valueAutarkyHH1[stateIndex],
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH1Consumption
)return(y)
}$x
)
nextStorageArrayNew[
stateIndex, which.min(abs(
2] - relativeParetoWeightsGridPoints
resSolve[
)),
storageIndex<- resSolve[1]
] 2, stateIndex, storageIndex] <- resSolve[2]
relativeParetoWeightsBoundsArrayNew[
}
# (ii) Find lower bound
if (
calculatePCDiff(
aggregateIncomeGridPoints[stateIndex],currentStorage = storageGridPoints[storageIndex],
currentRelativeParetoWeight = min(relativeParetoWeightsGridPoints),
returnOnStorage,nextPeriodStorage = 0,
relativeParetoWeightsGridPoints,valueArray = valueArrayHH2,
valueAutarky = valueAutarkyHH2[stateIndex],
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH2Consumption> 0
)
) {<- min(relativeParetoWeightsGridPoints)
relativeParetoWeightsLowerTmp else {
} <- uniroot(
relativeParetoWeightsLowerTmp function(x) {
calculatePCDiff(
aggregateIncomeGridPoints[stateIndex],currentStorage = storageGridPoints[storageIndex],
currentRelativeParetoWeight = x,
returnOnStorage,nextPeriodStorage = 0,
relativeParetoWeightsGridPoints,valueArray = valueArrayHH2,
valueAutarky = valueAutarkyHH2[stateIndex],
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH2Consumption
)
},c(min(relativeParetoWeightsGridPoints), max(relativeParetoWeightsGridPoints))
$root
)
}
if (
calculateEulerEquationDiff(
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightsLowerTmp,
returnOnStorage,nextPeriodStorage = 0,
aggregateIncomeGridPoints,
relativeParetoWeightsGridPoints,
nextStorageArray,
relativeParetoWeightsBoundsArray,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta>= 0
)
) {
nextStorageArrayNew[
stateIndex, which.min(abs(
- relativeParetoWeightsGridPoints
relativeParetoWeightsLowerTmp
)),
storageIndex<- 0
] 1, stateIndex, storageIndex] <- relativeParetoWeightsLowerTmp
relativeParetoWeightsBoundsArrayNew[else {
} <- nleqslv(
resSolve c(0.5, 1),
function(x) {
<- x[1]
nextPeriodStorage <- x[2]
relativeParetoWeightLowerBound <- numeric(2)
y
1] <- calculateEulerEquationDiff(
y[
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightLowerBound,
returnOnStorage,nextPeriodStorage = nextPeriodStorage,
aggregateIncomeGridPoints,
relativeParetoWeightsGridPoints,
nextStorageArray,
relativeParetoWeightsBoundsArray,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta
)
2] <- calculatePCDiff(
y[
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightLowerBound,
returnOnStorage,nextPeriodStorage = nextPeriodStorage,
relativeParetoWeightsGridPoints,valueArray = valueArrayHH2,
valueAutarky = valueAutarkyHH2[stateIndex],
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH2Consumption
)
return(y)
}$x
)
nextStorageArrayNew[
stateIndex, which.min(abs(
2] - relativeParetoWeightsGridPoints
resSolve[
)),
storageIndex<- resSolve[1]
] 1, stateIndex, storageIndex] <- resSolve[2]
relativeParetoWeightsBoundsArrayNew[
}
# (iii) Calculate values in between
<- relativeParetoWeightsBoundsArrayNew[1, stateIndex, storageIndex]
relativeParetoWeightsLower <- relativeParetoWeightsBoundsArrayNew[2, stateIndex, storageIndex]
relativeParetoWeightsUpper
<- which.min(
relativeParetoWeightsLowerIndex abs(relativeParetoWeightsGridPoints - relativeParetoWeightsLower)
)<- which.min(
relativeParetoWeightsUpperIndex abs(relativeParetoWeightsGridPoints - relativeParetoWeightsUpper)
)
for (weightIndex in seq(relativeParetoWeightsLowerIndex, relativeParetoWeightsUpperIndex)) {
if (
calculateEulerEquationDiff(
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],
relativeParetoWeightsGridPoints[weightIndex],
returnOnStorage,nextPeriodStorage = 0,
aggregateIncomeGridPoints,
relativeParetoWeightsGridPoints,
nextStorageArray,
relativeParetoWeightsBoundsArray,
incomeTransitionMatrix[stateIndex,],
storageGridPoints,
numStates,
sigma,
beta> 0) {
) <- 0
nextStorageArrayNew[stateIndex, weightIndex, storageIndex] <- calculateValue(
valueArrayHH1New[stateIndex, weightIndex, storageIndex]
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightsGridPoints[weightIndex],
returnOnStorage,nextPeriodStorage = 0,
relativeParetoWeightsGridPoints,
valueArrayHH1,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH1Consumption
)<- calculateValue(
valueArrayHH2New[stateIndex, weightIndex, storageIndex]
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightsGridPoints[weightIndex],
returnOnStorage,nextPeriodStorage = 0,
relativeParetoWeightsGridPoints,
valueArrayHH2,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH2Consumption
)else {
} <- uniroot(
nextStorageArrayNew[stateIndex, weightIndex, storageIndex] function(x) {calculateEulerEquationDiff(
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],
relativeParetoWeightsGridPoints[weightIndex],
returnOnStorage,
x,
aggregateIncomeGridPoints,
relativeParetoWeightsGridPoints,
nextStorageArray,
relativeParetoWeightsBoundsArray,
incomeTransitionMatrix[stateIndex,],
storageGridPoints,
numStates,
sigma,
beta
)},c(
0,
aggregateIncomeGridPoints[stateIndex] + (1 + returnOnStorage) * storageGridPoints[storageIndex]
- 1e-12
)$root
)<- calculateValue(
valueArrayHH1New[stateIndex, weightIndex, storageIndex]
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightsGridPoints[weightIndex],
returnOnStorage,nextPeriodStorage = nextStorageArrayNew[stateIndex, weightIndex, storageIndex],
relativeParetoWeightsGridPoints,
valueArrayHH1,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH1Consumption
)<- calculateValue(
valueArrayHH2New[stateIndex, weightIndex, storageIndex]
aggregateIncomeGridPoints[stateIndex],
storageGridPoints[storageIndex],currentRelativeParetoWeight = relativeParetoWeightsGridPoints[weightIndex],
returnOnStorage,nextPeriodStorage = nextStorageArrayNew[stateIndex, weightIndex, storageIndex],
relativeParetoWeightsGridPoints,
valueArrayHH2,
incomeTransitionProbVec,
storageGridPoints,
numStates,
sigma,
beta,
calculateHH2Consumption
)
}
}
# Values and policies outside the interval
nextStorageArrayNew[
stateIndex,> relativeParetoWeightsUpper,
relativeParetoWeightsGridPoints
storageIndex<- nextStorageArrayNew[
]
stateIndex,
relativeParetoWeightsUpperIndex,
storageIndex
]
valueArrayHH1New[
stateIndex,> relativeParetoWeightsUpper,
relativeParetoWeightsGridPoints
storageIndex<- valueArrayHH1New[
]
stateIndex,
relativeParetoWeightsUpperIndex,
storageIndex
]
valueArrayHH2New[
stateIndex,> relativeParetoWeightsUpper,
relativeParetoWeightsGridPoints
storageIndex<- valueArrayHH2New[
]
stateIndex,
relativeParetoWeightsUpperIndex,
storageIndex
]
nextStorageArrayNew[
stateIndex,< relativeParetoWeightsLower,
relativeParetoWeightsGridPoints
storageIndex<- nextStorageArrayNew[
]
stateIndex,
relativeParetoWeightsLowerIndex,
storageIndex
]
valueArrayHH1New[
stateIndex,< relativeParetoWeightsLower,
relativeParetoWeightsGridPoints
storageIndex<- valueArrayHH1New[
]
stateIndex,
relativeParetoWeightsLowerIndex,
storageIndex
]
valueArrayHH2New[
stateIndex,< relativeParetoWeightsLower,
relativeParetoWeightsGridPoints
storageIndex<- valueArrayHH2New[
]
stateIndex,
relativeParetoWeightsLowerIndex,
storageIndex
]
}
}
<- max(c(
diff max(abs(valueArrayHH1New - valueArrayHH1)),
max(abs(valueArrayHH2New - valueArrayHH2))
))
<- relativeParetoWeightsBoundsArrayNew
relativeParetoWeightsBoundsArray <- nextStorageArrayNew
nextStorageArray <- valueArrayHH1New
valueArrayHH1 <- valueArrayHH2New
valueArrayHH2 <- iter + 1
iter
}
return(
list(
valueArrayHH1 = valueArrayHH1,
valueArrayHH2 = valueArrayHH2,
nextStorageArray = nextStorageArray,
relativeParetoWeightsBoundsArray = relativeParetoWeightsBoundsArray
)
) }
<- solveLCWithStorage(
LCWithStorageResult
beta,
sigma,
returnOnStorage,
numStates,
incomeGridPointsHH1,
incomeGridPointsHH2,
aggregateIncomeGridPoints,
incomeTransitionProbVec,
incomeTransitionMatrix )
saveRDS(
LCWithStorageResult,file.path('IntermediateData/modelSolution.rds')
)
Ábrahám, Árpád, and Sarolta Laczó. 2018. “Efficient Risk Sharing with Limited Commitment and Storage.” The Review of Economic Studies 85 (3): 1389–1424.