# -*- coding: UTF-8 -*- import sys from math import * from random import * import numpy as np ##################### # クラスInletの定義 ##################### class Inlet : ########################################################### # コンストラクタ # name1 : 入り口名 # a_t1 # = -n : 到着する客の人数を負の値にしたもの # # =0 : 指数分布 # # =1 : 一定時間間隔 # m_a: 到着時間間隔またはその平均 # que1 : 客の到着時刻リスト # name2 : 待ち行列名 ########################################################### def __init__(self, name1, a_t1, m_a, que1, name2) : self.name = name1 # 入り口名 self.out = name2 # 待ち行列名 self.a_t = a_t1 # = -n : 到着する客の人数を負の値にしたもの # =0 : 指数分布 # =1 : 一定時間間隔 self.mean = m_a # 到着時間間隔またはその平均 self.que = que1 # 客の到着時刻リスト if self.a_t == 0 : self.arrive_time = expovariate(1.0 / self.mean) # 客の到着時刻(負:客がない) elif self.a_t == 1 : self.arrive_time = 0 else : self.arrive_time = self.que.pop(0) self.out_n = 0 # 待ち行列番号(Q_baseのコンストラクタで設定) ##################### # クラスQueueの定義 ##################### class Queue : ############################################# # コンストラクタ # name1 : 待ち行列名 # n1 : =0 : 入り口から入る # >0 : 複数の窓口から入る(窓口数) # in1 : 入り口名,または,窓口名 # m1 : 処理する窓口数 # out1 : 窓口名 ############################################# def __init__(self, name1, n1, in1, m1, out1) : self.name = name1 # 待ち行列名 self.n = n1 # =0 : 入り口から入る # >0 : 複数の窓口から入る(窓口数) self.inn = in1 # 入り口名,または,窓口名(入り口) self.m = m1 # 処理する窓口数 self.out = out1 # 窓口名(出口) self.nc = 0 # 待ち行列への到着客数カウンタ self.max_q_l = 0 # 最大待ち行列長 self.c_ql = 0.0 # 待ち行列長にその長さが継続した時間を乗じた値の累計 self.ql_t = 0.0 # 現在の待ち行列長になった時間 self.max_wt = 0.0 # 最大待ち時間 self.c_wt = 0.0 # 待ち時間の累計 self.in_n = [] # 入り口番号,または,窓口番号(Q_baseのコンストラクタで設定) self.out_n = [] # 窓口番号(Q_baseのコンストラクタで設定) self.que = [] # 待ち行列 ###################### # クラスEntityの定義 ###################### class Entity : ######################################## # コンストラクタ # name1 : 窓口名 # s_t1 # =0 : 指数分布 # # =1 : 一定時間 # m_s:サービス時間またはその平均 # in : 待ち行列(入力)の名前 # sw : =0 : システムの外に出る # =1 : 待ち行列に入る # out : 待ち行列(出力)の名前 ######################################## def __init__(self, name1, s_t1, m_s, name2, sw, name3) : self.name = name1 # 窓口名 self.to = sw # =0 : システムの外に出る # =1 : 待ち行列に入る self.inn = name2 # 待ち行列(入力)の名前 if self.to > 0 : self.out = name3 # 待ち行列(出力)の名前 self.end_time = -1.0 # サービス終了時刻(負:何も処理していない) self.s_t = s_t1 # =0 : 指数分布 # =1 : 一定時間 self.mean = m_s # 平均サービス時間 self.service = 0 # サービス中の客番号(0のときは無し) self.busy_t = -1.0 # 窓口がふさがった時刻 self.c_busy = 0.0 # 窓口がふさがっている時間の累計 self.in_n = -1 # 待ち行列(入力)番号(Q_baseのコンストラクタで設定) self.out_n = -1 # 待ち行列(出力)番号(Q_baseのコンストラクタで設定) ######################## # クラスCustomerの定義 ######################## class Customer : ##################### # コンストラクタ # s1,s2 : 状態 # t : 到着時刻 ##################### def __init__(self, s1, s2, t) : self.time = t # 到着時刻 self.state1 = s1 # 客の状態1 # =0 : 待ち行列に入っている # =1 : サービスを受けている self.state2 = s2 # 客の状態2(待ち行列番号,または,窓口番号) ####################### # クラスQ_baseの定義 ####################### class Q_base : ######################################## # コンストラクタ # v_i : Inletオブジェクトリスト # v_q : Queueオブジェクトリスト # v_e : Entityオブジェクトリスト # e : シミュレーション終了時刻 ######################################## def __init__(self, v_i, v_q, v_e, e) : print("") # 接続関係のチェック self.inl = v_i # Inletオブジェクトリスト self.que = v_q # Queueオブジェクトリスト self.ent = v_e # Entityオブジェクトリスト # Inlet for i1 in range(0, len(self.inl)-1) : for i2 in range(i1+1, len(self.inl)) : if self.inl[i1].name == self.inl[i2].name : print("***error 同じ名前の入り口があります " + self.inl[i1].name) for i1 in range(0, len(self.inl)) : k = -1 for i2 in range(0, len(self.que)) : if self.inl[i1].out == self.que[i2].name : k = i2 break if k >= 0 : self.inl[i1].out_n = k else : print("***error 入り口から入る待ち行列名が不適当です " + self.inl[i1].out) # Queue for i1 in range(0, len(self.que)-1) : for i2 in range(i1+1, len(self.que)) : if self.que[i1].name == self.que[i2].name : cout << "***error 同じ名前の待ち行列があります " + self.que[i1].name + "\n" for i1 in range(0, len(self.que)) : if self.que[i1].n == 0 : k = -1 for i2 in range(0, len(self.inl)) : if self.que[i1].inn[0] == self.inl[i2].name : k = i2 break if k >= 0 : self.que[i1].in_n.append(k) else : print("***error 待ち行列に入る入り口名が不適当です " + self.que[i1].inn[0]) else : for i2 in range(0, self.que[i1].n) : k = -1 for i3 in range(0, len(self.ent)) : if self.que[i1].inn[i2] == self.ent[i3].name : k = i3 break if k >= 0 : self.que[i1].in_n.append(k) else : print("***error 待ち行列に入る窓口名が不適当です " + self.que[i1].inn[i2]) for i2 in range(0, self.que[i1].m) : k = -1 for i3 in range(0, len(self.ent)) : if self.que[i1].out[i2] == self.ent[i3].name : k = i3 break if k >= 0 : self.que[i1].out_n.append(k) else : print("***error 待ち行列を処理する窓口名が不適当です " + self.que[i1].out[i2]) # Entity for i1 in range(0, len(self.ent)-1) : k = -1 for i2 in range(i1+1, len(self.ent)) : if self.ent[i1].name == self.ent[i2].name : print("***error 同じ名前の窓口があります " + self.ent[i1].name) for i1 in range(0, len(self.ent)) : k = -1 for i2 in range(0, len(self.que)) : if self.ent[i1].inn == self.que[i2].name : k = i2 break if k >= 0 : self.ent[i1].in_n = k else : print("***error 窓口に入る待ち行列名が不適当です " + self.ent[i1].inn) if self.ent[i1].to > 0 : k = -1 for i2 in range(0, len(self.que)) : if self.ent[i1].out == self.que[i2].name : k = i2 break if k >= 0 : self.ent[i1].out_n = k else : print("***error 窓口の出口にある待ち行列名が不適当です " + self.ent[i1].out) # 初期設定 self.p_time = 0.0 # 現在時刻 self.max_c = 0 # 最大系内客数 self.nc = 0 # システムへの到着客数カウンタ self.now_c_t = 0.0 # 現在の系内客数になった時間 self.c_now_c = 0.0 # 系内客数にその数が継続した時間を乗じた値の累計 self.c_sys = 0.0 # 滞在時間の累計 self.max_sys = 0.0 # 最大滞在時間 self.end = e # シミュレーション終了時間 self.cus = dict() # 系内にいる客のリスト ############# # 全体の制御 ############# def Control(self) : sw = np.zeros(2, np.int) while sw[0] > -2 : self.Next(sw) # 次の処理の選択 if sw[0] == -1 : sw[0] = self.End_o_s() # シミュレーションの終了 else : if sw[0] == 0 : self.Arrive(sw[1]) # 客の到着処理 else : self.Service(sw[1]) # サービスの終了 ############################################# # 次の処理の決定 # sw[0] : =-1 : シミュレーションの終了 # =0 : 客の到着処理 # =1 : 窓口のサービス終了 # [1] : 入り口番号 or 窓口番号 ############################################# def Next(self, sw) : tm = self.end # 次の処理時刻 sw[0] = -1 # 次の客の到着時刻 for i1 in range(0, len(self.inl)) : x = self.inl[i1] if x.arrive_time >= 0.0 and x.arrive_time < tm : sw[0] = 0 sw[1] = i1 tm = x.arrive_time # サービス終了時刻 for i1 in range(0, len(self.ent)) : x = self.ent[i1] if x.service > 0 and x.end_time <= tm : sw[0] = 1 sw[1] = i1 tm = x.end_time if sw[0] < 0 : self.end = self.p_time ################################## # 終了処理 # return : =-1 : 終了前処理 # =-2 : 実際の終了 ################################## def End_o_s(self) : sw = -2 self.p_time = self.end # 現在時刻 for i1 in range(0, len(self.ent)) : x = self.ent[i1] if x.service > 0 : # サービス中の客はいるか? if sw == -2 : sw = -1 self.end = x.end_time # 窓口i1のサービス終了時刻 else : if x.end_time > self.end : self.end = x.end_time # 窓口i1のサービス終了時刻 return sw ######################## # 客の到着処理 # kk : 入り口番号 ######################## def Arrive(self, kk) : # 客数の増加と次の客の到着時刻の設定 self.nc += 1 # 到着客数カウンタ self.p_time = self.inl[kk].arrive_time # 現在時刻 if self.inl[kk].a_t == 0 : # 次の客の到着時刻 self.inl[kk].arrive_time = self.p_time + expovariate(1.0 / self.inl[kk].mean) elif self.inl[kk].a_t == 1 : self.inl[kk].arrive_time = self.p_time + self.inl[kk].mean else : if len(self.inl[kk].que) < 1 : self.inl[kk].arrive_time = -1.0 else : self.inl[kk].arrive_time = self.inl[kk].que.pop(0) if self.inl[kk].arrive_time >= self.end : self.inl[kk].arrive_time = -1.0 # 系内客数の処理 self.c_now_c += len(self.cus) * (self.p_time - self.now_c_t) # 系内客数にその数が継続した時間を乗じた値の累計 self.now_c_t = self.p_time # 現在の系内客数になった時刻 if len(self.cus)+1 > self.max_c : self.max_c = len(self.cus) + 1 # 最大系内客数 # 空いている窓口を探す k1 = self.inl[kk].out_n self.que[k1].nc += 1 k = -1 for i1 in range(0, self.que[k1].m) : k2 = self.que[k1].out_n[i1] # 処理窓口 if self.ent[k2].service == 0 : k = k2 break # 窓口に空きがない場合 if k < 0 : ct_p = Customer(0, k1, self.p_time) self.cus[self.nc] = ct_p # 客の登録(系内客数) self.que[k1].c_ql += len(self.que[k1].que) * (self.p_time - self.que[k1].ql_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 self.que[k1].que.append(self.nc) # 客の登録(待ち行列) self.que[k1].ql_t = self.p_time # 現在の待ち行列長になった時刻 if len(self.que[k1].que) > self.que[k1].max_q_l : self.que[k1].max_q_l = len(self.que[k1].que) # 最大待ち行列長 # すぐサービスをうけられる場合 else : ct_p = Customer(1, k, self.p_time) self.cus[self.nc] = ct_p # 客の登録(系内客数) self.ent[k].service = self.nc # サービスを受けている客番号 self.ent[k].busy_t = self.p_time # 窓口がふさがった時刻 if self.ent[k].s_t == 0 : # 窓口のサービス終了時刻 self.ent[k].end_time = self.p_time + expovariate(1.0 / self.ent[k].mean) else : self.ent[k].end_time = self.p_time + self.ent[k].mean ################################### # サービス終了時の処理 # kk : サービス終了窓口番号 ################################### def Service(self, kk) : # 時間の設定 self.p_time = self.ent[kk].end_time # 現在時刻 self.ent[kk].end_time = -1.0 # サービス終了時間 # システムの外へ出る場合 if self.ent[kk].to == 0 : # 系内客数の処理 self.c_now_c += len(self.cus) * (self.p_time - self.now_c_t) # 系内客数にその数が継続した時間を乗じた値の累計 self.now_c_t = self.p_time # 現在の系内客数になった時刻 # 滞在時間の処理 it = self.cus[self.ent[kk].service] # サービス中の客 x1 = self.p_time - it.time self.c_sys += x1 # 滞在時間の累計 if x1 > self.max_sys : self.max_sys = x1 # 最大滞在時間 self.cus.pop(self.ent[kk].service) # 客の削除(系内客数) # 他の窓口処理へ入る場合の処理 else : k1 = self.ent[kk].out_n self.que[k1].nc += 1 sw = 1 k2 = 0 if len(self.que[k1].que) == 0 : for i1 in range(0, self.que[k1].m) : k2 = self.que[k1].out_n[i1] # 窓口 if self.ent[k2].service == 0 : sw = 0 break # 待ち行列がある場合 if sw > 0 : self.que[k1].c_ql += len(self.que[k1].que) * (self.p_time - self.que[k1].ql_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 self.que[k1].que.append(self.ent[kk].service) # 客の登録(待ち行列) self.que[k1].ql_t = self.p_time # 現在の待ち行列長になった時刻 if len(self.que[k1].que) > self.que[k1].max_q_l : self.que[k1].max_q_l = len(self.que[k1].que) # 最大待ち行列長 it = self.cus[self.ent[kk].service] it.state1 = 0 # 客の状態変更(待ち行列) it.state2 = self.ent[kk].out_n # 客の状態変更(待ち行列番号) # すぐサービスをうけられる場合 else : self.ent[k2].service = self.ent[kk].service # サービスを受けている客番号 self.ent[k2].busy_t = self.p_time # 窓口がふさがった時刻 if self.ent[k2].s_t == 0 : # 窓口のサービス終了時刻 self.ent[k2].end_time = self.p_time + expovariate(1.0 / self.ent[k2].mean) else : self.ent[k2].end_time = self.p_time + self.ent[k2].mean # 窓口使用時間の処理 self.ent[kk].service = 0 # 窓口を空き状態にする self.ent[kk].c_busy += (self.p_time - self.ent[kk].busy_t) # 窓口がふさがっている時間の累計 # この窓口に対する待ち行列がある場合 k3 = self.ent[kk].in_n if len(self.que[k3].que) > 0 : self.que[k3].c_ql += len(self.que[k3].que) * (self.p_time - self.que[k3].ql_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 n = self.que[k3].que.pop(0) # 待ち行列の先頭にいる客 self.que[k3].ql_t = self.p_time # 現在の待ち行列長になった時刻 x1 = self.p_time - self.cus[n].time self.que[k3].c_wt += x1 # 待ち時間の累計 if x1 > self.que[k3].max_wt : self.que[k3].max_wt = x1 # 最大待ち時間 for i1 in range(0, self.que[k3].m) : k4 = self.que[k3].out_n[i1] # 窓口 if self.ent[k4].service == 0 : self.ent[k4].service = n # 窓口の客番号 self.ent[k4].busy_t = self.p_time # 窓口がふさがった時刻 if self.ent[k4].s_t == 0 : # 窓口のサービス終了時刻 self.ent[k4].end_time = self.p_time + expovariate(1.0 / self.ent[k4].mean) else : self.ent[k4].end_time = self.p_time + self.ent[k4].mean self.cus[n].state1 = 1 # 客の状態変更(サービス中) self.cus[n].state2 = k4 # 客の状態変更(窓口番号) break ########################## # 統計量の計算と最終出力 ########################## def Output(self) : # System print("全客数 {0:d}".format(self.nc), end="") print(" 最大系内客数 {0:d} 最大滞在時間 {1:.3f}".format(self.max_c, self.max_sys)) print("平均系内客数 {0:.3f}".format(self.c_now_c / self.p_time), end="") print(" 平均滞在時間 {0:.3f}".format(self.c_sys / self.nc), end="") print(" 終了時間 {0:.3f}".format(self.p_time)) # Entity for i1 in range(0, len(self.ent)) : e = self.ent[i1] print("Entity " + e.name, end="") print(" 稼働率 {0:.3f}".format(e.c_busy / self.p_time)) # Queue for i1 in range(0, len(self.que)) : q = self.que[i1] print("Queue " + q.name, end="") print(" 客数 {0:d}".format(q.nc), end="") print(" 最大待ち行列長 {0:d}".format(q.max_q_l), end="") print(" 最大待ち時間 {0:.3f}".format(q.max_wt)) print(" 平均待ち行列長 {0:.3f}".format(q.c_ql / self.p_time), end="") print(" 平均待ち時間 {0:.3f}".format(q.c_wt / q.nc)) ---------------------------------- # -*- coding: UTF-8 -*- import numpy as np import sys from math import * from random import * from function import Inlet, Queue, Entity, Customer, Q_base ############################# # 複雑な待ち行列問題 # coded by Y.Suganuma ############################# # 入り口 n_i = int(input("入り口(Inlet)の数は? ")) inl = [] for i1 in range(0, n_i) : print(str(i1+1) + " 番目の入り口(Inlet)") name1 = input(" 名前は? ").strip(" \n") qq = [] n = int(input(" 到着分布(=0:指数分布,=1:一定時間間隔,<0:指定,客数の負値)? ")) if n == 0 : m_a = float(input(" 到着時間間隔の平均値は? ")) elif n == 1 : m_a = float(input(" 到着時間間隔は? ")) else : for i2 in range(0, -n) : x = float(input(" 到着時間は? ")) qq.append(x) name2 = input(" 並ぶ待ち行列の名前は? ").strip(" \n") inl_e = Inlet(name1, n, m_a, qq, name2) inl.append(inl_e) # 待ち行列 n_q = int(input("待ち行列(Queue)の数は? ")) que = [] for i1 in range(0, n_q) : print(str(i1+1) + " 番目の待ち行列(Queue)") name1 = input(" 名前は? ").strip(" \n") n = int(input(" 入り口(0),または,窓口(n>0,窓口の数)から? ")) inn = [] if n == 0 : name2 = input(" 入り口の名前は? ").strip(" \n") inn.append(name2) else : for i2 in range(0, n) : name3 = input(" " + str(i2+1) + " 番目の窓口の名前は? ").strip(" \n") inn.append(name3) m = int(input(" 処理する窓口の数は? ")) out = [] for i2 in range(0, m) : name4 = input(" " +str(i2+1) + " 番目の窓口の名前は? ").strip(" \n") out.append(name4) que_e = Queue(name1, n, inn, m, out) que.append(que_e) # 窓口 n_e = int(input("窓口(Entity)の数は? ")) ent = [] for i1 in range(0, n_e) : print(str(i1+1) + " 番目の窓口(Entity)") name1 = input(" 名前は? ").strip(" \n") s_t = int(input(" サービス分布(=0:指数分布,=1:一定時間)? ")) if s_t == 0 : m_s = float(input(" サービス時間の平均値は? ")) else : m_s = float(input(" サービス時間は? ")) name2 = input(" 待ち行列(入力)の名前は? ").strip(" \n") sw = int(input(" 終了後,外部(0),または,待ち行列(1)? ")) name3 = "" if sw > 0 : name3 = input(" 待ち行列(出力)の名前は? ").strip(" \n") ent_e = Entity(name1, s_t, m_s, name2, sw, name3) ent.append(ent_e) # 全体の制御を行うクラス end = float(input("シミュレーション終了時間? ")) base = Q_base(inl, que, ent, end) # 全体の制御を行うクラス # 実行 base.Control() # 出力 base.Output() ------------入力例(簡単な場合)----------- 1 Inlet 0 5 Queue 1 Queue 0 Inlet 2 Entity1 Entity2 2 Entity1 0 4 Queue 0 Entity2 0 4 Queue 0 10000 ------------入力例(複雑な場合)----------- 2 Inlet1 0 5 Queue1 Inlet2 0 5 Queue2 3 Queue1 0 Inlet1 1 Entity1 Queue2 0 Inlet2 1 Entity2 Queue3 2 Entity1 Entity2 2 Entity3 Entity4 4 Entity1 0 4 Queue1 1 Queue3 Entity2 0 4 Queue2 1 Queue3 Entity3 0 3 Queue3 0 Entity4 0 3 Queue3 0 10000