Skip to content

Commit 3c51d8d

Browse files
committed
update calvo_addon note
1 parent 57c299b commit 3c51d8d

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed

lectures/_toc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ parts:
6767
- file: dyn_stack
6868
- file: calvo_machine_learn
6969
- file: calvo
70+
- file: calvo_addon
7071
- file: opt_tax_recur
7172
- file: amss
7273
- file: amss2

lectures/calvo_addon.md

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
---
2+
jupytext:
3+
text_representation:
4+
extension: .md
5+
format_name: myst
6+
format_version: 0.13
7+
jupytext_version: 1.16.1
8+
kernelspec:
9+
display_name: Python 3 (ipykernel)
10+
language: python
11+
name: python3
12+
---
13+
14+
# Another Look at Machine Learning a Ramsey Plan
15+
16+
I'd like you to use your gradient code to compute a Ramsey plan for a versionof Calvo's original model.
17+
18+
That model was not LQ.
19+
20+
But your code can be tweaked to compute the Ramsey plan I suspect.
21+
22+
I sketch the main idea here.
23+
24+
## Calvo's setup
25+
26+
The Ramsey planner's one-period social utility function
27+
is
28+
29+
$$
30+
u(c) + v(m) \equiv u(f(x)) + v(m)
31+
$$
32+
33+
where in our notation Calvo or Chang's objects become
34+
35+
$$
36+
\begin{align*}
37+
x & = \mu \cr
38+
m & = -\alpha \theta \cr
39+
u(c) & = u(f(x)) = u(f(\mu)) \cr
40+
v(m) & = v (-\alpha \theta)
41+
\end{align*}
42+
$$
43+
44+
45+
In the quantecon lecture about the Chang-Calvo model, we deployed the following functional forms:
46+
47+
$$
48+
u(c) = \log(c)
49+
$$
50+
51+
$$
52+
v(m) = \frac{1}{500}(m \bar m - 0.5m^2)^{0.5}
53+
$$
54+
55+
$$
56+
f(x) = 180 - (0.4x)^2
57+
$$
58+
59+
where $\bar m$ is a parameter set somewhere in the quantecon code.
60+
61+
So with this parameterization of Calvo and Chang's functions, components of our one-period criterion become
62+
63+
$$
64+
u(c_t) = \log (180 - (0.4 \mu_t)^2)
65+
$$
66+
67+
and
68+
69+
$$
70+
v(m_t - p_t) = \frac{1}{500}((-\alpha \theta_t) \bar m - 0.5(-\alpha \theta_t)^2)^{0.5}
71+
$$
72+
73+
As in our ``calvo_machine_learning`` lecture, the Ramsey planner maximizes the criterion
74+
75+
$$
76+
\sum_{t=0}^\infty \beta^t [ u(c_t) + v(m_t)] \tag{1}
77+
$$
78+
79+
subject to the constraint
80+
81+
82+
$$
83+
\theta_t = \frac{1}{1+\alpha} \sum_{j=0}^\infty \left(\frac{\alpha}{1+\alpha}\right)^j \mu_{t+j}, \quad t \geq 0 \tag{2}
84+
$$
85+
86+
87+
## Proposal to Humphrey
88+
89+
I'd like to take big parts of the code that you used for the ``gradient`` method only -- the first method you created -- and adapt it to compute a Ramsey plan for this non LQ version of the Calvo's model.
90+
91+
* it is quite close to the version in the main part of Calvo's 1978 classic paper
92+
93+
I'd like you to use exactly the same assumptions about the $\{\mu_t\}_{t=0}^\infty$ process that is in the code, which means that you'll only have to compute a truncated sequence $\{\mu_t\}_{t=0}^T$ parameterized by $T$ and $\bar \mu$ as in the code.
94+
95+
And it would be great if you could also compute the Ramsey plan restricted to a constant $\vec \mu$ sequence so that we could get our hands on that plan to plot and compare with the ordinary Ramsey plan.
96+
97+
98+
After you've computed the Ramsey plan, I'd like to ask you to plot the pretty graphs of $\vec \theta, \vec \mu$ and also $\vec v$ where (recycling notation) here $\vec v$ is a sequence of continuation values.
99+
100+
Qualitatively, these graphs should look a lot like the ones plotted in the ``calvo_machine_learning`` lecture.
101+
102+
Later, after those plots are done, I'd like to describe some **nonlinear** regressions to run that we'll use to try to discover a recursive represenation of a Ramsey plan.
103+
104+
* this will be fun -- we might want to use some neural nets to approximate these functions -- then we'll **really** be doing machine learning.
105+
106+
107+
## Excuses and Apologies
108+
109+
I have recycled some notation -- e.g., $v$ and $v_t$. And Calvo uses $m$ for what we call $m_t - p_t$ and so on.
110+
111+
Later we can do some notation policing and cleaning up.
112+
113+
But right now, let's just proceed as best we can with notation that makes it easiest to take
114+
the ``calvo_machine_learning`` code and apply it with minimal changes.
115+
116+
Thanks!
117+
118+
```{code-cell} ipython3
119+
from quantecon import LQ
120+
import numpy as np
121+
import jax.numpy as jnp
122+
from jax import jit, grad
123+
import optax
124+
import statsmodels.api as sm
125+
import matplotlib.pyplot as plt
126+
```
127+
128+
```{code-cell} ipython3
129+
from collections import namedtuple
130+
131+
def create_ChangML(T=40, β=0.3, c=2, α=1, mbar=30.0):
132+
ChangML = namedtuple('ChangML', ['T', 'β', 'c', 'α',
133+
'mbar'])
134+
135+
return ChangML(T=T, β=β, c=c, α=α, mbar=mbar)
136+
137+
138+
model = create_ChangML()
139+
```
140+
141+
```{code-cell} ipython3
142+
@jit
143+
def compute_θ(μ, α):
144+
λ = α / (1 + α)
145+
T = len(μ) - 1
146+
μbar = μ[-1]
147+
148+
# Create an array of powers for λ
149+
λ_powers = λ ** jnp.arange(T + 1)
150+
151+
# Compute the weighted sums for all t
152+
weighted_sums = jnp.array(
153+
[jnp.sum(λ_powers[:T-t] * μ[t:T]) for t in range(T)])
154+
155+
# Compute θ values except for the last element
156+
θ = (1 - λ) * weighted_sums + λ**(T - jnp.arange(T)) * μbar
157+
158+
# Set the last element
159+
θ = jnp.append(θ, μbar)
160+
161+
return θ
162+
163+
def compute_V(μ, model):
164+
β, c, α, mbar,= model.β, model.c, model.α, model.mbar
165+
θ = compute_θ(μ, α)
166+
167+
T = len(μ) - 1
168+
t = jnp.arange(T)
169+
170+
def u(μ, m, mbar):
171+
# print('μ', μ)
172+
f_μ = 180 - (0.4 * μ)**2
173+
# print('f_μ', f_μ)
174+
# print('m, mbar:', m, mbar, (mbar * m - 0.5 * m**2))
175+
v_m = 1 / 500 * jnp.sqrt(jnp.maximum(1e-16, mbar * m - 0.5 * m**2))
176+
# print('v_μ', v_m)
177+
return jnp.log(f_μ) + v_m
178+
179+
# Compute sum except for the last element
180+
181+
# TO TOM: -α*θ is causing trouble in utility calculation (u) above
182+
# As it makes mbar * m - 0.5 * m**2 < 0 and sqrt of negative
183+
# values returns NA
184+
V_sum = jnp.sum(β**t * u(μ[:T], -α*θ[:T], mbar))
185+
# print('V_sum', V_sum)
186+
187+
# Compute the final term
188+
V_final = (β**T / (1 - β)) * u(μ[-1], -α*θ[-1], mbar)
189+
# print('V_final', V_final)
190+
V = V_sum + V_final
191+
192+
return V
193+
194+
# compute_V(jnp.array([1.0, 1.0, 1.0]), model)
195+
```
196+
197+
```{code-cell} ipython3
198+
def adam_optimizer(grad_func, init_params,
199+
lr=0.1,
200+
max_iter=10_000,
201+
error_tol=1e-7):
202+
203+
# Set initial parameters and optimizer
204+
params = init_params
205+
optimizer = optax.adam(learning_rate=lr)
206+
opt_state = optimizer.init(params)
207+
208+
# Update parameters and gradients
209+
@jit
210+
def update(params, opt_state):
211+
grads = grad_func(params)
212+
updates, opt_state = optimizer.update(grads, opt_state)
213+
params = optax.apply_updates(params, updates)
214+
return params, opt_state, grads
215+
216+
# Gradient descent loop
217+
for i in range(max_iter):
218+
params, opt_state, grads = update(params, opt_state)
219+
220+
if jnp.linalg.norm(grads) < error_tol:
221+
print(f"Converged after {i} iterations.")
222+
break
223+
224+
if i % 100 == 0:
225+
print(f"Iteration {i}, grad norm: {jnp.linalg.norm(grads)}")
226+
227+
return params
228+
```
229+
230+
```{code-cell} ipython3
231+
T = 40
232+
233+
# Initial guess for μ
234+
μ_init = jnp.ones(T)
235+
236+
# Maximization instead of minimization
237+
grad_V = jit(grad(
238+
lambda μ: -compute_V(μ, model)))
239+
```
240+
241+
```{code-cell} ipython3
242+
%%time
243+
244+
# Optimize μ
245+
optimized_μ = adam_optimizer(grad_V, μ_init)
246+
247+
print(f"optimized μ = \n{optimized_μ}")
248+
```
249+
250+
```{code-cell} ipython3
251+
compute_V(optimized_μ, model)
252+
```
253+
254+
```{code-cell} ipython3
255+
model = create_ChangML(β=0.8)
256+
257+
grad_V = jit(grad(
258+
lambda μ: -compute_V(μ, model)))
259+
```
260+
261+
```{code-cell} ipython3
262+
%%time
263+
264+
# Optimize μ
265+
optimized_μ = adam_optimizer(grad_V, μ_init)
266+
267+
print(f"optimized μ = \n{optimized_μ}")
268+
```
269+
270+
```{code-cell} ipython3
271+
compute_V(optimized_μ, model)
272+
```

0 commit comments

Comments
 (0)