示例#1
0
 /**
  * Return the upper bounds for the problem. If the original upper bounds are null, the they are
  * set to the value of <i>maxUBValue</i>. Otherwise, any upper bound is limited to the value of
  * <i>maxUBValue</i>
  */
 @Override
 protected DoubleMatrix1D getUb() {
   if (this.limitedUb == null) {
     if (super.getUb() == null) {
       this.limitedUb = F1.make(getC().size(), maxUBValue);
     } else {
       this.limitedUb = F1.make(super.getUb().size());
       for (int i = 0; i < super.getUb().size(); i++) {
         double ubi = super.getUb().getQuick(i);
         if (maxUBValue < ubi) {
           log.warn(
               "the "
                   + i
                   + "-th upper bound was limited form "
                   + ubi
                   + " to the value of maxUBValue: "
                   + maxUBValue);
           limitedUb.setQuick(i, maxUBValue);
         } else {
           limitedUb.setQuick(i, ubi);
         }
       }
     }
   }
   return limitedUb;
 }
示例#2
0
 /**
  * Return the lower bounds for the problem. If the original lower bounds are null, the they are
  * set to the value of <i>minLBValue</i>. Otherwise, any lower bound is limited to the value of
  * <i>minLBValue</i>
  */
 @Override
 protected DoubleMatrix1D getLb() {
   if (this.limitedLb == null) {
     if (super.getLb() == null) {
       this.limitedLb = F1.make(getC().size(), minLBValue);
     } else {
       this.limitedLb = F1.make(super.getLb().size());
       for (int i = 0; i < super.getLb().size(); i++) {
         double lbi = super.getLb().getQuick(i);
         if (lbi < minLBValue) {
           log.warn(
               "the "
                   + i
                   + "-th lower bound was limited form "
                   + lbi
                   + " to the value of minLBValue: "
                   + minLBValue);
           limitedLb.setQuick(i, minLBValue);
         } else {
           limitedLb.setQuick(i, lbi);
         }
       }
     }
   }
   return limitedLb;
 }
  private double multiLL(DoubleMatrix2D coeffs, Node dep, List<Node> indep) {

    DoubleMatrix2D indepData =
        factory2D.make(internalData.subsetColumns(indep).getDoubleData().toArray());
    List<Node> depList = new ArrayList<>();
    depList.add(dep);
    DoubleMatrix2D depData =
        factory2D.make(internalData.subsetColumns(depList).getDoubleData().toArray());

    int N = indepData.rows();
    DoubleMatrix2D probs =
        Algebra.DEFAULT.mult(factory2D.appendColumns(factory2D.make(N, 1, 1.0), indepData), coeffs);

    probs =
        factory2D
            .appendColumns(factory2D.make(indepData.rows(), 1, 1.0), probs)
            .assign(Functions.exp);
    double ll = 0;
    for (int i = 0; i < N; i++) {
      DoubleMatrix1D curRow = probs.viewRow(i);
      curRow.assign(Functions.div(curRow.zSum()));
      ll += Math.log(curRow.get((int) depData.get(i, 0)));
    }
    return ll;
  }
