code: @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[targetComponents[targetComponents.length-1]+1];
          int[] usedIn = new int[queryComponents[queryComponents.length-1] + 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;
      }
docs: 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