GitHub

@@ -0,0 +1,298 @@

1+

import numpy as np

2+

from scipy.optimize import fmin_slsqp

3+

from scipy.optimize import root

4+

from quantecon import MarkovChain

5+6+7+

class RecursiveAllocationAMSS:

8+9+

def __init__(self, model, μgrid, tol_diff=1e-7, tol=1e-7):

10+11+

self.β, self.π, self.G = model.β, model.π, model.G

12+

self.mc, self.S = MarkovChain(self.π), len(model.π) # Number of states

13+

self.Θ, self.model, self.μgrid = model.Θ, model, μgrid

14+

self.tol_diff, self.tol = tol_diff, tol

15+16+

# Find the first best allocation

17+

self.solve_time1_bellman()

18+

self.T.time_0 = True # Bellman equation now solves time 0 problem

19+20+

def solve_time1_bellman(self):

21+

'''

22+

Solve the time 1 Bellman equation for calibration model and

23+

initial grid μgrid0

24+

'''

25+

model, μgrid0 = self.model, self.μgrid

26+

π = model.π

27+

S = len(model.π)

28+29+

# First get initial fit from Lucas Stokey solution.

30+

# Need to change things to be ex ante

31+

pp = SequentialAllocation(model)

32+

interp = interpolator_factory(2, None)

33+34+

def incomplete_allocation(μ_, s_):

35+

c, n, x, V = pp.time1_value(μ_)

36+

return c, n, π[s_] @ x, π[s_] @ V

37+

cf, nf, xgrid, Vf, xprimef = [], [], [], [], []

38+

for s_ in range(S):

39+

c, n, x, V = zip(*map(lambda μ: incomplete_allocation(μ, s_), μgrid0))

40+

c, n = np.vstack(c).T, np.vstack(n).T

41+

x, V = np.hstack(x), np.hstack(V)

42+

xprimes = np.vstack([x] * S)

43+

cf.append(interp(x, c))

44+

nf.append(interp(x, n))

45+

Vf.append(interp(x, V))

46+

xgrid.append(x)

47+

xprimef.append(interp(x, xprimes))

48+

cf, nf, xprimef = fun_vstack(cf), fun_vstack(nf), fun_vstack(xprimef)

49+

Vf = fun_hstack(Vf)

50+

policies = [cf, nf, xprimef]

51+52+

# Create xgrid

53+

x = np.vstack(xgrid).T

54+

xbar = [x.min(0).max(), x.max(0).min()]

55+

xgrid = np.linspace(xbar[0], xbar[1], len(μgrid0))

56+

self.xgrid = xgrid

57+58+

# Now iterate on Bellman equation

59+

T = BellmanEquation(model, xgrid, policies, tol=self.tol)

60+

diff = 1

61+

while diff > self.tol_diff:

62+

PF = T(Vf)

63+64+

Vfnew, policies = self.fit_policy_function(PF)

65+

diff = np.abs((Vf(xgrid) - Vfnew(xgrid)) / Vf(xgrid)).max()

66+67+

print(diff)

68+

Vf = Vfnew

69+70+

# Store value function policies and Bellman Equations

71+

self.Vf = Vf

72+

self.policies = policies

73+

self.T = T

74+75+

def fit_policy_function(self, PF):

76+

'''

77+

Fits the policy functions

78+

'''

79+

S, xgrid = len(self.π), self.xgrid

80+

interp = interpolator_factory(3, 0)

81+

cf, nf, xprimef, Tf, Vf = [], [], [], [], []

82+

for s_ in range(S):

83+

PFvec = np.vstack([PF(x, s_) for x in self.xgrid]).T

84+

Vf.append(interp(xgrid, PFvec[0, :]))

85+

cf.append(interp(xgrid, PFvec[1:1 + S]))

86+

nf.append(interp(xgrid, PFvec[1 + S:1 + 2 * S]))

87+

xprimef.append(interp(xgrid, PFvec[1 + 2 * S:1 + 3 * S]))

88+

Tf.append(interp(xgrid, PFvec[1 + 3 * S:]))

89+

policies = fun_vstack(cf), fun_vstack(

90+

nf), fun_vstack(xprimef), fun_vstack(Tf)