示例#4
0
  public double getNearestInRangeDOFVal(
      double startVal, double min, double max, DoubleMatrix1D x, int dof, int[] indices) {
    // Return the nearest value of DOF #dof in x to startVal that will make this GenCoord (operating
    // on
    // the given indices of x) return a value in the range[min,max]
    // If there is no such value, NaN is returned
    switch (type) {
      case REGULAR:
        if (startVal < min) return min;
        else if (startVal > max) return max;
        else // startVal is in range already
        return startVal;

      case SUMSQ:
        double sum = 0;
        for (int q : indices) sum += Math.pow(x.get(q), 2);
        double minsq = Math.pow(min, 2);
        if (sum
            < minsq) { // Increase the absolute value of x.get(dof) until it makes sum equal to
                       // min^2
          double absAns = Math.sqrt(Math.pow(min, 2) - (sum - Math.pow(startVal, 2)));
          if (startVal > 0) return absAns;
          else return -absAns;
        }
        double maxsq = Math.pow(max, 2);
        if (sum
            > maxsq) { // Decrease the absolute value of x.get(dof) until it makes sum equal to
                       // min^2
          double absAns = Math.sqrt(Math.pow(max, 2) - (sum - Math.pow(startVal, 2)));
          if (startVal > 0) return absAns;
          else return -absAns;
        } else // In range already
        return startVal;

      case LINCOMB:
        double ans = 0;
        int DOFLocalInd = -1; // Index of dof in the "indices" array
        for (int a = 0; a < coeffs.length; a++) {
          if (indices[a] == dof) {
            ans += coeffs[a] * startVal;
            DOFLocalInd = a;
          } else ans += coeffs[a] * x.get(indices[a]);
        }
        if (ans < min) {
          if (coeffs[DOFLocalInd] == 0) return Double.NaN;
          return startVal + (min - ans) / coeffs[DOFLocalInd];
        } else if (ans > max) {
          if (coeffs[DOFLocalInd] == 0) return Double.NaN;
          return startVal + (max - ans) / coeffs[DOFLocalInd];
        } else // In range already
        return startVal;

      default:
        System.err.println("ERROR: Unrecognized generalized coordinate type: " + type);
        System.exit(1);
        return 0;
    }
  }
 public static DoubleMatrix2D[][] modelEffectsToxty(ModelEffect[] mes, double[] data) {
   int dim = mes.length;
   DoubleMatrix2D[][] xty = new DoubleMatrix2D[dim][1];
   for (int i = 0; i < dim; i++) {
     DoubleMatrix1D dm = mes[i].getXTy(data);
     xty[i][0] = DoubleFactory2D.dense.make(dm.toArray(), dm.size());
   }
   return xty;
 }
示例#6
0
 /**
  * Inequality functions values at X. This is (-x+lb) for all bounded lb and (x-ub) for all bounded
  * ub.
  */
 @Override
 protected DoubleMatrix1D getFi(DoubleMatrix1D X) {
   double[] ret = new double[getMieq()];
   for (int i = 0; i < getDim(); i++) {
     ret[i] = -X.getQuick(i) + getLb().getQuick(i);
     ret[getDim() + i] = X.getQuick(i) - getUb().getQuick(i);
   }
   return F1.make(ret);
 }
示例#7
0
  /** Computes the term Grad[fi].stepX */
  protected DoubleMatrix1D gradFiStepX(DoubleMatrix1D stepX) {

    DoubleMatrix1D ret = F1.make(getMieq());
    for (int i = 0; i < getDim(); i++) {
      ret.setQuick(i, -stepX.getQuick(i));
      ret.setQuick(getDim() + i, stepX.getQuick(i));
    }

    return ret;
  }
示例#8
0
 /**
  * Calculates the second term of the first row of (11.55) "Convex Optimization".
  *
  * @see "Convex Optimization, 11.55"
  */
 protected DoubleMatrix1D gradSum(double t, DoubleMatrix1D fiX) {
   DoubleMatrix1D gradSum = F1.make(getDim());
   for (int i = 0; i < dim; i++) {
     double d = 0;
     d += 1. / (t * fiX.getQuick(i));
     d += -1. / (t * fiX.getQuick(getDim() + i));
     gradSum.setQuick(i, d);
   }
   return gradSum;
 }
