How do the savings decisions of one generation affect the capital stock and welfare of future generations? This is the central question of the overlapping generations (OLG) model introduced by Diamond (1965), building on the pure-exchange framework of Samuelson (1958).
In an infinite-horizon representative agent model, a single household lives forever and internalizes the effect of its savings on future capital. In the OLG model, by contrast, each household lives for only two periods. Young households save for retirement, and their collective savings become the capital stock available to the next generation. Because no single household lives long enough to account for the entire future path of capital, the competitive equilibrium need not be efficient.
In this lecture we develop the two-period Diamond OLG model from first principles. We derive the competitive equilibrium, characterize the social planner’s solution, define the Golden Rule, and show how these three benchmarks relate to one another. Along the way we introduce the concept of dynamic efficiency and explain why the first welfare theorem can fail in an OLG economy.
We use a per-generation calibration in which each model period represents roughly 30 years. The baseline parameters are (capital share), (household discount factor), (gross population growth, corresponding to approximately 3% annual growth compounded over 30 years), and (social planner discount factor).
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
import sympy as sp
import pandas as pdfrom collections import namedtuple
OLGModel = namedtuple('OLGModel', ['epsilon', 'beta', 'N', 'beth'])Model Setup¶
Demographics and Timing¶
Time is discrete, indexed by . Each individual lives for two periods: young (period ) and old (period ). The population of young agents in period is
where is the gross population growth factor and is the net growth rate. In each period the economy contains young agents and old agents.
Endowments and Technology¶
Young agents supply one unit of labor inelastically and earn a wage. Old agents do not work, so their only source of income is the return on savings accumulated when young. We write for the income of a young agent and set .
There are no bequests, so each generation starts with zero financial wealth. Total savings of the young generation at fund the capital stock at :
where denotes the assets (savings) of a representative young agent after consumption.
A representative firm operates a constant-returns-to-scale production function . By Euler’s theorem for homogeneous functions, output equals the sum of factor payments:
We assume no depreciation of capital within a generation.
Per-Capita Variables and Factor Prices¶
It is convenient to express all quantities in per-young-worker terms. Define the capital-labor ratio and the per-worker production function
Under competitive factor markets, each input is paid its marginal product. The wage equals the marginal product of labor and the gross interest rate equals the marginal product of capital:
We adopt a Cobb-Douglas specification with representing the capital share. Factor prices then take the form
def wage(k, epsilon):
"""Cobb-Douglas wage: marginal product of labor."""
return (1 - epsilon) * k**epsilon
def interest_rate(k, epsilon):
"""Cobb-Douglas gross interest rate: marginal product of capital."""
return epsilon * k**(epsilon - 1)Household Optimization¶
Preferences and Budget Constraints¶
A household born at date has preferences over consumption when young, , and consumption when old, . We represent these preferences with the lifetime utility function
where is a strictly increasing, strictly concave flow utility function and is the discount factor.
The household faces two budget constraints. When young, labor income is split between consumption and savings:
When old, consumption is financed entirely by the gross return on savings:
Since is strictly increasing, both constraints bind at the optimum.
The Euler Equation¶
Substituting the binding budget constraints into the lifetime utility function and taking the first-order condition with respect to yields the Euler equation:
The left side is the marginal utility cost of saving one additional unit when young. The right side is the discounted marginal utility benefit of consuming the gross return when old. At the optimum the household is indifferent between consuming a little more today and saving a little more for tomorrow.
Log Utility¶
We specialize to the case . The Euler equation becomes . Substituting the budget constraints and solving for consumption when young:
Savings are whatever is left from the wage:
A useful feature of log utility is that savings depend only on the wage and the discount factor, not on the interest rate. This occurs because the income and substitution effects of a change in exactly offset each other.
def savings_log(W, beta):
"""Optimal savings under log utility."""
return beta / (1 + beta) * WCompetitive Equilibrium¶
Law of Motion for Capital¶
In equilibrium, next period’s capital stock equals total savings of the current young generation. Dividing the capital accumulation equation by gives the per-young-worker capital stock:
Each unit of individual savings is spread across new workers. Substituting the savings function and the wage equation into this expression:
The coefficient summarizes how technology (), patience (), and population growth () interact to determine capital accumulation. Higher population growth lowers because each generation’s savings must be spread more thinly.
The derivative of the law of motion is
Because , the map is concave, which guarantees a unique positive steady state and global convergence from any positive initial condition.
def Q_coefficient(epsilon, beta, N):
"""Coefficient in the law of motion for capital."""
return (1 - epsilon) * beta / (N * (1 + beta))
def k_next(k, epsilon, beta, N):
"""One-period law of motion for capital per young worker."""
return Q_coefficient(epsilon, beta, N) * k**epsilonSteady State¶
Setting in the law of motion and solving:
Once we know we can recover the steady-state wage , the gross interest rate , and consumption in each period of life.
def steady_state_competitive(epsilon, beta, N):
"""Steady-state capital in the competitive equilibrium."""
Q = Q_coefficient(epsilon, beta, N)
return Q**(1 / (1 - epsilon))We can verify the steady-state formula symbolically. Setting in the law of motion gives . Solving for :
k_sym, Q_sym, eps_sym = sp.symbols('k Q varepsilon', positive=True)
# Steady-state condition: k = Q * k^epsilon
ss_eq = sp.Eq(k_sym, Q_sym * k_sym**eps_sym)
k_star_symbolic = sp.solve(ss_eq, k_sym)
display(sp.Eq(sp.Symbol(r'\bar{k}'), k_star_symbolic[0]))Phase Diagram and Convergence¶
The 45-degree diagram below plots against the identity line. The unique intersection at is the steady state. Because the law of motion is concave and passes through the origin, any positive initial capital stock converges monotonically to .
model = OLGModel(epsilon=0.33, beta=0.96, N=2.5, beth=0.99)
epsilon, beta, N = model.epsilon, model.beta, model.N
k_bar = steady_state_competitive(epsilon, beta, N)
k_grid = np.linspace(0, 0.15, 300)
k_grid_next = k_next(k_grid, epsilon, beta, N)
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(k_grid, k_grid_next, lw=2, label=r'$k_{t+1} = \mathcal{Q}\,k_t^\varepsilon$')
ax.plot(k_grid, k_grid, 'k-', lw=1, alpha=0.7, label=r'$45^\circ$ line')
ax.plot(k_bar, k_bar, 'ro', ms=8, zorder=5,
label=rf'$\bar{{k}} = {k_bar:.4f}$')
ax.set_xlabel('$k_t$')
ax.set_ylabel('$k_{t+1}$')
ax.legend(frameon=False)
ax.set_xlim(0, 0.15)
ax.set_ylim(0, 0.15)
ax.grid(True, alpha=0.3)
plt.show()Time Series¶
The following figure simulates capital from three different initial conditions, confirming convergence to (dashed line).
T = 30
k0_values = [0.005, 0.05, 0.12]
fig, ax = plt.subplots()
for k0 in k0_values:
k_series = np.empty(T)
k_series[0] = k0
for t in range(T - 1):
k_series[t + 1] = k_next(k_series[t], epsilon, beta, N)
ax.plot(k_series, '-o', ms=3, lw=1.5, label=rf'$k_0 = {k0}$')
ax.axhline(k_bar, ls='--', color='k', alpha=0.5, label=rf'$\bar{{k}} = {k_bar:.4f}$')
ax.set_xlabel('$t$')
ax.set_ylabel('$k_t$')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()Comparative Statics¶
Higher population growth lowers the steady-state capital stock because savings are diluted across more workers. The figure below plots against for the baseline calibration.
N_vals = np.linspace(1.0, 4.0, 300)
k_ss_vals = np.array([steady_state_competitive(epsilon, beta, Nv) for Nv in N_vals])
fig, ax = plt.subplots()
ax.plot(N_vals, k_ss_vals, 'r-', lw=2, label=r'$\bar{k}$ vs $N$')
ax.axvline(N, ls=':', color='gray', alpha=0.5)
ax.set_xlabel(r'Population growth factor $N$')
ax.set_ylabel(r'Steady-state capital $\bar{k}$')
ax.grid(True, alpha=0.3)
plt.show()The Social Planner’s Problem¶
So far we have characterized the competitive equilibrium, describing what happens when households and firms optimize independently. We now turn to a normative question: what should happen? In particular, is the competitive equilibrium efficient?
In many standard macroeconomic models, the first welfare theorem guarantees that competitive equilibria are Pareto efficient. The OLG model is a notable exception. Because new agents are born every period, the economy has a countable infinity of agents, and the standard proof of the first welfare theorem breaks down. To evaluate efficiency we need to solve the social planner’s problem and compare its solution with the competitive outcome.
Social Welfare and the Resource Constraint¶
Let denote the lifetime utility of the generation born at . The social planner maximizes
where (the Hebrew letter beth) is the rate at which the planner discounts the welfare of future generations.[1]
The planner faces an aggregate resource constraint. Total output plus the existing capital stock must cover next period’s capital, consumption of the young, and consumption of the old:
Socially Optimal Steady State¶
Solving the planner’s problem in steady state yields the following condition on the optimal capital stock (see Blanchard & Fischer (1989), Chapter 3):
This equation says that the gross return on capital, , should equal the ratio of population growth to the social discount factor. A more patient planner (higher ) chooses a higher capital stock.
With Cobb-Douglas production, we can solve the optimality condition explicitly:
The competitive steady state depends on the household discount factor , while the social optimum depends on the social discount factor . There is no reason for these two capital stocks to coincide: the competitive equilibrium may feature too much or too little capital relative to what a social planner would choose.
def steady_state_social(epsilon, N, beth):
"""Steady-state capital chosen by the social planner."""
return ((N / beth - 1) / epsilon)**(1 / (epsilon - 1))
beth = 0.99
k_bar = steady_state_competitive(epsilon, beta, N)
k_star = steady_state_social(epsilon, N, beth)
print(f"Competitive equilibrium: k_bar = {k_bar:.4f}")
print(f"Social optimum: k_bar* = {k_star:.4f}")The Golden Rule and Dynamic Efficiency¶
Maximizing Steady-State Consumption¶
Setting aside the planner’s intertemporal tradeoff, we can ask an even simpler question: what capital stock maximizes total per-capita consumption in steady state? Dividing the resource constraint by and imposing steady-state conditions gives aggregate per-capita consumption
where is the net population growth rate. The Golden Rule capital stock maximizes this expression:
The first-order condition equates the marginal product of capital to the net population growth rate. At the Golden Rule, one additional unit of capital raises output by exactly enough to equip the additional workers in the next generation.
With Cobb-Douglas production:
def steady_state_golden(epsilon, n):
"""Golden Rule capital stock maximizing steady-state consumption."""
return (n / epsilon)**(1 / (epsilon - 1))Steady-State Consumption and Dynamic Inefficiency¶
The figure below plots steady-state per-capita consumption as a function of . Three capital stocks are marked: the competitive equilibrium , the Golden Rule , and the social optimum . The shaded region to the right of the Golden Rule is the dynamically inefficient zone where additional capital actually reduces aggregate consumption.
At the far right, consumption falls to zero at the capital stock where all output is absorbed by equipping new workers:
n = N - 1
k_gold = steady_state_golden(epsilon, n)
k_zero = n**(1 / (epsilon - 1))
k_grid = np.linspace(0.001, min(k_zero * 1.1, 0.7), 400)
c_ss = k_grid**epsilon - n * k_grid
c_gold = k_gold**epsilon - n * k_gold
c_ce = k_bar**epsilon - n * k_bar
c_star = k_star**epsilon - n * k_star
fig, ax = plt.subplots()
ax.plot(k_grid, c_ss, 'b-', lw=2,
label=r'$\bar{c} = f(\bar{k}) - n\,\bar{k}$')
ax.axhline(0, color='k', lw=0.5)
ax.plot(k_bar, c_ce, 'go', ms=10, zorder=5,
label=rf'Competitive $\bar{{k}} = {k_bar:.3f}$')
ax.plot(k_star, c_star, 's', color='darkorange', ms=10, zorder=5,
label=rf'Social optimum $\bar{{k}}^* = {k_star:.3f}$')
ax.plot(k_gold, c_gold, 'r*', ms=15, zorder=5,
label=rf'Golden Rule $\bar{{k}}^{{**}} = {k_gold:.3f}$')
ax.fill_betweenx([0, c_gold * 1.15], k_gold, min(k_zero, k_grid[-1]),
color='red', alpha=0.08, label='Dynamically inefficient')
ax.axvline(k_gold, color='r', ls=':', alpha=0.4)
ax.set_xlabel(r'Steady-state capital $\bar{k}$')
ax.set_ylabel(r'Steady-state consumption $\bar{c}$')
ax.set_xlim(0, k_grid[-1])
ax.legend(fontsize=9, loc='upper right')
ax.grid(True, alpha=0.3)
plt.show()The following table summarizes the three steady states and their associated prices and consumption levels.
rows = []
for label, kv in [('Competitive $\\bar{k}$', k_bar),
('Social optimum $\\bar{k}^*$', k_star),
('Golden Rule $\\bar{k}^{**}$', k_gold)]:
W_v = wage(kv, epsilon)
R_v = interest_rate(kv, epsilon)
c1_v = W_v / (1 + beta)
c2_v = R_v * beta / (1 + beta) * W_v
c_v = kv**epsilon - n * kv
rows.append({'Steady state': label, 'k': kv, 'W': W_v, 'R': R_v,
'c1': c1_v, 'c2': c2_v, 'c_bar': c_v})
df = pd.DataFrame(rows).set_index('Steady state').round(4)
print(f"Zero-consumption capital: k_0 = {k_zero:.4f}")
dfPareto Efficiency Across Generations¶
The Golden Rule divides the set of possible steady states into two regions with very different welfare properties.
When , the economy is dynamically efficient. Capital is scarce enough that its marginal product exceeds the population growth rate, . Reducing capital would lower output by more than it saves in equipping new workers, so there is no free lunch. Raising one generation’s consumption necessarily comes at the expense of another.
When , the economy is dynamically inefficient. Capital is so abundant that its marginal product falls below the population growth rate, . In this case, a social planner can reduce saving, raise the consumption of the current old generation, and simultaneously raise the consumption of every future generation. The mechanism is straightforward: by accumulating less capital, society wastes fewer resources on a factor whose return is below the growth rate of the economy.
This observation has a striking implication.
The failure arises because the OLG economy has a countable infinity of agents (one generation per period, stretching into the infinite future). With finitely many agents, the first welfare theorem guarantees efficiency under standard assumptions. With infinitely many agents, the argument breaks down: the “budget constraint of the economy” involves an infinite sum, and Walras’ law need not enforce efficiency.
Under standard calibrations, however, the competitive equilibrium tends to be dynamically efficient. As we will see in the exercises below, pushing above requires an implausibly large discount factor .
CRRA Preferences¶
The log-utility analysis above admits a closed-form savings function because income and substitution effects cancel exactly. With general CRRA preferences , , this cancellation no longer holds and the savings function depends on the interest rate.
The household’s Euler equation gives optimal savings
When , a higher interest rate raises savings (the substitution effect dominates); when , savings fall. At the expression reduces to the log-utility savings function (12).
Because depends on
itself, the law of motion is now an
implicit equation. We solve it numerically using
scipy.optimize.brentq. See Blanchard & Fischer (1989),
Chapter 3, for further discussion of the CRRA extension.
def savings_crra(W, R, beta, gamma):
"""Optimal savings under CRRA utility with risk aversion gamma."""
return W / (1 + beta ** (-1 / gamma) * R ** ((gamma - 1) / gamma))
def k_next_crra(k, epsilon, beta, N, gamma):
"""Solve the implicit law of motion for k_{t+1} under CRRA preferences."""
def residual(k1):
R1 = interest_rate(k1, epsilon)
W = wage(k, epsilon)
return savings_crra(W, R1, beta, gamma) / N - k1
try:
return optimize.brentq(residual, 1e-12, k**epsilon * 2 + 0.5)
except ValueError:
return np.nangamma_values = [0.5, 1.0, 2.0, 5.0]
k_grid_crra = np.linspace(1e-4, 0.15, 300)
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(k_grid_crra, k_grid_crra, 'k-', lw=1, alpha=0.7, label=r'$45^\circ$ line')
for gamma in gamma_values:
k1_vals = np.array([k_next_crra(kv, epsilon, beta, N, gamma)
for kv in k_grid_crra])
lbl = rf'$\gamma = {gamma}$'
if gamma == 1.0:
lbl += ' (log)'
ax.plot(k_grid_crra, k1_vals, lw=2, label=lbl)
ax.set_xlabel('$k_t$')
ax.set_ylabel('$k_{t+1}$')
ax.set_xlim(0, 0.15)
ax.set_ylim(0, 0.15)
ax.legend(frameon=False, fontsize=9)
ax.grid(True, alpha=0.3)
ax.set_title('Law of motion under CRRA preferences')
plt.show()Exercises¶
Solution to Exercise 1
epsilon, beta, N, beth = 0.33, 0.96, 2.5, 0.99
n = N - 1
k_ce = steady_state_competitive(epsilon, beta, N)
k_so = steady_state_social(epsilon, N, beth)
k_gr = steady_state_golden(epsilon, n)
print(f"Competitive equilibrium: k_bar = {k_ce:.4f}")
print(f"Social optimum: k_bar* = {k_so:.4f}")
print(f"Golden Rule: k_bar** = {k_gr:.4f}")
print()
if k_ce < k_gr:
print("The competitive equilibrium is dynamically efficient (k_bar < k_bar**).")
else:
print("The competitive equilibrium is dynamically INEFFICIENT (k_bar >= k_bar**).")labels = [r'$\bar{k}$' + '\n(competitive)',
r'$\bar{k}^*$' + '\n(social)',
r'$\bar{k}^{**}$' + '\n(golden rule)']
values = [k_ce, k_so, k_gr]
colors = ['#2196F3', '#FF9800', '#F44336']
fig, ax = plt.subplots()
bars = ax.bar(labels, values, color=colors, width=0.5)
for bar, v in zip(bars, values):
ax.text(bar.get_x() + bar.get_width() / 2, v + 0.002,
f'{v:.4f}', ha='center', fontsize=10)
ax.set_ylabel('Capital per young worker')
ax.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.show()Solution to Exercise 2
beth_vals = np.linspace(0.90, 0.999, 200)
k_so_vals = np.array([steady_state_social(epsilon, N, b) for b in beth_vals])
fig, ax = plt.subplots()
ax.plot(beth_vals, k_so_vals, 'b-', lw=2, label=r"$\bar{k}^*(\beth)$")
ax.axhline(k_ce, color='green', ls='--',
label=rf'$\bar{{k}}$ (competitive) $= {k_ce:.4f}$')
ax.axhline(k_gr, color='red', ls='--',
label=rf'$\bar{{k}}^{{**}}$ (golden rule) $= {k_gr:.4f}$')
ax.set_xlabel(r'Social discount factor $\beth$')
ax.set_ylabel('Steady-state capital')
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3)
plt.show()As increases toward 1, the planner cares almost as much about distant future generations as about the current one. The socially optimal capital stock rises, approaching the Golden Rule. In the limit , the planner’s optimality condition ((19)) gives , or equivalently , which is exactly the Golden Rule condition ((22)).
As falls toward , the right-hand side of the optimality condition grows without bound, so the optimal falls toward zero: a very impatient planner barely invests.
Solution to Exercise 3
def gap(beta_val):
return steady_state_competitive(epsilon, beta_val, N) - steady_state_golden(epsilon, n)
beta_crit = optimize.brentq(gap, 0.5, 50.0)
print(f"Critical beta: beta_crit = {beta_crit:.4f}")
print(f"For beta > {beta_crit:.2f}, the economy is dynamically inefficient.")
print()
print("Verification:")
print(f" k_bar(beta_crit) = {steady_state_competitive(epsilon, beta_crit, N):.6f}")
print(f" k_bar** = {steady_state_golden(epsilon, n):.6f}")The critical discount factor is approximately 4.58, far above 1. A per-generation discount factor of (the baseline calibration) implies that households discount the future at a modest rate. Even converting from annual to generational rates, , the result is well below .
Achieving dynamic inefficiency in this model would require households to be extraordinarily patient, valuing old-age consumption nearly five times as much as young-age consumption. Under any conventional calibration the competitive equilibrium is dynamically efficient.
The term gives weight to the old generation already alive at date . Multiplying by rather than some other constant prevents the social planner’s problem from exhibiting time inconsistency. See Blanchard & Fischer (1989), Chapter 3, for the derivation.
- Diamond, P. A. (1965). National Debt in a Neoclassical Growth Model. American Economic Review, 55(5), 1126–1150.
- Samuelson, P. A. (1958). An Exact Consumption-Loan Model of Interest with or without the Social Contrivance of Money. Journal of Political Economy, 66(6), 467–482. 10.1086/258100
- Blanchard, O. J., & Fischer, S. (1989). Lectures on Macroeconomics. MIT Press.