# -*- 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