示例#9
0
  @Test
  public void testInclinedPlane() throws IOException {
    DoubleMatrix1D normal = new DenseDoubleMatrix1D(3);
    normal.assign(new double[] {.0, .0, 1.0});

    InclinedPlane3D inclinedPlane = new InclinedPlane3D();
    inclinedPlane.setRandomGenerator(new MersenneTwister(123456789));
    inclinedPlane.setNormal(normal);
    inclinedPlane.setBounds(new Rectangle(-5, -5, 10, 10));
    inclinedPlane.setNoiseStd(0.5);
    DoubleMatrix2D data = inclinedPlane.generate(10);

    SVDPCA pca = new SVDPCA(data);

    System.out.println("Eigenvalues:");
    System.out.println(pca.getEigenvalues());

    System.out.println("Eigenvectors:");
    System.out.println(pca.getEigenvectors());

    System.out.println("Meanvector:");
    System.out.println(pca.getMean());

    // Recalculate the input from a truncated SVD, first calculate the mean
    DoubleMatrix1D mean = new SparseDoubleMatrix1D(3);
    for (int i = 0; i < data.rows(); ++i) {
      mean.assign(data.viewRow(i), Functions.plus);
    }
    mean.assign(Functions.div(data.rows()));

    // Truncate the SVD and calculate the coefficient matrix
    DenseDoubleMatrix2D coefficients = new DenseDoubleMatrix2D(data.rows(), 2);
    DoubleMatrix2D centeredInput = data.copy();
    for (int i = 0; i < data.rows(); ++i) {
      centeredInput.viewRow(i).assign(mean, Functions.minus);
    }
    centeredInput.zMult(
        pca.getEigenvectors().viewPart(0, 0, 2, 3), coefficients, 1, 0, false, true);

    // Reconstruct the data from the lower dimensional information
    DoubleMatrix2D reconstruction = data.copy();
    for (int i = 0; i < reconstruction.rows(); ++i) {
      reconstruction.viewRow(i).assign(mean);
    }
    coefficients.zMult(
        pca.getEigenvectors().viewPart(0, 0, 2, 3), reconstruction, 1, 1, false, false);

    // Output to file (can be read by GNU Plot)
    String fileName = "inclined-plane-svd-pca.dat";
    String packagePath = this.getClass().getPackage().getName().replaceAll("\\.", "/");
    File outputFile = new File("src/test/resources/" + packagePath + "/" + fileName);
    PrintWriter writer = new PrintWriter(outputFile);
    writer.write(data.toString());
    writer.close();
  }
示例#10
0
 /** @see "Convex Optimization, p. 610" */
 protected DoubleMatrix1D rDual(DoubleMatrix1D gradF0X, DoubleMatrix1D L, DoubleMatrix1D V) {
   // m1 = GradFiX[T].L + gradF0X
   DoubleMatrix1D m1 = F1.make(getDim());
   for (int i = 0; i < getDim(); i++) {
     double m = 0;
     m += -L.getQuick(i);
     m += L.getQuick(getDim() + i);
     m1.setQuick(i, m + gradF0X.get(i));
   }
   if (getMeq() == 0) {
     return m1;
   }
   return ColtUtils.zMultTranspose(getA(), V, m1, 1.);
 }
示例#11
0
  /**
   * Return the H matrix (that is diagonal). This is the third addendum of (11.56) of "Convex
   * Optimization".
   *
   * @see "Convex Optimization, 11.56"
   */
  protected DoubleMatrix2D GradLSum(DoubleMatrix1D L, DoubleMatrix1D fiX) {
    // DoubleMatrix2D GradLSum = F2.make(1, getDim());
    SparseDoubleMatrix2D GradLSum =
        new SparseDoubleMatrix2D(getDim(), getDim(), getDim(), 0.001, 0.01);
    for (int i = 0; i < getDim(); i++) {
      double d = 0;
      d -= L.getQuick(i) / fiX.getQuick(i);
      d -= L.getQuick(getDim() + i) / fiX.getQuick(getDim() + i);
      // GradLSum.setQuick(0, i, d);
      GradLSum.setQuick(i, i, d);
    }

    return GradLSum;
  }
示例#12
0
  public static DoubleMatrix1D normalizeVector(DoubleMatrix1D vector) {
    ArrayList<Double> vl = new ArrayList<Double>();

    for (int i = 0; i < vector.size(); i++) {
      vl.add(Math.pow(vector.get(i), 2));
    }

    vl = normalizeVector(vl);

    DoubleMatrix1D rt = DoubleFactory1D.sparse.make(vl.size());

    for (int i = 0; i < vector.size(); i++) {
      rt.set(i, vl.get(i));
    }

    return rt;
  }
