diff options
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/UniquenessEnforcerNode.java')
-rw-r--r-- | subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/UniquenessEnforcerNode.java | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/UniquenessEnforcerNode.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/UniquenessEnforcerNode.java new file mode 100644 index 00000000..5bfde248 --- /dev/null +++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/UniquenessEnforcerNode.java | |||
@@ -0,0 +1,321 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2004-2008 Gabor Bergmann, Tamas Szabo and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | |||
10 | package tools.refinery.viatra.runtime.rete.single; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Map; | ||
14 | import java.util.Set; | ||
15 | |||
16 | import tools.refinery.viatra.runtime.matchers.context.IPosetComparator; | ||
17 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
18 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
19 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory; | ||
20 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
21 | import tools.refinery.viatra.runtime.matchers.util.IMultiset; | ||
22 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
23 | import tools.refinery.viatra.runtime.rete.index.MemoryIdentityIndexer; | ||
24 | import tools.refinery.viatra.runtime.rete.index.MemoryNullIndexer; | ||
25 | import tools.refinery.viatra.runtime.rete.index.ProjectionIndexer; | ||
26 | import tools.refinery.viatra.runtime.rete.network.PosetAwareReceiver; | ||
27 | import tools.refinery.viatra.runtime.rete.network.RederivableNode; | ||
28 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
29 | import tools.refinery.viatra.runtime.rete.network.communication.CommunicationGroup; | ||
30 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp; | ||
31 | import tools.refinery.viatra.runtime.rete.network.communication.timeless.RecursiveCommunicationGroup; | ||
32 | import tools.refinery.viatra.runtime.rete.network.mailbox.Mailbox; | ||
33 | import tools.refinery.viatra.runtime.rete.network.mailbox.timeless.BehaviorChangingMailbox; | ||
34 | import tools.refinery.viatra.runtime.rete.network.mailbox.timeless.PosetAwareMailbox; | ||
35 | |||
36 | /** | ||
37 | * Timeless uniqueness enforcer node implementation. | ||
38 | * <p> | ||
39 | * The node is capable of operating in the delete and re-derive mode. In this mode, it is also possible to equip the | ||
40 | * node with an {@link IPosetComparator} to identify monotone changes; thus, ensuring that a fix-point can be reached | ||
41 | * during the evaluation. | ||
42 | * | ||
43 | * @author Gabor Bergmann | ||
44 | * @author Tamas Szabo | ||
45 | * @noinstantiate This class is not intended to be instantiated by clients. | ||
46 | * @noextend This class is not intended to be subclassed by clients. | ||
47 | */ | ||
48 | public class UniquenessEnforcerNode extends AbstractUniquenessEnforcerNode | ||
49 | implements RederivableNode, PosetAwareReceiver { | ||
50 | |||
51 | protected IMultiset<Tuple> memory; | ||
52 | /** | ||
53 | * @since 1.6 | ||
54 | */ | ||
55 | protected IMultiset<Tuple> rederivableMemory; | ||
56 | /** | ||
57 | * @since 1.6 | ||
58 | */ | ||
59 | protected boolean deleteRederiveEvaluation; | ||
60 | |||
61 | /** | ||
62 | * @since 1.7 | ||
63 | */ | ||
64 | protected CommunicationGroup currentGroup; | ||
65 | |||
66 | public UniquenessEnforcerNode(final ReteContainer reteContainer, final int tupleWidth) { | ||
67 | this(reteContainer, tupleWidth, false); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * OPTIONAL ELEMENT - ONLY PRESENT IF MONOTONICITY INFO WAS AVAILABLE | ||
72 | * | ||
73 | * @since 1.6 | ||
74 | */ | ||
75 | protected final TupleMask coreMask; | ||
76 | /** | ||
77 | * OPTIONAL ELEMENTS - ONLY PRESENT IF MONOTONICITY INFO WAS AVAILABLE | ||
78 | * | ||
79 | * @since 1.6 | ||
80 | */ | ||
81 | protected final TupleMask posetMask; | ||
82 | /** | ||
83 | * OPTIONAL ELEMENTS - ONLY PRESENT IF MONOTONICITY INFO WAS AVAILABLE | ||
84 | * | ||
85 | * @since 1.6 | ||
86 | */ | ||
87 | protected final IPosetComparator posetComparator; | ||
88 | |||
89 | /** | ||
90 | * @since 1.6 | ||
91 | */ | ||
92 | public UniquenessEnforcerNode(final ReteContainer reteContainer, final int tupleWidth, | ||
93 | final boolean deleteRederiveEvaluation) { | ||
94 | this(reteContainer, tupleWidth, deleteRederiveEvaluation, null, null, null); | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * @since 1.6 | ||
99 | */ | ||
100 | public UniquenessEnforcerNode(final ReteContainer reteContainer, final int tupleWidth, | ||
101 | final boolean deleteRederiveEvaluation, final TupleMask coreMask, final TupleMask posetMask, | ||
102 | final IPosetComparator posetComparator) { | ||
103 | super(reteContainer, tupleWidth); | ||
104 | this.memory = CollectionsFactory.createMultiset(); | ||
105 | this.rederivableMemory = CollectionsFactory.createMultiset(); | ||
106 | reteContainer.registerClearable(this.memory); | ||
107 | reteContainer.registerClearable(this.rederivableMemory); | ||
108 | this.deleteRederiveEvaluation = deleteRederiveEvaluation; | ||
109 | this.coreMask = coreMask; | ||
110 | this.posetMask = posetMask; | ||
111 | this.posetComparator = posetComparator; | ||
112 | this.mailbox = instantiateMailbox(); | ||
113 | reteContainer.registerClearable(this.mailbox); | ||
114 | } | ||
115 | |||
116 | @Override | ||
117 | public void pullInto(final Collection<Tuple> collector, final boolean flush) { | ||
118 | for (final Tuple tuple : this.memory.distinctValues()) { | ||
119 | collector.add(tuple); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * @since 2.8 | ||
125 | */ | ||
126 | @Override | ||
127 | public Set<Tuple> getTuples() { | ||
128 | return this.memory.distinctValues(); | ||
129 | } | ||
130 | |||
131 | @Override | ||
132 | public boolean isInDRedMode() { | ||
133 | return this.deleteRederiveEvaluation; | ||
134 | } | ||
135 | |||
136 | @Override | ||
137 | public TupleMask getCoreMask() { | ||
138 | return coreMask; | ||
139 | } | ||
140 | |||
141 | @Override | ||
142 | public TupleMask getPosetMask() { | ||
143 | return posetMask; | ||
144 | } | ||
145 | |||
146 | @Override | ||
147 | public IPosetComparator getPosetComparator() { | ||
148 | return posetComparator; | ||
149 | } | ||
150 | |||
151 | @Override | ||
152 | public void pullIntoWithTimeline(final Map<Tuple, Timeline<Timestamp>> collector, final boolean flush) { | ||
153 | throw new UnsupportedOperationException("Use the timely version of this node!"); | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * @since 2.0 | ||
158 | */ | ||
159 | protected Mailbox instantiateMailbox() { | ||
160 | if (coreMask != null && posetMask != null && posetComparator != null) { | ||
161 | return new PosetAwareMailbox(this, this.reteContainer); | ||
162 | } else { | ||
163 | return new BehaviorChangingMailbox(this, this.reteContainer); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | @Override | ||
168 | public void update(final Direction direction, final Tuple update, final Timestamp timestamp) { | ||
169 | updateWithPosetInfo(direction, update, false); | ||
170 | } | ||
171 | |||
172 | @Override | ||
173 | public void updateWithPosetInfo(final Direction direction, final Tuple update, final boolean monotone) { | ||
174 | if (this.deleteRederiveEvaluation) { | ||
175 | if (updateWithDeleteAndRederive(direction, update, monotone)) { | ||
176 | propagate(direction, update, Timestamp.ZERO); | ||
177 | } | ||
178 | } else { | ||
179 | if (updateDefault(direction, update)) { | ||
180 | propagate(direction, update, Timestamp.ZERO); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * @since 2.4 | ||
187 | */ | ||
188 | protected boolean updateWithDeleteAndRederive(final Direction direction, final Tuple update, | ||
189 | final boolean monotone) { | ||
190 | boolean propagate = false; | ||
191 | |||
192 | final int memoryCount = memory.getCount(update); | ||
193 | final int rederivableCount = rederivableMemory.getCount(update); | ||
194 | |||
195 | if (direction == Direction.INSERT) { | ||
196 | // INSERT | ||
197 | if (rederivableCount != 0) { | ||
198 | // the tuple is in the re-derivable memory | ||
199 | rederivableMemory.addOne(update); | ||
200 | if (rederivableMemory.isEmpty()) { | ||
201 | // there is nothing left to be re-derived | ||
202 | // this can happen if the INSERT cancelled out a DELETE | ||
203 | ((RecursiveCommunicationGroup) currentGroup).removeRederivable(this); | ||
204 | } | ||
205 | } else { | ||
206 | // the tuple is in the main memory | ||
207 | propagate = memory.addOne(update); | ||
208 | } | ||
209 | } else { | ||
210 | // DELETE | ||
211 | if (rederivableCount != 0) { | ||
212 | // the tuple is in the re-derivable memory | ||
213 | if (memoryCount != 0) { | ||
214 | issueError("[INTERNAL ERROR] Inconsistent state for " + update | ||
215 | + " because it is present both in the main and re-derivable memory in the UniquenessEnforcerNode " | ||
216 | + this + " for pattern(s) " + getTraceInfoPatternsEnumerated(), null); | ||
217 | } | ||
218 | |||
219 | try { | ||
220 | rederivableMemory.removeOne(update); | ||
221 | } catch (final IllegalStateException ex) { | ||
222 | issueError( | ||
223 | "[INTERNAL ERROR] Duplicate deletion of " + update + " was detected in UniquenessEnforcer " | ||
224 | + this + " for pattern(s) " + getTraceInfoPatternsEnumerated(), | ||
225 | ex); | ||
226 | } | ||
227 | if (rederivableMemory.isEmpty()) { | ||
228 | // there is nothing left to be re-derived | ||
229 | ((RecursiveCommunicationGroup) currentGroup).removeRederivable(this); | ||
230 | } | ||
231 | } else { | ||
232 | // the tuple is in the main memory | ||
233 | if (monotone) { | ||
234 | propagate = memory.removeOne(update); | ||
235 | } else { | ||
236 | final int count = memoryCount - 1; | ||
237 | if (count > 0) { | ||
238 | if (rederivableMemory.isEmpty()) { | ||
239 | // there is now something to be re-derived | ||
240 | ((RecursiveCommunicationGroup) currentGroup).addRederivable(this); | ||
241 | } | ||
242 | rederivableMemory.addPositive(update, count); | ||
243 | } | ||
244 | memory.clearAllOf(update); | ||
245 | propagate = true; | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | return propagate; | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * @since 2.4 | ||
255 | */ | ||
256 | protected boolean updateDefault(final Direction direction, final Tuple update) { | ||
257 | boolean propagate = false; | ||
258 | if (direction == Direction.INSERT) { | ||
259 | // INSERT | ||
260 | propagate = memory.addOne(update); | ||
261 | } else { | ||
262 | // DELETE | ||
263 | try { | ||
264 | propagate = memory.removeOne(update); | ||
265 | } catch (final IllegalStateException ex) { | ||
266 | propagate = false; | ||
267 | issueError("[INTERNAL ERROR] Duplicate deletion of " + update + " was detected in " | ||
268 | + this.getClass().getName() + " " + this + " for pattern(s) " | ||
269 | + getTraceInfoPatternsEnumerated(), ex); | ||
270 | } | ||
271 | } | ||
272 | return propagate; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * @since 1.6 | ||
277 | */ | ||
278 | @Override | ||
279 | public void rederiveOne() { | ||
280 | final Tuple update = rederivableMemory.iterator().next(); | ||
281 | final int count = rederivableMemory.getCount(update); | ||
282 | rederivableMemory.clearAllOf(update); | ||
283 | memory.addPositive(update, count); | ||
284 | // if there is no other re-derivable tuple, then unregister the node itself | ||
285 | if (this.rederivableMemory.isEmpty()) { | ||
286 | ((RecursiveCommunicationGroup) currentGroup).removeRederivable(this); | ||
287 | } | ||
288 | propagate(Direction.INSERT, update, Timestamp.ZERO); | ||
289 | } | ||
290 | |||
291 | @Override | ||
292 | public ProjectionIndexer getNullIndexer() { | ||
293 | if (this.memoryNullIndexer == null) { | ||
294 | this.memoryNullIndexer = new MemoryNullIndexer(this.reteContainer, this.tupleWidth, | ||
295 | this.memory.distinctValues(), this, this, this.specializedListeners); | ||
296 | this.getCommunicationTracker().registerDependency(this, this.memoryNullIndexer); | ||
297 | } | ||
298 | return this.memoryNullIndexer; | ||
299 | } | ||
300 | |||
301 | @Override | ||
302 | public ProjectionIndexer getIdentityIndexer() { | ||
303 | if (this.memoryIdentityIndexer == null) { | ||
304 | this.memoryIdentityIndexer = new MemoryIdentityIndexer(this.reteContainer, this.tupleWidth, | ||
305 | this.memory.distinctValues(), this, this, this.specializedListeners); | ||
306 | this.getCommunicationTracker().registerDependency(this, this.memoryIdentityIndexer); | ||
307 | } | ||
308 | return this.memoryIdentityIndexer; | ||
309 | } | ||
310 | |||
311 | @Override | ||
312 | public CommunicationGroup getCurrentGroup() { | ||
313 | return currentGroup; | ||
314 | } | ||
315 | |||
316 | @Override | ||
317 | public void setCurrentGroup(final CommunicationGroup currentGroup) { | ||
318 | this.currentGroup = currentGroup; | ||
319 | } | ||
320 | |||
321 | } | ||