/**
   * Splits recursively the points of the graph while the value of the best cut found is less of a
   * specified limit (the alpha star factor).
   *
   * @param W the weight matrix of the graph
   * @param alpha_star the alpha star factor
   * @return an array of sets of points (partitions)
   */
  protected int[][] partition(DoubleMatrix2D W, double alpha_star) {
    numPartitions++;

    // System.out.println("!");

    // If the graph contains only one point
    if (W.columns() == 1) {
      int[][] p = new int[1][1];
      p[0][0] = 0;
      return p;
      // Otherwise
    } else {
      // Computes the best cut
      int[][] cut = bestCut(W);
      // Computes the value of the found cut
      double cutVal = Ncut(W, cut[0], cut[1], null);

      // System.out.println("cutVal = "+cutVal +"\tnumPartitions = "+numPartitions);

      // If the value is less than alpha star
      if (cutVal < alpha_star && numPartitions < 2) {

        // Recursively partitions the first one found ...
        DoubleMatrix2D W0 = W.viewSelection(cut[0], cut[0]);
        int[][] p0 = partition(W0, alpha_star);
        // ... and the second one
        DoubleMatrix2D W1 = W.viewSelection(cut[1], cut[1]);
        int[][] p1 = partition(W1, alpha_star);

        // Merges the partitions found in the previous recursive steps
        int[][] p = new int[p0.length + p1.length][];
        for (int i = 0; i < p0.length; i++) {
          p[i] = new int[p0[i].length];
          for (int j = 0; j < p0[i].length; j++) p[i][j] = cut[0][p0[i][j]];
        }

        for (int i = 0; i < p1.length; i++) {
          p[i + p0.length] = new int[p1[i].length];
          for (int j = 0; j < p1[i].length; j++) p[i + p0.length][j] = cut[1][p1[i][j]];
        }

        return p;
      } else {
        // Otherwise returns the partitions found in current step
        // w/o recursive invocation
        int[][] p = new int[1][W.columns()];
        for (int i = 0; i < p[0].length; i++) p[0][i] = i;
        return p;
      }
    }
  }
 /**
  * Computes the association degree between two partitions of a graph.<br>
  * The association degree is defined as the sum of the weights of all the edges between points of
  * the two partitions.
  *
  * @param W the weight matrix of the graph
  * @param a the points of the first partition
  * @param b the points of the second partition
  * @return the association degree
  */
 protected static double asso(DoubleMatrix2D W, int[] a, int[] b) {
   return W.viewSelection(a, b).zSum();
 }