示例#13
0
  /**
   * Feature-specific contribution to the prediction of the value of an instance.
   *
   * @param x instance
   * @param i index of the feature of interest
   * @param xi value of the feature of interest
   * @return value of the contribution of the feature to the prediction
   */
  public double prediction(I x, int i, double xi) {
    double wi = w.getQuick(i);
    DoubleMatrix1D mi = m.viewRow(i);

    double pred = 0.0;

    pred += xi * wi;

    pred +=
        x.operate(
            (j, xj) -> {
              DoubleMatrix1D mj = m.viewRow(j);

              return xi * xj * mi.zDotProduct(mj);
            },
            (v1, v2) -> v1 + v2);

    return pred;
  }
示例#14
0
 private static void saveDenseDoubleMatrix1D(OutputStream stream, DoubleMatrix1D vector)
     throws IOException {
   BufferedWriter out = new BufferedWriter(new OutputStreamWriter(stream));
   double[] v = vector.toArray();
   for (int j = 0; j < v.length; j++) {
     out.write(Double.toString(v[j]));
     out.newLine();
   }
   out.flush();
 }
示例#15
0
  public double eval(DoubleMatrix1D x, int[] indices) {
    // The "regular" coordinates to be used have the indicated indices in x

    switch (type) {
      case REGULAR:
        return x.get(indices[0]);
      case SUMSQ:
        double sum = 0;
        for (int q : indices) sum += Math.pow(x.get(q), 2);
        return Math.sqrt(sum);
      case LINCOMB:
        double ans = 0;
        for (int a = 0; a < coeffs.length; a++) ans += coeffs[a] * x.get(indices[a]);
        return ans;
      default:
        System.err.println("ERROR: Unrecognized generalized coordinate type: " + type);
        System.exit(1);
        return 0;
    }
  }
示例#16
0
    public double apply(int first, int second, double third) {

      if (first == second) {
        return third;
      }

      //            System.out.println("checking = " + min_val + " versus " +
      // (third/count_matrix.getQuick(first,second)));
      double d_q =
          2
              * (third / m_total_distances
                  - (a_matrix.getQuick(first) * a_matrix.getQuick(second))
                      / (m_total_distances * m_total_distances));
      if (d_q > max_q) {
        min_m = first;
        min_n = second;
        max_q = d_q;
      }

      return third;
    }
示例#17
0
 /** @see "Convex Optimization, p. 610" */
 private DoubleMatrix1D rCent(DoubleMatrix1D fiX, DoubleMatrix1D L, double t) {
   DoubleMatrix1D ret = F1.make(L.size());
   for (int i = 0; i < ret.size(); i++) {
     ret.setQuick(i, -L.getQuick(i) * fiX.getQuick(i) - 1. / t);
   }
   return ret;
 }
示例#18
0
  private static double[] solution(DoubleMatrix2D X, DoubleMatrix2D Y, int k) {
    // Solve X * Beta = Y for Beta
    // Only the first column of Y is used
    // k is number of beta coefficients

    QRDecomposition qr = new QRDecomposition(X);

    if (qr.hasFullRank()) {
      DoubleMatrix2D B = qr.solve(Y);
      return B.viewColumn(0).toArray();

    } else {
      DoubleMatrix1D Y0 = Y.viewColumn(0); // first column of Y
      SingularValueDecomposition svd = new SingularValueDecomposition(X);
      DoubleMatrix2D S = svd.getS();
      DoubleMatrix2D V = svd.getV();
      DoubleMatrix2D U = svd.getU();
      Algebra alg = new Algebra();
      DoubleMatrix2D Ut = alg.transpose(U);
      DoubleMatrix1D g = alg.mult(Ut, Y0); // Ut*Y0

      for (int j = 0; j < k; j++) {
        // solve S*p = g for p;  S is a diagonal matrix
        double x = S.getQuick(j, j);
        if (x > 0.) {
          x = g.getQuick(j) / x; // p[j] = g[j]/S[j]
          g.setQuick(j, x); // overwrite g by p
        } else g.setQuick(j, 0.);
      }
      DoubleMatrix1D beta = alg.mult(V, g); // V*p
      return beta.toArray();
    }
  }
