#!/usr/bin/env python # coding: utf-8 # ## Solow Growth Model # # 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) $ # In[2]: import numpy as np import matplotlib.pyplot as plt get_ipython().run_line_magic('matplotlib', 'inline') # In[68]: 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 class **Solow** """ 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 # In[62]: 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() # ## Solow Growth Model: Capital-Output Ratio as State Variable # # # # ### Catch Our Breath—Further Notes: # #
# # ---- # # * Weblog Support # * nbViewer # #   # # ---- #   # # ---- # # ### Change Log # # **2019-07-25** by DeLong: Playing with Sargent and Stachurowski's QuantEcon: # #   # # ---- # # __2019-08-05__ by Yinshan, list of changes made: # # 1. Merged `generate_x_sequence` into one method # 2. Added initializing steps to `generate_sequence` method to eliminate the need of redefining instance for every plot # 2. Removed unnecessary `import` commands # 2. Changed comment to docstring for the class `SolowKappa` # 2. 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 # 3. Modified unpacking commands for self variables, removed unused ones and added used ones # # ---- # # **2019-08-07** by delong: list of changes made: # # 1. Named `s_base` and `s_alt` cases # 2. Added the six-panel summary graph # # ---- # # **2019-08-08** by delong: list of changes made: # # 1. Renamed `SolowKappa` class to `Solow_delong` # 2. Added info about Stachurski-Sargeant QuantEcon to the docstring. # # ---- # # # **2019-08-08** by Yinshan: list of changes made: # # 1. Modified six-panel summary code, added loop and `figcontents` dictionary # 2. Changed six-panel summary graph legend to global, added subtitles to subplots # 3. Added illustration on # ``` # self.initdata = vars(self).copy() # ``` # and # ``` # if init == True: # for para in self.initdata: # setattr(self, para, self.initdata[para]) # ``` # # ---- # #   #   # # ## Appendices # **Illustration on selected syntaxes:** # 1. `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. # # 2. # ``` # 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. # # In[63]: # 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() # In[5]: 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() # In[6]: 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() # In[7]: 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() # In[8]: 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() # In[9]: 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() # In[10]: 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()