Factor accumulation:
(1) $ \frac{dL_t}{dt} = nL_t $
(2) $ \frac{dE_t}{dt} = gE_t $
(3) $ \frac{dK_t}{dt} = sY_t - δK_t $
Production function:
(4) $ Y_t = K_t^α(L_tE_t)^{(1-α)} $
Definition of capital-output ratio:
(5) $ κ_t = \frac{K_t}{Y_t} $
Solving for the rate of change of the capital-output ratio:
(6) $ Y_t = κ_t^{(α/(1-α))}(L_tE_t) $
(7) $ \frac{1}{K_t}\frac{dK_t}{dt} = \frac{s}{κ_t} - δ $
(8) $ \frac{1}{Y_t}\frac{dY_t}{dt} = α \left( \frac{1}{K_t}\frac{dK_t}{dt} \right) + (1-α)(n+g) $
(9) $ \frac{1}{κ_t}\frac{dκ_t}{dt} = \frac{1}{K_t}\frac{dK_t}{dt} - α \left( \frac{1}{K_t}\frac{dK_t}{dt} \right) - (1-α)(n+g) $
(10) $ \frac{1}{κ_t}\frac{dκ_t}{dt} = (1- α) \left( \frac{1}{K_t}\frac{dK_t}{dt} \right) - (1-α)(n+g) $
(11) $ \frac{1}{κ_t}\frac{dκ_t}{dt} = (1- α) \left( \frac{s}{κ_t} - δ \right) - (1-α)(n+g) $
(12) $ \frac{dκ_t}{dt} = (1- α) \left( s - (n+g+δ)κ_t \right) $
Integrating:
(13) $ κ_t = \frac{s}{n+g+δ} + e^{-(1-α)(n+g+δ)t} \left[ κ_0 - \frac{s}{n+g+δ} \right] $
Discretizing for a difference model:
(14) $ κ_{t+1} = κ_t + \left[ \frac{1 - e^{-(1-α)(n+g+δ)}}{n+g+δ} \right] \left( s - (n+g+δ)κ_t \right) $
(15) $ 1 - α' = (1 - α) [ 1 - \frac{(1-α)(n+g+δ)}{2} + \frac{(1-α)^2(n+g+δ)^2}{6} - ... ] $
(16) $ κ_{t+1} = κ_t + (1- α') \left( s - (n+g+δ)κ_t \right) $
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
class Solow_delong:
"""
Implements the Solow growth model calculation of the
capital-output ratio κ and other model variables
using the update rule:
κ_{t+1} = κ_t + ( 1 - α) ( s - (n+g+δ)κ_t )
Built upon and modified from Stachurski-Sargeant
<https://quantecon.org> class **Solow**
<https://lectures.quantecon.org/py/python_oop.html>
"""
def __init__(self, n=0.01, # population growth rate
s=0.20, # savings rate
δ=0.03, # depreciation rate
α=1/3, # share of capital
g=0.01, # productivity
κ=0.2/(.01+.01+.03), # current capital-labor ratio
E=1.0, # current efficiency of labor
L=1.0): # current labor force
self.n, self.s, self.δ, self.α, self.g = n, s, δ, α, g
self.κ, self.E, self.L = κ, E, L
self.Y = self.κ**(self.α/(1-self.α))*self.E*self.L
self.K = self.κ * self.Y
self.y = self.Y/self.L
self.α1 = 1-((1-np.exp((self.α-1)*(self.n+self.g+self.δ)))/(self.n+self.g+self.δ))
self.initdata = vars(self).copy()
def calc_next_period_kappa(self):
"Calculate the next period capital-output ratio."
# Unpack parameters (get rid of self to simplify notation)
n, s, δ, α1, g, κ= self.n, self.s, self.δ, self.α1, self.g, self.κ
# Apply the update rule
return (κ + (1 - α1)*( s - (n+g+δ)*κ ))
def calc_next_period_E(self):
"Calculate the next period efficiency of labor."
# Unpack parameters (get rid of self to simplify notation)
E, g = self.E, self.g
# Apply the update rule
return (E * np.exp(g))
def calc_next_period_L(self):
"Calculate the next period labor force."
# Unpack parameters (get rid of self to simplify notation)
n, L = self.n, self.L
# Apply the update rule
return (L*np.exp(n))
def update(self):
"Update the current state."
self.κ = self.calc_next_period_kappa()
self.E = self.calc_next_period_E()
self.L = self.calc_next_period_L()
self.Y = self.κ**(self.α/(1-self.α))*self.E*self.L
self.K = self.κ * self.Y
self.y = self.Y/self.L
def steady_state(self):
"Compute the steady state value of the capital-output ratio."
# Unpack parameters (get rid of self to simplify notation)
n, s, δ, g = self.n, self.s, self.δ, self.g
# Compute and return steady state
return (s /(n + g + δ))
def generate_sequence(self, t, var = 'κ', init = True):
"Generate and return time series of selected variable. Variable is κ by default. Start from t=0 by default."
path = []
# initialize data
if init == True:
for para in self.initdata:
setattr(self, para, self.initdata[para])
for i in range(t):
path.append(vars(self)[var])
self.update()
return path
T = 100
s_base = Solow_delong(κ=4.0)
s_base.scenario = "base scenario"
s_alt = Solow_delong(κ=0.5)
s_alt.scenario = "alt scenario"
figcontents = {
(0,0):('κ','Capital Output'),
(0,1):('E','Efficiency of Labor'),
(1,0):('L','Labor Force'),
(1,1):('K','Capital Stock'),
(2,0):('Y','Output'),
(2,1):('y','Output-per-worker')
}
num_rows, num_cols = 3,2
fig, axes = plt.subplots(num_rows, num_cols, figsize=(12, 12))
for i in range(num_rows):
for j in range(num_cols):
for s in s_base, s_alt:
lb = f'{s.scenario}: initial κ = {s.initdata["κ"]}'
axes[i,j].plot(s.generate_sequence(T, var = figcontents[i,j][0]),'o-', lw=2, alpha=0.5, label=lb)
axes[i,j].set(title=figcontents[i,j][1])
# global legend
axes[(0,0)].legend(loc='upper center', bbox_to_anchor=(1.1,1.3))
plt.suptitle('Solow Growth Model: Simulation Run', size = 20)
plt.show()
2019-07-25 by DeLong: Playing with Sargent and Stachurowski's QuantEcon: https://quantecon.org
2019-08-05 by Yinshan, list of changes made:
generate_x_sequence
into one methodgenerate_sequence
method to eliminate the need of redefining instance for every plotimport
commandsSolowKappa
Changed $\alpha$ to $\alpha'$ in calculation of $\kappa$
Effect: slight change in $\kappa$ value for each time period (converge slower to the steady state), but no change in general convergence behavior
2019-08-07 by delong: list of changes made:
s_base
and s_alt
cases2019-08-08 by delong: list of changes made:
SolowKappa
class to Solow_delong
2019-08-08 by Yinshan: list of changes made:
figcontents
dictionaryself.initdata = vars(self).copy()
and
if init == True:
for para in self.initdata:
setattr(self, para, self.initdata[para])
Illustration on selected syntaxes:
self.initdata = vars(self).copy()
vars(self)
returns a dictionary containing data attributes of the instance self
.
More technically speaking, for every module object in Python, the read-only attribute __dict__
returns the dictionary used to implement the module’s namespace.
In our case, vars(self)
gives us all initial data attributes we just defined. self.initdata = vars(self).copy()
copies the returned dictionary and stores it for future use in the initializing step of generate_sequence
method.
if init == True:
for para in self.initdata:
setattr(self, para, self.initdata[para])
The above steps initialize all parameters stored in self.initdata
. setattr
is used to assigns a value to the attribute, provided the object allows it. Usually setattr(object,name,value)
is equivalent to object.name = value
.
However, in our case, we need to get attributes dynamically named in a loop, depending on current para
. setattr
gives a handy solution. The usual =
way of assigning value would return an error.
# change starting points
s_base = Solow_delong(κ=1.0)
s_alt = Solow_delong(κ=10.0)
# reproduce plots
num_rows, num_cols = 3,2
fig, axes = plt.subplots(num_rows, num_cols, figsize=(12, 12))
for s in s_base, s_alt:
for i in range(num_rows):
for j in range(num_cols):
lb = f'initial κ = {s.initdata["κ"]}'
axes[i,j].plot(s.generate_sequence(T, var = figcontents[i,j][0]),'o-', lw=2, alpha=0.5, label=lb)
axes[i,j].set(title=figcontents[i,j][1])
# add steady state to capital output
axes[(0,0)].plot([s_base.steady_state()]*T, 'k-', label='steady state')
# global legend
axes[(0,0)].legend(loc='upper center', bbox_to_anchor=(1.1,1.3),ncol=3)
plt.suptitle('Solow Growth Model: Simulation Run', size = 20)
plt.show()
T = 100
s_base = Solow_delong(κ=1.0)
s_alt = Solow_delong(κ=10.0)
fig, ax = plt.subplots(figsize=(9, 6))
# Plot the common steady-state value of the capital-output ratio
ax.plot([s_base.steady_state()]*T, 'k-', label='steady state')
# Plot time series for each economy
for s in s_base, s_alt:
lb = f'capital-output series from initial state {s.initdata["κ"]}'
ax.plot(s.generate_sequence(T), 'o-', lw=2, alpha=0.5, label=lb)
ax.legend()
plt.show()
fig, ax = plt.subplots(figsize=(9, 6))
# Plot time series for each economy
for s in s_base, s_alt:
lb = f'efficiency-of-labor series from initial state {s.initdata["κ"]}'
ax.plot(s.generate_sequence(T, var='E'), 'o-', lw=2, alpha=0.5, label=lb)
ax.legend()
plt.show()
fig, ax = plt.subplots(figsize=(9, 6))
# Plot time series for each economy
for s in s_base, s_alt:
lb = f'labor-force series from initial state {s.initdata["κ"]}'
ax.plot(s.generate_sequence(T, var = 'L'), 'o-', lw=2, alpha=0.5, label=lb)
ax.legend()
plt.show()
fig, ax = plt.subplots(figsize=(9, 6))
# Plot time series for each economy
for s in s_base, s_alt:
lb = f'capital-stock series from initial state {s.initdata["κ"]}'
ax.plot(s.generate_sequence(T, var = 'K'), 'o-', lw=2, alpha=0.5, label=lb)
ax.legend()
plt.show()
fig, ax = plt.subplots(figsize=(9, 6))
# Plot time series for each economy
for s in s_base, s_alt:
lb = f'output series from initial state {s.initdata["κ"]}'
ax.plot(s.generate_sequence(T, var = 'Y'), 'o-', lw=2, alpha=0.5, label=lb)
ax.legend()
plt.show()
fig, ax = plt.subplots(figsize=(9, 6))
for s in s_base, s_alt:
lb = f'output-per-worker series from initial state {s.initdata["κ"]}'
ax.plot(s.generate_sequence(T, var = 'y'), 'o-', lw=2, alpha=0.5, label=lb)
ax.legend()
plt.show()