SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
Henriksen.java
1/*
2 * Class: Henriksen
3 * Description: implementation of class EventList using the doubly-linked
4 indexed list of Henriksen
5 * Environment: Java
6 * Software: SSJ
7 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
8 * Organization: DIRO, Universite de Montreal
9 * @author
10 * @since
11 *
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *
25 */
26package umontreal.ssj.simevents.eventlist;
27
28import java.util.Iterator;
29import java.util.ListIterator;
30import java.util.ConcurrentModificationException;
31import java.util.NoSuchElementException;
32import umontreal.ssj.util.PrintfFormat;
33import umontreal.ssj.simevents.Event;
34
44public class Henriksen implements EventList {
45 /*
46 * Fonctionnement de l'algorithme :
47 *
48 * On maintient une liste doublement chainee contenant les evenements. Les deux
49 * extremites de cette liste sont occupees par des bornes qui ont des temps qui
50 * ne peuvent pas etre depasses.
51 *
52 * Au-dessus de cette liste se retrouve un index (trie en ordre decroissant) qui
53 * contient des pointeurs vers certaines des entrees de la liste chainee. Le
54 * premier element de l'index est toujours la borne superieure. On se sert de
55 * cet index pour faire des recherches binaires pour retrouver rapidement un
56 * element dans la liste. On fait d'abord une recherche binaire dans l'index
57 * avant de faire une recherche lineaire dans la liste. On compte aussi le
58 * nombre d'elements qui doivent etre parcourus dans la recherche lineaire. Si
59 * ce nombre atteint une certaine valeur (4 dans cette implantation), alors on
60 * fait en sorte qu'un element de l'index pointe vers l'element de la liste que
61 * l'on parcourt. Ceci permet un certain balancement des elements presents dans
62 * l'index, et donc une meilleure efficacite de la recherche binaire sans avoir
63 * a mettre tous les elements dans l'index.
64 */
65
66 private static final double MIN_VALUE = -10E38; // n'importe quoi < 0
67 private static final double MAX_VALUE = 10E38; // le plus gros possible
68
69 private static final int ARRAY_LENGTH_INIT = 256;
70
71 private int modCount = 0;
72
73 private Entry firstEntry;
74
75 // for the binary search
76 private Entry[] entryVec;
77
78 private int vectSize;
79 private int arrayLength;
80
81 public Henriksen() {
82 // creation des bornes
83 Entry lastEntry = new Entry(null, null, null, MAX_VALUE);
84 firstEntry = new Entry(null, null, lastEntry, MIN_VALUE);
85 lastEntry.left = firstEntry;
86
87 arrayLength = ARRAY_LENGTH_INIT;
88 entryVec = new Entry[arrayLength];
89
90 changeSize(1);
91 entryVec[0] = lastEntry;
92 }
93
94 public boolean isEmpty() {
95 return firstEntry.right == entryVec[0];
96 }
97
98 public void clear() {
99 if (isEmpty())
100 return;
101
102 firstEntry.right = entryVec[0];
103 entryVec[0].left = firstEntry;
104 changeSize(1);
105
106 // on enleve tous les liens menant aux entrees supprimees :
107 for (int i = 1; i < arrayLength; i++)
108 entryVec[i] = null;
109
110 modCount++;
111 }
112
113 public void add(Event ev) {
114 Entry prec = findEntry(ev, false);
115
116 Entry e = new Entry(ev, prec, prec.right, ev.time());
117 e.right.left = e;
118 prec.right = e;
119 modCount++;
120 }
121
122 public void addFirst(Event ev) {
123 Entry e = new Entry(ev, firstEntry, firstEntry.right, ev.time());
124 firstEntry.right.left = e;
125 firstEntry.right = e;
126
127 modCount++;
128 }
129
130 public void addBefore(Event ev, Event other) {
131 Entry otherEntry = findEntry(other, true);
132 if (otherEntry == null)
133 throw new IllegalArgumentException("Event not in list.");
134 Entry e = new Entry(ev, otherEntry.left, otherEntry, ev.time());
135 otherEntry.left.right = e;
136 otherEntry.left = e;
137
138 modCount++;
139 }
140
141 public void addAfter(Event ev, Event other) {
142 Entry otherEntry = findEntry(other, true);
143 if (otherEntry == null)
144 throw new IllegalArgumentException("Event not in list.");
145 Entry e = new Entry(ev, otherEntry, otherEntry.right, ev.time());
146 otherEntry.right.left = e;
147 otherEntry.right = e;
148
149 modCount++;
150 }
151
152 public Event getFirst() {
153 return firstEntry.right.event;
154 }
155
156 public Event getFirstOfClass(String cl) {
157 Entry e = firstEntry.right;
158 while (e.right != null) {
159 if (e.event.getClass().getName().equals(cl))
160 return e.event;
161 e = e.right;
162 }
163 return null;
164 }
165
166 @SuppressWarnings("unchecked")
167
168 public <E extends Event> E getFirstOfClass(Class<E> cl) {
169 Entry e = firstEntry.right;
170 while (e.right != null) {
171 if (e.event.getClass() == cl)
172 return (E) e.event;
173 e = e.right;
174 }
175 return null;
176 }
177
178 public Iterator<Event> iterator() {
179 return listIterator();
180 }
181
182 public ListIterator<Event> listIterator() {
183 return new HItr();
184 }
185
186 public boolean remove(Event ev) {
187 Entry e = findEntry(ev, true);
188 if (e == null)
189 return false;
190
191 // on l'enleve de l'index
192 int i = findIndex(ev.time());
193 i++;
194
195 while (i < vectSize && entryVec[i].event != null && ev.compareTo(entryVec[i].event) == 0) {
196 if (entryVec[i].event == ev)
197 entryVec[i] = e.left;
198
199 i++;
200 }
201
202 // on l'enleve de la liste
203 e.left.right = e.right;
204 e.right.left = e.left;
205 e.right = null;
206 e.left = null;
207 e.event = null;
208
209 modCount++;
210
211 return true;
212 }
213
215 // si la premiere moitie de l'index est composee d'entrees perimees,
216 // on coupe de moitie l'index
217 if (entryVec[vectSize / 2].time <= firstEntry.right.time && vectSize > 1)
218 changeSize(vectSize / 2);
219
220 Entry e = firstEntry.right;
221
222 // borne superieure
223 if (e == entryVec[0])
224 return null;
225
226 firstEntry.right = e.right;
227 e.right.left = firstEntry;
228
229 e.right = null;
230 e.left = null;
231
232 Event ev = e.event;
233 e.event = null;
234
235 modCount++;
236
237 return ev;
238 }
239
240 public String toString() {
241 StringBuilder sb = new StringBuilder("Contents of the event list Henriksen:");
242 Entry e = firstEntry.right;
243 while (e.right != null) {
244 sb.append(PrintfFormat.NEWLINE + PrintfFormat.g(12, 7, e.event.time()) + ", "
245 + PrintfFormat.g(8, 4, e.event.priority()) + " : " + e.event.toString());
246 e = e.right;
247 }
248 return sb.toString();
249 }
250
251 private static class Entry {
252 public Event event;
253 public Entry left;
254 public Entry right;
255 public double time;
256
257 Entry(Event event, Entry left, Entry right, double time) {
258 this.event = event;
259 this.left = left;
260 this.right = right;
261 this.time = time;
262 }
263
264 public String toString() {
265 return "[" + event + " |" + time + "|]";
266 }
267 }
268
269 private class HItr implements ListIterator<Event> {
270 private Entry prev;
271 private Entry next;
272 private Entry lastRet;
273 private int expectedModCount;
274 private int nextIndex;
275
276 private HItr() {
277 prev = firstEntry;
278 next = firstEntry.right;
279 expectedModCount = modCount;
280 lastRet = null;
281 nextIndex = 0;
282 }
283
284 public void add(Event ev) {
285 if (modCount != expectedModCount)
286 throw new ConcurrentModificationException();
287
288 // make sure the time is in the right order
289 if (ev.time() > next.time) {
290 ev.setTime(next.time);
291 ev.setPriority(next.event.priority());
292 }
293 if (ev.time() < prev.time) {
294 ev.setTime(prev.time);
295 ev.setPriority(prev.event.priority());
296 }
297
298 Entry e = new Entry(ev, prev, next, ev.time());
299 prev.right = e;
300 next.left = e;
301 prev = e;
302
303 nextIndex++;
304 lastRet = null;
305 modCount++;
306 expectedModCount++;
307 }
308
309 public boolean hasNext() {
310 if (modCount != expectedModCount)
311 throw new ConcurrentModificationException();
312 return next != entryVec[0];
313 }
314
315 public boolean hasPrevious() {
316 if (modCount != expectedModCount)
317 throw new ConcurrentModificationException();
318 return next != firstEntry;
319 }
320
321 public Event next() {
322 if (!hasNext())
323 throw new NoSuchElementException();
324
325 nextIndex++;
326 Event ev = next.event;
327 lastRet = next;
328 next = next.right;
329 prev = prev.right;
330 return ev;
331 }
332
333 public int nextIndex() {
334 if (!hasNext())
335 throw new NoSuchElementException();
336
337 return nextIndex;
338 }
339
340 public Event previous() {
341 if (!hasPrevious())
342 throw new NoSuchElementException();
343
344 nextIndex--;
345 Event ev = prev.event;
346 lastRet = prev;
347 prev = prev.left;
348 next = next.left;
349 return ev;
350 }
351
352 public int previousIndex() {
353 if (!hasPrevious())
354 throw new NoSuchElementException();
355
356 return nextIndex - 1;
357 }
358
359 public void remove() {
360 if (modCount != expectedModCount)
361 throw new ConcurrentModificationException();
362 if (lastRet == null)
363 throw new IllegalStateException();
364
365 if (lastRet == next) { // last call was to previous, not next
366 if (next != entryVec[0])
367 next = next.right;
368 } else { // last call was to next or nothing
369 if (prev != firstEntry) {
370 prev = prev.left;
371 nextIndex--;
372 }
373 }
374
375 // remove the deleted entry in the vector
376 double evtime = lastRet.time;
377 int i = findIndex(evtime);
378 i++;
379
380 while (i < vectSize && entryVec[i].time == evtime) {
381 if (entryVec[i].event == lastRet.event)
382 entryVec[i] = lastRet.left;
383 i++;
384 }
385
386 lastRet.event = null;
387 lastRet.left.right = lastRet.right;
388 lastRet.right.left = lastRet.left;
389 lastRet.left = null;
390 lastRet.right = null;
391 lastRet = null;
392 modCount++;
393 expectedModCount++;
394 }
395
396 public void set(Event ev) {
397 if (modCount != expectedModCount)
398 throw new ConcurrentModificationException();
399 if (lastRet == null)
400 throw new IllegalStateException();
401
402 // Check for a good time
403 if (ev.time() < lastRet.left.time) {
404 ev.setTime(lastRet.left.time);
405 ev.setPriority(lastRet.left.event.priority());
406 }
407 if (ev.time() > lastRet.right.time) {
408 ev.setTime(lastRet.right.time);
409 ev.setPriority(lastRet.right.event.priority());
410 }
411
412 lastRet.event = ev;
413 }
414 }
415
416 /*
417 * On change la taille de l'index. Le changement de taille se fait du cote des
418 * entrees de temps inferieures. Ces entrees se retrouvent a la fin de l'index
419 * pour simplifier ce travail.
420 */
421 private void changeSize(int newSize) {
422 // si on grossit le vecteur reel
423 if (newSize > arrayLength) {
424 Entry[] newVec = new Entry[newSize];
425 for (int i = 0; i < vectSize; i++)
426 newVec[i] = entryVec[i];
427 entryVec = newVec;
428 arrayLength = newSize;
429 }
430
431 // les nouveaux emplacements sont remplis par la borne min
432 for (int i = vectSize; i < newSize; i++)
433 entryVec[i] = firstEntry;
434
435 vectSize = newSize;
436 }
437
438 /*
439 * Fait une recherche binaire a l'interieur de l'index pour trouve l'entree dans
440 * l'index qui a la plus petite valeur de temps, mais dont la valeur est
441 * superieure a evtime. Les entrees sont triees en ordre inverse dans l'index,
442 * pour simplifie le changement de taille de l'index.
443 */
444 private int findIndex(double evtime) {
445 int i = vectSize / 2;
446 int j = vectSize / 4;
447
448 // recherche binaire dans le vecteur d'index
449 while (j > 0) {
450 // note : entryVec est trie a l'envers
451 if (evtime >= entryVec[i].time)
452 i -= j;
453 else
454 i += j;
455 j /= 2;
456 }
457
458 if (evtime >= entryVec[i].time)
459 i--;
460
461 return i;
462 }
463
464 /*
465 * Si findEvent est false, trouve la derniere entree qui a un temps egal ou
466 * inferieur au temps de l'evenement ev. Sinon, trouve l'entree contenant ev
467 * dans la liste.
468 */
469 private Entry findEntry(Event ev, boolean findEvent) {
470 double evtime = ev.time();
471 int i = findIndex(evtime);
472
473 Entry e = entryVec[i].left;
474 if (null == e)
475 return null;
476 int count = 0;
477
478 while (e.time >= evtime/* && e.event != null */ && ev.compareTo(e.event) < 0) {
479 ++count;
480 if (count == 4) {
481 // operation pull
482 if (i + 1 >= vectSize)
483 changeSize(vectSize * 2);
484
485 i++;
486 count = 0;
487 entryVec[i] = e;
488 }
489
490 e = e.left;
491 }
492
493 if (findEvent) {
494 // on cherche l'evenement identique
495 // Entry start = e;
496 while (e != firstEntry && e.time == evtime && e.event != ev)
497 e = e.left;
498 // on ne l'a pas trouve
499 if (e.event != ev)
500 return null;
501 }
502 return e;
503 }
504
505}
This abstract class provides event scheduling tools.
Definition Event.java:53
final double time()
Returns the (planned) time of occurence of this event.
Definition Event.java:279
ListIterator< Event > listIterator()
Returns a list iterator over the elements of the class Event in this list.
void addFirst(Event ev)
Adds a new event at the beginning of the event list.
boolean isEmpty()
Returns true if and only if the event list is empty (no event is scheduled).
void addBefore(Event ev, Event other)
Same as add, but adds the new event ev immediately before the event other in the list.
void addAfter(Event ev, Event other)
Same as add, but adds the new event ev immediately after the event other in the list.
Event removeFirst()
Removes the first event from the event list (to cancel or execute this event).
void clear()
Empties the event list, i.e., cancels all events.
Event getFirst()
Returns the first event in the event list.
Event getFirstOfClass(String cl)
Returns the first event of the class cl (a subclass of Event) in the event list.
void add(Event ev)
Adds a new event in the event list, according to the time of ev.
This class acts like a StringBuffer which defines new types of append methods.
static final String NEWLINE
End-of-line symbol or line separator.
static String g(double x)
Same as g(0, 6, x).
An interface for implementations of event lists.