| 情報学部 | 菅沼ホーム | 目次 | 索引 |

/******************************/
/* 簡単な待ち行列問題(M/M/s)*/
/* coded by Y.Suganuma */
/******************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
#include <math.h>
#include <map>
#include <queue>
#include "MT.h"
using namespace std;
/************************/
/* クラスCustomerの定義 */
/************************/
class Customer
{
public :
double time; // 到着時刻
int state; // 客の状態
// =-1 : 待ち行列に入っている
// >=0 : サービスを受けている窓口番号
/*********************/
/* コンストラクタ */
/* s : 状態 */
/* t : 到着時刻 */
/*******************************/
Customer::Customer(int s, double t)
{
time = t;
state = s;
}
};
/**********************/
/* クラスQ_baseの定義 */
/**********************/
class Q_base {
int s; // 窓口の数
int asb; // 全窓口の空き状況
// =0 : すべての窓口がふさがっている
// =n : n個の窓口が空いている
int *sb; // 各窓口の空き状況
// =0 : 窓口は空いている
// >0 : サービスを受けている客番号
double asb_t; // すべての窓口がふさがった時刻
double c_asb; // すべての窓口がふさがっている時間の累計
double *c_sb; // 各窓口がふさがっている時間の累計
double *st_e; // 各窓口のサービス終了時刻
double *st_s; // 各窓口がふさがった時刻
int m_lq; // 最大待ち行列長
double c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計
double c_wt; // 待ち時間の累計
double lq_t; // 現在の待ち行列長になった時刻
double m_wt; // 最大待ち時間
double c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計
double c_sys; // 滞在時間の累計
double m_sys; // 最大滞在時間
double sc_t; // 現在の系内客数になった時刻
int m_sc; // 最大系内客数
double m_a; // 到着時間間隔の平均値
double m_s; // サービス時間の平均値
double at; // 次の客の到着時刻(負の時は,終了)
double p_time; // 現在時刻
double end; // シミュレーション終了時刻
int nc; // 到着客数カウンタ
map<int, Customer> cus; // 系内にいる客のリスト
queue<int> que; // 待ち行列
public:
Q_base(int, double, double, double); // コンストラクタ
~Q_base(); // デストラクタ
double Next_at(); // 次の到着時刻
double Next_sv(); // サービス終了時刻
void Control(); // 全体の制御
int Next(); // 次の処理の決定
int End_o_s(); // 終了処理
void Arrive(); // 客の到着処理
void Service(int); // サービス終了
void Output(); // 出力
};
/*****************************************/
/* コンストラクタ */
/* s_i : 窓口の数 */
/* m_a_i : 到着時間間隔の平均値 */
/* m_s_i : サービス時間の平均値 */
/* end_i : シミュレーション終了時刻 */
/*****************************************/
Q_base::Q_base (int s_i, double m_a_i, double m_s_i, double end_i)
{
/*
設定
*/
s = s_i;
m_a = m_a_i;
m_s = m_s_i;
end = end_i;
/*
領域の確保
*/
sb = new int [s];
c_sb = new double [s];
st_e = new double [s];
st_s = new double [s];
for (int i1 = 0; i1 < s; i1++) {
sb[i1] = 0;
c_sb[i1] = 0.0;
}
/*
初期設定
*/
p_time = 0.0;
nc = 0;
asb = s;
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;
/*
乱数の初期設定
*/
init_genrand((unsigned)time(NULL));
/*
最初の客の到着時刻の設定
*/
at = p_time + Next_at();
}
/****************/
/* デストラクタ */
/****************/
Q_base::~Q_base()
{
delete [] sb;
delete [] c_sb;
delete [] st_e;
delete [] st_s;
}
/********************************/
/* 次の客の到着までの時間の発生 */
/********************************/
double Q_base::Next_at()
{
return -m_a * log(genrand_real3());
}
/************************/
/* サービス時間の発生 */
/************************/
double Q_base::Next_sv()
{
return -m_s * log(genrand_real3());
}
/**************/
/* 全体の制御 */
/**************/
void Q_base::Control()
{
int sw = 0;
while (sw > -2) {
sw = Next(); // 次の処理の選択
if (sw == -1)
sw = End_o_s(); // シミュレーションの終了
else {
if (sw == 0)
Arrive(); // 客の到着処理
else
Service(sw); // サービスの終了
}
}
}
/**************************************************/
/* 次の処理の決定 */
/* return : =-1 : シミュレーションの終了 */
/* =0 : 客の到着処理 */
/* =i : i番目の窓口のサービス終了 */
/**************************************************/
int Q_base::Next()
{
int sw = -1;
double t = end; // シミュレーション終了時刻で初期設定
// 次の客の到着時刻
if (at >= 0.0 && at < t) {
sw = 0;
t = at;
}
// サービス終了時刻
for (int i1 = 0; i1 < s; i1++) {
if (sb[i1] > 0 && st_e[i1] <= t) {
sw = i1 + 1;
t = st_e[i1]; // 窓口i1のサービス終了時刻
}
}
return sw;
}
/**********************************/
/* 終了処理 */
/* return : =-1 : 終了前処理 */
/* =-2 : 実際の終了 */
/**********************************/
int Q_base::End_o_s()
{
int sw = -2;
p_time = end; // 現在時刻
at = -1.0; // 次の客の到着時刻
for (int i1 = 0; i1 < s; i1++) {
if (sb[i1] > 0) { // サービス中の客はいるか?
if (sw == -2) {
sw = -1;
end = st_e[i1]; // 窓口i1のサービス終了時刻
}
else {
if (st_e[i1] > end)
end = st_e[i1]; // 窓口i1のサービス終了時刻
}
}
}
return sw;
}
/****************/
/* 客の到着処理 */
/****************/
void Q_base::Arrive()
{
/*
客数の増加と次の客の到着時刻の設定
*/
nc += 1; // 到着客数カウンタ
p_time = at; // 現在時刻
at = p_time + Next_at(); // 次の客の到着時刻
if (at >= end)
at = -1.0;
/*
系内客数の処理
*/
c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time; // 現在の系内客数になった時刻
if ((int)cus.size()+1 > m_sc)
m_sc = cus.size() + 1; // 最大系内客数
/*
窓口に空きがない場合
*/
if (asb == 0) {
Customer ct_p(-1, p_time);
cus.insert(pair<int, Customer>(nc, ct_p)); // 客の登録(系内客数)
c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
que.push(nc); // 客の登録(待ち行列)
lq_t = p_time; // 現在の待ち行列長になった時刻
if ((int)que.size() > m_lq)
m_lq = que.size(); // 最大待ち行列長
}
/*
すぐサービスを受けられる場合
*/
else {
int k = -1;
for (int i1 = 0; i1 < s && k < 0; i1++) {
if (sb[i1] == 0) {
Customer ct_p(i1, p_time);
cus.insert(pair<int, Customer>(nc, ct_p)); // 客の登録(系内客数)
k = i1;
sb[k] = nc; // サービスを受けている客番号
st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻
asb -= 1; // 空いている窓口数
}
}
st_s[k] = p_time; // 窓口kがふさがった時刻
if (asb == 0)
asb_t = p_time; // すべての窓口がふさがった時刻
}
}
/*********************************/
/* サービス終了時の処理 */
/* k : サービス終了窓口番号 */
/*********************************/
void Q_base::Service(int k)
{
/*
時間の設定
*/
k -= 1;
p_time = st_e[k]; // 現在時刻
st_e[k] = -1.0; // サービス終了時間
/*
系内客数の処理
*/
c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time; // 現在の系内客数になった時刻
/*
滞在時間の処理
*/
map<int, Customer>::iterator it = cus.find(sb[k]);
double x1 = p_time - (it->second).time;
c_sys += x1; // 滞在時間の累計
if (x1 > m_sys)
m_sys = x1; // 最大滞在時間
cus.erase(sb[k]); // 客の削除(系内客数)
/*
窓口使用時間の処理
*/
asb += 1; // 空いている窓口数
sb[k] = 0; // 窓口kを空き状態にする
c_sb[k] += (p_time - st_s[k]); // 窓口kがふさがっている時間の累計
/*
待ち行列がある場合
*/
if (que.size() > 0) {
asb -= 1; // 開いている窓口数
c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
int n = que.front();
que.pop(); // 客の削除(待ち行列)
lq_t = p_time; // 現在の待ち行列長になった時刻
it = cus.find(n);
x1 = p_time - (it->second).time;
c_wt += x1; // 待ち時間の累計
if (x1 > m_wt)
m_wt = x1; // 最大待ち時間
int k = -1;
for (int i1 = 0; i1 < s && k < 0; i1++) {
if (sb[i1] == 0) {
k = i1;
sb[k] = n; // 窓口kの客番号
st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻
st_s[k] = p_time; // 窓口kがふさがった時刻
(it->second).state = k; // 客の状態変更
}
}
}
/*
待ち行列がない場合
*/
else {
if (asb == 1)
c_asb += (p_time - asb_t); // すべての窓口がふさがっている時間の累計
}
}
/************************/
/* 結果の出力 */
/* (カッコ内は理論値) */
/************************/
void Q_base::Output()
{
double rn = (double)nc;
double rs = (double)s;
double ram = 1.0 / m_a;
double myu = 1.0 / m_s;
double rou = ram / (rs * myu);
double p0, pi;
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));
}
double Lq = pi * rou / (1.0 - rou);
double L = Lq + rs * rou;
double Wq = Lq / ram;
double 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 (int i1 = 0; i1 < s; i1++)
printf(" %d %.3f\n", i1+1, c_sb[i1]/p_time);
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);
}
/****************/
/* main program */
/****************/
int main()
{
int s;
double end, m_a, m_s;
/*
入力データ
*/
printf("窓口の数は? ");
scanf("%d", &s);
printf("シミュレーション終了時間? ");
scanf("%lf", &end);
printf(" 到着時間間隔の平均値は? ");
scanf("%lf", &m_a);
printf(" サービス時間の平均値は? ");
scanf("%lf", &m_s);
/*
システムの定義
*/
Q_base base(s, m_a, m_s, end);
/*
シミュレーションの実行
*/
base.Control();
/*
出力
*/
base.Output();
return 0;
}
//---------------------MT.h---------------------------
// A C-program for MT19937, with initialization improved 2002/1/26.
// Coded by Takuji Nishimura and Makoto Matsumoto.
//
// Before using, initialize the state by using init_genrand(seed)
// or init_by_array(init_key, key_length).
//
// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The names of its contributors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Any feedback is very welcome.
// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
// email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
// The original version of http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c was modified by Takahiro Omi as
// - delete line 47 "#include<stdio.h>"
// - delete line 174 int main(void){...}
// - change N -> MT_N
// - change N -> MT_N
// - change the file name "mt19937ar.c" -> "MT.h"
/*
// Period parameters
#define MT_N 624
#define MT_M 397
#define MATRIX_A 0x9908b0dfUL // constant vector a
#define UPPER_MASK 0x80000000UL // most significant w-r bits
#define LOWER_MASK 0x7fffffffUL // least significant r bits
static unsigned long mt[MT_N]; // the array for the state vector
static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized
// initializes mt[MT_N] with a seed
void init_genrand(unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<MT_N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
// See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
// In the previous versions, MSBs of the seed affect
// only MSBs of the array mt[].
// 2002/01/09 modified by Makoto Matsumoto
mt[mti] &= 0xffffffffUL;
// for >32 bit machines
}
}
// initialize by an array with array-length
// init_key is the array for initializing keys
// key_length is its length
// slight change for C++, 2004/2/26
void init_by_array(unsigned long init_key[], int key_length)
{
int i, j, k;
init_genrand(19650218UL);
i=1; j=0;
k = (MT_N>key_length ? MT_N : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ init_key[j] + j; // non linear
mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines
i++; j++;
if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=MT_N-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i; // non linear
mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines
i++;
if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; }
}
mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array
}
// generates a random number on [0,0xffffffff]-interval
unsigned long genrand_int32(void)
{
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
// mag01[x] = x * MATRIX_A for x=0,1
if (mti >= MT_N) { // generate N words at one time
int kk;
if (mti == MT_N+1) // if init_genrand() has not been called,
init_genrand(5489UL); // a default initial seed is used
for (kk=0;kk<MT_N-MT_M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+MT_M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (;kk<MT_N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(MT_M-MT_N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
// Tempering
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
// generates a random number on [0,0x7fffffff]-interval
long genrand_int31(void)
{
return (long)(genrand_int32()>>1);
}
// generates a random number on [0,1]-real-interval
double genrand_real1(void)
{
return genrand_int32()*(1.0/4294967295.0);
// divided by 2^32-1
}
// generates a random number on [0,1)-real-interval
double genrand_real2(void)
{
return genrand_int32()*(1.0/4294967296.0);
// divided by 2^32
}
// generates a random number on (0,1)-real-interval
double genrand_real3(void)
{
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
// divided by 2^32
}
// generates a random number on [0,1) with 53-bit resolution
double genrand_res53(void)
{
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
return(a*67108864.0+b)*(1.0/9007199254740992.0);
}
// These real versions are due to Isaku Wada, 2002/01/09 added
*/
/******************************/
/* 簡単な待ち行列問題(M/M/s)*/
/* coded by Y.Suganuma */
/******************************/
import java.io.*;
import java.util.*;
public class Test
{
/****************/
/* main program */
/****************/
public static void main(String args[]) throws IOException
{
int s;
double end, m_a, m_s;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
/*
入力データ
*/
System.out.print("窓口の数は? ");
s = Integer.parseInt(in.readLine());
System.out.print("シミュレーション終了時間? ");
end = Double.parseDouble(in.readLine());
System.out.print(" 到着時間間隔の平均値は? ");
m_a = Double.parseDouble(in.readLine());
System.out.print(" サービス時間の平均値は? ");
m_s = Double.parseDouble(in.readLine());
/*
システムの定義
*/
Q_base base = new Q_base(s, m_a, m_s, end);
/*
シミュレーションの実行
*/
base.Control();
/*
出力
*/
base.Output();
}
}
/**********************/
/* クラスQ_baseの定義 */
/**********************/
class Q_base {
private int s; // 窓口の数
private int asb; // 全窓口の空き状況
// =0 : すべての窓口がふさがっている
// =n : n個の窓口が空いている
private int [] sb; // 各窓口の空き状況
// =0 : 窓口は空いている
// >0 : サービスを受けている客番号
private double asb_t; // すべての窓口がふさがった時間
private double c_asb; // すべての窓口がふさがっている時間の累計
private double [] c_sb; // 各窓口がふさがっている時間の累計
private double [] st_e; // 各窓口のサービス終了時間
private double [] st_s; // 各窓口がふさがった時間
private int m_lq; // 最大待ち行列長
private double c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計
private double c_wt; // 待ち時間の累計
private double lq_t; // 現在の待ち行列長になった時間
private double m_wt; // 最大待ち時間
private double c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計
private double c_sys; // 滞在時間の累計
private double m_sys; // 最大滞在時間
private double sc_t; // 現在の系内客数になった時間
private int m_sc; // 最大系内客数
private double m_a; // 到着時間間隔の平均値
private double m_s; // サービス時間の平均値
private double at; // 次の客の到着時間(負の時は,終了)
private double p_time; // 現在時間
private double end; // シミュレーション終了時間
private int nc; // 到着客数カウンタ
private Random rn; // 乱数
private TreeMap <Integer, Customer> cus; // 系内にいる客のリスト
private ArrayDeque <Integer> que; // 待ち行列
/*****************************************/
/* コンストラクタ */
/* s_i : 窓口の数 */
/* m_a_i : 到着時間間隔の平均値 */
/* m_s_i : サービス時間の平均値 */
/* end_i : シミュレーション終了時間 */
/*****************************************/
Q_base (int s_i, double m_a_i, double m_s_i, double end_i)
{
/*
設定
*/
s = s_i;
m_a = m_a_i;
m_s = m_s_i;
end = end_i;
/*
領域の確保
*/
sb = new int [s];
c_sb = new double [s];
st_e = new double [s];
st_s = new double [s];
for (int i1 = 0; i1 < s; i1++) {
sb[i1] = 0;
c_sb[i1] = 0.0;
}
cus = new TreeMap <Integer, Customer> ();
que = new ArrayDeque <Integer> ();
/*
初期設定
*/
p_time = 0.0;
nc = 0;
asb = s;
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;
/*
乱数の初期設定
*/
rn = new Random();
/*
最初の客の到着時間の設定
*/
at = p_time + Next_at();
}
/**********************************/
/* 次の客の到着までの時間の発生 */
/**********************************/
double Next_at()
{
return -m_a * Math.log(rn.nextDouble());
}
/************************/
/* サービス時間の発生 */
/************************/
double Next_sv()
{
return -m_s * Math.log(rn.nextDouble());
}
/**************/
/* 全体の制御 */
/**************/
void Control()
{
int sw = 0;
while (sw > -2) {
sw = Next(); // 次の処理の選択
if (sw == -1)
sw = End_o_s(); // シミュレーションの終了
else {
if (sw == 0)
Arrive(); // 客の到着処理
else
Service(sw); // サービスの終了
}
}
}
/**************************************************/
/* 次の処理の決定 */
/* return : =-1 : シミュレーションの終了 */
/* =0 : 客の到着処理 */
/* =i : i番目の窓口のサービス終了 */
/**************************************************/
int Next()
{
int sw = -1;
double t = end; // シミュレーション終了時刻で初期設定
// 次の客の到着時刻
if (at >= 0.0 && at < t) {
sw = 0;
t = at;
}
// サービス終了時刻
for (int i1 = 0; i1 < s; i1++) {
if (sb[i1] > 0 && st_e[i1] <= t) {
sw = i1 + 1;
t = st_e[i1]; // 窓口i1のサービス終了時刻
}
}
return sw;
}
/**********************************/
/* 終了処理 */
/* return : =-1 : 終了前処理 */
/* =-2 : 実際の終了 */
/**********************************/
int End_o_s()
{
int sw = -2;
p_time = end; // 現在時刻
at = -1.0; // 次の客の到着時刻
for (int i1 = 0; i1 < s; i1++) {
if (sb[i1] > 0) { // サービス中の客はいるか?
if (sw == -2) {
sw = -1;
end = st_e[i1]; // 窓口i1のサービス終了時刻
}
else {
if (st_e[i1] > end)
end = st_e[i1]; // 窓口i1のサービス終了時刻
}
}
}
return sw;
}
/****************************/
/* 客の到着処理 */
/* ct : 客リストの先頭 */
/****************************/
void Arrive()
{
/*
客数の増加と次の客の到着時刻の設定
*/
nc += 1; // 到着客数カウンタ
p_time = at; // 現在時刻
at = p_time + Next_at(); // 次の客の到着時刻
if (at >= end)
at = -1.0;
/*
系内客数の処理
*/
c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time; // 現在の系内客数になった時刻
if (cus.size()+1 > m_sc)
m_sc = cus.size() + 1; // 最大系内客数
/*
窓口に空きがない場合
*/
if (asb == 0) {
Customer ct_p = new Customer(-1, p_time);
cus.put(new Integer(nc), ct_p); // 客の登録(系内客数)
c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
que.add(new Integer(nc)); // 客の登録(待ち行列)
lq_t = p_time; // 現在の待ち行列長になった時刻
if (que.size() > m_lq)
m_lq = que.size(); // 最大待ち行列長
}
/*
すぐサービスを受けられる場合
*/
else {
int k = -1;
for (int i1 = 0; i1 < s && k < 0; i1++) {
if (sb[i1] == 0) {
Customer ct_p = new Customer(i1, p_time);
cus.put(new Integer(nc), ct_p); // 客の登録(系内客数)
k = i1;
sb[k] = nc; // サービスを受けている客番号
st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻
asb -= 1; // 空いている窓口数
}
}
st_s[k] = p_time; // 窓口kがふさがった時刻
if (asb == 0)
asb_t = p_time; // すべての窓口がふさがった時刻
}
}
/*********************************/
/* サービス終了時の処理 */
/* k : サービス終了窓口番号 */
/* ct : 客リストの先頭 */
/*********************************/
void Service(int k)
{
/*
時間の設定
*/
k -= 1;
p_time = st_e[k]; // 現在時刻
st_e[k] = -1.0; // サービス終了時間
/*
系内客数の処理
*/
c_sc_t += cus.size() * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time; // 現在の系内客数になった時刻
/*
滞在時間の処理
*/
Customer ct = cus.get(new Integer(sb[k]));
double x1 = p_time - ct.time;
c_sys += x1; // 滞在時間の累計
if (x1 > m_sys)
m_sys = x1; // 最大滞在時間
cus.remove(new Integer(sb[k])); // 客の削除(系内客数)
/*
窓口使用時間の処理
*/
asb += 1; // 空いている窓口数
sb[k] = 0; // 窓口kを空き状態にする
c_sb[k] += (p_time - st_s[k]); // 窓口kがふさがっている時間の累計
/*
待ち行列がある場合
*/
if (que.size() > 0) {
asb -= 1; // 開いている窓口数
c_lq_t += que.size() * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
int n = que.pollFirst().intValue(); // 客の削除(待ち行列)
lq_t = p_time; // 現在の待ち行列長になった時刻
ct = cus.get(new Integer(n));
x1 = p_time - ct.time;
c_wt += x1; // 待ち時間の累計
if (x1 > m_wt)
m_wt = x1; // 最大待ち時間
k = -1;
for (int i1 = 0; i1 < s && k < 0; i1++) {
if (sb[i1] == 0) {
k = i1;
sb[k] = n; // 窓口kの客番号
st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻
st_s[k] = p_time; // 窓口kがふさがった時刻
ct.state = k; // 客の状態変更
}
}
}
/*
待ち行列がない場合
*/
else {
if (asb == 1)
c_asb += (p_time - asb_t); // すべての窓口がふさがっている時間の累計
}
}
/************************/
/* 結果の出力 */
/* (カッコ内は理論値) */
/************************/
void Output()
{
double rn = (double)nc;
double rs = (double)s;
double ram = 1.0 / m_a;
double myu = 1.0 / m_s;
double rou = ram / (rs * myu);
double p0, pi;
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));
}
double Lq = pi * rou / (1.0 - rou);
double L = Lq + rs * rou;
double Wq = Lq / ram;
double W = Wq + 1.0 / myu;
System.out.printf("シミュレーション終了時間=%.3f 客数=%d ρ=%.3f p0=%.3f\n",
p_time, nc, rou, p0);
System.out.printf(" すべての窓口が塞がっている割合=%.3f (%.3f)\n",
c_asb/p_time, pi);
System.out.printf(" 各窓口が塞がっている割合\n");
for (int i1 = 0; i1 < s; i1++)
System.out.printf(" %d %.3f\n", i1+1, c_sb[i1]/p_time);
System.out.printf(" 平均待ち行列長=%.3f (%.3f) 最大待ち行列長=%d\n",
c_lq_t/p_time, Lq, m_lq);
System.out.printf(" 平均系内客数 =%.3f (%.3f) 最大系内客数 =%d\n",
c_sc_t/p_time, L, m_sc);
System.out.printf(" 平均待ち時間 =%.3f (%.3f) 最大待ち時間 =%.3f\n",
c_wt/rn, Wq, m_wt);
System.out.printf(" 平均滞在時間 =%.3f (%.3f) 最大滞在時間 =%.3f\n",
c_sys/rn, W, m_sys);
}
}
/************************/
/* クラスCustomerの定義 */
/************************/
class Customer
{
double time; // 到着時刻
int state; // 客の状態
// =-1 : 待ち行列に入っている
// >=0 : サービスを受けている窓口番号
/*******************/
/* コンストラクタ */
/* n : 客番号 */
/* s : 状態 */
/*******************/
Customer (int s, double t)
{
time = t;
state = s;
}
}
test.html
<!DOCTYPE HTML> <HTML> <HEAD> <TITLE>簡単な待ち行列</TITLE> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8"> <SCRIPT TYPE="text/javascript" SRC="simple.js"></SCRIPT> </HEAD> <BODY STYLE="font-size: 130%; background-color: #eeffee;"> <H2 STYLE="text-align:center"><B>簡単な待ち行列</B></H2> <DIV STYLE="text-align:center"> 窓口の数:<INPUT ID="s" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="2"> シミュレーション時間:<INPUT ID="end" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="10000"><BR><BR> 平均到着時間間隔:<INPUT ID="m_a" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="5"> 平均サービス時間:<INPUT ID="m_s" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="4"><BR><BR> <BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">実行</BUTTON> 結果は下<BR> <TEXTAREA ID="res" COLS="60" ROWS="15" STYLE="font-size: 100%"></TEXTAREA> </DIV> </BODY> </HTML>
simple.js
/******************************/
/* 簡単な待ち行列問題(M/M/s)*/
/* coded by Y.Suganuma */
/******************************/
base = null;
cus = new Array();
que = new Array();
/****************/
/* main program */
/****************/
function main()
{
cus.splice(0); // 系内にいる客のリスト
que.splice(0); // Queueオブジェクトリスト
/*
入力データ
*/
let s = parseInt(document.getElementById("s").value); // 窓口の数
let end = parseFloat(document.getElementById("end").value); // シミュレーション終了時間
let m_a = parseFloat(document.getElementById("m_a").value); // 平均到着時間間隔
let m_s = parseFloat(document.getElementById("m_s").value); // 平均サービス時間
/*
システムの定義
*/
base = new Q_base(s, m_a, m_s, end);
base.at = base.p_time + base.Next_at(); // 最初の客の到着時間
/*
シミュレーションの実行
*/
base.Control();
/*
出力
*/
base.Output();
}
/******************************/
/* Customerオブジェクトの定義 */
/******************************/
function Customer(n, s, t)
{
this.time = t; // 到着時刻
this.num = n; // 客番号
this.state = s; // 客の状態
// =-1 : 待ち行列に入っている
// >=0 : サービスを受けている窓口番号
return this;
}
/**********************/
/* Q_baseオブジェクト */
/**********************/
function Q_base(s, m_a, m_s, end) {
/*
入力データの設定
*/
this.s = s; // 窓口の数
this.m_a = m_a; // 到着時間間隔の平均値
this.m_s = m_s; // サービス時間の平均値
this.end = end; // シミュレーション終了時刻
/*
初期設定
*/
this.asb = s; // 全窓口の空き状況
// =0 : すべての窓口がふさがっている
// =n : n個の窓口が空いている
this.sb = new Array(); // 各窓口の空き状況
// =0 : 窓口は空いている
// >0 : サービスを受けている客番号
this.c_sb = new Array(); // 各窓口がふさがっている時間の累計
this.st_e = new Array(); // 各窓口のサービス終了時刻
this.st_s = new Array(); // 各窓口がふさがった時刻
for (let i1 = 0; i1 < this.s; i1++) {
this.sb[i1] = 0;
this.c_sb[i1] = 0.0;
}
this.asb_t; // すべての窓口がふさがった時刻
this.c_asb = 0.0; // すべての窓口がふさがっている時間の累計
this.m_lq = 0; // 最大待ち行列長
this.c_lq_t = 0.0; // 待ち行列長にその長さが継続した時間を乗じた値の累計
this.c_wt = 0.0; // 待ち時間の累計
this.lq_t = 0.0; // 現在の待ち行列長になった時刻
this.m_wt = 0.0; // 最大待ち時間
this.c_sc_t = 0.0; // 系内客数にその数が継続した時間を乗じた値の累計
this.c_sys = 0.0; // 滞在時間の累計
this.m_sys = 0.0; // 最大滞在時間
this.sc_t = 0.0; // 現在の系内客数になった時刻
this.m_sc = 0; // 最大系内客数
this.at; // 次の客の到着時刻(負の時は,終了)
this.p_time = 0.0; // 現在時刻
this.nc = 0; // 到着客数カウンタ
return this;
}
/********************************/
/* 次の客の到着までの時間の発生 */
/********************************/
Q_base.prototype.Next_at = function()
{
return -base.m_a * Math.log(Math.random());
}
/**********************/
/* サービス時間の発生 */
/**********************/
Q_base.prototype.Next_sv = function()
{
return -base.m_s * Math.log(Math.random());
}
/**************/
/* 全体の制御 */
/**************/
Q_base.prototype.Control = function()
{
let sw = 0;
while (sw > -2) {
sw = base.Next(); // 次の処理の選択
if (sw == -1)
sw = base.End_o_s(); // シミュレーションの終了
else {
if (sw == 0)
base.Arrive(); // 客の到着処理
else
base.Service(sw); // サービスの終了
}
}
}
/**************************************************/
/* 次の処理の決定 */
/* return : =-1 : シミュレーションの終了 */
/* =0 : 客の到着処理 */
/* =i : i番目の窓口のサービス終了 */
/**************************************************/
Q_base.prototype.Next = function()
{
let sw = -1;
let t = base.end; // シミュレーション終了時刻で初期設定
// 次の客の到着時刻
if (base.at >= 0.0 && base.at < t) {
sw = 0;
t = base.at;
}
// サービス終了時刻
for (let i1 = 0; i1 < base.s; i1++) {
if (base.sb[i1] > 0 && base.st_e[i1] <= t) {
sw = i1 + 1;
t = base.st_e[i1]; // 窓口i1のサービス終了時刻
}
}
return sw;
}
/**********************************/
/* 終了処理 */
/* return : =-1 : 終了前処理 */
/* =-2 : 実際の終了 */
/**********************************/
Q_base.prototype.End_o_s = function()
{
let sw = -2;
base.p_time = base.end; // 現在時刻
base.at = -1.0; // 次の客の到着時刻
for (let i1 = 0; i1 < base.s; i1++) {
if (base.sb[i1] > 0) { // サービス中の客はいるか?
if (sw == -2) {
sw = -1;
base.end = base.st_e[i1]; // 窓口i1のサービス終了時刻
}
else {
if (base.st_e[i1] > base.end)
base.end = base.st_e[i1]; // 窓口i1のサービス終了時刻
}
}
}
return sw;
}
/****************/
/* 客の到着処理 */
/****************/
Q_base.prototype.Arrive = function()
{
/*
客数の増加と次の客の到着時刻の設定
*/
base.nc += 1; // 到着客数カウンタ
base.p_time = base.at; // 現在時刻
base.at = base.p_time + base.Next_at(); // 次の客の到着時刻
if (base.at >= base.end)
base.at = -1.0;
/*
系内客数の処理
*/
base.c_sc_t += cus.length * (base.p_time - base.sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
base.sc_t = base.p_time; // 現在の系内客数になった時刻
if (cus.length+1 > base.m_sc)
base.m_sc = cus.length + 1; // 最大系内客数
/*
窓口に空きがない場合
*/
if (base.asb == 0) {
let ct = new Customer(base.nc, -1, base.p_time);
cus.push(ct); // 客の登録(系内客数)
base.c_lq_t += que.length * (base.p_time - base.lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
que.push(base.nc); // 客の登録(待ち行列)
base.lq_t = base.p_time; // 現在の待ち行列長になった時刻
if (que.length > base.m_lq)
base.m_lq = que.length; // 最大待ち行列長
}
/*
すぐサービスを受けられる場合
*/
else {
let k = -1;
for (let i1 = 0; i1 < base.s && k < 0; i1++) {
if (base.sb[i1] == 0) {
let ct = new Customer(base.nc, i1, base.p_time);
cus.push(ct); // 客の登録(系内客数)
k = i1;
base.sb[k] = base.nc; // サービスを受けている客番号
base.st_e[k] = base.p_time + base.Next_sv(); // 窓口kのサービス終了時刻
base.asb -= 1; // 空いている窓口数
}
}
base.st_s[k] = base.p_time; // 窓口kがふさがった時刻
if (base.asb == 0)
base.asb_t = base.p_time; // すべての窓口がふさがった時刻
}
}
/*********************************/
/* サービス終了時の処理 */
/* k : サービス終了窓口番号 */
/*********************************/
Q_base.prototype.Service = function(k)
{
/*
時間の設定
*/
k -= 1;
base.p_time = base.st_e[k]; // 現在時刻
base.st_e[k] = -1.0; // サービス終了時間
/*
系内客数の処理
*/
base.c_sc_t += cus.length * (base.p_time - base.sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
base.sc_t = base.p_time; // 現在の系内客数になった時刻
/*
滞在時間の処理
*/
let n = base.Search(base.sb[k]);
let x1 = base.p_time - cus[n].time;
base.c_sys += x1; // 滞在時間の累計
if (x1 > base.m_sys)
base.m_sys = x1; // 最大滞在時間
cus.splice(n, 1); // 客の削除(系内客数)
/*
窓口使用時間の処理
*/
base.asb += 1; // 空いている窓口数
base.sb[k] = 0; // 窓口kを空き状態にする
base.c_sb[k] += (base.p_time - base.st_s[k]); // 窓口kがふさがっている時間の累計
/*
待ち行列がある場合
*/
if (que.length > 0) {
base.asb -= 1; // 開いている窓口数
base.c_lq_t += que.length * (base.p_time - base.lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
n = que.shift(); // 客の削除(待ち行列)
base.lq_t = base.p_time; // 現在の待ち行列長になった時刻
let m = base.Search(n);
x1 = base.p_time - cus[m].time;
base.c_wt += x1; // 待ち時間の累計
if (x1 > base.m_wt)
base.m_wt = x1; // 最大待ち時間
let k = -1;
for (let i1 = 0; i1 < base.s && k < 0; i1++) {
if (base.sb[i1] == 0) {
k = i1;
base.sb[k] = n; // 窓口kの客番号
base.st_e[k] = base.p_time + base.Next_sv(); // 窓口kのサービス終了時刻
base.st_s[k] = base.p_time; // 窓口kがふさがった時刻
cus[m].state = k; // 客の状態変更
}
}
}
/*
待ち行列がない場合
*/
else {
if (base.asb == 1)
base.c_asb += (base.p_time - base.asb_t); // すべての窓口がふさがっている時間の累計
}
}
/****************************/
/* 指定した客の配列上の位置 */
/* nm : 客番号 */
/* return : 要素番号 */
/****************************/
Q_base.prototype.Search = function(nm)
{
let n = -1;
for (let i1 = 0; i1 < cus.length; i1++) {
if (cus[i1].num == nm) {
n = i1;
break;
}
}
return n;
}
/************************/
/* 結果の出力 */
/* (カッコ内は理論値) */
/************************/
Q_base.prototype.Output = function()
{
let ram = 1.0 / base.m_a;
let myu = 1.0 / base.m_s;
let rou = ram / (base.s * myu);
let pi, p0;
if (base.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));
}
let Lq = pi * rou / (1.0 - rou);
let L = Lq + base.s * rou;
let Wq = Lq / ram;
let W = Wq + 1.0 / myu;
let str = "シミュレーション時間=" + Math.round(base.p_time) + " 客数=" + base.nc + " ρ=" + Math.round(1000*rou)/1000 + " p0=" + Math.round(1000*p0)/1000 + "\n";
str += " すべての窓口が塞がっている割合=" + Math.round(1000*base.c_asb/base.p_time)/1000 + " (" + Math.round(1000*pi)/1000 + ")\n";
str += " 各窓口が塞がっている割合\n";
for (let i1 = 0; i1 < base.s; i1++)
str += " " + (i1+1) + " " + Math.round(1000*base.c_sb[i1]/base.p_time)/1000 + "\n";
str += " 平均待ち行列長=" + Math.round(1000*base.c_lq_t/base.p_time)/1000 + " (" + Math.round(1000*Lq)/1000 + ") 最大待ち行列長=" + base.m_lq + "\n";
str += " 平均系内客数 =" + Math.round(1000*base.c_sc_t/base.p_time)/1000 + " (" + Math.round(1000*L)/1000 + ") 最大系内客数 =" + base.m_sc + "\n";
str += " 平均待ち時間 =" + Math.round(1000*base.c_wt/base.nc)/1000 + " (" + Math.round(1000*Wq)/1000 + ") 最大待ち時間 =" + Math.round(base.m_wt) + "\n";
str += " 平均滞在時間 =" + Math.round(1000*base.c_sys/base.nc)/1000 + " (" + Math.round(1000*W)/1000 + ") 最大滞在時間 =" + Math.round(base.m_sys) + "\n";
document.getElementById("res").value = str;
}
<?php
/******************************/
/* 簡単な待ち行列問題(M/M/s)*/
/* coded by Y.Suganuma */
/******************************/
/************************/
/* クラスCustomerの定義 */
/************************/
class Customer
{
public $time; // 到着時刻
public $state; // 客の状態
// =-1 : 待ち行列に入っている
// >=0 : サービスを受けている窓口番号
/*********************/
/* コンストラクタ */
/* s : 状態 */
/* t : 到着時刻 */
/*******************************/
function Customer($s, $t)
{
$this->time = $t;
$this->state = $s;
}
}
/**********************/
/* クラスQ_baseの定義 */
/**********************/
class Q_base {
private $s; // 窓口の数
private $asb; // 全窓口の空き状況
// =0 : すべての窓口がふさがっている
// =n : n個の窓口が空いている
private $sb; // 各窓口の空き状況
// =0 : 窓口は空いている
// >0 : サービスを受けている客番号
private $asb_t; // すべての窓口がふさがった時刻
private $c_asb; // すべての窓口がふさがっている時間の累計
private $c_sb; // 各窓口がふさがっている時間の累計
private $st_e; // 各窓口のサービス終了時刻
private $st_s; // 各窓口がふさがった時刻
private $m_lq; // 最大待ち行列長
private $c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計
private $c_wt; // 待ち時間の累計
private $lq_t; // 現在の待ち行列長になった時刻
private $m_wt; // 最大待ち時間
private $c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計
private $c_sys; // 滞在時間の累計
private $m_sys; // 最大滞在時間
private $sc_t; // 現在の系内客数になった時刻
private $m_sc; // 最大系内客数
private $m_a; // 到着時間間隔の平均値
private $m_s; // サービス時間の平均値
private $at; // 次の客の到着時刻(負の時は,終了)
private $p_time; // 現在時刻
private $end; // シミュレーション終了時刻
private $nc; // 到着客数カウンタ
private $cus; // 系内にいる客のリスト
private $que; // 待ち行列
/*****************************************/
/* コンストラクタ */
/* s_i : 窓口の数 */
/* m_a_i : 到着時間間隔の平均値 */
/* m_s_i : サービス時間の平均値 */
/* end_i : シミュレーション終了時刻 */
/*****************************************/
function Q_base ($s_i, $m_a_i, $m_s_i, $end_i)
{
/*
設定
*/
$this->s = $s_i;
$this->m_a = $m_a_i;
$this->m_s = $m_s_i;
$this->end = $end_i;
/*
領域の確保
*/
$this->sb = array();
$this->c_sb = array();
$this->st_e = array();
$this->st_s = array();
$this->cus = array();
$this->que = array();
for ($i1 = 0; $i1 < $this->s; $i1++) {
$this->sb[$i1] = 0;
$this->c_sb[$i1] = 0.0;
}
/*
初期設定
*/
$this->p_time = 0.0;
$this->nc = 0;
$this->asb = $this->s;
$this->m_lq = 0;
$this->m_sc = 0;
$this->c_asb = 0.0;
$this->c_wt = 0.0;
$this->m_wt = 0.0;
$this->c_lq_t = 0.0;
$this->lq_t = 0.0;
$this->m_sys = 0.0;
$this->c_sys = 0.0;
$this->c_sc_t = 0.0;
$this->sc_t = 0.0;
/*
乱数の初期設定
*/
mt_srand();
/*
最初の客の到着時刻の設定
*/
$this->at = $this->p_time + $this->Next_at();
}
/********************************/
/* 次の客の到着までの時間の発生 */
/********************************/
function Next_at()
{
return -$this->m_a * log(mt_rand() / mt_getrandmax());
}
/************************/
/* サービス時間の発生 */
/************************/
function Next_sv()
{
return -$this->m_s * log(mt_rand() / mt_getrandmax());
}
/**************/
/* 全体の制御 */
/**************/
function Control()
{
$sw = 0;
while ($sw > -2) {
$sw = $this->Next(); // 次の処理の選択
if ($sw == -1)
$sw = $this->End_o_s(); // シミュレーションの終了
else {
if ($sw == 0)
$this->Arrive(); // 客の到着処理
else
$this->Service($sw); // サービスの終了
}
}
}
/**************************************************/
/* 次の処理の決定 */
/* return : =-1 : シミュレーションの終了 */
/* =0 : 客の到着処理 */
/* =i : i番目の窓口のサービス終了 */
/**************************************************/
function Next()
{
$sw = -1;
$t = $this->end; // シミュレーション終了時刻で初期設定
// 次の客の到着時刻
if ($this->at >= 0.0 && $this->at < $t) {
$sw = 0;
$t = $this->at;
}
// サービス終了時刻
for ($i1 = 0; $i1 < $this->s; $i1++) {
if ($this->sb[$i1] > 0 && $this->st_e[$i1] <= $t) {
$sw = $i1 + 1;
$t = $this->st_e[$i1]; // 窓口i1のサービス終了時刻
}
}
return $sw;
}
/**********************************/
/* 終了処理 */
/* return : =-1 : 終了前処理 */
/* =-2 : 実際の終了 */
/**********************************/
function End_o_s()
{
$sw = -2;
$this->p_time = $this->end; // 現在時刻
$this->at = -1.0; // 次の客の到着時刻
for ($i1 = 0; $i1 < $this->s; $i1++) {
if ($this->sb[$i1] > 0) { // サービス中の客はいるか?
if ($sw == -2) {
$sw = -1;
$this->end = $this->st_e[$i1]; // 窓口i1のサービス終了時刻
}
else {
if ($this->st_e[$i1] > $this->end)
$this->end = $this->st_e[$i1]; // 窓口i1のサービス終了時刻
}
}
}
return $sw;
}
/****************/
/* 客の到着処理 */
/****************/
function Arrive()
{
/*
客数の増加と次の客の到着時刻の設定
*/
$this->nc += 1; // 到着客数カウンタ
$this->p_time = $this->at; // 現在時刻
$this->at = $this->p_time + $this->Next_at(); // 次の客の到着時刻
if ($this->at >= $this->end)
$this->at = -1.0;
/*
系内客数の処理
*/
$this->c_sc_t += (count($this->cus) * ($this->p_time - $this->sc_t)); // 系内客数にその数が継続した時間を乗じた値の累計
$this->sc_t = $this->p_time; // 現在の系内客数になった時刻
if (count($this->cus)+1 > $this->m_sc)
$this->m_sc = count($this->cus) + 1; // 最大系内客数
/*
窓口に空きがない場合
*/
if ($this->asb == 0) {
$ct_p = new Customer(-1, $this->p_time);
$this->cus['no'.strval($this->nc)] = $ct_p; // 客の登録(系内客数)
$this->c_lq_t += count($this->que) * ($this->p_time - $this->lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
array_push($this->que, $this->nc); // 客の登録(待ち行列)
$this->lq_t = $this->p_time; // 現在の待ち行列長になった時刻
if (count($this->que) > $this->m_lq)
$this->m_lq = count($this->que); // 最大待ち行列長
}
/*
すぐサービスを受けられる場合
*/
else {
$k = -1;
for ($i1 = 0; $i1 < $this->s && $k < 0; $i1++) {
if ($this->sb[$i1] == 0) {
$ct_p = new Customer($i1, $this->p_time);
$this->cus['no'.strval($this->nc)] = $ct_p; // 客の登録(系内客数)
$k = $i1;
$this->sb[$k] = $this->nc; // サービスを受けている客番号
$this->st_e[$k] = $this->p_time + $this->Next_sv(); // 窓口kのサービス終了時刻
$this->asb -= 1; // 空いている窓口数
}
}
$this->st_s[$k] = $this->p_time; // 窓口kがふさがった時刻
if ($this->asb == 0)
$this->asb_t = $this->p_time; // すべての窓口がふさがった時刻
}
}
/*********************************/
/* サービス終了時の処理 */
/* k : サービス終了窓口番号 */
/*********************************/
function Service($k)
{
/*
時間の設定
*/
$k -= 1;
$this->p_time = $this->st_e[$k]; // 現在時刻
$this->st_e[$k] = -1.0; // サービス終了時間
/*
系内客数の処理
*/
$this->c_sc_t += (count($this->cus) * ($this->p_time - $this->sc_t)); // 系内客数にその数が継続した時間を乗じた値の累計
$this->sc_t = $this->p_time; // 現在の系内客数になった時刻
/*
滞在時間の処理
*/
$it = $this->cus['no'.strval($this->sb[$k])];
$x1 = $this->p_time - $it->time;
$this->c_sys += $x1; // 滞在時間の累計
if ($x1 > $this->m_sys)
$this->m_sys = $x1; // 最大滞在時間
unset($this->cus['no'.strval($this->sb[$k])]); // 客の削除(系内客数)
/*
窓口使用時間の処理
*/
$this->asb += 1; // 空いている窓口数
$this->sb[$k] = 0; // 窓口kを空き状態にする
$this->c_sb[$k] += ($this->p_time - $this->st_s[$k]); // 窓口kがふさがっている時間の累計
/*
待ち行列がある場合
*/
if (count($this->que) > 0) {
$this->asb -= 1; // 開いている窓口数
$this->c_lq_t += count($this->que) * ($this->p_time - $this->lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
$n = array_shift($this->que); // 客の削除(待ち行列)
$this->lq_t = $this->p_time; // 現在の待ち行列長になった時刻
$it = $this->cus['no'.strval($n)];
$x1 = $this->p_time - $it->time;
$this->c_wt += $x1; // 待ち時間の累計
if ($x1 > $this->m_wt)
$this->m_wt = $x1; // 最大待ち時間
$k = -1;
for ($i1 = 0; $i1 < $this->s && $k < 0; $i1++) {
if ($this->sb[$i1] == 0) {
$k = $i1;
$this->sb[$k] = $n; // 窓口kの客番号
$this->st_e[$k] = $this->p_time + $this->Next_sv(); // 窓口kのサービス終了時刻
$this->st_s[$k] = $this->p_time; // 窓口kがふさがった時刻
$it->state = $k; // 客の状態変更
}
}
}
/*
待ち行列がない場合
*/
else {
if ($this->asb == 1)
$this->c_asb += ($this->p_time - $this->asb_t); // すべての窓口がふさがっている時間の累計
}
}
/************************/
/* 結果の出力 */
/* (カッコ内は理論値) */
/************************/
function Output()
{
$rn = floatval($this->nc);
$rs = floatval($this->s);
$ram = 1.0 / $this->m_a;
$myu = 1.0 / $this->m_s;
$rou = $ram / ($rs * $myu);
if ($this->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));
}
$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",
$this->p_time, $this->nc, $rou, $p0);
printf(" すべての窓口が塞がっている割合=%.3f (%.3f)\n",
$this->c_asb/$this->p_time, $pi);
printf(" 各窓口が塞がっている割合\n");
for ($i1 = 0; $i1 < $this->s; $i1++)
printf(" %d %.3f\n", $i1+1, $this->c_sb[$i1]/$this->p_time);
printf(" 平均待ち行列長=%.3f (%.3f) 最大待ち行列長=%d\n",
$this->c_lq_t/$this->p_time, $Lq, $this->m_lq);
printf(" 平均系内客数 =%.3f (%.3f) 最大系内客数 =%d\n",
$this->c_sc_t/$this->p_time, $L, $this->m_sc);
printf(" 平均待ち時間 =%.3f (%.3f) 最大待ち時間 =%.3f\n",
$this->c_wt/$rn, $Wq, $this->m_wt);
printf(" 平均滞在時間 =%.3f (%.3f) 最大滞在時間 =%.3f\n",
$this->c_sys/$rn, $W, $this->m_sys);
}
}
/****************/
/* main program */
/****************/
/*
入力データ
*/
printf("窓口の数は? ");
fscanf(STDIN, "%d", $s);
printf("シミュレーション終了時間? ");
fscanf(STDIN, "%lf", $end);
printf(" 到着時間間隔の平均値は? ");
fscanf(STDIN, "%lf", $m_a);
printf(" サービス時間の平均値は? ");
fscanf(STDIN, "%lf", $m_s);
/*
システムの定義
*/
$base = new Q_base($s, $m_a, $m_s, $end);
/*
シミュレーションの実行
*/
$base->Control();
/*
出力
*/
$base->Output();
?>
#############################
# 簡単な待ち行列問題(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()
# -*- coding: UTF-8 -*-
import numpy as np
import sys
from math import *
from random import *
########################
# クラスCustomerの定義
########################
class Customer :
#####################
# コンストラクタ
# s : 状態
# t : 到着時刻
#####################
def __init__(self, s, t) :
self.state = s # 客の状態
# =-1 : 待ち行列に入っている
# >=0 : サービスを受けている窓口番号
self.time = t # 到着時刻
########################
# クラスQ_baseの定義
########################
class Q_base :
#########################################
# コンストラクタ
# s_i : 窓口の数
# m_a_i : 到着時間間隔の平均値
# m_s_i : サービス時間の平均値
# end_i : シミュレーション終了時刻
#########################################
def __init__(self, s_i, m_a_i, m_s_i, end_i) :
# 設定
self.s = s_i # 窓口の数
self.m_a = m_a_i # 到着時間間隔の平均値
self.m_s = m_s_i # サービス時間の平均値
self.end = end_i # シミュレーション終了時刻
# 領域の確保
self.sb = np.zeros(self.s, np.int) # 各窓口の空き状況
# =0 : 窓口は空いている
# >0 : サービスを受けている客番号
self.c_sb = np.zeros(self.s, np.float) # 各窓口がふさがっている時間の累計
self.st_e = np.empty(self.s, np.float) # 各窓口のサービス終了時刻
self.st_s = np.empty(self.s, np.float) # 各窓口がふさがった時刻
# 初期設定
self.p_time = 0.0 # 現在時刻
self.nc = 0 # 到着客数カウンタ
self.asb = self.s # 全窓口の空き状況
# =0 : すべての窓口がふさがっている
# =n : n個の窓口が空いている
self.m_lq = 0 # 最大待ち行列長
self.m_sc = 0 # 最大系内客数
self.c_asb = 0.0 # すべての窓口がふさがっている時間の累計
self.c_wt = 0.0 # 待ち時間の累計
self.m_wt = 0.0 # 最大待ち時間
self.c_lq_t = 0.0 # 待ち行列長にその長さが継続した時間を乗じた値の累計
self.lq_t = 0.0 # 現在の待ち行列長になった時刻
self.m_sys = 0.0 # 最大滞在時間
self.c_sys = 0.0 # 滞在時間の累計
self.c_sc_t = 0.0 # 系内客数にその数が継続した時間を乗じた値の累計
self.sc_t = 0.0 # 現在の系内客数になった時刻
self.asb_t = 0.0 # すべての窓口がふさがった時刻
self.cus = dict() # 系内にいる客のリスト
self.que = [] # 待ち行列
# 最初の客の到着時刻の設定
self.at = self.p_time + self.Next_at() # 次の客の到着時刻(負の時は,終了)
################################
# 次の客の到着までの時間の発生
################################
def Next_at(self) :
# return -self.m_a * log(random())
return expovariate(1.0 / self.m_a)
#####################
# サービス時間の発生
#####################
def Next_sv(self) :
# return -self.m_s * log(random())-4.0 * log(random())
return expovariate(1.0 / self.m_s)
##############
# 全体の制御
##############
def Control(self) :
sw = 0
while sw > -2 :
sw = self.Next() # 次の処理の選択
if sw == -1 :
sw = self.End_o_s() # シミュレーションの終了
else :
if sw == 0 :
self.Arrive() # 客の到着処理
else :
self.Service(sw) # サービスの終了
##################################################
# 次の処理の決定
# return : =-1 : シミュレーションの終了
# =0 : 客の到着処理
# =i : i番目の窓口のサービス終了
##################################################
def Next(self) :
sw = -1
t = self.end # シミュレーション終了時刻で初期設定
# 次の客の到着時刻
if self.at >= 0.0 and self.at < t :
sw = 0
t = self.at
# サービス終了時刻
for i1 in range(0, self.s) :
if self.sb[i1] > 0 and self.st_e[i1] <= t :
sw = i1 + 1
t = self.st_e[i1] # 窓口i1のサービス終了時刻
return sw
##################################
# 終了処理
# return : =-1 : 終了前処理
# =-2 : 実際の終了
##################################
def End_o_s(self) :
sw = -2
self.p_time = self.end # 現在時刻
self.at = -1.0 # 次の客の到着時刻
for i1 in range(0, self.s) :
if self.sb[i1] > 0 : # サービス中の客はいるか?
if sw == -2 :
sw = -1
self.end = self.st_e[i1] # 窓口i1のサービス終了時刻
else :
if self.st_e[i1] > self.end :
self.end = self.st_e[i1] # 窓口i1のサービス終了時刻
return sw
################
# 客の到着処理
################
def Arrive(self) :
# 客数の増加と次の客の到着時刻の設定
self.nc += 1 # 到着客数カウンタ
self.p_time = self.at # 現在時刻
self.at = self.p_time + self.Next_at() # 次の客の到着時刻
if self.at >= self.end :
self.at = -1.0
# 系内客数の処理
self.c_sc_t += len(self.cus) * (self.p_time - self.sc_t) # 系内客数にその数が継続した時間を乗じた値の累計
self.sc_t = self.p_time # 現在の系内客数になった時刻
if len(self.cus)+1 > self.m_sc :
self.m_sc = len(self.cus) + 1 # 最大系内客数
# 窓口に空きがない場合
if self.asb == 0 :
ct_p = Customer(-1, self.p_time)
self.cus[self.nc] = ct_p # 客の登録(系内客数)
self.c_lq_t += len(self.que) * (self.p_time - self.lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計
self.que.append(self.nc) # 客の登録(待ち行列)
self.lq_t = self.p_time # 現在の待ち行列長になった時刻
if len(self.que) > self.m_lq :
self.m_lq = len(self.que) # 最大待ち行列長
# すぐサービスを受けられる場合
else :
k = -1
for i1 in range(0, self.s) :
if self.sb[i1] == 0 :
ct_p = Customer(i1, self.p_time)
self.cus[self.nc] = ct_p # 客の登録(系内客数)
k = i1
self.sb[k] = self.nc # サービスを受けている客番号
self.st_e[k] = self.p_time + self.Next_sv() # 窓口kのサービス終了時刻
self.asb -= 1 # 空いている窓口数
break
self.st_s[k] = self.p_time # 窓口kがふさがった時刻
if self.asb == 0 :
self.asb_t = self.p_time # すべての窓口がふさがった時刻
#################################
# サービス終了時の処理
# k : サービス終了窓口番号
#################################
def Service(self, k) :
# 時間の設定
k -= 1
self.p_time = self.st_e[k] # 現在時刻
self.st_e[k] = -1.0 # サービス終了時間
# 系内客数の処理
self.c_sc_t += len(self.cus) * (self.p_time - self.sc_t) # 系内客数にその数が継続した時間を乗じた値の累計
self.sc_t = self.p_time # 現在の系内客数になった時刻
# 滞在時間の処理
x1 = self.p_time - self.cus[self.sb[k]].time
self.c_sys += x1 # 滞在時間の累計
if x1 > self.m_sys :
self.m_sys = x1 # 最大滞在時間
self.cus.pop(self.sb[k]) # 客の削除(系内客数)
# 窓口使用時間の処理
self.asb += 1 # 空いている窓口数
self.sb[k] = 0 # 窓口kを空き状態にする
self.c_sb[k] += (self.p_time - self.st_s[k]) # 窓口kがふさがっている時間の累計
# 待ち行列がある場合
if len(self.que) > 0 :
self.asb -= 1 # 開いている窓口数
self.c_lq_t += len(self.que) * (self.p_time - self.lq_t) # 待ち行列長にその長さが継続した時間を乗じた値の累計
n = self.que.pop(0)
self.lq_t = self.p_time # 現在の待ち行列長になった時刻
x1 = self.p_time - self.cus[n].time
self.c_wt += x1 # 待ち時間の累計
if x1 > self.m_wt :
self.m_wt = x1 # 最大待ち時間
k = -1
for i1 in range(0, self.s) :
if self.sb[i1] == 0 :
k = i1
self.sb[k] = n # 窓口kの客番号
self.st_e[k] = self.p_time + self.Next_sv() # 窓口kのサービス終了時刻
self.st_s[k] = self.p_time # 窓口kがふさがった時刻
self.cus[n].state = k # 客の状態変更
break
# 待ち行列がない場合
else :
if self.asb == 1 :
self.c_asb += (self.p_time - self.asb_t) # すべての窓口がふさがっている時間の累計
########################
# 結果の出力
# (カッコ内は理論値)
########################
def Output(self) :
rn = float(self.nc)
rs = float(self.s)
ram = 1.0 / self.m_a
myu = 1.0 / self.m_s
rou = ram / (rs * myu)
if self.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))
Lq = pi * rou / (1.0 - rou)
L = Lq + rs * rou
Wq = Lq / ram
W = Wq + 1.0 / myu
print("シミュレーション終了時間={0:.3f} 客数={1:d} ρ={2:.3f} p0={3:.3f}".format(self.p_time, self.nc, rou, p0))
print(" すべての窓口が塞がっている割合={0:.3f} ({1:.3f})".format(self.c_asb/self.p_time, pi))
print(" 各窓口が塞がっている割合")
for i1 in range(0, self.s) :
print(" {0:d} {1:.3f}".format(i1+1, self.c_sb[i1]/self.p_time))
print(" 平均待ち行列長={0:.3f} ({1:.3f}) 最大待ち行列長={2:d}".format(self.c_lq_t/self.p_time, Lq, self.m_lq))
print(" 平均系内客数 ={0:.3f} ({1:.3f}) 最大系内客数 ={2:d}".format(self.c_sc_t/self.p_time, L, self.m_sc))
print(" 平均待ち時間 ={0:.3f} ({1:.3f}) 最大待ち時間 ={2:.3f}".format(self.c_wt/rn, Wq, self.m_wt))
print(" 平均滞在時間 ={0:.3f} ({1:.3f}) 最大滞在時間 ={2:.3f}".format(self.c_sys/rn, W, self.m_sys))
#############################
# 簡単な待ち行列問題(M/M/s)
# coded by Y.Suganuma
#############################
# 入力データ
s = int(input("窓口の数は? "))
end = float(input("シミュレーション終了時間? "))
m_a = float(input(" 到着時間間隔の平均値は? "))
m_s = float(input(" サービス時間の平均値は? "))
# システムの定義
base = Q_base(s, m_a, m_s, end)
# シミュレーションの実行
seed()
base.Control()
# 出力
base.Output()
/******************************/
/* 簡単な待ち行列問題(M/M/s)*/
/* coded by Y.Suganuma */
/******************************/
using System;
using System.Collections.Generic;
class Program
{
/****************/
/* main program */
/****************/
static void Main()
{
/*
入力データ
*/
Console.Write("窓口の数は? ");
int s = int.Parse(Console.ReadLine());
Console.Write("シミュレーション終了時間? ");
double end = double.Parse(Console.ReadLine());
Console.Write(" 到着時間間隔の平均値は? ");
double m_a = double.Parse(Console.ReadLine());
Console.Write(" サービス時間の平均値は? ");
double m_s = double.Parse(Console.ReadLine());
/*
システムの定義
*/
Q_base base1 = new Q_base(s, m_a, m_s, end);
/*
シミュレーションの実行
*/
base1.Control();
/*
出力
*/
base1.Output();
}
}
/**********************/
/* クラスQ_baseの定義 */
/**********************/
class Q_base {
int s; // 窓口の数
int asb; // 全窓口の空き状況
// =0 : すべての窓口がふさがっている
// =n : n個の窓口が空いている
int [] sb; // 各窓口の空き状況
// =0 : 窓口は空いている
// >0 : サービスを受けている客番号
double asb_t; // すべての窓口がふさがった時間
double c_asb; // すべての窓口がふさがっている時間の累計
double [] c_sb; // 各窓口がふさがっている時間の累計
double [] st_e; // 各窓口のサービス終了時間
double [] st_s; // 各窓口がふさがった時間
int m_lq; // 最大待ち行列長
double c_lq_t; // 待ち行列長にその長さが継続した時間を乗じた値の累計
double c_wt; // 待ち時間の累計
double lq_t; // 現在の待ち行列長になった時間
double m_wt; // 最大待ち時間
double c_sc_t; // 系内客数にその数が継続した時間を乗じた値の累計
double c_sys; // 滞在時間の累計
double m_sys; // 最大滞在時間
double sc_t; // 現在の系内客数になった時間
int m_sc; // 最大系内客数
double m_a; // 到着時間間隔の平均値
double m_s; // サービス時間の平均値
double at; // 次の客の到着時間(負の時は,終了)
double p_time; // 現在時間
double end; // シミュレーション終了時間
int nc; // 到着客数カウンタ
Random rn; // 乱数
Dictionary<int, Customer> cus; // 系内にいる客のリスト
Queue<int> que; // 待ち行列
/*****************************************/
/* コンストラクタ */
/* s_i : 窓口の数 */
/* m_a_i : 到着時間間隔の平均値 */
/* m_s_i : サービス時間の平均値 */
/* end_i : シミュレーション終了時間 */
/*****************************************/
public Q_base (int s_i, double m_a_i, double m_s_i, double end_i)
{
/*
設定
*/
s = s_i;
m_a = m_a_i;
m_s = m_s_i;
end = end_i;
/*
領域の確保
*/
sb = new int [s];
c_sb = new double [s];
st_e = new double [s];
st_s = new double [s];
for (int i1 = 0; i1 < s; i1++) {
sb[i1] = 0;
c_sb[i1] = 0.0;
}
cus = new Dictionary <int, Customer> ();
que = new Queue <int> ();
/*
初期設定
*/
p_time = 0.0;
nc = 0;
asb = s;
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;
/*
乱数の初期設定
*/
rn = new Random();
/*
最初の客の到着時間の設定
*/
at = p_time + Next_at();
}
/**********************************/
/* 次の客の到着までの時間の発生 */
/**********************************/
double Next_at()
{
return -m_a * Math.Log(rn.NextDouble());
}
/************************/
/* サービス時間の発生 */
/************************/
double Next_sv()
{
return -m_s * Math.Log(rn.NextDouble());
}
/**************/
/* 全体の制御 */
/**************/
public void Control()
{
int sw = 0;
while (sw > -2) {
sw = Next(); // 次の処理の選択
if (sw == -1)
sw = End_o_s(); // シミュレーションの終了
else {
if (sw == 0)
Arrive(); // 客の到着処理
else
Service(sw); // サービスの終了
}
}
}
/**************************************************/
/* 次の処理の決定 */
/* return : =-1 : シミュレーションの終了 */
/* =0 : 客の到着処理 */
/* =i : i番目の窓口のサービス終了 */
/**************************************************/
int Next()
{
int sw = -1;
double t = end; // シミュレーション終了時刻で初期設定
// 次の客の到着時刻
if (at >= 0.0 && at < t) {
sw = 0;
t = at;
}
// サービス終了時刻
for (int i1 = 0; i1 < s; i1++) {
if (sb[i1] > 0 && st_e[i1] <= t) {
sw = i1 + 1;
t = st_e[i1]; // 窓口i1のサービス終了時刻
}
}
return sw;
}
/**********************************/
/* 終了処理 */
/* return : =-1 : 終了前処理 */
/* =-2 : 実際の終了 */
/**********************************/
int End_o_s()
{
int sw = -2;
p_time = end; // 現在時刻
at = -1.0; // 次の客の到着時刻
for (int i1 = 0; i1 < s; i1++) {
if (sb[i1] > 0) { // サービス中の客はいるか?
if (sw == -2) {
sw = -1;
end = st_e[i1]; // 窓口i1のサービス終了時刻
}
else {
if (st_e[i1] > end)
end = st_e[i1]; // 窓口i1のサービス終了時刻
}
}
}
return sw;
}
/****************************/
/* 客の到着処理 */
/* ct : 客リストの先頭 */
/****************************/
void Arrive()
{
/*
客数の増加と次の客の到着時刻の設定
*/
nc += 1; // 到着客数カウンタ
p_time = at; // 現在時刻
at = p_time + Next_at(); // 次の客の到着時刻
if (at >= end)
at = -1.0;
/*
系内客数の処理
*/
c_sc_t += cus.Count * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time; // 現在の系内客数になった時刻
if (cus.Count+1 > m_sc)
m_sc = cus.Count + 1; // 最大系内客数
/*
窓口に空きがない場合
*/
if (asb == 0) {
Customer ct_p = new Customer(-1, p_time);
cus.Add(nc, ct_p); // 客の登録(系内客数)
c_lq_t += que.Count * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
que.Enqueue(nc); // 客の登録(待ち行列)
lq_t = p_time; // 現在の待ち行列長になった時刻
if (que.Count > m_lq)
m_lq = que.Count; // 最大待ち行列長
}
/*
すぐサービスを受けられる場合
*/
else {
int k = -1;
for (int i1 = 0; i1 < s && k < 0; i1++) {
if (sb[i1] == 0) {
Customer ct_p = new Customer(i1, p_time);
cus.Add(nc, ct_p); // 客の登録(系内客数)
k = i1;
sb[k] = nc; // サービスを受けている客番号
st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻
asb -= 1; // 空いている窓口数
}
}
st_s[k] = p_time; // 窓口kがふさがった時刻
if (asb == 0)
asb_t = p_time; // すべての窓口がふさがった時刻
}
}
/*********************************/
/* サービス終了時の処理 */
/* k : サービス終了窓口番号 */
/* ct : 客リストの先頭 */
/*********************************/
void Service(int k)
{
/*
時間の設定
*/
k -= 1;
p_time = st_e[k]; // 現在時刻
st_e[k] = -1.0; // サービス終了時間
/*
系内客数の処理
*/
c_sc_t += cus.Count * (p_time - sc_t); // 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time; // 現在の系内客数になった時刻
/*
滞在時間の処理
*/
Customer ct = cus[sb[k]];
double x1 = p_time - ct.time;
c_sys += x1; // 滞在時間の累計
if (x1 > m_sys)
m_sys = x1; // 最大滞在時間
cus.Remove(sb[k]); // 客の削除(系内客数)
/*
窓口使用時間の処理
*/
asb += 1; // 空いている窓口数
sb[k] = 0; // 窓口kを空き状態にする
c_sb[k] += (p_time - st_s[k]); // 窓口kがふさがっている時間の累計
/*
待ち行列がある場合
*/
if (que.Count > 0) {
asb -= 1; // 開いている窓口数
c_lq_t += que.Count * (p_time - lq_t); // 待ち行列長にその長さが継続した時間を乗じた値の累計
int n = que.Dequeue(); // 客の削除(待ち行列)
lq_t = p_time; // 現在の待ち行列長になった時刻
ct = cus[n];
x1 = p_time - ct.time;
c_wt += x1; // 待ち時間の累計
if (x1 > m_wt)
m_wt = x1; // 最大待ち時間
k = -1;
for (int i1 = 0; i1 < s && k < 0; i1++) {
if (sb[i1] == 0) {
k = i1;
sb[k] = n; // 窓口kの客番号
st_e[k] = p_time + Next_sv(); // 窓口kのサービス終了時刻
st_s[k] = p_time; // 窓口kがふさがった時刻
ct.state = k; // 客の状態変更
}
}
}
/*
待ち行列がない場合
*/
else {
if (asb == 1)
c_asb += (p_time - asb_t); // すべての窓口がふさがっている時間の累計
}
}
/************************/
/* 結果の出力 */
/* (カッコ内は理論値) */
/************************/
public void Output()
{
double rn = (double)nc;
double rs = (double)s;
double ram = 1.0 / m_a;
double myu = 1.0 / m_s;
double rou = ram / (rs * myu);
double p0, pi;
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));
}
double Lq = pi * rou / (1.0 - rou);
double L = Lq + rs * rou;
double Wq = Lq / ram;
double W = Wq + 1.0 / myu;
Console.WriteLine("シミュレーション終了時間=" + p_time + " 客数=" + nc + " ρ=" + rou + " p0=" + p0);
Console.WriteLine(" すべての窓口が塞がっている割合=" + (c_asb/p_time) + " (" + pi + ")");
Console.WriteLine(" 各窓口が塞がっている割合");
for (int i1 = 0; i1 < s; i1++)
Console.WriteLine(" " + (i1+1) + " " + (c_sb[i1]/p_time));
Console.WriteLine(" 平均待ち行列長=" + (c_lq_t/p_time) + " (" + Lq + ") 最大待ち行列長=" + m_lq);
Console.WriteLine(" 平均系内客数 =" + (c_sc_t/p_time) + " (" + L + ") 最大系内客数 =" + m_sc);
Console.WriteLine(" 平均待ち時間 =" + (c_wt/rn) + " (" + Wq + ") 最大待ち時間 =" + m_wt);
Console.WriteLine(" 平均滞在時間 =" + (c_sys/rn) + " (" + W + ") 最大滞在時間 =" + m_sys);
}
}
/************************/
/* クラスCustomerの定義 */
/************************/
class Customer
{
public double time; // 到着時刻
public int state; // 客の状態
// =-1 : 待ち行列に入っている
// >=0 : サービスを受けている窓口番号
/*******************/
/* コンストラクタ */
/* n : 客番号 */
/* s : 状態 */
/*******************/
public Customer (int s, double t)
{
time = t;
state = s;
}
}
'****************************'
' 簡単な待ち行列問題(M/M/s)'
' coded by Y.Suganuma '
'****************************'
Imports System.Collections.Generic
Module Test
Sub Main()
'
' 入力データ
'
Console.Write("窓口の数は? ")
Dim s As Integer = Integer.Parse(Console.ReadLine())
Console.Write("シミュレーション終了時間? ")
Dim end_s As Double = Double.Parse(Console.ReadLine())
Console.Write(" 到着時間間隔の平均値は? ")
Dim m_a As Double = Double.Parse(Console.ReadLine())
Console.Write(" サービス時間の平均値は? ")
Dim m_s As Double = Double.Parse(Console.ReadLine())
'
' システムの定義
'
Dim base1 As Q_base = new Q_base(s, m_a, m_s, end_s)
'
' シミュレーションの実行
'
base1.Control()
'
' 出力
'
base1.Output()
End Sub
'********************'
' クラスQ_baseの定義 '
'********************'
Class Q_base
Private s As Integer ' 窓口の数
Private asb As Integer ' 全窓口の空き状況
' =0 : すべての窓口がふさがっている
' =n : n個の窓口が空いている
Private sb() As Integer ' 各窓口の空き状況
' =0 : 窓口は空いている
' >0 : サービスを受けている客番号
Private asb_t As Double ' すべての窓口がふさがった時間
Private c_asb As Double ' すべての窓口がふさがっている時間の累計
Private c_sb() As Double ' 各窓口がふさがっている時間の累計
Private st_e() As Double ' 各窓口のサービス終了時間
Private st_s() As Double ' 各窓口がふさがった時間
Private m_lq As Integer ' 最大待ち行列長
Private c_lq_t As Double ' 待ち行列長にその長さが継続した時間を乗じた値の累計
Private c_wt As Double ' 待ち時間の累計
Private lq_t As Double ' 現在の待ち行列長になった時間
Private m_wt As Double ' 最大待ち時間
Private c_sc_t As Double ' 系内客数にその数が継続した時間を乗じた値の累計
Private c_sys As Double ' 滞在時間の累計
Private m_sys As Double ' 最大滞在時間
Private sc_t As Double ' 現在の系内客数になった時間
Private m_sc As Integer ' 最大系内客数
Private m_a As Double ' 到着時間間隔の平均値
Private m_s As Double ' サービス時間の平均値
Private at As Double ' 次の客の到着時間(負の時は,終了)
Private p_time As Double ' 現在時間
Private end_s As Double ' シミュレーション終了時間
Private nc As Integer ' 到着客数カウンタ
Private rn As Random ' 乱数
Private cus As New Dictionary(Of Integer, Customer) ' 系内にいる客のリスト
Private que As New Queue(Of Integer) ' 待ち行列
'***************************************'
' コンストラクタ '
' s_i : 窓口の数 '
' m_a_i : 到着時間間隔の平均値 '
' m_s_i : サービス時間の平均値 '
' end_i : シミュレーション終了時間 '
'***************************************'
Public Sub New(s_i As Integer, m_a_i As Double, m_s_i As Double, end_i As Double)
'
' 設定
'
s = s_i
m_a = m_a_i
m_s = m_s_i
end_s = end_i
'
' 領域の確保
'
ReDim sb(s)
ReDim c_sb(s)
ReDim st_e(s)
ReDim st_s(s)
For i1 As Integer = 0 To s-1
sb(i1) = 0
c_sb(i1) = 0.0
Next
'
' 初期設定
'
p_time = 0.0
nc = 0
asb = s
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
'
' 乱数の初期設定
'
rn = new Random()
'
' 最初の客の到着時間の設定
'
at = p_time + Next_at()
End Sub
'********************************'
' 次の客の到着までの時間の発生 '
'********************************'
Function Next_at()
Return -m_a * Math.Log(rn.NextDouble())
End Function
'**********************'
' サービス時間の発生 '
'**********************'
Function Next_sv()
Return -m_s * Math.Log(rn.NextDouble())
End Function
'************'
' 全体の制御 '
'************'
Sub Control()
Dim sw As Integer = 0
Do While sw > -2
sw = Next_e() ' 次の処理の選択
If sw = -1
sw = End_o_s() ' シミュレーションの終了
Else
If sw = 0
Arrive() ' 客の到着処理
Else
Service(sw) ' サービスの終了
End If
End If
Loop
End Sub
'************************************************'
' 次の処理の決定 '
' return : =-1 : シミュレーションの終了 '
' =0 : 客の到着処理 '
' =i : i番目の窓口のサービス終了 '
'************************************************'
Function Next_e()
Dim sw As Integer = -1
Dim t As Double = end_s ' シミュレーション終了時刻で初期設定
' 次の客の到着時刻
If at >= 0.0 and at < t
sw = 0
t = at
End If
' サービス終了時刻
For i1 As Integer = 0 To s-1
If sb(i1) > 0 and st_e(i1) <= t
sw = i1 + 1
t = st_e(i1) ' 窓口i1のサービス終了時刻
End If
Next
Return sw
End Function
'********************************'
' 終了処理 '
' return : =-1 : 終了前処理 '
' =-2 : 実際の終了 '
'********************************'
Function End_o_s()
Dim sw As Integer = -2
p_time = end_s ' 現在時刻
at = -1.0 ' 次の客の到着時刻
For i1 As Integer = 0 To s-1
If sb(i1) > 0 ' サービス中の客はいるか?
If sw = -2
sw = -1
end_s = st_e(i1) ' 窓口i1のサービス終了時刻
Else
If st_e(i1) > end_s
end_s = st_e(i1) ' 窓口i1のサービス終了時刻
End If
End If
End If
Next
Return sw
End Function
'**************************'
' 客の到着処理 '
' ct : 客リストの先頭 '
'**************************'
Sub Arrive()
'
' 客数の増加と次の客の到着時刻の設定
'
nc += 1 ' 到着客数カウンタ
p_time = at ' 現在時刻
at = p_time + Next_at() ' 次の客の到着時刻
If at >= end_s
at = -1.0
End If
'
' 系内客数の処理
'
c_sc_t += cus.Count * (p_time - sc_t) ' 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time ' 現在の系内客数になった時刻
If cus.Count+1 > m_sc
m_sc = cus.Count + 1 ' 最大系内客数
End If
'
' 窓口に空きがない場合
'
If asb = 0
Dim ct_p As Customer = new Customer(-1, p_time)
cus.Add(nc, ct_p) ' 客の登録(系内客数)
c_lq_t += que.Count * (p_time - lq_t) ' 待ち行列長にその長さが継続した時間を乗じた値の累計
que.Enqueue(nc) ' 客の登録(待ち行列)
lq_t = p_time ' 現在の待ち行列長になった時刻
If que.Count > m_lq
m_lq = que.Count ' 最大待ち行列長
End If
'
' すぐサービスを受けられる場合
'
Else
Dim k As Integer = -1
Dim i1t As Integer = 0
Do While i1t < s and k < 0
If sb(i1t) = 0
Dim ct_p As Customer = new Customer(i1t, p_time)
cus.Add(nc, ct_p) ' 客の登録(系内客数)
k = i1t
sb(k) = nc ' サービスを受けている客番号
st_e(k) = p_time + Next_sv() ' 窓口kのサービス終了時刻
asb -= 1 ' 空いている窓口数
End If
i1t += 1
Loop
st_s(k) = p_time ' 窓口kがふさがった時刻
If asb = 0
asb_t = p_time ' すべての窓口がふさがった時刻
End If
End If
End Sub
'*******************************'
' サービス終了時の処理 '
' k : サービス終了窓口番号 '
' ct : 客リストの先頭 '
'*******************************'
Sub Service(k As Integer)
'
' 時間の設定
'
k -= 1
p_time = st_e(k) ' 現在時刻
st_e(k) = -1.0 ' サービス終了時間
'
' 系内客数の処理
'
c_sc_t += cus.Count * (p_time - sc_t) ' 系内客数にその数が継続した時間を乗じた値の累計
sc_t = p_time ' 現在の系内客数になった時刻
'
' 滞在時間の処理
'
Dim ct As Customer = cus(sb(k))
Dim x1 As Double = p_time - ct.time
c_sys += x1 ' 滞在時間の累計
If x1 > m_sys
m_sys = x1 ' 最大滞在時間
End If
cus.Remove(sb(k)) ' 客の削除(系内客数)
'
' 窓口使用時間の処理
'
asb += 1 ' 空いている窓口数
sb(k) = 0 ' 窓口kを空き状態にする
c_sb(k) += (p_time - st_s(k)) ' 窓口kがふさがっている時間の累計
'
' 待ち行列がある場合
'
If que.Count > 0
asb -= 1 ' 開いている窓口数
c_lq_t += que.Count * (p_time - lq_t) ' 待ち行列長にその長さが継続した時間を乗じた値の累計
Dim n As Integer = que.Dequeue() ' 客の削除(待ち行列)
lq_t = p_time ' 現在の待ち行列長になった時刻
ct = cus(n)
x1 = p_time - ct.time
c_wt += x1 ' 待ち時間の累計
If x1 > m_wt
m_wt = x1 ' 最大待ち時間
End If
k = -1
Dim i1t As Integer = 0
Do While i1t < s and k < 0
If sb(i1t) = 0
k = i1t
sb(k) = n ' 窓口kの客番号
st_e(k) = p_time + Next_sv() ' 窓口kのサービス終了時刻
st_s(k) = p_time ' 窓口kがふさがった時刻
ct.state = k ' 客の状態変更
End If
i1t += 1
Loop
'
' 待ち行列がない場合
'
Else
If asb = 1
c_asb += (p_time - asb_t) ' すべての窓口がふさがっている時間の累計
End If
End If
End Sub
'**********************'
' 結果の出力 '
' (カッコ内は理論値) '
'**********************'
Sub Output()
Dim rn As Double = nc
Dim rs As Double = s
Dim ram As Double = 1.0 / m_a
Dim myu As Double = 1.0 / m_s
Dim rou As Double = ram / (rs * myu)
Dim p0 As Double
Dim pi As Double
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 If
Dim Lq As Double = pi * rou / (1.0 - rou)
Dim L As Double = Lq + rs * rou
Dim Wq As Double = Lq / ram
Dim W As Double = Wq + 1.0 / myu
Console.WriteLine("シミュレーション終了時間=" & p_time & " 客数=" & nc & " ρ=" & rou & " p0=" & p0)
Console.WriteLine(" すべての窓口が塞がっている割合=" & (c_asb/p_time) & " (" & pi & ")")
Console.WriteLine(" 各窓口が塞がっている割合")
For i1 As Integer = 0 To s-1
Console.WriteLine(" " & (i1+1) & " " & (c_sb(i1)/p_time))
Next
Console.WriteLine(" 平均待ち行列長=" & (c_lq_t/p_time) & " (" & Lq & ") 最大待ち行列長=" & m_lq)
Console.WriteLine(" 平均系内客数 =" & (c_sc_t/p_time) & " (" & L & ") 最大系内客数 =" & m_sc)
Console.WriteLine(" 平均待ち時間 =" & (c_wt/rn) & " (" & Wq & ") 最大待ち時間 =" & m_wt)
Console.WriteLine(" 平均滞在時間 =" & (c_sys/rn) & " (" & W & ") 最大滞在時間 =" & m_sys)
End Sub
End Class
'**********************'
' クラスCustomerの定義 '
'**********************'
Class Customer
Public time As Double ' 到着時刻
Public state As Integer ' 客の状態
' =-1 : 待ち行列に入っている
' >=0 : サービスを受けている窓口番号
'*****************'
' コンストラクタ '
' n : 客番号 '
' s : 状態 '
'*****************'
Public Sub New(s As Integer, t As Double)
time = t
state = s
End Sub
End Class
End Module
| 情報学部 | 菅沼ホーム | 目次 | 索引 |