"""
ランダムな経済取引による富の分布シミュレーション。
概要:
多数の参加者間で行われるランダムな金銭交換が、どのように富の不均衡(指数分布)
を生み出すかをシミュレーションし、リアルタイムで可視化します。
詳細説明:
- 統計力学におけるエネルギー等分配や、経済物理学における所得分布のモデルです。
- 全員が同じ初期資金からスタートし、ランダムに選ばれた相手に一定額(vtrade)を支払います。
- 支払う資金がない場合は、持っている全額を支払います(負債はなし)。
- 多数の取引サイクルを経て、以下の3つの観点から解析を行います:
1. 個人の資産推移(カオスな状態)
2. ソートされた資産分布(格差の可視化)
3. 資産の頻度分布(理論的な指数分布 $f(x) = A e^{-x/\langle x \rangle}$ への収束)
関連リンク: :doc:`randomtrade_usage`
"""
import sys
import random
import numpy as np
from math import exp
import matplotlib.pyplot as plt
#=============================
# デフォルトパラメータ
#=============================
NP_DEF = 50 # 参加人数
VAL_DEF = 50 # 初期資金(平均額)
VTRADE_DEF = 1 # 1回の取引額
NITER_DEF = 500 # 最大反復サイクル数
NPLOT_DEF = 100 # グラフ更新間隔
NFX_DEF = 21 # 頻度分布のメッシュ数
[ドキュメント]
def main():
"""
シミュレーションのメインループ。
取引の実行、統計計算、グラフの更新を制御します。
"""
# 引数処理
argv = sys.argv
npersons = int(argv[1]) if len(argv) >= 2 else NP_DEF
avg_value = int(argv[2]) if len(argv) >= 3 else VAL_DEF
vtrade = int(argv[3]) if len(argv) >= 4 else VTRADE_DEF
niter = int(argv[4]) if len(argv) >= 5 else NITER_DEF
nplotinterval = int(argv[5]) if len(argv) >= 6 else NPLOT_DEF
nfx = int(argv[6]) if len(argv) >= 7 else NFX_DEF
# 初期化:全員同じ金額からスタート
x_index = np.arange(npersons)
v = np.full(npersons, float(avg_value))
# 理論的な指数分布(ボルツマン分布相当)の準備
# f(x) = (N/avg) * exp(-x/avg)
beta = 1.0 / avg_value
coeff_a = npersons * beta
ftx = np.linspace(0, avg_value * 10, 101)
fty = [coeff_a * exp(-beta * x) for x in ftx]
print(f"\nSimulation settings: n={npersons}, avg={avg_value}, trade={vtrade}")
print(f"Theoretical eq: f(x) = {coeff_a:.4g} * exp(-{beta:.4g} * x)")
# 描画準備
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(8, 10))
plt.subplots_adjust(hspace=0.4)
# 取引シミュレーション開始
for i in range(niter):
# 1サイクル:全員がランダムに1人と取引
for ip in range(npersons):
itarget = random.randrange(npersons)
if itarget == ip: continue # 自分自身とは取引しない
# 支払額の決定(所持金が足りない場合は全額)
payment = vtrade if v[ip] >= vtrade else v[ip]
v[ip] -= payment
v[itarget] += payment
# 表示更新タイミングの判定
if i == 0 or (i + 1) % nplotinterval == 0 or i == niter - 1:
v_sorted = np.sort(v)
v_max = np.max(v)
ax1.cla()
ax2.cla()
ax3.cla()
# グラフ1: 生の資産分布
ax1.bar(x_index, v, color='skyblue', alpha=0.7)
ax1.axhline(avg_value, color='red', linestyle='--', linewidth=0.8, label='Initial/Avg')
ax1.set_title(f'Individual Wealth (Step {i+1}/{niter})')
ax1.set_ylabel('Wealth')
ax1.set_xlim(-1, npersons)
# グラフ2: 格差の可視化(ソート済み)
ax2.bar(x_index, v_sorted, color='steelblue', alpha=0.7)
ax2.axhline(avg_value, color='red', linestyle='--', linewidth=0.8)
ax2.set_title('Wealth Distribution (Sorted)')
ax2.set_ylabel('Wealth (Sorted)')
ax2.set_xlim(-1, npersons)
# グラフ3: 頻度分布と理論曲線
# ヒストグラムの計算
counts, bins = np.histogram(v, bins=nfx, range=(0, max(v_max, 1)), density=False)
bin_width = bins[1] - bins[0]
bin_centers = (bins[:-1] + bins[1:]) / 2.0
y_dist = counts / bin_width # 密度に変換
ax3.step(bin_centers, y_dist, where='mid', label='Simulation', color='black')
ax3.plot(ftx, fty, label='Exponential Theory', color='red', linestyle='dashed', alpha=0.7)
ax3.set_title('Probability Density (Wealth Function)')
ax3.set_xlabel('Wealth')
ax3.set_ylabel('Frequency Density')
ax3.set_xlim(0, max(v_max, avg_value * 3))
ax3.legend(fontsize=9)
plt.pause(0.05)
print("\nSimulation completed.")
plt.show(block=False)
input("Press ENTER to exit>>")
if __name__ == '__main__':
main()