package org.simantics.graph.matching; import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.TIntHashSet; import java.util.Arrays; import java.util.Comparator; import org.simantics.databoard.binding.mutable.Variant; public enum CanonicalizingMatchingStrategy implements GraphMatchingStrategy { INSTANCE; private static class Vertex { int graph; int original; int pos; Stat[] stats; public Vertex(int graph, int original, int pos, Stat[] stats) { this.graph = graph; this.original = original; this.pos = pos; this.stats = stats; } } private static final Comparator VERTEX_COMPARATOR = new Comparator() { @Override public int compare(Vertex o1, Vertex o2) { int pos1 = o1.pos; int pos2 = o2.pos; if(pos1 < pos2) return -1; if(pos1 > pos2) return 1; Stat[] stats1 = o1.stats; Stat[] stats2 = o2.stats; if(stats1.length < stats2.length) return -1; if(stats1.length > stats2.length) return 1; for(int i=0;i o2.graph) return 1; if(o1.original < o2.original) return -1; if(o1.original > o2.original) return 1; return 0; } }; private static int[] generateMapA(int[] aToB) { int[] map = new int[aToB.length]; for(int i=0;i= 0) map[i] = -1 - c; else map[i] = 0; } return map; } private static int[] generateMapB(int[] bToA) { int[] map = new int[bToA.length]; for(int i=0;i= 0) map[i] = -1 - i; else map[i] = 0; } return map; } private static Vertex[] generateVertices(int graph, int[] map, Stat[][] statements) { int size = 0; for(int s=0;s { @Override protected boolean equals(Object one, Object two) { return Arrays.equals((byte[])one, (byte[])two); } @Override protected int hash(Object obj) { return Arrays.hashCode((byte[])obj); } } private boolean separateByValues(Vertex[] can, int begin, int end, Variant[] aValues, Variant[] bValues) { int valueCount = 0; TObjectIntHashMap valueIds = new TObjectIntHashMap(); int[] ids = new int[end-begin]; for(int i=begin;i 1) { Vertex[] vs = Arrays.copyOfRange(can, begin, end); int[] temp = new int[valueCount]; for(int id : ids) ++temp[id]; int cur = begin; for(int i=0;i 2) modified |= separateByValues(can, begin, end, aValues, bValues); } return modified; } private boolean hasBigGroups(Vertex[] can, int[] groupPos) { for(int i=0;i 2 && can[begin].graph == 0 && can[end-1].graph == 1) return true; } return false; } static class UnionFind { int[] canonical; public UnionFind(int size) { canonical = new int[size]; for(int i=0;i= 0) uf.merge(i, stat.p); if(stat.o >= 0) uf.merge(i, stat.o); } } TIntHashSet done = new TIntHashSet(); for(int i=0;i 2 && can[begin].graph == 0 && can[end-1].graph == 1) { int c = uf.canonical(begin); if(done.add(c)) { int middle = begin+1; while(can[middle].graph==0) ++middle; int j; for(j=0;begin+j < middle && middle+j < end;++j) { can[begin+j].pos = begin + j*2; can[middle+j].pos = begin + j*2; } int pos = begin+j*2; for(;begin+j < middle;++j) can[begin+j].pos = pos; for(;middle+j < end;++j) can[middle+j].pos = pos; } } } } @Override public void applyTo(GraphMatching matching) { if(matching.size == matching.aGraph.resourceCount || matching.size == matching.bGraph.resourceCount) return; long begin1 = System.nanoTime(); int[] aMap = generateMapA(matching.aToB); int[] bMap = generateMapB(matching.bToA); Vertex[] aVertices = generateVertices(0, aMap, matching.aGraph.statements); Vertex[] bVertices = generateVertices(1, bMap, matching.bGraph.statements); Vertex[] can = concat(aVertices, bVertices); if(GraphMatching.TIMING) System.out.println(" Init: " + (System.nanoTime()-begin1)*1e-6 + "ms"); int[] groupPos = null; boolean doneSeparationByValues = false; while(true) { long begin2 = System.nanoTime(); Arrays.sort(can, VERTEX_COMPARATOR); if(GraphMatching.TIMING) System.out.println(" Sort: " + (System.nanoTime()-begin2)*1e-6 + "ms"); long begin3 = System.nanoTime(); if(!updatePositions(can)) { groupPos = groupPositions(can); if(!hasBigGroups(can, groupPos)) break; boolean modified = false; if(!doneSeparationByValues) { modified = separateByValues(can, groupPos, matching.aGraph.values, matching.bGraph.values); doneSeparationByValues = true; if(GraphMatching.TIMING) System.out.println(" - separate by values"); } if(!modified) { guessIsomorphism(can, groupPos); if(GraphMatching.TIMING) System.out.println(" - guess isomorphism"); } } if(GraphMatching.TIMING) System.out.println(" Update1: " + (System.nanoTime()-begin3)*1e-6 + "ms"); long begin4 = System.nanoTime(); updateMap(aVertices, aMap); updateMap(bVertices, bMap); if(GraphMatching.TIMING) System.out.println(" Update2: " + (System.nanoTime()-begin4)*1e-6 + "ms"); long begin5 = System.nanoTime(); updateVertices(aVertices, aMap, matching.aGraph.statements); updateVertices(bVertices, bMap, matching.bGraph.statements); if(GraphMatching.TIMING) System.out.println(" Update3: " + (System.nanoTime()-begin5)*1e-6 + "ms"); } for(int i=0;i 2) { System.out.println("----"); for(int j=begin;j