91+

Vf = fun_hstack(Vf)

92+

return Vf, policies

93+94+

def Τ(self, c, n):

95+

'''

96+

Computes Τ given c and n

97+

'''

98+

model = self.model

99+

Uc, Un = model.Uc(c, n), model.Un(c, n)

100+101+

return 1 + Un / (self.Θ * Uc)

102+103+

def time0_allocation(self, B_, s0):

104+

'''

105+

Finds the optimal allocation given initial government debt B_ and

106+

state s_0

107+

'''

108+

PF = self.T(self.Vf)

109+

z0 = PF(B_, s0)

110+

c0, n0, xprime0, T0 = z0[1:]

111+

return c0, n0, xprime0, T0

112+113+

def simulate(self, B_, s_0, T, sHist=None):

114+

'''

115+

Simulates planners policies for T periods

116+

'''

117+

model, π = self.model, self.π

118+

Uc = model.Uc

119+

cf, nf, xprimef, Tf = self.policies

120+121+

if sHist is None:

122+

sHist = simulate_markov(π, s_0, T)

123+124+

cHist, nHist, Bhist, xHist, ΤHist, THist, μHist = np.zeros((7, T))

125+

# Time 0

126+

cHist[0], nHist[0], xHist[0], THist[0] = self.time0_allocation(B_, s_0)

127+

ΤHist[0] = self.Τ(cHist[0], nHist[0])[s_0]

128+

Bhist[0] = B_

129+

μHist[0] = self.Vf[s_0](xHist[0])

130+131+

# Time 1 onward

132+

for t in range(1, T):

133+

s_, x, s = sHist[t - 1], xHist[t - 1], sHist[t]

134+

c, n, xprime, T = cf[s_, :](x), nf[s_, :](

135+

x), xprimef[s_, :](x), Tf[s_, :](x)

136+137+

Τ = self.Τ(c, n)[s]

138+

u_c = Uc(c, n)

139+

Eu_c = π[s_, :] @ u_c

140+141+

μHist[t] = self.Vf[s](xprime[s])

142+143+

cHist[t], nHist[t], Bhist[t], ΤHist[t] = c[s], n[s], x / Eu_c, Τ

144+

xHist[t], THist[t] = xprime[s], T[s]

145+

return np.array([cHist, nHist, Bhist, ΤHist, THist, μHist, sHist, xHist])

146+147+148+

class BellmanEquation:

149+

'''

150+

Bellman equation for the continuation of the Lucas-Stokey Problem

151+

'''

152+153+

def __init__(self, model, xgrid, policies0, tol, maxiter=1000):

154+155+

self.β, self.π, self.G = model.β, model.π, model.G

156+

self.S = len(model.π) # Number of states

157+

self.Θ, self.model, self.tol = model.Θ, model, tol

158+

self.maxiter = maxiter

159+160+

self.xbar = [min(xgrid), max(xgrid)]

161+

self.time_0 = False

162+163+

self.z0 = {}

164+

cf, nf, xprimef = policies0

165+166+

for s_ in range(self.S):

167+

for x in xgrid:

168+

self.z0[x, s_] = np.hstack([cf[s_, :](x),

169+

nf[s_, :](x),

170+

xprimef[s_, :](x),

171+

np.zeros(self.S)])

172+173+

self.find_first_best()

174+175+

def find_first_best(self):

176+

'''

177+

Find the first best allocation

178+

'''

179+

model = self.model

180+

S, Θ, Uc, Un, G = self.S, self.Θ, model.Uc, model.Un, self.G

181+182+

def res(z):

183+

c = z[:S]

184+

n = z[S:]

185+

return np.hstack([Θ * Uc(c, n) + Un(c, n), Θ * n - c - G])

186+187+

res = root(res, 0.5 * np.ones(2 * S))

188+

if not res.success:

189+

raise Exception('Could not find first best')

190+191+

self.cFB = res.x[:S]

192+

self.nFB = res.x[S:]

193+

IFB = Uc(self.cFB, self.nFB) * self.cFB + \

194+

Un(self.cFB, self.nFB) * self.nFB

195+196+

self.xFB = np.linalg.solve(np.eye(S) - self.β * self.π, IFB)

