はじめに
前回に続きMeaa3.xでプログラム。
お題は、「貨幣の複雑性」(安富歩)の物々交換モデル(本書P59-61)です。
jupyter notebook上で動きます。
虫取りは不完全ですが、とりあえず動く状態なので、忘れないうちにアップします。
補助関数等
ロジックで共通なものを抜き出しました。
from mesa import Agent, Model
import numpy as np
import random
def random_n_except_i(n,i):
r = random.randint(1,n-1)
if r >= i:
r += 1
return r
# 配列hの数の少ない順に、配列位置を配列rに返す。
# 但し、個数の数だけ重複登録し、同数グループの順番はシャッフルする。
# 最後に配列の頭からm個を切り出す。
def select_k(h,m):
r = []
for i in range(1,max(h)+1): # i = 1..配列hの最大個数
t = [] # t 同じ個数のグループ
for j in range(len(h)):
if h[j] == i:
for k in range(1,i+1): # 個数分だけ複製
t.append(j)
random.shuffle(t)
print(f"{i} = {t}")
r.extend(t)
return r[:m]
def exchange(AH,AD,BH,BD,DB):
ks = select_k(BH,DB)
print(ks)
for k in ks:
if BH[k] > 0:
AH[k] += 1
AD[k] -= 1
BH[k] -= 1
for j in range(len(BD)):
BH[j] += BD[j]
BD[j] = 0
return ks
MoneyAgentを作成
class MoneyAgent(Agent):
def __init__(self, model):
super().__init__(model)
self.w = 0 # 要求する財
self.p = 0 # 生産する財
self.h = [] # 所有商品
self.d = [] # 需要
self.u = 0.0 # 得点
self.s = 0
def step(self):
# 1. 交換相手Bを選択する
max_w = 0
for b in self.model.agents:
if b.unique_id != self.unique_id:
hw = b.h[self.w - 1] # bが持っている商品wの数量
if hw > 0:
if hw > max_w: # 所有数の最も大きい相手を選ぶ
B = b
max_w = hw
if max_w > 0: # 2. 互いの需要量を決定する
A=self
AW = A.w - 1 # Aの需要する商品index
BW = B.w - 1 # Bの需要する商品index
A.d[AW] = B.h[AW] # Aの需要数量
B.d[BW] = A.h[BW] # Bの需要数量
DA = np.sum(A.d) # Aの需要数量
DB = np.sum(B.d) # Bの需要数量
# 交換するかどうかの判定して交換する
if DA == DB and DB > 0:
for i in range(len(A.h)):
CA = A.d[AW] - A.d[AW]
CB = B.d[BW] - B.d[BW]
A.h[AW] += CA
B.h[AW] -= CA
B.h[AW] += CB
A.h[AW] -= CB
elif DA > DB and DB > 0:
exchange(AH,AD,BH,BD,DB)
elif DB > DA and DA > 0:
exchange(BH,BD,AH,AD,DA)
if DA > 0 and DB > 0:
self.s += 1
print(f"AW={AW+1} BW={BW+1} DA={DA} DB={DB}")
print(f"A:Agent{A.unique_id} has h={A.h} d={A.d} w={A.w} and p={A.p} u={A.u} sumD={np.sum(A.d)}")
print(f"B:Agent{B.unique_id} has h={B.h} d={B.d} w={B.w} and p={B.p} u={B.u} sumD={np.sum(B.d)}")
# 交換後、需要量を初期化
A.d = np.zeros(len(A.h),dtype=int)
B.d = np.zeros(len(B.h),dtype=int)
MoneyModelの作成
class MoneyModel(Model):
def __init__(self, n, seed=None):
super().__init__(seed=seed)
self.num_agents = n
self.count = 0
self.s = 0
# Create n agents
MoneyAgent.create_agents(model=self,n=n)
def initalize(self):
n = self.num_agents
for a in self.agents:
i = a.unique_id
a.w = random_n_except_i(n,i)
a.p = i
a.h = np.zeros(n,dtype=int)
a.d = np.zeros(n,dtype=int)
a.h[i-1] = 1
a.u = 0.0
a.s = 0 # 取引回数
def chenge_w(self):
n = self.num_agents
for a in self.agents:
i = a.unique_id
w = a.w
a.w = random_n_except_i(n,i)
## print(f"Agent{i} change W from {w} to {a.w}")
def step(self):
self.initalize()
self.agents.do("step")
self.s = 0
for a in self.agents:
self.s += a.s
if self.s > 0:
print(f"success = {self.s}")
print("***********************")
実行結果
最後は、取引回数と、取引成功の平均値です。
model = MoneyModel(5)
ss = []
for _ in range(5):
model.step()
ss.append(model.s)
model.chenge_w()
print(ss)
print(np.mean(ss))
AW=4 BW=2 DA=1 DB=1
A:Agent2 has h=[0 1 0 0 0] d=[0 0 0 1 0] w=4 and p=2 u=0.0 sumD=1
B:Agent4 has h=[0 0 0 1 0] d=[0 1 0 0 0] w=2 and p=4 u=0.0 sumD=1
AW=2 BW=4 DA=1 DB=1
A:Agent4 has h=[0 0 0 1 0] d=[0 1 0 0 0] w=2 and p=4 u=0.0 sumD=1
B:Agent2 has h=[0 1 0 0 0] d=[0 0 0 1 0] w=4 and p=2 u=0.0 sumD=1
success = 2
AW=4 BW=1 DA=1 DB=1
A:Agent1 has h=[1 0 0 0 0] d=[0 0 0 1 0] w=4 and p=1 u=0.0 sumD=1
B:Agent4 has h=[0 0 0 1 0] d=[1 0 0 0 0] w=1 and p=4 u=0.0 sumD=1
AW=5 BW=2 DA=1 DB=1
A:Agent2 has h=[0 1 0 0 0] d=[0 0 0 0 1] w=5 and p=2 u=0.0 sumD=1
B:Agent5 has h=[0 0 0 0 1] d=[0 1 0 0 0] w=2 and p=5 u=0.0 sumD=1
AW=1 BW=4 DA=1 DB=1
A:Agent4 has h=[0 0 0 1 0] d=[1 0 0 0 0] w=1 and p=4 u=0.0 sumD=1
B:Agent1 has h=[1 0 0 0 0] d=[0 0 0 1 0] w=4 and p=1 u=0.0 sumD=1
AW=2 BW=5 DA=1 DB=1
A:Agent5 has h=[0 0 0 0 1] d=[0 1 0 0 0] w=2 and p=5 u=0.0 sumD=1
B:Agent2 has h=[0 1 0 0 0] d=[0 0 0 0 1] w=5 and p=2 u=0.0 sumD=1
success = 4
[2, 0, 0, 4, 0]
1.2
おわりに
力不足なので、まだ実装してない部分があります。
とりあえずは忘れない内に。