SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
CallCenter.java
1package tutorial;
2
3import umontreal.ssj.simevents.*;
4import umontreal.ssj.rng.*;
5import umontreal.ssj.randvar.*;
6import umontreal.ssj.probdist.*;
7import umontreal.ssj.stat.*;
8import java.io.*;
9import java.util.*;
10
11public class CallCenter {
12 static final double HOUR = 3600.0; // Time is in seconds.
13
14 // Data
15 // Arrival rates are per hour, service and patience times are in seconds.
16 double openingTime; // Opening time of the center (in hours).
17 int numPeriods; // Number of working periods (hours) in the day.
18 int[] numAgents; // Number of agents for each period.
19 double[] lambda; // Base arrival rate lambda_j for each j.
20 double alpha0; // Parameter of gamma distribution for B.
21 double p; // Probability that patience time is 0.
22 double nu; // Parameter of exponential for patience time.
23 double alpha, beta; // Parameters of gamma service time distribution.
24 double s; // Want stats on waiting times smaller than s.
25
26 // Variables
27 double busyness; // Current value of B.
28 double arrRate = 0.0; // Current arrival rate.
29 int nAgents; // Number of agents in current period.
30 int nBusy; // Number of agents occupied;
31 int nArrivals; // Number of arrivals today;
32 int nAbandon; // Number of abandonments during the day.
33 int nGoodQoS; // Number of waiting times less than s today.
34 double nCallsExpected; // Expected number of calls per day.
35
36 Event nextArrival = new Arrival(); // The next Arrival event.
37 LinkedList<Call> waitList = new LinkedList<Call>();
38
39 RandomStream streamB = new MRG32k3a(); // For B.
40 RandomStream streamArr = new MRG32k3a(); // For arrivals.
41 RandomStream streamPatience = new MRG32k3a(); // For patience times.
42 GammaGen genServ; // For service times; created in readData().
43
44 Tally[] allTal = new Tally[5];
45 Tally statArrivals = allTal[0] = new Tally("Number of arrivals per day"); // Just to check.
46 Tally statWaits = allTal[1] = new Tally("Average waiting time per customer");
47 Tally statGoodQoS = allTal[2] = new Tally("Proportion of waiting times < s");
48 Tally statAbandon = allTal[3] = new Tally("Proportion of calls lost");
49 Tally statService = allTal[4] = new Tally("Service times"); // Just to check mean and variance.
50 Tally statWaitsDay = new Tally("Waiting times within a day");
51
52 public CallCenter(String fileName) throws IOException {
53 readData(fileName);
54 // genServ can be created only after its parameters are read.
55 // The acceptance/rejection method is much faster than inversion.
56 genServ = new GammaAcceptanceRejectionGen(new MRG32k3a(), alpha, beta);
57 }
58
59 // Reads data and construct arrays.
60 public void readData(String dataFile) throws IOException {
61 Locale loc = Locale.getDefault();
62 Locale.setDefault(Locale.US); // to read reals as 8.3 instead of 8,3
63 BufferedReader input = new BufferedReader(new FileReader(dataFile));
64 Scanner scan = new Scanner(input);
65 openingTime = scan.nextDouble();
66 scan.nextLine();
67 numPeriods = scan.nextInt();
68 scan.nextLine();
69 numAgents = new int[numPeriods];
70 lambda = new double[numPeriods];
71 nCallsExpected = 0.0;
72 for (int j = 0; j < numPeriods; j++) {
73 numAgents[j] = scan.nextInt();
74 lambda[j] = scan.nextDouble();
75 nCallsExpected += lambda[j];
76 scan.nextLine();
77 }
78 alpha0 = scan.nextDouble();
79 scan.nextLine();
80 p = scan.nextDouble();
81 scan.nextLine();
82 nu = scan.nextDouble();
83 scan.nextLine();
84 alpha = scan.nextDouble();
85 scan.nextLine();
86 beta = scan.nextDouble();
87 scan.nextLine();
88 s = scan.nextDouble();
89 scan.close();
90 Locale.setDefault(loc);
91 }
92
93 // A phone call object.
94 class Call {
95 double arrivalTime, serviceTime, patienceTime;
96
97 public Call() {
98 serviceTime = genServ.nextDouble(); // Generate service time.
99 statService.add(serviceTime); // Just for checking...
100 // patienceTime = generPatience(); // Generate the patience for all.
101 if (nBusy < nAgents) { // Start service immediately.
102 nBusy++;
103 nGoodQoS++;
104 statWaitsDay.add(0.0);
105 new CallCompletion().schedule(serviceTime);
106 } else { // Join the queue.
107 patienceTime = generPatience(); // Generate the patience only if needed.
108 arrivalTime = Sim.time();
109 waitList.addLast(this);
110 }
111 }
112
113 public void endWait() {
114 double wait = Sim.time() - arrivalTime;
115 if (patienceTime < wait) { // Caller has abandoned.
116 nAbandon++;
117 wait = patienceTime; // Effective waiting time.
118 } else {
119 nBusy++;
120 new CallCompletion().schedule(serviceTime);
121 }
122 if (wait < s)
123 nGoodQoS++;
124 statWaitsDay.add(wait);
125 }
126 }
127
128 // Event: A new period begins.
129 class NextPeriod extends Event {
130 int j; // Number of the new period.
131
132 public NextPeriod(int period) {
133 j = period;
134 }
135
136 public void actions() {
137 if (j < numPeriods) {
138 nAgents = numAgents[j];
139 arrRate = busyness * lambda[j] / HOUR;
140 if (j == 0) {
141 nextArrival.schedule(ExponentialDist.inverseF(arrRate, streamArr.nextDouble()));
142 } else {
143 checkQueue();
144 nextArrival.reschedule((nextArrival.time() - Sim.time()) * lambda[j - 1] / lambda[j]);
145 }
146 new NextPeriod(j + 1).schedule(1.0 * HOUR);
147 } else
148 nextArrival.cancel(); // End of the day.
149 }
150 }
151
152 // Event: A call arrives.
153 class Arrival extends Event {
154 public void actions() {
155 nextArrival.schedule(ExponentialDist.inverseF(arrRate, streamArr.nextDouble()));
156 nArrivals++;
157 new Call(); // Call just arrived.
158 }
159 }
160
161 // Event: A call is completed.
162 class CallCompletion extends Event {
163 public void actions() {
164 nBusy--;
165 checkQueue();
166 }
167 }
168
169 // Start answering new calls if agents are free and queue not empty.
170 public void checkQueue() {
171 while ((waitList.size() > 0) && (nBusy < nAgents))
172 (waitList.removeFirst()).endWait();
173 }
174
175 // Generates the patience time for a call.
176 public double generPatience() {
177 double u = streamPatience.nextDouble();
178 if (u <= p)
179 return 0.0;
180 else
181 return ExponentialDist.inverseF(nu, (1.0 - u) / (1.0 - p));
182 }
183
184 public void simulateOneDay(double busyness) {
185 Sim.init();
186 statWaitsDay.init();
187 nArrivals = 0;
188 nAbandon = 0;
189 nGoodQoS = 0;
190 nBusy = 0;
191 this.busyness = busyness;
192
193 new NextPeriod(0).schedule(openingTime * HOUR);
194 Sim.start();
195 // Here the simulation is running...
196
197 statArrivals.add((double) nArrivals);
198 statWaits.add(statWaitsDay.sum() / nCallsExpected);
199 statGoodQoS.add((double) nGoodQoS / nCallsExpected);
200 statAbandon.add((double) nAbandon / nCallsExpected);
201 }
202
203 public void simulateOneDay() {
204 simulateOneDay(GammaDist.inverseF(alpha0, alpha0, 8, streamB.nextDouble()));
205 }
206
207 static public void main(String[] args) throws IOException {
208 CallCenter cc = new CallCenter(args.length == 1 ? args[0] : "src/main/docs/examples/tutorial/CallCenter.dat");
209 for (int i = 0; i < 10000; i++)
210 cc.simulateOneDay();
211 System.out.println("\nNumber of calls expected per day = " + cc.nCallsExpected + "\n");
212 for (int i = 0; i < cc.allTal.length; i++) {
213 cc.allTal[i].setConfidenceIntervalStudent();
214 cc.allTal[i].setConfidenceLevel(0.90);
215 }
216 System.out.println(Tally.report("CallCenter:", cc.allTal));
217 }
218}
void actions()
This is the method that is executed when this event occurs.
void actions()
This is the method that is executed when this event occurs.
void actions()
This is the method that is executed when this event occurs.
Extends the class ContinuousDistribution for the exponential distribution tjoh95a  (page 494) with me...
double inverseF(double u)
Returns the inverse distribution function .
This class implements gamma random variate generators using a method that combines acceptance-rejecti...
This class implements random variate generators for the gamma distribution.
Definition GammaGen.java:47
Extends the abstract class RandomStreamBase by using as a backbone (or main) generator the combined m...
Definition MRG32k3a.java:46
This abstract class provides event scheduling tools.
Definition Event.java:53
Event()
Constructs a new event instance, which can be placed afterwards into the event list of the default si...
Definition Event.java:126
void schedule(double delay)
Schedules this event to happen in delay time units, i.e., at time sim.time() + delay,...
Definition Event.java:153
This static class contains the executive of a discrete-event simulation.
Definition Sim.java:48
static double time()
Returns the current value of the simulation clock.
Definition Sim.java:59
A subclass of StatProbe.
Definition Tally.java:47
This interface defines the basic structures to handle multiple streams of uniform (pseudo)random numb...
double nextDouble()
Returns a (pseudo)random number from the uniform distribution over the interval , using this stream,...