diff options
Diffstat (limited to 'subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc')
13 files changed, 1279 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/DFSPathFinder.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/DFSPathFinder.java new file mode 100644 index 00000000..51017b1a --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/DFSPathFinder.java | |||
@@ -0,0 +1,146 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2016, Abel Hegedus and IncQueryLabs Ltd. | ||
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.base.itc.alg.misc; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Deque; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.Iterator; | ||
15 | import java.util.LinkedList; | ||
16 | import java.util.List; | ||
17 | import java.util.Set; | ||
18 | |||
19 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
20 | import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource; | ||
21 | import tools.refinery.viatra.runtime.matchers.util.IMemoryView; | ||
22 | |||
23 | /** | ||
24 | * A depth-first search implementation of the {@link IGraphPathFinder}. | ||
25 | * | ||
26 | * TODO use ITC to filter nodes that must be traversed, instead of checks | ||
27 | * | ||
28 | * @author Abel Hegedus | ||
29 | * | ||
30 | * @param <V> | ||
31 | * the node type of the graph | ||
32 | */ | ||
33 | public class DFSPathFinder<V> implements IGraphPathFinder<V> { | ||
34 | |||
35 | private IGraphDataSource<V> graph; | ||
36 | private ITcDataSource<V> itc; | ||
37 | |||
38 | public DFSPathFinder(IGraphDataSource<V> graph, ITcDataSource<V> itc) { | ||
39 | this.graph = graph; | ||
40 | this.itc = itc; | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public Iterable<Deque<V>> getAllPaths(V sourceNode, V targetNode) { | ||
45 | Set<V> endNodes = new HashSet<V>(); | ||
46 | endNodes.add(targetNode); | ||
47 | return getAllPathsToTargets(sourceNode, endNodes); | ||
48 | } | ||
49 | |||
50 | @Override | ||
51 | public Iterable<Deque<V>> getAllPathsToTargets(V sourceNode, Set<V> targetNodes) { | ||
52 | List<Deque<V>> paths = new ArrayList<Deque<V>>(); | ||
53 | Deque<V> visited = new LinkedList<V>(); | ||
54 | Set<V> reachableTargets = new HashSet<V>(); | ||
55 | for (V targetNode : targetNodes) { | ||
56 | if (itc.isReachable(sourceNode, targetNode)) { | ||
57 | reachableTargets.add(targetNode); | ||
58 | } | ||
59 | } | ||
60 | if (!reachableTargets.isEmpty()) { | ||
61 | return paths; | ||
62 | } | ||
63 | visited.add(sourceNode); | ||
64 | return getPaths(paths, visited, reachableTargets); | ||
65 | } | ||
66 | |||
67 | protected Iterable<Deque<V>> getPaths(List<Deque<V>> paths, Deque<V> visited, Set<V> targetNodes) { | ||
68 | IMemoryView<V> nodes = graph.getTargetNodes(visited.getLast()); | ||
69 | // examine adjacent nodes | ||
70 | for (V node : nodes.distinctValues()) { | ||
71 | if (visited.contains(node)) { | ||
72 | continue; | ||
73 | } | ||
74 | if (targetNodes.contains(node)) { | ||
75 | visited.add(node); | ||
76 | // clone visited LinkedList | ||
77 | Deque<V> visitedClone = new LinkedList<V>(visited); | ||
78 | paths.add(visitedClone); | ||
79 | visited.removeLast(); | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | // in breadth-first, recursion needs to come after visiting connected nodes | ||
85 | for (V node : nodes.distinctValues()) { | ||
86 | if (visited.contains(node) || targetNodes.contains(node)) { | ||
87 | continue; | ||
88 | } | ||
89 | boolean canReachTarget = false; | ||
90 | for (V target : targetNodes) { | ||
91 | if (itc.isReachable(node, target)) { | ||
92 | canReachTarget = true; | ||
93 | break; | ||
94 | } | ||
95 | } | ||
96 | if (canReachTarget) { | ||
97 | visited.addLast(node); | ||
98 | getPaths(paths, visited, targetNodes); | ||
99 | visited.removeLast(); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | return paths; | ||
104 | } | ||
105 | |||
106 | public String printPaths(List<Deque<V>> paths) { | ||
107 | StringBuilder sb = new StringBuilder(); | ||
108 | for (Deque<V> visited : paths) { | ||
109 | sb.append("Path: "); | ||
110 | for (V node : visited) { | ||
111 | sb.append(node); | ||
112 | sb.append(" --> "); | ||
113 | } | ||
114 | sb.append("\n"); | ||
115 | } | ||
116 | return sb.toString(); | ||
117 | } | ||
118 | |||
119 | @Override | ||
120 | public Deque<V> getPath(V sourceNode, V targetNode) { | ||
121 | // TODO optimize | ||
122 | Iterable<Deque<V>> allPaths = getAllPaths(sourceNode, targetNode); | ||
123 | Iterator<Deque<V>> pathIterator = allPaths.iterator(); | ||
124 | return pathIterator.hasNext() ? pathIterator.next() : new LinkedList<V>(); | ||
125 | } | ||
126 | |||
127 | @Override | ||
128 | public Iterable<Deque<V>> getShortestPaths(V sourceNode, V targetNode) { | ||
129 | // TODO optimize | ||
130 | Iterable<Deque<V>> allPaths = getAllPaths(sourceNode, targetNode); | ||
131 | List<Deque<V>> shortestPaths = new ArrayList<Deque<V>>(); | ||
132 | int shortestPathLength = -1; | ||
133 | for (Deque<V> path : allPaths) { | ||
134 | int pathLength = path.size(); | ||
135 | if (shortestPathLength == -1 || pathLength < shortestPathLength) { | ||
136 | shortestPaths.clear(); | ||
137 | shortestPathLength = pathLength; | ||
138 | } | ||
139 | if (pathLength == shortestPathLength) { | ||
140 | shortestPaths.add(path); | ||
141 | } | ||
142 | } | ||
143 | return shortestPaths; | ||
144 | } | ||
145 | |||
146 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Edge.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Edge.java new file mode 100644 index 00000000..cf68d36a --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Edge.java | |||
@@ -0,0 +1,38 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc; | ||
11 | |||
12 | public class Edge<V> { | ||
13 | private V source; | ||
14 | private V target; | ||
15 | |||
16 | public Edge(V source, V target) { | ||
17 | super(); | ||
18 | this.source = source; | ||
19 | this.target = target; | ||
20 | } | ||
21 | |||
22 | public V getSource() { | ||
23 | return source; | ||
24 | } | ||
25 | |||
26 | public void setSource(V source) { | ||
27 | this.source = source; | ||
28 | } | ||
29 | |||
30 | public V getTarget() { | ||
31 | return target; | ||
32 | } | ||
33 | |||
34 | public void setTarget(V target) { | ||
35 | this.target = target; | ||
36 | } | ||
37 | |||
38 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/GraphHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/GraphHelper.java new file mode 100644 index 00000000..194e979b --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/GraphHelper.java | |||
@@ -0,0 +1,173 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2013, 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.base.itc.alg.misc; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collection; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.List; | ||
15 | import java.util.Map.Entry; | ||
16 | import java.util.Set; | ||
17 | |||
18 | import tools.refinery.viatra.runtime.base.itc.graphimpl.Graph; | ||
19 | import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource; | ||
20 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
21 | import tools.refinery.viatra.runtime.matchers.util.IMemoryView; | ||
22 | |||
23 | /** | ||
24 | * Utility class for graph related operations. | ||
25 | * | ||
26 | * @author Tamas Szabo | ||
27 | */ | ||
28 | public class GraphHelper { | ||
29 | |||
30 | private GraphHelper() {/*Utility class constructor*/} | ||
31 | |||
32 | /** | ||
33 | * Returns the subgraph from the given {@link IBiDirectionalGraphDataSource} which contains the given set of nodes. | ||
34 | * | ||
35 | * @param nodesInSubGraph | ||
36 | * the nodes that are present in the subgraph | ||
37 | * @param graphDataSource | ||
38 | * the graph data source for the original graph | ||
39 | * @return the subgraph associated to the given nodes | ||
40 | */ | ||
41 | public static <V> Graph<V> getSubGraph(Collection<V> nodesInSubGraph, | ||
42 | IBiDirectionalGraphDataSource<V> graphDataSource) { | ||
43 | Graph<V> g = new Graph<V>(); | ||
44 | if (nodesInSubGraph != null) { | ||
45 | for (V node : nodesInSubGraph) { | ||
46 | g.insertNode(node); | ||
47 | } | ||
48 | |||
49 | for (V node : nodesInSubGraph) { | ||
50 | IMemoryView<V> sources = graphDataSource.getSourceNodes(node); | ||
51 | for (Entry<V, Integer> entry : sources.entriesWithMultiplicities()) { | ||
52 | for (int i = 0; i < entry.getValue(); i++) { | ||
53 | V s = entry.getKey(); | ||
54 | if (nodesInSubGraph.contains(s)) { | ||
55 | g.insertEdge(s, node); | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | return g; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Constructs a path between source and target in the given graph. Both the {@link IGraphDataSource} and the set of | ||
67 | * nodes are used, this way it is possible to construct a path in a given subgraph. | ||
68 | * | ||
69 | * The returned {@link List} contains the nodes along the path (this means that there is an edge in the graph | ||
70 | * between two consecutive nodes). A self loop (one edge) is indicated with the source node being present two times | ||
71 | * in the returned {@link List}. | ||
72 | * | ||
73 | * @param source | ||
74 | * the source node | ||
75 | * @param target | ||
76 | * the target node | ||
77 | * @param nodesInGraph | ||
78 | * the nodes that are present in the subgraph | ||
79 | * @param graphDataSource | ||
80 | * the graph data source | ||
81 | * @return the path between the two nodes | ||
82 | */ | ||
83 | public static <V> List<V> constructPath(V source, V target, Set<V> nodesInGraph, | ||
84 | IGraphDataSource<V> graphDataSource) { | ||
85 | Set<V> visitedNodes = new HashSet<V>(); | ||
86 | List<V> path = new ArrayList<V>(); | ||
87 | |||
88 | visitedNodes.add(source); | ||
89 | path.add(source); | ||
90 | V act = source; | ||
91 | |||
92 | // if source and target are the same node | ||
93 | if (source.equals(target) && graphDataSource.getTargetNodes(source).containsNonZero(target)) { | ||
94 | // the node will be present in the path two times | ||
95 | path.add(source); | ||
96 | return path; | ||
97 | } else { | ||
98 | while (act != null) { | ||
99 | V nextNode = getNextNodeToVisit(act, graphDataSource, nodesInGraph, visitedNodes); | ||
100 | if (nextNode == null && path.size() > 1) { | ||
101 | // needs to backtrack along path | ||
102 | // remove the last element in the path because we can't go | ||
103 | // anywhere from there | ||
104 | path.remove(path.size() - 1); | ||
105 | while (nextNode == null && path.size() > 0) { | ||
106 | V lastPathElement = path.get(path.size() - 1); | ||
107 | nextNode = getNextNodeToVisit(lastPathElement, graphDataSource, nodesInGraph, visitedNodes); | ||
108 | if (nextNode == null) { | ||
109 | path.remove(path.size() - 1); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (nextNode != null) { | ||
115 | visitedNodes.add(nextNode); | ||
116 | path.add(nextNode); | ||
117 | if (nextNode.equals(target)) { | ||
118 | return path; | ||
119 | } | ||
120 | } | ||
121 | act = nextNode; | ||
122 | } | ||
123 | return null; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | private static <V> V getNextNodeToVisit(V act, IGraphDataSource<V> graphDataSource, Set<V> nodesInSubGraph, | ||
128 | Set<V> visitedNodes) { | ||
129 | IMemoryView<V> targetNodes = graphDataSource.getTargetNodes(act); | ||
130 | for (Entry<V, Integer> entry : targetNodes.entriesWithMultiplicities()) { | ||
131 | for (int i = 0; i < entry.getValue(); i++) { | ||
132 | V node = entry.getKey(); | ||
133 | if (nodesInSubGraph.contains(node) && !visitedNodes.contains(node)) { | ||
134 | return node; | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | return null; | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * Returns the number of self-loop edges for the given node. | ||
143 | * | ||
144 | * @param node | ||
145 | * the node | ||
146 | * @param graphDataSource | ||
147 | * the graph data source | ||
148 | * @return the number of self-loop edges | ||
149 | */ | ||
150 | public static <V> int getEdgeCount(V node, IGraphDataSource<V> graphDataSource) { | ||
151 | return getEdgeCount(node, node, graphDataSource); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * Returns the number of edges between the given source and target nodes. | ||
156 | * | ||
157 | * @param source | ||
158 | * the source node | ||
159 | * @param target | ||
160 | * the target node | ||
161 | * @param graphDataSource | ||
162 | * the graph data source | ||
163 | * @return the number of parallel edges between the two nodes | ||
164 | */ | ||
165 | public static <V> int getEdgeCount(V source, V target, IGraphDataSource<V> graphDataSource) { | ||
166 | Integer count = graphDataSource.getTargetNodes(source).getCount(target); | ||
167 | if (count == null) { | ||
168 | return 0; | ||
169 | } else { | ||
170 | return count; | ||
171 | } | ||
172 | } | ||
173 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/IGraphPathFinder.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/IGraphPathFinder.java new file mode 100644 index 00000000..cebb09c8 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/IGraphPathFinder.java | |||
@@ -0,0 +1,67 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2013, Abel Hegedus, 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.base.itc.alg.misc; | ||
10 | |||
11 | import java.util.Deque; | ||
12 | import java.util.Set; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource; | ||
15 | |||
16 | /** | ||
17 | * The path finder provides methods for retrieving paths in a graph between a source node and one or more target nodes. | ||
18 | * Use {@link ITcDataSource#getPathFinder()} for instantiating. | ||
19 | * | ||
20 | * @author Abel Hegedus | ||
21 | * | ||
22 | * @param <V> the node type of the graph | ||
23 | */ | ||
24 | public interface IGraphPathFinder<V> { | ||
25 | |||
26 | /** | ||
27 | * Returns an arbitrary path from the source node to the target node (if such exists). If there is no path | ||
28 | * between them, an empty collection is returned. | ||
29 | * | ||
30 | * @param sourceNode the source node of the path | ||
31 | * @param targetNode the target node of the path | ||
32 | * @return the path from the source to the target, or empty collection if target is not reachable from source. | ||
33 | */ | ||
34 | Deque<V> getPath(V sourceNode, V targetNode); | ||
35 | |||
36 | /** | ||
37 | * Returns the collection of shortest paths from the source node to the target node (if such exists). If there is no path | ||
38 | * between them, an empty collection is returned. | ||
39 | * | ||
40 | * @param sourceNode the source node of the path | ||
41 | * @param targetNode the target node of the path | ||
42 | * @return the collection of shortest paths from the source to the target, or empty collection if target is not reachable from source. | ||
43 | */ | ||
44 | Iterable<Deque<V>> getShortestPaths(V sourceNode, V targetNode); | ||
45 | |||
46 | /** | ||
47 | * Returns the collection of paths from the source node to the target node (if such exists). If there is no path | ||
48 | * between them, an empty collection is returned. | ||
49 | * | ||
50 | * @param sourceNode the source node of the path | ||
51 | * @param targetNode the target node of the path | ||
52 | * @return the collection of paths from the source to the target, or empty collection if target is not reachable from source. | ||
53 | */ | ||
54 | Iterable<Deque<V>> getAllPaths(V sourceNode, V targetNode); | ||
55 | |||
56 | /** | ||
57 | * Returns the collection of paths from the source node to any of the target nodes (if such exists). If there is no path | ||
58 | * between them, an empty collection is returned. | ||
59 | * | ||
60 | * @param sourceNode the source node of the path | ||
61 | * @param targetNodes the set of target nodes of the paths | ||
62 | * @return the collection of paths from the source to any of the targets, or empty collection if neither target is reachable from source. | ||
63 | */ | ||
64 | Iterable<Deque<V>> getAllPathsToTargets(V sourceNode, Set<V> targetNodes); | ||
65 | |||
66 | |||
67 | } \ No newline at end of file | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/ITcRelation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/ITcRelation.java new file mode 100644 index 00000000..a41ff6c7 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/ITcRelation.java | |||
@@ -0,0 +1,31 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc; | ||
11 | |||
12 | import java.util.Set; | ||
13 | |||
14 | public interface ITcRelation<V> { | ||
15 | |||
16 | /** | ||
17 | * Returns the starting nodes from a transitive closure relation. | ||
18 | * | ||
19 | * @return the set of starting nodes | ||
20 | */ | ||
21 | public Set<V> getTupleStarts(); | ||
22 | |||
23 | /** | ||
24 | * Returns the set of nodes that are reachable from the given node. | ||
25 | * | ||
26 | * @param start | ||
27 | * the starting node | ||
28 | * @return the set of reachable nodes | ||
29 | */ | ||
30 | public Set<V> getTupleEnds(V start); | ||
31 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Tuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Tuple.java new file mode 100644 index 00000000..a2d54a59 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Tuple.java | |||
@@ -0,0 +1,60 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc; | ||
11 | |||
12 | public class Tuple<V> { | ||
13 | |||
14 | private V source; | ||
15 | private V target; | ||
16 | |||
17 | public Tuple(V source, V target) { | ||
18 | super(); | ||
19 | this.source = source; | ||
20 | this.target = target; | ||
21 | } | ||
22 | |||
23 | public V getSource() { | ||
24 | return source; | ||
25 | } | ||
26 | |||
27 | public void setSource(V source) { | ||
28 | this.source = source; | ||
29 | } | ||
30 | |||
31 | public V getTarget() { | ||
32 | return target; | ||
33 | } | ||
34 | |||
35 | public void setTarget(V target) { | ||
36 | this.target = target; | ||
37 | } | ||
38 | |||
39 | @Override | ||
40 | public String toString() { | ||
41 | return "(" + source.toString() + "," + target.toString() + ")"; | ||
42 | } | ||
43 | |||
44 | @Override | ||
45 | public boolean equals(Object o) { | ||
46 | if (o instanceof Tuple) { | ||
47 | Tuple<?> t = (Tuple<?>) o; | ||
48 | |||
49 | if (t.getSource().equals(this.source) && t.getTarget().equals(this.target)) { | ||
50 | return true; | ||
51 | } | ||
52 | } | ||
53 | return false; | ||
54 | } | ||
55 | |||
56 | @Override | ||
57 | public int hashCode() { | ||
58 | return source.hashCode() + target.hashCode(); | ||
59 | } | ||
60 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/bfs/BFS.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/bfs/BFS.java new file mode 100644 index 00000000..798f31d2 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/bfs/BFS.java | |||
@@ -0,0 +1,151 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc.bfs; | ||
11 | |||
12 | import java.util.ArrayList; | ||
13 | import java.util.HashSet; | ||
14 | import java.util.List; | ||
15 | import java.util.Set; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource; | ||
18 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
19 | |||
20 | public class BFS<V> { | ||
21 | |||
22 | private BFS() {/*Utility class constructor*/} | ||
23 | |||
24 | /** | ||
25 | * Performs a breadth first search on the given graph to determine whether source is reachable from target. | ||
26 | * | ||
27 | * @param <V> | ||
28 | * the type parameter of the nodes in the graph | ||
29 | * @param source | ||
30 | * the source node | ||
31 | * @param target | ||
32 | * the target node | ||
33 | * @param graph | ||
34 | * the graph data source | ||
35 | * @return true if source is reachable from target, false otherwise | ||
36 | */ | ||
37 | public static <V> boolean isReachable(V source, V target, IGraphDataSource<V> graph) { | ||
38 | List<V> nodeQueue = new ArrayList<V>(); | ||
39 | Set<V> visited = new HashSet<V>(); | ||
40 | |||
41 | nodeQueue.add(source); | ||
42 | visited.add(source); | ||
43 | |||
44 | boolean ret = _isReachable(target, graph, nodeQueue, visited); | ||
45 | return ret; | ||
46 | } | ||
47 | |||
48 | private static <V> boolean _isReachable(V target, IGraphDataSource<V> graph, List<V> nodeQueue, Set<V> visited) { | ||
49 | |||
50 | while (!nodeQueue.isEmpty()) { | ||
51 | V node = nodeQueue.remove(0); | ||
52 | for (V t : graph.getTargetNodes(node).distinctValues()){ | ||
53 | if (t.equals(target)) { | ||
54 | return true; | ||
55 | } | ||
56 | if (!visited.contains(t)) { | ||
57 | visited.add(t); | ||
58 | nodeQueue.add(t); | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | return false; | ||
63 | } | ||
64 | |||
65 | public static <V> Set<V> reachableSources(IBiDirectionalGraphDataSource<V> graph, V target) { | ||
66 | Set<V> retSet = new HashSet<V>(); | ||
67 | retSet.add(target); | ||
68 | List<V> nodeQueue = new ArrayList<V>(); | ||
69 | nodeQueue.add(target); | ||
70 | |||
71 | _reachableSources(graph, nodeQueue, retSet); | ||
72 | |||
73 | return retSet; | ||
74 | } | ||
75 | |||
76 | private static <V> void _reachableSources(IBiDirectionalGraphDataSource<V> graph, List<V> nodeQueue, | ||
77 | Set<V> retSet) { | ||
78 | while (!nodeQueue.isEmpty()) { | ||
79 | V node = nodeQueue.remove(0); | ||
80 | for (V _node : graph.getSourceNodes(node).distinctValues()) { | ||
81 | if (!retSet.contains(_node)) { | ||
82 | retSet.add(_node); | ||
83 | nodeQueue.add(_node); | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | public static <V> Set<V> reachableTargets(IGraphDataSource<V> graph, V source) { | ||
90 | Set<V> retSet = new HashSet<V>(); | ||
91 | retSet.add(source); | ||
92 | List<V> nodeQueue = new ArrayList<V>(); | ||
93 | nodeQueue.add(source); | ||
94 | |||
95 | _reachableTargets(graph, nodeQueue, retSet); | ||
96 | |||
97 | return retSet; | ||
98 | } | ||
99 | |||
100 | private static <V> void _reachableTargets(IGraphDataSource<V> graph, List<V> nodeQueue, Set<V> retSet) { | ||
101 | while (!nodeQueue.isEmpty()) { | ||
102 | V node = nodeQueue.remove(0); | ||
103 | |||
104 | for (V _node : graph.getTargetNodes(node).distinctValues()) { | ||
105 | |||
106 | if (!retSet.contains(_node)) { | ||
107 | retSet.add(_node); | ||
108 | nodeQueue.add(_node); | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * Performs a breadth first search on the given graph and collects all the nodes along the path from source to | ||
116 | * target if such path exists. | ||
117 | * | ||
118 | * @param <V> | ||
119 | * the type parameter of the nodes in the graph | ||
120 | * @param source | ||
121 | * the source node | ||
122 | * @param target | ||
123 | * the target node | ||
124 | * @param graph | ||
125 | * the graph data source | ||
126 | * @return the set of nodes along the path | ||
127 | */ | ||
128 | public static <V> Set<V> collectNodesAlongPath(V source, V target, IGraphDataSource<V> graph) { | ||
129 | Set<V> path = new HashSet<V>(); | ||
130 | _collectNodesAlongPath(source, target, graph, path); | ||
131 | return path; | ||
132 | } | ||
133 | |||
134 | private static <V> boolean _collectNodesAlongPath(V node, V target, IGraphDataSource<V> graph, Set<V> path) { | ||
135 | |||
136 | boolean res = false; | ||
137 | |||
138 | // end recursion | ||
139 | if (node.equals(target)) { | ||
140 | path.add(node); | ||
141 | return true; | ||
142 | } else { | ||
143 | for (V _nodeT : graph.getTargetNodes(node).distinctValues()) { | ||
144 | res = (_collectNodesAlongPath(_nodeT, target, graph, path)) || res; | ||
145 | } | ||
146 | if (res) | ||
147 | path.add(node); | ||
148 | return res; | ||
149 | } | ||
150 | } | ||
151 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/dfs/DFSAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/dfs/DFSAlg.java new file mode 100644 index 00000000..c8d25c4e --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/dfs/DFSAlg.java | |||
@@ -0,0 +1,93 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc.dfs; | ||
11 | |||
12 | import java.util.HashMap; | ||
13 | |||
14 | import tools.refinery.viatra.runtime.base.itc.alg.dred.DRedTcRelation; | ||
15 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
16 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver; | ||
17 | |||
18 | public class DFSAlg<V> implements IGraphObserver<V> { | ||
19 | |||
20 | private IGraphDataSource<V> gds; | ||
21 | private DRedTcRelation<V> tc; | ||
22 | private int[] visited; | ||
23 | private HashMap<V, Integer> nodeMap; | ||
24 | |||
25 | public DFSAlg(IGraphDataSource<V> gds) { | ||
26 | this.gds = gds; | ||
27 | this.tc = new DRedTcRelation<V>(); | ||
28 | gds.attachObserver(this); | ||
29 | deriveTc(); | ||
30 | } | ||
31 | |||
32 | private void deriveTc() { | ||
33 | tc.clear(); | ||
34 | |||
35 | this.visited = new int[gds.getAllNodes().size()]; | ||
36 | nodeMap = new HashMap<V, Integer>(); | ||
37 | |||
38 | int j = 0; | ||
39 | for (V n : gds.getAllNodes()) { | ||
40 | nodeMap.put(n, j); | ||
41 | j++; | ||
42 | } | ||
43 | |||
44 | for (V n : gds.getAllNodes()) { | ||
45 | oneDFS(n, n); | ||
46 | initVisitedArray(); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | private void initVisitedArray() { | ||
51 | for (int i = 0; i < visited.length; i++) | ||
52 | visited[i] = 0; | ||
53 | } | ||
54 | |||
55 | private void oneDFS(V act, V source) { | ||
56 | |||
57 | if (!act.equals(source)) { | ||
58 | tc.addTuple(source, act); | ||
59 | } | ||
60 | |||
61 | visited[nodeMap.get(act)] = 1; | ||
62 | |||
63 | for (V t : gds.getTargetNodes(act).distinctValues()) { | ||
64 | if (visited[nodeMap.get(t)] == 0) { | ||
65 | oneDFS(t, source); | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | public DRedTcRelation<V> getTcRelation() { | ||
71 | return this.tc; | ||
72 | } | ||
73 | |||
74 | @Override | ||
75 | public void edgeInserted(V source, V target) { | ||
76 | deriveTc(); | ||
77 | } | ||
78 | |||
79 | @Override | ||
80 | public void edgeDeleted(V source, V target) { | ||
81 | deriveTc(); | ||
82 | } | ||
83 | |||
84 | @Override | ||
85 | public void nodeInserted(V n) { | ||
86 | deriveTc(); | ||
87 | } | ||
88 | |||
89 | @Override | ||
90 | public void nodeDeleted(V n) { | ||
91 | deriveTc(); | ||
92 | } | ||
93 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/PKAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/PKAlg.java new file mode 100644 index 00000000..c99a48ab --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/PKAlg.java | |||
@@ -0,0 +1,179 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc.scc; | ||
11 | |||
12 | import java.util.ArrayList; | ||
13 | import java.util.Collections; | ||
14 | import java.util.HashMap; | ||
15 | import java.util.List; | ||
16 | import java.util.Map; | ||
17 | |||
18 | import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource; | ||
19 | import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalWrapper; | ||
20 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
21 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver; | ||
22 | |||
23 | public class PKAlg<V> implements IGraphObserver<V> { | ||
24 | |||
25 | /** | ||
26 | * Maps the nodes to their indicies. | ||
27 | */ | ||
28 | private Map<V, Integer> node2index; | ||
29 | private Map<Integer, V> index2node; | ||
30 | private Map<V, Boolean> node2mark; | ||
31 | |||
32 | /** | ||
33 | * Maps the index of a node to the index in the topsort. | ||
34 | */ | ||
35 | private Map<Integer, Integer> index2topsort; | ||
36 | private Map<Integer, Integer> topsort2index; | ||
37 | |||
38 | /** | ||
39 | * Index associated to the inserted nodes (incrementing with every insertion). | ||
40 | */ | ||
41 | private int index; | ||
42 | |||
43 | /** | ||
44 | * Index within the topsort for the target node when edge insertion occurs. | ||
45 | */ | ||
46 | private int lower_bound; | ||
47 | |||
48 | /** | ||
49 | * Index within the topsort for the source node when edge insertion occurs. | ||
50 | */ | ||
51 | private int upper_bound; | ||
52 | |||
53 | private List<V> RF; | ||
54 | private List<V> RB; | ||
55 | private IBiDirectionalGraphDataSource<V> gds; | ||
56 | |||
57 | public PKAlg(IGraphDataSource<V> gds) { | ||
58 | if (gds instanceof IBiDirectionalGraphDataSource<?>) { | ||
59 | this.gds = (IBiDirectionalGraphDataSource<V>) gds; | ||
60 | } else { | ||
61 | this.gds = new IBiDirectionalWrapper<V>(gds); | ||
62 | } | ||
63 | |||
64 | node2mark = new HashMap<V, Boolean>(); | ||
65 | node2index = new HashMap<V, Integer>(); | ||
66 | index2node = new HashMap<Integer, V>(); | ||
67 | index2topsort = new HashMap<Integer, Integer>(); | ||
68 | topsort2index = new HashMap<Integer, Integer>(); | ||
69 | index = 0; | ||
70 | |||
71 | gds.attachObserver(this); | ||
72 | } | ||
73 | |||
74 | @Override | ||
75 | public void edgeInserted(V source, V target) { | ||
76 | |||
77 | RF = new ArrayList<V>(); | ||
78 | RB = new ArrayList<V>(); | ||
79 | |||
80 | lower_bound = index2topsort.get(node2index.get(target)); | ||
81 | upper_bound = index2topsort.get(node2index.get(source)); | ||
82 | |||
83 | if (lower_bound < upper_bound) { | ||
84 | dfsForward(target); | ||
85 | dfsBackward(source); | ||
86 | reorder(); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | private List<Integer> getIndicies(List<V> list) { | ||
91 | List<Integer> indicies = new ArrayList<Integer>(); | ||
92 | |||
93 | for (V n : list) | ||
94 | indicies.add(index2topsort.get(node2index.get(n))); | ||
95 | |||
96 | return indicies; | ||
97 | } | ||
98 | |||
99 | private void reorder() { | ||
100 | |||
101 | Collections.reverse(RB); | ||
102 | |||
103 | // azon csomopontok indexei amelyek sorrendje nem jo | ||
104 | List<Integer> L = getIndicies(RF); | ||
105 | L.addAll(getIndicies(RB)); | ||
106 | Collections.sort(L); | ||
107 | |||
108 | for (int i = 0; i < RB.size(); i++) { | ||
109 | index2topsort.put(node2index.get(RB.get(i)), L.get(i)); | ||
110 | topsort2index.put(L.get(i), node2index.get(RB.get(i))); | ||
111 | } | ||
112 | |||
113 | for (int i = 0; i < RF.size(); i++) { | ||
114 | index2topsort.put(node2index.get(RF.get(i)), L.get(i + RB.size())); | ||
115 | topsort2index.put(L.get(i + RB.size()), node2index.get(RF.get(i))); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | @SuppressWarnings("unused") | ||
120 | private List<V> getTopSort() { | ||
121 | List<V> topsort = new ArrayList<V>(); | ||
122 | |||
123 | for (int i : topsort2index.values()) { | ||
124 | topsort.add(index2node.get(i)); | ||
125 | } | ||
126 | |||
127 | return topsort; | ||
128 | } | ||
129 | |||
130 | private void dfsBackward(V node) { | ||
131 | node2mark.put(node, true); | ||
132 | RB.add(node); | ||
133 | |||
134 | for (V sn : gds.getSourceNodes(node).distinctValues()) { | ||
135 | int top_id = index2topsort.get(node2index.get(sn)); | ||
136 | |||
137 | if (!node2mark.get(sn) && lower_bound < top_id) | ||
138 | dfsBackward(sn); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | private void dfsForward(V node) { | ||
143 | node2mark.put(node, true); | ||
144 | RF.add(node); | ||
145 | |||
146 | for (V tn : gds.getTargetNodes(node).distinctValues()) { | ||
147 | int top_id = index2topsort.get(node2index.get(tn)); | ||
148 | |||
149 | if (top_id == upper_bound) | ||
150 | System.out.println("!!!Cycle detected!!!"); | ||
151 | else if (!node2mark.get(tn) && top_id < upper_bound) | ||
152 | dfsForward(tn); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | @Override | ||
157 | public void edgeDeleted(V source, V target) { | ||
158 | // Edge deletion does not affect topsort | ||
159 | } | ||
160 | |||
161 | @Override | ||
162 | public void nodeInserted(V n) { | ||
163 | node2mark.put(n, false); | ||
164 | node2index.put(n, index); | ||
165 | index2node.put(index, n); | ||
166 | index2topsort.put(index, index); | ||
167 | topsort2index.put(index, index); | ||
168 | index++; | ||
169 | } | ||
170 | |||
171 | @Override | ||
172 | public void nodeDeleted(V n) { | ||
173 | node2mark.remove(n); | ||
174 | int node_id = node2index.remove(n); | ||
175 | index2node.remove(node_id); | ||
176 | int top_id = index2topsort.remove(node_id); | ||
177 | topsort2index.remove(top_id); | ||
178 | } | ||
179 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCC.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCC.java new file mode 100644 index 00000000..8915998b --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCC.java | |||
@@ -0,0 +1,146 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc.scc; | ||
11 | |||
12 | import java.util.HashSet; | ||
13 | import java.util.Map; | ||
14 | import java.util.Set; | ||
15 | import java.util.Stack; | ||
16 | |||
17 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
18 | import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory; | ||
19 | |||
20 | /** | ||
21 | * Efficient algorithms to compute the Strongly Connected Components in a directed graph. | ||
22 | * | ||
23 | * @author Tamas Szabo | ||
24 | * | ||
25 | * @param <V> | ||
26 | * the type parameter of the nodes in the graph | ||
27 | */ | ||
28 | public class SCC<V> { | ||
29 | |||
30 | private SCC() {/*Utility class constructor*/} | ||
31 | |||
32 | public static long sccId = 0; | ||
33 | |||
34 | /** | ||
35 | * Computes the SCCs for the given graph and returns them as a multiset. (Iterative version of Tarjan's algorithm) | ||
36 | * | ||
37 | * @param g | ||
38 | * the directed graph data source | ||
39 | * @return the set of SCCs | ||
40 | */ | ||
41 | public static <V> SCCResult<V> computeSCC(IGraphDataSource<V> g) { | ||
42 | int index = 0; | ||
43 | Set<Set<V>> ret = new HashSet<Set<V>>(); | ||
44 | |||
45 | // stores the lowlink and index information for the given node | ||
46 | Map<V, SCCProperty> nodeMap = CollectionsFactory.createMap(); | ||
47 | |||
48 | // stores all target nodes of a given node - the list will be modified | ||
49 | Map<V, Set<V>> targetNodeMap = CollectionsFactory.createMap(); | ||
50 | |||
51 | // stores those target nodes for a given node which have not been visited | ||
52 | Map<V, Set<V>> notVisitedMap = CollectionsFactory.createMap(); | ||
53 | |||
54 | // stores the nodes during the traversal | ||
55 | Stack<V> nodeStack = new Stack<V>(); | ||
56 | |||
57 | // stores the nodes which belong to an scc (there can be many sccs in the stack at the same time) | ||
58 | Stack<V> sccStack = new Stack<V>(); | ||
59 | |||
60 | boolean sink = false, finishedTraversal = true; | ||
61 | |||
62 | // initialize all nodes with 0 index and 0 lowlink | ||
63 | Set<V> allNodes = g.getAllNodes(); | ||
64 | for (V n : allNodes) { | ||
65 | nodeMap.put(n, new SCCProperty(0, 0)); | ||
66 | } | ||
67 | |||
68 | for (V n : allNodes) { | ||
69 | // if the node has not been visited yet | ||
70 | if (nodeMap.get(n).getIndex() == 0) { | ||
71 | nodeStack.push(n); | ||
72 | |||
73 | while (!nodeStack.isEmpty()) { | ||
74 | V currentNode = nodeStack.peek(); | ||
75 | sink = false; | ||
76 | finishedTraversal = false; | ||
77 | SCCProperty prop = nodeMap.get(currentNode); | ||
78 | |||
79 | if (nodeMap.get(currentNode).getIndex() == 0) { | ||
80 | index++; | ||
81 | sccStack.push(currentNode); | ||
82 | prop.setIndex(index); | ||
83 | prop.setLowlink(index); | ||
84 | |||
85 | notVisitedMap.put(currentNode, new HashSet<V>()); | ||
86 | |||
87 | // storing the target nodes of the actual node | ||
88 | if (g.getTargetNodes(currentNode) != null) { | ||
89 | Set<V> targets = g.getTargetNodes(currentNode).distinctValues(); | ||
90 | targetNodeMap.put(currentNode, CollectionsFactory.createSet(targets)); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | if (targetNodeMap.get(currentNode) != null) { | ||
95 | |||
96 | // remove node from stack, the exploration of its children has finished | ||
97 | if (targetNodeMap.get(currentNode).size() == 0) { | ||
98 | targetNodeMap.remove(currentNode); | ||
99 | |||
100 | nodeStack.pop(); | ||
101 | |||
102 | for (V targetNode : g.getTargetNodes(currentNode).distinctValues()) { | ||
103 | if (notVisitedMap.get(currentNode).contains(targetNode)) { | ||
104 | prop.setLowlink(Math.min(prop.getLowlink(), nodeMap.get(targetNode).getLowlink())); | ||
105 | } else if (sccStack.contains(targetNode)) { | ||
106 | prop.setLowlink(Math.min(prop.getLowlink(), nodeMap.get(targetNode).getIndex())); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | finishedTraversal = true; | ||
111 | } else { | ||
112 | V targetNode = targetNodeMap.get(currentNode).iterator().next(); | ||
113 | targetNodeMap.get(currentNode).remove(targetNode); | ||
114 | // if the targetNode has not yet been visited push it to the stack | ||
115 | // and mark it in the notVisitedMap | ||
116 | if (nodeMap.get(targetNode).getIndex() == 0) { | ||
117 | notVisitedMap.get(currentNode).add(targetNode); | ||
118 | nodeStack.add(targetNode); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | // if currentNode has no target nodes | ||
123 | else { | ||
124 | nodeStack.pop(); | ||
125 | sink = true; | ||
126 | } | ||
127 | |||
128 | // create scc if node is a sink or an scc has been found | ||
129 | if ((sink || finishedTraversal) && (prop.getLowlink() == prop.getIndex())) { | ||
130 | Set<V> sc = new HashSet<V>(); | ||
131 | V targetNode = null; | ||
132 | |||
133 | do { | ||
134 | targetNode = sccStack.pop(); | ||
135 | sc.add(targetNode); | ||
136 | } while (!targetNode.equals(currentNode)); | ||
137 | |||
138 | ret.add(sc); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | return new SCCResult<V>(ret, g); | ||
145 | } | ||
146 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCProperty.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCProperty.java new file mode 100644 index 00000000..b26e3d37 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCProperty.java | |||
@@ -0,0 +1,37 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc.scc; | ||
11 | |||
12 | public class SCCProperty { | ||
13 | private int index; | ||
14 | private int lowlink; | ||
15 | |||
16 | public SCCProperty(int index, int lowlink) { | ||
17 | super(); | ||
18 | this.index = index; | ||
19 | this.lowlink = lowlink; | ||
20 | } | ||
21 | |||
22 | public int getIndex() { | ||
23 | return index; | ||
24 | } | ||
25 | |||
26 | public void setIndex(int index) { | ||
27 | this.index = index; | ||
28 | } | ||
29 | |||
30 | public int getLowlink() { | ||
31 | return lowlink; | ||
32 | } | ||
33 | |||
34 | public void setLowlink(int lowlink) { | ||
35 | this.lowlink = lowlink; | ||
36 | } | ||
37 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCResult.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCResult.java new file mode 100644 index 00000000..fde59d3b --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCResult.java | |||
@@ -0,0 +1,81 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc.scc; | ||
11 | |||
12 | import java.util.Map.Entry; | ||
13 | import java.util.Set; | ||
14 | |||
15 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
16 | |||
17 | public class SCCResult<V> { | ||
18 | |||
19 | private Set<Set<V>> sccs; | ||
20 | private IGraphDataSource<V> gds; | ||
21 | |||
22 | public SCCResult(Set<Set<V>> sccs, IGraphDataSource<V> gds) { | ||
23 | this.sccs = sccs; | ||
24 | this.gds = gds; | ||
25 | } | ||
26 | |||
27 | public Set<Set<V>> getSccs() { | ||
28 | return sccs; | ||
29 | } | ||
30 | |||
31 | public int getSCCCount() { | ||
32 | return sccs.size(); | ||
33 | } | ||
34 | |||
35 | public double getAverageNodeCount() { | ||
36 | double a = 0; | ||
37 | |||
38 | for (Set<V> s : sccs) { | ||
39 | a += s.size(); | ||
40 | } | ||
41 | |||
42 | return a / sccs.size(); | ||
43 | } | ||
44 | |||
45 | public double getAverageEdgeCount() { | ||
46 | long edgeSum = 0; | ||
47 | |||
48 | for (Set<V> scc : sccs) { | ||
49 | for (V source : scc) { | ||
50 | for (Entry<V, Integer> entry : gds.getTargetNodes(source).entriesWithMultiplicities()) { | ||
51 | if (scc.contains(entry.getKey())) { | ||
52 | edgeSum += entry.getValue(); | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | |||
58 | return (double) edgeSum / (double) sccs.size(); | ||
59 | } | ||
60 | |||
61 | public int getBiggestSCCSize() { | ||
62 | int max = 0; | ||
63 | |||
64 | for (Set<V> scc : sccs) { | ||
65 | if (scc.size() > max) | ||
66 | max = scc.size(); | ||
67 | } | ||
68 | |||
69 | return max; | ||
70 | } | ||
71 | |||
72 | public long getSumOfSquares() { | ||
73 | long sum = 0; | ||
74 | |||
75 | for (Set<V> scc : sccs) { | ||
76 | sum += scc.size() * scc.size(); | ||
77 | } | ||
78 | |||
79 | return sum; | ||
80 | } | ||
81 | } | ||
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/topsort/TopologicalSorting.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/topsort/TopologicalSorting.java new file mode 100644 index 00000000..dd18e6c8 --- /dev/null +++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/topsort/TopologicalSorting.java | |||
@@ -0,0 +1,77 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2012, 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 | |||
10 | package tools.refinery.viatra.runtime.base.itc.alg.misc.topsort; | ||
11 | |||
12 | import java.util.HashSet; | ||
13 | import java.util.LinkedList; | ||
14 | import java.util.List; | ||
15 | import java.util.Set; | ||
16 | import java.util.Stack; | ||
17 | |||
18 | import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource; | ||
19 | |||
20 | /** | ||
21 | * @since 1.6 | ||
22 | */ | ||
23 | public class TopologicalSorting { | ||
24 | |||
25 | private TopologicalSorting() {/*Utility class constructor*/} | ||
26 | |||
27 | private static final class Pair<T> { | ||
28 | public T element; | ||
29 | public boolean isParent; | ||
30 | |||
31 | public Pair(final T element, final boolean isParent) { | ||
32 | this.element = element; | ||
33 | this.isParent = isParent; | ||
34 | } | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * Returns a topological ordering for the given graph data source. | ||
39 | * Output format: if there is an a -> b (transitive) reachability, then node <code>a</code> will come before node <code>b</code> in the resulting list. | ||
40 | * | ||
41 | * @param gds the graph data source | ||
42 | * @return a topological ordering | ||
43 | */ | ||
44 | public static <T> List<T> compute(final IGraphDataSource<T> gds) { | ||
45 | final Set<T> visited = new HashSet<T>(); | ||
46 | final LinkedList<T> result = new LinkedList<T>(); | ||
47 | final Stack<Pair<T>> dfsStack = new Stack<Pair<T>>(); | ||
48 | |||
49 | for (final T node : gds.getAllNodes()) { | ||
50 | if (!visited.contains(node)) { | ||
51 | dfsStack.push(new Pair<T>(node, false)); | ||
52 | } | ||
53 | |||
54 | while (!dfsStack.isEmpty()) { | ||
55 | final Pair<T> head = dfsStack.pop(); | ||
56 | final T source = head.element; | ||
57 | |||
58 | if (head.isParent) { | ||
59 | // we have already seen source, push it to the resulting stack | ||
60 | result.addFirst(source); | ||
61 | } else { | ||
62 | // first time we see source, continue with its children | ||
63 | visited.add(source); | ||
64 | dfsStack.push(new Pair<T>(source, true)); | ||
65 | |||
66 | for (final T target : gds.getTargetNodes(source).distinctValues()) { | ||
67 | if (!visited.contains(target)) { | ||
68 | dfsStack.push(new Pair<T>(target, false)); | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | return result; | ||
76 | } | ||
77 | } | ||