示例#19
0
  static boolean computeLogMi(
      FeatureGenerator featureGen,
      double lambda[],
      DoubleMatrix2D Mi_YY,
      DoubleMatrix1D Ri_Y,
      boolean takeExp,
      boolean reuseM,
      boolean initMDone) {

    if (reuseM && initMDone) {
      Mi_YY = null;
    } else initMDone = false;
    if (Mi_YY != null) Mi_YY.assign(0);
    Ri_Y.assign(0);
    while (featureGen.hasNext()) {
      Feature feature = featureGen.next();
      int f = feature.index();
      int yp = feature.y();
      int yprev = feature.yprev();
      float val = feature.value();
      //	    System.out.println(feature.toString());

      if (yprev < 0) {
        // this is a single state feature.
        double oldVal = Ri_Y.getQuick(yp);
        Ri_Y.setQuick(yp, oldVal + lambda[f] * val);
      } else if (Mi_YY != null) {
        Mi_YY.setQuick(yprev, yp, Mi_YY.getQuick(yprev, yp) + lambda[f] * val);
        initMDone = true;
      }
    }
    if (takeExp) {
      for (int r = Ri_Y.size() - 1; r >= 0; r--) {
        Ri_Y.setQuick(r, expE(Ri_Y.getQuick(r)));
        if (Mi_YY != null)
          for (int c = Mi_YY.columns() - 1; c >= 0; c--) {
            Mi_YY.setQuick(r, c, expE(Mi_YY.getQuick(r, c)));
          }
      }
    }
    return initMDone;
  }
