aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java')
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java174
1 files changed, 174 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java
new file mode 100644
index 00000000..794dabc0
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/itc/alg/representative/RepresentativeElectionAlgorithm.java
@@ -0,0 +1,174 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.rete.itc.alg.representative;
7
8import tools.refinery.viatra.runtime.rete.itc.graphimpl.Graph;
9import tools.refinery.viatra.runtime.rete.itc.igraph.IGraphObserver;
10import tools.refinery.viatra.runtime.matchers.util.Direction;
11
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<Object> {
18 protected final Graph<Object> graph;
19 protected final Map<Object, Object> representatives = new HashMap<>();
20 protected final Map<Object, Set<Object>> components = new HashMap<>();
21 private RepresentativeObserver observer;
22
23 protected RepresentativeElectionAlgorithm(Graph<Object> graph) {
24 this.graph = graph;
25 initializeComponents();
26 graph.attachObserver(this);
27 }
28
29 protected abstract void initializeComponents();
30
31 protected void initializeSet(Set<Object> set) {
32 var iterator = set.iterator();
33 if (!iterator.hasNext()) {
34 // Set is empty.
35 return;
36 }
37 var representative = iterator.next();
38 for (var node : set) {
39 var oldRepresentative = representatives.put(node, representative);
40 if (oldRepresentative != null && !representative.equals(oldRepresentative)) {
41 throw new IllegalStateException("Node %s is already in a set represented by %s, cannot add it to %s"
42 .formatted(node, oldRepresentative, set));
43 }
44 }
45 components.put(representative, set);
46 }
47
48 protected void merge(Set<Object> toMerge) {
49 if (toMerge.isEmpty()) {
50 return;
51 }
52 var representativesToMerge = new HashSet<>();
53 Object bestRepresentative = null;
54 Set<Object> bestSet = null;
55 for (var object : toMerge) {
56 var representative = getRepresentative(object);
57 if (representativesToMerge.add(representative)) {
58 var component = getComponent(representative);
59 if (bestSet == null || bestSet.size() < component.size()) {
60 bestRepresentative = representative;
61 bestSet = component;
62 }
63 }
64 }
65 if (bestRepresentative == null) {
66 throw new AssertionError("Could not determine best representative");
67 }
68 for (var representative : representativesToMerge) {
69 if (!bestRepresentative.equals(representative)) {
70 components.remove(representative);
71 }
72 }
73 components.put(bestRepresentative, toMerge);
74 for (var object : toMerge) {
75 var previousRepresentative = representatives.put(object, bestRepresentative);
76 if (!bestSet.contains(object)) {
77 notifyToObservers(object, previousRepresentative, bestRepresentative);
78 }
79 }
80 }
81
82 protected void merge(Object leftRepresentative, Object rightRepresentative) {
83 if (leftRepresentative.equals(rightRepresentative)) {
84 return;
85 }
86 var leftSet = getComponent(leftRepresentative);
87 var rightSet = getComponent(rightRepresentative);
88 if (leftSet.size() < rightSet.size()) {
89 merge(rightRepresentative, rightSet, leftRepresentative, leftSet);
90 } else {
91 merge(leftRepresentative, leftSet, rightRepresentative, rightSet);
92 }
93 }
94
95 private void merge(Object preservedRepresentative, Set<Object> preservedSet, Object removedRepresentative,
96 Set<Object> removedSet) {
97 components.remove(removedRepresentative);
98 for (var node : removedSet) {
99 representatives.put(node, preservedRepresentative);
100 preservedSet.add(node);
101 notifyToObservers(node, removedRepresentative, preservedRepresentative);
102 }
103 }
104
105 protected void assignNewRepresentative(Object oldRepresentative, Set<Object> set) {
106 var iterator = set.iterator();
107 if (!iterator.hasNext()) {
108 return;
109 }
110 var newRepresentative = iterator.next();
111 components.put(newRepresentative, set);
112 for (var node : set) {
113 var oldRepresentativeOfNode = representatives.put(node, newRepresentative);
114 if (!oldRepresentative.equals(oldRepresentativeOfNode)) {
115 throw new IllegalArgumentException("Node %s was not represented by %s but by %s"
116 .formatted(node, oldRepresentative, oldRepresentativeOfNode));
117 }
118 notifyToObservers(node, oldRepresentative, newRepresentative);
119 }
120 }
121
122 public void setObserver(RepresentativeObserver observer) {
123 this.observer = observer;
124 }
125
126 public Map<Object, Set<Object>> getComponents() {
127 return components;
128 }
129
130 public Object getRepresentative(Object node) {
131 return representatives.get(node);
132 }
133
134 public Set<Object> getComponent(Object representative) {
135 return components.get(representative);
136 }
137
138 public void dispose() {
139 graph.detachObserver(this);
140 }
141
142 @Override
143 public void nodeInserted(Object n) {
144 var component = new HashSet<>(1);
145 component.add(n);
146 initializeSet(component);
147 notifyToObservers(n, n, Direction.INSERT);
148 }
149
150 @Override
151 public void nodeDeleted(Object n) {
152 var representative = representatives.remove(n);
153 if (!representative.equals(n)) {
154 throw new IllegalStateException("Trying to delete node with dangling edges");
155 }
156 components.remove(representative);
157 notifyToObservers(n, representative, Direction.DELETE);
158 }
159
160 protected void notifyToObservers(Object node, Object oldRepresentative, Object newRepresentative) {
161 notifyToObservers(node, oldRepresentative, Direction.DELETE);
162 notifyToObservers(node, newRepresentative, Direction.INSERT);
163 }
164
165 protected void notifyToObservers(Object node, Object representative, Direction direction) {
166 if (observer != null) {
167 observer.tupleChanged(node, representative, direction);
168 }
169 }
170
171 public interface Factory {
172 RepresentativeElectionAlgorithm create(Graph<Object> graph);
173 }
174}