aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/UniquenessEnforcerNode.java
diff options
context:
space:
mode:
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.java321
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
10package tools.refinery.viatra.runtime.rete.single;
11
12import java.util.Collection;
13import java.util.Map;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.context.IPosetComparator;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
20import tools.refinery.viatra.runtime.matchers.util.Direction;
21import tools.refinery.viatra.runtime.matchers.util.IMultiset;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
23import tools.refinery.viatra.runtime.rete.index.MemoryIdentityIndexer;
24import tools.refinery.viatra.runtime.rete.index.MemoryNullIndexer;
25import tools.refinery.viatra.runtime.rete.index.ProjectionIndexer;
26import tools.refinery.viatra.runtime.rete.network.PosetAwareReceiver;
27import tools.refinery.viatra.runtime.rete.network.RederivableNode;
28import tools.refinery.viatra.runtime.rete.network.ReteContainer;
29import tools.refinery.viatra.runtime.rete.network.communication.CommunicationGroup;
30import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
31import tools.refinery.viatra.runtime.rete.network.communication.timeless.RecursiveCommunicationGroup;
32import tools.refinery.viatra.runtime.rete.network.mailbox.Mailbox;
33import tools.refinery.viatra.runtime.rete.network.mailbox.timeless.BehaviorChangingMailbox;
34import 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 */
48public 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}