diff --git a/java/com.sap.sse.test/src/com/sap/sse/test/GraphTest.java b/java/com.sap.sse.test/src/com/sap/sse/test/GraphTest.java index 8c064d30726..9643972148a 100644 --- a/java/com.sap.sse.test/src/com/sap/sse/test/GraphTest.java +++ b/java/com.sap.sse.test/src/com/sap/sse/test/GraphTest.java @@ -1,8 +1,10 @@ package com.sap.sse.test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; @@ -12,6 +14,9 @@ import java.util.Set; import org.junit.Test; import com.sap.sse.common.Util; +import com.sap.sse.common.Util.Pair; +import com.sap.sse.util.graph.CycleCluster; +import com.sap.sse.util.graph.CycleClusters; import com.sap.sse.util.graph.DirectedEdge; import com.sap.sse.util.graph.DirectedGraph; @@ -31,6 +36,30 @@ public class GraphTest { assertEquals(2, graph.getCycleClusters().getClusters().iterator().next().getClusterNodes().size()); } + @Test + public void testVerySimpleCycleDetectionWithTwoCycles() { + final String a = "a"; + final String b = "b"; + final String c = "c"; + final String d = "d"; + final Set nodes = new HashSet<>(); + nodes.add(a); + nodes.add(b); + nodes.add(c); + nodes.add(d); + final Set> edges = new HashSet<>(); + edges.add(DirectedEdge.create(a, b)); + edges.add(DirectedEdge.create(b, a)); + edges.add(DirectedEdge.create(c, d)); + edges.add(DirectedEdge.create(d, c)); + edges.add(DirectedEdge.create(a, c)); // connect the two cycles, but not cyclically + DirectedGraph graph = DirectedGraph.create(nodes, edges); + assertEquals(2, Util.size(graph.getCycleClusters().getClusters())); + for (final CycleCluster cluster : graph.getCycleClusters().getClusters()) { + assertEquals(2, cluster.getClusterNodes().size()); + } + } + @Test public void testCycleDetection() { final String cro = "CRO"; @@ -156,4 +185,98 @@ public class GraphTest { assertEquals(1, Util.size(graph.getCycleClusters().getClusters())); assertEquals(6, graph.getCycleClusters().getClusters().iterator().next().getClusterNodes().size()); } + + @Test + public void testCompetitorGraphWithMultipleCycles() { + final String usa1 = "USA1"; + final String cro = "CRO"; + final String pol2 = "POL2"; + final String fin = "FIN"; + final String ger = "GER"; + final String nor = "NOR"; + final String ksss = "KSSS"; + final String pot = "POT"; + final String usa2 = "USA2"; + final String mal = "MAL"; + final Set nodes = new LinkedHashSet<>(); + nodes.addAll(Arrays.asList(usa2, nor, ksss, pot, pol2, usa1, cro, mal, fin, ger)); + final Set> edges = new HashSet<>(); + // USA 2 LISOT Black with boat USA 2 LISOT Black=[Norway with boat Norway, Sweden KSSS with boat Sweden KSSS, + // Potsdamer Yacht Club with boat Potsdamer Yacht Club, Poland 2 with boat Poland 2, Sweden Malmström with boat + // Sweden Malmström, Finland with boat Finland, Germany Worlds with boat Germany Worlds] + edges.add(DirectedEdge.create(usa2, nor)); + edges.add(DirectedEdge.create(usa2, ksss)); + edges.add(DirectedEdge.create(usa2, pot)); + edges.add(DirectedEdge.create(usa2, pol2)); + edges.add(DirectedEdge.create(usa2, mal)); + edges.add(DirectedEdge.create(usa2, fin)); + edges.add(DirectedEdge.create(usa2, ger)); + // Norway with boat Norway=[Finland with boat Finland] + edges.add(DirectedEdge.create(nor, fin)); + // Sweden KSSS with boat Sweden KSSS=[Norway with boat Norway, Potsdamer Yacht Club with boat Potsdamer Yacht + // Club, Poland 2 with boat Poland 2, USA 1 Hampton Sailing Club with boat USA 1 Hampton Sailing Club, Finland + // with boat Finland] + edges.add(DirectedEdge.create(ksss, nor)); + edges.add(DirectedEdge.create(ksss, pot)); + edges.add(DirectedEdge.create(ksss, pol2)); + edges.add(DirectedEdge.create(ksss, usa1)); + edges.add(DirectedEdge.create(ksss, fin)); + // Potsdamer Yacht Club with boat Potsdamer Yacht Club=[Norway with boat Norway, Finland with boat Finland] + edges.add(DirectedEdge.create(pot, nor)); + edges.add(DirectedEdge.create(pot, fin)); + // Poland 2 with boat Poland 2=[Norway with boat Norway, Sweden KSSS with boat Sweden KSSS, Potsdamer Yacht Club + // with boat Potsdamer Yacht Club, Finland with boat Finland] + edges.add(DirectedEdge.create(nor, ksss)); + edges.add(DirectedEdge.create(nor, pot)); + edges.add(DirectedEdge.create(nor, fin)); + // USA 1 Hampton Sailing Club with boat USA 1 Hampton Sailing Club=[USA 2 LISOT Black with boat USA 2 LISOT + // Black, Norway with boat Norway, Sweden KSSS with boat Sweden KSSS, Potsdamer Yacht Club with boat Potsdamer + // Yacht Club, Poland 2 with boat Poland 2, Finland with boat Finland, Germany Worlds with boat Germany Worlds] + edges.add(DirectedEdge.create(usa1, usa2)); + edges.add(DirectedEdge.create(usa1, nor)); + edges.add(DirectedEdge.create(usa1, ksss)); + edges.add(DirectedEdge.create(usa1, pot)); + edges.add(DirectedEdge.create(usa1, pol2)); + edges.add(DirectedEdge.create(usa1, fin)); + edges.add(DirectedEdge.create(usa1, ger)); + // Croatia with boat Croatia=[USA 2 LISOT Black with boat USA 2 LISOT Black, Norway with boat Norway, Sweden + // KSSS with boat Sweden KSSS, Potsdamer Yacht Club with boat Potsdamer Yacht Club, Poland 2 with boat Poland 2, + // USA 1 Hampton Sailing Club with boat USA 1 Hampton Sailing Club, Finland with boat Finland, Sweden Malmström + // with boat Sweden Malmström, Germany Worlds with boat Germany Worlds] + edges.add(DirectedEdge.create(cro, usa2)); + edges.add(DirectedEdge.create(cro, nor)); + edges.add(DirectedEdge.create(cro, ksss)); + edges.add(DirectedEdge.create(cro, pot)); + edges.add(DirectedEdge.create(cro, pol2)); + edges.add(DirectedEdge.create(cro, usa1)); + edges.add(DirectedEdge.create(cro, fin)); + edges.add(DirectedEdge.create(cro, mal)); + edges.add(DirectedEdge.create(cro, ger)); + // Sweden Malmström with boat Sweden Malmström=[Norway with boat Norway, Sweden KSSS with boat Sweden KSSS, + // Potsdamer Yacht Club with boat Potsdamer Yacht Club, Poland 2 with boat Poland 2, USA 1 Hampton Sailing Club + // with boat USA 1 Hampton Sailing Club, Croatia with boat Croatia, Finland with boat Finland, Germany Worlds + // with boat Germany Worlds] + edges.add(DirectedEdge.create(mal, nor)); + edges.add(DirectedEdge.create(mal, ksss)); + edges.add(DirectedEdge.create(mal, pot)); + edges.add(DirectedEdge.create(mal, pol2)); + edges.add(DirectedEdge.create(mal, usa1)); + edges.add(DirectedEdge.create(mal, cro)); + edges.add(DirectedEdge.create(mal, fin)); + edges.add(DirectedEdge.create(mal, ger)); + // Finland with boat Finland=[Potsdamer Yacht Club with boat Potsdamer Yacht Club] + edges.add(DirectedEdge.create(fin, pot)); + // Germany Worlds with boat Germany Worlds=[Norway with boat Norway, Sweden KSSS with boat Sweden KSSS, + // Potsdamer Yacht Club with boat Potsdamer Yacht Club, Poland 2 with boat Poland 2, Finland with boat Finland] + edges.add(DirectedEdge.create(ger, nor)); + edges.add(DirectedEdge.create(ger, ksss)); + edges.add(DirectedEdge.create(ger, pot)); + edges.add(DirectedEdge.create(ger, pol2)); + edges.add(DirectedEdge.create(ger, fin)); + // graph construction: + final DirectedGraph graph = DirectedGraph.create(nodes, edges); + final Pair, CycleClusters> dag = graph.graphWithCombinedCycleNodes(); + // tests: + assertTrue(Util.isEmpty(dag.getA().getCycleClusters().getClusters())); + } } diff --git a/java/com.sap.sse/src/com/sap/sse/util/graph/impl/CycleClustersImpl.java b/java/com.sap.sse/src/com/sap/sse/util/graph/impl/CycleClustersImpl.java index 40f7058487c..7301653fabc 100755 --- a/java/com.sap.sse/src/com/sap/sse/util/graph/impl/CycleClustersImpl.java +++ b/java/com.sap.sse/src/com/sap/sse/util/graph/impl/CycleClustersImpl.java @@ -32,7 +32,7 @@ public class CycleClustersImpl implements CycleClusters { @Override public boolean isEdgeInCycleCluster(DirectedEdge edge) { - return clusters.stream().anyMatch(c->c.contains(edge.getFrom() )&& c.contains(edge.getTo())); + return clusters.stream().anyMatch(c->c.contains(edge.getFrom()) && c.contains(edge.getTo())); } @Override diff --git a/java/com.sap.sse/src/com/sap/sse/util/graph/impl/DirectedGraphImpl.java b/java/com.sap.sse/src/com/sap/sse/util/graph/impl/DirectedGraphImpl.java index 5bafd703926..5414d6b0e0b 100755 --- a/java/com.sap.sse/src/com/sap/sse/util/graph/impl/DirectedGraphImpl.java +++ b/java/com.sap.sse/src/com/sap/sse/util/graph/impl/DirectedGraphImpl.java @@ -88,54 +88,33 @@ public class DirectedGraphImpl implements DirectedGraph { } } - private class TraverseNonTreeEdge implements DFSStep { + private class TraverseEdge implements DFSStep { private final T toNode; - - public TraverseNonTreeEdge(T toNode) { + + public TraverseEdge(T toNode) { this.toNode = toNode; } - + @Override public int applyAndReturnNextDFSNumber(LinkedList oReps, LinkedList oNodes, Map representatives, Map depthFirstSearchPosition, Set remainingRoots, LinkedList> worklist, int nodeCounter, Set oNodesForFastContains) { - if (oNodesForFastContains.contains(toNode)) { - while (depthFirstSearchPosition.get(toNode) < depthFirstSearchPosition.get(oReps.getLast())) { - oReps.removeLast(); + if (depthFirstSearchPosition.containsKey(toNode)) { + if (oNodesForFastContains.contains(toNode)) { + while (depthFirstSearchPosition.get(toNode) < depthFirstSearchPosition.get(oReps.getLast())) { + oReps.removeLast(); + } } + } else { + oReps.add(toNode); + oNodes.add(toNode); + oNodesForFastContains.add(toNode); + remainingRoots.remove(toNode); + depthFirstSearchPosition.put(toNode, nodeCounter++); + worklist.add(new DFS(toNode)); } return nodeCounter; } - - @Override - public String toString() { - return "traverseNonTreeEdge("+toNode+")"; - } - } - - private class TraverseTreeEdge implements DFSStep { - private final T toNode; - - public TraverseTreeEdge(T toNode) { - this.toNode = toNode; - } - - @Override - public int applyAndReturnNextDFSNumber(LinkedList oReps, LinkedList oNodes, Map representatives, - Map depthFirstSearchPosition, Set remainingRoots, LinkedList> worklist, int nodeCounter, Set oNodesForFastContains) { - oReps.add(toNode); - oNodes.add(toNode); - oNodesForFastContains.add(toNode); - remainingRoots.remove(toNode); - depthFirstSearchPosition.put(toNode, nodeCounter++); - worklist.add(new DFS(toNode)); - return nodeCounter; - } - - @Override - public String toString() { - return "traverseTreeEdge("+toNode+")"; - } } private class Root implements DFSStep { @@ -176,11 +155,7 @@ public class DirectedGraphImpl implements DirectedGraph { Map depthFirstSearchPosition, Set remainingRoots, LinkedList> worklist, int nodeCounter, Set oNodesForFastContains) { worklist.add(new Backtrack(to)); for (final T successor : immediateSuccessors.get(to)) { - if (depthFirstSearchPosition.containsKey(successor)) { - worklist.add(new TraverseNonTreeEdge(successor)); - } else { - worklist.add(new TraverseTreeEdge(successor)); - } + worklist.add(new TraverseEdge(successor)); } return nodeCounter; }