public void nearestN(final double[] key, final int n, final Callback<Object[]> callback) {

    HRect hr = HRect.infiniteHRect(key.length);
    double max_dist_sqd = Double.MAX_VALUE;

    NearestNeighborList nnl = new NearestNeighborList(n);
    Distance distance = getDistance();
    internalNearest(this, distance, key, hr, max_dist_sqd, 0, key.length, threshold, nnl);

    Object[] res = nnl.getAllNodes();
    callback.on(res);
  }
  public void nearest(final double[] key, final Callback<Object> callback) {

    // initial call is with infinite hyper-rectangle and max distance
    HRect hr = HRect.infiniteHRect(key.length);
    double max_dist_sqd = Double.MAX_VALUE;

    NearestNeighborList nnl = new NearestNeighborList(1);
    Distance distance = getDistance();
    internalNearest(this, distance, key, hr, max_dist_sqd, 0, key.length, threshold, nnl);

    Object res = nnl.getHighest();
    callback.on(res);
  }
Beispiel #3
0
  // Method Nearest Neighbor from Andrew Moore's thesis. Numbered
  // comments are direct quotes from there. Step "SDL" is added to
  // make the algorithm work correctly.  NearestNeighborList solution
  // courtesy of Bjoern Heckel.
  protected static void nnbr(
      KDNode kd,
      HPoint target,
      HRect hr,
      double max_dist_sqd,
      int lev,
      int K,
      NearestNeighborList nnl) {

    // 1. if kd is empty then set dist-sqd to infinity and exit.
    if (kd == null) {
      return;
    }

    // 2. s := split field of kd
    int s = lev % K;

    // 3. pivot := dom-elt field of kd
    HPoint pivot = kd.k;
    double pivot_to_target = HPoint.sqrdist(pivot, target);

    // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr.
    //    The cut plane is through pivot and perpendicular to the s
    //    dimension.
    HRect left_hr = hr; // optimize by not cloning
    HRect right_hr = (HRect) hr.clone();
    left_hr.max.coord[s] = pivot.coord[s];
    right_hr.min.coord[s] = pivot.coord[s];

    // 5. target-in-left := target_s <= pivot_s
    boolean target_in_left = target.coord[s] < pivot.coord[s];

    KDNode nearer_kd;
    HRect nearer_hr;
    KDNode further_kd;
    HRect further_hr;

    // 6. if target-in-left then
    //    6.1. nearer-kd := left field of kd and nearer-hr := left-hr
    //    6.2. further-kd := right field of kd and further-hr := right-hr
    if (target_in_left) {
      nearer_kd = kd.left;
      nearer_hr = left_hr;
      further_kd = kd.right;
      further_hr = right_hr;
    }
    //
    // 7. if not target-in-left then
    //    7.1. nearer-kd := right field of kd and nearer-hr := right-hr
    //    7.2. further-kd := left field of kd and further-hr := left-hr
    else {
      nearer_kd = kd.right;
      nearer_hr = right_hr;
      further_kd = kd.left;
      further_hr = left_hr;
    }

    // 8. Recursively call Nearest Neighbor with paramters
    //    (nearer-kd, target, nearer-hr, max-dist-sqd), storing the
    //    results in nearest and dist-sqd
    nnbr(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl);

    KDNode nearest = (KDNode) nnl.getHighest();
    double dist_sqd;

    if (!nnl.isCapacityReached()) {
      dist_sqd = Double.MAX_VALUE;
    } else {
      dist_sqd = nnl.getMaxPriority();
    }

    // 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd
    max_dist_sqd = Math.min(max_dist_sqd, dist_sqd);

    // 10. A nearer point could only lie in further-kd if there were some
    //     part of further-hr within distance sqrt(max-dist-sqd) of
    //     target.  If this is the case then
    HPoint closest = further_hr.closest(target);
    if (HPoint.eucdist(closest, target) < Math.sqrt(max_dist_sqd)) {

      // 10.1 if (pivot-target)^2 < dist-sqd then
      if (pivot_to_target < dist_sqd) {

        // 10.1.1 nearest := (pivot, range-elt field of kd)
        nearest = kd;

        // 10.1.2 dist-sqd = (pivot-target)^2
        dist_sqd = pivot_to_target;

        // add to nnl
        if (!kd.deleted) {
          nnl.insert(kd, dist_sqd);
        }

        // 10.1.3 max-dist-sqd = dist-sqd
        // max_dist_sqd = dist_sqd;
        if (nnl.isCapacityReached()) {
          max_dist_sqd = nnl.getMaxPriority();
        } else {
          max_dist_sqd = Double.MAX_VALUE;
        }
      }

      // 10.2 Recursively call Nearest Neighbor with parameters
      //      (further-kd, target, further-hr, max-dist_sqd),
      //      storing results in temp-nearest and temp-dist-sqd
      nnbr(further_kd, target, further_hr, max_dist_sqd, lev + 1, K, nnl);
      KDNode temp_nearest = (KDNode) nnl.getHighest();
      double temp_dist_sqd = nnl.getMaxPriority();

      // 10.3 If tmp-dist-sqd < dist-sqd then
      if (temp_dist_sqd < dist_sqd) {

        // 10.3.1 nearest := temp_nearest and dist_sqd := temp_dist_sqd
        nearest = temp_nearest;
        dist_sqd = temp_dist_sqd;
      }
    }

    // SDL: otherwise, current point is nearest
    else if (pivot_to_target < max_dist_sqd) {
      nearest = kd;
      dist_sqd = pivot_to_target;
    }
  }
  private static void internalNearest(
      KDNodeJava node,
      final Distance distance,
      double[] target,
      HRect hr,
      double max_dist_sqd,
      int lev,
      int dim,
      double err,
      NearestNeighborList nnl) {
    // 1. if kd is empty exit.
    if (node == null) {
      return;
    }

    double[] pivot = node.key;
    if (pivot == null) {
      return;
    }

    // 2. s := split field of kd
    int s = lev % dim;

    // 3. pivot := dom-elt field of kd

    double pivot_to_target = distance.measure(pivot, target);

    // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr.
    // The cut plane is through pivot and perpendicular to the s
    // dimension.
    HRect left_hr = hr; // optimize by not cloning
    HRect right_hr = (HRect) hr.clone();
    left_hr.max[s] = pivot[s];
    right_hr.min[s] = pivot[s];

    // 5. target-in-left := target_s <= pivot_s
    boolean target_in_left = target[s] < pivot[s];

    KDNodeJava nearer_kd;
    HRect nearer_hr;
    KDNodeJava further_kd;
    HRect further_hr;

    // 6. if target-in-left then
    // 6.1. nearer-kd := left field of kd and nearer-hr := left-hr
    // 6.2. further-kd := right field of kd and further-hr := right-hr
    if (target_in_left) {
      nearer_kd = node.left;
      nearer_hr = left_hr;
      further_kd = node.right;
      further_hr = right_hr;
    }
    //
    // 7. if not target-in-left then
    // 7.1. nearer-kd := right field of kd and nearer-hr := right-hr
    // 7.2. further-kd := left field of kd and further-hr := left-hr
    else {
      nearer_kd = node.right;
      nearer_hr = right_hr;
      further_kd = node.left;
      further_hr = left_hr;
    }

    // 8. Recursively call Nearest Neighbor with paramters
    // (nearer-kd, target, nearer-hr, max-dist-sqd), storing the
    // results in nearest and dist-sqd
    // nnbr(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl);
    internalNearest(nearer_kd, distance, target, nearer_hr, max_dist_sqd, lev + 1, dim, err, nnl);

    double dist_sqd;

    if (!nnl.isCapacityReached()) {
      dist_sqd = Double.MAX_VALUE;
    } else {
      dist_sqd = nnl.getMaxPriority();
    }

    // 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd
    max_dist_sqd = Math.min(max_dist_sqd, dist_sqd);

    // 10. A nearer point could only lie in further-kd if there were some
    // part of further-hr within distance sqrt(max-dist-sqd) of
    // target. If this is the case then
    double[] closest = further_hr.closest(target);
    if (distance.measure(closest, target) < max_dist_sqd) {

      // 10.1 if (pivot-target)^2 < dist-sqd then
      if (pivot_to_target < dist_sqd) {

        // 10.1.2 dist-sqd = (pivot-target)^2
        dist_sqd = pivot_to_target;
        nnl.insert(node.value, dist_sqd);

        // 10.1.3 max-dist-sqd = dist-sqd
        // max_dist_sqd = dist_sqd;
        if (nnl.isCapacityReached()) {
          max_dist_sqd = nnl.getMaxPriority();
        } else {
          max_dist_sqd = Double.MAX_VALUE;
        }
      }

      // 10.2 Recursively call Nearest Neighbor with parameters
      // (further-kd, target, further-hr, max-dist_sqd),
      // storing results in temp-nearest and temp-dist-sqd
      // nnbr(further_kd, target, further_hr, max_dist_sqd, lev + 1, K, nnl);
      internalNearest(
          further_kd, distance, target, further_hr, max_dist_sqd, lev + 1, dim, err, nnl);
    }
  }