1 | package desmoj.core.simulator; |
2 | |
3 | import java.util.Random; |
4 | |
5 | /** |
6 | * A specialized Event vector providing random order for concurrent Event notes. |
7 | * Random order is achieved by computing a random insert position within the |
8 | * range of simultaneous (concurrent) events. Existing connections between |
9 | * events are maintained, i.e. a new event-note will never be inserted between |
10 | * two connected event-notes. Connections are only possible between to |
11 | * successive concurrent Event notes where one of the notes was inserted by call |
12 | * of the insertBefore() or the insertAfter() method. Most of the methods |
13 | * inherited from the super class |
14 | * {@link desmoj.core.simulator.EventVectorList EventVector}are only overwritten to |
15 | * keep track of the existing connections. |
16 | * |
17 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
18 | * @author Ruth Meyer |
19 | * |
20 | * Licensed under the Apache License, Version 2.0 (the "License"); |
21 | * you may not use this file except in compliance with the License. You |
22 | * may obtain a copy of the License at |
23 | * http://www.apache.org/licenses/LICENSE-2.0 |
24 | * |
25 | * Unless required by applicable law or agreed to in writing, software |
26 | * distributed under the License is distributed on an "AS IS" |
27 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
28 | * or implied. See the License for the specific language governing |
29 | * permissions and limitations under the License. |
30 | * |
31 | */ |
32 | public class RandomizingEventVector extends EventVectorList { |
33 | |
34 | // ------------------------------------------------------------------- |
35 | // Fields |
36 | |
37 | /** the random position generator. */ |
38 | private Random _positionGenerator; |
39 | |
40 | // ------------------------------------------------------------- |
41 | // Constructors |
42 | |
43 | /** |
44 | * Constructs a new randomizing Event vector. Initializes the event vector |
45 | * and the random position generator. |
46 | */ |
47 | public RandomizingEventVector() { |
48 | super(); |
49 | _positionGenerator = new Random(); |
50 | } |
51 | |
52 | // ------------------------------------------------------------------ |
53 | // Methods |
54 | |
55 | /** |
56 | * Inserts the given new event-note directly before the specified Event |
57 | * note. Registers <code>where</code> as connected to <code>newNote</code>. |
58 | * |
59 | * @param where : |
60 | * the event-note before which the new note shall be inserted |
61 | * @param newNote : |
62 | * the new event-note to be inserted |
63 | */ |
64 | void insertBefore(EventNote where, EventNote newNote) { |
65 | super.insertBefore(where, newNote); |
66 | // insertBefore means a "backward" connection: newNote is connected to |
67 | // its successor where |
68 | // this is translated to the "forward" connection: where is connected to |
69 | // its predecessor newNote |
70 | int i = this.eVector.indexOf(where); |
71 | if (i >= 0) |
72 | where.setConnected(true); |
73 | } |
74 | |
75 | /** |
76 | * Inserts the given new event-note directly behind the specified Event |
77 | * note. Registers <code>newNote</code> as connected to <code>where</code>. |
78 | * |
79 | * @param where : |
80 | * the event-note after which the new note shall be inserted |
81 | * @param newNote : |
82 | * the new event-note to be inserted |
83 | */ |
84 | void insertAfter(EventNote where, EventNote newNote) { |
85 | super.insertAfter(where, newNote); |
86 | // insertAfter means a "forward" connection: newNote is connected to its |
87 | // predecessor where |
88 | int i = this.eVector.indexOf(newNote); |
89 | if (i >= 0) |
90 | newNote.setConnected(true); |
91 | } |
92 | |
93 | /** |
94 | * Inserts the given event-note at the front of the event vector. |
95 | * |
96 | * @param newNote |
97 | * EventNote : the new event-note to be inserted as first note. |
98 | */ |
99 | void insertAsFirst(EventNote newNote) { |
100 | super.insertAsFirst(newNote); |
101 | newNote.setConnected(false); |
102 | } |
103 | |
104 | /** |
105 | * Inserts the given event-note at the back of the event vector. |
106 | * |
107 | * @param newNote |
108 | * EventNote : the new event-note to be inserted as last note. |
109 | */ |
110 | void insertAsLast(EventNote newNote) { |
111 | super.insertAsLast(newNote); |
112 | newNote.setConnected(false); |
113 | } |
114 | |
115 | /** |
116 | * Removes the given note from the event vector. |
117 | * A connection between the note's previous and next note |
118 | * is established if and only if the given note was |
119 | * connnect to both the previous and next node. |
120 | * |
121 | * @param note |
122 | * EventNote : the event-note to be removed |
123 | */ |
124 | void remove(EventNote note) { |
125 | int i = this.eVector.indexOf(note); |
126 | if (i >= 0) { |
127 | EventNote prev = this.prevNote(note); |
128 | EventNote next = this.nextNote(note); |
129 | if (prev != null && next != null) { |
130 | if (note.isConnected() && next.isConnected()) |
131 | next.setConnected(true); |
132 | else |
133 | next.setConnected(false); |
134 | } |
135 | super.remove(note); |
136 | } |
137 | } |
138 | |
139 | /** |
140 | * Removes the first event-note (if any). |
141 | */ |
142 | void removeFirst() { |
143 | if (!this.isEmpty()) { |
144 | super.removeFirst(); |
145 | if (this.isEmpty()) |
146 | this.firstNote().setConnected(false); |
147 | } |
148 | } |
149 | |
150 | /** |
151 | * Inserts the given event-note into the event vector. Overwrites the |
152 | * inherited insert() method to achieve random insert for concurrent Events. |
153 | * Takes possible connections between existing event-notes into account, |
154 | * i.e. will not insert the new note between connected events. Connections |
155 | * may only exist between two events of the same time where one of the |
156 | * events has been inserted via insertBefore() or insertAfter(). |
157 | * |
158 | * @param newNote |
159 | * EventNote : the event-note to be inserted |
160 | */ |
161 | //TODO: |
162 | void insert(EventNote newNote) { |
163 | if (isEmpty()) { |
164 | super.insert(newNote); |
165 | newNote.setConnected(false); |
166 | // notes inserted via insert() are not connected to other notes |
167 | return; // no need to continue |
168 | } |
169 | // use binary search to determine first event-note with same time |
170 | TimeInstant refTime = newNote.getTime(); |
171 | int firstIndexForInsert, lastIndexForInsert; |
172 | int left = 0; |
173 | int right = eVector.size(); |
174 | while (left < right) { |
175 | int middle = (left + right) / 2; |
176 | if (TimeInstant.isBefore(((EventNote) eVector.get(middle)).getTime(), |
177 | refTime)) { |
178 | left = middle + 1; |
179 | } else { |
180 | right = middle; |
181 | } |
182 | } |
183 | if (right < eVector.size() |
184 | && TimeInstant.isEqual(((EventNote) eVector.get(right)).getTime(), |
185 | refTime)) { |
186 | // same time found |
187 | firstIndexForInsert = right; |
188 | // look for last event-note with same time; last position to insert |
189 | // is AFTER last concurrent note |
190 | lastIndexForInsert = findLastIndex(firstIndexForInsert) + 1; |
191 | } else { |
192 | // same time not found, but right still holds the insert position |
193 | firstIndexForInsert = right; |
194 | lastIndexForInsert = firstIndexForInsert; |
195 | } |
196 | // do we need to generate a random insert position? |
197 | if (firstIndexForInsert != lastIndexForInsert) { |
198 | // yeah, so here we go |
199 | firstIndexForInsert += _positionGenerator.nextInt(lastIndexForInsert - firstIndexForInsert + 1); |
200 | // defer in case connection violated |
201 | while (firstIndexForInsert < this.eVector.size() && ((EventNote) eVector.get(firstIndexForInsert)).isConnected()) firstIndexForInsert++; |
202 | } |
203 | // at last do the actual inserting |
204 | this.eVector.add(firstIndexForInsert, newNote); |
205 | newNote.setConnected(false); |
206 | } |
207 | |
208 | /** |
209 | * This helper method determines the position of the last event-note with |
210 | * the same time as the event-note at position firstIndex doing a simple |
211 | * linear search from firstIndex. |
212 | */ |
213 | //TODO: |
214 | protected int findLastIndex(int firstIndex) { |
215 | TimeInstant refTime = ((EventNote) eVector.get(firstIndex)).getTime(); |
216 | int lastIndex = firstIndex + 1; |
217 | while (lastIndex < eVector.size() |
218 | && TimeInstant.isEqual(refTime, |
219 | ((EventNote) eVector.get(lastIndex)).getTime())) { |
220 | lastIndex++; |
221 | } |
222 | return lastIndex - 1; |
223 | } |
224 | |
225 | } /* end of class RandomizingEventVector */ |