Source code: desmoj/QueueBased.java
1 package desmoj;
2
3 /**
4 * Provides the typical statistics common to all ModelComponents based on
5 * Queues. It is set abstract to prevent users to use it straight without
6 * deriving a class first because it only provides the functionality
7 * for statistical data extraction, not the functionality for actually
8 * queueing Entities.
9 * The statistical values provided are the queue's length and its
10 * elements' waiting times with minimum, maximum, mean and
11 * standard deviation for each.
12 * This class should be used when any type of ModelComponent using Queues
13 * is created. In combination with class QueueList an automatic insert/remove
14 * mechanism including search functionality with condition checking
15 * can be set up within a few lines of code. It also provides full
16 * automatic statistical data about the Queue used.
17 * @author Tim Lechler
18 * @author modified by Soenke Claassen
19 * @see QueueList
20 *
21 * @version DESMO-J, Ver. 1.5 copyright (c) 2001 licensed under GNU GPL
22 */
23 public abstract class QueueBased extends desmoj.Reportable {
24
25 /**
26 * Represents the value returned if for a given statistics no valid value
27 * can be returned.
28 */
29 public static final double UNDEFINED = -1;
30
31 /**
32 * Displays the current number of objects waiting inside the queue.
33 */
34 private int currentLength;
35
36 /**
37 * Flag for letting the underlying queue implementation (<code>QueueList</code>)
38 * show own warnings (<code>true</code>) or suppressing
39 * them (<code>false</code>).
40 * Is <code>false</code> by default but can be set to <code>true</code> for
41 * debugging purposes
42 */
43 private boolean qImpWarnings;
44
45 /**
46 * Displays the minimum number of objects that have been waiting inside
47 * the queue since the last reset.
48 */
49 private int minimumLength;
50
51 /**
52 * Displays the maximum number of objects that have been waiting inside
53 * the queue since the last reset.
54 */
55 private int maximumLength;
56
57 /**
58 * Displays the number of objects that have passed the queue without
59 * waiting time. Thus the name "zeros" for zero waiting time.
60 * Value is valid for the span of time since the last reset.
61 */
62 private long zeros;
63
64 /**
65 * Displays the sum of the queue length weighted over the time each
66 * object spent waiting in the queue.
67 * Value is valid for the span of time since the last reset.
68 */
69 private double wSumLength;
70
71 /**
72 * Displays the squares of the sums of the queue length weighted over
73 * the time each object spent waiting in the queue.
74 * Value is valid for the span of time since the last reset.
75 */
76 private double wSumSquareLength;
77
78 /**
79 * The point in simulation time the queue was last accessed.
80 * Value is valid for the span of time since the last reset.
81 */
82 private SimTime lastAcc;
83
84 /**
85 * The point in simulation time the queue's minimum length was recorded.
86 * Value is valid for the span of time since the last reset.
87 */
88 private SimTime minimumLengthAt;
89
90 /**
91 * The point in simulation time the queue's maximum length was recorded.
92 * Value is valid for the span of time since the last reset.
93 */
94 private SimTime maximumLengthAt;
95
96 /**
97 * The maximum time an object inside the queue spent waiting.
98 * Value is valid for the span of time since the last reset.
99 */
100 private SimTime maximumWaitTime;
101
102 /**
103 * The point in simulation time the maximum waiting time of an object inside
104 * the queue was recorded at.
105 * Value is valid for the span of time since the last reset.
106 */
107 private SimTime maximumWaitTimeAt;
108
109 /**
110 * The sum of the waiting times spent by all objects that have passed through
111 * the queue.
112 * Value is valid for the span of time since the last reset.
113 */
114 private SimTime sumWaitTime;
115
116 /**
117 * The square of the sums of the waiting times spent by all objects that
118 * have passed through the queue.
119 * Value is valid for the span of time since the last reset.
120 */
121 private SimTime sumSquareWaitTime;
122
123 /**
124 * Defining a constant for the service discipline of the underlying queue.
125 * FIFO = First In First Out.
126 */
127 public final static int FIFO = 0;
128
129 /**
130 * Defining a constant for the service discipline of the underlying queue.
131 * LIFO = Last In First Out.
132 */
133 public final static int LIFO = 1;
134
135 /**
136 * Represents the maximum number of entities in the queue (default is
137 * unlimited capacity).
138 */
139 protected int queueLimit = Integer.MAX_VALUE;
140
141 /**
142 * An array representing the possible queueing strategies as implemented
143 * in the QueueListFifo and QueueListLifo classes. If new queueing
144 * strategies are added later on, they must be declared here also.
145 */
146 protected java.lang.Class[] queueingStrategy =
147 new Class[] {desmoj.QueueListFifo.class, desmoj.QueueListLifo.class};
148
149 /**
150 * Creates a queuebased object and initializes all statistical counters.
151 * If this standard constructor is used a queue with Fifo sort order and
152 * no limited capacity will be created.
153 * @param owner desmoj.Model : The model it belongs to
154 * @param name java.lang.String : The name for this QueueBased object
155 * @param showInReport boolean : Flag if values are shown in report
156 * @param showInTrace boolean : Flag if QueueBased writes trace messages
157 */
158 public QueueBased(desmoj.Model owner, String name,
159 boolean showInReport, boolean showInTrace) {
160
161 super(owner, name, showInReport, showInTrace); // create reportable
162
163 // initialize all statistics
164 currentLength = 0; // no one in here at starting time
165 lastAcc = currentTime(); // time of last access is now
166 minimumLength = currentLength;
167 maximumLength = currentLength;
168 zeros = 0;
169 wSumLength = 0;
170 wSumSquareLength = 0;
171 sumWaitTime = sumSquareWaitTime // reset points of simulation time
172 = maximumWaitTime
173 = maximumWaitTimeAt
174 = minimumLengthAt
175 = maximumLengthAt = new SimTime(0);
176
177 qImpWarnings = false; // no queue implementation warnings
178
179 }
180 /**
181 * Updates the statistics when a new element is inserted into the underlying
182 * queue.
183 * Note that this method must always be called whenever an insertion is
184 * made. If class <code>QueueList</code> is used in combination with a
185 * queuebased, this method gets called automatically whenever a new entity
186 * is inserted.
187 * @see QueueList
188 * @see QueueListFifo
189 * @see QueueListLifo
190 */
191 protected void addItem() {
192
193 updateStatistics();
194 currentLength++;
195
196 if ( currentLength > maximumLength ) { // do we have a new record high?
197 maximumLength = currentLength; // yes, store the record length
198 maximumLengthAt = currentTime(); // and write down the time for it
199 }
200
201 }
202 /**
203 * Returns the average length of the underlying queue since the last reset.
204 * Current length of that queue will be returned, if the time span since
205 * the last reset is smaller than the smallest distinguishable timespan
206 * epsilon.
207 * @return double : The average queue length since last reset or current length
208 * of queue if no distinguishable periode of time has passed
209 */
210 public double averageLength() {
211
212 SimTime now = currentTime(); // store current time
213 SimTime deltaTime = SimTime.diff(now, resetAt()); // time since last reset
214
215 // calculate the average length
216 double avgLength = (wSumLength +
217 ( currentLength * (now.getTimeValue() - lastAcc.getTimeValue())))
218 / deltaTime.getTimeValue(); // not nice to read, but it really does
219 // calculate the average!!!
220
221 // round the average length
222 double rndAvgLength = java.lang.Math.rint( 100000 * avgLength )
223 / 100000;
224 // return the rounded average length
225 if ( SimTime.isSmaller(deltaTime, epsilon())) // is delta too small?
226 return UNDEFINED; // value is not defined
227 else
228 {
229 return rndAvgLength;
230 }
231 }
232 /**
233 * Returns the average waiting time of all objects who have exited the queue.
234 * Value is valid for the time span since the last reset.
235 * Returns 0 (zero) if no objects have exited the queue after the last reset.
236 * @return SimTime : Average waiting time of all objects since last reset
237 * or 0 if no objects have exited the queue
238 */
239 public SimTime averageWaitTime() {
240
241 double obs = getObservations(); // get and store number of observations
242
243 // calculate the resulting average wait time and round it
244 double avgWaitTime = java.lang.Math.rint(100000 *
245 (sumWaitTime.getTimeValue()
246 / obs)
247 )
248 / 100000;
249 // return rounded average wait time
250 if ( obs > 0 ) return new SimTime( avgWaitTime );
251 else return new SimTime(0); // no observations -> zero SimTime value
252
253 }
254 /**
255 * Creates the reporter qualified to produce a report about a class
256 * that has been derived from queuebased.
257 * This method is declared abstract since no real queuebased is supposed to be
258 * instantiated and thus no rReporter can be defined here.
259 * Implement this method in the subclasses of queuebased such as in class
260 * Queue.
261 * @see Queue
262 */
263 public abstract desmoj.report.Reporter createReporter() ;
264 /**
265 * Updates the statistics when a new element is exiting the underlying queue.
266 * Note that this method must always be called whenever an object is
267 * taken from the queue. The simulation time parameter given provides the
268 * statistics with the information about the point of time the exiting object
269 * had enterd this queue. This is needed to calculate the waiting times.
270 * If a queuebased is used in conjunction with class queuelist,
271 * this method is automatically called whenever an entity is taken from
272 * the queuelist to keep track of
273 * @param entryTime SimTime : Point of simulation time that the object
274 * now exiting the queuebased had entered it
275 */
276 protected void deleteItem(SimTime entryTime) {
277
278 updateStatistics();
279 SimTime now = currentTime(); // Store the actual simulation time
280 SimTime waitTime = SimTime.diff(now, entryTime); // time waited in queue
281 sumWaitTime = SimTime.add(sumWaitTime, waitTime); // update sum
282
283 // calculate square of waitTimes and
284 sumSquareWaitTime = new SimTime( sumSquareWaitTime.getTimeValue()
285 + ( waitTime.getTimeValue() * waitTime.getTimeValue())) ;
286
287 if ( SimTime.isLarger( waitTime, maximumWaitTime ) ) // do we have a new waiting record?
288 {
289 maximumWaitTime = waitTime; // store new record
290 maximumWaitTimeAt = now; // and the moment it happened
291 }
292
293 if ( SimTime.isSmaller( waitTime, epsilon() ) ) { // no recognizable timespan
294 zeros++;
295 }
296
297 if ( currentLength <= 0 ) {
298 sendWarning("Inconsistent Qeueue length",
299 "QueueBased : "
300 +getName()+" Method: void activateAfter(SimTime dt)",
301 "Error in Statistic operations of Queues",
302 "Report information to DESMO-J designer Tim Lechler via eMail : "+
303 "1lechler@informatik.uni-hamburg.de");
304 return; // bad stuff ?? We got more objects in the queue than registered!!!
305 }
306
307 currentLength--;
308
309 if ( currentLength < minimumLength ) {
310 minimumLength = currentLength;
311 }
312
313 incrementObservations();
314 }
315 /**
316 * Returns the maximum possible number of entities in the underlying queue.
317 * @return int : the maximum number of entities in the queue.
318 */
319 public int getQueueLimit() {
320 return queueLimit;
321 }
322 /**
323 * Returns the current length of the underlying queue.
324 * @return int : The current queue length
325 */
326 public int length() {
327
328 return currentLength;
329
330 }
331 /**
332 * Returns the maximum length of the underlying queue since the last reset.
333 * @return int : The maximum queue length since last reset
334 */
335 public int maxLength() {
336
337 return maximumLength;
338
339 }
340 /**
341 * Returns the point of simulation time with the maximum number of objects
342 * waiting inside the underlying queue.
343 * The value is valid for the period since the last reset.
344 * @return desmoj.SimTime : Point of time with maximum queue length since last
345 * reset
346 */
347 public SimTime maxLengthAt() {
348
349 return maximumLengthAt;
350
351 }
352 /**
353 * Returns the maximum duration in simulation time that an object has
354 * spent waiting inside the underlying queue.
355 * The value is valid for the period since the last reset.
356 * @return desmoj.SimTime : Longest waiting time of an object in the queue
357 * since last reset
358 */
359 public SimTime maxWaitTime() {
360
361 return maximumWaitTime;
362
363 }
364 /**
365 * Returns the point of simulation time when the object with the maximum
366 * waiting time exited the underlying queue.
367 * The value is valid for the period since the last reset.
368 * @return desmoj.SimTime : The point of simulation time when the object with the maximum
369 * waiting time exited the queue
370 */
371 public SimTime maxWaitTimeAt() {
372
373 return maximumWaitTimeAt;
374
375 }
376 /**
377 * Returns the minimumn length of the underlying queue since the last reset.
378 * @return int : The minimum queue length since last reset
379 */
380 public int minLength() {
381
382 return minimumLength;
383
384 }
385 /**
386 * Returns the point of simulation time with the minimum number of objects
387 * waiting inside the underlying queue.
388 * The value is valid for the period since the last reset.
389 * @return desmoj.SimTime : Point of time with minimum queue length since last
390 * reset
391 */
392 public SimTime minLengthAt() {
393
394 return minimumLengthAt;
395
396 }
397 /**
398 * Returns a boolean flag telling if the underlying queue implementation
399 * should issue own warnings or not. The warnings from the queue implementation
400 *(<code>QueueList</code>) are needed for debugging purposes.
401 * @return boolean : Is <code>true</code> if the underlying queue
402 * implementation should issue warnings, <code>false</code> otherwise
403 */
404 boolean qImpWarn() {
405
406 return qImpWarnings;
407
408 }
409 /**
410 * Resets all statistical counters to their default values. The mininum and
411 * maximum length of the queue are set to the current number of queued objects.
412 */
413 public void reset() {
414
415 super.reset(); // reset of Reportable
416
417 lastAcc = currentTime(); // time of last access is now
418 minimumLength = currentLength;
419 maximumLength = currentLength;
420 zeros = 0;
421 wSumLength = 0;
422 wSumSquareLength = 0;
423 sumWaitTime = sumSquareWaitTime // reset points of simulation time
424 = maximumWaitTime
425 = maximumWaitTimeAt
426 = minimumLengthAt
427 = maximumLengthAt = new SimTime(0);
428
429 }
430 /**
431 * Method switches on warnings issued from the underlying queue
432 * implementation if parameter given is <code>true</code>.
433 * Warnings are suppressed if <code>false</code> is given.
434 * This method is used for internal debugging only.
435 * @param warnFlag boolean : <code>true</code> switches warnings on,
436 * <code>false</code> switches warnings off
437 */
438 public void setQueueImpWarning(boolean warnFlag) {
439
440 qImpWarnings = warnFlag;
441
442 }
443 /**
444 * Returns the standard deviation of the queue's length.
445 * Value is weighted over time.
446 * @return double : The standard deviation for the queue's length weighted over
447 * time
448 */
449 public double stdDevLength() {
450
451 SimTime now = currentTime(); // store current time
452 SimTime deltaTime = SimTime.diff(now, resetAt()); // time since last reset
453
454 if ( SimTime.isSmaller(deltaTime, epsilon())) // is delta too small?
455 return UNDEFINED; // no valid data
456 else {
457 double len = (double)currentLength; // store and convert length
458 double mean = averageLength(); // get mean for queuelength
459 SimTime span = SimTime.diff(now, lastAcc); // time span since last access
460
461 return java.lang.Math.sqrt(
462 java.lang.Math.abs(
463 (wSumSquareLength + (len * len * span.getTimeValue()))
464 / deltaTime.getTimeValue() - ( mean * mean )));
465 }
466
467 }
468 /**
469 * Returns the standard deviation of the queue's objects waiting times.
470 * @return double : The standard deviation for the queue's objects waiting
471 * times
472 */
473 public SimTime stdDevWaitTime() {
474
475 if ( getObservations() > 0 ) {
476 double mean = averageWaitTime().getTimeValue(); // get avrg time
477 double obs = (double)getObservations(); // number of obs exited
478
479 return new SimTime ( java.lang.Math.sqrt( // not nice but functual
480 java.lang.Math.abs(
481 ((obs * sumSquareWaitTime.getTimeValue())
482 - ( mean * mean ))
483 / ( obs * (obs - 1.0 ) ))) ); // as simple as that
484 }
485 else return new SimTime(0); // no observations -> no values
486
487 }
488 /**
489 * Updates the parts of the statistics used by both addItem and deleteItem.
490 */
491 protected void updateStatistics() {
492
493 SimTime now = currentTime(); // store current time
494 SimTime deltaTime = SimTime.diff( now, lastAcc ); // get time since last xs
495 wSumLength += currentLength * deltaTime.getTimeValue(); // weighted length sum
496 wSumSquareLength += currentLength * currentLength
497 * deltaTime.getTimeValue(); // weighted square length sum
498 lastAcc = now;
499
500 }
501 /**
502 * Returns the number of objects that have passed through the queue without
503 * spending time waiting.
504 * @return long : The number of elements who have passed the queue without
505 * waiting
506 */
507 public long zeroWaits() {
508
509 return zeros;
510
511 }
512 }