/** * Does the mapping respected the component grouping specified by the query. * * @param mapping a permutation of the query vertices * @return the mapping preserves the specified grouping */ @Override public boolean apply(final int[] mapping) { // no grouping required if (queryComponents == null) return true; // bidirectional map of query/target components, last index // of query components holds the count int[] usedBy = new int[cc.nComponents() + 1]; int[] usedIn = new int[queryComponents[mapping.length] + 1]; // verify we don't have any collisions for (int v = 0; v < mapping.length; v++) { if (queryComponents[v] == 0) continue; int w = mapping[v]; int queryComponent = queryComponents[v]; int targetComponent = targetComponents[w]; // is the target component already used by a query component? if (usedBy[targetComponent] == 0) usedBy[targetComponent] = queryComponent; else if (usedBy[targetComponent] != queryComponent) return false; // is the query component already used in a target component? if (usedIn[queryComponent] == 0) usedIn[queryComponent] = targetComponent; else if (usedIn[queryComponent] != targetComponent) return false; } return true; }
/** * Create a predicate to match components for the provided query (grouping) and target (connected * components). * * @param grouping query grouping * @param cc connected component of the target */ public ComponentGrouping(int[] grouping, ConnectedComponents cc) { this.queryComponents = grouping; this.cc = cc; this.targetComponents = cc != null ? cc.components() : null; }