/**
   * Determines whether variable x is independent of variable y given a list of conditioning
   * variables z.
   *
   * @param x the one variable being compared.
   * @param y the second variable being compared.
   * @param z the list of conditioning variables.
   * @return true iff x _||_ y | z.
   * @throws RuntimeException if a matrix singularity is encountered.
   */
  public boolean isIndependent(Node x, Node y, List<Node> z) {
    TetradMatrix submatrix = subMatrix(x, y, z);
    double r = 0;

    try {
      r = StatUtils.partialCorrelation(submatrix);

      if (Double.isNaN((r)) || r < -1. || r > 1.) throw new RuntimeException();
    } catch (Exception e) {
      DepthChoiceGenerator gen = new DepthChoiceGenerator(z.size(), z.size());
      int[] choice;

      while ((choice = gen.next()) != null) {
        try {
          List<Node> z2 = new ArrayList<Node>(z);
          z2.removeAll(GraphUtils.asList(choice, z));
          submatrix = subMatrix(x, y, z2);
          r = StatUtils.partialCorrelation(submatrix);
        } catch (Exception e2) {
          continue;
        }

        //                if (Double.isNaN(r)) continue;
        //
        //                if (r > 1.) r = 1.;
        //                 if (r < -1.) r = -1.;

        if (Double.isNaN(r) || r < -1. || r > 1.) continue;

        break;
      }
    }

    // Either dividing by a zero standard deviation (in which case it's dependent) or doing a
    // regression
    // (effectively) with a multicolliarity
    if (Double.isNaN(r)) {
      int[] _z = new int[z.size()];
      //            for (int i = 0; i < _z.length; i++) _z[i] = i + 2;
      //
      ////            double varx = StatUtils.partialVariance(submatrix, 0, _z); // submatrix.get(0,
      // 0);
      ////            double vary = StatUtils.partialVariance(submatrix, 1, _z); //submatrix.get(1,
      // 1);
      //
      //            double varx = submatrix.get(0, 0);
      //            double vary = submatrix.get(1, 1);
      //
      //            if (varx * vary == 0) {
      return true;
      //            }
    }

    if (r > 1.) r = 1.;
    if (r < -1.) r = -1.;

    this.fisherZ =
        Math.sqrt(sampleSize() - z.size() - 3.0) * 0.5 * (Math.log(1.0 + r) - Math.log(1.0 - r));

    if (Double.isNaN(this.fisherZ)) {
      throw new IllegalArgumentException(
          "The Fisher's Z "
              + "score for independence fact "
              + x
              + " _||_ "
              + y
              + " | "
              + z
              + " is undefined. r = "
              + r);
    }

    boolean independent = getPValue() > alpha;

    if (independent) {
      TetradLogger.getInstance()
          .log("independencies", SearchLogUtils.independenceFactMsg(x, y, z, getPValue()));
    } else {
      TetradLogger.getInstance()
          .log("dependencies", SearchLogUtils.dependenceFactMsg(x, y, z, getPValue()));
    }

    return independent;
  }