Skip to content

Commit

Permalink
#31 fixed bugs of the sort-/nf-algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
hoechp committed Mar 5, 2017
1 parent f215a9a commit d1a89a4
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 53 deletions.
4 changes: 4 additions & 0 deletions src/main/java/org/fujaba/graphengine/GraphEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ public static ArrayList<ArrayList<Node>> removeImpossibleCandidates(ArrayList<Ar
return couldMatch;
}

public static Graph normalized(Graph g) {
return getNormalizationFallback().normalized(g);
}

public static int generateHash(Graph g) {
int hash = ((Integer)g.getNodes().size()).hashCode();
for (Node n: g.getNodes()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.fujaba.graphengine.graph.Graph;
import org.fujaba.graphengine.graph.Node;
import org.fujaba.graphengine.isomorphismtools.sort.NodeSortTree;
import org.fujaba.graphengine.isomorphismtools.sort.NodeSortTreeNode;

public class IsomorphismHandlerSorting extends IsomorphismHandler {

Expand All @@ -25,73 +26,120 @@ public boolean isIsomorphTo(Graph one, Graph other) {
public HashMap<Node, Node> 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<Node> targets = node.getEdges(key);
ArrayList<Node> sortedTargetNodes = new ArrayList<Node>();
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<NodeSortTree> nodeSortTrees = new ArrayList<NodeSortTree>();
for (Node node: graph.getNodes()) {
nodeSortTrees.add(new NodeSortTree(graph, node));
}
ArrayList<NodeSortTree> nodeSortTreesCopy = null;
// // sort the list of nodeSortTrees:
// while (!nodeSortTrees.equals(nodeSortTreesCopy)) {
// nodeSortTreesCopy = (ArrayList<NodeSortTree>)nodeSortTrees.clone();
// Collections.sort(nodeSortTrees);
// for (NodeSortTree nodeSortTree: nodeSortTrees) {
// nodeSortTree.doInnerSort(nodeSortTrees);
// }
// }
// sort the list of nodeSortTrees:
ArrayList<String> nodeSortTreesStrings = new ArrayList<String>();
for (NodeSortTree nst: nodeSortTrees) {
nodeSortTreesStrings.add(GraphEngine.getGson().toJson(nst));
if (graph.getNodes().isEmpty()) {
return graph.clone();
}
ArrayList<String> nodeSortTreesCopyStrings = null;
while (!nodeSortTreesStrings.equals(nodeSortTreesCopyStrings)) {
nodeSortTreesCopyStrings = (ArrayList<String>)nodeSortTreesStrings.clone();
HashMap<String, NodeSortTree> mapping = new HashMap<String, NodeSortTree>();
ArrayList<Graph> parts = new ArrayList<Graph>();
// ##### 1.: split #####
for (Graph subGraph: GraphEngine.split(graph)) {
// ##### 2.: do the node-sort-tree sort: #####
ArrayList<NodeSortTree> nodeSortTrees = new ArrayList<NodeSortTree>();
for (Node node: subGraph.getNodes()) {
nodeSortTrees.add(new NodeSortTree(subGraph, node));
}
ArrayList<NodeSortTree> nodeSortTreesCopy = null;
ArrayList<String> nodeSortTreesStrings = new ArrayList<String>();
for (NodeSortTree nst: nodeSortTrees) {
mapping.put(GraphEngine.getGson().toJson(nst), nst);
nodeSortTreesStrings.add(GraphEngine.getGson().toJson(nst));
}
ArrayList<String> nodeSortTreesCopyStrings = null;
while (!nodeSortTreesStrings.equals(nodeSortTreesCopyStrings)) {
nodeSortTreesCopyStrings = (ArrayList<String>)nodeSortTreesStrings.clone();
HashMap<String, NodeSortTree> mapping = new HashMap<String, NodeSortTree>();
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<NodeSortTree>();
for (String s: nodeSortTreesStrings) {
nodeSortTreesCopy.add(mapping.get(s));
}
nodeSortTrees = nodeSortTreesCopy;
for (NodeSortTree nodeSortTree: nodeSortTrees) {
nodeSortTree.doInnerSort(nodeSortTrees);
}
nodeSortTreesStrings = new ArrayList<String>();
for (NodeSortTree nst: nodeSortTrees) {
nodeSortTreesStrings.add(GraphEngine.getGson().toJson(nst));
}
}
Collections.sort(nodeSortTreesStrings);
nodeSortTreesCopy = new ArrayList<NodeSortTree>();
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<Node> 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<String> partsSerialized = new ArrayList<String>();
HashMap<String, ArrayList<Graph>> graphMap = new HashMap<String, ArrayList<Graph>>();
for (Graph g: parts) {
String serialization = GraphEngine.getGson().toJson(g);
if (graphMap.get(serialization) == null) {
graphMap.put(serialization, new ArrayList<Graph>());
}
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<String> used = new ArrayList<String>();
for (String key: partsSerialized) {
if (used.contains(key)) {
continue;
}
nodeSortTreesStrings = new ArrayList<String>();
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<Node> sortedTargets = new ArrayList<Node>();
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<Node> getSortedNodes(NodeSortTree baseNST, ArrayList<Node> nodes) {
ArrayList<Node> result = new ArrayList<Node>();
ArrayList<NodeSortTreeNode> open = new ArrayList<NodeSortTreeNode>();
ArrayList<NodeSortTreeNode> closed = new ArrayList<NodeSortTreeNode>();
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
Expand Down
65 changes: 65 additions & 0 deletions src/test/java/org/fujaba/graphengine/unitTests/GraphTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit d1a89a4

Please sign in to comment.