前回は公共財自発的供給メカニズム(VCM)を紹介しました。VCMではただ乗り行動が支配戦略になることを確認し、また、VCMは予算均衡条件のみ満たされており、それ以外(ボーエン=サミュエルソン条件、個人合理性、耐戦略性)は満たされていないことを確認しました。今回はリンダールメカニズムというメカニズムを紹介します。
【概要】
本記事で紹介するリンダールメカニズムでは、全プレイヤーの公共財供給量(表明)が一致するまで公共財の負担割合$q_i$を繰り返し調整します。最終的に全員が合意する供給水準 $G^{\ast}$ と負担割合の組 $(G^{\ast}, q^{\ast})$ を「リンダール均衡」と呼びます。つまり、$G_1=G_2=\cdots=G_n=G^{\ast}$ となる$G^{\ast}$を決定するために公共財の負担割合の組$q=(q_1,q_2,\cdots,q_n)$を調整します。
満たす性質
| 性質 | 結果 | 理由 |
|---|---|---|
| ボーエン=サミュエルソン条件 | ⚫ | リンダール均衡では $\sum v'_i(G^{\ast}) = c'(G^{\ast})$ が成立します |
| 予算均衡条件 | ⚫ | $\sum x_i = c(G^{\ast})$ が成立します |
| 個人合理性 | ⚫ | 均衡では各プレイヤーが自分の望む水準で同意するため参加制約を満たします |
| 耐戦略性 | × | 便益関数を偽ることで個人の利得を改善できます(数値例参照) |
ここで、負担割合 $q_i$ の具体的な更新手順が定められていません。そのため、実装には追加的な手続きが必要となり、$q_i$ の更新ルールはデザイナーの裁量に任されています。
【アルゴリズム】
- ステップ1:政府は各プレイヤー $i$ に対して個別の費用負担割合 $q_i$ を提示します。ただし $\sum_{i=1}^{n} q_i = 1$ を満たします。
- ステップ2:各プレイヤー $i$ は $q_i$ を所与として、自分の利得 $u_i = v_i(G_i) - q_i c(G_i)$ を最大化する供給水準 $G_i$ を政府に伝えます。
- ステップ3(反復):$G_1 = G_2 = \cdots = G_n$ が成立していない場合、低い $G_i$ を申告したプレイヤーの $q_i$ を下げ、高い $G_i$ を申告したプレイヤーの $q_i$ を上げ、ステップ1に戻ります。
- ステップ4:全員が同一の $G^{\ast}$ に合意した時点で供給を確定し、各プレイヤーから $x_i = q_i^{\ast} c(G^{\ast})$ を徴収して終了します。
性質の確認
\begin{align*}
【\text{予算均衡条件}】\quad \sum_{i=1}^{n} x_i &= c(G^*) \sum_{i=1}^{n} q_i^* = c(G^*)\cdot 1=c(G^*)\\[4mm]
【\text{ボーエン=サミュエルソン条件}】\quad
v'_i(G_i) &= q_i c'(G_i) \quad \therefore\quad \sum_{i=1}^{n} v'_i(G^*) = c'(G^*) \quad
\end{align*}
【プログラム】Python
以下の便益関数を前提として実装します。
$$
v_i(G) = G - \frac{1}{2} a_i G^2 \quad (a_i > 0), \quad c(G) = G
$$
解析解
リンダール均衡(最終的に合意された供給水準)を$G\rightarrow G^{\ast}、q_i\rightarrow q_i^{\ast}$とすると、$G^{\ast}$と$q^{\ast}$は以下のように導出されます。
$$
【\boldsymbol{供給水準}】G^* = \frac{n-1}{\sum_{i=1}^{n} a_i}, \qquad 【\boldsymbol{負担割合}】q_i^* = 1 - a_i G^*
$$
上式を用いて、最終的な利得$u_i$は下式のようになります。
$$
【\boldsymbol{利得}】u_i= G-\frac{1}{2}a_iG^2-x_i
$$
"""
リンダールメカニズム(Lindahl Mechanism)
"""
# ===== 定数 =====
SEPARATOR = "=" * 50
# ===== 入力設定 =====
def input_data() -> tuple:
"""パラメータを設定する"""
N = 3 # プレイヤー数
a = [1, 2, 3] # 便益パラメータ a_i(値が大きいほど限界便益が急減)
return N, a
# ===== 供給水準の決定 =====
def determine_supply(N: int, a: list) -> float:
"""リンダール均衡における公共財の供給水準 G* = (N-1) / Σa_i を計算する"""
return (N - 1) / sum(a)
# ===== 費用負担の計算 =====
def calculate_burden(N: int, a: list, G: float) -> tuple:
"""各プレイヤーの費用負担額 x_i = q_i * c(G) = q_i * G を計算する
リンダール均衡の費用負担割合: q_i* = 1 - a_i * G*
"""
q = [1 - a[i] * G for i in range(N)]
x = [q[i] * G for i in range(N)]
return x, q
# ===== 利得の計算 =====
def calculate_payoff(N: int, a: list, G: float, x: list) -> list:
"""各プレイヤーの利得 u_i = v_i(G) - x_i を計算する
v_i(G) = G - 0.5 * a_i * G^2
"""
return [G - 0.5 * a[i] * G**2 - x[i] for i in range(N)]
# ===== 条件の確認 =====
def check_conditions(N: int, G: float, burden: list, payoff: list,
endowment: list, c_G: float) -> None:
"""予算均衡条件と個人合理性を数値的に確認する"""
budget_ok = abs(sum(burden) - c_G) < 1e-9
ir_flags = [payoff[i] >= endowment[i] for i in range(N)]
ir_ok = all(ir_flags)
print("【条件の確認】")
print(f" 予算均衡条件 : {'⚫ 成立' if budget_ok else '× 不成立'}"
f" (Σx_i = {sum(burden):.4f}, c(G) = {c_G:.4f})")
print(f" 個人合理性 : {'⚫ 成立' if ir_ok else '× 不成立'}")
for i in range(N):
sign = "≥" if ir_flags[i] else "<"
mark = "⚫" if ir_flags[i] else "×"
print(f" プレイヤー {i+1}: u_{i+1} = {payoff[i]:.4f} "
f"{sign} 参加前 = {endowment[i]:.4f} {mark}")
# ===== メイン =====
def main() -> None:
print(SEPARATOR)
print(" リンダールメカニズム(Lindahl Mechanism)")
print(SEPARATOR + "\n")
# 1. 入力情報
N, a = input_data()
print("【入力情報】")
print(f" プレイヤー数 N : {N}")
print(f" 便益パラメータ a_i : {a}")
print(f" 便益関数 v_i(G) : G - 0.5 * a_i * G^2")
print(f" 供給費用 c(G) : G\n")
# 2. 公共財供給水準の決定(リンダール均衡)
G = determine_supply(N, a)
print("【公共財供給水準】")
print(f" G* = (N-1) / Σa_i = {N-1} / {sum(a)} = {G:.4f}\n")
# 3. 費用負担の計算
burden, q = calculate_burden(N, a, G)
print("【費用負担】 x_i = q_i* × G* (q_i* = 1 - a_i × G*)")
for i in range(N):
print(f" プレイヤー {i+1}: q_{i+1}* = {q[i]:.4f}, x_{i+1} = {burden[i]:.4f}")
print(f" 費用負担割合の合計 Σq_i = {sum(q):.4f} (≒ 1 を確認)\n")
# 4. 利得の計算
payoff = calculate_payoff(N, a, G, burden)
print("【利得】 u_i = v_i(G*) - x_i")
for i in range(N):
vi = G - 0.5 * a[i] * G**2
print(f" プレイヤー {i+1}: v_{i+1}(G*) = {vi:.4f}, u_{i+1} = {payoff[i]:.4f}")
print()
# 5. 条件の確認(参加前の利得 = G=0 時の便益 = 0)
check_conditions(N, G, burden, payoff, endowment=[0.0]*N, c_G=G)
if __name__ == "__main__":
main()
コード解説
-
determine_supply(N, a):ボーエン=サミュエルソン条件 $\sum v'_i(G) = c'(G)$ を解いた解析解 $G^* = \frac{N-1}{\sum a_i}$ を計算します。 -
calculate_burden(N, a, G):リンダール均衡の負担割合 $q_i^* = 1 - a_i G^$ と費用負担額 $x_i = q_i^ G^*$ を計算し、タプル(x, q)として返します。 -
calculate_payoff(N, a, G, x):各プレイヤーの利得 $u_i = v_i(G^*) - x_i$ を計算します。 -
check_conditions(...):4メカニズム共通の条件確認関数です。リンダールは「参加前」($G=0$ 時の便益 = 0)と比較します。
実行結果(N=3、$a = [1, 2, 3]$)
==================================================
リンダールメカニズム(Lindahl Mechanism)
==================================================
【入力情報】
プレイヤー数 N : 3
便益パラメータ a_i : [1, 2, 3]
便益関数 v_i(G) : G - 0.5 * a_i * G^2
供給費用 c(G) : G
【公共財供給水準】
G* = (N-1) / Σa_i = 2 / 6 = 0.3333
【費用負担】 x_i = q_i* × G* (q_i* = 1 - a_i × G*)
プレイヤー 1: q_1* = 0.6667, x_1 = 0.2222
プレイヤー 2: q_2* = 0.3333, x_2 = 0.1111
プレイヤー 3: q_3* = 0.0000, x_3 = 0.0000
費用負担割合の合計 Σq_i = 1.0000 (≒ 1 を確認)
【利得】 u_i = v_i(G*) - x_i
プレイヤー 1: v_1(G*) = 0.2778, u_1 = 0.0556
プレイヤー 2: v_2(G*) = 0.2222, u_2 = 0.1111
プレイヤー 3: v_3(G*) = 0.1667, u_3 = 0.1667
【条件の確認】
予算均衡条件 : ⚫ 成立 (Σx_i = 0.3333, c(G) = 0.3333)
個人合理性 : ⚫ 成立
プレイヤー 1: u_1 = 0.0556 ≥ 参加前 = 0.0000 ⚫
プレイヤー 2: u_2 = 0.1111 ≥ 参加前 = 0.0000 ⚫
プレイヤー 3: u_3 = 0.1667 ≥ 参加前 = 0.0000 ⚫
実行結果の読み方
$G^{\ast} = \frac{2}{6} = \frac{1}{3}$ がリンダール均衡の供給量であり、$a_i$ が大きいほど$v_i$や$q_i$が低下します。例えば、プレイヤー3は $q_3^{\ast} = 0$、つまり費用負担なしでリンダール均衡に合意します。全員の利得 $u_i > 0$ であるため個人合理性が成立し、$\sum x_i = G^{\ast}$ により予算均衡条件も成立しています。
耐戦略性が満たされない理由(数値例)
$n=2$、$a_1=a_2=1$、$\theta=1.5$(プレイヤー1が $a_1$ を $\theta$ に偽った場合)として確認します。
\begin{align*}
【\text{真実申告}】&\quad v_1(G^*) - q_1^* c(G^*) = \frac{0.5 \cdot 1}{(1+1)^2} = \frac{1}{8} = 0.125 \\[2mm]
【\text{虚偽申告}】&\quad v_1(G^{**}) - q_1^{**} c(G^{**}) = \frac{1.5 - 0.5}{(1.5+1)^2} = \frac{4}{25} = 0.16
\end{align*}
$0.16 > 0.125$ より、プレイヤー1は虚偽申告することで利得を増やせます。リンダールメカニズムは耐戦略的ではありません。