aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ExistenceNode.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ExistenceNode.java')
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ExistenceNode.java199
1 files changed, 199 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ExistenceNode.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ExistenceNode.java
new file mode 100644
index 00000000..275ff638
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ExistenceNode.java
@@ -0,0 +1,199 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann 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.index;
11
12import java.util.Collection;
13import java.util.Map;
14
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.util.Direction;
17import tools.refinery.viatra.runtime.matchers.util.Signed;
18import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
19import tools.refinery.viatra.runtime.rete.network.ReteContainer;
20import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
21
22/**
23 * Propagates all substitutions arriving at the PRIMARY slot if and only if (a matching substitution on the SECONDARY is
24 * present) xor (NEGATIVE).
25 *
26 * The negative parameter specifies whether this node checks for existence or non-existence.
27 * <p>
28 * It is mandatory in differential dataflow evaluation that the secondary parent is in an upstream dependency component
29 * (so that every secondary tuple comes with zero timestamp).
30 *
31 * @author Gabor Bergmann
32 */
33public class ExistenceNode extends DualInputNode {
34
35 protected boolean negative;
36
37 /**
38 * @param reteContainer
39 * @param negative
40 * if false, act as existence checker, otherwise a nonexistence-checker
41 */
42 public ExistenceNode(final ReteContainer reteContainer, final boolean negative) {
43 super(reteContainer, null);
44 this.negative = negative;
45 this.logic = createLogic();
46 }
47
48 @Override
49 public Tuple calibrate(final Tuple primary, final Tuple secondary) {
50 return primary;
51 }
52
53 @Override
54 public void networkStructureChanged() {
55 if (this.reteContainer.isTimelyEvaluation() && this.secondarySlot != null
56 && this.reteContainer.getCommunicationTracker().areInSameGroup(this, this.secondarySlot)) {
57 throw new IllegalStateException("Secondary parent must be in an upstream dependency component!");
58 }
59 super.networkStructureChanged();
60 }
61
62 private final NetworkStructureChangeSensitiveLogic TIMELESS = new NetworkStructureChangeSensitiveLogic() {
63
64 @Override
65 public void pullIntoWithTimeline(final Map<Tuple, Timeline<Timestamp>> collector, final boolean flush) {
66 throw new UnsupportedOperationException();
67 }
68
69 @Override
70 public void pullInto(final Collection<Tuple> collector, final boolean flush) {
71 if (primarySlot == null || secondarySlot == null) {
72 return;
73 }
74 if (flush) {
75 reteContainer.flushUpdates();
76 }
77
78 for (final Tuple signature : primarySlot.getSignatures()) {
79 // primaries can not be null due to the contract of IterableIndex.getSignatures()
80 final Collection<Tuple> primaries = primarySlot.get(signature);
81 final Collection<Tuple> opposites = secondarySlot.get(signature);
82 if ((opposites != null) ^ negative) {
83 collector.addAll(primaries);
84 }
85 }
86 }
87
88 @Override
89 public void notifyUpdate(final Side side, final Direction direction, final Tuple updateElement,
90 final Tuple signature, final boolean change, final Timestamp timestamp) {
91 // in the default case, all timestamps must be zero
92 assert Timestamp.ZERO.equals(timestamp);
93
94 switch (side) {
95 case PRIMARY:
96 if ((retrieveOpposites(side, signature) != null) ^ negative) {
97 propagateUpdate(direction, updateElement, timestamp);
98 }
99 break;
100 case SECONDARY:
101 if (change) {
102 final Collection<Tuple> opposites = retrieveOpposites(side, signature);
103 if (opposites != null) {
104 for (final Tuple opposite : opposites) {
105 propagateUpdate((negative ? direction.opposite() : direction), opposite, timestamp);
106 }
107 }
108 }
109 break;
110 case BOTH:
111 // in case the slots coincide,
112 // negative --> always empty
113 // !positive --> identity
114 if (!negative) {
115 propagateUpdate(direction, updateElement, timestamp);
116 }
117 break;
118 }
119 }
120 };
121
122 private final NetworkStructureChangeSensitiveLogic TIMELY = new NetworkStructureChangeSensitiveLogic() {
123
124 @Override
125 public void pullIntoWithTimeline(final Map<Tuple, Timeline<Timestamp>> collector, final boolean flush) {
126 if (primarySlot == null || secondarySlot == null) {
127 return;
128 }
129 if (flush) {
130 reteContainer.flushUpdates();
131 }
132
133 for (final Tuple signature : primarySlot.getSignatures()) {
134 // primaries can not be null due to the contract of IterableIndex.getSignatures()
135 final Map<Tuple, Timeline<Timestamp>> primaries = getTimeline(signature, primarySlot);
136 // see contract: secondary must be in an upstream SCC
137 final Collection<Tuple> opposites = secondarySlot.get(signature);
138 if ((opposites != null) ^ negative) {
139 for (final Tuple primary : primaries.keySet()) {
140 collector.put(primary, primaries.get(primary));
141 }
142 }
143 }
144 }
145
146 @Override
147 public void pullInto(final Collection<Tuple> collector, final boolean flush) {
148 ExistenceNode.this.TIMELESS.pullInto(collector, flush);
149 }
150
151 @Override
152 public void notifyUpdate(final Side side, final Direction direction, final Tuple updateElement,
153 final Tuple signature, final boolean change, final Timestamp timestamp) {
154 switch (side) {
155 case PRIMARY: {
156 final Collection<Tuple> opposites = secondarySlot.get(signature);
157 if ((opposites != null) ^ negative) {
158 propagateUpdate(direction, updateElement, timestamp);
159 }
160 break;
161 }
162 case SECONDARY: {
163 final Map<Tuple, Timeline<Timestamp>> opposites = primarySlot.getTimeline(signature);
164 if (change) {
165 if (opposites != null) {
166 for (final Tuple opposite : opposites.keySet()) {
167 for (final Signed<Timestamp> oppositeSigned : opposites.get(opposite).asChangeSequence()) {
168 final Direction product = direction.multiply(oppositeSigned.getDirection());
169 propagateUpdate((negative ? product.opposite() : product), opposite,
170 oppositeSigned.getPayload());
171 }
172 }
173 }
174 }
175 break;
176 }
177 case BOTH:
178 // in case the slots coincide,
179 // negative --> always empty
180 // positive --> identity
181 if (!negative) {
182 propagateUpdate(direction, updateElement, timestamp);
183 }
184 break;
185 }
186 }
187 };
188
189 @Override
190 protected NetworkStructureChangeSensitiveLogic createTimelessLogic() {
191 return this.TIMELESS;
192 }
193
194 @Override
195 protected NetworkStructureChangeSensitiveLogic createTimelyLogic() {
196 return this.TIMELY;
197 }
198
199}