From d1a89a41b315645ede8c7159e2b0238311ea08d5 Mon Sep 17 00:00:00 2001 From: hoechp Date: Sun, 5 Mar 2017 01:46:02 +0100 Subject: [PATCH] #31 fixed bugs of the sort-/nf-algorithm --- .../org/fujaba/graphengine/GraphEngine.java | 4 + .../IsomorphismHandlerSorting.java | 154 ++++++++++++------ .../graphengine/unitTests/GraphTest.java | 65 ++++++++ 3 files changed, 170 insertions(+), 53 deletions(-) diff --git a/src/main/java/org/fujaba/graphengine/GraphEngine.java b/src/main/java/org/fujaba/graphengine/GraphEngine.java index 68af955..9aef7ff 100644 --- a/src/main/java/org/fujaba/graphengine/GraphEngine.java +++ b/src/main/java/org/fujaba/graphengine/GraphEngine.java @@ -280,6 +280,10 @@ public static ArrayList> removeImpossibleCandidates(ArrayList mappingFrom(Graph subGraph, Graph baseGraph) { return GraphEngine.getMappingFallback().mappingFrom(subGraph, baseGraph); } + + private void sortTargets(Graph g) { + for (Node node: g.getNodes()) { + for (String key: node.getEdges().keySet()) { + ArrayList targets = node.getEdges(key); + ArrayList sortedTargetNodes = new ArrayList(); +targetMatch: for (Node nSorted: g.getNodes()) { + for (Node nTarget: targets) { + if (nSorted == nTarget) { + sortedTargetNodes.add(nSorted); + continue targetMatch; + } + } + } + targets.clear(); + targets.addAll(sortedTargetNodes); + } + } + } @Override @SuppressWarnings("unchecked") public Graph normalized(Graph graph) { - Graph nf = graph.clone(); - // obtain a list of memory-intensive nodeSortTrees to sort all data of the graph: - ArrayList nodeSortTrees = new ArrayList(); - for (Node node: graph.getNodes()) { - nodeSortTrees.add(new NodeSortTree(graph, node)); - } - ArrayList nodeSortTreesCopy = null; -// // sort the list of nodeSortTrees: -// while (!nodeSortTrees.equals(nodeSortTreesCopy)) { -// nodeSortTreesCopy = (ArrayList)nodeSortTrees.clone(); -// Collections.sort(nodeSortTrees); -// for (NodeSortTree nodeSortTree: nodeSortTrees) { -// nodeSortTree.doInnerSort(nodeSortTrees); -// } -// } - // sort the list of nodeSortTrees: - ArrayList nodeSortTreesStrings = new ArrayList(); - for (NodeSortTree nst: nodeSortTrees) { - nodeSortTreesStrings.add(GraphEngine.getGson().toJson(nst)); + if (graph.getNodes().isEmpty()) { + return graph.clone(); } - ArrayList nodeSortTreesCopyStrings = null; - while (!nodeSortTreesStrings.equals(nodeSortTreesCopyStrings)) { - nodeSortTreesCopyStrings = (ArrayList)nodeSortTreesStrings.clone(); - HashMap mapping = new HashMap(); + ArrayList parts = new ArrayList(); + // ##### 1.: split ##### + for (Graph subGraph: GraphEngine.split(graph)) { + // ##### 2.: do the node-sort-tree sort: ##### + ArrayList nodeSortTrees = new ArrayList(); + for (Node node: subGraph.getNodes()) { + nodeSortTrees.add(new NodeSortTree(subGraph, node)); + } + ArrayList nodeSortTreesCopy = null; + ArrayList nodeSortTreesStrings = new ArrayList(); for (NodeSortTree nst: nodeSortTrees) { - mapping.put(GraphEngine.getGson().toJson(nst), nst); + nodeSortTreesStrings.add(GraphEngine.getGson().toJson(nst)); + } + ArrayList nodeSortTreesCopyStrings = null; + while (!nodeSortTreesStrings.equals(nodeSortTreesCopyStrings)) { + nodeSortTreesCopyStrings = (ArrayList)nodeSortTreesStrings.clone(); + HashMap mapping = new HashMap(); + for (NodeSortTree nst: nodeSortTrees) { // TODO: shouldn't this be done just once initially??? + mapping.put(GraphEngine.getGson().toJson(nst), nst); + } + Collections.sort(nodeSortTreesStrings); + nodeSortTreesCopy = new ArrayList(); + for (String s: nodeSortTreesStrings) { + nodeSortTreesCopy.add(mapping.get(s)); + } + nodeSortTrees = nodeSortTreesCopy; + for (NodeSortTree nodeSortTree: nodeSortTrees) { + nodeSortTree.doInnerSort(nodeSortTrees); + } + nodeSortTreesStrings = new ArrayList(); + for (NodeSortTree nst: nodeSortTrees) { + nodeSortTreesStrings.add(GraphEngine.getGson().toJson(nst)); + } } - Collections.sort(nodeSortTreesStrings); - nodeSortTreesCopy = new ArrayList(); - for (String s: nodeSortTreesStrings) { - nodeSortTreesCopy.add(mapping.get(s)); + // ##### 3.: sort sub-graph by layout of the 'first' node-sort-tree: ##### + NodeSortTree baseNST = nodeSortTrees.get(0); + ArrayList sortedNodes = getSortedNodes(baseNST, subGraph.getNodes()); + subGraph.getNodes().clear(); + subGraph.getNodes().addAll(sortedNodes); + sortTargets(subGraph); + parts.add(subGraph); + } + // ##### 4.: merge sub-graphs in order based on their (single) serializations: ##### + ArrayList partsSerialized = new ArrayList(); + HashMap> graphMap = new HashMap>(); + for (Graph g: parts) { + String serialization = GraphEngine.getGson().toJson(g); + if (graphMap.get(serialization) == null) { + graphMap.put(serialization, new ArrayList()); } - nodeSortTrees = nodeSortTreesCopy; - for (NodeSortTree nodeSortTree: nodeSortTrees) { - nodeSortTree.doInnerSort(nodeSortTrees); + graphMap.get(serialization).add(g); + partsSerialized.add(serialization); + } + Collections.sort(partsSerialized); + Graph nf = new Graph(); + ArrayList used = new ArrayList(); + for (String key: partsSerialized) { + if (used.contains(key)) { + continue; } - nodeSortTreesStrings = new ArrayList(); - for (NodeSortTree nst: nodeSortTrees) { - nodeSortTreesStrings.add(GraphEngine.getGson().toJson(nst)); + used.add(key); + for (Graph g: graphMap.get(key)) { + nf.getNodes().addAll(g.getNodes()); } } -// -// -// - nf.getNodes().clear(); - for (int i = 0; i < nodeSortTrees.size(); ++i) { - Node node = nodeSortTrees.get(i).getRootNode(); - for (String key: node.getEdges().keySet()) { - ArrayList sortedTargets = new ArrayList(); - for (int j = 0; j < nodeSortTrees.size(); ++j) { - for (int k = 0; k < node.getEdges(key).size(); ++k) { - Node target = node.getEdges(key).get(k); - if (target == nodeSortTrees.get(j).getRootNode()) { - sortedTargets.add(target); - } - } + return nf; + } + + private ArrayList getSortedNodes(NodeSortTree baseNST, ArrayList nodes) { + ArrayList result = new ArrayList(); + ArrayList open = new ArrayList(); + ArrayList closed = new ArrayList(); + open.add(baseNST.getRootNodeSortTreeNode()); + while (!open.isEmpty()) { + NodeSortTreeNode current = open.remove(0); + closed.add(current); + for (NodeSortTreeNode nst: current.getChildrenNodeSortTreeNodes()) { + if (!open.contains(nst) && !closed.contains(nst)) { + open.add(nst); +// open.add(0, nst); } - node.getEdges(key).clear(); - node.getEdges(key).addAll(sortedTargets); } - nf.getNodes().add(node); + Node node = current.getNode(); + if (!result.contains(node)) { + result.add(node); + } } - return nf; + return result; } @Override diff --git a/src/test/java/org/fujaba/graphengine/unitTests/GraphTest.java b/src/test/java/org/fujaba/graphengine/unitTests/GraphTest.java index 8e7865e..8a16e44 100644 --- a/src/test/java/org/fujaba/graphengine/unitTests/GraphTest.java +++ b/src/test/java/org/fujaba/graphengine/unitTests/GraphTest.java @@ -2,6 +2,7 @@ import java.io.FileReader; import java.util.ArrayList; +import java.util.Collections; import org.fujaba.graphengine.GraphEngine; import org.fujaba.graphengine.graph.Graph; @@ -489,6 +490,70 @@ public void testGraphSplitting() { GraphEngine.isIsomorphTo(a, splitted.get(2)); // ok, after splitting, the third splitted part is the original graph, that was added 3 times } + + /* + * A: B: __ + * (1)--(2) vs (1) (2) + * \/ ¯¯ + * /\ __ + * (3)--(4) (3) (4) + * ¯¯ + */ + @Test + public void testNormalizationNotDoingWickedStuff() { + + Graph a = new Graph(); + Node a1 = new Node(); + Node a2 = new Node(); + Node a3 = new Node(); + Node a4 = new Node(); + a1.addEdge("a", a2); + a1.addEdge("b", a4); + a3.addEdge("a", a4); + a3.addEdge("b", a2); + a.addNode(a1, a2, a3, a4); + + Graph b = new Graph(); + Node b1 = new Node(); + Node b2 = new Node(); + Node b3 = new Node(); + Node b4 = new Node(); + b1.addEdge("a", b2); + b1.addEdge("b", b2); + b3.addEdge("a", b4); + b3.addEdge("b", b4); + b.addNode(b1, b2, b3, b4); + +// System.out.println(); + String lastSerialization = null; + for (int i = 0; i < 100; ++i) { + Collections.shuffle(a.getNodes()); + a = GraphEngine.normalized(a); + if (lastSerialization == null) { + lastSerialization = GraphEngine.getGson().toJson(a); + } else { + String currentSerialization = GraphEngine.getGson().toJson(a); + Assert.assertEquals(lastSerialization, currentSerialization); + lastSerialization = currentSerialization; + } + //System.out.println(GraphEngine.getGson().toJson(a)); + } +// System.out.println(); + lastSerialization = null; + for (int i = 0; i < 100; ++i) { + Collections.shuffle(b.getNodes()); + b = GraphEngine.normalized(b); + if (lastSerialization == null) { + lastSerialization = GraphEngine.getGson().toJson(b); + } else { + String currentSerialization = GraphEngine.getGson().toJson(b); + Assert.assertEquals(lastSerialization, currentSerialization); + lastSerialization = currentSerialization; + } + //System.out.println(GraphEngine.getGson().toJson(b)); + } + + } /** * Method to obtain the initial situation of the ferryman's problem as a graph.