示例#20
0
  /**
   * Predict the value of an instance.
   *
   * @param x instance
   * @return value of prediction
   */
  public double prediction(I x) {
    double pred = b;

    DoubleMatrix1D xm = new DenseDoubleMatrix1D(m.columns());
    pred +=
        x.operate(
            (i, xi) -> {
              double wi = w.getQuick(i);
              DoubleMatrix1D mi = m.viewRow(i);

              xm.assign(mi, (r, s) -> r + xi * s);

              return xi * wi - 0.5 * xi * xi * mi.zDotProduct(mi);
            },
            (v1, v2) -> v1 + v2);

    pred += 0.5 * xm.zDotProduct(xm);

    return pred;
  }
 public void decrementDisp(double x, double y) {
   disp.set(0, disp.get(0) - x);
   disp.set(1, disp.get(1) - y);
 }
 public void incrementDisp(double x, double y) {
   disp.set(0, disp.get(0) + x);
   disp.set(1, disp.get(1) + y);
 }
 public void setDisp(double x, double y) {
   disp.set(0, x);
   disp.set(1, y);
 }
 public double getYDisp() {
   return disp.get(1);
 }
 public double getXDisp() {
   return disp.get(0);
 }
  /**
   * Returns the best cut of a graph w.r.t. the degree of dissimilarity between points of different
   * partitions and the degree of similarity between points of the same partition.
   *
   * @param W the weight matrix of the graph
   * @return an array of two elements, each of these contains the points of a partition
   */
  protected static int[][] bestCut(DoubleMatrix2D W) {
    int n = W.columns();
    // Builds the diagonal matrices D and D^(-1/2) (represented as their diagonals)
    DoubleMatrix1D d = DoubleFactory1D.dense.make(n);
    DoubleMatrix1D d_minus_1_2 = DoubleFactory1D.dense.make(n);
    for (int i = 0; i < n; i++) {
      double d_i = W.viewRow(i).zSum();
      d.set(i, d_i);
      d_minus_1_2.set(i, 1 / Math.sqrt(d_i));
    }
    DoubleMatrix2D D = DoubleFactory2D.sparse.diagonal(d);

    // System.out.println("DoubleMatrix2D :\n"+D.toString());

    DoubleMatrix2D X = D.copy();

    // System.out.println("DoubleMatrix2D copy :\n"+X.toString());

    // X = D^(-1/2) * (D - W) * D^(-1/2)
    X.assign(W, Functions.minus);
    // System.out.println("DoubleMatrix2D X: (D-W) :\n"+X.toString());
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        X.set(i, j, X.get(i, j) * d_minus_1_2.get(i) * d_minus_1_2.get(j));

    // Computes the eigenvalues and the eigenvectors of X
    EigenvalueDecomposition e = new EigenvalueDecomposition(X);
    DoubleMatrix1D lambda = e.getRealEigenvalues();

    // Selects the eigenvector z_2 associated with the second smallest eigenvalue
    // Creates a map that contains the pairs <index, eigenvalue>
    AbstractIntDoubleMap map = new OpenIntDoubleHashMap(n);
    for (int i = 0; i < n; i++) map.put(i, Math.abs(lambda.get(i)));
    IntArrayList list = new IntArrayList();
    // Sorts the map on the value
    map.keysSortedByValue(list);
    // Gets the index of the second smallest element
    int i_2 = list.get(1);

    // y_2 = D^(-1/2) * z_2
    DoubleMatrix1D y_2 = e.getV().viewColumn(i_2).copy();
    y_2.assign(d_minus_1_2, Functions.mult);

    // Creates a map that contains the pairs <i, y_2[i]>
    map.clear();
    for (int i = 0; i < n; i++) map.put(i, y_2.get(i));
    // Sorts the map on the value
    map.keysSortedByValue(list);
    // Search the element in the map previuosly ordered that minimizes the cut
    // of the partition
    double best_cut = Double.POSITIVE_INFINITY;
    int[][] partition = new int[2][];

    // The array v contains all the elements of the graph ordered by their
    // projection on vector y_2
    int[] v = list.elements();
    // For each admissible splitting point i
    for (int i = 1; i < n; i++) {
      // The array a contains all the elements that have a projection on vector
      // y_2 less or equal to the one of i-th element
      // The array b contains the remaining elements
      int[] a = new int[i];
      int[] b = new int[n - i];
      System.arraycopy(v, 0, a, 0, i);
      System.arraycopy(v, i, b, 0, n - i);
      double cut = Ncut(W, a, b, v);
      if (cut < best_cut) {
        best_cut = cut;
        partition[0] = a;
        partition[1] = b;
      }
    }

    // System.out.println("Partition:");
    // UtilsJS.printMatrix(partition);

    return partition;
  }
 /**
  * Returns the Euclidean distance between two points. It is used to compute the similarity degree
  * of these ones.
  *
  * @param x the first point
  * @param y the second point
  * @return the Euclidean distance between the points
  */
 protected static double distnorm2(DoubleMatrix1D x, DoubleMatrix1D y) {
   DoubleMatrix1D z = x.copy();
   z.assign(y, Functions.minus);
   return z.zDotProduct(z);
 }