197+198+

self.zFB = {}

199+

for s in range(S):

200+

self.zFB[s] = np.hstack(

201+

[self.cFB[s], self.nFB[s], self.π[s] @ self.xFB, 0.])

202+203+

def __call__(self, Vf):

204+

'''

205+

Given continuation value function next period return value function this

206+

period return T(V) and optimal policies

207+

'''

208+

if not self.time_0:

209+

def PF(x, s): return self.get_policies_time1(x, s, Vf)

210+

else:

211+

def PF(B_, s0): return self.get_policies_time0(B_, s0, Vf)

212+

return PF

213+214+

def get_policies_time1(self, x, s_, Vf):

215+

'''

216+

Finds the optimal policies

217+

'''

218+

model, β, Θ, G, S, π = self.model, self.β, self.Θ, self.G, self.S, self.π

219+

U, Uc, Un = model.U, model.Uc, model.Un

220+221+

def objf(z):

222+

c, n, xprime = z[:S], z[S:2 * S], z[2 * S:3 * S]

223+224+

Vprime = np.empty(S)

225+

for s in range(S):

226+

Vprime[s] = Vf[s](xprime[s])

227+228+

return -π[s_] @ (U(c, n) + β * Vprime)

229+230+

def objf_prime(x):

231+232+

epsilon = 1e-7

233+

x0 = np.asfarray(x)

234+

f0 = np.atleast_1d(objf(x0))

235+

jac = np.zeros([len(x0), len(f0)])

236+

dx = np.zeros(len(x0))

237+

for i in range(len(x0)):

238+

dx[i] = epsilon

239+

jac[i] = (objf(x0+dx) - f0)/epsilon

240+

dx[i] = 0.0

241+242+

return jac.transpose()

243+244+

def cons(z):

245+

c, n, xprime, T = z[:S], z[S:2 * S], z[2 * S:3 * S], z[3 * S:]

246+

u_c = Uc(c, n)

247+

Eu_c = π[s_] @ u_c

248+

return np.hstack([

249+

x * u_c / Eu_c - u_c * (c - T) - Un(c, n) * n - β * xprime,

250+

Θ * n - c - G])

251+252+

if model.transfers:

253+

bounds = [(0., 100)] * S + [(0., 100)] * S + \

254+

[self.xbar] * S + [(0., 100.)] * S

255+

else:

256+

bounds = [(0., 100)] * S + [(0., 100)] * S + \

257+

[self.xbar] * S + [(0., 0.)] * S

258+

out, fx, _, imode, smode = fmin_slsqp(objf, self.z0[x, s_],

259+

f_eqcons=cons, bounds=bounds,

260+

fprime=objf_prime, full_output=True,

261+

iprint=0, acc=self.tol, iter=self.maxiter)

262+263+

if imode > 0:

264+

raise Exception(smode)

265+266+

self.z0[x, s_] = out

267+

return np.hstack([-fx, out])

268+269+

def get_policies_time0(self, B_, s0, Vf):

270+

'''

271+

Finds the optimal policies

272+

'''

273+

model, β, Θ, G = self.model, self.β, self.Θ, self.G

274+

U, Uc, Un = model.U, model.Uc, model.Un

275+276+

def objf(z):

277+

c, n, xprime = z[:-1]

278+279+

return -(U(c, n) + β * Vf[s0](xprime))

280+281+

def cons(z):

282+

c, n, xprime, T = z

283+

return np.hstack([

284+

-Uc(c, n) * (c - B_ - T) - Un(c, n) * n - β * xprime,

285+

(Θ * n - c - G)[s0]])

286+287+

if model.transfers:

288+

bounds = [(0., 100), (0., 100), self.xbar, (0., 100.)]

289+

else:

290+

bounds = [(0., 100), (0., 100), self.xbar, (0., 0.)]

291+

out, fx, _, imode, smode = fmin_slsqp(objf, self.zFB[s0], f_eqcons=cons,

292+

bounds=bounds, full_output=True,

293+

iprint=0)

294+295+

if imode > 0:

296+

raise Exception(smode)

297+298+

return np.hstack([-fx, out])

Read the original on github.com ↗