]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.graph/src/org/simantics/graph/matching/ComponentMatchingStrategy.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.graph / src / org / simantics / graph / matching / ComponentMatchingStrategy.java
diff --git a/bundles/org.simantics.graph/src/org/simantics/graph/matching/ComponentMatchingStrategy.java b/bundles/org.simantics.graph/src/org/simantics/graph/matching/ComponentMatchingStrategy.java
new file mode 100644 (file)
index 0000000..ef354a1
--- /dev/null
@@ -0,0 +1,309 @@
+package org.simantics.graph.matching;\r
+\r
+import gnu.trove.list.array.TIntArrayList;\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.map.hash.TIntIntHashMap;\r
+import gnu.trove.map.hash.TIntObjectHashMap;\r
+import gnu.trove.procedure.TObjectProcedure;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Comparator;\r
+\r
+/**\r
+ * Matches isomorphic components of the not yet matched graphs together.\r
+ * \r
+ * @author Hannu Niemistö\r
+ */\r
+public enum ComponentMatchingStrategy implements GraphMatchingStrategy {\r
+       INSTANCE;\r
+\r
+       static class UnionFind {\r
+               int[] canonical;\r
+               \r
+               public UnionFind(int size) {\r
+                       canonical = new int[size];\r
+                       for(int i=0;i<size;++i)\r
+                               canonical[i] = i;\r
+               }\r
+               \r
+               public int canonical(int a) {\r
+                       int b = canonical[a];\r
+                       if(b != a) {\r
+                               int c = canonical[b];\r
+                               if(b != c) {\r
+                                       c = canonical(c);\r
+                                       canonical[b] = c;                                       \r
+                                       canonical[a] = c;\r
+                                       return c;\r
+                               }\r
+                       }\r
+                       return b;\r
+               }\r
+               \r
+               public void merge(int a, int b) {\r
+                       a = canonical(a);\r
+                       b = canonical(b);\r
+                       canonical[a] = b;\r
+               }\r
+       }\r
+       \r
+       public static int[][] findComponents(int[] map, Stat[][] statements, TIntIntHashMap inverses) {\r
+               int resourceCount = map.length;\r
+               \r
+               UnionFind uf = new UnionFind(resourceCount);\r
+               for(int s=0;s<resourceCount;++s)\r
+                       if(map[s] < 0) {\r
+                               for(Stat stat : statements[s]) {\r
+                                       int o = stat.o;\r
+                                       if(s < o && map[o] < 0)\r
+                                               uf.merge(s, o);\r
+                               }\r
+                               /*if(inverses.containsKey(s))\r
+                                       uf.merge(s, inverses.get(s));\r
+                                       */\r
+                       }\r
+               \r
+               TIntObjectHashMap<TIntArrayList> components = new TIntObjectHashMap<TIntArrayList>();\r
+               for(int i=0;i<resourceCount;++i)\r
+                       if(map[i] < 0) {\r
+                               int c = uf.canonical(i);\r
+                               TIntArrayList els = components.get(c);\r
+                               if(els == null) {\r
+                                       els = new TIntArrayList(2);\r
+                                       components.put(c, els);\r
+                               }\r
+                               els.add(i);\r
+                       }\r
+               \r
+               final int[][] result = new int[components.size()][];\r
+               components.forEachValue(new TObjectProcedure<TIntArrayList>() {\r
+                       int i = 0;\r
+                       @Override\r
+                       public boolean execute(TIntArrayList els) {\r
+                               result[i++] = els.toArray();\r
+                               return true;\r
+                       }\r
+               });\r
+               return result;\r
+       }       \r
+       \r
+       public static Stat[][] neighbors(int[] map, Stat[][] statements) {\r
+               int resourceCount = map.length;\r
+               Stat[][] neighbors = new Stat[resourceCount][];\r
+               \r
+               ArrayList<Stat> stats = new ArrayList<Stat>();\r
+               for(int s=0;s<resourceCount;++s) {\r
+                       if(map[s] >= 0) {\r
+                               neighbors[s] = Stat.NO_STATS;\r
+                               continue;\r
+                       }\r
+                       \r
+                       for(Stat stat : statements[s]) {\r
+                               int pp = map[stat.p] >= 0 ? stat.p : -1;\r
+                               int oo = map[stat.o] >= 0 ? stat.o : -1;                                \r
+                               stats.add(new Stat(pp, oo));\r
+                       }\r
+                       \r
+                       if(stats.isEmpty())\r
+                               neighbors[s] = Stat.NO_STATS;\r
+                       else {\r
+                               neighbors[s] = stats.toArray(new Stat[stats.size()]);\r
+                               stats.clear();\r
+                       }\r
+               }\r
+               \r
+               return neighbors;\r
+       }\r
+       \r
+       static class Component {\r
+               int[] elements;\r
+               Stat[][] neighbors;\r
+               \r
+               public Component(int[] elements, Stat[][] neighbors) {\r
+                       this.elements = elements;\r
+                       this.neighbors = new Stat[elements.length][];\r
+                       for(int i=0;i<elements.length;++i)\r
+                               this.neighbors[i] = neighbors[elements[i]];\r
+               }\r
+               \r
+               public void map(int[] map) {\r
+                       for(Stat[] stats : neighbors)\r
+                               for(Stat stat : stats)\r
+                                       stat.map(map);\r
+               }\r
+               \r
+               static class PP {\r
+                       int element;\r
+                       Stat[] stats;\r
+                       \r
+                       public PP(int element, Stat[] stats) {\r
+                               this.element = element;\r
+                               Arrays.sort(stats, Stat.STAT_COMPARATOR);\r
+                               this.stats = stats;\r
+                       }\r
+               }\r
+               \r
+               static final Comparator<PP> PP_COMPARATOR = new Comparator<PP>() {\r
+                       @Override\r
+                       public int compare(PP o1, PP o2) {\r
+                               Stat[] stats1 = o1.stats;\r
+                               Stat[] stats2 = o2.stats;\r
+                               int l1 = stats1.length;\r
+                               int l2 = stats2.length;\r
+                               if(l1 < l2)\r
+                                       return -1;\r
+                               else if(l1 > l2)\r
+                                       return 1;\r
+                               for(int i=0;i<l1;++i) {\r
+                                       Stat s1 = stats1[i];\r
+                                       Stat s2 = stats2[i];\r
+                                       if(s1.p < s2.p)\r
+                                               return -1;\r
+                                       else if(s1.p > s2.p)\r
+                                               return 1;\r
+                                       else if(s1.o < s2.o)\r
+                                               return -1;\r
+                                       else if(s1.o > s2.o)\r
+                                               return 1;\r
+                               }\r
+                               return 0;\r
+                       }                       \r
+               };\r
+               \r
+               public void canonicalize(String[] elNames, String[] statNames) {\r
+                       PP[] pps = new PP[elements.length];\r
+                       for(int i=0;i<elements.length;++i)\r
+                               pps[i] = new PP(elements[i], neighbors[i]);\r
+                       Arrays.sort(pps, PP_COMPARATOR);\r
+                       for(int i=0;i<pps.length-1;++i)\r
+                               if(PP_COMPARATOR.compare(pps[i], pps[i+1]) == 0) {\r
+                                       System.out.println("AMB " + pps.length + " " + (elNames==statNames));\r
+                                       for(i=0;i<pps.length-1;++i) {\r
+                                               if(PP_COMPARATOR.compare(pps[i], pps[i+1]) == 0)\r
+                                                       System.out.print(">   ");\r
+                                               else\r
+                                                       System.out.print("    ");\r
+                                               System.out.println(elNames[pps[i].element]);\r
+                                               for(Stat stat : pps[i].stats)\r
+                                                       System.out.println("        " + stat.toString(statNames));\r
+                                       }\r
+                                       break;\r
+                               }\r
+                       for(int i=0;i<elements.length;++i) {\r
+                               PP pp = pps[i];\r
+                               elements[i] = pp.element;\r
+                               neighbors[i] = pp.stats;\r
+                       }\r
+               }\r
+\r
+               public boolean isIsolated() {\r
+                       for(Stat[] stats : neighbors)\r
+                               if(stats.length > 0)\r
+                                       return false;\r
+                       return true;\r
+               }\r
+       }\r
+       \r
+       static class TNeighbourObjectHashMap<T> extends THashMap<Stat[][], T> {\r
+               @Override\r
+               protected boolean equals(Object one, Object two) {\r
+                       Stat[][] o1 = (Stat[][])one;\r
+                       Stat[][] o2 = (Stat[][])two;\r
+                       if(o1.length != o2.length)\r
+                               return false;\r
+                       for(int i=0;i<o1.length;++i) {\r
+                               Stat[] ss1 = o1[i];\r
+                               Stat[] ss2 = o2[i];\r
+                               if(ss1.length != ss2.length)\r
+                                       return false;\r
+                               for(int j=0;j<ss1.length;++j) {\r
+                                       Stat s1 = ss1[j];\r
+                                       Stat s2 = ss2[j];\r
+                                       if(s1.p != s2.p || s1.o != s2.o)\r
+                                               return false;\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+               \r
+               @Override\r
+               protected int hash(Object obj) {\r
+                       int result = 152433;\r
+                       for(Stat[] stats : (Stat[][])obj)\r
+                               for(Stat stat : stats)\r
+                                       result = (result*31 + stat.p)*31 + stat.o;\r
+                       return result;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void applyTo(GraphMatching matching) {\r
+               System.out.println("ComponentMatchingStrategy");\r
+               TNeighbourObjectHashMap<ArrayList<int[]>> aComponents = new TNeighbourObjectHashMap<ArrayList<int[]>>(); \r
+               {                       \r
+                       Stat[][] neighbors = neighbors(matching.aToB, matching.aGraph.statements);\r
+                       //TIntIntHashMap componentSizes = new TIntIntHashMap();\r
+                       for(int[] els : findComponents(matching.aToB, matching.aGraph.statements, matching.aGraph.inverses)) {\r
+                               /*for(int el : els)\r
+                                       System.out.print(matching.aGraph.names[el] + " ");\r
+                               System.out.println();\r
+                               componentSizes.adjustOrPutValue(els.length, 1, 1);*/\r
+                               Component component = new Component(els, neighbors);\r
+                               if(component.isIsolated())\r
+                                       continue;\r
+                               component.map(matching.aToB);\r
+                               component.canonicalize(matching.aGraph.names, matching.bGraph.names);\r
+                               ArrayList<int[]> values = aComponents.get(component.neighbors);\r
+                               if(values == null) {\r
+                                       values = new ArrayList<int[]>(1);\r
+                                       aComponents.put(component.neighbors, values);\r
+                               }\r
+                               values.add(component.elements);\r
+                       }\r
+                       /*componentSizes.forEachEntry(new TIntIntProcedure() {                          \r
+                               @Override\r
+                               public boolean execute(int a, int b) {\r
+                                       System.out.println("Components of size " + a + ": " + b);\r
+                                       return true;\r
+                               }\r
+                       });*/\r
+               }\r
+               \r
+               ArrayList<Component> bComponents = new ArrayList<Component>(); \r
+               {\r
+                       Stat[][] neighbors = neighbors(matching.bToA, matching.bGraph.statements);\r
+                       for(int[] els : findComponents(matching.bToA, matching.bGraph.statements, matching.bGraph.inverses)) {\r
+                               Component component = new Component(els, neighbors);\r
+                               if(component.isIsolated())\r
+                                       continue;\r
+                               component.canonicalize(matching.bGraph.names, matching.bGraph.names);\r
+                               bComponents.add(component);\r
+                       }\r
+               }\r
+               \r
+               for(Component c : bComponents) {\r
+                       ArrayList<int[]> candidates = aComponents.get(c.neighbors);\r
+                       if(candidates != null)\r
+                               for(int i=0;i<candidates.size();++i) {\r
+                                       int[] els = candidates.get(i);\r
+                                       if(els != null) {\r
+                                               matching.map(els, c.elements);\r
+                                               if(matching.checkMatch(els, c.elements)) {\r
+                                                       if(candidates.size() == 1)\r
+                                                               aComponents.remove(c.neighbors);\r
+                                                       else {\r
+                                                               int last = candidates.size()-1;\r
+                                                               int[] temp = candidates.remove(last);\r
+                                                               if(i < last)\r
+                                                                       candidates.set(i, temp);\r
+                                                       }\r
+                                                   break;\r
+                                               }\r
+                                               else\r
+                                                       matching.unmap(els, c.elements);\r
+                                       }       \r
+                               }                       \r
+               }\r
+       }\r
+}\r