示例#28
0
  public void newmanCluster(ItemRegistry registry) {

    DoubleMatrix2D distance_matrix =
        DoubleFactory2D.sparse.make(
            registry.getGraph().getNodeCount(), registry.getGraph().getNodeCount());
    DoubleMatrix1D a_matrix = DoubleFactory1D.dense.make(registry.getGraph().getNodeCount(), 0.);

    Map<String, Cluster> cluster_map = new HashMap<String, Cluster>();

    // construct the leaf node distance matrix

    Iterator edge_iter = registry.getGraph().getEdges();
    m_total_distances = 0.;
    while (edge_iter.hasNext()) {
      Edge edge = (Edge) edge_iter.next();
      Cluster clust1 = (Cluster) edge.getFirstNode();
      Cluster clust2 = (Cluster) edge.getSecondNode();
      if (cluster_map.get(clust1.getAttribute("id")) == null) {
        cluster_map.put(clust1.getAttribute("id"), clust1);
      }
      if (cluster_map.get(clust2.getAttribute("id")) == null) {
        cluster_map.put(clust2.getAttribute("id"), clust2);
      }
      int n = Integer.parseInt(clust1.getAttribute("id"));
      int m = Integer.parseInt(clust2.getAttribute("id"));
      // make reciprocal (big values = good in newman, but not in our case)
      double dist = 1 / clust1.getCenter().distance(clust2.getCenter());
      distance_matrix.set(Math.max(n, m), Math.min(n, m), dist);
      //            m_total_distances += dist;
      //            a_matrix.setQuick( n, a_matrix.getQuick( n ) + dist );
      //            a_matrix.setQuick( m, a_matrix.getQuick( m ) + dist );
      m_total_distances += 1;
      a_matrix.setQuick(n, a_matrix.getQuick(n) + 1);
      a_matrix.setQuick(m, a_matrix.getQuick(m) + 1);
    }

    //        System.out.println(distance_matrix);
    //        System.out.println(count_matrix);
    // agglomerate nodes until we reach a root node (or nodes)
    boolean done = false;
    int trash = 0;
    QFinder qfinder = new QFinder();
    qfinder.a_matrix = a_matrix;
    QMerger qmerger = new QMerger();
    while (!done) {
      // find the minimum cluster distance

      qfinder.reset();

      distance_matrix.forEachNonZero(qfinder);

      //            done = true;

      //            System.out.println(distance_matrix);
      //            System.out.println(count_matrix);
      if (qfinder.getVal() == -Double.MAX_VALUE) {
        break;
      }

      // add a parent cluster to the graph

      Cluster clust1 = cluster_map.get("" + qfinder.getM());
      Cluster clust2 = cluster_map.get("" + qfinder.getN());
      while (clust1.getParent() != null) {
        clust1 = clust1.getParent();
      }
      while (clust2.getParent() != null) {
        clust2 = clust2.getParent();
      }
      trash++;
      double dist = Math.max(clust1.getHeight(), clust2.getHeight());
      Cluster new_cluster =
          new DefaultCluster(
              (float) (clust1.getCenter().getX() + clust2.getCenter().getX()) / 2.f,
              (float) (clust1.getCenter().getY() + clust2.getCenter().getY()) / 2.f,
              (float)
                  Math.sqrt(
                      clust1.getRadius() * clust1.getRadius()
                          + clust2.getRadius() * clust2.getRadius()),
              clust1,
              clust2,
              dist);
      registry.getGraph().addNode(new_cluster);

      // merge the clusters distances / counts

      int M = Math.max(qfinder.getM(), qfinder.getN());
      int N = Math.min(qfinder.getM(), qfinder.getN());
      a_matrix.set(N, a_matrix.getQuick(M) + a_matrix.getQuick(N));
      a_matrix.set(M, 0);
      //            System.out.println("M = "+M+" N = "+N + " VAL=" + minfinder.getVal() );
      qmerger.setM(M);
      qmerger.setN(N);
      qmerger.setParent(distance_matrix);
      qmerger.setMode(true);
      //            System.out.println(distance_matrix.viewPart( 0, M, distance_matrix.rows(), 1));
      distance_matrix.viewPart(0, M, distance_matrix.rows(), 1).forEachNonZero(qmerger);
      qmerger.setMode(false);
      //            System.out.println(distance_matrix.viewPart( M, 0, 1, M ));
      distance_matrix.viewPart(M, 0, 1, M).forEachNonZero(qmerger);

      //            System.out.println(distance_matrix);
      //            System.out.println(count_matrix);
      // free any superfluous memory randomly ~ (1/20) times

      if (Math.random() > 0.95) {
        distance_matrix.trimToSize();
      }
    }
  }
  public static boolean isInScope(
      final DoubleMatrix1D position,
      final DoubleMatrix1D dimensions,
      final DoubleMatrix1D feature) {
    if (position.size() != dimensions.size() || position.size() != feature.size()) {
      throw new IllegalArgumentException(
          "feature, position and dimensions" + "must have the same size");
    }

    // is the feature inside the tile (including boundaries)
    for (int i = 0; i < feature.size(); i++) {
      if (!(feature.get(i) >= position.get(i) - dimensions.get(i) / 2
          && feature.get(i) <= position.get(i) + dimensions.get(i) / 2)) {
        return false;
      }
    }
    return true;
  }
 public boolean isInScope(final Tile node, final DoubleMatrix1D feat) {
   return (TileInScopeCalculator.isInScope(
       node.getPosition(), feat.like().assign(this.maxDimensions), feat));
 }