]> gerrit.simantics Code Review - simantics/interop.git/blobdiff - org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java
Path comparisons are now much more reliable
[simantics/interop.git] / org.simantics.interop / src / org / simantics / interop / test / GraphComparator.java
index 4fb9cf24e88e9f2b8078c5e3036019445aec2a8d..58e2c0531cb41bec456b451663450b6a6a030881 100644 (file)
@@ -16,17 +16,22 @@ import java.util.Arrays;
 import java.util.Collection;\r
 import java.util.Collections;\r
 import java.util.Comparator;\r
+import java.util.HashMap;\r
 import java.util.HashSet;\r
 import java.util.List;\r
+import java.util.Map;\r
 import java.util.Set;\r
 import java.util.Stack;\r
 \r
 import org.simantics.db.ReadGraph;\r
 import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
 import org.simantics.db.Statement;\r
+import org.simantics.db.common.request.ReadRequest;\r
 import org.simantics.db.common.utils.NameUtils;\r
 import org.simantics.db.exception.DatabaseException;\r
 import org.simantics.db.exception.DoesNotContainValueException;\r
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
 import org.simantics.db.exception.ServiceException;\r
 import org.simantics.db.exception.ValidationException;\r
 import org.simantics.layer0.Layer0;\r
@@ -50,6 +55,7 @@ public class GraphComparator {
 \r
        private Resource r1;\r
        private Resource r2;\r
+       private Set<Resource> strong = new HashSet<Resource>();       // List of relations that identify object, if subject is already identified. \r
        private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)\r
        private List<Resource> tested = new ArrayList<Resource>();    // list of relations that are tested, but not traversed\r
        private List<Resource> nonTraversed = new ArrayList<Resource>(); // list of relations that are not traversed\r
