aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index')
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DefaultIndexerListener.java28
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DualInputNode.java348
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ExistenceNode.java199
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/GenericProjectionIndexer.java76
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IdentityIndexer.java76
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/Indexer.java71
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerListener.java41
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerWithMemory.java284
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IterableIndexer.java34
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/JoinNode.java193
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryIdentityIndexer.java55
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryNullIndexer.java54
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/NullIndexer.java88
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/OnetimeIndexer.java47
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ProjectionIndexer.java21
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java176
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/StandardIndexer.java127
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/TransitiveClosureNodeIndexer.java121
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryIdentityIndexer.java51
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryNullIndexer.java49
20 files changed, 2139 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DefaultIndexerListener.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DefaultIndexerListener.java
new file mode 100644
index 00000000..6306a482
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DefaultIndexerListener.java
@@ -0,0 +1,28 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Istvan Rath 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.rete.index;
10
11import java.lang.ref.WeakReference;
12
13import tools.refinery.viatra.runtime.rete.network.Node;
14
15public abstract class DefaultIndexerListener implements IndexerListener {
16
17 WeakReference<Node> owner;
18
19 public DefaultIndexerListener(Node owner) {
20 this.owner = new WeakReference<Node>(owner);
21 }
22
23 @Override
24 public Node getOwner() {
25 return owner.get();
26 }
27
28}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DualInputNode.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DualInputNode.java
new file mode 100644
index 00000000..170ac460
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/DualInputNode.java
@@ -0,0 +1,348 @@
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;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
19import tools.refinery.viatra.runtime.matchers.util.Direction;
20import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
21import tools.refinery.viatra.runtime.rete.network.NetworkStructureChangeSensitiveNode;
22import tools.refinery.viatra.runtime.rete.network.Receiver;
23import tools.refinery.viatra.runtime.rete.network.ReteContainer;
24import tools.refinery.viatra.runtime.rete.network.StandardNode;
25import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
26import tools.refinery.viatra.runtime.rete.network.communication.Timestamp.AllZeroMap;
27import tools.refinery.viatra.runtime.rete.network.delayed.DelayedConnectCommand;
28import tools.refinery.viatra.runtime.rete.traceability.TraceInfo;
29import tools.refinery.viatra.runtime.rete.util.Options;
30
31/**
32 * Abstract superclass for nodes with two inputs that are matched against each other.
33 *
34 * @author Gabor Bergmann
35 */
36public abstract class DualInputNode extends StandardNode implements NetworkStructureChangeSensitiveNode {
37
38 /**
39 * @since 2.3
40 */
41 protected NetworkStructureChangeSensitiveLogic logic;
42
43 public IterableIndexer getPrimarySlot() {
44 return primarySlot;
45 }
46
47 public Indexer getSecondarySlot() {
48 return secondarySlot;
49 }
50
51 /**
52 * @author Gabor Bergmann
53 *
54 */
55 public enum Side {
56 PRIMARY, SECONDARY, BOTH;
57
58 public Side opposite() {
59 switch (this) {
60 case PRIMARY:
61 return SECONDARY;
62 case SECONDARY:
63 return PRIMARY;
64 case BOTH:
65 return BOTH;
66 default:
67 return BOTH;
68 }
69 }
70 }
71
72 /**
73 * Holds the primary input slot of this node.
74 */
75 protected IterableIndexer primarySlot;
76
77 /**
78 * Holds the secondary input slot of this node.
79 */
80 protected Indexer secondarySlot;
81
82 /**
83 * Optional complementer mask
84 */
85 protected TupleMask complementerSecondaryMask;
86
87 /**
88 * true if the primary and secondary slots coincide
89 */
90 protected boolean coincidence;
91
92 /**
93 * @param reteContainer
94 */
95 public DualInputNode(final ReteContainer reteContainer, final TupleMask complementerSecondaryMask) {
96 super(reteContainer);
97 this.complementerSecondaryMask = complementerSecondaryMask;
98 this.indexerGroupCache = CollectionsFactory.createMap();
99 this.refreshIndexerGroupCache();
100 }
101
102 /**
103 * Should be called only once, when node is initialized.
104 */
105 public void connectToIndexers(final IterableIndexer primarySlot, final Indexer secondarySlot) {
106 this.primarySlot = primarySlot;
107 this.secondarySlot = secondarySlot;
108
109 reteContainer.getCommunicationTracker().registerDependency(primarySlot, this);
110 reteContainer.getCommunicationTracker().registerDependency(secondarySlot, this);
111
112 // attach listeners
113 // if there is syncing, do this after the flush done for pulling, but before syncing updates
114 coincidence = primarySlot.equals(secondarySlot);
115
116 if (!coincidence) { // regular case
117 primarySlot.attachListener(new DefaultIndexerListener(this) {
118 @Override
119 public void notifyIndexerUpdate(final Direction direction, final Tuple updateElement,
120 final Tuple signature, final boolean change, final Timestamp timestamp) {
121 DualInputNode.this.logic.notifyUpdate(Side.PRIMARY, direction, updateElement, signature, change,
122 timestamp);
123 }
124
125 @Override
126 public String toString() {
127 return "primary@" + DualInputNode.this;
128 }
129 });
130 secondarySlot.attachListener(new DefaultIndexerListener(this) {
131 public void notifyIndexerUpdate(final Direction direction, final Tuple updateElement,
132 final Tuple signature, final boolean change, final Timestamp timestamp) {
133 DualInputNode.this.logic.notifyUpdate(Side.SECONDARY, direction, updateElement, signature, change,
134 timestamp);
135 }
136
137 @Override
138 public String toString() {
139 return "secondary@" + DualInputNode.this;
140 }
141 });
142 } else { // if the two slots are the same, updates have to be handled carefully
143 primarySlot.attachListener(new DefaultIndexerListener(this) {
144 public void notifyIndexerUpdate(final Direction direction, final Tuple updateElement,
145 final Tuple signature, final boolean change, final Timestamp timestamp) {
146 DualInputNode.this.logic.notifyUpdate(Side.BOTH, direction, updateElement, signature, change,
147 timestamp);
148 }
149
150 @Override
151 public String toString() {
152 return "both@" + DualInputNode.this;
153 }
154 });
155 }
156
157 for (final Receiver receiver : getReceivers()) {
158 this.reteContainer.getDelayedCommandQueue()
159 .add(new DelayedConnectCommand(this, receiver, this.reteContainer));
160 }
161
162 // Given that connectToIndexers registers new dependencies, the networkStructureChanged() method will be called
163 // by the CommunicationTracker, and the implementation of that method in turn will call refreshIndexerGroupCache() anyway.
164 this.refreshIndexerGroupCache();
165 }
166
167 /**
168 * Helper: retrieves all stored substitutions from the opposite side memory.
169 *
170 * @return the collection of opposite substitutions if any, or null if none
171 */
172 protected Collection<Tuple> retrieveOpposites(final Side side, final Tuple signature) {
173 return getSlot(side.opposite()).get(signature);
174 }
175
176 /**
177 * @since 2.3
178 */
179 protected NetworkStructureChangeSensitiveLogic createLogic() {
180 if (this.reteContainer.isTimelyEvaluation()
181 && this.reteContainer.getCommunicationTracker().isInRecursiveGroup(this)) {
182 return createTimelyLogic();
183 } else {
184 return createTimelessLogic();
185 }
186 }
187
188 /**
189 * Helper: unifies a left and right partial matching.
190 */
191 protected Tuple unify(final Tuple left, final Tuple right) {
192 return complementerSecondaryMask.combine(left, right, Options.enableInheritance, true);
193 }
194
195 @Override
196 public void pullInto(final Collection<Tuple> collector, final boolean flush) {
197 this.logic.pullInto(collector, flush);
198 }
199
200 @Override
201 public void pullIntoWithTimeline(final Map<Tuple, Timeline<Timestamp>> collector, final boolean flush) {
202 this.logic.pullIntoWithTimeline(collector, flush);
203 }
204
205 /**
206 * Helper: unifies a substitution from the specified side with another substitution from the other side.
207 */
208 protected Tuple unify(final Side side, final Tuple ps, final Tuple opposite) {
209 switch (side) {
210 case PRIMARY:
211 return unify(ps, opposite);
212 case SECONDARY:
213 return unify(opposite, ps);
214 case BOTH:
215 return unify(ps, opposite);
216 default:
217 return null;
218 }
219 }
220
221 /**
222 * Simulates the behavior of the node for calibration purposes only.
223 */
224 public abstract Tuple calibrate(final Tuple primary, final Tuple secondary);
225
226 /**
227 * @param complementerSecondaryMask
228 * the complementerSecondaryMask to set
229 */
230 public void setComplementerSecondaryMask(final TupleMask complementerSecondaryMask) {
231 this.complementerSecondaryMask = complementerSecondaryMask;
232 }
233
234 /**
235 * Retrieves the slot corresponding to the specified side.
236 */
237 protected Indexer getSlot(final Side side) {
238 if (side == Side.SECONDARY) {
239 return secondarySlot;
240 } else {
241 return primarySlot;
242 }
243 }
244
245 @Override
246 public void assignTraceInfo(final TraceInfo traceInfo) {
247 super.assignTraceInfo(traceInfo);
248 if (traceInfo.propagateToIndexerParent()) {
249 if (primarySlot != null) {
250 primarySlot.acceptPropagatedTraceInfo(traceInfo);
251 }
252 if (secondarySlot != null) {
253 secondarySlot.acceptPropagatedTraceInfo(traceInfo);
254 }
255 }
256 }
257
258 @Override
259 public void networkStructureChanged() {
260 super.networkStructureChanged();
261 this.logic = createLogic();
262 this.refreshIndexerGroupCache();
263 }
264
265 /**
266 * @since 2.3
267 */
268 protected abstract NetworkStructureChangeSensitiveLogic createTimelyLogic();
269
270 /**
271 * @since 2.3
272 */
273 protected abstract NetworkStructureChangeSensitiveLogic createTimelessLogic();
274
275 /**
276 * This map caches the result of a CommunicationTracker.areInSameGroup(indexer, this) call. It does that for both
277 * the primary and secondary slots. This way we can avoid the lookup in the getWithTimestamp call for each tuple.
278 * The cache needs to be maintained when the network structure changes.
279 * @since 2.3
280 */
281 protected Map<Indexer, Boolean> indexerGroupCache;
282
283 /**
284 * @since 2.3
285 */
286 protected void refreshIndexerGroupCache() {
287 this.indexerGroupCache.clear();
288 if (this.primarySlot != null) {
289 this.indexerGroupCache.put(this.primarySlot,
290 this.reteContainer.getCommunicationTracker().areInSameGroup(this.primarySlot, this));
291 }
292 if (this.secondarySlot != null) {
293 this.indexerGroupCache.put(this.secondarySlot,
294 this.reteContainer.getCommunicationTracker().areInSameGroup(this.secondarySlot, this));
295 }
296 }
297
298 /**
299 * @since 2.4
300 */
301 protected Map<Tuple, Timeline<Timestamp>> getTimeline(final Tuple signature, final Indexer indexer) {
302 if (this.indexerGroupCache.get(indexer)) {
303 // recursive timely case
304 return indexer.getTimeline(signature);
305 } else {
306 // the indexer is in a different group, treat all of its tuples as they would have timestamp 0
307 final Collection<Tuple> tuples = indexer.get(signature);
308 if (tuples == null) {
309 return null;
310 } else {
311 return new AllZeroMap<Tuple>((Set<Tuple>) tuples);
312 }
313 }
314 }
315
316 /**
317 * @since 2.3
318 */
319 protected static abstract class NetworkStructureChangeSensitiveLogic {
320
321 /**
322 * Abstract handler for update event.
323 *
324 * @param side
325 * The side on which the event occurred.
326 * @param direction
327 * The direction of the update.
328 * @param updateElement
329 * The partial matching that is inserted.
330 * @param signature
331 * Masked signature of updateElement.
332 * @param change
333 * Indicates whether this is/was the first/last instance of this signature in this slot.
334 * @since 2.4
335 */
336 public abstract void notifyUpdate(final Side side, final Direction direction, final Tuple updateElement,
337 final Tuple signature, final boolean change, final Timestamp timestamp);
338
339 public abstract void pullInto(final Collection<Tuple> collector, final boolean flush);
340
341 /**
342 * @since 2.4
343 */
344 public abstract void pullIntoWithTimeline(final Map<Tuple, Timeline<Timestamp>> collector, final boolean flush);
345
346 }
347
348}
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}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/GenericProjectionIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/GenericProjectionIndexer.java
new file mode 100644
index 00000000..3de10def
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/GenericProjectionIndexer.java
@@ -0,0 +1,76 @@
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.Iterator;
14import java.util.Map;
15
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.util.Direction;
19import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
20import tools.refinery.viatra.runtime.rete.network.Receiver;
21import tools.refinery.viatra.runtime.rete.network.ReteContainer;
22import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
23
24/**
25 * A generic Indexer capable of indexing along any valid TupleMask. Does not keep track of parents, because will not
26 * ever pull parents.
27 *
28 * @author Gabor Bergmann
29 *
30 */
31public class GenericProjectionIndexer extends IndexerWithMemory implements ProjectionIndexer {
32
33 public GenericProjectionIndexer(ReteContainer reteContainer, TupleMask mask) {
34 super(reteContainer, mask);
35 }
36
37 @Override
38 protected void update(Direction direction, Tuple updateElement, Tuple signature, boolean change,
39 Timestamp timestamp) {
40 propagate(direction, updateElement, signature, change, timestamp);
41 }
42
43 @Override
44 public Collection<Tuple> get(Tuple signature) {
45 return memory.get(signature);
46 }
47
48 @Override
49 public Map<Tuple, Timeline<Timestamp>> getTimeline(Tuple signature) {
50 return memory.getWithTimeline(signature);
51 }
52
53 @Override
54 public Iterator<Tuple> iterator() {
55 return memory.iterator();
56 }
57
58 @Override
59 public Iterable<Tuple> getSignatures() {
60 return memory.getSignatures();
61 }
62
63 /**
64 * @since 2.0
65 */
66 @Override
67 public int getBucketCount() {
68 return memory.getKeysetSize();
69 }
70
71 @Override
72 public Receiver getActiveNode() {
73 return this;
74 }
75
76}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IdentityIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IdentityIndexer.java
new file mode 100644
index 00000000..6c158f2c
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IdentityIndexer.java
@@ -0,0 +1,76 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2012 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.Collections;
14import java.util.Iterator;
15import java.util.List;
16
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.util.Direction;
20import tools.refinery.viatra.runtime.rete.network.Node;
21import tools.refinery.viatra.runtime.rete.network.ReteContainer;
22import tools.refinery.viatra.runtime.rete.network.Supplier;
23import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
24
25/**
26 * Defines an abstract trivial indexer that identically projects the contents of some stateful node, and can therefore
27 * save space. Can only exist in connection with a stateful store, and must be operated by another node (the active
28 * node). Do not attach parents directly!
29 *
30 * @author Gabor Bergmann
31 * @noimplement Rely on the provided implementations
32 * @noreference Use only via standard Node and Indexer interfaces
33 * @noinstantiate This class is not intended to be instantiated by clients.
34 */
35public abstract class IdentityIndexer extends SpecializedProjectionIndexer {
36
37 protected abstract Collection<Tuple> getTuples();
38
39 public IdentityIndexer(ReteContainer reteContainer, int tupleWidth, Supplier parent,
40 Node activeNode, List<ListenerSubscription> sharedSubscriptionList) {
41 super(reteContainer, TupleMask.identity(tupleWidth), parent, activeNode, sharedSubscriptionList);
42 }
43
44 @Override
45 public Collection<Tuple> get(Tuple signature) {
46 if (contains(signature)) {
47 return Collections.singleton(signature);
48 } else
49 return null;
50 }
51
52 protected boolean contains(Tuple signature) {
53 return getTuples().contains(signature);
54 }
55
56 @Override
57 public Collection<Tuple> getSignatures() {
58 return getTuples();
59 }
60
61 @Override
62 public int getBucketCount() {
63 return getTuples().size();
64 }
65
66 @Override
67 public Iterator<Tuple> iterator() {
68 return getTuples().iterator();
69 }
70
71 @Override
72 public void propagateToListener(IndexerListener listener, Direction direction, Tuple updateElement, Timestamp timestamp) {
73 listener.notifyIndexerUpdate(direction, updateElement, updateElement, true, timestamp);
74 }
75
76} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/Indexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/Indexer.java
new file mode 100644
index 00000000..fc9d7781
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/Indexer.java
@@ -0,0 +1,71 @@
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.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
18import tools.refinery.viatra.runtime.rete.network.Node;
19import tools.refinery.viatra.runtime.rete.network.Supplier;
20import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
21
22/**
23 * A node that indexes incoming Tuples by their signatures as specified by a TupleMask. Notifies listeners about such
24 * update events through the IndexerListener.
25 *
26 * Signature tuples are created by transforming the update tuples using the mask. Tuples stored with the same signature
27 * are grouped together. The group or a reduction thereof is retrievable.
28 *
29 * @author Gabor Bergmann
30 */
31public interface Indexer extends Node {
32 /**
33 * @return the mask by which the contents are indexed.
34 */
35 public TupleMask getMask();
36
37 /**
38 * @return the node whose contents are indexed.
39 */
40 public Supplier getParent();
41
42 /**
43 * @return all stored tuples that conform to the specified signature, null if there are none such. CONTRACT: do not
44 * modify!
45 */
46 public Collection<Tuple> get(Tuple signature);
47
48 /**
49 * @since 2.4
50 */
51 default public Map<Tuple, Timeline<Timestamp>> getTimeline(Tuple signature) {
52 throw new UnsupportedOperationException();
53 }
54
55 /**
56 * This indexer will be updated whenever a Rete update is sent to the active node (or an equivalent time slot
57 * allotted to it). The active node is typically the indexer itself, but it can be a different node such as its
58 * parent.
59 *
60 * @return the active node that operates this indexer
61 */
62 public Node getActiveNode();
63
64
65 public Collection<IndexerListener> getListeners();
66
67 public void attachListener(IndexerListener listener);
68
69 public void detachListener(IndexerListener listener);
70
71}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerListener.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerListener.java
new file mode 100644
index 00000000..f52b6a06
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerListener.java
@@ -0,0 +1,41 @@
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 tools.refinery.viatra.runtime.matchers.tuple.Tuple;
13import tools.refinery.viatra.runtime.matchers.util.Direction;
14import tools.refinery.viatra.runtime.rete.network.Node;
15import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
16
17/**
18 * A listener for update events concerning an Indexer.
19 *
20 * @author Gabor Bergmann
21 *
22 */
23public interface IndexerListener {
24 /**
25 * Notifies recipient that the indexer has just received an update. Contract: indexer already reflects the updated
26 * state.
27 *
28 * @param direction
29 * the direction of the update.
30 * @param updateElement
31 * the tuple that was updated.
32 * @param signature
33 * the signature of the tuple according to the indexer's mask.
34 * @param change
35 * whether this was the first inserted / last revoked update element with this particular signature.
36 * @since 2.4
37 */
38 void notifyIndexerUpdate(Direction direction, Tuple updateElement, Tuple signature, boolean change, Timestamp timestamp);
39
40 Node getOwner();
41}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerWithMemory.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerWithMemory.java
new file mode 100644
index 00000000..a31562e9
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IndexerWithMemory.java
@@ -0,0 +1,284 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2009 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.Collections;
14import java.util.Map;
15import java.util.Map.Entry;
16
17import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
22import tools.refinery.viatra.runtime.matchers.util.Direction;
23import tools.refinery.viatra.runtime.matchers.util.Signed;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
25import tools.refinery.viatra.runtime.rete.matcher.TimelyConfiguration.TimelineRepresentation;
26import tools.refinery.viatra.runtime.rete.network.NetworkStructureChangeSensitiveNode;
27import tools.refinery.viatra.runtime.rete.network.Receiver;
28import tools.refinery.viatra.runtime.rete.network.ReteContainer;
29import tools.refinery.viatra.runtime.rete.network.Supplier;
30import tools.refinery.viatra.runtime.rete.network.communication.CommunicationGroup;
31import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
32import tools.refinery.viatra.runtime.rete.network.communication.timely.ResumableNode;
33import tools.refinery.viatra.runtime.rete.network.mailbox.Mailbox;
34import tools.refinery.viatra.runtime.rete.network.mailbox.timeless.BehaviorChangingMailbox;
35import tools.refinery.viatra.runtime.rete.network.mailbox.timely.TimelyMailbox;
36
37/**
38 * @author Gabor Bergmann
39 * @author Tamas Szabo
40 */
41public abstract class IndexerWithMemory extends StandardIndexer
42 implements Receiver, NetworkStructureChangeSensitiveNode, ResumableNode {
43
44 protected MaskedTupleMemory<Timestamp> memory;
45
46 /**
47 * @since 2.3
48 */
49 protected NetworkStructureChangeSensitiveLogic logic;
50
51 /**
52 * @since 1.6
53 */
54 protected final Mailbox mailbox;
55
56 /**
57 * @since 2.4
58 */
59 protected CommunicationGroup group;
60
61 public IndexerWithMemory(final ReteContainer reteContainer, final TupleMask mask) {
62 super(reteContainer, mask);
63 final boolean isTimely = reteContainer.isTimelyEvaluation()
64 && reteContainer.getCommunicationTracker().isInRecursiveGroup(this);
65 memory = MaskedTupleMemory.create(mask, MemoryType.SETS, this, isTimely, isTimely && reteContainer
66 .getTimelyConfiguration().getTimelineRepresentation() == TimelineRepresentation.FAITHFUL);
67 reteContainer.registerClearable(memory);
68 mailbox = instantiateMailbox();
69 reteContainer.registerClearable(mailbox);
70 this.logic = createLogic();
71 }
72
73 @Override
74 public CommunicationGroup getCurrentGroup() {
75 return this.group;
76 }
77
78 @Override
79 public void setCurrentGroup(final CommunicationGroup group) {
80 this.group = group;
81 }
82
83 @Override
84 public void networkStructureChanged() {
85 super.networkStructureChanged();
86 final boolean wasTimely = this.memory.isTimely();
87 final boolean isTimely = this.reteContainer.isTimelyEvaluation()
88 && this.reteContainer.getCommunicationTracker().isInRecursiveGroup(this);
89 if (wasTimely != isTimely) {
90 final MaskedTupleMemory<Timestamp> newMemory = MaskedTupleMemory.create(mask, MemoryType.SETS, this,
91 isTimely, isTimely && reteContainer.getTimelyConfiguration()
92 .getTimelineRepresentation() == TimelineRepresentation.FAITHFUL);
93 newMemory.initializeWith(this.memory, Timestamp.ZERO);
94 memory.clear();
95 memory = newMemory;
96 }
97 this.logic = createLogic();
98 }
99
100 /**
101 * Instantiates the {@link Mailbox} of this receiver. Subclasses may override this method to provide their own
102 * mailbox implementation.
103 *
104 * @return the mailbox
105 * @since 2.0
106 */
107 protected Mailbox instantiateMailbox() {
108 if (this.reteContainer.isTimelyEvaluation()) {
109 return new TimelyMailbox(this, this.reteContainer);
110 } else {
111 return new BehaviorChangingMailbox(this, this.reteContainer);
112 }
113 }
114
115 @Override
116 public Mailbox getMailbox() {
117 return this.mailbox;
118 }
119
120 /**
121 * @since 2.0
122 */
123 public MaskedTupleMemory<Timestamp> getMemory() {
124 return memory;
125 }
126
127 @Override
128 public void update(final Direction direction, final Tuple updateElement, final Timestamp timestamp) {
129 this.logic.update(direction, updateElement, timestamp);
130 }
131
132 /**
133 * Refined version of update
134 *
135 * @since 2.4
136 */
137 protected abstract void update(final Direction direction, final Tuple updateElement, final Tuple signature,
138 final boolean change, final Timestamp timestamp);
139
140 @Override
141 public void appendParent(final Supplier supplier) {
142 if (parent == null) {
143 parent = supplier;
144 } else {
145 throw new UnsupportedOperationException("Illegal RETE edge: " + this + " already has a parent (" + parent
146 + ") and cannot connect to additional parent (" + supplier + "). ");
147 }
148 }
149
150 @Override
151 public void removeParent(final Supplier supplier) {
152 if (parent == supplier) {
153 parent = null;
154 } else {
155 throw new IllegalArgumentException(
156 "Illegal RETE edge removal: the parent of " + this + " is not " + supplier);
157 }
158 }
159
160 /**
161 * @since 2.4
162 */
163 @Override
164 public Collection<Supplier> getParents() {
165 return Collections.singleton(parent);
166 }
167
168 /**
169 * @since 2.4
170 */
171 @Override
172 public void resumeAt(final Timestamp timestamp) {
173 this.logic.resumeAt(timestamp);
174 }
175
176 /**
177 * @since 2.4
178 */
179 @Override
180 public Timestamp getResumableTimestamp() {
181 return this.memory.getResumableTimestamp();
182 }
183
184 /**
185 * @since 2.3
186 */
187 protected static abstract class NetworkStructureChangeSensitiveLogic {
188
189 /**
190 * @since 2.4
191 */
192 public abstract void update(final Direction direction, final Tuple updateElement, final Timestamp timestamp);
193
194 /**
195 * @since 2.4
196 */
197 public abstract void resumeAt(final Timestamp timestamp);
198
199 }
200
201 /**
202 * @since 2.3
203 */
204 protected NetworkStructureChangeSensitiveLogic createLogic() {
205 if (this.reteContainer.isTimelyEvaluation()
206 && this.reteContainer.getCommunicationTracker().isInRecursiveGroup(this)) {
207 return TIMELY;
208 } else {
209 return TIMELESS;
210 }
211 }
212
213 private final NetworkStructureChangeSensitiveLogic TIMELY = new NetworkStructureChangeSensitiveLogic() {
214
215 @Override
216 public void resumeAt(final Timestamp timestamp) {
217 final Iterable<Tuple> signatures = memory.getResumableSignatures();
218
219 final Map<Tuple, Boolean> wasPresent = CollectionsFactory.createMap();
220 for (final Tuple signature : signatures) {
221 wasPresent.put(signature, memory.isPresentAtInfinity(signature));
222 }
223
224 final Map<Tuple, Map<Tuple, Diff<Timestamp>>> signatureMap = memory.resumeAt(timestamp);
225
226 for (final Entry<Tuple, Map<Tuple, Diff<Timestamp>>> outerEntry : signatureMap.entrySet()) {
227 final Tuple signature = outerEntry.getKey();
228 final Map<Tuple, Diff<Timestamp>> diffMap = outerEntry.getValue();
229 final boolean isPresent = memory.isPresentAtInfinity(signature);
230 // only send out a potential true value the first time for a given signature, then set it to false
231 boolean change = wasPresent.get(signature) ^ isPresent;
232
233 for (final Entry<Tuple, Diff<Timestamp>> innerEntry : diffMap.entrySet()) {
234 final Tuple tuple = innerEntry.getKey();
235 final Diff<Timestamp> diffs = innerEntry.getValue();
236 for (final Signed<Timestamp> signed : diffs) {
237 IndexerWithMemory.this.update(signed.getDirection(), tuple, signature, change,
238 signed.getPayload());
239 }
240 // change is a signature-wise flag, so it is ok to "try" to signal it for the first tuple only
241 change = false;
242 }
243 }
244
245 final Timestamp nextTimestamp = memory.getResumableTimestamp();
246 if (nextTimestamp != null) {
247 group.notifyHasMessage(mailbox, nextTimestamp);
248 }
249 }
250
251 @Override
252 public void update(final Direction direction, final Tuple update, final Timestamp timestamp) {
253 final Tuple signature = mask.transform(update);
254 final boolean wasPresent = memory.isPresentAtInfinity(signature);
255 final Diff<Timestamp> resultDiff = direction == Direction.INSERT
256 ? memory.addWithTimestamp(update, signature, timestamp)
257 : memory.removeWithTimestamp(update, signature, timestamp);
258 final boolean isPresent = memory.isPresentAtInfinity(signature);
259 final boolean change = wasPresent ^ isPresent;
260 for (final Signed<Timestamp> signed : resultDiff) {
261 IndexerWithMemory.this.update(signed.getDirection(), update, signature, change, signed.getPayload());
262 }
263 }
264
265 };
266
267 private final NetworkStructureChangeSensitiveLogic TIMELESS = new NetworkStructureChangeSensitiveLogic() {
268
269 @Override
270 public void update(final Direction direction, final Tuple update, final Timestamp timestamp) {
271 final Tuple signature = mask.transform(update);
272 final boolean change = direction == Direction.INSERT ? memory.add(update, signature)
273 : memory.remove(update, signature);
274 IndexerWithMemory.this.update(direction, update, signature, change, timestamp);
275 }
276
277 @Override
278 public void resumeAt(final Timestamp timestamp) {
279 // there is nothing to resume in the timeless case because we do not even care about timestamps
280 }
281
282 };
283
284} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IterableIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IterableIndexer.java
new file mode 100644
index 00000000..d6f8ef05
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/IterableIndexer.java
@@ -0,0 +1,34 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2009 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 tools.refinery.viatra.runtime.matchers.tuple.Tuple;
13
14/**
15 * An indexer that allows the iteration of all retrievable tuple groups (or reduced groups).
16 *
17 * @author Gabor Bergmann
18 *
19 */
20public interface IterableIndexer extends Indexer, Iterable<Tuple> {
21
22 /**
23 * A view consisting of exactly those signatures whose tuple group is not empty
24 * @since 2.0
25 */
26 public Iterable<Tuple> getSignatures();
27
28 /**
29 * @return the number of signatures whose tuple group is not empty
30 * @since 2.0
31 */
32 public int getBucketCount();
33
34}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/JoinNode.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/JoinNode.java
new file mode 100644
index 00000000..9a6a0de9
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/JoinNode.java
@@ -0,0 +1,193 @@
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.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.util.Direction;
18import tools.refinery.viatra.runtime.matchers.util.Signed;
19import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
20import tools.refinery.viatra.runtime.rete.network.ReteContainer;
21import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
22
23/**
24 * @author Gabor Bergmann
25 *
26 */
27public class JoinNode extends DualInputNode {
28
29 public JoinNode(final ReteContainer reteContainer, final TupleMask complementerSecondaryMask) {
30 super(reteContainer, complementerSecondaryMask);
31 this.logic = createLogic();
32 }
33
34 @Override
35 public Tuple calibrate(final Tuple primary, final Tuple secondary) {
36 return unify(primary, secondary);
37 }
38
39 private final NetworkStructureChangeSensitiveLogic TIMELESS = new NetworkStructureChangeSensitiveLogic() {
40
41 @Override
42 public void pullIntoWithTimeline(final Map<Tuple, Timeline<Timestamp>> collector, final boolean flush) {
43 throw new UnsupportedOperationException();
44 }
45
46 @Override
47 public void pullInto(final Collection<Tuple> collector, final boolean flush) {
48 if (primarySlot == null || secondarySlot == null) {
49 return;
50 }
51
52 if (flush) {
53 reteContainer.flushUpdates();
54 }
55
56 for (final Tuple signature : primarySlot.getSignatures()) {
57 // primaries can not be null due to the contract of IterableIndex.getSignatures()
58 final Collection<Tuple> primaries = primarySlot.get(signature);
59 final Collection<Tuple> opposites = secondarySlot.get(signature);
60 if (opposites != null) {
61 for (final Tuple primary : primaries) {
62 for (final Tuple opposite : opposites) {
63 collector.add(unify(primary, opposite));
64 }
65 }
66 }
67 }
68 }
69
70 @Override
71 public void notifyUpdate(final Side side, final Direction direction, final Tuple updateElement,
72 final Tuple signature, final boolean change, final Timestamp timestamp) {
73 // in the default case, all timestamps must be zero
74 assert Timestamp.ZERO.equals(timestamp);
75
76 final Collection<Tuple> opposites = retrieveOpposites(side, signature);
77
78 if (!coincidence) {
79 if (opposites != null) {
80 for (final Tuple opposite : opposites) {
81 propagateUpdate(direction, unify(side, updateElement, opposite), timestamp);
82 }
83 }
84 } else {
85 // compensate for coincidence of slots - this is the case when an Indexer is joined with itself
86 if (opposites != null) {
87 for (final Tuple opposite : opposites) {
88 if (opposite.equals(updateElement)) {
89 // handle self-joins of a single tuple separately
90 continue;
91 }
92 propagateUpdate(direction, unify(opposite, updateElement), timestamp);
93 propagateUpdate(direction, unify(updateElement, opposite), timestamp);
94 }
95 }
96
97 // handle self-joins here
98 propagateUpdate(direction, unify(updateElement, updateElement), timestamp);
99 }
100 }
101 };
102
103 private final NetworkStructureChangeSensitiveLogic TIMELY = new NetworkStructureChangeSensitiveLogic() {
104
105 @Override
106 public void pullIntoWithTimeline(final Map<Tuple, Timeline<Timestamp>> collector, final boolean flush) {
107 if (primarySlot == null || secondarySlot == null) {
108 return;
109 }
110
111 if (flush) {
112 reteContainer.flushUpdates();
113 }
114
115 for (final Tuple signature : primarySlot.getSignatures()) {
116 // primaries can not be null due to the contract of IterableIndex.getSignatures()
117 final Map<Tuple, Timeline<Timestamp>> primaries = getTimeline(signature, primarySlot);
118 final Map<Tuple, Timeline<Timestamp>> opposites = getTimeline(signature, secondarySlot);
119 if (opposites != null) {
120 for (final Tuple primary : primaries.keySet()) {
121 for (final Tuple opposite : opposites.keySet()) {
122 final Timeline<Timestamp> primaryTimeline = primaries.get(primary);
123 final Timeline<Timestamp> oppositeTimeline = opposites.get(opposite);
124 final Timeline<Timestamp> mergedTimeline = primaryTimeline
125 .mergeMultiplicative(oppositeTimeline);
126 if (!mergedTimeline.isEmpty()) {
127 collector.put(unify(primary, opposite), mergedTimeline);
128 }
129 }
130 }
131 }
132 }
133 }
134
135 @Override
136 public void pullInto(final Collection<Tuple> collector, final boolean flush) {
137 JoinNode.this.TIMELESS.pullInto(collector, flush);
138 }
139
140 @Override
141 public void notifyUpdate(final Side side, final Direction direction, final Tuple updateElement,
142 final Tuple signature, final boolean change, final Timestamp timestamp) {
143 final Indexer oppositeIndexer = getSlot(side.opposite());
144 final Map<Tuple, Timeline<Timestamp>> opposites = getTimeline(signature, oppositeIndexer);
145
146 if (!coincidence) {
147 if (opposites != null) {
148 for (final Tuple opposite : opposites.keySet()) {
149 final Tuple unifiedTuple = unify(side, updateElement, opposite);
150 for (final Signed<Timestamp> signed : opposites.get(opposite).asChangeSequence()) {
151 // TODO only consider signed timestamps that are greater or equal to timestamp
152 // plus compact the previous timestamps into at most one update
153 propagateUpdate(signed.getDirection().multiply(direction), unifiedTuple,
154 timestamp.max(signed.getPayload()));
155 }
156 }
157 }
158 } else {
159 // compensate for coincidence of slots - this is the case when an Indexer is joined with itself
160 if (opposites != null) {
161 for (final Tuple opposite : opposites.keySet()) {
162 if (opposite.equals(updateElement)) {
163 // handle self-joins of a single tuple separately
164 continue;
165 }
166 final Tuple u1 = unify(opposite, updateElement);
167 final Tuple u2 = unify(updateElement, opposite);
168 for (final Signed<Timestamp> oppositeSigned : opposites.get(opposite).asChangeSequence()) {
169 final Direction updateDirection = direction.multiply(oppositeSigned.getDirection());
170 final Timestamp updateTimestamp = timestamp.max(oppositeSigned.getPayload());
171 propagateUpdate(updateDirection, u1, updateTimestamp);
172 propagateUpdate(updateDirection, u2, updateTimestamp);
173 }
174 }
175 }
176
177 // handle self-join here
178 propagateUpdate(direction, unify(updateElement, updateElement), timestamp);
179 }
180 }
181 };
182
183 @Override
184 protected NetworkStructureChangeSensitiveLogic createTimelessLogic() {
185 return this.TIMELESS;
186 }
187
188 @Override
189 protected NetworkStructureChangeSensitiveLogic createTimelyLogic() {
190 return this.TIMELY;
191 }
192
193}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryIdentityIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryIdentityIndexer.java
new file mode 100644
index 00000000..59b75c33
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryIdentityIndexer.java
@@ -0,0 +1,55 @@
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.List;
14
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.rete.network.Receiver;
17import tools.refinery.viatra.runtime.rete.network.ReteContainer;
18import tools.refinery.viatra.runtime.rete.network.Supplier;
19
20/**
21 * Defines a trivial indexer that identically projects the contents of a memory-equipped node, and can therefore save
22 * space. Can only exist in connection with a memory, and must be operated by another node. Do not attach parents
23 * directly!
24 *
25 * @noimplement Rely on the provided implementations
26 * @noreference Use only via standard Node and Indexer interfaces
27 * @noinstantiate This class is not intended to be instantiated by clients.
28 * @author Gabor Bergmann
29 */
30
31public class MemoryIdentityIndexer extends IdentityIndexer {
32
33 protected final Collection<Tuple> memory;
34
35 /**
36 * @param reteContainer
37 * @param tupleWidth
38 * the width of the tuples of memoryNode
39 * @param memory
40 * the memory whose contents are to be identity-indexed
41 * @param parent
42 * the parent node that owns the memory
43 */
44 public MemoryIdentityIndexer(ReteContainer reteContainer, int tupleWidth, Collection<Tuple> memory,
45 Supplier parent, Receiver activeNode, List<ListenerSubscription> sharedSubscriptionList) {
46 super(reteContainer, tupleWidth, parent, activeNode, sharedSubscriptionList);
47 this.memory = memory;
48 }
49
50 @Override
51 protected Collection<Tuple> getTuples() {
52 return this.memory;
53 }
54
55}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryNullIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryNullIndexer.java
new file mode 100644
index 00000000..204fe433
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/MemoryNullIndexer.java
@@ -0,0 +1,54 @@
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.List;
14
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.rete.network.Receiver;
17import tools.refinery.viatra.runtime.rete.network.ReteContainer;
18import tools.refinery.viatra.runtime.rete.network.Supplier;
19
20/**
21 * Defines a trivial indexer that projects the contents of a memory-equipped node to the empty tuple, and can therefore
22 * save space. Can only exist in connection with a memory, and must be operated by another node. Do not attach parents
23 * directly!
24 *
25 * @author Gabor Bergmann
26 * @noimplement Rely on the provided implementations
27 * @noreference Use only via standard Node and Indexer interfaces
28 * @noinstantiate This class is not intended to be instantiated by clients.
29 */
30public class MemoryNullIndexer extends NullIndexer {
31
32 Collection<Tuple> memory;
33
34 /**
35 * @param reteContainer
36 * @param tupleWidth
37 * the width of the tuples of memoryNode
38 * @param memory
39 * the memory whose contents are to be null-indexed
40 * @param parent
41 * the parent node that owns the memory
42 */
43 public MemoryNullIndexer(ReteContainer reteContainer, int tupleWidth, Collection<Tuple> memory,
44 Supplier parent, Receiver activeNode, List<ListenerSubscription> sharedSubscriptionList) {
45 super(reteContainer, tupleWidth, parent, activeNode, sharedSubscriptionList);
46 this.memory = memory;
47 }
48
49 @Override
50 protected Collection<Tuple> getTuples() {
51 return this.memory;
52 }
53
54}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/NullIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/NullIndexer.java
new file mode 100644
index 00000000..a875b29f
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/NullIndexer.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2012 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.Collections;
14import java.util.Iterator;
15import java.util.List;
16
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
20import tools.refinery.viatra.runtime.matchers.util.Direction;
21import tools.refinery.viatra.runtime.rete.network.Node;
22import tools.refinery.viatra.runtime.rete.network.ReteContainer;
23import tools.refinery.viatra.runtime.rete.network.Supplier;
24import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
25
26/**
27 * Defines an abstract trivial indexer that projects the contents of some stateful node to the empty tuple, and can
28 * therefore save space. Can only exist in connection with a stateful store, and must be operated by another node (the
29 * active node). Do not attach parents directly!
30 *
31 * @author Gabor Bergmann
32 * @noimplement Rely on the provided implementations
33 * @noreference Use only via standard Node and Indexer interfaces
34 * @noinstantiate This class is not intended to be instantiated by clients.
35 */
36public abstract class NullIndexer extends SpecializedProjectionIndexer {
37
38 protected abstract Collection<Tuple> getTuples();
39
40 protected static final Tuple nullSignature = Tuples.staticArityFlatTupleOf();
41 protected static final Collection<Tuple> nullSingleton = Collections.singleton(nullSignature);
42 protected static final Collection<Tuple> emptySet = Collections.emptySet();
43
44 public NullIndexer(ReteContainer reteContainer, int tupleWidth, Supplier parent, Node activeNode,
45 List<ListenerSubscription> sharedSubscriptionList) {
46 super(reteContainer, TupleMask.linear(0, tupleWidth), parent, activeNode, sharedSubscriptionList);
47 }
48
49 @Override
50 public Collection<Tuple> get(Tuple signature) {
51 if (nullSignature.equals(signature))
52 return isEmpty() ? null : getTuples();
53 else
54 return null;
55 }
56
57 @Override
58 public Collection<Tuple> getSignatures() {
59 return isEmpty() ? emptySet : nullSingleton;
60 }
61
62 protected boolean isEmpty() {
63 return getTuples().isEmpty();
64 }
65
66 protected boolean isSingleElement() {
67 return getTuples().size() == 1;
68 }
69
70 @Override
71 public Iterator<Tuple> iterator() {
72 return getTuples().iterator();
73 }
74
75 @Override
76 public int getBucketCount() {
77 return getTuples().isEmpty() ? 0 : 1;
78 }
79
80 @Override
81 public void propagateToListener(IndexerListener listener, Direction direction, Tuple updateElement,
82 Timestamp timestamp) {
83 boolean radical = (direction == Direction.DELETE && isEmpty())
84 || (direction == Direction.INSERT && isSingleElement());
85 listener.notifyIndexerUpdate(direction, updateElement, nullSignature, radical, timestamp);
86 }
87
88} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/OnetimeIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/OnetimeIndexer.java
new file mode 100644
index 00000000..fef84bb1
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/OnetimeIndexer.java
@@ -0,0 +1,47 @@
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;
13
14import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
15import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
16import tools.refinery.viatra.runtime.rete.network.ReteContainer;
17import tools.refinery.viatra.runtime.rete.network.Supplier;
18
19/**
20 * @author Gabor Bergmann Indexer whose lifetime last until the first get() DO NOT connect to nodes!
21 */
22public class OnetimeIndexer extends GenericProjectionIndexer {
23
24 public OnetimeIndexer(ReteContainer reteContainer, TupleMask mask) {
25 super(reteContainer, mask);
26 }
27
28 @Override
29 public Collection<Tuple> get(Tuple signature) {
30 if (tools.refinery.viatra.runtime.rete.util.Options.releaseOnetimeIndexers) {
31 reteContainer.unregisterClearable(memory);
32 reteContainer.unregisterNode(this);
33 }
34 return super.get(signature);
35 }
36
37 @Override
38 public void appendParent(Supplier supplier) {
39 throw new UnsupportedOperationException("onetime indexer cannot have parents");
40 }
41
42 @Override
43 public void attachListener(IndexerListener listener) {
44 throw new UnsupportedOperationException("onetime indexer cannot have listeners");
45 }
46
47}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ProjectionIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ProjectionIndexer.java
new file mode 100644
index 00000000..58e593d9
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/ProjectionIndexer.java
@@ -0,0 +1,21 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2009 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
12/**
13 * An iterable indexer that receives updates from a node, and groups received tuples intact, i.e. it does not reduce
14 * tuple groups.
15 *
16 * @author Gabor Bergmann
17 *
18 */
19public interface ProjectionIndexer extends IterableIndexer {
20
21}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java
new file mode 100644
index 00000000..9c647aa9
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java
@@ -0,0 +1,176 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2012 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.ArrayList;
13import java.util.List;
14import java.util.Objects;
15
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.util.Direction;
19import tools.refinery.viatra.runtime.rete.network.Node;
20import tools.refinery.viatra.runtime.rete.network.ReteContainer;
21import tools.refinery.viatra.runtime.rete.network.Supplier;
22import tools.refinery.viatra.runtime.rete.network.communication.CommunicationTracker;
23import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
24
25/**
26 * A specialized projection indexer that can be memory-less (relying on an external source of information).
27 *
28 * <p>
29 * All specialized projection indexers of a single node will share the same listener list, so that notification order is
30 * maintained (see Bug 518434).
31 *
32 * @author Gabor Bergmann
33 * @noimplement Rely on the provided implementations
34 * @noreference Use only via standard Node and Indexer interfaces
35 * @noinstantiate This class is not intended to be instantiated by clients.
36 */
37public abstract class SpecializedProjectionIndexer extends StandardIndexer implements ProjectionIndexer {
38
39 protected Node activeNode;
40 protected List<ListenerSubscription> subscriptions;
41
42 /**
43 * @since 1.7
44 */
45 public SpecializedProjectionIndexer(final ReteContainer reteContainer, final TupleMask mask, final Supplier parent,
46 final Node activeNode, final List<ListenerSubscription> subscriptions) {
47 super(reteContainer, mask);
48 this.parent = parent;
49 this.activeNode = activeNode;
50 this.subscriptions = subscriptions;
51 }
52
53 public List<ListenerSubscription> getSubscriptions() {
54 return subscriptions;
55 }
56
57 @Override
58 public Node getActiveNode() {
59 return activeNode;
60 }
61
62 @Override
63 protected void propagate(final Direction direction, final Tuple updateElement, final Tuple signature,
64 final boolean change, final Timestamp timestamp) {
65 throw new UnsupportedOperationException();
66 }
67
68 @Override
69 public void attachListener(final IndexerListener listener) {
70 super.attachListener(listener);
71 final CommunicationTracker tracker = this.getCommunicationTracker();
72 final IndexerListener proxy = tracker.proxifyIndexerListener(this, listener);
73 final ListenerSubscription subscription = new ListenerSubscription(this, proxy);
74 tracker.registerDependency(this, proxy.getOwner());
75 // See Bug 518434
76 // Must add to the first position, so that the later listeners are notified earlier.
77 // Thus if the beta node added as listener is also an indirect descendant of the same indexer on its opposite
78 // slot,
79 // then the beta node is connected later than its ancestor's listener, therefore it will be notified earlier,
80 // eliminating duplicate insertions and lost deletions that would result from fall-through update propagation
81 subscriptions.add(0, subscription);
82 }
83
84 @Override
85 public void detachListener(final IndexerListener listener) {
86 final CommunicationTracker tracker = this.getCommunicationTracker();
87 // obtain the proxy before the super call would unregister the dependency
88 final IndexerListener proxy = tracker.proxifyIndexerListener(this, listener);
89 super.detachListener(listener);
90 final ListenerSubscription subscription = new ListenerSubscription(this, proxy);
91 final boolean wasContained = subscriptions.remove(subscription);
92 assert wasContained;
93 tracker.unregisterDependency(this, proxy.getOwner());
94 }
95
96 @Override
97 public void networkStructureChanged() {
98 super.networkStructureChanged();
99 final List<ListenerSubscription> oldSubscriptions = new ArrayList<ListenerSubscription>();
100 oldSubscriptions.addAll(subscriptions);
101 subscriptions.clear();
102 for (final ListenerSubscription oldSubscription : oldSubscriptions) {
103 // there is no need to unregister and re-register the dependency between indexer and listener
104 // because the owner of the listener is the same (even if it is proxified)
105 final CommunicationTracker tracker = this.getCommunicationTracker();
106 // the subscriptions are shared, so we MUST reuse the indexer of the subscription instead of simply 'this'
107 final IndexerListener proxy = tracker.proxifyIndexerListener(oldSubscription.indexer, oldSubscription.listener);
108 final ListenerSubscription newSubscription = new ListenerSubscription(oldSubscription.indexer, proxy);
109 subscriptions.add(newSubscription);
110 }
111 }
112
113 /**
114 * @since 2.4
115 */
116 public abstract void propagateToListener(IndexerListener listener, Direction direction, Tuple updateElement,
117 Timestamp timestamp);
118
119 /**
120 * Infrastructure to share subscriptions between specialized indexers of the same parent node.
121 *
122 * @author Gabor Bergmann
123 * @since 1.7
124 */
125 public static class ListenerSubscription {
126 protected SpecializedProjectionIndexer indexer;
127 protected IndexerListener listener;
128
129 public ListenerSubscription(SpecializedProjectionIndexer indexer, IndexerListener listener) {
130 super();
131 this.indexer = indexer;
132 this.listener = listener;
133 }
134
135 /**
136 * @since 2.4
137 */
138 public SpecializedProjectionIndexer getIndexer() {
139 return indexer;
140 }
141
142 /**
143 * @since 2.4
144 */
145 public IndexerListener getListener() {
146 return listener;
147 }
148
149 /**
150 * Call this from parent node.
151 * @since 2.4
152 */
153 public void propagate(Direction direction, Tuple updateElement, Timestamp timestamp) {
154 indexer.propagateToListener(listener, direction, updateElement, timestamp);
155 }
156
157 @Override
158 public int hashCode() {
159 return Objects.hash(indexer, listener);
160 }
161
162 @Override
163 public boolean equals(Object obj) {
164 if (this == obj)
165 return true;
166 if (obj == null)
167 return false;
168 if (getClass() != obj.getClass())
169 return false;
170 ListenerSubscription other = (ListenerSubscription) obj;
171 return Objects.equals(listener, other.listener) && Objects.equals(indexer, other.indexer);
172 }
173
174 }
175
176}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/StandardIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/StandardIndexer.java
new file mode 100644
index 00000000..9847a8dd
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/StandardIndexer.java
@@ -0,0 +1,127 @@
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.List;
14
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
18import tools.refinery.viatra.runtime.matchers.util.Direction;
19import tools.refinery.viatra.runtime.rete.network.BaseNode;
20import tools.refinery.viatra.runtime.rete.network.NetworkStructureChangeSensitiveNode;
21import tools.refinery.viatra.runtime.rete.network.ReteContainer;
22import tools.refinery.viatra.runtime.rete.network.Supplier;
23import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
24import tools.refinery.viatra.runtime.rete.traceability.TraceInfo;
25
26/**
27 * An abstract standard implementation of the Indexer interface, providing common bookkeeping functionality.
28 *
29 * @author Gabor Bergmann
30 *
31 */
32public abstract class StandardIndexer extends BaseNode implements Indexer, NetworkStructureChangeSensitiveNode {
33
34 protected Supplier parent;
35 private final List<IndexerListener> originalListeners;
36 private final List<IndexerListener> proxyListeners;
37 protected TupleMask mask;
38
39 public StandardIndexer(ReteContainer reteContainer, TupleMask mask) {
40 super(reteContainer);
41 this.parent = null;
42 this.mask = mask;
43 this.originalListeners = CollectionsFactory.createObserverList();
44 this.proxyListeners = CollectionsFactory.createObserverList();
45 }
46
47 /**
48 * @since 2.4
49 */
50 protected void propagate(Direction direction, Tuple updateElement, Tuple signature, boolean change, Timestamp timestamp) {
51 for (IndexerListener listener : proxyListeners) {
52 listener.notifyIndexerUpdate(direction, updateElement, signature, change, timestamp);
53 }
54 }
55
56 @Override
57 public TupleMask getMask() {
58 return mask;
59 }
60
61 @Override
62 public Supplier getParent() {
63 return parent;
64 }
65
66 @Override
67 public void attachListener(IndexerListener listener) {
68 this.getCommunicationTracker().registerDependency(this, listener.getOwner());
69 // obtain the proxy after registering the dependency because then the proxy reflects the new SCC structure
70 final IndexerListener proxy = this.getCommunicationTracker().proxifyIndexerListener(this, listener);
71 // See Bug 518434
72 // Must add to the first position, so that the later listeners are notified earlier.
73 // Thus if the beta node added as listener is also an indirect descendant of the same indexer on its opposite slot,
74 // then the beta node is connected later than its ancestor's listener, therefore it will be notified earlier,
75 // eliminating duplicate insertions and lost deletions that would result from fall-through update propagation
76 this.originalListeners.add(0, listener);
77 this.proxyListeners.add(0, proxy);
78 }
79
80 @Override
81 public void detachListener(IndexerListener listener) {
82 this.originalListeners.remove(listener);
83 IndexerListener listenerToRemove = null;
84 for (final IndexerListener proxyListener : this.proxyListeners) {
85 if (proxyListener.getOwner() == listener.getOwner()) {
86 listenerToRemove = proxyListener;
87 break;
88 }
89 }
90 assert listenerToRemove != null;
91 this.proxyListeners.remove(listenerToRemove);
92 this.getCommunicationTracker().unregisterDependency(this, listener.getOwner());
93 }
94
95 @Override
96 public void networkStructureChanged() {
97 this.proxyListeners.clear();
98 for (final IndexerListener original : this.originalListeners) {
99 this.proxyListeners.add(this.getCommunicationTracker().proxifyIndexerListener(this, original));
100 }
101 }
102
103 @Override
104 public Collection<IndexerListener> getListeners() {
105 return proxyListeners;
106 }
107
108 @Override
109 public ReteContainer getContainer() {
110 return reteContainer;
111 }
112
113 @Override
114 protected String toStringCore() {
115 return super.toStringCore() + "(" + parent + "/" + mask + ")";
116 }
117
118 @Override
119 public void assignTraceInfo(TraceInfo traceInfo) {
120 super.assignTraceInfo(traceInfo);
121 if (traceInfo.propagateFromIndexerToSupplierParent())
122 if (parent != null)
123 parent.acceptPropagatedTraceInfo(traceInfo);
124 }
125
126
127}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/TransitiveClosureNodeIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/TransitiveClosureNodeIndexer.java
new file mode 100644
index 00000000..77202004
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/TransitiveClosureNodeIndexer.java
@@ -0,0 +1,121 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Gabor Bergmann, Istvan Rath 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.rete.index;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.rete.itc.alg.incscc.IncSCCAlg;
17import tools.refinery.viatra.runtime.matchers.tuple.MaskedTuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.Direction;
23import tools.refinery.viatra.runtime.rete.network.Receiver;
24import tools.refinery.viatra.runtime.rete.single.TransitiveClosureNode;
25
26// UNFINISHED, not used yet
27public class TransitiveClosureNodeIndexer extends StandardIndexer implements IterableIndexer {
28 private TransitiveClosureNode tcNode;
29 private IncSCCAlg<Object> tcAlg;
30 private Collection<Tuple> emptySet;
31
32 public TransitiveClosureNodeIndexer(TupleMask mask, IncSCCAlg<Object> tcAlg, TransitiveClosureNode tcNode) {
33 super(tcNode.getContainer(), mask);
34 this.tcAlg = tcAlg;
35 this.tcNode = tcNode;
36 this.emptySet = Collections.emptySet();
37 this.parent = tcNode;
38 }
39
40 @Override
41 public Collection<Tuple> get(Tuple signature) {
42 if (signature.getSize() == mask.sourceWidth) {
43 if (mask.indices.length == 0) {
44 // mask ()/2
45 return getSignatures();
46 } else if (mask.indices.length == 1) {
47 Set<Tuple> retSet = CollectionsFactory.createSet();
48
49 // mask (0)/2
50 if (mask.indices[0] == 0) {
51 Object source = signature.get(0);
52 for (Object target : tcAlg.getAllReachableTargets(source)) {
53 retSet.add(Tuples.staticArityFlatTupleOf(source, target));
54 }
55 return retSet;
56 }
57 // mask (1)/2
58 if (mask.indices[0] == 1) {
59 Object target = signature.get(1);
60 for (Object source : tcAlg.getAllReachableSources(target)) {
61 retSet.add(Tuples.staticArityFlatTupleOf(source, target));
62 }
63 return retSet;
64 }
65 } else {
66 // mask (0,1)/2
67 if (mask.indices[0] == 0 && mask.indices[1] == 1) {
68 Object source = signature.get(0);
69 Object target = signature.get(1);
70 Tuple singleton = Tuples.staticArityFlatTupleOf(source, target);
71 return (tcAlg.isReachable(source, target) ? Collections.singleton(singleton) : emptySet);
72 }
73 // mask (1,0)/2
74 if (mask.indices[0] == 1 && mask.indices[1] == 0) {
75 Object source = signature.get(1);
76 Object target = signature.get(0);
77 Tuple singleton = Tuples.staticArityFlatTupleOf(source, target);
78 return (tcAlg.isReachable(source, target) ? Collections.singleton(singleton) : emptySet);
79 }
80 }
81 }
82 return null;
83 }
84
85 @Override
86 public int getBucketCount() {
87 throw new UnsupportedOperationException();
88 }
89
90 @Override
91 public Collection<Tuple> getSignatures() {
92 return asTupleCollection(tcAlg.getTcRelation());
93 }
94
95 @Override
96 public Iterator<Tuple> iterator() {
97 return asTupleCollection(tcAlg.getTcRelation()).iterator();
98 }
99
100 private Collection<Tuple> asTupleCollection(
101 Collection<tools.refinery.viatra.runtime.rete.itc.alg.misc.Tuple<Object>> tuples) {
102 Set<Tuple> retSet = CollectionsFactory.createSet();
103 for (tools.refinery.viatra.runtime.rete.itc.alg.misc.Tuple<Object> tuple : tuples) {
104 retSet.add(Tuples.staticArityFlatTupleOf(tuple.getSource(), tuple.getTarget()));
105 }
106 return retSet;
107 }
108
109 /**
110 * @since 2.4
111 */
112 public void propagate(Direction direction, Tuple updateElement, boolean change) {
113 propagate(direction, updateElement, new MaskedTuple(updateElement, mask), change, null);
114 }
115
116 @Override
117 public Receiver getActiveNode() {
118 return tcNode;
119 }
120
121}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryIdentityIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryIdentityIndexer.java
new file mode 100644
index 00000000..4319ee29
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryIdentityIndexer.java
@@ -0,0 +1,51 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, Istvan Rath 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.rete.index.timely;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.List;
14import java.util.Map;
15
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
18import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
19import tools.refinery.viatra.runtime.rete.index.IdentityIndexer;
20import tools.refinery.viatra.runtime.rete.network.Receiver;
21import tools.refinery.viatra.runtime.rete.network.ReteContainer;
22import tools.refinery.viatra.runtime.rete.network.Supplier;
23import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
24
25public class TimelyMemoryIdentityIndexer extends IdentityIndexer {
26
27 protected final TimelyMemory<Timestamp> memory;
28
29 public TimelyMemoryIdentityIndexer(final ReteContainer reteContainer, final int tupleWidth,
30 final TimelyMemory<Timestamp> memory, final Supplier parent, final Receiver activeNode,
31 final List<ListenerSubscription> sharedSubscriptionList) {
32 super(reteContainer, tupleWidth, parent, activeNode, sharedSubscriptionList);
33 this.memory = memory;
34 }
35
36 @Override
37 public Map<Tuple, Timeline<Timestamp>> getTimeline(final Tuple signature) {
38 final Timeline<Timestamp> timestamp = this.memory.get(signature);
39 if (timestamp != null) {
40 return Collections.singletonMap(signature, timestamp);
41 } else {
42 return null;
43 }
44 }
45
46 @Override
47 protected Collection<Tuple> getTuples() {
48 return this.memory.getTuplesAtInfinity();
49 }
50
51}
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryNullIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryNullIndexer.java
new file mode 100644
index 00000000..0386b006
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/timely/TimelyMemoryNullIndexer.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, Istvan Rath 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.rete.index.timely;
10
11import java.util.Collection;
12import java.util.List;
13import java.util.Map;
14
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
17import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
18import tools.refinery.viatra.runtime.rete.index.NullIndexer;
19import tools.refinery.viatra.runtime.rete.network.Receiver;
20import tools.refinery.viatra.runtime.rete.network.ReteContainer;
21import tools.refinery.viatra.runtime.rete.network.Supplier;
22import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
23
24public class TimelyMemoryNullIndexer extends NullIndexer {
25
26 protected final TimelyMemory<Timestamp> memory;
27
28 public TimelyMemoryNullIndexer(final ReteContainer reteContainer, final int tupleWidth,
29 final TimelyMemory<Timestamp> memory, final Supplier parent,
30 final Receiver activeNode, final List<ListenerSubscription> sharedSubscriptionList) {
31 super(reteContainer, tupleWidth, parent, activeNode, sharedSubscriptionList);
32 this.memory = memory;
33 }
34
35 @Override
36 public Map<Tuple, Timeline<Timestamp>> getTimeline(final Tuple signature) {
37 if (nullSignature.equals(signature)) {
38 return isEmpty() ? null : this.memory.asMap();
39 } else {
40 return null;
41 }
42 }
43
44 @Override
45 protected Collection<Tuple> getTuples() {
46 return this.memory.getTuplesAtInfinity();
47 }
48
49}