예제 #1
0
int main()
{
	//double simTime = 1e6;
	double simTime = 30;		// Run time set to 30 years
							    // let the system run for a max length of time 
	int simNum = 30;            // number of runs
								
	//Edited by Kiat Boon on 5/3/2016 to simulate M/M/1 queue
	unsigned int N = 1;      // number of servers
	char outputFileName[] = "N100gamma1LogNormal2.txt";

//	double mu = 1.0;         	

	int I=1, J=1, K=1;
	RngBase *arr[1], *ser[1], *abd[1];

	//for deciding to go urgent queue or non-urgent queue
	RngBase *decide[1];

	double decideValue;
	int countUrgent, countNonUrgent;
	int totalArr = 0;
	int totalAbd = 0;
	int totalRej = 0;
	int totalSer = 0;
	int totalUrgSer = 0;
	int totalNonUrgSer = 0;
	int totalUrgQueue = 0;						//amount of patients still in urgent queue at end of run
	int totalNonUrgQueue = 0;					//amount of patients still in non urgent queue at end of run
	int totalInServer = 0;						//amount of patients still in server at end of run

	double privHospCost = 49891.82;				//cost of surgery in private hospital: source from health-tourism.com, raffles hosp is 36700 USD
	double pubHospCost = 4978.85;				//cost of surgery in public hospital = (4729*272+5760*87)/(272+87)

	//****Note: All subsidies are assumed 10% co-insurance, so govt pays 90%****//

	double waitingCostInNonUrgQueue = .9*200*12;			//cost of waiting in non-urgent queue per yr
															//MediShield organ transplant for immunosuppressant subsidy is $200/mth
	double waitingCostInUrgQueue = .9*700*365;				//inpatient: 700/day

	double averageNonUrgSubsidy = .9*(650.0+1*1200+5.4*700);		//estimated average cost of subsidy per patient served from mediShield 
	double averageUrgSubsidy = .9*(1550.0+2*1200+7.2*700);			//Non-urg: 25th percentile of range, 200 to 2000
																				//Urg: 75th percentile of range, 200 to 2000
																				//Assume 10% of the time post-op in ICU
	//For overflow policy
	//double arrRate = 269.28;
	//int queueLength = 66;					    	//queue length to be set for overflow policy	
	//double incentiveProportion = 0;				    //percentage of incentive to be given to reduce arr rate

	//For incentive policy
	int queueLength = INT_MAX;
	double incentiveProportion = 0.22;
	double arrRate = 269.28*(1-seekPrivProportion(incentiveProportion)); 

	//no need to remove this section for overflow policy
	double incentive = (privHospCost-pubHospCost)*incentiveProportion;			   	//incentive to be given to each patient seeking private hospital		
	double totalIncentive = (269.28 - arrRate)*incentive*simTime;			        //expected total amount of incentive given to reduce queue length

	double serRate = 272;
	double lifeTime = 0.288;							//mean of 180.76 weeks
	//double lifeTime = 12;
	//double lifeTime = 1e8;

	double nonUrgentProportion = 0.231;						//proportion of patients in non-urgent queue: 1920/8325, table 1, sobolev
	double upgradeProportion = 0.513;						//proportion of patients to be upgraded
	vector<double> cs2(2);

	arr[0] = new ExpGen(arrRate);		
	//arr[0] = new DetGen(0.1);
	double ca2 = 1;
	

	/*NOTE: By default, ser[0] is exponential, but if ser[0] is not exponential, please change the service time generator in MS_Queue_Abd init()*/
	ser[0] = new ExpGen(serRate);
	//ser[0] = new DetGen(0.1);
	cs2[0] = 2.0;
	// ser[0] = new ErlangGen(2*mu, 2); 
	// cs2[0] = 0.5;
	// ser[1] = new DetGen(1.0); 
	// cs2[1] = 0.0;	
	//ser[1] = new ErlangGen(2*mu, 2); 
	//cs2[1] = 0.5;
	//ser[2] = new ExpGen(mu); 
	//cs2[2] = 1;
	//ser[3] = new HyperExp2Gen(1/0.169, 1/2.20327, .5915); 
	//cs2[3] = 3.0;
	//ser[4] = new LogNormalGen(1/mu, 3); 
	//cs2[4] = 3.0;

	abd[0] = new ExpGen(lifeTime);
	//abd[0] = new DetGen(1e8);								//so that patients will not abandon queue

	// abd[0] = new ErlangGen(3*alpha,3);
   // abd[0] = new HyperExp2Gen(1.0, 200.0, 0.9);
	//abd[0] = new HyperExp2Gen(0.2, 6.0, 0.9);
   // abd[0] = new HyperExp2Gen(1, 1/3.0, .5);
   // abd[0] = new HyperExp2Gen(alpha*0.3, 79*alpha/30, 0.7);
   // abd[1] = new ExpGen(2.0/3);
   // abd[0] = new UniformGen(0, 10);
   // abd[1] = new ExpGen(.25);


	decide[0] = new UniformGen(0,1);

	int sysSize;
	double depWaitTime;
	double depSoujournTime;
		
	int startTime = time(NULL);
	
	srand (time(NULL));

//i is for arr, j is for ser, k is for abd
for(int k=0;k<K;k++){
for(int j=0;j<J;j++){
for(int i=0;i<I;i++){

	
	/*   ------ Start Simulation  -----  */

	SampleStat bSize, bSizeL, sSize;
		bSize.reset();
		bSizeL.reset();
		sSize.reset();

	SampleStat bSizeU, bSizeLU;
		bSizeU.reset();
		bSizeLU.reset();

	SampleStat bTime, bTimeU;
		bTime.reset();
		bTimeU.reset();

	SampleStat bTimeSouj, bTimeSoujU;
		bTimeSouj.reset();
		bTimeSoujU.reset();

	SampleStat probAbd;
		probAbd.reset();
		
	Counter bSizeOne, sSizeOne;
	Counter bSizeOneL;
	Counter bSizeOneU;
	Counter bSizeOneLU;
	Counter bSizeSquareOne;
	Counter bSizeSquareOneU;
	Counter bTimeOne;
	Counter bTimeOneU;
	Counter bTimeOneSouj;
	Counter bTimeOneSoujU;
	Counter bTimeSquareOne;
	Counter bTimeSquareOneU;
	Counter probAbdOne;
	double totalNonUrgWaitingTime = 0.0;		//calculates total time of customers spent waiting in non-urgent queue 
	double totalUrgWaitingTime = 0.0;			//calculates total time of customers spent waiting in urgent queue
	int id;
	//running simulation for 30 times
	for(int run=0; run<simNum; run++)
	{	
	id = 1;
	//number of servers = N
	MS_Queue_Abd q(N);
	q.initSystemClock();
	q.init(upgradeProportion,queueLength, serRate);

	Event event; 

		
		bSizeOne.reset();
		bSizeOneL.reset();
		bSizeOneU.reset();
		bSizeOneLU.reset();
		sSizeOne.reset();
		bSizeSquareOne.reset();
		bSizeSquareOneU.reset();
		bTimeOne.reset(); 
		bTimeOneSouj.reset();
		bTimeOneU.reset();
		bTimeOneSoujU.reset();
		bTimeSquareOne.reset();
		bTimeSquareOneU.reset();
		probAbdOne.reset();
		countUrgent=0;
		countNonUrgent=0;
		cout<<"Run number: "<<run+1<<endl;
		q.setRunNumber(run+1);

		//each run: run for simTime units
		//run+1 required since getClock will not reset to 0, so have to increase length of new run
		while(q.getClock()<simTime)
		{	
			//find next event happening along with its maturity time
			event=q.nextEvent();

			//get nonUrgentQueue size - regBufAdj plus server size
			sysSize = q.getSize();
			
			//increases bSizeOne by nonUrgentQueue size*tm of event
			//meant for taking the average of the nonUrgentQueueSize later
			bSizeOne.update(q.getnonUrgentQueueSize(), event.tm);
			bSizeSquareOne.update(q.getnonUrgentQueueSize()*q.getnonUrgentQueueSize(), event.tm);

			//increases bSizeOne by nonUrgentQueue size*tm of event
			//meant for taking the average of the nonUrgentQueueSize later
			bSizeOneU.update(q.getUrgentQueueSize(), event.tm);	
			bSizeSquareOneU.update(q.getUrgentQueueSize()*q.getUrgentQueueSize(), event.tm);	

			//increases sSizeOne by server size*tm of event
			//meant for taking the average of the serverSize later
			sSizeOne.update(q.getServerSize(), event.tm);

			//new
			//don't need to include event.tm since alr included earlier
			bSizeOneL.update(q.getNumOfNonUrgentInServer(), event.tm);
			bSizeOneLU.update(q.getNumOfUrgentInServer(), event.tm);

			//amends server and queue based on event(arrival/depart/renege)
			//for arrival, customer will join server, or join queue along with regList
			//for departure, customer leaves server, and customer in queue joins server
			//for reneging, customer leaves regList, while modifying regBufAdj to account for customer left
			q.actOn(event);

			//checks if nonUrgentQueue size is correct, particularly regBufAdj
			q.checkStatus();

			if(event.tp==arrival)
			{
				decideValue = decide[0]->genNext();

				if (decideValue > nonUrgentProportion) 
				{
					q.schNextArr(arr[i]->genNext(),ser[j]->genNext(), abd[k]->genNext(), run+1, urgent, id);
					countUrgent++;
					id++;
				}
				else
				{	
					q.schNextArr(arr[i]->genNext(),ser[j]->genNext(), abd[k]->genNext(), run+1, nonUrgent, id);	
					countNonUrgent++;				
					id++;
				}
			}
			else if(event.tp==departure)
			{
				//get customer's waiting time in queue before entering server
				depWaitTime = q.getDepWaitTime();
				depSoujournTime = q.getDepRespTime();		//soujourn time

				if (q.getDepStatus() == nonUrgent)
				{
					bTimeOne.update(depWaitTime);
					bTimeSquareOne.update(depWaitTime*depWaitTime);
					bTimeOneSouj.update(depSoujournTime);
					if (q.getDepAbandoned() == false) {
						totalNonUrgWaitingTime += q.getDepWaitTime();	
					} else {
						totalNonUrgWaitingTime += q.getDepRegTime();
					}
				} 
				else if (q.getDepStatus() == urgent)
				{
					bTimeOneU.update(depWaitTime);
					bTimeSquareOneU.update(depWaitTime*depWaitTime);
					bTimeOneSoujU.update(depSoujournTime);
					totalUrgWaitingTime += q.getDepWaitTime();
				}

			//	if(!q.getDepReneged())
				//	probAbdOne.update(0);
			}
			else
			{
				//probAbdOne.update(1);
			   // bTimeOne.update(q.getRegWaitTime()); /// Use this line when computing the nonUrgentQueue time
			}

		}
		totalNonUrgWaitingTime += q.getStillInNonUrgQueueWaitTime();
		totalUrgWaitingTime += q.getStillInUrgQueueWaitTime();
//		q.printIds();

		int serverSize = q.checkServerSizeAndRemove();

//		cout<<"Number arrived: "<<q.getNumArrived()<<endl;
//		cout<<"Number abandoned: "<<q.getNumAbandoned()<<endl;
//		cout<<"Number served: "<<q.getNumServed()<<endl;
//		cout<<"Number rejected: "<<q.getNumRejected()<<endl;
//		cout<<"Number currently in server: "<<serverSize<<endl;
//		cout<<"Number in urg queue: "<<q.getUrgentQueueSize()<<endl;
//		cout<<"Number in non-urg queue: "<<q.getnonUrgentQueueSize()<<endl;
		cout<<"Unaccounted str: "<<q.getNumArrived()-q.getNumAbandoned()-q.getNumServed()-serverSize-q.getUrgentQueueSize()-q.getnonUrgentQueueSize()<<endl;
		probAbdOne.update2(q.getNumAbandoned(),q.getNumArrived()+q.getNumRejected());
		totalArr += q.getNumArrived();
		totalAbd += q.getNumAbandoned();
		totalRej += q.getNumRejected();
		totalSer += q.getNumServed();
		totalUrgSer += q.getUrgServed();
		totalNonUrgSer += q.getNonUrgServed();
		totalUrgQueue += q.getUrgentQueueSize();
		totalNonUrgQueue += q.getnonUrgentQueueSize();
		totalInServer += serverSize;
		q.initNumArrived();
		q.initNumAbandoned();
		q.initNumRejected();
		q.initNumServed();
		q.initUrgServed();
		q.initNonUrgServed();

		//end of single run here//
//		cout<<"No. of urgent: "<<countUrgent<<endl;
//		cout<<"No. of non-urgent: "<<countNonUrgent<<endl;
		cout<<run+1<<" out of "<<simNum<<" runs done ..."<<endl;
		cout<<"Clock: "<<q.getClock()<<endl; 
		//for subsequent runs beyond the first, the following is done
		if(run+1){
			bSize.update(bSizeOne.average());
			bSizeU.update(bSizeOneU.average());//new
			sSize.update(sSizeOne.average());

			bTime.update(bTimeOne.average());
			bTimeU.update(bTimeOneU.average());//new

			bTimeSouj.update(bTimeOneSouj.average());
			bTimeSoujU.update(bTimeOneSoujU.average());


			bSizeL.update(bSizeOneL.average());
			bSizeLU.update(bSizeOneLU.average());

			probAbd.update(probAbdOne.average());
		}
	}	
	//additional stuff done ends here

	ofstream outputFile;
	outputFile.open (outputFileName, ios::out | ios::app);
	
	//cout.setf(ios::fixed);
	//cout.precision(4);
	
	cout<<"________________________________\nNumber of servers = "<<N<<", Arrival rate = "<<arrRate
	    <<", Service rate = "<<serRate<<", Lifetime rate = ";
	if (lifeTime == 1e8) {
		cout<<"No deaths"<<". \n"<<endl;
	} else {
		cout<<lifeTime<<". \n"<<endl;
	}
	outputFile<<"\n\n\nNumber of servers = "<<N<<", Arrival rate = "<<arrRate
	    <<", Service rate = "<<serRate<<", Lifetime rate = ";
	if (lifeTime == 1e8) {
		outputFile<<"No deaths"<<". \n"<<endl;
	} else {
		outputFile<<lifeTime<<". \n"<<endl;
	};

	cout<<"Max queue length set to: ";
	if (queueLength==INT_MAX) {
		cout<<"Max integer value"<<endl;
	} else {
		cout<<queueLength<<endl;
	}
	
	outputFile<<"Max queue length set to: ";
	if (queueLength==INT_MAX) {
		outputFile<<"Max integer value"<<endl;
	} else {
		outputFile<<queueLength<<endl;
	}

	//Percentage of difference between private hospital and public hospital bill
	cout<<"Percentage incentive given to patients to seek private treatment: "<<incentiveProportion*100<<"%"<<endl;
	outputFile<<"Percentage incentive given to patients to seek private treatment: "<<incentiveProportion*100<<"%"<<endl;

	cout<<"Arrival time is "<<arr[i]->getName()
		<<"; Service time is "<<ser[j]->getName()
		<<"; Patient time is "<<abd[k]->getName()<<"\n"<<endl;
	outputFile<<"Arrival time is "<<arr[i]->getName()
		<<"; Service time is "<<ser[j]->getName()
		<<"; Patient time is "<<abd[k]->getName()<<"\n"<<endl;
	
	cout<<"Proportion of non-urgent patients: "<<nonUrgentProportion*100<<"%"<<endl;
	cout<<"Probability of upgrading upon expiration of lifetime: "<<upgradeProportion*100<<"%"<<endl;
	cout<<endl;
	outputFile<<"Proportion of non-urgent patients: "<<nonUrgentProportion*100<<"%"<<endl;
	outputFile<<"Probability of upgrading upon expiration of lifetime: "<<upgradeProportion*100<<"%"<<endl;
	outputFile<<endl;

	cout<<"Estimated waiting cost of patient in non-urgent queue per year = $"<<waitingCostInNonUrgQueue<<endl;
	cout<<"Estimated waiting cost of patient in urgent queue per year = $"<<waitingCostInUrgQueue<<endl;
	cout<<"Estimated subsidies per non-urgent patient served = $"<<averageNonUrgSubsidy<<endl;
	cout<<"Estimated subsidies per urgent patient served = $"<<averageUrgSubsidy<<endl;
	
	cout<<endl;
	outputFile<<"Estimated waiting cost of patient in non-urgent queue per year = $"<<waitingCostInNonUrgQueue<<endl;
	outputFile<<"Estimated waiting cost of patient in urgent queue per year = $"<<waitingCostInUrgQueue<<endl;
	outputFile<<"Estimated subsidies per non-urgent patient served = $"<<averageNonUrgSubsidy<<endl;
	outputFile<<"Estimated subsidies per urgent patient served = $"<<averageUrgSubsidy<<endl;
	outputFile<<endl;

	double meanServed = double(totalSer)/simNum;
	double meanUrgServed = double(totalUrgSer)/simNum;
	double meanNonUrgServed = double(totalNonUrgSer)/simNum;
	double meanArrived = double(totalArr)/simNum;
	double meanAbandoned = double(totalAbd)/simNum;
	double meanRejected = double(totalRej)/simNum;
	double meanUrgQueue = double(totalUrgQueue)/simNum;
	double meanNonUrgQueue = double(totalNonUrgQueue)/simNum;
	double meanInServer = double(totalInServer)/simNum;
	double meanNonUrgWaiting = totalNonUrgWaitingTime/simNum;
	double meanUrgWaiting = totalUrgWaitingTime/simNum;

	cout<<"Mean number of patients entered system per run = "<<meanArrived<<endl;
	outputFile<<"Mean number of patients entered system per run = "<<meanArrived<<endl;

	cout<<"Mean pre-operative deaths per run = "<<meanAbandoned<<endl;
	outputFile<<"Mean pre-operative deaths per run = "<<meanAbandoned<<endl;

	cout<<"Mean number of patients still stuck in non-urgent queue at end of run = "<<meanNonUrgQueue<<endl;
	outputFile<<"Mean number of patients still stuck in non-urgent queue at end of run = "<<meanNonUrgQueue<<endl;

	cout<<"Mean number of patients still stuck in urgent queue at end of run = "<<meanUrgQueue<<endl;
	outputFile<<"Mean number of patients still stuck in urgent queue at end of run = "<<meanUrgQueue<<endl;

	cout<<"Mean number of patients still stuck in server at end of run = "<<meanInServer<<endl;
	outputFile<<"Mean number of patients still stuck in server at end of run = "<<meanInServer<<endl;

	cout<<"Mean number of customers served per run = "<<meanServed<<endl;
	cout<<endl;
	outputFile<<"Mean number of customers served per run = "<<meanServed<<endl;
	outputFile<<endl;

	cout<<"Mean number of urgent customers served per run = "<<meanUrgServed<<endl;
	cout<<"Mean number of non-urgent customers served per run = "<<meanNonUrgServed<<endl;
	cout<<endl;
	outputFile<<"Mean number of urgent customers served per run = "<<meanUrgServed<<endl;
	outputFile<<"Mean number of non-urgent customers served per run = "<<meanNonUrgServed<<endl;
	outputFile<<endl;

	cout<<"Estimated total cost of subsidies from urgent customers served = $"<<meanUrgServed*averageUrgSubsidy<<endl;
	cout<<endl;
	outputFile<<"Estimated total cost of subsidies from urgent customers served = $"<<meanUrgServed*averageUrgSubsidy<<endl;
	outputFile<<endl;

	cout<<"Estimated total cost of subsidies from non-urgent customers served = $"<<meanNonUrgServed*averageNonUrgSubsidy<<endl;
	cout<<endl;
	outputFile<<"Estimated total cost of subsidies from non-urgent customers served = $"<<meanNonUrgServed*averageNonUrgSubsidy<<endl;
	outputFile<<endl;

	cout<<"Mean patients rejected per run = "<<meanRejected<<endl;
	cout<<"Cost of each rejection = "<<privHospCost<<endl;
	cout<<"Total cost of rejections = "<<meanRejected*privHospCost<<endl;
	cout<<"Percentage of rejections = "<<meanRejected*100/(meanRejected+meanArrived)<<"%"<<endl;
	cout<<endl;	
	outputFile<<"Mean patients rejected per run = "<<meanRejected<<endl;
	outputFile<<"Cost of each rejection = "<<privHospCost<<endl;
	outputFile<<"Total cost of rejections = "<<meanRejected*privHospCost<<endl;
	outputFile<<"Percentage of rejections = "<<meanRejected*100/(meanRejected+meanArrived)<<"%"<<endl;
	outputFile<<endl;

	//Probability of deaths over all arriving patients, including those rejected
	cout<<"Pre-operative death probability = "<<probAbd.mean()*100<<"%"<<endl;
	cout<<endl;	
	outputFile<<"Pre-operative death probability = "<<probAbd.mean()*100<<"%"<<endl;
	outputFile<<endl;	
	
	cout<<"Mean non-urgent queue length = "<<bSize.mean()<<endl;
	outputFile<<"Mean non-urgent queue length = "<<bSize.mean()<<endl;

	cout<<"Mean urgent queue length = "<<bSizeU.mean()<<endl;
	cout<<endl;
	outputFile<<"Mean urgent queue length = "<<bSizeU.mean()<<endl;
	outputFile<<endl;

	cout<<"Mean total time waited per run in non-urgent queue = "<<meanNonUrgWaiting<<endl;
	outputFile<<"Mean total time waited per run in non-urgent queue = "<<meanNonUrgWaiting<<endl;
	cout<<"Monetary cost of waiting in non-urgent queue = $"<<meanNonUrgWaiting*waitingCostInNonUrgQueue<<endl;
	outputFile<<"Monetary cost of waiting in non-urgent queue = $"<<meanNonUrgWaiting*waitingCostInNonUrgQueue<<endl;

	cout<<"Mean waiting time in non-urgent queue = "<<bTime.mean()<<endl;
	outputFile<<"Mean waiting time in non-urgent queue = "<<bTime.mean()<<endl;

	cout<<"Mean soujourn time of non-urgent patients = "<<bTimeSouj.mean()<<endl;
	cout<<endl;
	outputFile<<"Mean soujourn time of non-urgent patients = "<<bTimeSouj.mean()<<endl;
	outputFile<<endl;

	cout<<"Mean total time waited per run in urgent queue = "<<meanUrgWaiting<<endl;
	outputFile<<"Mean total time waited per run in urgent queue = "<<meanUrgWaiting<<endl;

	cout<<"Monetary cost of waiting in urgent queue = $"<<meanUrgWaiting*waitingCostInUrgQueue<<endl;
	outputFile<<"Monetary cost of waiting in urgent queue = $"<<meanUrgWaiting*waitingCostInUrgQueue<<endl;

	cout<<"Mean waiting time in urgent queue = "<<bTimeU.mean()<<endl;
	outputFile<<"Mean waiting time in urgent queue = "<<bTimeU.mean()<<endl;

	cout<<"Mean soujourn time of urgent patients = "<<bTimeSoujU.mean()<<endl;
	cout<<endl;
	outputFile<<"Mean soujourn time of urgent patients = "<<bTimeSoujU.mean()<<endl;
	outputFile<<endl;
	
	//bSizeL for server, bSize for queue
	cout<<"Mean non-urgent patients in system = "<<bSizeL.mean()+bSize.mean()<<endl;
	outputFile<<"Mean non-urgent patients in system = "<<bSizeL.mean()+bSize.mean()<<endl;

	cout<<"Mean urgent patients in system = "<<bSizeLU.mean()+bSizeU.mean()<<endl;
	cout<<endl;
	outputFile<<"Mean urgent patients in system = "<<bSizeLU.mean()+bSizeU.mean()<<endl;
	outputFile<<endl;

	cout<<"Mean number of busy servers = "<<sSize.mean()<<endl;
	cout<<endl; 
	outputFile<<"Mean number of busy servers = "<<sSize.mean()<<endl;
	outputFile<<endl; 

	cout<<"Estimated total cost = $"<<meanRejected*privHospCost + meanUrgServed*averageUrgSubsidy + meanNonUrgServed*averageNonUrgSubsidy + 
		meanNonUrgWaiting*waitingCostInNonUrgQueue + meanUrgWaiting*waitingCostInUrgQueue + totalIncentive<<endl;
	cout<<endl;
	outputFile<<"Estimated total cost = $"<<meanRejected*privHospCost + meanUrgServed*averageUrgSubsidy + meanNonUrgServed*averageNonUrgSubsidy + 
		meanNonUrgWaiting*waitingCostInNonUrgQueue + meanUrgWaiting*waitingCostInUrgQueue + totalIncentive<<endl;
	outputFile<<endl;

	outputFile<<"***********************************************************"<<endl;

	outputFile.close();
}
}
}

	int endTime = time(NULL);
	cout<<"\nCPU time: "<<(endTime-startTime)/60<<" min "
	    <<(endTime-startTime)%60<<" seconds"<<endl;
	    
	char endchar;
	cin >> endchar;

	return 0;
}