@@ -64,12 +70,12 @@ public class GraphComparator {
 \r
        private BijectionMap<Statement, Statement> comparableStatements = new BijectionMap<Statement, Statement>();\r
        private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<Resource, Resource>();\r
+       private Set<Resource> processedResources = new HashSet<Resource>();\r
        \r
-       \r
-       private ObjectComparator comparator;\r
+       private ResourceComparator comparator;\r
        \r
        private Comparator<Statement> scomp = new PredicateComparator();\r
-       private Comparator<Resource> rcomp = new ResourceComparator();\r
+       private Comparator<Resource> rcomp = new ResComparator();\r
        \r
        // runtime attributes\r
        \r
@@ -82,7 +88,7 @@ public class GraphComparator {
                comparator = new TypeComparator();\r
        }\r
        \r
-       public GraphComparator(Resource r1, Resource r2, ObjectComparator comparator) {\r
+       public GraphComparator(Resource r1, Resource r2, ResourceComparator comparator) {\r
                this.r1 = r1;\r
                this.r2 = r2;\r
                this.comparator = comparator;\r
@@ -148,36 +154,129 @@ public class GraphComparator {
                comparableResources.addAll(matching);\r
        }\r
        \r
-       public void clearRels() {\r
-               traversed.clear();\r
-               tested.clear();\r
-               nonTraversed.clear();\r
-               nonTested.clear();\r
+       public void addStrong(Resource r) {\r
+               strong.add(r);\r
+       }\r
+       \r
+       public void addStrong(Collection<Resource> rels) {\r
+               strong.addAll(rels);\r
        }\r
        \r
+       \r
        public void test(ReadGraph g) throws DatabaseException {\r
                this.g = g;\r
                this.b = Layer0.getInstance(g);\r
                comparator.setComparator(this);\r
                \r
-               Stack<Resource> stack1 = new Stack<Resource>();\r
-               Stack<Resource> stack2 = new Stack<Resource>();\r
-               stack1.push(r1);\r
-               stack2.push(r2);\r
+               Stack<Resource> objectsLeft = new Stack<Resource>();\r
+               Stack<Resource> objectsRight = new Stack<Resource>();\r
+               objectsLeft.push(r1);\r
+               objectsRight.push(r2);\r
                \r
+               Set<Statement> unreliableLeft = new HashSet<Statement>();\r
+               Set<Statement> unreliableRight = new HashSet<Statement>();\r
                \r
+               while (true) {\r
+                       if (objectsLeft.isEmpty())\r
+                               break;\r
+                       \r
+                       \r
+                       // process compares objects that are identified and searches for more resources to process. \r
+                       process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);\r
+                       // process unreliable handles cases where unidentified statements subject and object have been identified \r
+                       processUnreliable(unreliableLeft, unreliableRight);\r
+                       // process unreliable handles cases where unidentified resources have path of length one to identified resource\r
+                       processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);\r
+                       if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {\r
+                               // comparison is ending, but we have still unprocessed unidentified resources left.\r
+                               // These cases have longer path than one to identified objects.\r
+                               processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);\r
+                       }\r
+                       \r
+               }\r
+               for (Statement s : unreliableLeft) {\r
+                       if (!comparableStatements.containsLeft(s))\r
+                               addDeletion(s);\r
+               }\r
+               for (Statement s : unreliableRight) {\r
+                       if (!comparableStatements.containsRight(s))\r
+                               addAddition(s);\r
+               }\r
+               \r
+               \r
+       }\r
+       \r
+       public void test(Session session) throws DatabaseException {\r
+               \r
+               comparator.setComparator(this);\r
+               \r
+               comparableResources.map(r1, r2);\r
+               \r
+               final Stack<Resource> objectsLeft = new Stack<Resource>();\r
+               final Stack<Resource> objectsRight = new Stack<Resource>();\r
+               objectsLeft.push(r1);\r
+               objectsRight.push(r2);\r
+               \r
+               final Set<Statement> unreliableLeft = new HashSet<Statement>();\r
+               final Set<Statement> unreliableRight = new HashSet<Statement>();\r
+               \r
+               while (true) {\r
+                       if (objectsLeft.isEmpty())\r
+                               break;\r
+                       session.syncRequest(new ReadRequest() {\r
+                               \r
+                               @Override\r
+                               public void run(ReadGraph graph) throws DatabaseException {\r
+                                       g = graph;\r
+                                       b = Layer0.getInstance(graph);\r
+                                       // process compares objects that are identified and searches for more resources to process. \r
+                                       process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);\r
+                                       // process unreliable handles cases where unidentified statements subject and object have been identified \r
+                                       processUnreliable(unreliableLeft, unreliableRight);\r
+                                       // process unreliable handles cases where unidentified resources have path of length one to identified resource\r
+                                       processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);\r
+                                       if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {\r
+                                               // comparison is ending, but we have still unprocessed unidentified resources left.\r
+                                               // These cases have longer path than one to identified objects.\r
+                                               processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);\r
+                                       }\r
+                               }\r
+                       });\r
+                       \r
+                       \r
+                       \r
+               }\r
+               for (Statement s : unreliableLeft) {\r
+                       if (!comparableStatements.containsLeft(s))\r
+                               addDeletion(s);\r
+               }\r
+               for (Statement s : unreliableRight) {\r
+                       if (!comparableStatements.containsRight(s))\r
+                               addAddition(s);\r
+               }\r
+               \r
+               \r
+       }\r
+       \r
+       private void process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {\r
                List<Statement> ss1 = new ArrayList<Statement>();\r
                List<Statement> ss2 = new ArrayList<Statement>();\r
                \r
-               while (!stack1.isEmpty()) {\r
-                       Resource r1 = stack1.pop();\r
-                       Resource r2 = stack2.pop();\r
-               \r
-                       if (comparableResources.contains(r1, r2)) {\r
-                               //System.out.println("already tested " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
+               while (!objectsLeft.isEmpty()) {\r
+                       Resource r1 = objectsLeft.pop();\r
+                       Resource r2 = objectsRight.pop();\r
+                       \r
+                       if (r1.equals(r2))\r
                                continue;\r
+                       \r
+                       if (processedResources.contains(r1))\r
+                               continue;\r
+                       processedResources.add(r1);\r
+                       \r
+               \r
+                       if(!comparableResources.contains(r1, r2) && (comparableResources.containsLeft(r1)||comparableResources.containsRight(r2))) {\r
+                               throw new DatabaseException("Comparator error: Trying to map " + r1 + " to " + r2 + " while mappings " + r1 + " to " + comparableResources.getRight(r1) + " and " + comparableResources.getLeft(r2) + " to " + r2 + " exist.");\r
                        }\r
-                       comparableResources.map(r1, r2);\r
                        \r
                        //System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
                        compareProps(r1, r2);\r
@@ -192,7 +291,7 @@ public class GraphComparator {
                                ss1 = filterNonTested(ss1);\r
                                ss2 = filterNonTested(ss2);\r
                                \r
-                               compareStatements(ss1, ss2, null, null);\r
+                               compareStatements(ss1, ss2, null, null,null,null);\r
                                ss1.clear();\r
                                ss2.clear();\r
                        }\r
@@ -202,14 +301,371 @@ public class GraphComparator {
                                ss2.addAll(g.getStatements(r2, rel));\r
                                ss1 = filterAsserted(r1, ss1);\r
                                ss2 = filterAsserted(r2, ss2);\r
-                               compareStatements(ss1, ss2, stack1, stack2);\r
+                               compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);\r
                                ss1.clear();\r
                                ss2.clear();\r
+                               \r
                        }\r
                }\r
-       }\r
+       }\r
        \r
