Python 数值仿真:古诺寡头博弈反应函数与动态收敛

从两厂商反应曲线到纳什均衡的蛛网迭代

在浏览器内直接运行 Python 代码,模拟双寡头古诺博弈最优反应函数的蛛网动态迭代与收敛。
作者

Shawn

Gemini 3.7 Flash

发布于

2026年8月27日

本文依据 Muñoz-Garcia《Advanced Microeconomic Theory》第 8 章及配套课程讲义撰写,属于微观经济学专栏的市场结构模块。它是价格竞争代表作伯特兰悖论在数量竞争维度上的经典对照。

注记本讲核心目标
  1. 理解古诺寡头模型(Cournot Duopoly)中厂商的产量决策逻辑最优反应函数(Best Response)推导;
  2. 掌握蛛网动态调整过程(Cobweb Dynamics):当市场偏离均衡时,厂商如何通过交替调整最优产量逐步收敛到纳什均衡;
  3. 掌握动态稳定性的充要判据:反应曲线斜率乘积绝对值 \(|R_1' \cdot R_2'| < 1\)
  4. 在浏览器中通过 Pyodide 运行 Python 代码,实时修改成本与需求参数观察收敛轨迹。

理论设定与反应函数

设市场逆需求函数为线性形式:

\[P(Q) = a - b Q = a - b(q_1 + q_2)\]

厂商 1 与厂商 2 生产同质产品,具有相同的常数边际成本 \(c > 0\)(且 \(a > c\))。

厂商 1 求解利润最大化:

\[\max_{q_1 \ge 0} \pi_1(q_1, q_2) = \big(a - b(q_1 + q_2) - c\big) q_1\]

一阶条件(FOC):

\[\frac{\partial \pi_1}{\partial q_1} = a - c - 2b q_1 - b q_2 = 0 \quad\Longrightarrow\quad q_1^*(q_2) = R_1(q_2) = \frac{a - c - b q_2}{2b}\]

同理对称地解出厂商 2 的最优反应函数:

\[q_2^*(q_1) = R_2(q_1) = \frac{a - c - b q_1}{2b}\]

联立两式求解,得到唯一的古诺–纳什均衡(Cournot-Nash Equilibrium)

\[q_1^N = q_2^N = \frac{a - c}{3b}, \qquad P^N = c + \frac{a - c}{3}\]


动手实验室:浏览器内运行 Python

下面的代码单元运行在你的浏览器内部(基于 WebAssembly 版 Python / Pyodide,无需在本地配置任何环境)。

你可以直接修改参数并点击运行按钮:

  1. 修改需求截距 a、斜率 b、边际成本 c 或初始猜测产量 (q1_start, q2_start)
  2. 观察绿色折线如何像“蛛网”一样在红蓝两条反应曲线之间折返,最终精准坠入紫色纳什均衡点;
  3. 思考:若把反应函数斜率人为改大(例如 \(|R_1' \cdot R_2'| > 1\)),轨迹会发生什么?
#| classes: "experiment-cell"
#| fig-cap: "古诺博弈反应曲线与蛛网迭代(浏览器内直接运行;图内标签采用英文以确保 WebAssembly 环境无字体警告)"
import numpy as np
import matplotlib.pyplot as plt

# ====== 可自由修改的参数 ======
a, b, c = 120.0, 1.0, 30.0      # 逆需求截距 a / 价格斜率 b / 边际成本 c
q1_start, q2_start = 5.0, 40.0 # 初始非均衡产量起点
steps = 8                       # 迭代步数
# ==============================

def br1(q2): return (a - c - b * q2) / (2 * b)
def br2(q1): return (a - c - b * q1) / (2 * b)

q_nash = (a - c) / (3 * b)

# 模拟蛛网迭代路径
path_q1, path_q2 = [q1_start], [q2_start]
for _ in range(steps):
    new_q1 = br1(path_q2[-1])
    path_q1.extend([new_q1, new_q1])
    path_q2.extend([path_q2[-1], br2(new_q1)])

q_max = max(60.0, q_nash * 2.2)
q_range = np.linspace(0, q_max, 300)

fig, ax = plt.subplots(figsize=(7, 5.4), dpi=140)
# 厂商 2 反应曲线: q2 = br2(q1)
ax.plot(q_range, [br2(x) for x in q_range], label=r"Firm 2 Best Response $R_2(q_1)$", color="#3b82f6", lw=2.2)
# 厂商 1 反应曲线在 (q1, q2) 平面上: q1 = br1(q2) => q2 = (a-c-2b*q1)/b
ax.plot(q_range, (a - c - 2 * b * q_range) / b, label=r"Firm 1 Best Response $R_1(q_2)$", color="#ef4444", lw=2.2)

# 绘制迭代轨迹与均衡点
ax.plot(path_q1, path_q2, color="#10b981", linestyle="--", marker="o", markersize=4.5, label="Adjustment Path")
ax.scatter([q_nash], [q_nash], color="#8b5cf6", s=140, zorder=6, label=rf"Nash Equilibrium $N^*$ ({q_nash:.1f}, {q_nash:.1f})")

ax.set_xlim(0, q_max)
ax.set_ylim(0, q_max)
ax.set_xlabel(r"Firm 1 Output $q_1$", fontsize=11)
ax.set_ylabel(r"Firm 2 Output $q_2$", fontsize=11)
ax.set_title(r"Cournot Dynamics: Cobweb Convergence to Nash Equilibrium", fontsize=12, fontweight="bold")
ax.legend(loc="upper right", frameon=True)
ax.grid(True, linestyle=":", alpha=0.6)
plt.tight_layout()
plt.show()
提示稳定性判据:为什么总是收敛?

蛛网迭代收敛的数学充要条件是:两厂商最优反应导数在均衡点处的乘积绝对值严格小于 1:

\[|R_1'(q_2^N) \cdot R_2'(q_1^N)| = \left| -\frac{1}{2} \times -\frac{1}{2} \right| = \frac{1}{4} < 1\]

在线性需求与常数边际成本下,斜率乘积永远是 \(1/4\),因此无论从空间中的哪一个非均衡起点出发,交替调整必然稳定收敛到古诺–纳什均衡!

如果某种非线性需求或极端成本结构导致反应曲线斜率乘积绝对值大于 1,迭代就会螺旋发散。

古诺与伯特兰的系统对比

维度 古诺模型(Cournot) 伯特兰模型(Bertrand)
决策变量 产量 \(q_1, q_2\) 价格 \(p_1, p_2\)
均衡价格 \(P = c + \frac{a-c}{3} > c\)(享有正溢价) \(p_1 = p_2 = c\)(完全竞争价格)
经济利润 双方享有正经济利润 经济利润为零(伯特兰悖论)
微观本质 产能决策、投资承诺(周期长) 货架定价、即时促销(周期短)

延伸阅读: - 伯特兰悖论:两家厂商就把价格打到边际成本 - 混合策略:当对手随机化时你该怎么办

None🤖 AI 助教「乐高」

对本讲内容有疑问?直接向 AI 助教「乐高」提问——它基于本站课程讲义回答,公式用 LaTeX 排版,回答附带讲义溯源。可以试试:

  • 为什么古诺反应曲线的斜率是 \(-1/2\)?在经济学上代表什么含义?
  • 如果厂商数量从 2 家扩展到 \(N\) 家,古诺均衡的总产量和价格如何逐渐逼近完全竞争?
  • 什么是斯塔克尔伯格(Stackelberg)先动优势?相比古诺同时博弈结果有何不同?