aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2023-10-15 16:51:42 +0200
committerLibravatar GitHub <noreply@github.com>2023-10-15 16:51:42 +0200
commitfce5f2ba9a872228e32702d293d37a92017fd4b7 (patch)
treea58ba07ae482ff1b850d040bb263e38ae0d50876
parentMerge pull request #44 from kris7t/interpreter-performance-fix (diff)
parentrefactor(interpreter): communication tracker algorithm (diff)
downloadrefinery-fce5f2ba9a872228e32702d293d37a92017fd4b7.tar.gz
refinery-fce5f2ba9a872228e32702d293d37a92017fd4b7.tar.zst
refinery-fce5f2ba9a872228e32702d293d37a92017fd4b7.zip
Merge pull request #45 from kris7t/interpreter-communication-tracker
Optimize Interpreter communication tracker
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java50
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeObserver.java4
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/StronglyConnectedComponentAlgorithm.java10
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java16
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/ReteContainer.java7
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/CommunicationTracker.java46
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/NetworkComponentDetector.java84
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timeless/TimelessCommunicationTracker.java20
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timely/TimelyCommunicationTracker.java29
-rw-r--r--subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/single/RepresentativeElectionNode.java4
10 files changed, 193 insertions, 77 deletions
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java
index 4d3ad759..ac5e2082 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java
@@ -14,13 +14,13 @@ import java.util.HashSet;
14import java.util.Map; 14import java.util.Map;
15import java.util.Set; 15import java.util.Set;
16 16
17public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<Object> { 17public abstract class RepresentativeElectionAlgorithm<T> implements IGraphObserver<T> {
18 protected final Graph<Object> graph; 18 protected final Graph<T> graph;
19 protected final Map<Object, Object> representatives = new HashMap<>(); 19 protected final Map<T, T> representatives = new HashMap<>();
20 protected final Map<Object, Set<Object>> components = new HashMap<>(); 20 protected final Map<T, Set<T>> components = new HashMap<>();
21 private RepresentativeObserver observer; 21 private RepresentativeObserver<? super T> observer;
22 22
23 protected RepresentativeElectionAlgorithm(Graph<Object> graph) { 23 protected RepresentativeElectionAlgorithm(Graph<T> graph) {
24 this.graph = graph; 24 this.graph = graph;
25 initializeComponents(); 25 initializeComponents();
26 graph.attachObserver(this); 26 graph.attachObserver(this);
@@ -28,7 +28,7 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
28 28
29 protected abstract void initializeComponents(); 29 protected abstract void initializeComponents();
30 30
31 protected void initializeSet(Set<Object> set) { 31 protected void initializeSet(Set<T> set) {
32 var iterator = set.iterator(); 32 var iterator = set.iterator();
33 if (!iterator.hasNext()) { 33 if (!iterator.hasNext()) {
34 // Set is empty. 34 // Set is empty.
@@ -45,13 +45,13 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
45 components.put(representative, set); 45 components.put(representative, set);
46 } 46 }
47 47
48 protected void merge(Set<Object> toMerge) { 48 protected void merge(Set<T> toMerge) {
49 if (toMerge.isEmpty()) { 49 if (toMerge.isEmpty()) {
50 return; 50 return;
51 } 51 }
52 var representativesToMerge = new HashSet<>(); 52 var representativesToMerge = new HashSet<T>();
53 Object bestRepresentative = null; 53 T bestRepresentative = null;
54 Set<Object> bestSet = null; 54 Set<T> bestSet = null;
55 for (var object : toMerge) { 55 for (var object : toMerge) {
56 var representative = getRepresentative(object); 56 var representative = getRepresentative(object);
57 if (representativesToMerge.add(representative)) { 57 if (representativesToMerge.add(representative)) {
@@ -79,7 +79,7 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
79 } 79 }
80 } 80 }
81 81
82 protected void merge(Object leftRepresentative, Object rightRepresentative) { 82 protected void merge(T leftRepresentative, T rightRepresentative) {
83 if (leftRepresentative.equals(rightRepresentative)) { 83 if (leftRepresentative.equals(rightRepresentative)) {
84 return; 84 return;
85 } 85 }
@@ -92,8 +92,7 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
92 } 92 }
93 } 93 }
94 94
95 private void merge(Object preservedRepresentative, Set<Object> preservedSet, Object removedRepresentative, 95 private void merge(T preservedRepresentative, Set<T> preservedSet, T removedRepresentative, Set<T> removedSet) {
96 Set<Object> removedSet) {
97 components.remove(removedRepresentative); 96 components.remove(removedRepresentative);
98 for (var node : removedSet) { 97 for (var node : removedSet) {
99 representatives.put(node, preservedRepresentative); 98 representatives.put(node, preservedRepresentative);
@@ -102,7 +101,7 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
102 } 101 }
103 } 102 }
104 103
105 protected void assignNewRepresentative(Object oldRepresentative, Set<Object> set) { 104 protected void assignNewRepresentative(T oldRepresentative, Set<T> set) {
106 var iterator = set.iterator(); 105 var iterator = set.iterator();
107 if (!iterator.hasNext()) { 106 if (!iterator.hasNext()) {
108 return; 107 return;
@@ -119,19 +118,19 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
119 } 118 }
120 } 119 }
121 120
122 public void setObserver(RepresentativeObserver observer) { 121 public void setObserver(RepresentativeObserver<? super T> observer) {
123 this.observer = observer; 122 this.observer = observer;
124 } 123 }
125 124
126 public Map<Object, Set<Object>> getComponents() { 125 public Map<T, Set<T>> getComponents() {
127 return components; 126 return components;
128 } 127 }
129 128
130 public Object getRepresentative(Object node) { 129 public T getRepresentative(T node) {
131 return representatives.get(node); 130 return representatives.get(node);
132 } 131 }
133 132
134 public Set<Object> getComponent(Object representative) { 133 public Set<T> getComponent(T representative) {
135 return components.get(representative); 134 return components.get(representative);
136 } 135 }
137 136
@@ -140,15 +139,15 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
140 } 139 }
141 140
142 @Override 141 @Override
143 public void nodeInserted(Object n) { 142 public void nodeInserted(T n) {
144 var component = new HashSet<>(1); 143 var component = new HashSet<T>(1);
145 component.add(n); 144 component.add(n);
146 initializeSet(component); 145 initializeSet(component);
147 notifyToObservers(n, n, Direction.INSERT); 146 notifyToObservers(n, n, Direction.INSERT);
148 } 147 }
149 148
150 @Override 149 @Override
151 public void nodeDeleted(Object n) { 150 public void nodeDeleted(T n) {
152 var representative = representatives.remove(n); 151 var representative = representatives.remove(n);
153 if (!representative.equals(n)) { 152 if (!representative.equals(n)) {
154 throw new IllegalStateException("Trying to delete node with dangling edges"); 153 throw new IllegalStateException("Trying to delete node with dangling edges");
@@ -157,18 +156,19 @@ public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<
157 notifyToObservers(n, representative, Direction.DELETE); 156 notifyToObservers(n, representative, Direction.DELETE);
158 } 157 }
159 158
160 protected void notifyToObservers(Object node, Object oldRepresentative, Object newRepresentative) { 159 protected void notifyToObservers(T node, T oldRepresentative, T newRepresentative) {
161 notifyToObservers(node, oldRepresentative, Direction.DELETE); 160 notifyToObservers(node, oldRepresentative, Direction.DELETE);
162 notifyToObservers(node, newRepresentative, Direction.INSERT); 161 notifyToObservers(node, newRepresentative, Direction.INSERT);
163 } 162 }
164 163
165 protected void notifyToObservers(Object node, Object representative, Direction direction) { 164 protected void notifyToObservers(T node, T representative, Direction direction) {
166 if (observer != null) { 165 if (observer != null) {
167 observer.tupleChanged(node, representative, direction); 166 observer.tupleChanged(node, representative, direction);
168 } 167 }
169 } 168 }
170 169
170 @FunctionalInterface
171 public interface Factory { 171 public interface Factory {
172 RepresentativeElectionAlgorithm create(Graph<Object> graph); 172 <T> RepresentativeElectionAlgorithm<T> create(Graph<T> graph);
173 } 173 }
174} 174}
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeObserver.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeObserver.java
index 7844f1c7..2a4f7102 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeObserver.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/RepresentativeObserver.java
@@ -7,6 +7,6 @@ package tools.refinery.interpreter.rete.itc.alg.representative;
7 7
8import tools.refinery.interpreter.matchers.util.Direction; 8import tools.refinery.interpreter.matchers.util.Direction;
9 9
10public interface RepresentativeObserver { 10public interface RepresentativeObserver<T> {
11 void tupleChanged(Object node, Object representative, Direction direction); 11 void tupleChanged(T node, T representative, Direction direction);
12} 12}
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/StronglyConnectedComponentAlgorithm.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/StronglyConnectedComponentAlgorithm.java
index 44afd73e..d2e524f7 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/StronglyConnectedComponentAlgorithm.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/StronglyConnectedComponentAlgorithm.java
@@ -13,8 +13,8 @@ import tools.refinery.interpreter.rete.itc.alg.misc.scc.SCC;
13import java.util.Collection; 13import java.util.Collection;
14import java.util.Set; 14import java.util.Set;
15 15
16public class StronglyConnectedComponentAlgorithm extends RepresentativeElectionAlgorithm { 16public class StronglyConnectedComponentAlgorithm<T> extends RepresentativeElectionAlgorithm<T> {
17 public StronglyConnectedComponentAlgorithm(Graph<Object> graph) { 17 public StronglyConnectedComponentAlgorithm(Graph<T> graph) {
18 super(graph); 18 super(graph);
19 } 19 }
20 20
@@ -27,7 +27,7 @@ public class StronglyConnectedComponentAlgorithm extends RepresentativeElectionA
27 } 27 }
28 28
29 @Override 29 @Override
30 public void edgeInserted(Object source, Object target) { 30 public void edgeInserted(T source, T target) {
31 var sourceRoot = getRepresentative(source); 31 var sourceRoot = getRepresentative(source);
32 var targetRoot = getRepresentative(target); 32 var targetRoot = getRepresentative(target);
33 if (sourceRoot.equals(targetRoot)) { 33 if (sourceRoot.equals(targetRoot)) {
@@ -43,7 +43,7 @@ public class StronglyConnectedComponentAlgorithm extends RepresentativeElectionA
43 } 43 }
44 44
45 @Override 45 @Override
46 public void edgeDeleted(Object source, Object target) { 46 public void edgeDeleted(T source, T target) {
47 var sourceRoot = getRepresentative(source); 47 var sourceRoot = getRepresentative(source);
48 var targetRoot = getRepresentative(target); 48 var targetRoot = getRepresentative(target);
49 if (!sourceRoot.equals(targetRoot)) { 49 if (!sourceRoot.equals(targetRoot)) {
@@ -57,7 +57,7 @@ public class StronglyConnectedComponentAlgorithm extends RepresentativeElectionA
57 } 57 }
58 } 58 }
59 59
60 private void split(Object preservedRepresentative, Collection<? extends Set<Object>> sets) { 60 private void split(T preservedRepresentative, Collection<? extends Set<T>> sets) {
61 for (var set : sets) { 61 for (var set : sets) {
62 if (set.contains(preservedRepresentative)) { 62 if (set.contains(preservedRepresentative)) {
63 components.put(preservedRepresentative, set); 63 components.put(preservedRepresentative, set);
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java
index 58227c44..6b6c19ed 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java
@@ -11,8 +11,8 @@ import java.util.ArrayDeque;
11import java.util.HashSet; 11import java.util.HashSet;
12import java.util.Set; 12import java.util.Set;
13 13
14public class WeaklyConnectedComponentAlgorithm extends RepresentativeElectionAlgorithm { 14public class WeaklyConnectedComponentAlgorithm<T> extends RepresentativeElectionAlgorithm<T> {
15 public WeaklyConnectedComponentAlgorithm(Graph<Object> graph) { 15 public WeaklyConnectedComponentAlgorithm(Graph<T> graph) {
16 super(graph); 16 super(graph);
17 } 17 }
18 18
@@ -28,14 +28,14 @@ public class WeaklyConnectedComponentAlgorithm extends RepresentativeElectionAlg
28 } 28 }
29 29
30 @Override 30 @Override
31 public void edgeInserted(Object source, Object target) { 31 public void edgeInserted(T source, T target) {
32 var sourceRoot = getRepresentative(source); 32 var sourceRoot = getRepresentative(source);
33 var targetRoot = getRepresentative(target); 33 var targetRoot = getRepresentative(target);
34 merge(sourceRoot, targetRoot); 34 merge(sourceRoot, targetRoot);
35 } 35 }
36 36
37 @Override 37 @Override
38 public void edgeDeleted(Object source, Object target) { 38 public void edgeDeleted(T source, T target) {
39 var sourceRoot = getRepresentative(source); 39 var sourceRoot = getRepresentative(source);
40 var targetRoot = getRepresentative(target); 40 var targetRoot = getRepresentative(target);
41 if (!sourceRoot.equals(targetRoot)) { 41 if (!sourceRoot.equals(targetRoot)) {
@@ -47,7 +47,7 @@ public class WeaklyConnectedComponentAlgorithm extends RepresentativeElectionAlg
47 } 47 }
48 } 48 }
49 49
50 private void split(Object sourceRepresentative, Set<Object> targetReachable) { 50 private void split(T sourceRepresentative, Set<T> targetReachable) {
51 var sourceComponent = getComponent(sourceRepresentative); 51 var sourceComponent = getComponent(sourceRepresentative);
52 sourceComponent.removeAll(targetReachable); 52 sourceComponent.removeAll(targetReachable);
53 if (targetReachable.contains(sourceRepresentative)) { 53 if (targetReachable.contains(sourceRepresentative)) {
@@ -58,10 +58,10 @@ public class WeaklyConnectedComponentAlgorithm extends RepresentativeElectionAlg
58 } 58 }
59 } 59 }
60 60
61 private Set<Object> getReachableNodes(Object source) { 61 private Set<T> getReachableNodes(T source) {
62 var retSet = new HashSet<>(); 62 var retSet = new HashSet<T>();
63 retSet.add(source); 63 retSet.add(source);
64 var nodeQueue = new ArrayDeque<>(); 64 var nodeQueue = new ArrayDeque<T>();
65 nodeQueue.addLast(source); 65 nodeQueue.addLast(source);
66 66
67 while (!nodeQueue.isEmpty()) { 67 while (!nodeQueue.isEmpty()) {
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/ReteContainer.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/ReteContainer.java
index b5c91d32..3eafc149 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/ReteContainer.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/ReteContainer.java
@@ -90,15 +90,16 @@ public final class ReteContainer {
90 this.delayedCommandBuffer = new LinkedHashSet<DelayedCommand>(); 90 this.delayedCommandBuffer = new LinkedHashSet<DelayedCommand>();
91 this.executingDelayedCommands = false; 91 this.executingDelayedCommands = false;
92 92
93 this.logger = network.getEngine().getLogger();
94
93 if (this.isTimelyEvaluation()) { 95 if (this.isTimelyEvaluation()) {
94 this.tracker = new TimelyCommunicationTracker(this.getTimelyConfiguration()); 96 this.tracker = new TimelyCommunicationTracker(logger, this.getTimelyConfiguration());
95 } else { 97 } else {
96 this.tracker = new TimelessCommunicationTracker(); 98 this.tracker = new TimelessCommunicationTracker(logger);
97 } 99 }
98 100
99 this.nodesById = CollectionsFactory.createMap(); 101 this.nodesById = CollectionsFactory.createMap();
100 this.clearables = new LinkedList<Clearable>(); 102 this.clearables = new LinkedList<Clearable>();
101 this.logger = network.getEngine().getLogger();
102 103
103 this.connectionFactory = new ConnectionFactory(this); 104 this.connectionFactory = new ConnectionFactory(this);
104 this.nodeProvisioner = new NodeProvisioner(this); 105 this.nodeProvisioner = new NodeProvisioner(this);
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/CommunicationTracker.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/CommunicationTracker.java
index 2e8eb338..1d089ba6 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/CommunicationTracker.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/CommunicationTracker.java
@@ -1,5 +1,6 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2010-2017, Tamas Szabo, Istvan Rath and Daniel Varro 2 * Copyright (c) 2010-2017, Tamas Szabo, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
3 * This program and the accompanying materials are made available under the 4 * 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 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 6 * http://www.eclipse.org/legal/epl-v20.html.
@@ -8,12 +9,13 @@
8 *******************************************************************************/ 9 *******************************************************************************/
9package tools.refinery.interpreter.rete.network.communication; 10package tools.refinery.interpreter.rete.network.communication;
10 11
12import org.apache.log4j.Logger;
13import org.jetbrains.annotations.Nullable;
11import tools.refinery.interpreter.matchers.tuple.TupleMask; 14import tools.refinery.interpreter.matchers.tuple.TupleMask;
12import tools.refinery.interpreter.rete.aggregation.IAggregatorNode; 15import tools.refinery.interpreter.rete.aggregation.IAggregatorNode;
13import tools.refinery.interpreter.rete.boundary.ExternalInputEnumeratorNode; 16import tools.refinery.interpreter.rete.boundary.ExternalInputEnumeratorNode;
14import tools.refinery.interpreter.rete.eval.RelationEvaluatorNode; 17import tools.refinery.interpreter.rete.eval.RelationEvaluatorNode;
15import tools.refinery.interpreter.rete.index.*; 18import tools.refinery.interpreter.rete.index.*;
16import tools.refinery.interpreter.rete.itc.alg.incscc.IncSCCAlg;
17import tools.refinery.interpreter.rete.itc.alg.misc.topsort.TopologicalSorting; 19import tools.refinery.interpreter.rete.itc.alg.misc.topsort.TopologicalSorting;
18import tools.refinery.interpreter.rete.itc.graphimpl.Graph; 20import tools.refinery.interpreter.rete.itc.graphimpl.Graph;
19import tools.refinery.interpreter.rete.network.*; 21import tools.refinery.interpreter.rete.network.*;
@@ -61,7 +63,7 @@ public abstract class CommunicationTracker {
61 /** 63 /**
62 * Incremental SCC information about the dependency graph 64 * Incremental SCC information about the dependency graph
63 */ 65 */
64 protected final IncSCCAlg<Node> sccInformationProvider; 66 private final NetworkComponentDetector componentDetector;
65 67
66 /** 68 /**
67 * Precomputed node -> communication group map 69 * Precomputed node -> communication group map
@@ -76,9 +78,9 @@ public abstract class CommunicationTracker {
76 // groups should have a simple integer flag which represents its position in a priority queue 78 // groups should have a simple integer flag which represents its position in a priority queue
77 // priority queue only contains the ACTIVE groups 79 // priority queue only contains the ACTIVE groups
78 80
79 public CommunicationTracker() { 81 public CommunicationTracker(Logger logger) {
80 this.dependencyGraph = new Graph<Node>(); 82 this.dependencyGraph = new Graph<Node>();
81 this.sccInformationProvider = new IncSCCAlg<Node>(this.dependencyGraph); 83 this.componentDetector = new NetworkComponentDetector(logger, dependencyGraph);
82 this.groupQueue = new PriorityQueue<CommunicationGroup>(); 84 this.groupQueue = new PriorityQueue<CommunicationGroup>();
83 this.groupMap = new HashMap<Node, CommunicationGroup>(); 85 this.groupMap = new HashMap<Node, CommunicationGroup>();
84 } 86 }
@@ -91,11 +93,33 @@ public abstract class CommunicationTracker {
91 return this.groupMap.get(node); 93 return this.groupMap.get(node);
92 } 94 }
93 95
96 @Nullable
97 protected Set<Node> getPartition(Node node) {
98 return componentDetector.getPartition(node);
99 }
100
101 protected boolean isSingleton(Node node) {
102 var partition = getPartition(node);
103 return partition == null || partition.isEmpty();
104 }
105
106 protected Node getRepresentative(Node node) {
107 return componentDetector.getRepresentative(node);
108 }
109
110 protected boolean hasOutgoingEdges(Node representative) {
111 return componentDetector.hasOutgoingEdges(representative);
112 }
113
114 protected Graph<Node> getReducedGraph() {
115 return componentDetector.getReducedGraph();
116 }
117
94 private void precomputeGroups() { 118 private void precomputeGroups() {
95 groupMap.clear(); 119 groupMap.clear();
96 120
97 // reconstruct group map from dependency graph 121 // reconstruct group map from dependency graph
98 final Graph<Node> reducedGraph = sccInformationProvider.getReducedGraph(); 122 final Graph<Node> reducedGraph = getReducedGraph();
99 final List<Node> representatives = TopologicalSorting.compute(reducedGraph); 123 final List<Node> representatives = TopologicalSorting.compute(reducedGraph);
100 124
101 for (int i = 0; i < representatives.size(); i++) { // groups for SCC representatives 125 for (int i = 0; i < representatives.size(); i++) { // groups for SCC representatives
@@ -107,7 +131,7 @@ public abstract class CommunicationTracker {
107 maxGroupId = representatives.size() - 1; 131 maxGroupId = representatives.size() - 1;
108 132
109 for (final Node node : dependencyGraph.getAllNodes()) { // extend group map to the rest of nodes 133 for (final Node node : dependencyGraph.getAllNodes()) { // extend group map to the rest of nodes
110 final Node representative = sccInformationProvider.getRepresentative(node); 134 final Node representative = getRepresentative(node);
111 final CommunicationGroup group = groupMap.get(representative); 135 final CommunicationGroup group = groupMap.get(representative);
112 if (representative != node) { 136 if (representative != node) {
113 addToGroup(node, group); 137 addToGroup(node, group);
@@ -285,9 +309,9 @@ public abstract class CommunicationTracker {
285 309
286 // query all these information before the actual edge insertion 310 // query all these information before the actual edge insertion
287 // because SCCs may be unified during the process 311 // because SCCs may be unified during the process
288 final Node sourceRepresentative = sccInformationProvider.getRepresentative(source); 312 final Node sourceRepresentative = getRepresentative(source);
289 final Node targetRepresentative = sccInformationProvider.getRepresentative(target); 313 final Node targetRepresentative = getRepresentative(target);
290 final boolean targetHadOutgoingEdges = sccInformationProvider.hasOutgoingEdges(targetRepresentative); 314 final boolean targetHadOutgoingEdges = hasOutgoingEdges(targetRepresentative);
291 315
292 // insert the edge 316 // insert the edge
293 dependencyGraph.insertEdge(source, target); 317 dependencyGraph.insertEdge(source, target);
@@ -372,8 +396,8 @@ public abstract class CommunicationTracker {
372 // delete the edge first, and then query the SCC info provider 396 // delete the edge first, and then query the SCC info provider
373 this.dependencyGraph.deleteEdgeIfExists(source, target); 397 this.dependencyGraph.deleteEdgeIfExists(source, target);
374 398
375 final Node sourceRepresentative = sccInformationProvider.getRepresentative(source); 399 final Node sourceRepresentative = getRepresentative(source);
376 final Node targetRepresentative = sccInformationProvider.getRepresentative(target); 400 final Node targetRepresentative = getRepresentative(target);
377 401
378 // if they are still in the same SCC, 402 // if they are still in the same SCC,
379 // then this deletion did not affect the SCCs, 403 // then this deletion did not affect the SCCs,
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/NetworkComponentDetector.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/NetworkComponentDetector.java
new file mode 100644
index 00000000..6ed84e45
--- /dev/null
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/NetworkComponentDetector.java
@@ -0,0 +1,84 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.interpreter.rete.network.communication;
7
8import org.apache.log4j.Logger;
9import org.jetbrains.annotations.Nullable;
10import tools.refinery.interpreter.matchers.util.Direction;
11import tools.refinery.interpreter.rete.itc.alg.incscc.IncSCCAlg;
12import tools.refinery.interpreter.rete.itc.alg.representative.RepresentativeObserver;
13import tools.refinery.interpreter.rete.itc.alg.representative.StronglyConnectedComponentAlgorithm;
14import tools.refinery.interpreter.rete.itc.graphimpl.Graph;
15import tools.refinery.interpreter.rete.network.Node;
16
17import java.util.Set;
18
19public class NetworkComponentDetector implements RepresentativeObserver<Node> {
20 private final Logger logger;
21 private final Graph<Node> dependencyGraph;
22 private StronglyConnectedComponentAlgorithm<Node> stronglyConnectedComponentAlgorithm;
23 private IncSCCAlg<Node> sccInformationProvider;
24
25 public NetworkComponentDetector(Logger logger, Graph<Node> dependencyGraph) {
26 this.logger = logger;
27 this.dependencyGraph = dependencyGraph;
28 stronglyConnectedComponentAlgorithm = new StronglyConnectedComponentAlgorithm<>(dependencyGraph);
29 stronglyConnectedComponentAlgorithm.setObserver(this);
30 if (stronglyConnectedComponentAlgorithm.getComponents()
31 .values()
32 .stream()
33 .anyMatch(component -> component.size() > 1)) {
34 switchToTransitiveClosureAlgorithm();
35 }
36 }
37
38 @Nullable
39 public Set<Node> getPartition(Node node) {
40 if (sccInformationProvider == null) {
41 return null;
42 }
43 return sccInformationProvider.sccs.getPartition(node);
44 }
45
46 public Node getRepresentative(Node node) {
47 if (sccInformationProvider == null) {
48 return node;
49 }
50 return sccInformationProvider.getRepresentative(node);
51 }
52
53 public boolean hasOutgoingEdges(Node representative) {
54 if (sccInformationProvider == null) {
55 return !dependencyGraph.getTargetNodes(representative).isEmpty();
56 }
57 return sccInformationProvider.hasOutgoingEdges(representative);
58 }
59
60 public Graph<Node> getReducedGraph() {
61 if (sccInformationProvider == null) {
62 return dependencyGraph;
63 }
64 return sccInformationProvider.getReducedGraph();
65 }
66
67 @Override
68 public void tupleChanged(Node node, Node representative, Direction direction) {
69 if (direction == Direction.INSERT && !node.equals(representative)) {
70 switchToTransitiveClosureAlgorithm();
71 }
72 }
73
74 private void switchToTransitiveClosureAlgorithm() {
75 logger.warn("RETE network cycle detected, switching to transitive closure algorithm for communication groups");
76 if (stronglyConnectedComponentAlgorithm != null) {
77 stronglyConnectedComponentAlgorithm.dispose();
78 stronglyConnectedComponentAlgorithm = null;
79 }
80 if (sccInformationProvider == null) {
81 sccInformationProvider = new IncSCCAlg<>(dependencyGraph);
82 }
83 }
84}
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timeless/TimelessCommunicationTracker.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timeless/TimelessCommunicationTracker.java
index 77f40fc3..02116d71 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timeless/TimelessCommunicationTracker.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timeless/TimelessCommunicationTracker.java
@@ -1,5 +1,6 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, Istvan Rath and Daniel Varro 2 * Copyright (c) 2010-2019, Tamas Szabo, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
3 * This program and the accompanying materials are made available under the 4 * 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 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 6 * http://www.eclipse.org/legal/epl-v20.html.
@@ -8,11 +9,7 @@
8 *******************************************************************************/ 9 *******************************************************************************/
9package tools.refinery.interpreter.rete.network.communication.timeless; 10package tools.refinery.interpreter.rete.network.communication.timeless;
10 11
11import java.util.Collection; 12import org.apache.log4j.Logger;
12import java.util.HashSet;
13import java.util.Set;
14import java.util.Map.Entry;
15
16import tools.refinery.interpreter.rete.index.DualInputNode; 13import tools.refinery.interpreter.rete.index.DualInputNode;
17import tools.refinery.interpreter.rete.index.Indexer; 14import tools.refinery.interpreter.rete.index.Indexer;
18import tools.refinery.interpreter.rete.index.IndexerListener; 15import tools.refinery.interpreter.rete.index.IndexerListener;
@@ -26,6 +23,11 @@ import tools.refinery.interpreter.rete.network.communication.MessageSelector;
26import tools.refinery.interpreter.rete.network.mailbox.Mailbox; 23import tools.refinery.interpreter.rete.network.mailbox.Mailbox;
27import tools.refinery.interpreter.rete.network.mailbox.timeless.BehaviorChangingMailbox; 24import tools.refinery.interpreter.rete.network.mailbox.timeless.BehaviorChangingMailbox;
28 25
26import java.util.Collection;
27import java.util.HashSet;
28import java.util.Map.Entry;
29import java.util.Set;
30
29/** 31/**
30 * Timeless implementation of the communication tracker. 32 * Timeless implementation of the communication tracker.
31 * 33 *
@@ -33,10 +35,13 @@ import tools.refinery.interpreter.rete.network.mailbox.timeless.BehaviorChanging
33 * @since 2.2 35 * @since 2.2
34 */ 36 */
35public class TimelessCommunicationTracker extends CommunicationTracker { 37public class TimelessCommunicationTracker extends CommunicationTracker {
38 public TimelessCommunicationTracker(Logger logger) {
39 super(logger);
40 }
36 41
37 @Override 42 @Override
38 protected CommunicationGroup createGroup(Node representative, int index) { 43 protected CommunicationGroup createGroup(Node representative, int index) {
39 final boolean isSingleton = this.sccInformationProvider.sccs.getPartition(representative).size() == 1; 44 final boolean isSingleton = isSingleton(representative);
40 final boolean isReceiver = representative instanceof Receiver; 45 final boolean isReceiver = representative instanceof Receiver;
41 final boolean isPosetIndifferent = isReceiver 46 final boolean isPosetIndifferent = isReceiver
42 && ((Receiver) representative).getMailbox() instanceof BehaviorChangingMailbox; 47 && ((Receiver) representative).getMailbox() instanceof BehaviorChangingMailbox;
@@ -95,14 +100,13 @@ public class TimelessCommunicationTracker extends CommunicationTracker {
95 final Mailbox mailbox = ((Receiver) node).getMailbox(); 100 final Mailbox mailbox = ((Receiver) node).getMailbox();
96 if (mailbox instanceof BehaviorChangingMailbox) { 101 if (mailbox instanceof BehaviorChangingMailbox) {
97 final CommunicationGroup group = this.groupMap.get(node); 102 final CommunicationGroup group = this.groupMap.get(node);
98 final Set<Node> sccNodes = this.sccInformationProvider.sccs.getPartition(node);
99 // a default mailbox must split its messages iff 103 // a default mailbox must split its messages iff
100 // (1) its receiver is in a recursive group and 104 // (1) its receiver is in a recursive group and
101 final boolean c1 = group.isRecursive(); 105 final boolean c1 = group.isRecursive();
102 // (2) its receiver is at the SCC boundary of that group 106 // (2) its receiver is at the SCC boundary of that group
103 final boolean c2 = isAtSCCBoundary(node); 107 final boolean c2 = isAtSCCBoundary(node);
104 // (3) its group consists of more than one node 108 // (3) its group consists of more than one node
105 final boolean c3 = sccNodes.size() > 1; 109 final boolean c3 = isSingleton(node);
106 ((BehaviorChangingMailbox) mailbox).setSplitFlag(c1 && c2 && c3); 110 ((BehaviorChangingMailbox) mailbox).setSplitFlag(c1 && c2 && c3);
107 } 111 }
108 } 112 }
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timely/TimelyCommunicationTracker.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timely/TimelyCommunicationTracker.java
index a0cdc701..6a92ac91 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timely/TimelyCommunicationTracker.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/network/communication/timely/TimelyCommunicationTracker.java
@@ -1,5 +1,6 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, Istvan Rath and Daniel Varro 2 * Copyright (c) 2010-2019, Tamas Szabo, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
3 * This program and the accompanying materials are made available under the 4 * 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 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 6 * http://www.eclipse.org/legal/epl-v20.html.
@@ -8,20 +9,14 @@
8 *******************************************************************************/ 9 *******************************************************************************/
9package tools.refinery.interpreter.rete.network.communication.timely; 10package tools.refinery.interpreter.rete.network.communication.timely;
10 11
11import java.util.Collection; 12import org.apache.log4j.Logger;
12import java.util.List;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Set;
16import java.util.function.Function;
17
18import tools.refinery.interpreter.rete.itc.alg.misc.topsort.TopologicalSorting;
19import tools.refinery.interpreter.rete.itc.graphimpl.Graph;
20import tools.refinery.interpreter.matchers.util.CollectionsFactory; 13import tools.refinery.interpreter.matchers.util.CollectionsFactory;
21import tools.refinery.interpreter.rete.index.IndexerListener; 14import tools.refinery.interpreter.rete.index.IndexerListener;
22import tools.refinery.interpreter.rete.index.SpecializedProjectionIndexer; 15import tools.refinery.interpreter.rete.index.SpecializedProjectionIndexer;
23import tools.refinery.interpreter.rete.index.SpecializedProjectionIndexer.ListenerSubscription; 16import tools.refinery.interpreter.rete.index.SpecializedProjectionIndexer.ListenerSubscription;
24import tools.refinery.interpreter.rete.index.StandardIndexer; 17import tools.refinery.interpreter.rete.index.StandardIndexer;
18import tools.refinery.interpreter.rete.itc.alg.misc.topsort.TopologicalSorting;
19import tools.refinery.interpreter.rete.itc.graphimpl.Graph;
25import tools.refinery.interpreter.rete.matcher.TimelyConfiguration; 20import tools.refinery.interpreter.rete.matcher.TimelyConfiguration;
26import tools.refinery.interpreter.rete.matcher.TimelyConfiguration.TimelineRepresentation; 21import tools.refinery.interpreter.rete.matcher.TimelyConfiguration.TimelineRepresentation;
27import tools.refinery.interpreter.rete.network.NetworkStructureChangeSensitiveNode; 22import tools.refinery.interpreter.rete.network.NetworkStructureChangeSensitiveNode;
@@ -35,6 +30,13 @@ import tools.refinery.interpreter.rete.network.communication.NodeComparator;
35import tools.refinery.interpreter.rete.network.mailbox.Mailbox; 30import tools.refinery.interpreter.rete.network.mailbox.Mailbox;
36import tools.refinery.interpreter.rete.single.DiscriminatorDispatcherNode; 31import tools.refinery.interpreter.rete.single.DiscriminatorDispatcherNode;
37 32
33import java.util.Collection;
34import java.util.List;
35import java.util.Map;
36import java.util.Map.Entry;
37import java.util.Set;
38import java.util.function.Function;
39
38/** 40/**
39 * Timely (DDF) implementation of the {@link CommunicationTracker}. 41 * Timely (DDF) implementation of the {@link CommunicationTracker}.
40 * 42 *
@@ -45,13 +47,14 @@ public class TimelyCommunicationTracker extends CommunicationTracker {
45 47
46 protected final TimelyConfiguration configuration; 48 protected final TimelyConfiguration configuration;
47 49
48 public TimelyCommunicationTracker(final TimelyConfiguration configuration) { 50 public TimelyCommunicationTracker(final Logger logger, final TimelyConfiguration configuration) {
51 super(logger);
49 this.configuration = configuration; 52 this.configuration = configuration;
50 } 53 }
51 54
52 @Override 55 @Override
53 protected CommunicationGroup createGroup(final Node representative, final int index) { 56 protected CommunicationGroup createGroup(final Node representative, final int index) {
54 final boolean isSingleton = this.sccInformationProvider.sccs.getPartition(representative).size() == 1; 57 final boolean isSingleton = isSingleton(representative);
55 return new TimelyCommunicationGroup(this, representative, index, isSingleton); 58 return new TimelyCommunicationGroup(this, representative, index, isSingleton);
56 } 59 }
57 60
@@ -130,8 +133,8 @@ public class TimelyCommunicationTracker extends CommunicationTracker {
130 protected void postProcessGroup(final CommunicationGroup group) { 133 protected void postProcessGroup(final CommunicationGroup group) {
131 if (this.configuration.getTimelineRepresentation() == TimelineRepresentation.FAITHFUL) { 134 if (this.configuration.getTimelineRepresentation() == TimelineRepresentation.FAITHFUL) {
132 final Node representative = group.getRepresentative(); 135 final Node representative = group.getRepresentative();
133 final Set<Node> groupMembers = this.sccInformationProvider.sccs.getPartition(representative); 136 final Set<Node> groupMembers = getPartition(representative);
134 if (groupMembers.size() > 1) { 137 if (groupMembers != null && groupMembers.size() > 1) {
135 final Graph<Node> graph = new Graph<Node>(); 138 final Graph<Node> graph = new Graph<Node>();
136 139
137 for (final Node node : groupMembers) { 140 for (final Node node : groupMembers) {
diff --git a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/single/RepresentativeElectionNode.java b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/single/RepresentativeElectionNode.java
index 75aa32ef..eb5ce363 100644
--- a/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/single/RepresentativeElectionNode.java
+++ b/subprojects/interpreter-rete/src/main/java/tools/refinery/interpreter/rete/single/RepresentativeElectionNode.java
@@ -23,11 +23,11 @@ import tools.refinery.interpreter.matchers.util.timeline.Timeline;
23import java.util.Collection; 23import java.util.Collection;
24import java.util.Map; 24import java.util.Map;
25 25
26public class RepresentativeElectionNode extends SingleInputNode implements Clearable, RepresentativeObserver, 26public class RepresentativeElectionNode extends SingleInputNode implements Clearable, RepresentativeObserver<Object>,
27 ReinitializedNode { 27 ReinitializedNode {
28 private final RepresentativeElectionAlgorithm.Factory algorithmFactory; 28 private final RepresentativeElectionAlgorithm.Factory algorithmFactory;
29 private Graph<Object> graph; 29 private Graph<Object> graph;
30 private RepresentativeElectionAlgorithm algorithm; 30 private RepresentativeElectionAlgorithm<Object> algorithm;
31 31
32 public RepresentativeElectionNode(ReteContainer reteContainer, 32 public RepresentativeElectionNode(ReteContainer reteContainer,
33 RepresentativeElectionAlgorithm.Factory algorithmFactory) { 33 RepresentativeElectionAlgorithm.Factory algorithmFactory) {