]> gerrit.simantics Code Review - simantics/interop.git/commitdiff
Three-way comparison: utilise old changes in the update step
authorMarko Luukkainen <marko.luukkainen@vtt.fi>
Thu, 6 Apr 2017 10:53:06 +0000 (13:53 +0300)
committerMarko Luukkainen <marko.luukkainen@vtt.fi>
Thu, 6 Apr 2017 10:53:06 +0000 (13:53 +0300)
refs #7045

Change-Id: Icb060716503992e2dbb69b779952f397e6df9169

org.simantics.interop.update/src/org/simantics/interop/update/editor/ModelUpdateEditor.java
org.simantics.interop.update/src/org/simantics/interop/update/editor/UpdateEditorInput.java
org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java

index 860057d240f6d9763c6659f62fed9b9f876a05e8..0881a7bbd44aa5ecf6286a97cb7a96632b36893a 100644 (file)
@@ -4,8 +4,8 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Stack;
 import java.util.Map.Entry;
+import java.util.Stack;
 
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.JFaceResources;
@@ -83,6 +83,7 @@ public abstract class ModelUpdateEditor extends Composite{
        private UpdateList updateList;
        
        private GraphChanges changes2;
+       private GraphChanges changes3;
        private UpdateTree updateTree2;
        private UpdateList updateList2;
        
@@ -401,23 +402,16 @@ public abstract class ModelUpdateEditor extends Composite{
                
                addFilters(filters);
 
-               Resource r1 = uei.getR1();
-               Resource r2 = uei.getR2();
-               Resource r3 = uei.getR3();
+               Resource oldModel = uei.getR1(); // old model that is being updated, contains user made changes
+               Resource newModel = uei.getR2(); // new model, 
+               Resource originalModel = uei.getR3(); // original old model without user made changes 
 
                try {
                        
-                       Pair<GraphComparator,String> result = getChanges(r1,r2);
-                       GraphComparator comparator  = result.first;
-                       if (result.second != null)
-                               showWarning(result.second);
-                       comparator.test(getSession());
-                       changes = comparator.getChanges();
-                       changes = getSession().syncRequest(new FilterChangesRead(changes));
-                       updateTree = getUpdateTree(changes);
-                       updateList = getUpdateList(changes);
-                       if (r3 != null) {
-                               Pair<GraphComparator,String> result2 = getChanges(r1,r3);
+                       if (originalModel != null) {
+                               // tree way comparison
+                               // compare the original and the old model
+                               Pair<GraphComparator,String> result2 = getChanges(originalModel, oldModel);
                                GraphComparator comparator2  = result2.first;
                                if (result2.second != null)
                                        showWarning(result2.second);
@@ -427,8 +421,63 @@ public abstract class ModelUpdateEditor extends Composite{
                                updateTree2 = getUpdateTree(changes2);
                                updateList2 = getUpdateList(changes2);
                                
+                               // compare the original and the new model
+                               Pair<GraphComparator,String> result3 = getChanges(originalModel,newModel);
+                               GraphComparator comparator3  = result3.first;
+                               if (result3.second != null)
+                                       showWarning(result3.second);
+                               comparator3.test(getSession());
+                               changes3 = comparator3.getChanges();
+                               changes3 = getSession().syncRequest(new FilterChangesRead(changes3));
+                       }
+                       
+                       Pair<GraphComparator,String> result = getChanges(oldModel,newModel);
+                       GraphComparator comparator  = result.first;
+                       if (result.second != null)
+                               showWarning(result.second);
+                       if (originalModel != null) {
+                               // three-way comparison: use change information to configure
+                               // the comparison between the old and the new model.
+                               
+                               // 1. map comparable resources
+                               for (Entry<Resource, Resource> origToOld : changes2.getComparable().getEntries()) {
+                                       Resource oldR = origToOld.getValue();
+                                       Resource newR = changes3.getComparable().getRight(origToOld.getKey());
+                                       if (newR != null) {
+                                               comparator.addComparableResources(oldR, newR);
+                                       }
+                               }
+                               // 2. mark removed resources as distinct, so that comparison does not pair them
+                               for (Statement s : changes2.getDeletions()) {
+                                       if (changes3.getComparable().containsLeft(s.getObject()))
+                                               comparator.addNonMatchedRight(changes3.getComparable().getRight(s.getObject()));
+                               }
+                               
+                               for (Statement s : changes3.getDeletions()) {
+                                       if (changes2.getComparable().containsLeft(s.getObject()))
+                                               comparator.addNonMatchedLeft(changes2.getComparable().getRight(s.getObject()));
+                               }
+                               if (uei.isNewDistinct()) {
+                                       // 3. mark added resources as distinct, so that comparison does not pair them
+                                       for (Statement s : changes2.getAdditions()) {
+                                               comparator.addNonMatchedLeft(s.getObject());
+                                       }
+                                       
+                                       for (Statement s : changes3.getAdditions()) {
+                                               comparator.addNonMatchedRight(s.getObject());
+                                       }
+                               }
+                       }
+                       comparator.test(getSession());
+                       changes = comparator.getChanges();
+                       changes = getSession().syncRequest(new FilterChangesRead(changes));
+                       updateTree = getUpdateTree(changes);
+                       updateList = getUpdateList(changes);
+                       
+                       if (originalModel != null) {
                                createDefaultSelections();
                        }
+                       
                } catch (DatabaseException e) {
                        Text text = new Text(this, SWT.MULTI);
                        text.setText(e.getMessage());
@@ -529,6 +578,47 @@ public abstract class ModelUpdateEditor extends Composite{
                        }
                });
        }
+       
+       protected void createDefaultSelections() {
+               // select all changes
+               for (Entry<Resource, UpdateOp> op : updateTree.getUpdateOps().getResourceMap().entrySet()) {
+                       op.getValue().select(true);
+               }
+               
+               
+               for (Pair<Statement, Statement> pair : updateList.getChanges()) {
+                       updateList.addSelected(pair);
+               }
+               
+               // preserve user-made changes (by removing selections)
+               for (Entry<Resource, UpdateOp> op : updateTree.getUpdateOps().getResourceMap().entrySet()) {
+                       UpdateOp op2 = updateTree2.getUpdateOps().getUpdateOp(op.getKey());
+                       if (op2 == null) {
+                               if (changes3.getComparable().containsRight(op.getKey())){
+                                       op2 = updateTree2.getUpdateOps().getUpdateOp(changes3.getComparable().getLeft(op.getKey()));
+                               }
+                       }
+                       if (op2 != null && op.getValue().getClass() == op2.getClass()) {
+                               op.getValue().select(false);
+                       }
+               }
+               
+               for (Pair<Statement, Statement> pair : updateList.getChanges()) {
+                       if (pair.first != null) {
+                               boolean found = false;
+                               for (Pair<Statement, Statement> pair2 : updateList2.getChanges()) {
+                                       if (pair.first.equals(pair2.first)) {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               if (found) {
+                                       updateList.removeSelected(pair);
+                               }
+                       }
+               }
+               
+       }
 
        
        /**
@@ -565,42 +655,7 @@ public abstract class ModelUpdateEditor extends Composite{
        public interface ChangeFilter {
                public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException;
        }
-       
-       
-       protected void createDefaultSelections() {
-               for (Entry<Resource, UpdateOp> op : updateTree.getUpdateOps().getResourceMap().entrySet()) {
-                       UpdateOp op2 = updateTree2.getUpdateOps().getUpdateOp(op.getKey());
-                       if (op2 == null) {
-                               op.getValue().select(true);
-                       }
-               }
-               
-               for (Entry<Statement, UpdateOp> op : updateTree.getUpdateOps().getStatementMap().entrySet()) {
-                       UpdateOp op2 = updateTree2.getUpdateOps().getUpdateOp(op.getKey());
-                       if (op2 == null) {
-                               op.getValue().select(true);
-                       }
-               }
-               
-               for (Pair<Statement, Statement> pair : updateList.getChanges()) {
-                       if (pair.first != null) {
-                               boolean found = false;
-                               for (Pair<Statement, Statement> pair2 : updateList2.getChanges()) {
-                                       if (pair.first.equals(pair2.first)) {
-                                               found = true;
-                                               break;
-                                       }
-                               }
-                               if (!found) {
-                                       updateList.addSelected(pair);
-                               }
-                       } else {
-                               updateList.addSelected(pair);
-                       }
-               }
-       }
-       
-       
+
        
        /**
         * 
index f54b1c935e9439e471ea175382b41486b62e558b..0494b0b5666f453f0c60fca41abb307ad5193e6a 100644 (file)
@@ -18,13 +18,23 @@ public class UpdateEditorInput extends ResourceEditorInput2{
        private Resource r1;
        private Resource r2;
        private Resource r3;
+       private boolean newDistinct = false;
        
-       public UpdateEditorInput(String editorID, Resource r1, Resource r2, Resource model, RVI rvi) {
-               this(editorID, r1, r2, null, model, rvi);
+       
+       public UpdateEditorInput(String editorID, Resource r1, Resource r2, RVI rvi) {
+               this(editorID, r1, r2, null,rvi);
        }
        
-       public UpdateEditorInput(String editorID, Resource r1, Resource r2, Resource r3, Resource model, RVI rvi) {
-               super(editorID, r1, model, rvi);
+       /**
+        * 
+        * @param editorID
+        * @param r1  old model that is being updated
+        * @param r2  new model containing the changes that we want to apply
+        * @param r3  original model to detect user mace changes to the old model r1. This parameter can be 
+        * @param rvi
+        */
+       public UpdateEditorInput(String editorID, Resource r1, Resource r2, Resource r3, RVI rvi) {
+               super(editorID, r1, r1, rvi);
                this.r1 = r1;
                this.r2 = r2;
                this.r3 = r3;
@@ -48,4 +58,14 @@ public class UpdateEditorInput extends ResourceEditorInput2{
                WorkbenchUtils.openEditor(editorID, this);
        }
        
+       // With tree-way comparison, treat new resources for compared old and new models as distinct.
+       // default : false. Comparison may consider that new objects in models r1 and r2 are the same. 
+       public boolean isNewDistinct() {
+               return newDistinct;
+       }
+       
+       public void setNewDistinct(boolean newDistinct) {
+               this.newDistinct = newDistinct;
+       }
+       
 }
index 0f61e5d523fd7447b81ae733fb19ece42f2b7997..aa2ddee72f84c3cd23dbb25cdc32768deb8852a3 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     Foster Wheeler Energia Oy - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.interop.test;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-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.layer0.Layer0;\r
-import org.simantics.utils.datastructures.BijectionMap;\r
-import org.simantics.utils.datastructures.MapList;\r
-import org.simantics.utils.datastructures.Pair;\r
-\r
-/**\r
- * Compares two subgraphs and reports differences.\r
- * \r
- * Assumes that subgraphs (defined using traverse relations) are not cyclic.\r
- * \r
- * Assumes that properties can be used to identify objects, if relation type is not enough.\r
- * \r
- * \r
- * \r
- * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
- *\r
- */\r
-public class GraphComparator {\r
-       \r
-       private static final boolean DEBUG = false;\r
-\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
-       private List<Resource> nonTested = new ArrayList<Resource>(); // list of relations that are not tested\r
-       \r
-       private List<Statement> changes1 = new ArrayList<Statement>();\r
-       private List<Statement> changes2 = new ArrayList<Statement>();\r
-       private List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();\r
-       private Set<Statement> changes1Set = new HashSet<Statement>();\r
-       private Set<Statement> changes2Set = new HashSet<Statement>();\r
-       private Set<Pair<Statement,Statement>> modificationsSet = new HashSet<Pair<Statement,Statement>>();\r
-\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
-       private ResourceComparator comparator;\r
-       \r
-       private Comparator<Statement> scomp = new PredicateComparator();\r
-       private Comparator<Resource> rcomp = new ResComparator();\r
-       \r
-       // runtime attributes\r
-       \r
-       private ReadGraph g;\r
-       private Layer0 b;\r
-       \r
-       public GraphComparator(Resource r1, Resource r2) {\r
-               this.r1 = r1;\r
-               this.r2 = r2;\r
-               comparator = new TypeComparator();\r
-       }\r
-       \r
-       public GraphComparator(Resource r1, Resource r2, ResourceComparator comparator) {\r
-               this.r1 = r1;\r
-               this.r2 = r2;\r
-               this.comparator = comparator;\r
-       }\r
-       \r
-       ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
-       ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
-       \r
-       \r
-       public Comparator<Resource> getResourceComparator() {\r
-               return rcomp;\r
-       }\r
-       \r
-       public Comparator<Statement> getStatementComparator() {\r
-               return scomp;\r
-       }\r
-       \r
-       public Resource getR1() {\r
-               return r1;\r
-       }\r
-       \r
-       public Resource getR2() {\r
-               return r2;\r
-       }\r
-       \r
-       public void addTraversed(Resource rel) {\r
-               traversed.add(rel);\r
-       }\r
-       \r
-       public void addTraversed(Collection<Resource> rels) {\r
-               traversed.addAll(rels);\r
-       }\r
-       \r
-       public void addNonTraversed(Resource rel) {\r
-               nonTraversed.add(rel);\r
-       }\r
-       \r
-       public void addNonTraversed(Collection<Resource> rels) {\r
-               nonTraversed.addAll(rels);\r
-       }\r
-       \r
-       public void addTested(Resource rel) {\r
-               tested.add(rel);\r
-       }\r
-       \r
-       public void addTested(Collection<Resource> rels) {\r
-               tested.addAll(rels);\r
-       }\r
-       \r
-       public void addNonTested(Resource rel) {\r
-               nonTested.add(rel);\r
-       }\r
-       \r
-       public void addNonTested(Collection<Resource> rels) {\r
-               nonTested.addAll(rels);\r
-       }\r
-       \r
-       public void addComparableResources(Resource r1, Resource r2) {\r
-               comparableResources.map(r1, r2);\r
-       }\r
-       \r
-       public void addComparableResources(BijectionMap<Resource, Resource> matching) {\r
-               comparableResources.addAll(matching);\r
-       }\r
-       \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> 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
-               test(session, r1, r2);\r
-       }\r
-       \r
-       public void test(Session session, Resource r1, Resource r2) throws DatabaseException {\r
-               \r
-               comparator.setComparator(this);\r
-               \r
-               addComparable(r1, r2, false);\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 (!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.containsLeft(r1)||comparableResources.containsRight(r2)) && !comparableResources.contains(r1, 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
-                       addComparable(r1, r2, false);\r
-                       \r
-                       //System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
-                       compareProps(r1, r2);\r
-                       \r
-                       for (Resource rel : tested) {\r
-                               ss1.addAll(g.getStatements(r1, rel));\r
-                               ss2.addAll(g.getStatements(r2, rel));\r
-                               ss1 = filterAsserted(r1, ss1);\r
-                               ss2 = filterAsserted(r2, ss2);\r
-                               ss1 = filterTraversed(ss1);\r
-                               ss2 = filterTraversed(ss2);\r
-                               ss1 = filterNonTested(ss1);\r
-                               ss2 = filterNonTested(ss2);\r
-                               \r
-                               \r
-                               compareStatements(ss1, ss2, null, null,null,null);\r
-                               ss1.clear();\r
-                               ss2.clear();\r
-                       }\r
-                       \r
-                       for (Resource rel : traversed) {\r
-                               ss1.addAll(g.getStatements(r1, rel));\r
-                               ss2.addAll(g.getStatements(r2, rel));\r
-                               ss1 = filterAsserted(r1, ss1);\r
-                               ss2 = filterAsserted(r2, ss2);\r
-                               ss1 = filterNonTraversed(ss1);\r
-                               ss2 = filterNonTraversed(ss2);\r
-                               compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);\r
-                               ss1.clear();\r
-                               ss2.clear();\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
-       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
-                                       } \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
-       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 DatabaseException {\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 DatabaseException {\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
-       }\r
-       \r
-       public BijectionMap<Resource, Resource> getComparableResources() {\r
-               return comparableResources;\r
-       }\r
-       \r
-       public GraphChanges getChanges() {\r
-               return new GraphChanges(r1,r2,changes1,changes2,modifications,comparableResources);\r
-       }\r
-       \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(left, right)) {\r
-                       if (comparableResources.containsLeft(left)||comparableResources.containsRight(right)) {\r
-                               throw new DatabaseException("Comparator error: Trying to map " + left + " to " + right + " while mappings " + left + " to " + comparableResources.getRight(left) + " and " + comparableResources.getLeft(right) + " to " + right + " exist.");\r
-                       } else {\r
-                               if (DEBUG) System.out.println(left + " = " + right);\r
-                               comparableResources.map(left, right);           \r
-                       }\r
-               }\r
-               \r
-       }\r
-       \r
-       public List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws DatabaseException {\r
-               List<Statement> out = new ArrayList<Statement>();\r
-               for (Statement s : in) {\r
-                       if (!s.isAsserted(r))\r
-                               out.add(s);\r
-                       \r
-               }\r
-               return out;\r
-       }\r
-       \r
-       \r
-\r
-       private String printStatement(ReadGraph graph, Statement s) throws DatabaseException {\r
-               return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());\r
-       }\r
-       \r
-       private List<Statement> filterTraversed(List<Statement> in) throws DatabaseException {\r
-               return filter(traversed, in);\r
-       }\r
-       \r
-       private List<Statement> filterNonTested(List<Statement> in) throws DatabaseException {\r
-               return filter(nonTested, in);\r
-       }\r
-       \r
-       private List<Statement> filterNonTraversed(List<Statement> in) throws DatabaseException {\r
-               return filter(nonTraversed, in);\r
-       }\r
-       \r
-       private List<Statement> filter(Collection<Resource> toFilter, List<Statement> in) throws DatabaseException {\r
-               if (toFilter.size() == 0)\r
-                       return in;\r
-               List<Statement> out = new ArrayList<Statement>();\r
-               for (Statement s : in) {\r
-                       boolean usable = true;\r
-                       for (Resource r : toFilter) {\r
-                               if (g.isSubrelationOf(s.getPredicate(),r)) {\r
-                                       usable = false;\r
-                                       break;\r
-                               }\r
-                       }\r
-                       if (usable) {\r
-                               out.add(s);\r
-                       }\r
-                       \r
-               }\r
-               return out;\r
-       }\r
-       \r
-       \r
-       private void addDeletion(Statement s) {\r
-               if (!changes1Set.contains(s)) {\r
-                       changes1Set.add(s);\r
-                       changes1.add(s);\r
-               }\r
-       }\r
-       \r
-       private void addAddition(Statement s) {\r
-               if (!changes2Set.contains(s)) {\r
-                       changes2Set.add(s);\r
-                       changes2.add(s);\r
-               }\r
-       }\r
-       \r
-       private void addModification(Statement s1, Statement s2) {\r
-               Pair<Statement, Statement> mod = new Pair<Statement, Statement>(s1,s2);\r
-               if (!modificationsSet.contains(mod)) {\r
-                       modificationsSet.add(mod);\r
-                       modifications.add(mod);\r
-               }\r
-       }\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
-               List<Statement> sorted1 = new ArrayList<Statement>(list1.size());\r
-               List<Statement> sorted2 = new ArrayList<Statement>(list2.size());\r
-               sorted1.addAll(list1);\r
-               sorted2.addAll(list2);\r
-               \r
-               int ss1 = 0;\r
-               int ss2 = 0;\r
-               for (int i = 0; i < list1.size(); ) {\r
-                       Statement s1 = list1.get(i);\r
-                       int same1 = sameRel(list1, i);  \r
-                       for (int j = 0; j < list2.size(); j++) {\r
-                               Statement s2 = list2.get(j);\r
-                               if (scomp.compare(s1, s2) == 0) {\r
-                                       int same2 = sameRel(list2, j);\r
-                                       copy(sorted1,ss1,list1,i,same1);\r
-                                       ss1 += same1;\r
-                                       copy(sorted2,ss2,list2,j,same2);\r
-                                       ss2 += same2;\r
-                                       break;\r
-                               }\r
-                       }\r
-                       i+= same1;\r
-               }\r
-               if (ss1 < sorted1.size()) {\r
-                       for (Statement s : list1) {\r
-                               if (!sorted1.contains(s)) {\r
-                                       sorted1.set(ss1,s);\r
-                                       ss1++;\r
-                               }\r
-                       }\r
-               }\r
-               if (ss2 < sorted2.size()) {\r
-                       for (Statement s : list2) {\r
-                               if (!sorted2.contains(s)) {\r
-                                       sorted2.set(ss2,s);\r
-                                       ss2++;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               list1.clear();\r
-               list2.clear();\r
-               list1.addAll(sorted1);\r
-               list2.addAll(sorted2);\r
-       }\r
-       \r
-       public <T> void copy(List<T> to, int toIndex, List<T> from, int fromIndex, int amount) {\r
-               for (int i = 0; i <  amount; i++) {\r
-                       to.set(toIndex + i, from.get(fromIndex+ i));\r
-               }\r
-       }\r
-       \r
-       public void sortResource(List<Resource> list1, List<Resource> list2) {\r
-               Collections.sort(list1,rcomp);\r
-               int js = 0;\r
-               for (int i = 0; i < list1.size(); i++) {\r
-                       Resource s1 = list1.get(i);\r
-                       for (int j = js; j < list2.size(); j++) {\r
-                               Resource s2 = list2.get(j);\r
-                               if (rcomp.compare(s1, s2) == 0) {\r
-                                       Resource t = list2.get(js);\r
-                                       list2.set(js, s2);\r
-                                       list2.set(j, t);\r
-                                       break;\r
-                               }\r
-                       }\r
-                       js++;\r
-               }\r
-       }\r
-       \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
-               \r
-               int i1 = 0;\r
-               int i2 = 0;\r
-               \r
-               while (true) {\r
-                       if (i1 >= ss1.size()) {\r
-                               if (i2 >= ss2.size()) {\r
-                                       break;\r
-                               } else {\r
-                                       while (i2 < ss2.size()) {\r
-                                               if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i2)));\r
-                                               \r
-                                               addAddition(ss2.get(i2));\r
-                                               i2++;\r
-                                       }\r
-                                       break;\r
-                               }\r
-                       } else if (i2 >= ss2.size()) {\r
-                               while (i1 < ss1.size()) {\r
-                                       if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i1)));\r
-                                       addDeletion(ss1.get(i1));\r
-                                       i1++;\r
-                               }\r
-                               break;\r
-                       }\r
-                       int same1 = sameRel(ss1, i1);\r
-                       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,objectsLeft,objectsRight,unreliableLeft,unreliableRight);\r
-                               i1+=same1;\r
-                               i2+=same2;\r
-                       } else if (c < 0) {\r
-                               for (int i = 0; i < same1; i++) {\r
-                                       if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i+i1)));\r
-                                       addDeletion(ss1.get(i+i1));\r
-                               }\r
-                               i1 += same1;\r
-                       } else {\r
-                               for (int i = 0; i < same2; i++) {\r
-                                       if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i+i2)));\r
-                                       addAddition(ss2.get(i+i2));\r
-                               }\r
-                               \r
-                               i2 += same2;\r
-                       }\r
-               }\r
-       }\r
-       \r
-\r
-       \r
-       private int sameRel(List<Statement> statements, int off) {\r
-               if (statements.size() <= off)\r
-                       return 0;\r
-               int same = 1;\r
-               long id = statements.get(off).getPredicate().getResourceId();\r
-               for (int i = off+1; i <statements.size(); i++) {\r
-                       if (statements.get(i).getPredicate().getResourceId() == id)\r
-                               same++;\r
-                       else \r
-                               break;\r
-               }\r
-               return same;\r
-               \r
-       }\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, 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
-               }\r
-               \r
-               boolean[] used2 = new boolean[len2];\r
-               for (int i = 0; i < used2.length; i++) {\r
-                       used2[i] = false;\r
-               }\r
-               \r
-               // left, right, difference\r
-               List<List<Integer>> differences = new ArrayList<List<Integer>>();\r
-               for (int i1 = off1; i1 < off1 + len1; i1++) {\r
-                       Statement s1 = ss1.get(i1);\r
-                       List<Integer> diff = new ArrayList<Integer>();\r
-                       for (int i2 = off2; i2 < off2 + len2; i2++) {\r
-                               Statement s2 = ss2.get(i2);\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
-               // difference, left\r
-               MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();\r
-               for (int i = 0; i < differences.size(); i++) {\r
-                       List<Integer> list = differences.get(i);\r
-                       for (int j = 0; j < list.size(); j++) {\r
-                               priorities.add(list.get(j), i);\r
-                       }\r
-               }\r
-               \r
-               Integer[] pris = priorities.getKeys(new Integer[]{});\r
-               Arrays.sort(pris);\r
-               \r
-               for (Integer pri : pris) {\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
-                                                               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
-                                       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
-                                               Statement s1  = ss1.get(i1+off1);\r
-                                               Statement s2  = ss2.get(i2+off2);\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
-                               if (DEBUG) System.out.println("Compare Object deletion " + printStatement(g,ss1.get(i1)));\r
-                               addDeletion(ss1.get(i1));\r
-                       }\r
-               }\r
-               for (int i2 = off2; i2 < off2 + len2; i2++) {\r
-                       if (!used2[i2-off2]) {\r
-                               if (DEBUG) System.out.println("Compare Object addition " + printStatement(g,ss2.get(i2)));\r
-                               addAddition(ss2.get(i2));\r
-                       }\r
-               }\r
-       }\r
-       \r
-       \r
-       \r
-       /**\r
-        * compares properties, assumes functional relations\r
-        * @param r1\r
-        * @param r2\r
-        * @throws ServiceException\r
-        * @throws DoesNotContainValueException\r
-        * @throws ValidationException \r
-        */\r
-       private void compareProps(Resource r1, Resource r2) throws DatabaseException {\r
-               if (DEBUG) System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));\r
-               List<Statement> ss1 = new ArrayList<Statement>();\r
-               List<Statement> ss2 = new ArrayList<Statement>();\r
-               ss1.addAll(g.getStatements(r1, b.HasProperty));\r
-               ss2.addAll(g.getStatements(r2, b.HasProperty));\r
-               ss1 = filterNonTested(ss1);\r
-               ss2 = filterNonTested(ss2);\r
-               sortStatement(ss1, ss2);\r
-               \r
-               int i1 = 0; \r
-               int i2 = 0;\r
-               \r
-               while (true) {\r
-                       if (i1 >= ss1.size()) {\r
-                               if (i2 >= ss2.size())\r
-                                       break;\r
-                               else {\r
-                                       while (i2 < ss2.size()) {\r
-                                               if (DEBUG) System.out.println("Compare Prop diff2 " + printStatement(g,ss2.get(i2)));\r
-                                               addAddition(ss2.get(i2));\r
-                                               i2++;\r
-                                       }\r
-                                       break;\r
-                               }\r
-                       } else if (i2 >= ss2.size()) {\r
-                               while (i1 < ss1.size()) {\r
-                                       if (DEBUG) System.out.println("Compare Prop diff1 " + printStatement(g,ss1.get(i1)));\r
-                                       addDeletion(ss1.get(i1));\r
-                                       i1++;\r
-                               }\r
-                               break;\r
-                       }\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
-                                                               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
-                                               addModification(s1, s2);\r
-                                               addComparable(s1, s2, false);\r
-                                       }\r
-                                       i1++;\r
-                                       i2++;\r
-                                       break;\r
-                               }\r
-                               case -1:{\r
-                                       if (DEBUG) System.out.println("Compare Prop diff1s " + printStatement(g,s1));\r
-                                       addDeletion(s1);\r
-                                       i1++;\r
-                                       break;\r
-                               }\r
-                                       \r
-                               case 1:{\r
-                                       if (DEBUG) System.out.println("Compare Prop diff2s " + printStatement(g,s2));\r
-                                       addAddition(s2);\r
-                                       i2++;\r
-                                       break;\r
-                               }\r
-                       }\r
-\r
-               }\r
-               \r
-               ss1.clear();\r
-               ss2.clear();\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
-               else if (v1 instanceof int[] && v2 instanceof int[]) \r
-                       return Arrays.equals((int[])v1, (int[])v2);\r
-               else if (v1 instanceof float[] && v2 instanceof float[]) \r
-                       return Arrays.equals((float[])v1, (float[])v2);\r
-               else if (v1 instanceof double[] && v2 instanceof double[]) \r
-                       return Arrays.equals((double[])v1, (double[])v2);\r
-               else if (v1 instanceof long[] && v2 instanceof long[]) \r
-                       return  Arrays.equals((long[])v1, (long[])v2);\r
-               else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
-                       return Arrays.equals((byte[])v1, (byte[])v2);\r
-               else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
-                       return Arrays.equals((boolean[])v1, (boolean[])v2);\r
-               else\r
-                       return v1.equals(v2);\r
-       }\r
-\r
-       \r
-       public class PredicateComparator implements Comparator<Statement> {\r
-               @Override\r
-               public int compare(Statement o1, Statement o2) {\r
-                       if (comparableResources.contains(o1.getPredicate(), o2.getPredicate()))\r
-                               return 0;\r
-                       if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
-                               return -1;\r
-                       if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())\r
-                               return 1;\r
-                       return 0;\r
-               }\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
-                       if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())\r
-                               return -1;\r
-                       if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())\r
-                               return 1;\r
-                       if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
-                               return -1;\r
-                       if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())\r
-                               return 1;\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 class ResComparator implements Comparator<Resource> {\r
-               @Override\r
-               public int compare(Resource o1, Resource o2) {\r
-                       if (comparableResources.contains(o1, o2))\r
-                               return 0;\r
-                       if (o1.getResourceId() < o2.getResourceId())\r
-                               return -1;\r
-                       if (o1.getResourceId() > o2.getResourceId())\r
-                               return 1;\r
-                       return 0;\r
-               }\r
-       }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Foster Wheeler Energia Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.interop.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.Statement;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.layer0.Layer0;
+import org.simantics.utils.datastructures.BijectionMap;
+import org.simantics.utils.datastructures.MapList;
+import org.simantics.utils.datastructures.Pair;
+
+/**
+ * Compares two subgraphs and reports differences.
+ * 
+ * Assumes that subgraphs (defined using traverse relations) are not cyclic.
+ * 
+ * Assumes that properties can be used to identify objects, if relation type is not enough.
+ * 
+ * 
+ * 
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class GraphComparator {
+       
+       private static final boolean DEBUG = false;
+
+       private Resource r1;
+       private Resource r2;
+       private Set<Resource> strong = new HashSet<Resource>();       // List of relations that identify object, if subject is already identified. 
+       private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)
+       private List<Resource> tested = new ArrayList<Resource>();    // list of relations that are tested, but not traversed
+       private List<Resource> nonTraversed = new ArrayList<Resource>(); // list of relations that are not traversed
+       private List<Resource> nonTested = new ArrayList<Resource>(); // list of relations that are not tested
+       
+       private List<Statement> changes1 = new ArrayList<Statement>();
+       private List<Statement> changes2 = new ArrayList<Statement>();
+       private List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
+       private Set<Statement> changes1Set = new HashSet<Statement>();
+       private Set<Statement> changes2Set = new HashSet<Statement>();
+       private Set<Pair<Statement,Statement>> modificationsSet = new HashSet<Pair<Statement,Statement>>();
+
+       private BijectionMap<Statement, Statement> comparableStatements = new BijectionMap<Statement, Statement>();
+       private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<Resource, Resource>();
+       
+       private Set<Resource> processedResources = new HashSet<Resource>();
+       
+       private ResourceComparator comparator;
+       
+       private Comparator<Statement> scomp = new PredicateComparator();
+       private Comparator<Resource> rcomp = new ResComparator();
+       
+       private Set<Resource> nonMatchedLeft = new HashSet<Resource>();
+       private Set<Resource> nonMatchedRight = new HashSet<Resource>();
+       
+       // runtime attributes
+       
+       private ReadGraph g;
+       private Layer0 b;
+       
+       public GraphComparator(Resource r1, Resource r2) {
+               this.r1 = r1;
+               this.r2 = r2;
+               comparator = new TypeComparator();
+       }
+       
+       public GraphComparator(Resource r1, Resource r2, ResourceComparator comparator) {
+               this.r1 = r1;
+               this.r2 = r2;
+               this.comparator = comparator;
+       }
+       
+       ArrayList<Statement> ss1 = new ArrayList<Statement>();
+       ArrayList<Statement> ss2 = new ArrayList<Statement>();
+       
+       
+       public Comparator<Resource> getResourceComparator() {
+               return rcomp;
+       }
+       
+       public Comparator<Statement> getStatementComparator() {
+               return scomp;
+       }
+       
+       public Resource getR1() {
+               return r1;
+       }
+       
+       public Resource getR2() {
+               return r2;
+       }
+       
+       public void addTraversed(Resource rel) {
+               traversed.add(rel);
+       }
+       
+       public void addTraversed(Collection<Resource> rels) {
+               traversed.addAll(rels);
+       }
+       
+       public void addNonTraversed(Resource rel) {
+               nonTraversed.add(rel);
+       }
+       
+       public void addNonTraversed(Collection<Resource> rels) {
+               nonTraversed.addAll(rels);
+       }
+       
+       public void addTested(Resource rel) {
+               tested.add(rel);
+       }
+       
+       public void addTested(Collection<Resource> rels) {
+               tested.addAll(rels);
+       }
+       
+       public void addNonTested(Resource rel) {
+               nonTested.add(rel);
+       }
+       
+       public void addNonTested(Collection<Resource> rels) {
+               nonTested.addAll(rels);
+       }
+       
+       public void addComparableResources(Resource r1, Resource r2) {
+               comparableResources.map(r1, r2);
+       }
+       
+       public void addComparableResources(BijectionMap<Resource, Resource> matching) {
+               comparableResources.addAll(matching);
+       }
+       
+       public void addStrong(Resource r) {
+               strong.add(r);
+       }
+       
+       public void addStrong(Collection<Resource> rels) {
+               strong.addAll(rels);
+       }
+       
+       public void addNonMatchedLeft(Resource r) {
+               nonMatchedLeft.add(r);
+       }
+       
+       public void addNonMatchedRight(Resource r) {
+               nonMatchedRight.add(r);
+       }
+       
+       public void test(ReadGraph g) throws DatabaseException {
+               this.g = g;
+               this.b = Layer0.getInstance(g);
+               comparator.setComparator(this);
+               
+               Stack<Resource> objectsLeft = new Stack<Resource>();
+               Stack<Resource> objectsRight = new Stack<Resource>();
+               objectsLeft.push(r1);
+               objectsRight.push(r2);
+               
+               Set<Statement> unreliableLeft = new HashSet<Statement>();
+               Set<Statement> unreliableRight = new HashSet<Statement>();
+               
+               while (true) {
+                       if (objectsLeft.isEmpty())
+                               break;
+                       
+                       
+                       // process compares objects that are identified and searches for more resources to process. 
+                       process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
+                       // process unreliable handles cases where unidentified statements subject and object have been identified 
+                       processUnreliable(unreliableLeft, unreliableRight);
+                       // process unreliable handles cases where unidentified resources have path of length one to identified resource
+                       processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
+                       if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
+                               // comparison is ending, but we have still unprocessed unidentified resources left.
+                               // These cases have longer path than one to identified objects.
+                               processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
+                       }
+                       
+               }
+               for (Statement s : unreliableLeft) {
+                       if (!comparableStatements.containsLeft(s))
+                               addDeletion(s);
+               }
+               for (Statement s : unreliableRight) {
+                       if (!comparableStatements.containsRight(s))
+                               addAddition(s);
+               }
+               
+               
+       }
+       
+       public void test(Session session) throws DatabaseException {
+               test(session, r1, r2);
+       }
+       
+       public void test(Session session, Resource r1, Resource r2) throws DatabaseException {
+               
+               comparator.setComparator(this);
+               
+               addComparable(r1, r2, false);
+               
+               final Stack<Resource> objectsLeft = new Stack<Resource>();
+               final Stack<Resource> objectsRight = new Stack<Resource>();
+               objectsLeft.push(r1);
+               objectsRight.push(r2);
+               
+               final Set<Statement> unreliableLeft = new HashSet<Statement>();
+               final Set<Statement> unreliableRight = new HashSet<Statement>();
+               
+               while (true) {
+                       if (objectsLeft.isEmpty())
+                               break;
+                       session.syncRequest(new ReadRequest() {
+                               
+                               @Override
+                               public void run(ReadGraph graph) throws DatabaseException {
+                                       g = graph;
+                                       b = Layer0.getInstance(graph);
+                                       // process compares objects that are identified and searches for more resources to process. 
+                                       process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
+                                       // process unreliable handles cases where unidentified statements subject and object have been identified 
+                                       processUnreliable(unreliableLeft, unreliableRight);
+                                       // process unreliable handles cases where unidentified resources have path of length one to identified resource
+                                       processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
+                                       if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
+                                               // comparison is ending, but we have still unprocessed unidentified resources left.
+                                               // These cases have longer path than one to identified objects.
+                                               processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
+                                       }
+                               }
+                       });
+                       
+                       
+                       
+               }
+               for (Statement s : unreliableLeft) {
+                       if (!comparableStatements.containsLeft(s))
+                               addDeletion(s);
+               }
+               for (Statement s : unreliableRight) {
+                       if (!comparableStatements.containsRight(s))
+                               addAddition(s);
+               }
+               
+               
+       }
+       
+       private void process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
+               List<Statement> ss1 = new ArrayList<Statement>();
+               List<Statement> ss2 = new ArrayList<Statement>();
+               
+               while (!objectsLeft.isEmpty()) {
+                       Resource r1 = objectsLeft.pop();
+                       Resource r2 = objectsRight.pop();
+                       
+                       if (r1.equals(r2))
+                               continue;
+                       
+                       if (processedResources.contains(r1))
+                               continue;
+                       processedResources.add(r1);
+                       
+               
+                       if((comparableResources.containsLeft(r1)||comparableResources.containsRight(r2)) && !comparableResources.contains(r1, r2)) {
+                               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.");
+                       }
+                       addComparable(r1, r2, false);
+                       
+                       //System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));
+                       compareProps(r1, r2);
+                       
+                       for (Resource rel : tested) {
+                               ss1.addAll(g.getStatements(r1, rel));
+                               ss2.addAll(g.getStatements(r2, rel));
+                               ss1 = filterAsserted(r1, ss1);
+                               ss2 = filterAsserted(r2, ss2);
+                               ss1 = filterTraversed(ss1);
+                               ss2 = filterTraversed(ss2);
+                               ss1 = filterNonTested(ss1);
+                               ss2 = filterNonTested(ss2);
+                               
+                               
+                               compareStatements(ss1, ss2, null, null,null,null);
+                               ss1.clear();
+                               ss2.clear();
+                       }
+                       
+                       for (Resource rel : traversed) {
+                               ss1.addAll(g.getStatements(r1, rel));
+                               ss2.addAll(g.getStatements(r2, rel));
+                               ss1 = filterAsserted(r1, ss1);
+                               ss2 = filterAsserted(r2, ss2);
+                               ss1 = filterNonTraversed(ss1);
+                               ss2 = filterNonTraversed(ss2);
+                               compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
+                               ss1.clear();
+                               ss2.clear();
+                               
+                       }
+               }
+       }
+       
+       private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
+               MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
+               
+               for (Statement s : unreliableLeft) {
+                       subjectLeft.add(s.getSubject(),s);
+                       objectLeft.add(s.getObject(),s);
+               }
+               for (Statement s : unreliableRight) {
+                       subjectRight.add(s.getSubject(),s);
+                       objectRight.add(s.getObject(),s);
+               }
+               
+               for (Resource left : subjectLeft.getKeys()) {
+                       if (!comparableResources.containsLeft(left))
+                               continue;
+                       Resource right = comparableResources.getRight(left);
+                       for (Statement leftS : subjectLeft.getValues(left)) {
+                               Resource leftO = leftS.getObject();
+                               if (!comparableResources.containsLeft(leftO)) 
+                                       continue;
+                               if (!unreliableLeft.contains(leftS))
+                                       continue;
+                               Resource rightO = comparableResources.getRight(leftO);
+                               for (Statement rightS : subjectRight.getValues(right)) {
+                                       if (!rightS.getObject().equals(rightO))
+                                               continue;
+                                       if (!unreliableRight.contains(rightS))
+                                               continue;
+                                       if (leftS.getPredicate().equals(rightS.getPredicate()) ||
+                                               comparableResources.contains(leftS.getPredicate(), rightS.getPredicate())) {
+                                               unreliableLeft.remove(leftS);
+                                               unreliableRight.remove(rightS);
+                                               addComparable(leftS, rightS, false);
+                                       }
+                               }
+                       }               
+               }
+       }
+       
+       private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
+               MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
+               
+               for (Statement s : unreliableLeft) {
+                       subjectLeft.add(s.getSubject(),s);
+                       objectLeft.add(s.getObject(),s);
+               }
+               for (Statement s : unreliableRight) {
+                       subjectRight.add(s.getSubject(),s);
+                       objectRight.add(s.getObject(),s);
+               }
+               
+               for (Resource ol : objectLeft.getKeys()) {
+                       // all statements to the left side object
+                       List<Statement> left = objectLeft.getValues(ol);
+                       // all subjects that have statements to the left side object (ol)
+                       Set<Resource> sLeft = new HashSet<Resource>();
+                       // all matching subjects on the right side
+                       Set<Resource> sRight = new HashSet<Resource>();
+                       for (Statement s : left) {
+                               sLeft.add(s.getSubject());
+                               sRight.add(comparableResources.getRight(s.getSubject()));
+                       }
+                       
+                       // check if object left can be reliably identified by available statements
+                       // if there are any objects on the left side with similar statements, object left cannot be mapped.
+                       boolean hasSimilar = false;
+                       MapList<Resource, Statement> comparableOLeft = new MapList<Resource, Statement>();
+                       for (Resource sl : sLeft) {
+                               for (Statement s : subjectLeft.getValues(sl)) {
+                                       if (!s.getObject().equals(ol)) {
+                                               comparableOLeft.add(s.getObject(),s);
+                                       }
+                               }
+                       }
+                       
+                       for (Resource similarOl : comparableOLeft.getKeys()) {
+                               List<Statement> similarLeft = comparableOLeft.getValues(similarOl);
+                               if (similarLeft.size() == left.size()) {
+                                       boolean useL[] = new boolean[left.size()];
+                                       boolean useSL[] = new boolean[left.size()];
+                                       for (int i = 0; i < left.size(); i++) {
+                                               useL[i] = false;
+                                               useSL[i] = false;
+                                       }
+                                       for (int i = 0; i < left.size(); i++) {
+                                               for (int j = 0; j < left.size(); j++) {
+                                                       if (useSL[j])
+                                                               continue;
+                                                       Resource pl = left.get(i).getPredicate();
+                                                       Resource psl = similarLeft.get(j).getPredicate();
+                                                       if (pl.equals(psl)) {
+                                                               useL[i] = true;
+                                                               useSL[j] = true;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       boolean diff = false;
+                                       for (int i = 0; i < left.size(); i++) {
+                                               if (!useL[i] || !useSL[i]) {
+                                                       diff = true;
+                                               }
+                                       }
+                                       if (!diff) {
+                                               hasSimilar = true;
+                                               break;
+                                       }
+                               }
+                       }
+                       
+                       if (hasSimilar)
+                               continue;
+                               
+                       
+                       // all objects that subjects on the right side point to. Object left has its matching resource among these, if it has matching resource
+                       MapList<Resource,Statement> possibleOR = new MapList<Resource, Statement>();
+                       for (Resource sr : sRight) {
+                               for (Statement s : subjectRight.getValues(sr))
+                                       possibleOR.add(s.getObject(),s);
+                       }
+                       
+                       // filter possible right side objects to those that have same amount of statements as the left side object
+                       for (Resource or : possibleOR.getKeys().toArray(new Resource[possibleOR.getKeys().size()])) {
+                               List<Statement> right = possibleOR.getValues(or);
+                               if (right.size() != left.size())
+                                       possibleOR.remove(or);
+                                       
+                       }
+                       
+                       // check for matching statements (comparable subjects, matching predicates)
+                       MapList<Resource,Statement> matchingOR = new MapList<Resource, Statement>(); // list of objects that have matching statements
+                       Map<Resource,Pair<int[], int[]>> matchingStatements = new HashMap<Resource, Pair<int[], int[]>>(); // matching statements
+                       for (Resource or : possibleOR.getKeys()) {
+                               List<Statement> right = possibleOR.getValues(or);
+                               int iLeft[] = new int[left.size()];
+                               int iRight[] = new int[right.size()];
+                               
+                               for (int i = 0; i < left.size(); i++) {
+                                       iLeft[i] = -1;
+                                       iRight[i] = -1;
+                               }
+                               
+                               for (int l = 0; l < left.size(); l++) {
+                                       Statement ls = left.get(l);
+                                       for (int r = 0; r < right.size(); r++) {
+                                               if (iRight[r] >= 0)
+                                                       continue;
+                                               Statement rs = right.get(r);
+                                               if (!comparableResources.contains(ls.getSubject(), rs.getSubject()))
+                                                       continue;
+                                               if (rcomp.compare(ls.getPredicate(),rs.getPredicate()) == 0) {
+                                                       iLeft[l] = r;
+                                                       iRight[r] = l;
+                                                       break;
+                                               }
+                                       }
+                                       
+                               }
+                               boolean success = true;
+                               for (int i = 0; i < left.size(); i++) {
+                                       if (iLeft[i] < 0) {
+                                               success = false;
+                                               break;
+                                       }
+                                       if (iRight[i] < 0) {
+                                               success = false;
+                                               break;
+                                       }
+                                               
+                               }
+                               if (success) {
+                                       for (Statement s : right) 
+                                               matchingOR.add(or,s);
+                                       matchingStatements.put(or, new Pair<int[], int[]>(iLeft, iRight));
+                               }
+                       }
+                       // if there is only one matching right side object, we have found a match 
+                       if (matchingOR.getKeySize() == 1) {
+                               Resource or = matchingOR.getKeys().iterator().next();
+                               List<Statement> right = matchingOR.getValues(or);
+                               Pair<int[], int[]> indices = matchingStatements.get(or);
+                               
+                               objectsLeft.add(ol);
+                               objectsRight.add(or);
+                               addComparable(ol, or, false);
+                               for (int l = 0; l < left.size(); l++) {
+                                       int r = indices.first[l];
+                                       Statement sl = left.get(l);
+                                       Statement sr = right.get(r);
+                                       addComparable(sl, sr, true);
+                                       unreliableLeft.remove(sl);
+                                       unreliableRight.remove(sr);
+                               }
+                               
+                       }
+
+               }
+               
+               
+       }
+       
+       private void processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
+               MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
+               MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
+               
+               for (Statement s : unreliableLeft) {
+                       subjectLeft.add(s.getSubject(),s);
+                       objectLeft.add(s.getObject(),s);
+               }
+               for (Statement s : unreliableRight) {
+                       subjectRight.add(s.getSubject(),s);
+                       objectRight.add(s.getObject(),s);
+               }
+               for (Resource ol : objectLeft.getKeys()) {
+                       Set<Path> pathsLeft = new HashSet<Path>();
+                       for (Resource rel : traversed) {
+                               pathsLeft.addAll(Path.create(g.getStatements(ol, rel)));
+                       }
+                       while (true) {
+                               expand(pathsLeft);
+                               if (pathsLeft.size() == 0)
+                                       break;
+                               Collection<Path> endPaths = new ArrayList<Path>(1);
+                               for (Path p : pathsLeft) {
+                                       if (comparableResources.containsLeft(p.getEnd())) {
+                                               endPaths.add(p);
+                                       }
+                               }
+                               if (endPaths.size() > 0) {
+                                       pathsLeft.clear();
+                                       pathsLeft.addAll(endPaths);
+                                       break;
+                               }       
+                       }
+                       if (pathsLeft.size() > 0) {
+                               Resource sl = objectLeft.getValues(ol).get(0).getSubject();
+                               Resource sr = comparableResources.getRight(sl);
+                               Collection<Resource> possibleOR = new ArrayList<Resource>();
+                               for (Statement s : subjectRight.getValues(sr)) {
+                                       possibleOR.add(s.getObject());
+                               }
+                               Map<Resource,Set<Path>> matchingPaths = new HashMap<Resource, Set<Path>>();
+                               for (Resource or : possibleOR) {
+                                       Set<Path> possiblePathsRight = new HashSet<Path>();
+                                       for (Path leftPath : pathsLeft) {
+                                               possiblePathsRight.addAll(findComparableRight(leftPath, or));
+                                       }
+                                       if (hasMatchingPaths(pathsLeft, possiblePathsRight)) {
+                                               matchingPaths.put(or, possiblePathsRight);
+                                       }
+                               }
+                               if (matchingPaths.size() > 0) {
+                                       if (matchingPaths.size() == 1) {
+                                               Resource or = matchingPaths.keySet().iterator().next();
+                                               
+                                               objectsLeft.add(ol);
+                                               objectsRight.add(or);
+                                               addComparable(ol, or, false);
+                                               Collection<Statement> statementsLeft = objectLeft.getValues(ol);
+                                               Collection<Statement> statementsRight = objectRight.getValues(or);
+                                               unreliableLeft.removeAll(statementsLeft);
+                                               unreliableRight.removeAll(statementsRight);
+                                               BijectionMap<Path,Path> map = getMatchingPaths(pathsLeft, matchingPaths.get(or));
+                                               for (Path left : map.getLeftSet()) {
+                                                       Path right = map.getRight(left);
+                                                       for (int i = 0; i < left.getLength(); i++) {
+                                                               addComparable(left.getStatements().get(i),right.getStatements().get(i),false);
+                                                       }
+                                               }
+                                       } 
+                               }
+                       }
+                       
+               }
+               
+       }
+       
+       private boolean hasMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {
+               if (leftPaths.size() != rightPaths.size())
+                       return false;
+               BijectionMap<Path,Path> map = getMatchingPaths(leftPaths, rightPaths);
+               return map.size() == leftPaths.size();
+       }
+       
+       private BijectionMap<Path,Path> getMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {
+               BijectionMap<Path,Path> map = new BijectionMap<Path, Path>();
+               for (Path leftPath : leftPaths) {
+                       for (Path rightPath : rightPaths) {
+                               if (map.containsRight(rightPath))
+                                       continue;
+                               if (leftPath.getLength() != rightPath.getLength())
+                                       continue;
+                               if (comparableResources.contains(leftPath.getEnd(), rightPath.getEnd())) {
+                                       map.map(leftPath, rightPath);
+                                       break;
+                               }
+                       }
+               }
+               return map;
+       }
+       
+       private void expand(Set<Path> paths) throws DatabaseException {
+               Set<Path> stepPathsLeft = new HashSet<Path>();
+               if (paths.size() == 0)
+                       return;
+               int length = paths.iterator().next().getLength() + 1;
+               for (Path p : paths) {
+                       for (Resource rel : traversed) {
+                               stepPathsLeft.addAll(Path.expand(p,g.getStatements(p.getEnd(), rel)));
+                       }
+               }
+               paths.clear();
+               for (Path p : stepPathsLeft) {
+                       if (p.getLength() == length)
+                               paths.add(p);
+               }
+       }
+       
+       private Collection<Path> findComparableRight(Path leftPath, Resource beginRight) throws DatabaseException {
+               Set<Path> rightPaths = new HashSet<Path>();
+               rightPaths.addAll(Path.create(g.getStatements(beginRight, getRight(leftPath.getStatements().get(0).getPredicate()))));
+               for (int i = 1; i < leftPath.getLength(); i++) {
+                       if (rightPaths.size() == 0)
+                               return rightPaths;
+                       Set<Path> stepPaths = new HashSet<Path>();
+                       for (Path p : rightPaths) {
+                               stepPaths.addAll(Path.expand(p, g.getStatements(p.getEnd(), getRight(leftPath.getStatements().get(i).getPredicate()))));
+                       }
+                       rightPaths.clear();
+                       for (Path p : stepPaths)
+                               if (p.getLength() == i+1) 
+                                       rightPaths.add(p);
+               }
+               return rightPaths;
+               
+       }
+       
+       private Resource getRight(Resource r) {
+               if (comparableResources.containsLeft(r))
+                       return comparableResources.getRight(r);
+               return r;
+       }
+       
+
+       
+       public BijectionMap<Statement, Statement> getComparableStatements() {
+               return comparableStatements;
+       }
+       
+       public BijectionMap<Resource, Resource> getComparableResources() {
+               return comparableResources;
+       }
+       
+       public GraphChanges getChanges() {
+               return new GraphChanges(r1,r2,changes1,changes2,modifications,comparableResources);
+       }
+       
+       private void addComparable(Statement left, Statement right, boolean process) throws DatabaseException {
+               addComparable(left.getObject(), right.getObject(), process);
+               comparableStatements.map(left, right);
+               //comparableResources.map(left.getObject(), right.getObject());
+       }
+       
+       private void addComparable(Resource left, Resource right, boolean process) throws DatabaseException {
+               if(!comparableResources.contains(left, right)) {
+                       if (comparableResources.containsLeft(left)||comparableResources.containsRight(right)) {
+                               throw new DatabaseException("Comparator error: Trying to map " + left + " to " + right + " while mappings " + left + " to " + comparableResources.getRight(left) + " and " + comparableResources.getLeft(right) + " to " + right + " exist.");
+                       } else {
+                               if (DEBUG) System.out.println(left + " = " + right);
+                               comparableResources.map(left, right);           
+                       }
+               }
+               
+       }
+       
+       public List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws DatabaseException {
+               List<Statement> out = new ArrayList<Statement>();
+               for (Statement s : in) {
+                       if (!s.isAsserted(r))
+                               out.add(s);
+                       
+               }
+               return out;
+       }
+       
+       
+
+       private String printStatement(ReadGraph graph, Statement s) throws DatabaseException {
+               return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());
+       }
+       
+       private List<Statement> filterTraversed(List<Statement> in) throws DatabaseException {
+               return filter(traversed, in);
+       }
+       
+       private List<Statement> filterNonTested(List<Statement> in) throws DatabaseException {
+               return filter(nonTested, in);
+       }
+       
+       private List<Statement> filterNonTraversed(List<Statement> in) throws DatabaseException {
+               return filter(nonTraversed, in);
+       }
+       
+       private List<Statement> filter(Collection<Resource> toFilter, List<Statement> in) throws DatabaseException {
+               if (toFilter.size() == 0)
+                       return in;
+               List<Statement> out = new ArrayList<Statement>();
+               for (Statement s : in) {
+                       boolean usable = true;
+                       for (Resource r : toFilter) {
+                               if (g.isSubrelationOf(s.getPredicate(),r)) {
+                                       usable = false;
+                                       break;
+                               }
+                       }
+                       if (usable) {
+                               out.add(s);
+                       }
+                       
+               }
+               return out;
+       }
+       
+       
+       private void addDeletion(Statement s) {
+               if (!changes1Set.contains(s)) {
+                       changes1Set.add(s);
+                       changes1.add(s);
+               }
+       }
+       
+       private void addAddition(Statement s) {
+               if (!changes2Set.contains(s)) {
+                       changes2Set.add(s);
+                       changes2.add(s);
+               }
+       }
+       
+       private void addModification(Statement s1, Statement s2) {
+               Pair<Statement, Statement> mod = new Pair<Statement, Statement>(s1,s2);
+               if (!modificationsSet.contains(mod)) {
+                       modificationsSet.add(mod);
+                       modifications.add(mod);
+               }
+       }
+       
+       public void sortStatement(List<Statement> list1, List<Statement> list2) {
+               sortStatement(list1, list2, scomp);
+       }
+       
+       public void sortStatement(List<Statement> list1, List<Statement> list2, Comparator<Statement> scomp) {
+               Collections.sort(list1,scomp);
+               Collections.sort(list2,scomp);
+               
+               List<Statement> sorted1 = new ArrayList<Statement>(list1.size());
+               List<Statement> sorted2 = new ArrayList<Statement>(list2.size());
+               sorted1.addAll(list1);
+               sorted2.addAll(list2);
+               
+               int ss1 = 0;
+               int ss2 = 0;
+               for (int i = 0; i < list1.size(); ) {
+                       Statement s1 = list1.get(i);
+                       int same1 = sameRel(list1, i);  
+                       for (int j = 0; j < list2.size(); j++) {
+                               Statement s2 = list2.get(j);
+                               if (scomp.compare(s1, s2) == 0) {
+                                       int same2 = sameRel(list2, j);
+                                       copy(sorted1,ss1,list1,i,same1);
+                                       ss1 += same1;
+                                       copy(sorted2,ss2,list2,j,same2);
+                                       ss2 += same2;
+                                       break;
+                               }
+                       }
+                       i+= same1;
+               }
+               if (ss1 < sorted1.size()) {
+                       for (Statement s : list1) {
+                               if (!sorted1.contains(s)) {
+                                       sorted1.set(ss1,s);
+                                       ss1++;
+                               }
+                       }
+               }
+               if (ss2 < sorted2.size()) {
+                       for (Statement s : list2) {
+                               if (!sorted2.contains(s)) {
+                                       sorted2.set(ss2,s);
+                                       ss2++;
+                               }
+                       }
+               }
+               
+               list1.clear();
+               list2.clear();
+               list1.addAll(sorted1);
+               list2.addAll(sorted2);
+       }
+       
+       public <T> void copy(List<T> to, int toIndex, List<T> from, int fromIndex, int amount) {
+               for (int i = 0; i <  amount; i++) {
+                       to.set(toIndex + i, from.get(fromIndex+ i));
+               }
+       }
+       
+       public void sortResource(List<Resource> list1, List<Resource> list2) {
+               Collections.sort(list1,rcomp);
+               int js = 0;
+               for (int i = 0; i < list1.size(); i++) {
+                       Resource s1 = list1.get(i);
+                       for (int j = js; j < list2.size(); j++) {
+                               Resource s2 = list2.get(j);
+                               if (rcomp.compare(s1, s2) == 0) {
+                                       Resource t = list2.get(js);
+                                       list2.set(js, s2);
+                                       list2.set(j, t);
+                                       break;
+                               }
+                       }
+                       js++;
+               }
+       }
+       
+       private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {
+               sortStatement(ss1, ss2);
+               
+               int i1 = 0;
+               int i2 = 0;
+               
+               while (true) {
+                       if (i1 >= ss1.size()) {
+                               if (i2 >= ss2.size()) {
+                                       break;
+                               } else {
+                                       while (i2 < ss2.size()) {
+                                               if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i2)));
+                                               
+                                               addAddition(ss2.get(i2));
+                                               i2++;
+                                       }
+                                       break;
+                               }
+                       } else if (i2 >= ss2.size()) {
+                               while (i1 < ss1.size()) {
+                                       if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i1)));
+                                       addDeletion(ss1.get(i1));
+                                       i1++;
+                               }
+                               break;
+                       }
+                       int same1 = sameRel(ss1, i1);
+                       int same2 = sameRel(ss2, i2);
+                       int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());
+                       if (c == 0) {
+                               compareStatements(ss1, i1, same1, ss2, i2, same2,objectsLeft,objectsRight,unreliableLeft,unreliableRight);
+                               i1+=same1;
+                               i2+=same2;
+                       } else if (c < 0) {
+                               for (int i = 0; i < same1; i++) {
+                                       if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i+i1)));
+                                       addDeletion(ss1.get(i+i1));
+                               }
+                               i1 += same1;
+                       } else {
+                               for (int i = 0; i < same2; i++) {
+                                       if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i+i2)));
+                                       addAddition(ss2.get(i+i2));
+                               }
+                               
+                               i2 += same2;
+                       }
+               }
+       }
+       
+
+       
+       private int sameRel(List<Statement> statements, int off) {
+               if (statements.size() <= off)
+                       return 0;
+               int same = 1;
+               long id = statements.get(off).getPredicate().getResourceId();
+               for (int i = off+1; i <statements.size(); i++) {
+                       if (statements.get(i).getPredicate().getResourceId() == id)
+                               same++;
+                       else 
+                               break;
+               }
+               return same;
+               
+       }
+
+       private int compareObject(Resource o1, Resource o2) throws DatabaseException {
+               if (o1.equals(o2))
+                       return -1;
+               if (comparableResources.contains(o1, o2))
+                       return (-1);
+               if (comparableResources.containsLeft(o1))
+                       return Integer.MAX_VALUE;
+               if (comparableResources.containsRight(o2))
+                       return Integer.MAX_VALUE;
+               if (nonMatchedLeft.contains(o1))
+                       return Integer.MAX_VALUE;
+               if (nonMatchedRight.contains(o2))
+                       return Integer.MAX_VALUE;
+               return comparator.compare(g, o1, o2);
+       }
+       
+       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 {
+               boolean[] used1 = new boolean[len1];
+               for (int i = 0; i < used1.length; i++) {
+                       used1[i] = false;
+               }
+               
+               boolean[] used2 = new boolean[len2];
+               for (int i = 0; i < used2.length; i++) {
+                       used2[i] = false;
+               }
+               
+               // left, right, difference
+               List<List<Integer>> differences = new ArrayList<List<Integer>>();
+               for (int i1 = off1; i1 < off1 + len1; i1++) {
+                       Statement s1 = ss1.get(i1);
+                       List<Integer> diff = new ArrayList<Integer>();
+                       for (int i2 = off2; i2 < off2 + len2; i2++) {
+                               Statement s2 = ss2.get(i2);
+                               int d = compareObject(s1.getObject(), s2.getObject());
+                               if (d == 0) {
+                                       for (Resource t : strong) {
+                                                if (s1.getPredicate().equals(t) || g.isSubrelationOf(s1.getPredicate(), t)) {
+                                                        d = 1;
+                                                        break;
+                                                }
+                                       }
+                               }
+                               diff.add(d);
+                       }
+                       differences.add(diff);
+               }
+               // difference, left
+               MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();
+               for (int i = 0; i < differences.size(); i++) {
+                       List<Integer> list = differences.get(i);
+                       for (int j = 0; j < list.size(); j++) {
+                               priorities.add(list.get(j), i);
+                       }
+               }
+               
+               Integer[] pris = priorities.getKeys(new Integer[]{});
+               Arrays.sort(pris);
+               
+               for (Integer pri : pris) {
+                       if (pri == Integer.MAX_VALUE) {
+
+                       } else if (pri == 0) {
+                               
+                       } else {
+                               List<Integer> i1s = priorities.getValues(pri);
+                               for (Integer i1 : i1s) {
+                                       if (used1[i1])
+                                               continue;
+                                       List<Integer> i2diff = differences.get(i1);
+                                       for (int i2 = 0; i2 < i2diff.size(); i2++) {
+                                               if (i2diff.get(i2) == pri) {
+                                                       if (used2[i2])
+                                                               continue;
+                                                       used1[i1] = true;
+                                                       used2[i2] = true;
+                                                       Statement s1  = ss1.get(i1+off1);
+                                                       Statement s2  = ss2.get(i2+off2);
+                                                       
+                                                       if (objectsLeft != null) {
+                                                               objectsLeft.add(s1.getObject());
+                                                               objectsRight.add(s2.getObject());
+                                                       } 
+                                                       addComparable(s1, s2, true);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               for (Integer pri : pris) {
+                       if (pri != 0)
+                               continue;
+                       Set<Statement> s1s = new HashSet<Statement>();
+                       Set<Statement> s2s = new HashSet<Statement>();
+                       Set<Integer> s1i = new HashSet<Integer>();
+                       Set<Integer> s2i = new HashSet<Integer>();
+                       List<Integer> i1s = priorities.getValues(pri);
+                       for (Integer i1 : i1s) {
+                               if (used1[i1])
+                                       continue;
+                               List<Integer> i2diff = differences.get(i1);
+                               for (int i2 = 0; i2 < i2diff.size(); i2++) {
+                                       if (i2diff.get(i2) == pri) {
+                                               if (used2[i2])
+                                                       continue;
+                                               Statement s1  = ss1.get(i1+off1);
+                                               Statement s2  = ss2.get(i2+off2);
+                                               s1s.add(s1);
+                                               s2s.add(s2);
+                                               s1i.add(i1);
+                                               s2i.add(i2);
+                                       }
+                               }
+                       }
+                       if (unreliableLeft != null) {
+                               unreliableLeft.addAll(s1s);
+                               unreliableRight.addAll(s2s);
+                       }
+                       for (Integer i : s1i)
+                               used1[i] = true;
+                       for (Integer i : s2i)
+                               used2[i] = true;
+
+               }
+               for (int i1 = off1; i1 < off1 + len1; i1++) {
+                       if (!used1[i1-off1]) {
+                               if (DEBUG) System.out.println("Compare Object deletion " + printStatement(g,ss1.get(i1)));
+                               addDeletion(ss1.get(i1));
+                       }
+               }
+               for (int i2 = off2; i2 < off2 + len2; i2++) {
+                       if (!used2[i2-off2]) {
+                               if (DEBUG) System.out.println("Compare Object addition " + printStatement(g,ss2.get(i2)));
+                               addAddition(ss2.get(i2));
+                       }
+               }
+       }
+       
+       
+       
+       /**
+        * compares properties, assumes functional relations
+        * @param r1
+        * @param r2
+        * @throws ServiceException
+        * @throws DoesNotContainValueException
+        * @throws ValidationException 
+        */
+       private void compareProps(Resource r1, Resource r2) throws DatabaseException {
+               if (DEBUG) System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));
+               List<Statement> ss1 = new ArrayList<Statement>();
+               List<Statement> ss2 = new ArrayList<Statement>();
+               ss1.addAll(g.getStatements(r1, b.HasProperty));
+               ss2.addAll(g.getStatements(r2, b.HasProperty));
+               ss1 = filterNonTested(ss1);
+               ss2 = filterNonTested(ss2);
+               sortStatement(ss1, ss2);
+               
+               int i1 = 0; 
+               int i2 = 0;
+               
+               while (true) {
+                       if (i1 >= ss1.size()) {
+                               if (i2 >= ss2.size())
+                                       break;
+                               else {
+                                       while (i2 < ss2.size()) {
+                                               if (DEBUG) System.out.println("Compare Prop diff2 " + printStatement(g,ss2.get(i2)));
+                                               addAddition(ss2.get(i2));
+                                               i2++;
+                                       }
+                                       break;
+                               }
+                       } else if (i2 >= ss2.size()) {
+                               while (i1 < ss1.size()) {
+                                       if (DEBUG) System.out.println("Compare Prop diff1 " + printStatement(g,ss1.get(i1)));
+                                       addDeletion(ss1.get(i1));
+                                       i1++;
+                               }
+                               break;
+                       }
+                       Statement s1 = ss1.get(i1);
+                       Statement s2 = ss2.get(i2);
+                       if (s1.isAsserted(r1) && s2.isAsserted(r2)) {
+                               i1++;
+                               i2++;
+                               continue;
+                       }
+                       int c = scomp.compare(s1, s2);
+                       switch (c) {
+                               case 0:{
+                                       boolean b1 = g.hasValue(s1.getObject());
+                                       boolean b2 = g.hasValue(s2.getObject());
+                                       if (b1 == b2) {
+                                               if (b1) {
+                                                       Object v1 = g.getValue(s1.getObject());
+                                                       Object v2 = g.getValue(s2.getObject());
+                                                       boolean eq = compareValue(v1, v2);
+                                                       if (!eq) {
+                                                               addModification(s1, s2);
+                                                               addComparable(s1, s2, false);
+                                                       }
+                                               } else {
+                                                       if (!s1.getObject().equals(s1.getSubject()) && !s2.getObject().equals(s2.getSubject()))
+                                                               compareProps(s1.getObject(), s2.getObject());
+                                               }
+                                       } else {
+                                               addModification(s1, s2);
+                                               addComparable(s1, s2, false);
+                                       }
+                                       i1++;
+                                       i2++;
+                                       break;
+                               }
+                               case -1:{
+                                       if (DEBUG) System.out.println("Compare Prop diff1s " + printStatement(g,s1));
+                                       addDeletion(s1);
+                                       i1++;
+                                       break;
+                               }
+                                       
+                               case 1:{
+                                       if (DEBUG) System.out.println("Compare Prop diff2s " + printStatement(g,s2));
+                                       addAddition(s2);
+                                       i2++;
+                                       break;
+                               }
+                       }
+
+               }
+               
+               ss1.clear();
+               ss2.clear();
+               
+       }
+       
+       public static boolean compareValue(Object v1, Object v2) {
+               if (v1 instanceof Object[] && v2 instanceof Object[])
+                       return Arrays.deepEquals((Object[])v1, (Object[])v2);
+               else if (v1 instanceof int[] && v2 instanceof int[]) 
+                       return Arrays.equals((int[])v1, (int[])v2);
+               else if (v1 instanceof float[] && v2 instanceof float[]) 
+                       return Arrays.equals((float[])v1, (float[])v2);
+               else if (v1 instanceof double[] && v2 instanceof double[]) 
+                       return Arrays.equals((double[])v1, (double[])v2);
+               else if (v1 instanceof long[] && v2 instanceof long[]) 
+                       return  Arrays.equals((long[])v1, (long[])v2);
+               else if (v1 instanceof byte[] && v2 instanceof byte[]) 
+                       return Arrays.equals((byte[])v1, (byte[])v2);
+               else if (v1 instanceof boolean[] && v2 instanceof boolean[]) 
+                       return Arrays.equals((boolean[])v1, (boolean[])v2);
+               else
+                       return v1.equals(v2);
+       }
+
+       
+       public class PredicateComparator implements Comparator<Statement> {
+               @Override
+               public int compare(Statement o1, Statement o2) {
+                       if (comparableResources.contains(o1.getPredicate(), o2.getPredicate()))
+                               return 0;
+                       if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
+                               return -1;
+                       if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
+                               return 1;
+                       return 0;
+               }
+       }
+       
+       public class SubjectComparator implements Comparator<Statement> {
+               @Override
+               public int compare(Statement o1, Statement o2) {
+                       if (comparableResources.contains(o1.getSubject(), o2.getSubject()))
+                               return 0;
+                       if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
+                               return -1;
+                       if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
+                               return 1;
+                       return 0;
+               }
+       }
+       
+       public class ObjectComparator implements Comparator<Statement> {
+               @Override
+               public int compare(Statement o1, Statement o2) {
+                       if (comparableResources.contains(o1.getObject(), o2.getObject()))
+                               return 0;
+                       if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
+                               return -1;
+                       if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
+                               return 1;
+                       return 0;
+               }
+       }
+       
+       public static class FullStatementComparator implements Comparator<Statement> {
+               @Override
+               public int compare(Statement o1, Statement o2) {
+                       if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
+                               return -1;
+                       if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
+                               return 1;
+                       if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
+                               return -1;
+                       if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
+                               return 1;
+                       if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
+                               return -1;
+                       if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
+                               return 1;
+                       return 0;
+               }
+       }
+       
+       public class ResComparator implements Comparator<Resource> {
+               @Override
+               public int compare(Resource o1, Resource o2) {
+                       if (comparableResources.contains(o1, o2))
+                               return 0;
+                       if (o1.getResourceId() < o2.getResourceId())
+                               return -1;
+                       if (o1.getResourceId() > o2.getResourceId())
+                               return 1;
+                       return 0;
+               }
+       }
+
+}