@@ -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])