/**
   * Check to see if we have found a solution to the problem. TODO: we could throw an exception to
   * simulate a non-local exit here, since we've assumed that P is the unity set.
   *
   * @param uCls
   * @param vCls
   * @param index
   */
  protected static void checkSolution(OntClass uCls, OntClass vCls, LCAIndex index) {
    DisjointSet vSet = index.getSet(vCls);
    DisjointSet uSet = index.getSet(uCls);

    if (vSet != null
        && vSet.isBlack()
        && !vSet.used()
        && uSet != null
        && uSet.isBlack()
        && !uSet.used()) {
      vSet.setUsed();
      uSet.setUsed();
      //            log.debug( "Found LCA: u = " + uCls + ", v = " + vCls  );
      OntClass lca = (OntClass) vSet.find().getAncestor().getNode();
      //            log.debug( "Found LCA: lca = " + lca );
      index.setLCA(uCls, vCls, lca);
    }
  }
  /**
   * Compute the LCA disjoint set at <code>cls</code>, noting that we are searching for the LCA of
   * <code>uCls</code> and <code>vCls</code>.
   *
   * @param cls The class we are testing (this is 'u' in the Wiki article)
   * @param uCls One of the two classes we are searching for the LCA of. We have simplified the set
   *     P of pairs to the unity set {uCls,vCls}
   * @param vCls One of the two classes we are searching for the LCA of. We have simplified the set
   *     P of pairs to the unity set {uCls,vCls}
   * @param index A data structure mapping resources to disjoint sets (since we can't side-effect
   *     Jena resources), and which is used to record the LCA pairs
   */
  protected static DisjointSet lca(OntClass cls, OntClass uCls, OntClass vCls, LCAIndex index) {
    //        log.debug( "Entering lca(), cls = " + cls );
    DisjointSet clsSet = index.getSet(cls);
    if (clsSet.isBlack()) {
      // already visited
      return clsSet;
    }

    // not visited yet
    clsSet.setAncestor(clsSet);

    // for each child of cls
    for (Iterator<OntClass> i = cls.listSubClasses(true); i.hasNext(); ) {
      OntClass child = i.next();

      if (child.equals(cls) || child.equals(cls.getProfile().NOTHING())) {
        // we ignore the reflexive case and bottom
        continue;
      }

      // compute the LCA of the sub-tree
      DisjointSet v = lca(child, uCls, vCls, index);

      // union the two disjoint sets together
      clsSet.union(v);

      // propagate the distinguished member
      clsSet.find().setAncestor(clsSet);
    }

    // this node is done
    clsSet.setBlack();

    // are we inspecting one of the elements we're interested in?
    if (cls.equals(uCls)) {
      checkSolution(uCls, vCls, index);
    } else if (cls.equals(vCls)) {
      checkSolution(vCls, uCls, index);
    }

    return clsSet;
  }
    /**
     * The union of two sets
     *
     * @param y
     */
    public void union(DisjointSet y) {
      DisjointSet xRoot = find();
      DisjointSet yRoot = y.find();

      if (xRoot.getRank() > yRoot.getRank()) {
        yRoot.setParent(xRoot);
      } else if (yRoot.getRank() > xRoot.getRank()) {
        xRoot.setParent(yRoot);
      } else if (xRoot != yRoot) {
        yRoot.setParent(xRoot);
        xRoot.incrementRank();
      }
    }