+       private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {\r
+               MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();\r
+               \r
+               for (Statement s : unreliableLeft) {\r
+                       subjectLeft.add(s.getSubject(),s);\r
+                       objectLeft.add(s.getObject(),s);\r
+               }\r
+               for (Statement s : unreliableRight) {\r
+                       subjectRight.add(s.getSubject(),s);\r
+                       objectRight.add(s.getObject(),s);\r
+               }\r
+               \r
+               for (Resource left : subjectLeft.getKeys()) {\r
+                       if (!comparableResources.containsLeft(left))\r
+                               continue;\r
+                       Resource right = comparableResources.getRight(left);\r
+                       for (Statement leftS : subjectLeft.getValues(left)) {\r
+                               Resource leftO = leftS.getObject();\r
+                               if (!comparableResources.containsLeft(leftO)) \r
+                                       continue;\r
+                               if (!unreliableLeft.contains(leftS))\r
+                                       continue;\r
+                               Resource rightO = comparableResources.getRight(leftO);\r
+                               for (Statement rightS : subjectRight.getValues(right)) {\r
+                                       if (!rightS.getObject().equals(rightO))\r
+                                               continue;\r
+                                       if (!unreliableRight.contains(rightS))\r
+                                               continue;\r
+                                       if (leftS.getPredicate().equals(rightS.getPredicate()) ||\r
+                                               comparableResources.contains(leftS.getPredicate(), rightS.getPredicate())) {\r
+                                               unreliableLeft.remove(leftS);\r
+                                               unreliableRight.remove(rightS);\r
+                                               addComparable(leftS, rightS, false);\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+               }\r
+       }\r
        \r
+       private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {\r
+               MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();\r
+               \r
+               for (Statement s : unreliableLeft) {\r
+                       subjectLeft.add(s.getSubject(),s);\r
+                       objectLeft.add(s.getObject(),s);\r
+               }\r
+               for (Statement s : unreliableRight) {\r
+                       subjectRight.add(s.getSubject(),s);\r
+                       objectRight.add(s.getObject(),s);\r
+               }\r
+               \r
+               for (Resource ol : objectLeft.getKeys()) {\r
+                       // all statements to the left side object\r
+                       List<Statement> left = objectLeft.getValues(ol);\r
+                       // all subjects that have statements to the left side object (ol)\r
+                       Set<Resource> sLeft = new HashSet<Resource>();\r
+                       // all matching subjects on the right side\r
+                       Set<Resource> sRight = new HashSet<Resource>();\r
+                       for (Statement s : left) {\r
+                               sLeft.add(s.getSubject());\r
+                               sRight.add(comparableResources.getRight(s.getSubject()));\r
+                       }\r
+                       \r
+                       // check if object left can be reliably identified by available statements\r
+                       // if there are any objects on the left side with similar statements, object left cannot be mapped.\r
+                       boolean hasSimilar = false;\r
+                       MapList<Resource, Statement> comparableOLeft = new MapList<Resource, Statement>();\r
+                       for (Resource sl : sLeft) {\r
+                               for (Statement s : subjectLeft.getValues(sl)) {\r
+                                       if (!s.getObject().equals(ol)) {\r
+                                               comparableOLeft.add(s.getObject(),s);\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       for (Resource similarOl : comparableOLeft.getKeys()) {\r
+                               List<Statement> similarLeft = comparableOLeft.getValues(similarOl);\r
+                               if (similarLeft.size() == left.size()) {\r
+                                       boolean useL[] = new boolean[left.size()];\r
+                                       boolean useSL[] = new boolean[left.size()];\r
+                                       for (int i = 0; i < left.size(); i++) {\r
+                                               useL[i] = false;\r
+                                               useSL[i] = false;\r
+                                       }\r
+                                       for (int i = 0; i < left.size(); i++) {\r
+                                               for (int j = 0; j < left.size(); j++) {\r
+                                                       if (useSL[j])\r
+                                                               continue;\r
+                                                       Resource pl = left.get(i).getPredicate();\r
+                                                       Resource psl = similarLeft.get(j).getPredicate();\r
+                                                       if (pl.equals(psl)) {\r
+                                                               useL[i] = true;\r
+                                                               useSL[j] = true;\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       boolean diff = false;\r
+                                       for (int i = 0; i < left.size(); i++) {\r
+                                               if (!useL[i] || !useSL[i]) {\r
+                                                       diff = true;\r
+                                               }\r
+                                       }\r
+                                       if (!diff) {\r
+                                               hasSimilar = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       if (hasSimilar)\r
+                               continue;\r
+                               \r
+                       \r
+                       // all objects that subjects on the right side point to. Object left has its matching resource among these, if it has matching resource\r
+                       MapList<Resource,Statement> possibleOR = new MapList<Resource, Statement>();\r
+                       for (Resource sr : sRight) {\r
+                               for (Statement s : subjectRight.getValues(sr))\r
+                                       possibleOR.add(s.getObject(),s);\r
+                       }\r
+                       \r
+                       // filter possible right side objects to those that have same amount of statements as the left side object\r
+                       for (Resource or : possibleOR.getKeys().toArray(new Resource[possibleOR.getKeys().size()])) {\r
+                               List<Statement> right = possibleOR.getValues(or);\r
+                               if (right.size() != left.size())\r
+                                       possibleOR.remove(or);\r
+                                       \r
+                       }\r
+                       \r
+                       // check for matching statements (comparable subjects, matching predicates)\r
+                       MapList<Resource,Statement> matchingOR = new MapList<Resource, Statement>(); // list of objects that have matching statements\r
+                       Map<Resource,Pair<int[], int[]>> matchingStatements = new HashMap<Resource, Pair<int[], int[]>>(); // matching statements\r
+                       for (Resource or : possibleOR.getKeys()) {\r
+                               List<Statement> right = possibleOR.getValues(or);\r
+                               int iLeft[] = new int[left.size()];\r
+                               int iRight[] = new int[right.size()];\r
+                               \r
+                               for (int i = 0; i < left.size(); i++) {\r
+                                       iLeft[i] = -1;\r
+                                       iRight[i] = -1;\r
+                               }\r
+                               \r
+                               for (int l = 0; l < left.size(); l++) {\r
+                                       Statement ls = left.get(l);\r
+                                       for (int r = 0; r < right.size(); r++) {\r
+                                               if (iRight[r] >= 0)\r
+                                                       continue;\r
+                                               Statement rs = right.get(r);\r
+                                               if (!comparableResources.contains(ls.getSubject(), rs.getSubject()))\r
+                                                       continue;\r
+                                               if (rcomp.compare(ls.getPredicate(),rs.getPredicate()) == 0) {\r
+                                                       iLeft[l] = r;\r
+                                                       iRight[r] = l;\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                                       \r
+                               }\r
+                               boolean success = true;\r
+                               for (int i = 0; i < left.size(); i++) {\r
+                                       if (iLeft[i] < 0) {\r
+                                               success = false;\r
+                                               break;\r
+                                       }\r
+                                       if (iRight[i] < 0) {\r
+                                               success = false;\r
+                                               break;\r
+                                       }\r
+                                               \r
+                               }\r
+                               if (success) {\r
+                                       for (Statement s : right) \r
+                                               matchingOR.add(or,s);\r
+                                       matchingStatements.put(or, new Pair<int[], int[]>(iLeft, iRight));\r
+                               }\r
+                       }\r
+                       // if there is only one matching right side object, we have found a match \r
+                       if (matchingOR.getKeySize() == 1) {\r
+                               Resource or = matchingOR.getKeys().iterator().next();\r
+                               List<Statement> right = matchingOR.getValues(or);\r
+                               Pair<int[], int[]> indices = matchingStatements.get(or);\r
+                               \r
+                               objectsLeft.add(ol);\r
+                               objectsRight.add(or);\r
+                               addComparable(ol, or, false);\r
+                               for (int l = 0; l < left.size(); l++) {\r
+                                       int r = indices.first[l];\r
+                                       Statement sl = left.get(l);\r
+                                       Statement sr = right.get(r);\r
+                                       addComparable(sl, sr, true);\r
+                                       unreliableLeft.remove(sl);\r
+                                       unreliableRight.remove(sr);\r
+                               }\r
+                               \r
+                       }\r
+\r
+               }\r
+               \r
+               \r
+       }\r
+       \r
+       private void processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {\r
+               MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();\r
+               MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();\r
+               \r
+               for (Statement s : unreliableLeft) {\r
+                       subjectLeft.add(s.getSubject(),s);\r
+                       objectLeft.add(s.getObject(),s);\r
+               }\r
+               for (Statement s : unreliableRight) {\r
+                       subjectRight.add(s.getSubject(),s);\r
+                       objectRight.add(s.getObject(),s);\r
+               }\r
+               for (Resource ol : objectLeft.getKeys()) {\r
+                       Set<Path> pathsLeft = new HashSet<Path>();\r
+                       for (Resource rel : traversed) {\r
+                               pathsLeft.addAll(Path.create(g.getStatements(ol, rel)));\r
+                       }\r
+                       while (true) {\r
+                               expand(pathsLeft);\r
+                               if (pathsLeft.size() == 0)\r
+                                       break;\r
+                               Collection<Path> endPaths = new ArrayList<Path>(1);\r
+                               for (Path p : pathsLeft) {\r
+                                       if (comparableResources.containsLeft(p.getEnd())) {\r
+                                               endPaths.add(p);\r
+                                       }\r
+                               }\r
+                               if (endPaths.size() > 0) {\r
+                                       pathsLeft.clear();\r
+                                       pathsLeft.addAll(endPaths);\r
+                                       break;\r
+                               }       \r
+                       }\r
+                       if (pathsLeft.size() > 0) {\r
+                               Resource sl = objectLeft.getValues(ol).get(0).getSubject();\r
+                               Resource sr = comparableResources.getRight(sl);\r
+                               Collection<Resource> possibleOR = new ArrayList<Resource>();\r
+                               for (Statement s : subjectRight.getValues(sr)) {\r
+                                       possibleOR.add(s.getObject());\r
+                               }\r
+                               Map<Resource,Set<Path>> matchingPaths = new HashMap<Resource, Set<Path>>();\r
+                               for (Resource or : possibleOR) {\r
+                                       Set<Path> possiblePathsRight = new HashSet<Path>();\r
+                                       for (Path leftPath : pathsLeft) {\r
+                                               possiblePathsRight.addAll(findComparableRight(leftPath, or));\r
+                                       }\r
+                                       if (hasMatchingPaths(pathsLeft, possiblePathsRight)) {\r
+                                               matchingPaths.put(or, possiblePathsRight);\r
+                                       }\r
+                               }\r
+                               if (matchingPaths.size() > 0) {\r
+                                       if (matchingPaths.size() == 1) {\r
+                                               Resource or = matchingPaths.keySet().iterator().next();\r
+                                               \r
+                                               objectsLeft.add(ol);\r
+                                               objectsRight.add(or);\r
+                                               addComparable(ol, or, false);\r
+                                               Collection<Statement> statementsLeft = objectLeft.getValues(ol);\r
+                                               Collection<Statement> statementsRight = objectRight.getValues(or);\r
+                                               unreliableLeft.removeAll(statementsLeft);\r
+                                               unreliableRight.removeAll(statementsRight);\r
+                                               BijectionMap<Path,Path> map = getMatchingPaths(pathsLeft, matchingPaths.get(or));\r
+                                               for (Path left : map.getLeftSet()) {\r
+                                                       Path right = map.getRight(left);\r
+                                                       for (int i = 0; i < left.getLength(); i++) {\r
+                                                               addComparable(left.getStatements().get(i),right.getStatements().get(i),false);\r
+                                                       }\r
+                                               }\r
+                                               //System.out.println("Compare not implemented");\r
+                                       } else {\r
+                                               //System.out.println("Compare not implemented");\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+               }\r
+               \r
+       }\r
+       \r
+       private boolean hasMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {\r
+               if (leftPaths.size() != rightPaths.size())\r
+                       return false;\r
+               BijectionMap<Path,Path> map = getMatchingPaths(leftPaths, rightPaths);\r
+               return map.size() == leftPaths.size();\r
+                       \r
+       }\r
+       \r
+       private BijectionMap<Path,Path> getMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {\r
+               BijectionMap<Path,Path> map = new BijectionMap<Path, Path>();\r
+               for (Path leftPath : leftPaths) {\r
+                       for (Path rightPath : rightPaths) {\r
+                               if (map.containsRight(rightPath))\r
+                                       continue;\r
+                               if (leftPath.getLength() != rightPath.getLength())\r
+                                       continue;\r
+                               if (comparableResources.contains(leftPath.getEnd(), rightPath.getEnd())) {\r
+                                       map.map(leftPath, rightPath);\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+               return map;\r
+       }\r
+       \r
+       private void expand(Set<Path> paths) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
+               Set<Path> stepPathsLeft = new HashSet<Path>();\r
+               if (paths.size() == 0)\r
+                       return;\r
+               int length = paths.iterator().next().getLength() + 1;\r
+               for (Path p : paths) {\r
+                       for (Resource rel : traversed) {\r
+                               stepPathsLeft.addAll(Path.expand(p,g.getStatements(p.getEnd(), rel)));\r
+                       }\r
+               }\r
+               paths.clear();\r
+               for (Path p : stepPathsLeft) {\r
+                       if (p.getLength() == length)\r
+                               paths.add(p);\r
+               }\r
+       }\r
+       \r
+       private Collection<Path> findComparableRight(Path leftPath, Resource beginRight) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
+               Set<Path> rightPaths = new HashSet<Path>();\r
+               rightPaths.addAll(Path.create(g.getStatements(beginRight, getRight(leftPath.getStatements().get(0).getPredicate()))));\r
+               for (int i = 1; i < leftPath.getLength(); i++) {\r
+                       if (rightPaths.size() == 0)\r
+                               return rightPaths;\r
+                       Set<Path> stepPaths = new HashSet<Path>();\r
+                       for (Path p : rightPaths) {\r
+                               stepPaths.addAll(Path.expand(p, g.getStatements(p.getEnd(), getRight(leftPath.getStatements().get(i).getPredicate()))));\r
+                       }\r
+                       rightPaths.clear();\r
+                       for (Path p : stepPaths)\r
+                               if (p.getLength() == i+1) \r
+                                       rightPaths.add(p);\r
+               }\r
+               return rightPaths;\r
+               \r
+       }\r
+       \r
+       private Resource getRight(Resource r) {\r
+               if (comparableResources.containsLeft(r))\r
+                       return comparableResources.getRight(r);\r
+               return r;\r
+       }\r
+       \r
+\r
        \r
        public BijectionMap<Statement, Statement> getComparableStatements() {\r
                return comparableStatements;\r
@@ -219,7 +675,24 @@ public class GraphComparator {
                return new GraphChanges(r1,r2,changes1,changes2,modifications,comparableResources);\r
        }\r
        \r
-       private List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws ServiceException {\r
+       private void addComparable(Statement left, Statement right, boolean process) throws DatabaseException {\r
+               addComparable(left.getObject(), right.getObject(), process);\r
+               comparableStatements.map(left, right);\r
+               comparableResources.map(left.getObject(), right.getObject());\r
+       }\r
+       \r
+       private void addComparable(Resource left, Resource right, boolean process) throws DatabaseException {\r
+               if(!comparableResources.contains(r1, r2)) {\r
+                       if (comparableResources.containsLeft(r1)||comparableResources.containsRight(r2)) {\r
+                               throw new DatabaseException("Comparator error: Trying to map " + r1 + " to " + r2 + " while mappings " + r1 + " to " + comparableResources.getRight(r1) + " and " + comparableResources.getLeft(r2) + " to " + r2 + " exist.");\r
+                       } else {\r
+                               comparableResources.map(left, right);           \r
+                       }\r
+               }\r
+               \r
+       }\r
+       \r
+       public List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws ServiceException {\r
                List<Statement> out = new ArrayList<Statement>();\r
                for (Statement s : in) {\r
                        if (!s.isAsserted(r))\r
@@ -228,7 +701,7 @@ public class GraphComparator {
                }\r
                return out;\r
        }\r
-       \r
+\r
        private String printStatement(ReadGraph graph, Statement s) throws ValidationException, ServiceException {\r
                return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());\r
        }\r
@@ -285,6 +758,10 @@ public class GraphComparator {
        }\r
        \r
        public void sortStatement(List<Statement> list1, List<Statement> list2) {\r
+               sortStatement(list1, list2, scomp);\r
+       }\r
+       \r
+       public void sortStatement(List<Statement> list1, List<Statement> list2, Comparator<Statement> scomp) {\r
                Collections.sort(list1,scomp);\r
                Collections.sort(list2,scomp);\r
                \r
@@ -355,14 +832,11 @@ public class GraphComparator {
                                }\r
                        }\r
                        js++;\r
-                       \r
                }\r
        }\r
        \r
-       private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> stack1, Stack<Resource> stack2) throws DatabaseException {\r
+       private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {\r
                sortStatement(ss1, ss2);\r
-//             Collections.sort(ss1, scomp);\r
-//             Collections.sort(ss2, scomp);\r
                \r
                int i1 = 0;\r
                int i2 = 0;\r
@@ -392,7 +866,7 @@ public class GraphComparator {
                        int same2 = sameRel(ss2, i2);\r
                        int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());\r
                        if (c == 0) {\r
-                               compareStatements(ss1, i1, same1, ss2, i2, same2,stack1,stack2);\r
+                               compareStatements(ss1, i1, same1, ss2, i2, same2,objectsLeft,objectsRight,unreliableLeft,unreliableRight);\r
                                i1+=same1;\r
                                i2+=same2;\r
                        } else if (c < 0) {\r
@@ -409,10 +883,11 @@ public class GraphComparator {
                                \r
                                i2 += same2;\r
                        }\r
-                       \r
                }\r
        }\r
        \r
+\r
+       \r
        private int sameRel(List<Statement> statements, int off) {\r
                if (statements.size() <= off)\r
                        return 0;\r
@@ -429,12 +904,18 @@ public class GraphComparator {
        }\r
 \r
        private int compareObject(Resource o1, Resource o2) throws DatabaseException {\r
+               if (o1.equals(o2))\r
+                       return -1;\r
                if (comparableResources.contains(o1, o2))\r
                        return (-1);\r
+               if (comparableResources.containsLeft(o1))\r
+                       return Integer.MAX_VALUE;\r
+               if (comparableResources.containsRight(o2))\r
+                       return Integer.MAX_VALUE;\r
                return comparator.compare(g, o1, o2);\r
        }\r
        \r
-       private void compareStatements(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Stack<Resource> stack1, Stack<Resource> stack2) throws DatabaseException {\r
+       private void compareStatements(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Collection<Resource> objectsLeft, Collection<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {\r
                boolean[] used1 = new boolean[len1];\r
                for (int i = 0; i < used1.length; i++) {\r
                        used1[i] = false;\r
@@ -452,7 +933,16 @@ public class GraphComparator {
                        List<Integer> diff = new ArrayList<Integer>();\r
                        for (int i2 = off2; i2 < off2 + len2; i2++) {\r
                                Statement s2 = ss2.get(i2);\r
-                               diff.add(compareObject(s1.getObject(), s2.getObject()));\r
+                               int d = compareObject(s1.getObject(), s2.getObject());\r
+                               if (d == 0) {\r
+                                       for (Resource t : strong) {\r
+                                                if (s1.getPredicate().equals(t) || g.isSubrelationOf(s1.getPredicate(), t)) {\r
+                                                        d = 1;\r
+                                                        break;\r
+                                                }\r
+                                       }\r
+                               }\r
+                               diff.add(d);\r
                        }\r
                        differences.add(diff);\r
                }\r
@@ -469,8 +959,46 @@ public class GraphComparator {
                Arrays.sort(pris);\r
                \r
                for (Integer pri : pris) {\r
-                       if (pri == Integer.MAX_VALUE)\r
+                       if (pri == Integer.MAX_VALUE) {\r
+\r
+                       } else if (pri == 0) {\r
+                               \r
+                       } else {\r
+                               List<Integer> i1s = priorities.getValues(pri);\r
+                               for (Integer i1 : i1s) {\r
+                                       if (used1[i1])\r
+                                               continue;\r
+                                       List<Integer> i2diff = differences.get(i1);\r
+                                       for (int i2 = 0; i2 < i2diff.size(); i2++) {\r
+                                               if (i2diff.get(i2) == pri) {\r
+                                                       if (used2[i2])\r
+                                                               continue;\r
+                                                       used1[i1] = true;\r
+                                                       used2[i2] = true;\r
+                                                       Statement s1  = ss1.get(i1+off1);\r
+                                                       Statement s2  = ss2.get(i2+off2);\r
+                                                       \r
+                                                       if (objectsLeft != null) {\r
+                                                               if (s1.getObject().getResourceId() == 52825217 || s1.getObject().getResourceId() == 52825127)\r
+                                                                       System.out.println();\r
+                                                               objectsLeft.add(s1.getObject());\r
+                                                               objectsRight.add(s2.getObject());\r
+                                                       } \r
+                                                       addComparable(s1, s2, true);\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               for (Integer pri : pris) {\r
+                       if (pri != 0)\r
                                continue;\r
+                       Set<Statement> s1s = new HashSet<Statement>();\r
+                       Set<Statement> s2s = new HashSet<Statement>();\r
+                       Set<Integer> s1i = new HashSet<Integer>();\r
+                       Set<Integer> s2i = new HashSet<Integer>();\r
                        List<Integer> i1s = priorities.getValues(pri);\r
                        for (Integer i1 : i1s) {\r
                                if (used1[i1])\r
@@ -480,35 +1008,24 @@ public class GraphComparator {
                                        if (i2diff.get(i2) == pri) {\r
                                                if (used2[i2])\r
                                                        continue;\r
-                                               used1[i1] = true;\r
-                                               used2[i2] = true;\r
                                                Statement s1  = ss1.get(i1+off1);\r
                                                Statement s2  = ss2.get(i2+off2);\r
-                                               \r
-                                               if (stack1 != null) {\r
-                                                       \r
-                                                               stack1.add(s1.getObject());\r
-                                                               stack2.add(s2.getObject());\r
-                                                       \r
-                                               } else {\r
-                                                       // TODO : how should we report non traversed differences\r
-                                                       // using compareProps assumes that referenced objects are the same (references are not different)\r
-                                                       // using propsDiffCount assumes that objects are different, and cannot report changes in referred object.\r
-                                                       \r
-                                                       \r
-//                                                     int diff = propsDiffCount(ss1.get(i1+off1).getObject(), ss2.get(i2+off2).getObject());\r
-//                                                     if (diff != 0) {\r
-//                                                             //changes1.add(ss1.get(i1+off1));\r
-//                                                             //changes2.add(ss2.get(i2+off2));\r
-//                                                             modifies.add(new Pair<Statement, Statement>(ss1.get(i1+off1), ss2.get(i2+off2)));\r
-//                                                     }\r
-                                               }\r
-                                               comparableStatements.map(s1, s2);\r
-                                               //comparableResources.map(s1.getObject(), s2.getObject());\r
-                                               break;\r
+                                               s1s.add(s1);\r
+                                               s2s.add(s2);\r
+                                               s1i.add(i1);\r
+                                               s2i.add(i2);\r
                                        }\r
                                }\r
                        }\r
+                       if (unreliableLeft != null) {\r
+                               unreliableLeft.addAll(s1s);\r
+                               unreliableRight.addAll(s2s);\r
+                       }\r
+                       for (Integer i : s1i)\r
+                               used1[i] = true;\r
+                       for (Integer i : s2i)\r
+                               used2[i] = true;\r
+\r
                }\r
                for (int i1 = off1; i1 < off1 + len1; i1++) {\r
                        if (!used1[i1-off1]) {\r
@@ -534,14 +1051,13 @@ public class GraphComparator {
         * @throws DoesNotContainValueException\r
         * @throws ValidationException \r
         */\r
-       private void compareProps(Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+       private void compareProps(Resource r1, Resource r2) throws DatabaseException {\r
+               System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));\r
                ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
                ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
                ss1.addAll(g.getStatements(r1, b.HasProperty));\r
                ss2.addAll(g.getStatements(r2, b.HasProperty));\r
                sortStatement(ss1, ss2);\r
-//             Collections.sort(ss1, scomp);\r
-//             Collections.sort(ss2, scomp);\r
                \r
                int i1 = 0; \r
                int i2 = 0;\r
@@ -568,49 +1084,52 @@ public class GraphComparator {
                        }\r
                        Statement s1 = ss1.get(i1);\r
                        Statement s2 = ss2.get(i2);\r
+                       if (s1.isAsserted(r1) && s2.isAsserted(r2)) {\r
+                               i1++;\r
+                               i2++;\r
+                               continue;\r
+                       }\r
                        int c = scomp.compare(s1, s2);\r
                        switch (c) {\r
-                       case 0:{\r
-                               boolean b1 = g.hasValue(s1.getObject());\r
-                               boolean b2 = g.hasValue(s2.getObject());\r
-                               if (b1 == b2) {\r
-                                       if (b1) {\r
-                                               Object v1 = g.getValue(s1.getObject());\r
-                                               Object v2 = g.getValue(s2.getObject());\r
-                                               boolean eq = compareValue(v1, v2);\r
-                                               if (!eq) {\r
-                                                       addModification(s1, s2);\r
-                                                       comparableStatements.map(s1, s2);\r
-                                                       comparableResources.map(s1.getObject(),s2.getObject());\r
+                               case 0:{\r
+                                       boolean b1 = g.hasValue(s1.getObject());\r
+                                       boolean b2 = g.hasValue(s2.getObject());\r
+                                       if (b1 == b2) {\r
+                                               if (b1) {\r
+                                                       Object v1 = g.getValue(s1.getObject());\r
+                                                       Object v2 = g.getValue(s2.getObject());\r
+                                                       boolean eq = compareValue(v1, v2);\r
+                                                       if (!eq) {\r
+                                                               addModification(s1, s2);\r
+                                                               addComparable(s1, s2, false);\r
+                                                       }\r
+                                               } else {\r
+                                                       if (!s1.getObject().equals(s1.getSubject()) && !s2.getObject().equals(s2.getSubject()))\r
+                                                               compareProps(s1.getObject(), s2.getObject());\r
                                                }\r
                                        } else {\r
-                                               compareProps(s1.getObject(), s2.getObject());\r
+                                               addModification(s1, s2);\r
+                                               addComparable(s1, s2, false);\r
                                        }\r
-                               } else {\r
-                                       addModification(s1, s2);\r
-                                       comparableStatements.map(s1, s2);\r
-                                       comparableResources.map(s1.getObject(),s2.getObject());\r
+                                       i1++;\r
+                                       i2++;\r
+                                       break;\r
+                               }\r
+                               case -1:{\r
+                                       System.out.println("Compare Prop diff1s " + printStatement(g,s1));\r
+                                       addDeletion(s1);\r
+                                       i1++;\r
+                                       break;\r
+                               }\r
+                                       \r
+                               case 1:{\r
+                                       System.out.println("Compare Prop diff2s " + printStatement(g,s2));\r
+                                       addAddition(s2);\r
+                                       i2++;\r
+                                       break;\r
                                }\r
-                               i1++;\r
-                               i2++;\r
-                               break;\r
-                       }\r
-                       case -1:{\r
-                               System.out.println("Compare Prop diff1s " + printStatement(g,s1));\r
-                               addDeletion(s1);\r
-                               i1++;\r
-                               break;\r
-                       }\r
-                               \r
-                       case 1:{\r
-                               System.out.println("Compare Prop diff2s " + printStatement(g,s2));\r
-                               addAddition(s2);\r
-                               i2++;\r
-                               break;\r
-                       }\r
                        }\r
-                       \r
-                       \r
+\r
                }\r
                \r
                ss1.clear();\r
@@ -618,7 +1137,6 @@ public class GraphComparator {
                \r
        }\r
        \r
-       \r
        public static boolean compareValue(Object v1, Object v2) {\r
                if (v1 instanceof Object[] && v2 instanceof Object[])\r
                        return Arrays.deepEquals((Object[])v1, (Object[])v2);\r
@@ -639,7 +1157,6 @@ public class GraphComparator {
        }\r
 \r
        \r
-       \r
        public class PredicateComparator implements Comparator<Statement> {\r
                @Override\r
                public int compare(Statement o1, Statement o2) {\r
@@ -653,6 +1170,32 @@ public class GraphComparator {
                }\r
        }\r
        \r
+       public class SubjectComparator implements Comparator<Statement> {\r
+               @Override\r
+               public int compare(Statement o1, Statement o2) {\r
+                       if (comparableResources.contains(o1.getSubject(), o2.getSubject()))\r
+                               return 0;\r
+                       if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())\r
+                               return -1;\r
+                       if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())\r
+                               return 1;\r
+                       return 0;\r
+               }\r
+       }\r
+       \r
+       public class ObjectComparator implements Comparator<Statement> {\r
+               @Override\r
+               public int compare(Statement o1, Statement o2) {\r
+                       if (comparableResources.contains(o1.getObject(), o2.getObject()))\r
+                               return 0;\r
+                       if (o1.getObject().getResourceId() < o2.getObject().getResourceId())\r
+                               return -1;\r
+                       if (o1.getObject().getResourceId() > o2.getObject().getResourceId())\r
+                               return 1;\r
+                       return 0;\r
+               }\r
+       }\r
+       \r
        public static class FullStatementComparator implements Comparator<Statement> {\r
                @Override\r
                public int compare(Statement o1, Statement o2) {\r
@@ -672,9 +1215,7 @@ public class GraphComparator {
                }\r
        }\r
        \r
-\r
-       \r
-       public class ResourceComparator implements Comparator<Resource> {\r
+       public class ResComparator implements Comparator<Resource> {\r
                @Override\r
                public int compare(Resource o1, Resource o2) {\r
                        if (comparableResources.contains(o1, o2))\r
@@ -686,6 +1227,5 @@ public class GraphComparator {
                        return 0;\r
                }\r
        }\r
-       \r
-       \r
+\r
 }\r