1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Foster Wheeler Energia Oy - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.interop.test;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.Map.Entry;
25 import java.util.Stack;
27 import org.simantics.db.ReadGraph;
28 import org.simantics.db.Resource;
29 import org.simantics.db.Session;
30 import org.simantics.db.Statement;
31 import org.simantics.db.common.request.ReadRequest;
32 import org.simantics.db.common.utils.NameUtils;
33 import org.simantics.db.exception.DatabaseException;
34 import org.simantics.layer0.Layer0;
35 import org.simantics.utils.datastructures.BijectionMap;
36 import org.simantics.utils.datastructures.MapList;
37 import org.simantics.utils.datastructures.Pair;
40 * Compares two subgraphs and reports differences.
42 * Assumes that subgraphs (defined using traverse relations) are not cyclic.
44 * Assumes that properties can be used to identify objects, if relation type is not enough.
48 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
51 public class GraphComparator {
53 private static final boolean DEBUG = false;
57 private Set<Resource> strong = new HashSet<Resource>(); // List of relations that identify object, if subject is already identified.
58 private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)
59 private List<Resource> tested = new ArrayList<Resource>(); // list of relations that are tested, but not traversed
60 private List<Resource> nonTraversed = new ArrayList<Resource>(); // list of relations that are not traversed
61 private List<Resource> nonTested = new ArrayList<Resource>(); // list of relations that are not tested
63 private List<Statement> changes1 = new ArrayList<Statement>();
64 private List<Statement> changes2 = new ArrayList<Statement>();
65 private List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
66 private Set<Statement> changes1Set = new HashSet<Statement>();
67 private Set<Statement> changes2Set = new HashSet<Statement>();
68 private Set<Pair<Statement,Statement>> modificationsSet = new HashSet<Pair<Statement,Statement>>();
70 private BijectionMap<Statement, Statement> comparableStatements = new BijectionMap<Statement, Statement>();
71 private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<Resource, Resource>();
73 private Set<Resource> processedResources = new HashSet<Resource>();
75 private ResourceComparator comparator;
77 private Comparator<Statement> scomp = new PredicateComparator();
78 private Comparator<Resource> rcomp = new ResComparator();
80 private Set<Resource> nonMatchedLeft = new HashSet<Resource>();
81 private Set<Resource> nonMatchedRight = new HashSet<Resource>();
88 public GraphComparator(Resource r1, Resource r2) {
91 comparator = new TypeComparator();
94 public GraphComparator(Resource r1, Resource r2, ResourceComparator comparator) {
97 this.comparator = comparator;
100 ArrayList<Statement> ss1 = new ArrayList<Statement>();
101 ArrayList<Statement> ss2 = new ArrayList<Statement>();
104 public Comparator<Resource> getResourceComparator() {
108 public Comparator<Statement> getStatementComparator() {
112 public Resource getR1() {
116 public Resource getR2() {
120 public void addTraversed(Resource rel) {
124 public void addTraversed(Collection<Resource> rels) {
125 traversed.addAll(rels);
128 public void addNonTraversed(Resource rel) {
129 nonTraversed.add(rel);
132 public void addNonTraversed(Collection<Resource> rels) {
133 nonTraversed.addAll(rels);
136 public void addTested(Resource rel) {
140 public void addTested(Collection<Resource> rels) {
144 public void addNonTested(Resource rel) {
148 public void addNonTested(Collection<Resource> rels) {
149 nonTested.addAll(rels);
152 public void addComparableResources(Resource r1, Resource r2) {
153 comparableResources.map(r1, r2);
156 public void addComparableResources(BijectionMap<Resource, Resource> matching) {
157 comparableResources.addAll(matching);
160 public void addStrong(Resource r) {
164 public void addStrong(Collection<Resource> rels) {
168 public void addNonMatchedLeft(Resource r) {
169 nonMatchedLeft.add(r);
172 public void addNonMatchedRight(Resource r) {
173 nonMatchedRight.add(r);
176 public void test(ReadGraph g) throws DatabaseException {
178 this.b = Layer0.getInstance(g);
179 comparator.setComparator(this);
181 Stack<Resource> objectsLeft = new Stack<Resource>();
182 Stack<Resource> objectsRight = new Stack<Resource>();
183 objectsLeft.push(r1);
184 objectsRight.push(r2);
186 Set<Statement> unreliableLeft = new HashSet<Statement>();
187 Set<Statement> unreliableRight = new HashSet<Statement>();
190 if (objectsLeft.isEmpty())
194 // process compares objects that are identified and searches for more resources to process.
195 process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
196 // process unreliable handles cases where unidentified statements subject and object have been identified
197 processUnreliable(unreliableLeft, unreliableRight);
198 // process unreliable handles cases where unidentified resources have path of length one to identified resource
199 processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
200 if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
201 processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
203 if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
204 // comparison is ending, but we have still unprocessed unidentified resources left.
205 // These cases have longer path than one to identified objects.
206 processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
210 for (Statement s : unreliableLeft) {
211 if (!comparableStatements.containsLeft(s))
214 for (Statement s : unreliableRight) {
215 if (!comparableStatements.containsRight(s))
220 public void test(Session session) throws DatabaseException {
221 test(session, r1, r2);
224 public void test(Session session, Resource r1, Resource r2) throws DatabaseException {
226 comparator.setComparator(this);
228 addComparable(r1, r2);
230 final Stack<Resource> objectsLeft = new Stack<Resource>();
231 final Stack<Resource> objectsRight = new Stack<Resource>();
232 objectsLeft.push(r1);
233 objectsRight.push(r2);
235 final Set<Statement> unreliableLeft = new HashSet<Statement>();
236 final Set<Statement> unreliableRight = new HashSet<Statement>();
239 if (objectsLeft.isEmpty())
241 session.syncRequest(new ReadRequest() {
244 public void run(ReadGraph graph) throws DatabaseException {
246 b = Layer0.getInstance(graph);
247 // process compares objects that are identified and searches for more resources to process.
248 process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
249 // process unreliable handles cases where unidentified statements subject and object have been identified
250 processUnreliable(unreliableLeft, unreliableRight);
251 // process unreliable handles cases where unidentified resources have path of length one to identified resource
252 processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
253 if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
254 processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
256 if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
257 // comparison is ending, but we have still unprocessed unidentified resources left.
258 // These cases have longer path than one to identified objects.
259 processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
267 for (Statement s : unreliableLeft) {
268 if (!comparableStatements.containsLeft(s))
269 if (s.getObject().getResourceId() == 303248)
270 System.out.println();
273 for (Statement s : unreliableRight) {
274 if (!comparableStatements.containsRight(s))
281 private void process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
282 List<Statement> ss1 = new ArrayList<Statement>();
283 List<Statement> ss2 = new ArrayList<Statement>();
285 while (!objectsLeft.isEmpty()) {
286 Resource r1 = objectsLeft.pop();
287 Resource r2 = objectsRight.pop();
292 if (processedResources.contains(r1))
294 processedResources.add(r1);
297 if((comparableResources.containsLeft(r1)||comparableResources.containsRight(r2)) && !comparableResources.contains(r1, r2)) {
298 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.");
300 addComparable(r1, r2);
302 //System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));
303 compareProps(r1, r2);
305 for (Resource rel : tested) {
306 ss1.addAll(g.getStatements(r1, rel));
307 ss2.addAll(g.getStatements(r2, rel));
308 ss1 = filterAsserted(r1, ss1);
309 ss2 = filterAsserted(r2, ss2);
310 ss1 = filterTraversed(ss1);
311 ss2 = filterTraversed(ss2);
312 ss1 = filterNonTested(ss1);
313 ss2 = filterNonTested(ss2);
316 compareStatements(ss1, ss2, null, null,null,null);
321 for (Resource rel : traversed) {
322 ss1.addAll(g.getStatements(r1, rel));
323 ss2.addAll(g.getStatements(r2, rel));
324 ss1 = filterAsserted(r1, ss1);
325 ss2 = filterAsserted(r2, ss2);
326 ss1 = filterNonTraversed(ss1);
327 ss2 = filterNonTraversed(ss2);
328 compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
336 private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
337 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
338 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
339 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
340 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
342 for (Statement s : unreliableLeft) {
343 subjectLeft.add(s.getSubject(),s);
344 objectLeft.add(s.getObject(),s);
346 for (Statement s : unreliableRight) {
347 subjectRight.add(s.getSubject(),s);
348 objectRight.add(s.getObject(),s);
351 for (Resource left : subjectLeft.getKeys()) {
352 Resource right = comparableResources.getRight(left);
355 for (Statement leftS : subjectLeft.getValues(left)) {
356 Resource leftO = leftS.getObject();
357 if (!unreliableLeft.contains(leftS))
359 Resource rightO = comparableResources.getRight(leftO);
362 for (Statement rightS : subjectRight.getValues(right)) {
363 if (!rightS.getObject().equals(rightO))
365 if (!unreliableRight.contains(rightS))
367 if (leftS.getPredicate().equals(rightS.getPredicate()) ||
368 comparableResources.contains(leftS.getPredicate(), rightS.getPredicate())) {
369 unreliableLeft.remove(leftS);
370 unreliableRight.remove(rightS);
371 addComparable(leftS, rightS);
378 private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
379 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
380 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
381 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
382 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
384 for (Statement s : unreliableLeft) {
385 subjectLeft.add(s.getSubject(),s);
386 objectLeft.add(s.getObject(),s);
388 for (Statement s : unreliableRight) {
389 subjectRight.add(s.getSubject(),s);
390 objectRight.add(s.getObject(),s);
393 for (Resource ol : objectLeft.getKeys()) {
394 // all statements to the left side object
395 List<Statement> left = objectLeft.getValues(ol);
396 // all subjects that have statements to the left side object (ol)
397 Set<Resource> sLeft = new HashSet<Resource>();
398 // all matching subjects on the right side
399 Set<Resource> sRight = new HashSet<Resource>();
400 for (Statement s : left) {
401 sLeft.add(s.getSubject());
402 sRight.add(comparableResources.getRight(s.getSubject()));
405 // check if object left can be reliably identified by available statements
406 // if there are any objects on the left side with similar statements, object left cannot be mapped.
407 boolean hasSimilar = false;
408 MapList<Resource, Statement> comparableOLeft = new MapList<Resource, Statement>();
409 for (Resource sl : sLeft) {
410 for (Statement s : subjectLeft.getValues(sl)) {
411 if (!s.getObject().equals(ol)) {
412 comparableOLeft.add(s.getObject(),s);
417 compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
419 for (Resource similarOl : comparableOLeft.getKeys()) {
420 List<Statement> similarLeft = comparableOLeft.getValues(similarOl);
421 if (similarLeft.size() == left.size()) {
422 boolean useL[] = new boolean[left.size()];
423 boolean useSL[] = new boolean[left.size()];
424 for (int i = 0; i < left.size(); i++) {
428 for (int i = 0; i < left.size(); i++) {
429 for (int j = 0; j < left.size(); j++) {
432 // compare predicates
433 Resource pl = left.get(i).getPredicate();
434 Resource psl = similarLeft.get(j).getPredicate();
435 if (pl.equals(psl)) {
436 // compare objects (unreliable result is interpreted as positive match)
438 int comp = comparator.compare(g, left.get(i).getObject(), similarLeft.get(j).getObject(), true);
439 if (comp >= 0 && comp < Integer.MAX_VALUE) {
447 boolean diff = false;
448 for (int i = 0; i < left.size(); i++) {
449 if (!useL[i] || !useSL[i]) {
464 // all objects that subjects on the right side point to. Object left has its matching resource among these, if it has matching resource
465 MapList<Resource,Statement> possibleOR = new MapList<Resource, Statement>();
466 for (Resource sr : sRight) {
467 for (Statement s : subjectRight.getValues(sr))
468 possibleOR.add(s.getObject(),s);
471 // filter possible right side objects to those that have same amount of statements as the left side object
472 for (Resource or : possibleOR.getKeys().toArray(new Resource[possibleOR.getKeys().size()])) {
473 List<Statement> right = possibleOR.getValues(or);
474 if (right.size() != left.size())
475 possibleOR.remove(or);
479 // check for matching statements (comparable subjects, matching predicates)
480 MapList<Resource,Statement> matchingOR = new MapList<Resource, Statement>(); // list of objects that have matching statements
481 Map<Resource,Pair<int[], int[]>> matchingStatements = new HashMap<Resource, Pair<int[], int[]>>(); // matching statements
482 for (Resource or : possibleOR.getKeys()) {
483 List<Statement> right = possibleOR.getValues(or);
484 int iLeft[] = new int[left.size()];
485 int iRight[] = new int[right.size()];
487 for (int i = 0; i < left.size(); i++) {
492 for (int l = 0; l < left.size(); l++) {
493 Statement ls = left.get(l);
494 for (int r = 0; r < right.size(); r++) {
497 Statement rs = right.get(r);
498 if (!comparableResources.contains(ls.getSubject(), rs.getSubject()))
500 if (rcomp.compare(ls.getPredicate(),rs.getPredicate()) == 0) {
501 // compare objects (unreliable result is not accepted)
502 int comp = comparator.compare(g, ls.getObject(), rs.getObject());
503 if (comp > 0 && comp < Integer.MAX_VALUE) {
513 boolean success = true;
514 for (int i = 0; i < left.size(); i++) {
526 for (Statement s : right)
527 matchingOR.add(or,s);
528 matchingStatements.put(or, new Pair<int[], int[]>(iLeft, iRight));
531 // if there is only one matching right side object, we have found a match
532 if (matchingOR.getKeySize() == 1) {
533 Resource or = matchingOR.getKeys().iterator().next();
534 List<Statement> right = matchingOR.getValues(or);
535 Pair<int[], int[]> indices = matchingStatements.get(or);
538 objectsRight.add(or);
539 addComparable(ol, or);
540 for (int l = 0; l < left.size(); l++) {
541 int r = indices.first[l];
542 Statement sl = left.get(l);
543 Statement sr = right.get(r);
544 addComparable(sl, sr);
545 unreliableLeft.remove(sl);
546 unreliableRight.remove(sr);
558 private void processUnreliable2(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
559 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
560 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
561 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
562 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
564 for (Statement s : unreliableLeft) {
565 subjectLeft.add(s.getSubject(),s);
566 objectLeft.add(s.getObject(),s);
568 for (Statement s : unreliableRight) {
569 subjectRight.add(s.getSubject(),s);
570 objectRight.add(s.getObject(),s);
573 for (Resource ol : objectLeft.getKeys()) {
574 // all statements to the left side object
575 List<Statement> left = objectLeft.getValues(ol);
576 // all subjects that have statements to the left side object (ol)
577 Set<Resource> sLeft = new HashSet<Resource>();
578 // all matching subjects on the right side
579 Set<Resource> sRight = new HashSet<Resource>();
580 for (Statement s : left) {
581 sLeft.add(s.getSubject());
582 sRight.add(comparableResources.getRight(s.getSubject()));
585 if (sLeft.size() == 1 && sRight.size() == 1) {
586 List<Statement> ss1 = new ArrayList<Statement>(subjectLeft.getValues(sLeft.iterator().next()));
587 List<Statement> ss2 = new ArrayList<Statement>(subjectRight.getValues(sRight.iterator().next()));
589 int count = comparableStatements.size();
590 compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
591 if (comparableStatements.size() > count) {
592 for (Entry<Statement, Statement> entry : comparableStatements.getEntries()) {
593 unreliableLeft.remove(entry.getKey());
594 unreliableRight.remove(entry.getValue());
601 private void processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
602 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
603 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
604 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
605 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
607 for (Statement s : unreliableLeft) {
608 subjectLeft.add(s.getSubject(),s);
609 objectLeft.add(s.getObject(),s);
611 for (Statement s : unreliableRight) {
612 subjectRight.add(s.getSubject(),s);
613 objectRight.add(s.getObject(),s);
615 for (Resource ol : objectLeft.getKeys()) {
616 Set<Path> pathsLeft = new HashSet<Path>();
617 for (Resource rel : traversed) {
618 pathsLeft.addAll(Path.create(g.getStatements(ol, rel)));
622 if (pathsLeft.size() == 0)
624 Collection<Path> endPaths = new ArrayList<Path>(1);
625 for (Path p : pathsLeft) {
626 if (comparableResources.containsLeft(p.getEnd())) {
630 if (endPaths.size() > 0) {
632 pathsLeft.addAll(endPaths);
636 if (pathsLeft.size() > 0) {
637 Resource sl = objectLeft.getValues(ol).get(0).getSubject();
638 Resource sr = comparableResources.getRight(sl);
639 Collection<Resource> possibleOR = new ArrayList<Resource>();
640 for (Statement s : subjectRight.getValues(sr)) {
641 possibleOR.add(s.getObject());
643 Map<Resource,Set<Path>> matchingPaths = new HashMap<Resource, Set<Path>>();
644 for (Resource or : possibleOR) {
645 Set<Path> possiblePathsRight = new HashSet<Path>();
646 for (Path leftPath : pathsLeft) {
647 possiblePathsRight.addAll(findComparableRight(leftPath, or));
649 if (hasMatchingPaths(pathsLeft, possiblePathsRight)) {
650 matchingPaths.put(or, possiblePathsRight);
653 if (matchingPaths.size() > 0) {
654 if (matchingPaths.size() == 1) {
655 Resource or = matchingPaths.keySet().iterator().next();
658 objectsRight.add(or);
659 addComparable(ol, or);
660 Collection<Statement> statementsLeft = objectLeft.getValues(ol);
661 Collection<Statement> statementsRight = objectRight.getValues(or);
662 unreliableLeft.removeAll(statementsLeft);
663 unreliableRight.removeAll(statementsRight);
664 BijectionMap<Path,Path> map = getMatchingPaths(pathsLeft, matchingPaths.get(or));
665 for (Path left : map.getLeftSet()) {
666 Path right = map.getRight(left);
667 for (int i = 0; i < left.getLength(); i++) {
668 addComparable(left.getStatements().get(i),right.getStatements().get(i));
679 private boolean hasMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {
680 if (leftPaths.size() != rightPaths.size())
682 BijectionMap<Path,Path> map = getMatchingPaths(leftPaths, rightPaths);
683 return map.size() == leftPaths.size();
686 private BijectionMap<Path,Path> getMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {
687 BijectionMap<Path,Path> map = new BijectionMap<Path, Path>();
688 for (Path leftPath : leftPaths) {
689 for (Path rightPath : rightPaths) {
690 if (map.containsRight(rightPath))
692 if (leftPath.getLength() != rightPath.getLength())
694 if (comparableResources.contains(leftPath.getEnd(), rightPath.getEnd())) {
695 map.map(leftPath, rightPath);
703 private void expand(Set<Path> paths) throws DatabaseException {
704 Set<Path> stepPathsLeft = new HashSet<Path>();
705 if (paths.size() == 0)
707 int length = paths.iterator().next().getLength() + 1;
708 for (Path p : paths) {
709 for (Resource rel : traversed) {
710 stepPathsLeft.addAll(Path.expand(p,g.getStatements(p.getEnd(), rel)));
714 for (Path p : stepPathsLeft) {
715 if (p.getLength() == length)
720 private Collection<Path> findComparableRight(Path leftPath, Resource beginRight) throws DatabaseException {
721 Set<Path> rightPaths = new HashSet<Path>();
722 rightPaths.addAll(Path.create(g.getStatements(beginRight, getRight(leftPath.getStatements().get(0).getPredicate()))));
723 for (int i = 1; i < leftPath.getLength(); i++) {
724 if (rightPaths.size() == 0)
726 Set<Path> stepPaths = new HashSet<Path>();
727 for (Path p : rightPaths) {
728 stepPaths.addAll(Path.expand(p, g.getStatements(p.getEnd(), getRight(leftPath.getStatements().get(i).getPredicate()))));
731 for (Path p : stepPaths)
732 if (p.getLength() == i+1)
739 private Resource getRight(Resource r) {
740 if (comparableResources.containsLeft(r))
741 return comparableResources.getRight(r);
747 public BijectionMap<Statement, Statement> getComparableStatements() {
748 return comparableStatements;
751 public BijectionMap<Resource, Resource> getComparableResources() {
752 return comparableResources;
755 public GraphChanges getChanges() {
756 return new GraphChanges(r1,r2,changes1,changes2,modifications,comparableResources);
759 private void addComparable(Statement left, Statement right) throws DatabaseException {
760 addComparable(left.getObject(), right.getObject());
761 comparableStatements.map(left, right);
762 //comparableResources.map(left.getObject(), right.getObject());
765 private void addComparable(Resource left, Resource right) throws DatabaseException {
766 if(!comparableResources.contains(left, right)) {
767 if (comparableResources.containsLeft(left)||comparableResources.containsRight(right)) {
768 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.");
770 if (DEBUG) System.out.println(left + " = " + right);
771 comparableResources.map(left, right);
772 //if (left.getResourceId() == 313071 && right.getResourceId() == 325324)
773 if (left.getResourceId() == 313231 && right.getResourceId() == 337775)
774 System.out.println();
780 public List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws DatabaseException {
781 List<Statement> out = new ArrayList<Statement>();
782 for (Statement s : in) {
783 if (!s.isAsserted(r))
792 private String printStatement(ReadGraph graph, Statement s) throws DatabaseException {
793 return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());
796 private List<Statement> filterTraversed(List<Statement> in) throws DatabaseException {
797 return filter(traversed, in);
800 private List<Statement> filterNonTested(List<Statement> in) throws DatabaseException {
801 return filter(nonTested, in);
804 private List<Statement> filterNonTraversed(List<Statement> in) throws DatabaseException {
805 return filter(nonTraversed, in);
808 private List<Statement> filter(Collection<Resource> toFilter, List<Statement> in) throws DatabaseException {
809 if (toFilter.size() == 0)
811 List<Statement> out = new ArrayList<Statement>();
812 for (Statement s : in) {
813 boolean usable = true;
814 for (Resource r : toFilter) {
815 if (g.isSubrelationOf(s.getPredicate(),r)) {
829 private void addDeletion(Statement s) {
830 if (!changes1Set.contains(s)) {
836 private void addAddition(Statement s) {
837 if (!changes2Set.contains(s)) {
843 private void addModification(Statement s1, Statement s2) {
844 Pair<Statement, Statement> mod = new Pair<Statement, Statement>(s1,s2);
845 if (!modificationsSet.contains(mod)) {
846 modificationsSet.add(mod);
847 modifications.add(mod);
851 public void sortStatement(List<Statement> list1, List<Statement> list2) {
852 sortStatement(list1, list2, scomp);
855 public void sortStatement(List<Statement> list1, List<Statement> list2, Comparator<Statement> scomp) {
856 Collections.sort(list1,scomp);
857 Collections.sort(list2,scomp);
859 List<Statement> sorted1 = new ArrayList<Statement>(list1.size());
860 List<Statement> sorted2 = new ArrayList<Statement>(list2.size());
861 sorted1.addAll(list1);
862 sorted2.addAll(list2);
866 for (int i = 0; i < list1.size(); ) {
867 Statement s1 = list1.get(i);
868 int same1 = sameRel(list1, i);
869 for (int j = 0; j < list2.size(); j++) {
870 Statement s2 = list2.get(j);
871 if (scomp.compare(s1, s2) == 0) {
872 int same2 = sameRel(list2, j);
873 copy(sorted1,ss1,list1,i,same1);
875 copy(sorted2,ss2,list2,j,same2);
882 if (ss1 < sorted1.size()) {
883 for (Statement s : list1) {
884 if (!sorted1.contains(s)) {
890 if (ss2 < sorted2.size()) {
891 for (Statement s : list2) {
892 if (!sorted2.contains(s)) {
901 list1.addAll(sorted1);
902 list2.addAll(sorted2);
905 public <T> void copy(List<T> to, int toIndex, List<T> from, int fromIndex, int amount) {
906 for (int i = 0; i < amount; i++) {
907 to.set(toIndex + i, from.get(fromIndex+ i));
911 public void sortResource(List<Resource> list1, List<Resource> list2) {
912 Collections.sort(list1,rcomp);
914 for (int i = 0; i < list1.size(); i++) {
915 Resource s1 = list1.get(i);
916 for (int j = js; j < list2.size(); j++) {
917 Resource s2 = list2.get(j);
918 if (rcomp.compare(s1, s2) == 0) {
919 Resource t = list2.get(js);
929 private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {
930 sortStatement(ss1, ss2);
936 if (i1 >= ss1.size()) {
937 if (i2 >= ss2.size()) {
940 while (i2 < ss2.size()) {
941 if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i2)));
943 addAddition(ss2.get(i2));
948 } else if (i2 >= ss2.size()) {
949 while (i1 < ss1.size()) {
950 if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i1)));
951 addDeletion(ss1.get(i1));
956 int same1 = sameRel(ss1, i1);
957 int same2 = sameRel(ss2, i2);
958 int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());
960 compareStatements(ss1, i1, same1, ss2, i2, same2,objectsLeft,objectsRight,unreliableLeft,unreliableRight);
964 for (int i = 0; i < same1; i++) {
965 if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i+i1)));
966 addDeletion(ss1.get(i+i1));
970 for (int i = 0; i < same2; i++) {
971 if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i+i2)));
972 addAddition(ss2.get(i+i2));
982 private int sameRel(List<Statement> statements, int off) {
983 if (statements.size() <= off)
986 long id = statements.get(off).getPredicate().getResourceId();
987 for (int i = off+1; i <statements.size(); i++) {
988 if (statements.get(i).getPredicate().getResourceId() == id)
997 private int compareObject(Resource o1, Resource o2) throws DatabaseException {
1000 if (comparableResources.contains(o1, o2))
1002 if (comparableResources.containsLeft(o1))
1003 return Integer.MAX_VALUE;
1004 if (comparableResources.containsRight(o2))
1005 return Integer.MAX_VALUE;
1006 if (nonMatchedLeft.contains(o1))
1007 return Integer.MAX_VALUE;
1008 if (nonMatchedRight.contains(o2))
1009 return Integer.MAX_VALUE;
1010 return comparator.compare(g, o1, o2);
1013 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 {
1014 boolean[] used1 = new boolean[len1];
1015 for (int i = 0; i < used1.length; i++) {
1019 boolean[] used2 = new boolean[len2];
1020 for (int i = 0; i < used2.length; i++) {
1024 // left, right, difference
1025 List<List<Integer>> differences = new ArrayList<List<Integer>>();
1026 for (int i1 = off1; i1 < off1 + len1; i1++) {
1027 Statement s1 = ss1.get(i1);
1028 List<Integer> diff = new ArrayList<Integer>();
1029 for (int i2 = off2; i2 < off2 + len2; i2++) {
1030 Statement s2 = ss2.get(i2);
1031 int d = compareObject(s1.getObject(), s2.getObject());
1033 for (Resource t : strong) {
1034 if (s1.getPredicate().equals(t) || g.isSubrelationOf(s1.getPredicate(), t)) {
1042 differences.add(diff);
1045 MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();
1046 for (int i = 0; i < differences.size(); i++) {
1047 List<Integer> list = differences.get(i);
1048 for (int j = 0; j < list.size(); j++) {
1049 priorities.add(list.get(j), i);
1053 Integer[] pris = priorities.getKeys(new Integer[]{});
1056 for (Integer pri : pris) {
1057 if (pri == Integer.MAX_VALUE) {
1059 } else if (pri == 0) {
1062 List<Integer> i1s = priorities.getValues(pri);
1063 for (Integer i1 : i1s) {
1066 List<Integer> i2diff = differences.get(i1);
1067 for (int i2 = 0; i2 < i2diff.size(); i2++) {
1068 if (i2diff.get(i2) == pri) {
1073 Statement s1 = ss1.get(i1+off1);
1074 Statement s2 = ss2.get(i2+off2);
1076 if (objectsLeft != null) {
1077 objectsLeft.add(s1.getObject());
1078 objectsRight.add(s2.getObject());
1080 addComparable(s1, s2);
1088 for (Integer pri : pris) {
1091 Set<Statement> s1s = new HashSet<Statement>();
1092 Set<Statement> s2s = new HashSet<Statement>();
1093 Set<Integer> s1i = new HashSet<Integer>();
1094 Set<Integer> s2i = new HashSet<Integer>();
1095 List<Integer> i1s = priorities.getValues(pri);
1096 for (Integer i1 : i1s) {
1099 List<Integer> i2diff = differences.get(i1);
1100 for (int i2 = 0; i2 < i2diff.size(); i2++) {
1101 if (i2diff.get(i2) == pri) {
1104 Statement s1 = ss1.get(i1+off1);
1105 Statement s2 = ss2.get(i2+off2);
1113 if (unreliableLeft != null) {
1114 unreliableLeft.addAll(s1s);
1115 unreliableRight.addAll(s2s);
1117 for (Integer i : s1i)
1119 for (Integer i : s2i)
1123 for (int i1 = off1; i1 < off1 + len1; i1++) {
1124 if (!used1[i1-off1]) {
1125 if (DEBUG) System.out.println("Compare Object deletion " + printStatement(g,ss1.get(i1)));
1126 addDeletion(ss1.get(i1));
1129 for (int i2 = off2; i2 < off2 + len2; i2++) {
1130 if (!used2[i2-off2]) {
1131 if (DEBUG) System.out.println("Compare Object addition " + printStatement(g,ss2.get(i2)));
1132 addAddition(ss2.get(i2));
1140 * compares properties, assumes functional relations
1143 * @throws ServiceException
1144 * @throws DoesNotContainValueException
1145 * @throws ValidationException
1147 private void compareProps(Resource r1, Resource r2) throws DatabaseException {
1148 if (DEBUG) System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));
1149 List<Statement> ss1 = new ArrayList<Statement>();
1150 List<Statement> ss2 = new ArrayList<Statement>();
1151 ss1.addAll(g.getStatements(r1, b.HasProperty));
1152 ss2.addAll(g.getStatements(r2, b.HasProperty));
1153 ss1 = filterNonTested(ss1);
1154 ss2 = filterNonTested(ss2);
1155 sortStatement(ss1, ss2);
1161 if (i1 >= ss1.size()) {
1162 if (i2 >= ss2.size())
1165 while (i2 < ss2.size()) {
1166 if (DEBUG) System.out.println("Compare Prop diff2 " + printStatement(g,ss2.get(i2)));
1167 addAddition(ss2.get(i2));
1172 } else if (i2 >= ss2.size()) {
1173 while (i1 < ss1.size()) {
1174 if (DEBUG) System.out.println("Compare Prop diff1 " + printStatement(g,ss1.get(i1)));
1175 addDeletion(ss1.get(i1));
1180 Statement s1 = ss1.get(i1);
1181 Statement s2 = ss2.get(i2);
1182 if (s1.isAsserted(r1) && s2.isAsserted(r2)) {
1187 int c = scomp.compare(s1, s2);
1190 boolean b1 = g.hasValue(s1.getObject());
1191 boolean b2 = g.hasValue(s2.getObject());
1194 Object v1 = g.getValue(s1.getObject());
1195 Object v2 = g.getValue(s2.getObject());
1196 boolean eq = compareValue(v1, v2);
1198 addModification(s1, s2);
1199 addComparable(s1, s2);
1202 if (!s1.getObject().equals(s1.getSubject()) && !s2.getObject().equals(s2.getSubject()))
1203 compareProps(s1.getObject(), s2.getObject());
1206 addModification(s1, s2);
1207 addComparable(s1, s2);
1214 if (DEBUG) System.out.println("Compare Prop diff1s " + printStatement(g,s1));
1221 if (DEBUG) System.out.println("Compare Prop diff2s " + printStatement(g,s2));
1235 public static boolean compareValue(Object v1, Object v2) {
1236 if (v1 instanceof Object[] && v2 instanceof Object[])
1237 return Arrays.deepEquals((Object[])v1, (Object[])v2);
1238 else if (v1 instanceof int[] && v2 instanceof int[])
1239 return Arrays.equals((int[])v1, (int[])v2);
1240 else if (v1 instanceof float[] && v2 instanceof float[])
1241 return Arrays.equals((float[])v1, (float[])v2);
1242 else if (v1 instanceof double[] && v2 instanceof double[])
1243 return Arrays.equals((double[])v1, (double[])v2);
1244 else if (v1 instanceof long[] && v2 instanceof long[])
1245 return Arrays.equals((long[])v1, (long[])v2);
1246 else if (v1 instanceof byte[] && v2 instanceof byte[])
1247 return Arrays.equals((byte[])v1, (byte[])v2);
1248 else if (v1 instanceof boolean[] && v2 instanceof boolean[])
1249 return Arrays.equals((boolean[])v1, (boolean[])v2);
1251 return v1.equals(v2);
1255 public class PredicateComparator implements Comparator<Statement> {
1257 public int compare(Statement o1, Statement o2) {
1258 if (comparableResources.contains(o1.getPredicate(), o2.getPredicate()))
1260 if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
1262 if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
1268 public class SubjectComparator implements Comparator<Statement> {
1270 public int compare(Statement o1, Statement o2) {
1271 if (comparableResources.contains(o1.getSubject(), o2.getSubject()))
1273 if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
1275 if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
1281 public class ObjectComparator implements Comparator<Statement> {
1283 public int compare(Statement o1, Statement o2) {
1284 if (comparableResources.contains(o1.getObject(), o2.getObject()))
1286 if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
1288 if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
1294 public static class FullStatementComparator implements Comparator<Statement> {
1296 public int compare(Statement o1, Statement o2) {
1297 if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
1299 if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
1301 if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
1303 if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
1305 if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
1307 if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
1313 public class ResComparator implements Comparator<Resource> {
1315 public int compare(Resource o1, Resource o2) {
1316 if (comparableResources.contains(o1, o2))
1318 if (o1.getResourceId() < o2.getResourceId())
1320 if (o1.getResourceId() > o2.getResourceId())