]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java
Builtins removed
[simantics/interop.git] / org.simantics.interop / src / org / simantics / interop / test / GraphComparator.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     Foster Wheeler Energia Oy - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.interop.test;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Arrays;\r
16 import java.util.Collection;\r
17 import java.util.Collections;\r
18 import java.util.Comparator;\r
19 import java.util.List;\r
20 import java.util.Stack;\r
21 \r
22 import org.simantics.db.ReadGraph;\r
23 import org.simantics.db.Resource;\r
24 import org.simantics.db.Statement;\r
25 import org.simantics.db.exception.DoesNotContainValueException;\r
26 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
27 import org.simantics.db.exception.ServiceException;\r
28 import org.simantics.db.exception.ValidationException;\r
29 import org.simantics.layer0.Layer0;\r
30 import org.simantics.layer0.utils.direct.GraphUtils;\r
31 import org.simantics.utils.datastructures.BijectionMap;\r
32 import org.simantics.utils.datastructures.MapList;\r
33 \r
34 /**\r
35  * Compares two subgraphs and reports differences.\r
36  * \r
37  * Assumes that subgraphs (defined using traverse relations) are not cyclic.\r
38  * \r
39  * Assumes that properties can be used to identify objects, if relation type is not enough.\r
40  * \r
41  * \r
42  * \r
43  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
44  *\r
45  */\r
46 public class GraphComparator {\r
47 \r
48         \r
49         private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)\r
50         private List<Resource> tested = new ArrayList<Resource>();    // list of relations that are tested, but not traversed\r
51         \r
52         \r
53         private List<Statement> changes1 = new ArrayList<Statement>();\r
54         private List<Statement> changes2 = new ArrayList<Statement>();\r
55         private BijectionMap<Statement, Statement> comparable = new BijectionMap<Statement, Statement>();\r
56         \r
57         \r
58         // runtime attributes\r
59         \r
60         private ReadGraph g;\r
61         private Layer0 b;\r
62         \r
63         ArrayList<Resource> rs1 = new ArrayList<Resource>();\r
64         ArrayList<Resource> rs2 = new ArrayList<Resource>();\r
65         ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
66         ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
67         Comparator<Statement> scomp = new StatementComparator();\r
68         Comparator<Resource> rcomp = new ResourceComparator();\r
69 \r
70         \r
71         public void addTraversed(Resource rel) {\r
72                 traversed.add(rel);\r
73         }\r
74         \r
75         public void addTraversed(Collection<Resource> rels) {\r
76                 traversed.addAll(rels);\r
77         }\r
78         \r
79         public void addTested(Resource rel) {\r
80                 tested.add(rel);\r
81         }\r
82         \r
83         public void addTested(Collection<Resource> rels) {\r
84                 tested.addAll(rels);\r
85         }\r
86         \r
87         public void clearRels() {\r
88                 traversed.clear();\r
89                 tested.clear();\r
90         }\r
91         \r
92         public void test(ReadGraph g, Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
93                 this.g = g;\r
94                 this.b = Layer0.getInstance(g);\r
95                 \r
96                 changes1.clear();\r
97                 changes2.clear();\r
98                 \r
99                 Stack<Resource> stack1 = new Stack<Resource>();\r
100                 Stack<Resource> stack2 = new Stack<Resource>();\r
101                 stack1.push(r1);\r
102                 stack2.push(r2);\r
103                 \r
104                 ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
105                 ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
106                 \r
107                 while (!stack1.isEmpty()) {\r
108                         r1 = stack1.pop();\r
109                         r2 = stack2.pop();\r
110                         \r
111                         System.out.println("test " + GraphUtils.getReadableName(g, r1) + " " + GraphUtils.getReadableName(g, r2));\r
112                         compareProps(r1, r2);\r
113                         \r
114                         for (Resource rel : tested) {\r
115                                 filterTraversed(g.getStatements(r1, rel), ss1);\r
116                                 filterTraversed(g.getStatements(r2, rel), ss2);\r
117                                 \r
118                                 compareStatement(ss1, ss2, null, null);\r
119                                 ss1.clear();\r
120                                 ss2.clear();\r
121                         }\r
122                         \r
123                         for (Resource rel : traversed) {\r
124                                 ss1.addAll(g.getStatements(r1, rel));\r
125                                 ss2.addAll(g.getStatements(r2, rel));\r
126                                 compareStatement(ss1, ss2, stack1, stack2);\r
127                                 ss1.clear();\r
128                                 ss2.clear();\r
129                         }\r
130                 }\r
131         }\r
132         \r
133         public Collection<Statement> getChanges1() {\r
134                 return changes1;\r
135         }\r
136         \r
137         public Collection<Statement> getChanges2() {\r
138                 return changes2;\r
139         }\r
140         \r
141         public BijectionMap<Statement, Statement> getComparable() {\r
142                 return comparable;\r
143         }\r
144         \r
145         private void filterTraversed(Collection<Statement> in, Collection<Statement> out) throws ServiceException {\r
146                 for (Statement s : in) {\r
147                         boolean usable = true;\r
148                         for (Resource r : traversed) {\r
149                                 if (g.isSubrelationOf(s.getPredicate(),r)) {\r
150                                         usable = false;\r
151                                         break;\r
152                                 }\r
153                         }\r
154                         if (usable) {\r
155                                 out.add(s);\r
156                         }\r
157                         \r
158                 }\r
159         }\r
160         \r
161         private void compareStatement(List<Statement> ss1, List<Statement> ss2, Stack<Resource> stack1, Stack<Resource> stack2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
162                 Collections.sort(ss1, scomp);\r
163                 Collections.sort(ss2, scomp);\r
164                 \r
165                 int i1 = 0;\r
166                 int i2 = 0;\r
167                 \r
168                 while (true) {\r
169                         if (i1 >= ss1.size()) {\r
170                                 if (i2 >= ss2.size()) {\r
171                                         break;\r
172                                 } else {\r
173                                         while (i2 < ss2.size()) {\r
174                                                 changes2.add(ss2.get(i2));\r
175                                                 i2++;\r
176                                         }\r
177                                         break;\r
178                                 }\r
179                         } else if (i2 >= ss2.size()) {\r
180                                 while (i1 < ss1.size()) {\r
181                                         changes1.add(ss1.get(i1));\r
182                                         i1++;\r
183                                 }\r
184                                 break;\r
185                         }\r
186                         int same1 = sameRel(ss1, i1);\r
187                         int same2 = sameRel(ss2, i2);\r
188                         int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());\r
189                         if (c == 0) {\r
190                                 compareObject(ss1, i1, same1, ss2, i2, same2,stack1,stack2);\r
191                                 i1+=same1;\r
192                                 i2+=same2;\r
193                         } else if (c < 0) {\r
194                                 for (int i = 0; i < same1; i++) {\r
195                                         changes1.add(ss1.get(i+i1));\r
196                                 }\r
197                                 i1 += same1;\r
198                                 } else {\r
199                                         for (int i = 0; i < same2; i++) {\r
200                                         changes2.add(ss2.get(i+i2));\r
201                                 }\r
202                                 i2 += same2;\r
203                         }\r
204                         \r
205                 }\r
206         }\r
207         \r
208         private int sameRel(List<Statement> statements, int off) {\r
209                 if (statements.size() <= off)\r
210                         return 0;\r
211                 int same = 1;\r
212                 long id = statements.get(off).getPredicate().getResourceId();\r
213                 for (int i = off+1; i <statements.size(); i++) {\r
214                         if (statements.get(i).getPredicate().getResourceId() == id)\r
215                                 same++;\r
216                         else \r
217                                 break;\r
218                 }\r
219                 return same;\r
220                 \r
221         }\r
222 \r
223         \r
224         private void compareObject(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Stack<Resource> stack1, Stack<Resource> stack2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
225                 boolean[] used1 = new boolean[len1];\r
226                 for (int i = 0; i < used1.length; i++) {\r
227                         used1[i] = false;\r
228                 }\r
229                 \r
230                 boolean[] used2 = new boolean[len2];\r
231                 for (int i = 0; i < used2.length; i++) {\r
232                         used2[i] = false;\r
233                 }\r
234                 \r
235                 // left, right, difference\r
236                 List<List<Integer>> differences = new ArrayList<List<Integer>>();\r
237                 for (int i1 = off1; i1 < off1 + len1; i1++) {\r
238                         Statement s1 = ss1.get(i1);\r
239                         //Map<Integer,Integer> differences = new HashMap<Integer, Integer>();\r
240                         List<Integer> diff = new ArrayList<Integer>();\r
241                         for (int i2 = off2; i2 < off2 + len2; i2++) {\r
242                                 Statement s2 = ss2.get(i2);\r
243                                 if (!compareType(s1.getObject(), s2.getObject())) {\r
244                                         diff.add(Integer.MAX_VALUE);\r
245                                         continue;\r
246                                 }\r
247                                 diff.add(propsDiffCount(s1.getObject(), s2.getObject()));\r
248                         }\r
249                         differences.add(diff);\r
250                 }\r
251                 // difference, left\r
252                 MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();\r
253                 for (int i = 0; i < differences.size(); i++) {\r
254                         List<Integer> list = differences.get(i);\r
255                         for (int j = 0; j < list.size(); j++) {\r
256                                 priorities.add(list.get(j), i);\r
257                         }\r
258                 }\r
259                 \r
260                 Integer[] pris = priorities.getKeys(new Integer[]{});\r
261                 Arrays.sort(pris);\r
262                 \r
263                 for (Integer pri : pris) {\r
264                         if (pri == Integer.MAX_VALUE)\r
265                                 continue;\r
266                         List<Integer> i1s = priorities.getValues(pri);\r
267                         for (Integer i1 : i1s) {\r
268                                 if (used1[i1])\r
269                                         continue;\r
270                                 List<Integer> i2diff = differences.get(i1);\r
271                                 for (int i2 = 0; i2 < i2diff.size(); i2++) {\r
272                                         if (i2diff.get(i2) == pri) {\r
273                                                 if (used2[i2])\r
274                                                         break;\r
275                                                 used1[i1] = true;\r
276                                                 used2[i2] = true;\r
277                                                 if (stack1 != null) {\r
278                                                         stack1.add(ss1.get(i1+off1).getObject());\r
279                                                         stack2.add(ss2.get(i2+off2).getObject());\r
280                                                 } else {\r
281                                                         // TODO : how should we report non traversed differences\r
282                                                         // using compareProps assumes that referenced objects are the same (references are not different)\r
283                                                         // using propsDiffCount assumes that objects are different, and cannot report changes in referred object.\r
284                                                         \r
285                                                         //compareProps(ss1.get(i1+off1).getObject(), ss2.get(i2+off2).getObject());\r
286                                                         int diff = propsDiffCount(ss1.get(i1+off1).getObject(), ss2.get(i2+off2).getObject());\r
287                                                         if (diff != 0) {\r
288                                                                 changes1.add(ss1.get(i1+off1));\r
289                                                                 changes2.add(ss2.get(i2+off2));\r
290                                                         }\r
291                                                 }\r
292                                         }\r
293                                 }\r
294                         }\r
295                 }\r
296                 for (int i1 = off1; i1 < off1 + len1; i1++) {\r
297                         if (!used1[i1-off1])\r
298                                 changes1.add(ss1.get(i1));\r
299                 }\r
300                 for (int i2 = off2; i2 < off2 + len2; i2++) {\r
301                         if (!used2[i2-off2])\r
302                                 changes2.add(ss2.get(i2));\r
303                 }\r
304         }\r
305         \r
306         private boolean compareType(Resource r1, Resource r2) throws ServiceException, ManyObjectsForFunctionalRelationException {\r
307                 rs1.addAll(g.getObjects(r1, b.InstanceOf));\r
308                 rs2.addAll(g.getObjects(r2, b.InstanceOf));\r
309                 if (rs1.size() != rs2.size()) {\r
310                         rs1.clear();\r
311                         rs2.clear();\r
312                         return false;\r
313                 }\r
314                 Collections.sort(rs1, rcomp);\r
315                 Collections.sort(rs2, rcomp);\r
316                 for (int i = 0; i < rs1.size(); i++) {\r
317                         int c = rcomp.compare(rs1.get(i), rs2.get(i));\r
318                         if (c != 0) {\r
319                                 rs1.clear();\r
320                                 rs2.clear();\r
321                                 return false;\r
322                         }\r
323                 }\r
324                 \r
325                 rs1.clear();\r
326                 rs2.clear();\r
327                 \r
328                 return true;\r
329         }\r
330         \r
331         /**\r
332          * compares properties, assumes functional relations\r
333          * @param r1\r
334          * @param r2\r
335          * @throws ManyObjectsForFunctionalRelationException\r
336          * @throws ServiceException\r
337          * @throws DoesNotContainValueException\r
338          */\r
339         private void compareProps(Resource r1, Resource r2) throws ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {\r
340                 ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
341                 ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
342                 ss1.addAll(g.getStatements(r1, b.HasProperty));\r
343                 ss2.addAll(g.getStatements(r2, b.HasProperty));\r
344                 Collections.sort(ss1, scomp);\r
345                 Collections.sort(ss2, scomp);\r
346                 \r
347                 int i1 = 0; \r
348                 int i2 = 0;\r
349                 \r
350                 while (true) {\r
351                         if (i1 >= ss1.size()) {\r
352                                 if (i2 >= ss2.size())\r
353                                         break;\r
354                                 else {\r
355                                         while (i2 < ss2.size()) {\r
356                                                 changes2.add(ss2.get(i2));\r
357                                                 i2++;\r
358                                         }\r
359                                         break;\r
360                                 }\r
361                         } else if (i2 >= ss2.size()) {\r
362                                 while (i1 < ss1.size()) {\r
363                                         changes1.add(ss1.get(i1));\r
364                                         i1++;\r
365                                 }\r
366                                 break;\r
367                         }\r
368                         Statement s1 = ss1.get(i1);\r
369                         Statement s2 = ss2.get(i2);\r
370                         int c = scomp.compare(s1, s2);\r
371                         switch (c) {\r
372                         case 0:{\r
373                                 boolean b1 = g.hasValue(s1.getObject());\r
374                                 boolean b2 = g.hasValue(s2.getObject());\r
375                                 if (b1 == b2) {\r
376                                         if (b1) {\r
377                                                 Object v1 = g.getValue(s1.getObject());\r
378                                                 Object v2 = g.getValue(s2.getObject());\r
379                                                 boolean eq = false;\r
380                                                 if (v1 instanceof Object[] && v2 instanceof Object[])\r
381                                                         eq = Arrays.deepEquals((Object[])v1, (Object[])v2);\r
382                                                 else\r
383                                                         eq = v1.equals(v2);\r
384                                                 if (!eq) {\r
385                                                         changes1.add(s1);\r
386                                                         changes2.add(s2);\r
387                                                         comparable.map(s1, s2);\r
388                                                 }\r
389                                         } else {\r
390                                                 compareProps(s1.getObject(), s2.getObject());\r
391                                         }\r
392                                 } else {\r
393                                         changes1.add(s1);\r
394                                         changes2.add(s2);\r
395                                         comparable.map(s1, s2);\r
396                                 }\r
397                                 i1++;\r
398                                 i2++;\r
399                                 break;\r
400                         }\r
401                         case -1:{\r
402                                 changes1.add(s1);\r
403                                 i1++;\r
404                                 break;\r
405                         }\r
406                                 \r
407                         case 1:{\r
408                                 changes2.add(s2);\r
409                                 i2++;\r
410                                 break;\r
411                         }\r
412                         }\r
413                         \r
414                         \r
415                 }\r
416                 \r
417                 ss1.clear();\r
418                 ss2.clear();\r
419                 \r
420         }\r
421         \r
422         private int propsDiffCount(Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
423                 ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
424                 ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
425                 ss1.addAll(g.getStatements(r1, b.HasProperty));\r
426                 ss2.addAll(g.getStatements(r2, b.HasProperty));\r
427                 //System.out.println("Props count " + GraphUtils.getReadableName(g, r1) + " " + GraphUtils.getReadableName(g, r2));\r
428                 Collections.sort(ss1, scomp);\r
429                 Collections.sort(ss2, scomp);\r
430                 \r
431                 int count = 0;\r
432                 \r
433                 int i1 = 0; \r
434                 int i2 = 0;\r
435                 \r
436                 while (true) {\r
437                         if (i1 >= ss1.size()) {\r
438                                 if (i2 >= ss2.size())\r
439                                         break;\r
440                                 else {\r
441                                         while (i2 < ss2.size()) {\r
442                                                 count++;\r
443                                                 i2++;\r
444                                         }\r
445                                         break;\r
446                                 }\r
447                         } else if (i2 >= ss2.size()) {\r
448                                 while (i1 < ss1.size()) {\r
449                                         count++;\r
450                                         i1++;\r
451                                 }\r
452                                 break;\r
453                         }\r
454                         Statement s1 = ss1.get(i1);\r
455                         Statement s2 = ss2.get(i2);\r
456                         int c = scomp.compare(s1, s2);\r
457                         switch (c) {\r
458                         case 0:{\r
459                                 boolean b1 = g.hasValue(s1.getObject());\r
460                                 boolean b2 = g.hasValue(s2.getObject());\r
461                                 if (b1 == b2) {\r
462                                         if (b1) {\r
463                                                 Object v1 = g.getValue(s1.getObject());\r
464                                                 Object v2 = g.getValue(s2.getObject());\r
465                                                 boolean eq = false;\r
466                                                 if (v1 instanceof Object[] && v2 instanceof Object[])\r
467                                                         eq = Arrays.deepEquals((Object[])v1, (Object[])v2);\r
468                                                 else\r
469                                                         eq = v1.equals(v2);\r
470                                                 if (!eq) {\r
471                                                         count++;\r
472                                                 }\r
473                                                 //System.out.println("Prop count values " + v1 + " " + v2);\r
474                                         } else {\r
475                                                 count += propsDiffCount(s1.getObject(), s2.getObject());\r
476                                         }\r
477                                 } else {\r
478                                         //System.out.println("Props count structural vs literal");\r
479                                         count++;\r
480                                 }\r
481                                 i1++;\r
482                                 i2++;\r
483                                 break;\r
484                         }\r
485                         case -1:{\r
486                                 count++;\r
487                                 i1++;\r
488                                 break;\r
489                         }\r
490                                 \r
491                         case 1:{\r
492                                 count++;\r
493                                 i2++;\r
494                                 break;\r
495                         }\r
496                         }\r
497                         \r
498 \r
499                 }\r
500                 \r
501                 ss1.clear();\r
502                 ss2.clear();\r
503                 return count;\r
504         }\r
505 \r
506         \r
507         \r
508         public class StatementComparator implements Comparator<Statement> {\r
509                 @Override\r
510                 public int compare(Statement o1, Statement o2) {\r
511                         if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
512                                 return -1;\r
513                         if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())\r
514                                 return 1;\r
515                         return 0;\r
516                 }\r
517         }\r
518         \r
519 \r
520         \r
521         public class ResourceComparator implements Comparator<Resource> {\r
522                 @Override\r
523                 public int compare(Resource o1, Resource o2) {\r
524                         if (o1.getResourceId() < o2.getResourceId())\r
525                                 return -1;\r
526                         if (o2.getResourceId() > o2.getResourceId())\r
527                                 return 1;\r
528                         return 0;\r
529                 }\r
530         }\r
531 }\r