読者です 読者をやめる 読者になる 読者になる

待ち行列シミュレーション

統計学

この前提出したシミュレーションの課題をJavaでサクサクできるように作りました。とりあえず1行列1サービスのやつしか作ってないけどw。試しに客の人数300人、客の発生は[0,5]の一様乱数、サービスにかかる時間は[0,5]の一様乱数でやってみたところなんか面白いグラフができたんで載せてみます。グラフはお得意(?)のJFreeChartで。

プログラムやらない人もパラメーターいじって簡単に遊べるようにしようということでサーブレット版も作ります。が、自宅サーバーのルーターの設定ができていないのでそれは出来次第ということで。。。

Customer.java

で、いつものごとく誰が使うのか知らないけどソースのっけて見るテスト。

public class Customer {
	private int ID;
	private int randomOccur;
	private int randomService;//サービスにかかる時間
	private int occurTime;//発生時刻
	private int finishWaitingTime;

	public void setID(int ID){
		this.ID=ID;
	}

	public int getID(){
		return ID;
	}

	public void setRandomOccur(int n){
		//客の発生する一様乱数の範囲の設定
		this.randomOccur=(int)(Math.random()*n);
	}
	public int getRandomOccur(){
		return randomOccur;
	}

	public void setRandomService(int n){
		//客のサービスにかかる時間の一様乱数の設定
		this.randomService=(int)(Math.random()*n);
	}

	public int getRandomService(){
		return randomService;
	}

	public void setOccurTime(Queue queue){
		//待ち行列に入った時刻=客の発生した時間
		if(queue.getQueueLength()==0){
			this.occurTime=this.getRandomOccur();
		}else{
			this.occurTime=queue.getCustermer(queue.getQueueLength()-1).getOccurTime()+this.getRandomOccur();
		}
	}

	public int getOccurTime(){
		return occurTime;
	}

	public void setFinishWaitingTime(Queue queue) {
		//待ち行列から出てくる時刻=サービスに入った時間
		if(queue.getQueueLength()==0){
			finishWaitingTime=getOccurTime();
		}else{
			if(queue.getCustermer(queue.getQueueLength()-1).getFinishWaitingTime()
					+queue.getCustermer(queue.getQueueLength()-1).getRandomService()<this.getOccurTime()){
				//もし自分が発生した時刻が前の人のサービスが終わった時間より遅かったら
				this.finishWaitingTime=occurTime;
			}else{
				this.finishWaitingTime=queue.getCustermer(queue.getQueueLength()-1).getFinishWaitingTime()+queue.getCustermer(queue.getQueueLength()-1).getRandomService();
			}
		}
	}
	
	public int getFinishWaitingTime() {
		return finishWaitingTime;
	}
	
	public int getServiceFinishedTime(){
		return getFinishWaitingTime()+getRandomService();
	}

	public String toString(){
		return "ID:"+this.getID()+"\n発生時間:"+this.getOccurTime()
		+"\n待ち行列から出てくる時間:"+this.getFinishWaitingTime();
	}
}

Queue.java

import java.util.ArrayList;
import java.util.List;

public class Queue{
	private List<Customer> queue=new ArrayList<Customer>();

	public void addCustomer(int randomOccur,int randomService){
		Customer cus=new Customer();
		cus.setID(queue.size()+1);
		cus.setRandomOccur(randomOccur);
		cus.setRandomService(randomService);
		cus.setOccurTime(this);
		cus.setFinishWaitingTime(this);
		queue.add(cus);
	}

	public void deleteCustomer(){
		queue.remove(0);
	}

	public int getQueueLength(){
		return queue.size();
	}

	public Customer getCustermer(int n){
		return queue.get(n);		
	}

	public int getWaitingPeopleNumber(Time timer){
		int count=0;
		for(int i=0;i<getQueueLength();i++){
			if(timer.getTime()>getCustermer(i).getOccurTime()){
				if(getCustermer(i).getServiceFinishedTime()>timer.getTime()){
					if(getCustermer(i).getOccurTime()<getCustermer(i).getFinishWaitingTime()){
						count++;
					}
				}
			}
		}
		return count;
	}

}

Time.java

public class Time{
	private int time;
	
	public void setTime(int time){
		this.time=time;
	}
	
	public int getTime(){
		return time;
	}
	
	public void increaseTime(int n){
		time=n+1;
	}
}

Graph.java

import java.io.File;
import java.io.IOException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Graph {
	private XYSeries series=new XYSeries("待ち人数");
	public void add(int i,double t){
		series.add(i,t);
	}
	
	public void makeGraph(String jpgName){
		XYSeriesCollection dataset=new XYSeriesCollection();
		dataset.addSeries(series);
		JFreeChart chart = ChartFactory.createScatterPlot("待ち行列シミュレーション"," N期", "", dataset, PlotOrientation.VERTICAL, true,true, false);
		File outputFile = new File(jpgName+".jpg");
		try {
			ChartUtilities.saveChartAsPNG(outputFile, chart, 500, 500);
		} catch (IOException ioEx) {
			ioEx.printStackTrace();
		}
	}
}

Main.java

public class Main {
	public static void main(String[] args) {
		final int OCCUR=5;//前の人が生まれてからどれくらいの時間で発生するか
		final int SERVICE=5;//サービスにかかる時間		
		final int N=300;//客の数
		Graph g=new Graph();
		Time timer=new Time();
		timer.setTime(0);
		Queue queue=new Queue();

		for(int i=0;i<N;i++){
			queue.addCustomer(OCCUR,SERVICE);
		}
		for(int i=0;i<queue.getQueueLength();i++){
			System.out.println(queue.getCustermer(i).toString());
		}
		int i=0;
		do{
			timer.increaseTime(i);
			g.add(i,queue.getWaitingPeopleNumber(timer));
			i++;
			}while(queue.getCustermer(queue.getQueueLength()-1).getFinishWaitingTime()>timer.getTime());
		g.makeGraph("queue");
	}
}

何でこんなに作るのに時間がかかったかというとアクセサの名前を相当いい加減に書いていたため、自分の中でこんがらかっていたことが原因でした。名前は重要、と自己メモ。

追記
ちゃかちゃかとサーブレットに仕上げてみました。パラメーターいじるといろいろ変わって、まあそれなりに(?)面白いんじゃないかと思います。サービスに時間がかかるようにor客の発生と同じくらいにして客を大量発生させるとぐにゃぐにゃ変化します*1
screenshot

*1:シミュレーションっていうよりグラフを面白がっているだけのような気がしなくもないw