############################# # 簡単な待ち行列問題(M/M/s) # coded by Y.Suganuma ############################# ######################## # クラスCustomerの定義 ######################## class Customer ##################### # コンストラクタ # s : 状態 # t : 到着時刻 ##################### def initialize(s, t) @_state = s # 客の状態 # =-1 : 待ち行列に入っている # >=0 : サービスを受けている窓口番号 @_time = t # 到着時刻 end attr_accessor("_state", "_time") end ######################## # クラスQ_baseの定義 ######################## class Q_base ######################################### # コンストラクタ # s_i : 窓口の数 # m_a_i : 到着時間間隔の平均値 # m_s_i : サービス時間の平均値 # stp_i : シミュレーション終了時刻 ######################################### def initialize(s_i, m_a_i, m_s_i, stp_i) # 設定 @_s = s_i # 窓口の数 @_m_a = m_a_i # 到着時間間隔の平均値 @_m_s = m_s_i # サービス時間の平均値 @_stp = stp_i # シミュレーション終了時刻 # 領域の確保 @_sb = Array.new(@_s) # 各窓口の空き状況 # =0 : 窓口は空いている # >0 : サービスを受けている客番号 @_c_sb = Array.new(@_s) # 各窓口がふさがっている時間の累計 for i1 in 0 ... @_s @_sb[i1] = 0 @_c_sb[i1] = 0.0 end @_st_e = Array.new(@_s) # 各窓口のサービス終了時刻 @_st_s = Array.new(@_s) # 各窓口がふさがった時刻 # 初期設定 @_p_time = 0.0 # 現在時刻 @_nc = 0 # 到着客数カウンタ @_asb = @_s # 全窓口の空き状況 # =0 : すべての窓口がふさがっている # =n : n個の窓口が空いている @_m_lq = 0 # 最大待ち行列長 @_m_sc = 0 # 最大系内客数 @_c_asb = 0.0 # すべての窓口がふさがっている時間の累計 @_c_wt = 0.0 # 待ち時間の累計 @_m_wt = 0.0 # 最大待ち時間 @_c_lq_t = 0.0 # 待ち行列長にその長さが継続した時間を乗じた値の累計 @_lq_t = 0.0 # 現在の待ち行列長になった時刻 @_m_sys = 0.0 # 最大滞在時間 @_c_sys = 0.0 # 滞在時間の累計 @_c_sc_t = 0.0 # 系内客数にその数が継続した時間を乗じた値の累計 @_sc_t = 0.0 # 現在の系内客数になった時刻 @_asb_t = 0.0 # すべての窓口がふさがった時刻 @_cus = Hash.new() # 系内にいる客のリスト @_que = Array.new() # 待ち行列 # 最初の客の到着時刻の設定 @_at = @_p_time + Next_at() # 次の客の到着時刻(負の時は,終了) end ################################ # 次の客の到着までの時間の発生 ################################ def Next_at() return -@_m_a * Math.log(rand(0)) end ##################### # サービス時間の発生 ##################### def Next_sv() return -@_m_s * Math.log(rand(0)) end ############## # 全体の制御 ############## def Control() sw = 0 while sw > -2 sw = Next() # 次の処理の選択 if sw == -1 sw = End_o_s() # シミュレーションの終了 else if sw == 0 Arrive() # 客の到着処理 else Service(sw) # サービスの終了 end end end end ################################################## # 次の処理の決定 # return : =-1 : シミュレーションの終了 # =0 : 客の到着処理 # =i : i番目の窓口のサービス終了 ################################################## def Next() sw = -1 t = @_stp # シミュレーション終了時刻で初期設定 # 次の客の到着時刻 if @_at >= 0.0 && @_at < t sw = 0 t = @_at end # サービス終了時刻 for i1 in 0 ... @_s if @_sb[i1] > 0 && @_st_e[i1] <= t sw = i1 + 1 t = @_st_e[i1] # 窓口i1のサービス終了時刻 end end return sw end ################################## # 終了処理 # return : =-1 : 終了前処理 # =-2 : 実際の終了 ################################## def End_o_s() sw = -2 @_p_time = @_stp # 現在時刻 @_at = -1.0 # 次の客の到着時刻 for i1 in 0 ... @_s if @_sb[i1] > 0 # サービス中の客はいるか? if sw == -2 sw = -1 @_stp = @_st_e[i1] # 窓口i1のサービス終了時刻 else if @_st_e[i1] > @_stp @_stp = @_st_e[i1] # 窓口i1のサービス終了時刻 end end end end return sw end ################ # 客の到着処理 ################ def Arrive() # 客数の増加と次の客の到着時刻の設定 @_nc += 1 # 到着客数カウンタ @_p_time = @_at # 現在時刻 @_at = @_p_time + Next_at() # 次の客の到着時刻 if @_at >= @_stp @_at = -1.0 end # 系内客数の処理 @_c_sc_t += @_cus.length * (@_p_time - @_sc_t) # 系内客数にその数が継続した時間を乗じた値の累計 @_sc_t = @_p_time # 現在の系内客数になった時刻 if @_cus.length+1 > @_m_sc @_m_sc = @_cus.length + 1 # 最大系内客数 end # 窓口に空きがない場合 if @_asb == 0 ct_p = Customer.new(-1, @_p_time) @_cus[@_nc] = ct_p # 客の登録(系内客数) @_c_lq_t += @_que.length * (@_p_time - @_lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 @_que.push(@_nc) # 客の登録(待ち行列) @_lq_t = @_p_time # 現在の待ち行列長になった時刻 if @_que.length > @_m_lq @_m_lq = @_que.length # 最大待ち行列長 end # すぐサービスを受けられる場合 else k = -1 for i1 in 0 ... @_s if @_sb[i1] == 0 ct_p = Customer.new(i1, @_p_time) @_cus[@_nc] = ct_p # 客の登録(系内客数) k = i1 @_sb[k] = @_nc # サービスを受けている客番号 @_st_e[k] = @_p_time + Next_sv() # 窓口kのサービス終了時刻 @_asb -= 1 # 空いている窓口数 break end end @_st_s[k] = @_p_time # 窓口kがふさがった時刻 if @_asb == 0 @_asb_t = @_p_time # すべての窓口がふさがった時刻 end end end ################################# # サービス終了時の処理 # k : サービス終了窓口番号 ################################# def Service(k) # 時間の設定 k -= 1 @_p_time = @_st_e[k] # 現在時刻 @_st_e[k] = -1.0 # サービス終了時間 # 系内客数の処理 @_c_sc_t += @_cus.length * (@_p_time - @_sc_t) # 系内客数にその数が継続した時間を乗じた値の累計 @_sc_t = @_p_time # 現在の系内客数になった時刻 # 滞在時間の処理 x1 = @_p_time - @_cus[@_sb[k]]._time @_c_sys += x1 # 滞在時間の累計 if x1 > @_m_sys @_m_sys = x1 # 最大滞在時間 end @_cus.delete(@_sb[k]) # 客の削除(系内客数) # 窓口使用時間の処理 @_asb += 1 # 空いている窓口数 @_sb[k] = 0 # 窓口kを空き状態にする @_c_sb[k] += (@_p_time - @_st_s[k]) # 窓口kがふさがっている時間の累計 # 待ち行列がある場合 if @_que.length > 0 @_asb -= 1 # 開いている窓口数 @_c_lq_t += @_que.length * (@_p_time - @_lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計 n = @_que.delete_at(0) @_lq_t = @_p_time # 現在の待ち行列長になった時刻 x1 = @_p_time - @_cus[n]._time @_c_wt += x1 # 待ち時間の累計 if x1 > @_m_wt @_m_wt = x1 # 最大待ち時間 end k = -1 for i1 in 0 ... @_s if @_sb[i1] == 0 k = i1 @_sb[k] = n # 窓口kの客番号 @_st_e[k] = @_p_time + Next_sv() # 窓口kのサービス終了時刻 @_st_s[k] = @_p_time # 窓口kがふさがった時刻 @_cus[n]._state = k # 客の状態変更 break end end # 待ち行列がない場合 else if @_asb == 1 @_c_asb += (@_p_time - @_asb_t) # すべての窓口がふさがっている時間の累計 end end end ######################## # 結果の出力 # (カッコ内は理論値) ######################## def Output() rn = Float(@_nc) rs = Float(@_s) ram = 1.0 / @_m_a myu = 1.0 / @_m_s rou = ram / (rs * myu) if @_s == 1 p0 = 1.0 - rou pi = rou else p0 = 1.0 / (1.0 + 2.0 * rou + 4.0 * rou * rou / (2.0 * (1.0 - rou))) pi = 4.0 * rou * rou * p0 / (2.0 * (1.0 - rou)) end lq = pi * rou / (1.0 - rou) l = lq + rs * rou wq = lq / ram w = wq + 1.0 / myu printf("シミュレーション終了時間=%.3f 客数=%d ρ=%.3f p0=%.3f\n", @_p_time, @_nc, rou, p0) printf(" すべての窓口が塞がっている割合=%.3f (%.3f)\n", @_c_asb/@_p_time, pi) printf(" 各窓口が塞がっている割合\n") for i1 in 0 ... @_s printf(" %d %.3f\n", (i1+1), @_c_sb[i1]/@_p_time) end printf(" 平均待ち行列長=%.3f (%.3f) 最大待ち行列長=%d\n", @_c_lq_t/@_p_time, lq, @_m_lq) printf(" 平均系内客数 =%.3f (%.3f) 最大系内客数 =%d\n", @_c_sc_t/@_p_time, l, @_m_sc) printf(" 平均待ち時間 =%.3f (%.3f) 最大待ち時間 =%.3f\n", @_c_wt/rn, wq, @_m_wt) printf(" 平均滞在時間 =%.3f (%.3f) 最大滞在時間 =%.3f\n", @_c_sys/rn, w, @_m_sys) end end # 入力データ print("窓口の数は? ") s = Integer(gets()) print("シミュレーション終了時間? ") stp = Float(gets()) print(" 到着時間間隔の平均値は? ") m_a = Float(gets()) print(" サービス時間の平均値は? ") m_s = Float(gets()) # システムの定義 base = Q_base.new(s, m_a, m_s, stp) # シミュレーションの実行 srand() base.Control() # 出力 base.Output()