diff options
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index')
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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.rete.index; | ||
10 | |||
11 | import java.lang.ref.WeakReference; | ||
12 | |||
13 | import tools.refinery.viatra.runtime.rete.network.Node; | ||
14 | |||
15 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Map; | ||
14 | import java.util.Set; | ||
15 | |||
16 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
17 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory; | ||
19 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
20 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
21 | import tools.refinery.viatra.runtime.rete.network.NetworkStructureChangeSensitiveNode; | ||
22 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
23 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
24 | import tools.refinery.viatra.runtime.rete.network.StandardNode; | ||
25 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp; | ||
26 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp.AllZeroMap; | ||
27 | import tools.refinery.viatra.runtime.rete.network.delayed.DelayedConnectCommand; | ||
28 | import tools.refinery.viatra.runtime.rete.traceability.TraceInfo; | ||
29 | import 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 | */ | ||
36 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Map; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
16 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
17 | import tools.refinery.viatra.runtime.matchers.util.Signed; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
19 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
20 | import 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 | */ | ||
33 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Iterator; | ||
14 | import java.util.Map; | ||
15 | |||
16 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
17 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
19 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
20 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
21 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
22 | import 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 | */ | ||
31 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Collections; | ||
14 | import java.util.Iterator; | ||
15 | import java.util.List; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
18 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
19 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
20 | import tools.refinery.viatra.runtime.rete.network.Node; | ||
21 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
22 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
23 | import 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 | */ | ||
35 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Map; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
16 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
17 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
18 | import tools.refinery.viatra.runtime.rete.network.Node; | ||
19 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
20 | import 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 | */ | ||
31 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
13 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
14 | import tools.refinery.viatra.runtime.rete.network.Node; | ||
15 | import 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 | */ | ||
23 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Collections; | ||
14 | import java.util.Map; | ||
15 | import java.util.Map.Entry; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory; | ||
18 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
19 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
20 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory; | ||
21 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType; | ||
22 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
23 | import tools.refinery.viatra.runtime.matchers.util.Signed; | ||
24 | import tools.refinery.viatra.runtime.matchers.util.timeline.Diff; | ||
25 | import tools.refinery.viatra.runtime.rete.matcher.TimelyConfiguration.TimelineRepresentation; | ||
26 | import tools.refinery.viatra.runtime.rete.network.NetworkStructureChangeSensitiveNode; | ||
27 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
28 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
29 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
30 | import tools.refinery.viatra.runtime.rete.network.communication.CommunicationGroup; | ||
31 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp; | ||
32 | import tools.refinery.viatra.runtime.rete.network.communication.timely.ResumableNode; | ||
33 | import tools.refinery.viatra.runtime.rete.network.mailbox.Mailbox; | ||
34 | import tools.refinery.viatra.runtime.rete.network.mailbox.timeless.BehaviorChangingMailbox; | ||
35 | import tools.refinery.viatra.runtime.rete.network.mailbox.timely.TimelyMailbox; | ||
36 | |||
37 | /** | ||
38 | * @author Gabor Bergmann | ||
39 | * @author Tamas Szabo | ||
40 | */ | ||
41 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import 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 | */ | ||
20 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Map; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
16 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
17 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.Signed; | ||
19 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
20 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
21 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp; | ||
22 | |||
23 | /** | ||
24 | * @author Gabor Bergmann | ||
25 | * | ||
26 | */ | ||
27 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.List; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
16 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
17 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
18 | import 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 | |||
31 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.List; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
16 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
17 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
18 | import 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 | */ | ||
30 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.Collections; | ||
14 | import java.util.Iterator; | ||
15 | import java.util.List; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
18 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
19 | import tools.refinery.viatra.runtime.matchers.tuple.Tuples; | ||
20 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
21 | import tools.refinery.viatra.runtime.rete.network.Node; | ||
22 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
23 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
24 | import 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 | */ | ||
36 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
15 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
16 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
17 | import 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 | */ | ||
22 | public 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 | |||
10 | package 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 | */ | ||
19 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.ArrayList; | ||
13 | import java.util.List; | ||
14 | import java.util.Objects; | ||
15 | |||
16 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
17 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
19 | import tools.refinery.viatra.runtime.rete.network.Node; | ||
20 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
21 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
22 | import tools.refinery.viatra.runtime.rete.network.communication.CommunicationTracker; | ||
23 | import 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 | */ | ||
37 | public 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 | |||
10 | package tools.refinery.viatra.runtime.rete.index; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.List; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
16 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
17 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
19 | import tools.refinery.viatra.runtime.rete.network.BaseNode; | ||
20 | import tools.refinery.viatra.runtime.rete.network.NetworkStructureChangeSensitiveNode; | ||
21 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
22 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
23 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp; | ||
24 | import 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 | */ | ||
32 | public 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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.rete.index; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.Collections; | ||
13 | import java.util.Iterator; | ||
14 | import java.util.Set; | ||
15 | |||
16 | import tools.refinery.viatra.runtime.rete.itc.alg.incscc.IncSCCAlg; | ||
17 | import tools.refinery.viatra.runtime.matchers.tuple.MaskedTuple; | ||
18 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
19 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
20 | import tools.refinery.viatra.runtime.matchers.tuple.Tuples; | ||
21 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory; | ||
22 | import tools.refinery.viatra.runtime.matchers.util.Direction; | ||
23 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
24 | import tools.refinery.viatra.runtime.rete.single.TransitiveClosureNode; | ||
25 | |||
26 | // UNFINISHED, not used yet | ||
27 | public 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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.rete.index.timely; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.Collections; | ||
13 | import java.util.List; | ||
14 | import java.util.Map; | ||
15 | |||
16 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
17 | import tools.refinery.viatra.runtime.matchers.util.TimelyMemory; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
19 | import tools.refinery.viatra.runtime.rete.index.IdentityIndexer; | ||
20 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
21 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
22 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
23 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp; | ||
24 | |||
25 | public 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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.rete.index.timely; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.List; | ||
13 | import java.util.Map; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.matchers.tuple.Tuple; | ||
16 | import tools.refinery.viatra.runtime.matchers.util.TimelyMemory; | ||
17 | import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline; | ||
18 | import tools.refinery.viatra.runtime.rete.index.NullIndexer; | ||
19 | import tools.refinery.viatra.runtime.rete.network.Receiver; | ||
20 | import tools.refinery.viatra.runtime.rete.network.ReteContainer; | ||
21 | import tools.refinery.viatra.runtime.rete.network.Supplier; | ||
22 | import tools.refinery.viatra.runtime.rete.network.communication.Timestamp; | ||
23 | |||
24 | public 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 | } | ||