Skip to content
Snippets Groups Projects
Commit e2669093 authored by Christophe Geuzaine's avatar Christophe Geuzaine
Browse files

*** empty log message ***

parent 509e02db
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 4041 deletions
ANN: Approximate Nearest Neighbors
Version: 1.1
Release Date: May 3, 2005
----------------------------------------------------------------------------
Copyright (c) 1997-2005 University of Maryland and Sunil Arya and David
Mount All Rights Reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser Public License for more details.
A copy of the terms and conditions of the license can be found in
License.txt or online at
http://www.gnu.org/copyleft/lesser.html
To obtain a copy, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Disclaimer
----------
The University of Maryland and the authors make no representations about
the suitability or fitness of this software for any purpose. It is
provided "as is" without express or implied warranty.
---------------------------------------------------------------------
Authors
-------
David Mount
Dept of Computer Science
University of Maryland,
College Park, MD 20742 USA
mount@cs.umd.edu
http://www.cs.umd.edu/~mount/
Sunil Arya
Dept of Computer Science
Hong University of Science and Technology
Clearwater Bay, HONG KONG
arya@cs.ust.hk
http://www.cs.ust.hk/faculty/arya/
This diff is collapsed.
# $Id: Makefile,v 1.2 2005-08-22 00:35:06 geuzaine Exp $
#
# Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
#
# Please report all bugs and problems to <gmsh@geuz.org>.
include ../variables
LIB = ../lib/libGmshANN.a
INCLUDE = -I../Common -I./include/
CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} -DNO_PARALLEL_THREADS -UWIN32
SRC = src/ANN.cpp\
src/bd_fix_rad_search.cpp\
src/bd_pr_search.cpp\
src/bd_search.cpp\
src/bd_tree.cpp\
src/brute.cpp\
src/kd_dump.cpp\
src/kd_fix_rad_search.cpp\
src/kd_pr_search.cpp\
src/kd_search.cpp\
src/kd_split.cpp\
src/kd_tree.cpp\
src/kd_util.cpp\
src/perf.cpp
OBJ = ${SRC:.cpp=.o}
.SUFFIXES: .o .cpp
${LIB}: ${OBJ}
${AR} ${LIB} ${OBJ}
${RANLIB} ${LIB}
.cpp.o:
${CXX} ${CFLAGS} -c $< -o ${<:.cpp=.o}
clean:
rm -f src/*.o
depend:
(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
${CXX} -MM ${CFLAGS} ${SRC} \
) >Makefile.new
cp Makefile Makefile.bak
cp Makefile.new Makefile
rm -f Makefile.new
# DO NOT DELETE THIS LINE
# 1 "/Users/geuzaine/.gmsh/ANN//"
ANN.o: src/ANN.cpp include/ANN/ANNx.h include/ANN/ANN.h \
include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
bd_fix_rad_search.o: src/bd_fix_rad_search.cpp src/bd_tree.h \
include/ANN/ANNx.h include/ANN/ANN.h src/kd_tree.h \
src/kd_fix_rad_search.h src/kd_util.h src/pr_queue_k.h \
include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
bd_pr_search.o: src/bd_pr_search.cpp src/bd_tree.h include/ANN/ANNx.h \
include/ANN/ANN.h src/kd_tree.h src/kd_pr_search.h src/kd_util.h \
src/pr_queue.h include/ANN/ANNperf.h src/pr_queue_k.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
bd_search.o: src/bd_search.cpp src/bd_tree.h include/ANN/ANNx.h \
include/ANN/ANN.h src/kd_tree.h src/kd_search.h src/kd_util.h \
src/pr_queue_k.h include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
bd_tree.o: src/bd_tree.cpp src/bd_tree.h include/ANN/ANNx.h \
include/ANN/ANN.h src/kd_tree.h src/kd_util.h src/kd_split.h \
include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
brute.o: src/brute.cpp include/ANN/ANNx.h include/ANN/ANN.h \
src/pr_queue_k.h include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
kd_dump.o: src/kd_dump.cpp src/kd_tree.h include/ANN/ANNx.h \
include/ANN/ANN.h src/bd_tree.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
kd_fix_rad_search.o: src/kd_fix_rad_search.cpp src/kd_fix_rad_search.h \
src/kd_tree.h include/ANN/ANNx.h include/ANN/ANN.h src/kd_util.h \
src/pr_queue_k.h include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
kd_pr_search.o: src/kd_pr_search.cpp src/kd_pr_search.h src/kd_tree.h \
include/ANN/ANNx.h include/ANN/ANN.h src/kd_util.h src/pr_queue.h \
include/ANN/ANNperf.h src/pr_queue_k.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
kd_search.o: src/kd_search.cpp src/kd_search.h src/kd_tree.h \
include/ANN/ANNx.h include/ANN/ANN.h src/kd_util.h src/pr_queue_k.h \
include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
kd_split.o: src/kd_split.cpp src/kd_tree.h include/ANN/ANNx.h \
include/ANN/ANN.h src/kd_util.h src/kd_split.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
kd_tree.o: src/kd_tree.cpp src/kd_tree.h include/ANN/ANNx.h \
include/ANN/ANN.h src/kd_split.h src/kd_util.h include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
kd_util.o: src/kd_util.cpp src/kd_util.h src/kd_tree.h include/ANN/ANNx.h \
include/ANN/ANN.h include/ANN/ANNperf.h
# 1 "/Users/geuzaine/.gmsh/ANN//"
perf.o: src/perf.cpp include/ANN/ANN.h include/ANN/ANNperf.h
This diff is collapsed.
//----------------------------------------------------------------------
// File: ANNperf.h
// Programmer: Sunil Arya and David Mount
// Last modified: 03/04/98 (Release 0.1)
// Description: Include file for ANN performance stats
//
// Some of the code for statistics gathering has been adapted
// from the SmplStat.h package in the g++ library.
//----------------------------------------------------------------------
// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David
// Mount. All Rights Reserved.
//
// This software and related documentation is part of the
// Approximate Nearest Neighbor Library (ANN).
//
// Permission to use, copy, and distribute this software and its
// documentation is hereby granted free of charge, provided that
// (1) it is not a component of a commercial product, and
// (2) this notice appears in all copies of the software and
// related documentation.
//
// The University of Maryland (U.M.) and the authors make no representations
// about the suitability or fitness of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision 1.0 04/01/05
// Added ANN_ prefix to avoid name conflicts.
//----------------------------------------------------------------------
#ifndef ANNperf_H
#define ANNperf_H
//----------------------------------------------------------------------
// basic includes
//----------------------------------------------------------------------
#include <ANN/ANN.h> // basic ANN includes
//----------------------------------------------------------------------
// kd-tree stats object
// This object is used for collecting information about a kd-tree
// or bd-tree.
//----------------------------------------------------------------------
class ANNkdStats { // stats on kd-tree
public:
int dim; // dimension of space
int n_pts; // no. of points
int bkt_size; // bucket size
int n_lf; // no. of leaves (including trivial)
int n_tl; // no. of trivial leaves (no points)
int n_spl; // no. of splitting nodes
int n_shr; // no. of shrinking nodes (for bd-trees)
int depth; // depth of tree
float sum_ar; // sum of leaf aspect ratios
float avg_ar; // average leaf aspect ratio
//
// reset stats
void reset(int d=0, int n=0, int bs=0)
{
dim = d; n_pts = n; bkt_size = bs;
n_lf = n_tl = n_spl = n_shr = depth = 0;
sum_ar = avg_ar = 0.0;
}
ANNkdStats() // basic constructor
{ reset(); }
void merge(const ANNkdStats &st); // merge stats from child
};
//----------------------------------------------------------------------
// ANNsampStat
// A sample stat collects numeric (double) samples and returns some
// simple statistics. Its main functions are:
//
// reset() Reset to no samples.
// += x Include sample x.
// samples() Return number of samples.
// mean() Return mean of samples.
// stdDev() Return standard deviation
// min() Return minimum of samples.
// max() Return maximum of samples.
//----------------------------------------------------------------------
class DLL_API ANNsampStat {
int n; // number of samples
double sum; // sum
double sum2; // sum of squares
double minVal, maxVal; // min and max
public :
void reset() // reset everything
{
n = 0;
sum = sum2 = 0;
minVal = ANN_DBL_MAX;
maxVal = -ANN_DBL_MAX;
}
ANNsampStat() { reset(); } // constructor
void operator+=(double x) // add sample
{
n++; sum += x; sum2 += x*x;
if (x < minVal) minVal = x;
if (x > maxVal) maxVal = x;
}
int samples() { return n; } // number of samples
double mean() { return sum/n; } // mean
// standard deviation
double stdDev() { return sqrt((sum2 - (sum*sum)/n)/(n-1));}
double min() { return minVal; } // minimum
double max() { return maxVal; } // maximum
};
//----------------------------------------------------------------------
// Operation count updates
//----------------------------------------------------------------------
#ifdef ANN_PERF
#define ANN_FLOP(n) {ann_Nfloat_ops += (n);}
#define ANN_LEAF(n) {ann_Nvisit_lfs += (n);}
#define ANN_SPL(n) {ann_Nvisit_spl += (n);}
#define ANN_SHR(n) {ann_Nvisit_shr += (n);}
#define ANN_PTS(n) {ann_Nvisit_pts += (n);}
#define ANN_COORD(n) {ann_Ncoord_hts += (n);}
#else
#define ANN_FLOP(n)
#define ANN_LEAF(n)
#define ANN_SPL(n)
#define ANN_SHR(n)
#define ANN_PTS(n)
#define ANN_COORD(n)
#endif
//----------------------------------------------------------------------
// Performance statistics
// The following data and routines are used for computing performance
// statistics for nearest neighbor searching. Because these routines
// can slow the code down, they can be activated and deactiviated by
// defining the ANN_PERF variable, by compiling with the option:
// -DANN_PERF
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Global counters for performance measurement
//
// visit_lfs The number of leaf nodes visited in the
// tree.
//
// visit_spl The number of splitting nodes visited in the
// tree.
//
// visit_shr The number of shrinking nodes visited in the
// tree.
//
// visit_pts The number of points visited in all the
// leaf nodes visited. Equivalently, this
// is the number of points for which distance
// calculations are performed.
//
// coord_hts The number of times a coordinate of a
// data point is accessed. This is generally
// less than visit_pts*d if partial distance
// calculation is used. This count is low
// in the sense that if a coordinate is hit
// many times in the same routine we may
// count it only once.
//
// float_ops The number of floating point operations.
// This includes all operations in the heap
// as well as distance calculations to boxes.
//
// average_err The average error of each query (the
// error of the reported point to the true
// nearest neighbor). For k nearest neighbors
// the error is computed k times.
//
// rank_err The rank error of each query (the difference
// in the rank of the reported point and its
// true rank).
//
// data_pts The number of data points. This is not
// a counter, but used in stats computation.
//----------------------------------------------------------------------
extern int ann_Ndata_pts; // number of data points
extern int ann_Nvisit_lfs; // number of leaf nodes visited
extern int ann_Nvisit_spl; // number of splitting nodes visited
extern int ann_Nvisit_shr; // number of shrinking nodes visited
extern int ann_Nvisit_pts; // visited points for one query
extern int ann_Ncoord_hts; // coordinate hits for one query
extern int ann_Nfloat_ops; // floating ops for one query
extern ANNsampStat ann_visit_lfs; // stats on leaf nodes visits
extern ANNsampStat ann_visit_spl; // stats on splitting nodes visits
extern ANNsampStat ann_visit_shr; // stats on shrinking nodes visits
extern ANNsampStat ann_visit_nds; // stats on total nodes visits
extern ANNsampStat ann_visit_pts; // stats on points visited
extern ANNsampStat ann_coord_hts; // stats on coordinate hits
extern ANNsampStat ann_float_ops; // stats on floating ops
//----------------------------------------------------------------------
// The following need to be part of the public interface, because
// they are accessed outside the DLL in ann_test.cpp.
//----------------------------------------------------------------------
DLL_API extern ANNsampStat ann_average_err; // average error
DLL_API extern ANNsampStat ann_rank_err; // rank error
//----------------------------------------------------------------------
// Declaration of externally accessible routines for statistics
//----------------------------------------------------------------------
DLL_API void annResetStats(int data_size); // reset stats for a set of queries
DLL_API void annResetCounts(); // reset counts for one queries
DLL_API void annUpdateStats(); // update stats with current counts
DLL_API void annPrintStats(ANNbool validate); // print statistics for a run
#endif
//----------------------------------------------------------------------
// File: ANNx.h
// Programmer: Sunil Arya and David Mount
// Last modified: 03/04/98 (Release 0.1)
// Description: Internal include file for ANN
//
// These declarations are of use in manipulating some of
// the internal data objects appearing in ANN, but are not
// needed for applications just using the nearest neighbor
// search.
//
// Typical users of ANN should not need to access this file.
//----------------------------------------------------------------------
// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David
// Mount. All Rights Reserved.
//
// This software and related documentation is part of the
// Approximate Nearest Neighbor Library (ANN).
//
// Permission to use, copy, and distribute this software and its
// documentation is hereby granted free of charge, provided that
// (1) it is not a component of a commercial product, and
// (2) this notice appears in all copies of the software and
// related documentation.
//
// The University of Maryland (U.M.) and the authors make no representations
// about the suitability or fitness of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision 1.0 04/01/05
// Changed LO, HI, IN, OUT to ANN_LO, ANN_HI, etc.
//----------------------------------------------------------------------
#ifndef ANNx_H
#define ANNx_H
#include <iomanip> // I/O manipulators
#include <ANN/ANN.h> // ANN includes
//----------------------------------------------------------------------
// Global constants and types
//----------------------------------------------------------------------
enum {ANN_LO=0, ANN_HI=1}; // splitting indices
enum {ANN_IN=0, ANN_OUT=1}; // shrinking indices
// what to do in case of error
enum ANNerr {ANNwarn = 0, ANNabort = 1};
//----------------------------------------------------------------------
// Maximum number of points to visit
// We have an option for terminating the search early if the
// number of points visited exceeds some threshold. If the
// threshold is 0 (its default) this means there is no limit
// and the algorithm applies its normal termination condition.
//----------------------------------------------------------------------
extern int ANNmaxPtsVisited; // maximum number of pts visited
extern int ANNptsVisited; // number of pts visited in search
//----------------------------------------------------------------------
// Global function declarations
//----------------------------------------------------------------------
void annError( // ANN error routine
char *msg, // error message
ANNerr level); // level of error
void annPrintPt( // print a point
ANNpoint pt, // the point
int dim, // the dimension
std::ostream &out); // output stream
//----------------------------------------------------------------------
// Orthogonal (axis aligned) rectangle
// Orthogonal rectangles are represented by two points, one
// for the lower left corner (min coordinates) and the other
// for the upper right corner (max coordinates).
//
// The constructor initializes from either a pair of coordinates,
// pair of points, or another rectangle. Note that all constructors
// allocate new point storage. The destructor deallocates this
// storage.
//
// BEWARE: Orthogonal rectangles should be passed ONLY BY REFERENCE.
// (C++'s default copy constructor will not allocate new point
// storage, then on return the destructor free's storage, and then
// you get into big trouble in the calling procedure.)
//----------------------------------------------------------------------
class ANNorthRect {
public:
ANNpoint lo; // rectangle lower bounds
ANNpoint hi; // rectangle upper bounds
//
ANNorthRect( // basic constructor
int dd, // dimension of space
ANNcoord l=0, // default is empty
ANNcoord h=0)
{ lo = annAllocPt(dd, l); hi = annAllocPt(dd, h); }
ANNorthRect( // (almost a) copy constructor
int dd, // dimension
const ANNorthRect &r) // rectangle to copy
{ lo = annCopyPt(dd, r.lo); hi = annCopyPt(dd, r.hi); }
ANNorthRect( // construct from points
int dd, // dimension
ANNpoint l, // low point
ANNpoint h) // hight point
{ lo = annCopyPt(dd, l); hi = annCopyPt(dd, h); }
~ANNorthRect() // destructor
{ annDeallocPt(lo); annDeallocPt(hi); }
ANNbool inside(int dim, ANNpoint p);// is point p inside rectangle?
};
void annAssignRect( // assign one rect to another
int dim, // dimension (both must be same)
ANNorthRect &dest, // destination (modified)
const ANNorthRect &source); // source
//----------------------------------------------------------------------
// Orthogonal (axis aligned) halfspace
// An orthogonal halfspace is represented by an integer cutting
// dimension cd, coordinate cutting value, cv, and side, sd, which is
// either +1 or -1. Our convention is that point q lies in the (closed)
// halfspace if (q[cd] - cv)*sd >= 0.
//----------------------------------------------------------------------
class ANNorthHalfSpace {
public:
int cd; // cutting dimension
ANNcoord cv; // cutting value
int sd; // which side
//
ANNorthHalfSpace() // default constructor
{ cd = 0; cv = 0; sd = 0; }
ANNorthHalfSpace( // basic constructor
int cdd, // dimension of space
ANNcoord cvv, // cutting value
int sdd) // side
{ cd = cdd; cv = cvv; sd = sdd; }
ANNbool in(ANNpoint q) const // is q inside halfspace?
{ return (ANNbool) ((q[cd] - cv)*sd >= 0); }
ANNbool out(ANNpoint q) const // is q outside halfspace?
{ return (ANNbool) ((q[cd] - cv)*sd < 0); }
ANNdist dist(ANNpoint q) const // (squared) distance from q
{ return (ANNdist) ANN_POW(q[cd] - cv); }
void setLowerBound(int d, ANNpoint p)// set to lower bound at p[i]
{ cd = d; cv = p[d]; sd = +1; }
void setUpperBound(int d, ANNpoint p)// set to upper bound at p[i]
{ cd = d; cv = p[d]; sd = -1; }
void project(ANNpoint &q) // project q (modified) onto halfspace
{ if (out(q)) q[cd] = cv; }
};
// array of halfspaces
typedef ANNorthHalfSpace *ANNorthHSArray;
#endif
//----------------------------------------------------------------------
// File: ANN.cpp
// Programmer: Sunil Arya and David Mount
// Description: Methods for ANN.h and ANNx.h
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision 1.0 04/01/05
// Added performance counting to annDist()
//----------------------------------------------------------------------
#include <ANN/ANNx.h> // all ANN includes
#include <ANN/ANNperf.h> // ANN performance
using namespace std; // make std:: accessible
//----------------------------------------------------------------------
// Point methods
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// Distance utility.
// (Note: In the nearest neighbor search, most distances are
// computed using partial distance calculations, not this
// procedure.)
//----------------------------------------------------------------------
ANNdist annDist( // interpoint squared distance
int dim,
ANNpoint p,
ANNpoint q)
{
register int d;
register ANNcoord diff;
register ANNcoord dist;
dist = 0;
for (d = 0; d < dim; d++) {
diff = p[d] - q[d];
dist = ANN_SUM(dist, ANN_POW(diff));
}
ANN_FLOP(3*dim) // performance counts
ANN_PTS(1)
ANN_COORD(dim)
return dist;
}
//----------------------------------------------------------------------
// annPrintPoint() prints a point to a given output stream.
//----------------------------------------------------------------------
void annPrintPt( // print a point
ANNpoint pt, // the point
int dim, // the dimension
std::ostream &out) // output stream
{
for (int j = 0; j < dim; j++) {
out << pt[j];
if (j < dim-1) out << " ";
}
}
//----------------------------------------------------------------------
// Point allocation/deallocation:
//
// Because points (somewhat like strings in C) are stored
// as pointers. Consequently, creating and destroying
// copies of points may require storage allocation. These
// procedures do this.
//
// annAllocPt() and annDeallocPt() allocate a deallocate
// storage for a single point, and return a pointer to it.
//
// annAllocPts() allocates an array of points as well a place
// to store their coordinates, and initializes the points to
// point to their respective coordinates. It allocates point
// storage in a contiguous block large enough to store all the
// points. It performs no initialization.
//
// annDeallocPts() should only be used on point arrays allocated
// by annAllocPts since it assumes that points are allocated in
// a block.
//
// annCopyPt() copies a point taking care to allocate storage
// for the new point.
//
// annAssignRect() assigns the coordinates of one rectangle to
// another. The two rectangles must have the same dimension
// (and it is not possible to test this here).
//----------------------------------------------------------------------
ANNpoint annAllocPt(int dim, ANNcoord c) // allocate 1 point
{
ANNpoint p = new ANNcoord[dim];
for (int i = 0; i < dim; i++) p[i] = c;
return p;
}
ANNpointArray annAllocPts(int n, int dim) // allocate n pts in dim
{
ANNpointArray pa = new ANNpoint[n]; // allocate points
ANNpoint p = new ANNcoord[n*dim]; // allocate space for coords
for (int i = 0; i < n; i++) {
pa[i] = &(p[i*dim]);
}
return pa;
}
void annDeallocPt(ANNpoint &p) // deallocate 1 point
{
delete [] p;
p = NULL;
}
void annDeallocPts(ANNpointArray &pa) // deallocate points
{
delete [] pa[0]; // dealloc coordinate storage
delete [] pa; // dealloc points
pa = NULL;
}
ANNpoint annCopyPt(int dim, ANNpoint source) // copy point
{
ANNpoint p = new ANNcoord[dim];
for (int i = 0; i < dim; i++) p[i] = source[i];
return p;
}
// assign one rect to another
void annAssignRect(int dim, ANNorthRect &dest, const ANNorthRect &source)
{
for (int i = 0; i < dim; i++) {
dest.lo[i] = source.lo[i];
dest.hi[i] = source.hi[i];
}
}
// is point inside rectangle?
ANNbool ANNorthRect::inside(int dim, ANNpoint p)
{
for (int i = 0; i < dim; i++) {
if (p[i] < lo[i] || p[i] > hi[i]) return ANNfalse;
}
return ANNtrue;
}
//----------------------------------------------------------------------
// Error handler
//----------------------------------------------------------------------
void annError(char *msg, ANNerr level)
{
if (level == ANNabort) {
cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n";
exit(1);
}
else {
cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n";
}
}
//----------------------------------------------------------------------
// Limit on number of points visited
// We have an option for terminating the search early if the
// number of points visited exceeds some threshold. If the
// threshold is 0 (its default) this means there is no limit
// and the algorithm applies its normal termination condition.
// This is for applications where there are real time constraints
// on the running time of the algorithm.
//----------------------------------------------------------------------
int ANNmaxPtsVisited = 0; // maximum number of pts visited
int ANNptsVisited; // number of pts visited in search
//----------------------------------------------------------------------
// Global function declarations
//----------------------------------------------------------------------
void annMaxPtsVisit( // set limit on max. pts to visit in search
int maxPts) // the limit
{
ANNmaxPtsVisited = maxPts;
}
//----------------------------------------------------------------------
// File: bd_fix_rad_search.cpp
// Programmer: David Mount
// Description: Standard bd-tree search
// Last modified: 05/03/05 (Version 1.1)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 1.1 05/03/05
// Initial release
//----------------------------------------------------------------------
#include "bd_tree.h" // bd-tree declarations
#include "kd_fix_rad_search.h" // kd-tree FR search declarations
//----------------------------------------------------------------------
// Approximate searching for bd-trees.
// See the file kd_FR_search.cpp for general information on the
// approximate nearest neighbor search algorithm. Here we
// include the extensions for shrinking nodes.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// bd_shrink::ann_FR_search - search a shrinking node
//----------------------------------------------------------------------
void ANNbd_shrink::ann_FR_search(ANNdist box_dist)
{
// check dist calc term cond.
if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
ANNdist inner_dist = 0; // distance to inner box
for (int i = 0; i < n_bnds; i++) { // is query point in the box?
if (bnds[i].out(ANNkdFRQ)) { // outside this bounding side?
// add to inner distance
inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdFRQ));
}
}
if (inner_dist <= box_dist) { // if inner box is closer
child[ANN_IN]->ann_FR_search(inner_dist);// search inner child first
child[ANN_OUT]->ann_FR_search(box_dist);// ...then outer child
}
else { // if outer box is closer
child[ANN_OUT]->ann_FR_search(box_dist);// search outer child first
child[ANN_IN]->ann_FR_search(inner_dist);// ...then outer child
}
ANN_FLOP(3*n_bnds) // increment floating ops
ANN_SHR(1) // one more shrinking node
}
//----------------------------------------------------------------------
// File: bd_pr_search.cpp
// Programmer: David Mount
// Description: Priority search for bd-trees
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
//History:
// Revision 0.1 03/04/98
// Initial release
//----------------------------------------------------------------------
#include "bd_tree.h" // bd-tree declarations
#include "kd_pr_search.h" // kd priority search declarations
//----------------------------------------------------------------------
// Approximate priority searching for bd-trees.
// See the file kd_pr_search.cc for general information on the
// approximate nearest neighbor priority search algorithm. Here
// we include the extensions for shrinking nodes.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// bd_shrink::ann_search - search a shrinking node
//----------------------------------------------------------------------
void ANNbd_shrink::ann_pri_search(ANNdist box_dist)
{
ANNdist inner_dist = 0; // distance to inner box
for (int i = 0; i < n_bnds; i++) { // is query point in the box?
if (bnds[i].out(ANNprQ)) { // outside this bounding side?
// add to inner distance
inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNprQ));
}
}
if (inner_dist <= box_dist) { // if inner box is closer
if (child[ANN_OUT] != KD_TRIVIAL) // enqueue outer if not trivial
ANNprBoxPQ->insert(box_dist,child[ANN_OUT]);
// continue with inner child
child[ANN_IN]->ann_pri_search(inner_dist);
}
else { // if outer box is closer
if (child[ANN_IN] != KD_TRIVIAL) // enqueue inner if not trivial
ANNprBoxPQ->insert(inner_dist,child[ANN_IN]);
// continue with outer child
child[ANN_OUT]->ann_pri_search(box_dist);
}
ANN_FLOP(3*n_bnds) // increment floating ops
ANN_SHR(1) // one more shrinking node
}
//----------------------------------------------------------------------
// File: bd_search.cpp
// Programmer: David Mount
// Description: Standard bd-tree search
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
//----------------------------------------------------------------------
#include "bd_tree.h" // bd-tree declarations
#include "kd_search.h" // kd-tree search declarations
//----------------------------------------------------------------------
// Approximate searching for bd-trees.
// See the file kd_search.cpp for general information on the
// approximate nearest neighbor search algorithm. Here we
// include the extensions for shrinking nodes.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// bd_shrink::ann_search - search a shrinking node
//----------------------------------------------------------------------
void ANNbd_shrink::ann_search(ANNdist box_dist)
{
// check dist calc term cond.
if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
ANNdist inner_dist = 0; // distance to inner box
for (int i = 0; i < n_bnds; i++) { // is query point in the box?
if (bnds[i].out(ANNkdQ)) { // outside this bounding side?
// add to inner distance
inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdQ));
}
}
if (inner_dist <= box_dist) { // if inner box is closer
child[ANN_IN]->ann_search(inner_dist); // search inner child first
child[ANN_OUT]->ann_search(box_dist); // ...then outer child
}
else { // if outer box is closer
child[ANN_OUT]->ann_search(box_dist); // search outer child first
child[ANN_IN]->ann_search(inner_dist); // ...then outer child
}
ANN_FLOP(3*n_bnds) // increment floating ops
ANN_SHR(1) // one more shrinking node
}
//----------------------------------------------------------------------
// File: bd_tree.cpp
// Programmer: David Mount
// Description: Basic methods for bd-trees.
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision l.0 04/01/05
// Fixed centroid shrink threshold condition to depend on the
// dimension.
// Moved dump routine to kd_dump.cpp.
//----------------------------------------------------------------------
#include "bd_tree.h" // bd-tree declarations
#include "kd_util.h" // kd-tree utilities
#include "kd_split.h" // kd-tree splitting rules
#include <ANN/ANNperf.h> // performance evaluation
//----------------------------------------------------------------------
// Printing a bd-tree
// These routines print a bd-tree. See the analogous procedure
// in kd_tree.cpp for more information.
//----------------------------------------------------------------------
void ANNbd_shrink::print( // print shrinking node
int level, // depth of node in tree
ostream &out) // output stream
{
child[ANN_OUT]->print(level+1, out); // print out-child
out << " ";
for (int i = 0; i < level; i++) // print indentation
out << "..";
out << "Shrink";
for (int j = 0; j < n_bnds; j++) { // print sides, 2 per line
if (j % 2 == 0) {
out << "\n"; // newline and indentation
for (int i = 0; i < level+2; i++) out << " ";
}
out << " ([" << bnds[j].cd << "]"
<< (bnds[j].sd > 0 ? ">=" : "< ")
<< bnds[j].cv << ")";
}
out << "\n";
child[ANN_IN]->print(level+1, out); // print in-child
}
//----------------------------------------------------------------------
// kd_tree statistics utility (for performance evaluation)
// This routine computes various statistics information for
// shrinking nodes. See file kd_tree.cpp for more information.
//----------------------------------------------------------------------
void ANNbd_shrink::getStats( // get subtree statistics
int dim, // dimension of space
ANNkdStats &st, // stats (modified)
ANNorthRect &bnd_box) // bounding box
{
ANNkdStats ch_stats; // stats for children
ANNorthRect inner_box(dim); // inner box of shrink
annBnds2Box(bnd_box, // enclosing box
dim, // dimension
n_bnds, // number of bounds
bnds, // bounds array
inner_box); // inner box (modified)
// get stats for inner child
ch_stats.reset(); // reset
child[ANN_IN]->getStats(dim, ch_stats, inner_box);
st.merge(ch_stats); // merge them
// get stats for outer child
ch_stats.reset(); // reset
child[ANN_OUT]->getStats(dim, ch_stats, bnd_box);
st.merge(ch_stats); // merge them
st.depth++; // increment depth
st.n_shr++; // increment number of shrinks
}
//----------------------------------------------------------------------
// bd-tree constructor
// This is the main constructor for bd-trees given a set of points.
// It first builds a skeleton kd-tree as a basis, then computes the
// bounding box of the data points, and then invokes rbd_tree() to
// actually build the tree, passing it the appropriate splitting
// and shrinking information.
//----------------------------------------------------------------------
ANNkd_ptr rbd_tree( // recursive construction of bd-tree
ANNpointArray pa, // point array
ANNidxArray pidx, // point indices to store in subtree
int n, // number of points
int dim, // dimension of space
int bsp, // bucket space
ANNorthRect &bnd_box, // bounding box for current node
ANNkd_splitter splitter, // splitting routine
ANNshrinkRule shrink); // shrinking rule
ANNbd_tree::ANNbd_tree( // construct from point array
ANNpointArray pa, // point array (with at least n pts)
int n, // number of points
int dd, // dimension
int bs, // bucket size
ANNsplitRule split, // splitting rule
ANNshrinkRule shrink) // shrinking rule
: ANNkd_tree(n, dd, bs) // build skeleton base tree
{
pts = pa; // where the points are
if (n == 0) return; // no points--no sweat
ANNorthRect bnd_box(dd); // bounding box for points
// construct bounding rectangle
annEnclRect(pa, pidx, n, dd, bnd_box);
// copy to tree structure
bnd_box_lo = annCopyPt(dd, bnd_box.lo);
bnd_box_hi = annCopyPt(dd, bnd_box.hi);
switch (split) { // build by rule
case ANN_KD_STD: // standard kd-splitting rule
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, shrink);
break;
case ANN_KD_MIDPT: // midpoint split
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, shrink);
break;
case ANN_KD_SUGGEST: // best (in our opinion)
case ANN_KD_SL_MIDPT: // sliding midpoint split
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, shrink);
break;
case ANN_KD_FAIR: // fair split
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, shrink);
break;
case ANN_KD_SL_FAIR: // sliding fair split
root = rbd_tree(pa, pidx, n, dd, bs,
bnd_box, sl_fair_split, shrink);
break;
default:
annError("Illegal splitting method", ANNabort);
}
}
//----------------------------------------------------------------------
// Shrinking rules
//----------------------------------------------------------------------
enum ANNdecomp {SPLIT, SHRINK}; // decomposition methods
//----------------------------------------------------------------------
// trySimpleShrink - Attempt a simple shrink
//
// We compute the tight bounding box of the points, and compute
// the 2*dim ``gaps'' between the sides of the tight box and the
// bounding box. If any of the gaps is large enough relative to
// the longest side of the tight bounding box, then we shrink
// all sides whose gaps are large enough. (The reason for
// comparing against the tight bounding box, is that after
// shrinking the longest box size will decrease, and if we use
// the standard bounding box, we may decide to shrink twice in
// a row. Since the tight box is fixed, we cannot shrink twice
// consecutively.)
//----------------------------------------------------------------------
const float BD_GAP_THRESH = 0.5; // gap threshold (must be < 1)
const int BD_CT_THRESH = 2; // min number of shrink sides
ANNdecomp trySimpleShrink( // try a simple shrink
ANNpointArray pa, // point array
ANNidxArray pidx, // point indices to store in subtree
int n, // number of points
int dim, // dimension of space
const ANNorthRect &bnd_box, // current bounding box
ANNorthRect &inner_box) // inner box if shrinking (returned)
{
int i;
// compute tight bounding box
annEnclRect(pa, pidx, n, dim, inner_box);
ANNcoord max_length = 0; // find longest box side
for (i = 0; i < dim; i++) {
ANNcoord length = inner_box.hi[i] - inner_box.lo[i];
if (length > max_length) {
max_length = length;
}
}
int shrink_ct = 0; // number of sides we shrunk
for (i = 0; i < dim; i++) { // select which sides to shrink
// gap between boxes
ANNcoord gap_hi = bnd_box.hi[i] - inner_box.hi[i];
// big enough gap to shrink?
if (gap_hi < max_length*BD_GAP_THRESH)
inner_box.hi[i] = bnd_box.hi[i]; // no - expand
else shrink_ct++; // yes - shrink this side
// repeat for high side
ANNcoord gap_lo = inner_box.lo[i] - bnd_box.lo[i];
if (gap_lo < max_length*BD_GAP_THRESH)
inner_box.lo[i] = bnd_box.lo[i]; // no - expand
else shrink_ct++; // yes - shrink this side
}
if (shrink_ct >= BD_CT_THRESH) // did we shrink enough sides?
return SHRINK;
else return SPLIT;
}
//----------------------------------------------------------------------
// tryCentroidShrink - Attempt a centroid shrink
//
// We repeatedly apply the splitting rule, always to the larger subset
// of points, until the number of points decreases by the constant
// fraction BD_FRACTION. If this takes more than dim*BD_MAX_SPLIT_FAC
// splits for this to happen, then we shrink to the final inner box
// Otherwise we split.
//----------------------------------------------------------------------
const float BD_MAX_SPLIT_FAC = 0.5; // maximum number of splits allowed
const float BD_FRACTION = 0.5; // ...to reduce points by this fraction
// ...This must be < 1.
ANNdecomp tryCentroidShrink( // try a centroid shrink
ANNpointArray pa, // point array
ANNidxArray pidx, // point indices to store in subtree
int n, // number of points
int dim, // dimension of space
const ANNorthRect &bnd_box, // current bounding box
ANNkd_splitter splitter, // splitting procedure
ANNorthRect &inner_box) // inner box if shrinking (returned)
{
int n_sub = n; // number of points in subset
int n_goal = (int) (n*BD_FRACTION); // number of point in goal
int n_splits = 0; // number of splits needed
// initialize inner box to bounding box
annAssignRect(dim, inner_box, bnd_box);
while (n_sub > n_goal) { // keep splitting until goal reached
int cd; // cut dim from splitter (ignored)
ANNcoord cv; // cut value from splitter (ignored)
int n_lo; // number of points on low side
// invoke splitting procedure
(*splitter)(pa, pidx, inner_box, n_sub, dim, cd, cv, n_lo);
n_splits++; // increment split count
if (n_lo >= n_sub/2) { // most points on low side
inner_box.hi[cd] = cv; // collapse high side
n_sub = n_lo; // recurse on lower points
}
else { // most points on high side
inner_box.lo[cd] = cv; // collapse low side
pidx += n_lo; // recurse on higher points
n_sub -= n_lo;
}
}
if (n_splits > dim*BD_MAX_SPLIT_FAC)// took too many splits
return SHRINK; // shrink to final subset
else
return SPLIT;
}
//----------------------------------------------------------------------
// selectDecomp - select which decomposition to use
//----------------------------------------------------------------------
ANNdecomp selectDecomp( // select decomposition method
ANNpointArray pa, // point array
ANNidxArray pidx, // point indices to store in subtree
int n, // number of points
int dim, // dimension of space
const ANNorthRect &bnd_box, // current bounding box
ANNkd_splitter splitter, // splitting procedure
ANNshrinkRule shrink, // shrinking rule
ANNorthRect &inner_box) // inner box if shrinking (returned)
{
ANNdecomp decomp = SPLIT; // decomposition
switch (shrink) { // check shrinking rule
case ANN_BD_NONE: // no shrinking allowed
decomp = SPLIT;
break;
case ANN_BD_SUGGEST: // author's suggestion
case ANN_BD_SIMPLE: // simple shrink
decomp = trySimpleShrink(
pa, pidx, // points and indices
n, dim, // number of points and dimension
bnd_box, // current bounding box
inner_box); // inner box if shrinking (returned)
break;
case ANN_BD_CENTROID: // centroid shrink
decomp = tryCentroidShrink(
pa, pidx, // points and indices
n, dim, // number of points and dimension
bnd_box, // current bounding box
splitter, // splitting procedure
inner_box); // inner box if shrinking (returned)
break;
default:
annError("Illegal shrinking rule", ANNabort);
}
return decomp;
}
//----------------------------------------------------------------------
// rbd_tree - recursive procedure to build a bd-tree
//
// This is analogous to rkd_tree, but for bd-trees. See the
// procedure rkd_tree() in kd_split.cpp for more information.
//
// If the number of points falls below the bucket size, then a
// leaf node is created for the points. Otherwise we invoke the
// procedure selectDecomp() which determines whether we are to
// split or shrink. If splitting is chosen, then we essentially
// do exactly as rkd_tree() would, and invoke the specified
// splitting procedure to the points. Otherwise, the selection
// procedure returns a bounding box, from which we extract the
// appropriate shrinking bounds, and create a shrinking node.
// Finally the points are subdivided, and the procedure is
// invoked recursively on the two subsets to form the children.
//----------------------------------------------------------------------
ANNkd_ptr rbd_tree( // recursive construction of bd-tree
ANNpointArray pa, // point array
ANNidxArray pidx, // point indices to store in subtree
int n, // number of points
int dim, // dimension of space
int bsp, // bucket space
ANNorthRect &bnd_box, // bounding box for current node
ANNkd_splitter splitter, // splitting routine
ANNshrinkRule shrink) // shrinking rule
{
ANNdecomp decomp; // decomposition method
ANNorthRect inner_box(dim); // inner box (if shrinking)
if (n <= bsp) { // n small, make a leaf node
if (n == 0) // empty leaf node
return KD_TRIVIAL; // return (canonical) empty leaf
else // construct the node and return
return new ANNkd_leaf(n, pidx);
}
decomp = selectDecomp( // select decomposition method
pa, pidx, // points and indices
n, dim, // number of points and dimension
bnd_box, // current bounding box
splitter, shrink, // splitting/shrinking methods
inner_box); // inner box if shrinking (returned)
if (decomp == SPLIT) { // split selected
int cd; // cutting dimension
ANNcoord cv; // cutting value
int n_lo; // number on low side of cut
// invoke splitting procedure
(*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo);
ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension
ANNcoord hv = bnd_box.hi[cd];
bnd_box.hi[cd] = cv; // modify bounds for left subtree
ANNkd_ptr lo = rbd_tree( // build left subtree
pa, pidx, n_lo, // ...from pidx[0..n_lo-1]
dim, bsp, bnd_box, splitter, shrink);
bnd_box.hi[cd] = hv; // restore bounds
bnd_box.lo[cd] = cv; // modify bounds for right subtree
ANNkd_ptr hi = rbd_tree( // build right subtree
pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1]
dim, bsp, bnd_box, splitter, shrink);
bnd_box.lo[cd] = lv; // restore bounds
// create the splitting node
return new ANNkd_split(cd, cv, lv, hv, lo, hi);
}
else { // shrink selected
int n_in; // number of points in box
int n_bnds; // number of bounding sides
annBoxSplit( // split points around inner box
pa, // points to split
pidx, // point indices
n, // number of points
dim, // dimension
inner_box, // inner box
n_in); // number of points inside (returned)
ANNkd_ptr in = rbd_tree( // build inner subtree pidx[0..n_in-1]
pa, pidx, n_in, dim, bsp, inner_box, splitter, shrink);
ANNkd_ptr out = rbd_tree( // build outer subtree pidx[n_in..n]
pa, pidx+n_in, n - n_in, dim, bsp, bnd_box, splitter, shrink);
ANNorthHSArray bnds = NULL; // bounds (alloc in Box2Bnds and
// ...freed in bd_shrink destroyer)
annBox2Bnds( // convert inner box to bounds
inner_box, // inner box
bnd_box, // enclosing box
dim, // dimension
n_bnds, // number of bounds (returned)
bnds); // bounds array (modified)
// return shrinking node
return new ANNbd_shrink(n_bnds, bnds, in, out);
}
}
//----------------------------------------------------------------------
// File: bd_tree.h
// Programmer: David Mount
// Description: Declarations for standard bd-tree routines
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision 1.0 04/01/05
// Changed IN, OUT to ANN_IN, ANN_OUT
//----------------------------------------------------------------------
#ifndef ANN_bd_tree_H
#define ANN_bd_tree_H
#include <ANN/ANNx.h> // all ANN includes
#include "kd_tree.h" // kd-tree includes
//----------------------------------------------------------------------
// bd-tree shrinking node.
// The main addition in the bd-tree is the shrinking node, which
// is declared here.
//
// Shrinking nodes are defined by list of orthogonal halfspaces.
// These halfspaces define a (possibly unbounded) orthogonal
// rectangle. There are two children, in and out. Points that
// lie within this rectangle are stored in the in-child, and the
// other points are stored in the out-child.
//
// We use a list of orthogonal halfspaces rather than an
// orthogonal rectangle object because typically the number of
// sides of the shrinking box will be much smaller than the
// worst case bound of 2*dim.
//
// BEWARE: Note that constructor just copies the pointer to the
// bounding array, but the destructor deallocates it. This is
// rather poor practice, but happens to be convenient. The list
// is allocated in the bd-tree building procedure rbd_tree() just
// prior to construction, and is used for no other purposes.
//
// WARNING: In the near neighbor searching code it is assumed that
// the list of bounding halfspaces is irredundant, meaning that there
// are no two distinct halfspaces in the list with the same outward
// pointing normals.
//----------------------------------------------------------------------
class ANNbd_shrink : public ANNkd_node // splitting node of a kd-tree
{
int n_bnds; // number of bounding halfspaces
ANNorthHSArray bnds; // list of bounding halfspaces
ANNkd_ptr child[2]; // in and out children
public:
ANNbd_shrink( // constructor
int nb, // number of bounding halfspaces
ANNorthHSArray bds, // list of bounding halfspaces
ANNkd_ptr ic=NULL, ANNkd_ptr oc=NULL) // children
{
n_bnds = nb; // cutting dimension
bnds = bds; // assign bounds
child[ANN_IN] = ic; // set children
child[ANN_OUT] = oc;
}
~ANNbd_shrink() // destructor
{
if (child[ANN_IN]!= NULL && child[ANN_IN]!= KD_TRIVIAL)
delete child[ANN_IN];
if (child[ANN_OUT]!= NULL&& child[ANN_OUT]!= KD_TRIVIAL)
delete child[ANN_OUT];
if (bnds != NULL)
delete [] bnds; // delete bounds
}
virtual void getStats( // get tree statistics
int dim, // dimension of space
ANNkdStats &st, // statistics
ANNorthRect &bnd_box); // bounding box
virtual void print(int level, ostream &out);// print node
virtual void dump(ostream &out); // dump node
virtual void ann_search(ANNdist); // standard search
virtual void ann_pri_search(ANNdist); // priority search
virtual void ann_FR_search(ANNdist); // fixed-radius search
};
#endif
//----------------------------------------------------------------------
// File: brute.cpp
// Programmer: Sunil Arya and David Mount
// Description: Brute-force nearest neighbors
// Last modified: 05/03/05 (Version 1.1)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision 1.1 05/03/05
// Added fixed-radius kNN search
//----------------------------------------------------------------------
#include <ANN/ANNx.h> // all ANN includes
#include "pr_queue_k.h" // k element priority queue
//----------------------------------------------------------------------
// Brute-force search simply stores a pointer to the list of
// data points and searches linearly for the nearest neighbor.
// The k nearest neighbors are stored in a k-element priority
// queue (which is implemented in a pretty dumb way as well).
//
// If ANN_ALLOW_SELF_MATCH is ANNfalse then data points at distance
// zero are not considered.
//
// Note that the error bound eps is passed in, but it is ignored.
// These routines compute exact nearest neighbors (which is needed
// for validation purposes in ann_test.cpp).
//----------------------------------------------------------------------
ANNbruteForce::ANNbruteForce( // constructor from point array
ANNpointArray pa, // point array
int n, // number of points
int dd) // dimension
{
dim = dd; n_pts = n; pts = pa;
}
ANNbruteForce::~ANNbruteForce() { } // destructor (empty)
void ANNbruteForce::annkSearch( // approx k near neighbor search
ANNpoint q, // query point
int k, // number of near neighbors to return
ANNidxArray nn_idx, // nearest neighbor indices (returned)
ANNdistArray dd, // dist to near neighbors (returned)
double eps) // error bound (ignored)
{
ANNmin_k mk(k); // construct a k-limited priority queue
int i;
if (k > n_pts) { // too many near neighbors?
annError("Requesting more near neighbors than data points", ANNabort);
}
// run every point through queue
for (i = 0; i < n_pts; i++) {
// compute distance to point
ANNdist sqDist = annDist(dim, pts[i], q);
if (ANN_ALLOW_SELF_MATCH || sqDist != 0)
mk.insert(sqDist, i);
}
for (i = 0; i < k; i++) { // extract the k closest points
dd[i] = mk.ith_smallest_key(i);
nn_idx[i] = mk.ith_smallest_info(i);
}
}
int ANNbruteForce::annkFRSearch( // approx fixed-radius kNN search
ANNpoint q, // query point
ANNdist sqRad, // squared radius
int k, // number of near neighbors to return
ANNidxArray nn_idx, // nearest neighbor array (returned)
ANNdistArray dd, // dist to near neighbors (returned)
double eps) // error bound
{
ANNmin_k mk(k); // construct a k-limited priority queue
int i;
int pts_in_range = 0; // number of points in query range
// run every point through queue
for (i = 0; i < n_pts; i++) {
// compute distance to point
ANNdist sqDist = annDist(dim, pts[i], q);
if (sqDist <= sqRad && // within radius bound
(ANN_ALLOW_SELF_MATCH || sqDist != 0)) { // ...and no self match
mk.insert(sqDist, i);
pts_in_range++;
}
}
for (i = 0; i < k; i++) { // extract the k closest points
if (dd != NULL)
dd[i] = mk.ith_smallest_key(i);
if (nn_idx != NULL)
nn_idx[i] = mk.ith_smallest_info(i);
}
return pts_in_range;
}
//----------------------------------------------------------------------
// File: kd_dump.cc
// Programmer: David Mount
// Description: Dump and Load for kd- and bd-trees
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision 1.0 04/01/05
// Moved dump out of kd_tree.cc into this file.
// Added kd-tree load constructor.
//----------------------------------------------------------------------
// This file contains routines for dumping kd-trees and bd-trees and
// reloading them. (It is an abuse of policy to include both kd- and
// bd-tree routines in the same file, sorry. There should be no problem
// in deleting the bd- versions of the routines if they are not
// desired.)
//----------------------------------------------------------------------
#include "kd_tree.h" // kd-tree declarations
#include "bd_tree.h" // bd-tree declarations
using namespace std; // make std:: available
//----------------------------------------------------------------------
// Constants
//----------------------------------------------------------------------
const int STRING_LEN = 500; // maximum string length
const double EPSILON = 1E-5; // small number for float comparison
enum ANNtreeType {KD_TREE, BD_TREE}; // tree types (used in loading)
//----------------------------------------------------------------------
// Procedure declarations
//----------------------------------------------------------------------
static ANNkd_ptr annReadDump( // read dump file
istream &in, // input stream
ANNtreeType tree_type, // type of tree expected
ANNpointArray &the_pts, // new points (if applic)
ANNidxArray &the_pidx, // point indices (returned)
int &the_dim, // dimension (returned)
int &the_n_pts, // number of points (returned)
int &the_bkt_size, // bucket size (returned)
ANNpoint &the_bnd_box_lo, // low bounding point
ANNpoint &the_bnd_box_hi); // high bounding point
static ANNkd_ptr annReadTree( // read tree-part of dump file
istream &in, // input stream
ANNtreeType tree_type, // type of tree expected
ANNidxArray the_pidx, // point indices (modified)
int &next_idx); // next index (modified)
//----------------------------------------------------------------------
// ANN kd- and bd-tree Dump Format
// The dump file begins with a header containing the version of
// ANN, an optional section containing the points, followed by
// a description of the tree. The tree is printed in preorder.
//
// Format:
// #ANN <version number> <comments> [END_OF_LINE]
// points <dim> <n_pts> (point coordinates: this is optional)
// 0 <xxx> <xxx> ... <xxx> (point indices and coordinates)
// 1 <xxx> <xxx> ... <xxx>
// ...
// tree <dim> <n_pts> <bkt_size>
// <xxx> <xxx> ... <xxx> (lower end of bounding box)
// <xxx> <xxx> ... <xxx> (upper end of bounding box)
// If the tree is null, then a single line "null" is
// output. Otherwise the nodes of the tree are printed
// one per line in preorder. Leaves and splitting nodes
// have the following formats:
// Leaf node:
// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
// Splitting nodes:
// split <cut_dim> <cut_val> <lo_bound> <hi_bound>
//
// For bd-trees:
//
// Shrinking nodes:
// shrink <n_bnds>
// <cut_dim> <cut_val> <side>
// <cut_dim> <cut_val> <side>
// ... (repeated n_bnds times)
//----------------------------------------------------------------------
void ANNkd_tree::Dump( // dump entire tree
ANNbool with_pts, // print points as well?
ostream &out) // output stream
{
out << "#ANN " << ANNversion << "\n";
out.precision(ANNcoordPrec); // use full precision in dumping
if (with_pts) { // print point coordinates
out << "points " << dim << " " << n_pts << "\n";
for (int i = 0; i < n_pts; i++) {
out << i << " ";
annPrintPt(pts[i], dim, out);
out << "\n";
}
}
out << "tree " // print tree elements
<< dim << " "
<< n_pts << " "
<< bkt_size << "\n";
annPrintPt(bnd_box_lo, dim, out); // print lower bound
out << "\n";
annPrintPt(bnd_box_hi, dim, out); // print upper bound
out << "\n";
if (root == NULL) // empty tree?
out << "null\n";
else {
root->dump(out); // invoke printing at root
}
out.precision(0); // restore default precision
}
void ANNkd_split::dump( // dump a splitting node
ostream &out) // output stream
{
out << "split " << cut_dim << " " << cut_val << " ";
out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n";
child[ANN_LO]->dump(out); // print low child
child[ANN_HI]->dump(out); // print high child
}
void ANNkd_leaf::dump( // dump a leaf node
ostream &out) // output stream
{
if (this == KD_TRIVIAL) { // canonical trivial leaf node
out << "leaf 0\n"; // leaf no points
}
else{
out << "leaf " << n_pts;
for (int j = 0; j < n_pts; j++) {
out << " " << bkt[j];
}
out << "\n";
}
}
void ANNbd_shrink::dump( // dump a shrinking node
ostream &out) // output stream
{
out << "shrink " << n_bnds << "\n";
for (int j = 0; j < n_bnds; j++) {
out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n";
}
child[ANN_IN]->dump(out); // print in-child
child[ANN_OUT]->dump(out); // print out-child
}
//----------------------------------------------------------------------
// Load kd-tree from dump file
// This rebuilds a kd-tree which was dumped to a file. The dump
// file contains all the basic tree information according to a
// preorder traversal. We assume that the dump file also contains
// point data. (This is to guarantee the consistency of the tree.)
// If not, then an error is generated.
//
// Indirectly, this procedure allocates space for points, point
// indices, all nodes in the tree, and the bounding box for the
// tree. When the tree is destroyed, all but the points are
// deallocated.
//
// This routine calls annReadDump to do all the work.
//----------------------------------------------------------------------
ANNkd_tree::ANNkd_tree( // build from dump file
istream &in) // input stream for dump file
{
int the_dim; // local dimension
int the_n_pts; // local number of points
int the_bkt_size; // local number of points
ANNpoint the_bnd_box_lo; // low bounding point
ANNpoint the_bnd_box_hi; // high bounding point
ANNpointArray the_pts; // point storage
ANNidxArray the_pidx; // point index storage
ANNkd_ptr the_root; // root of the tree
the_root = annReadDump( // read the dump file
in, // input stream
KD_TREE, // expecting a kd-tree
the_pts, // point array (returned)
the_pidx, // point indices (returned)
the_dim, the_n_pts, the_bkt_size, // basic tree info (returned)
the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned)
// create a skeletal tree
SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
bnd_box_lo = the_bnd_box_lo;
bnd_box_hi = the_bnd_box_hi;
root = the_root; // set the root
}
ANNbd_tree::ANNbd_tree( // build bd-tree from dump file
istream &in) : ANNkd_tree() // input stream for dump file
{
int the_dim; // local dimension
int the_n_pts; // local number of points
int the_bkt_size; // local number of points
ANNpoint the_bnd_box_lo; // low bounding point
ANNpoint the_bnd_box_hi; // high bounding point
ANNpointArray the_pts; // point storage
ANNidxArray the_pidx; // point index storage
ANNkd_ptr the_root; // root of the tree
the_root = annReadDump( // read the dump file
in, // input stream
BD_TREE, // expecting a bd-tree
the_pts, // point array (returned)
the_pidx, // point indices (returned)
the_dim, the_n_pts, the_bkt_size, // basic tree info (returned)
the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned)
// create a skeletal tree
SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
bnd_box_lo = the_bnd_box_lo;
bnd_box_hi = the_bnd_box_hi;
root = the_root; // set the root
}
//----------------------------------------------------------------------
// annReadDump - read a dump file
//
// This procedure reads a dump file, constructs a kd-tree
// and returns all the essential information needed to actually
// construct the tree. Because this procedure is used for
// constructing both kd-trees and bd-trees, the second argument
// is used to indicate which type of tree we are expecting.
//----------------------------------------------------------------------
static ANNkd_ptr annReadDump(
istream &in, // input stream
ANNtreeType tree_type, // type of tree expected
ANNpointArray &the_pts, // new points (returned)
ANNidxArray &the_pidx, // point indices (returned)
int &the_dim, // dimension (returned)
int &the_n_pts, // number of points (returned)
int &the_bkt_size, // bucket size (returned)
ANNpoint &the_bnd_box_lo, // low bounding point (ret'd)
ANNpoint &the_bnd_box_hi) // high bounding point (ret'd)
{
int j;
char str[STRING_LEN]; // storage for string
char version[STRING_LEN]; // ANN version number
ANNkd_ptr the_root = NULL;
//------------------------------------------------------------------
// Input file header
//------------------------------------------------------------------
in >> str; // input header
if (strcmp(str, "#ANN") != 0) { // incorrect header
annError("Incorrect header for dump file", ANNabort);
}
in.getline(version, STRING_LEN); // get version (ignore)
//------------------------------------------------------------------
// Input the points
// An array the_pts is allocated and points are read from
// the dump file.
//------------------------------------------------------------------
in >> str; // get major heading
if (strcmp(str, "points") == 0) { // points section
in >> the_dim; // input dimension
in >> the_n_pts; // number of points
// allocate point storage
the_pts = annAllocPts(the_n_pts, the_dim);
for (int i = 0; i < the_n_pts; i++) { // input point coordinates
ANNidx idx; // point index
in >> idx; // input point index
if (idx < 0 || idx >= the_n_pts) {
annError("Point index is out of range", ANNabort);
}
for (j = 0; j < the_dim; j++) {
in >> the_pts[idx][j]; // read point coordinates
}
}
in >> str; // get next major heading
}
else { // no points were input
annError("Points must be supplied in the dump file", ANNabort);
}
//------------------------------------------------------------------
// Input the tree
// After the basic header information, we invoke annReadTree
// to do all the heavy work. We create our own array of
// point indices (so we can pass them to annReadTree())
// but we do not deallocate them. They will be deallocated
// when the tree is destroyed.
//------------------------------------------------------------------
if (strcmp(str, "tree") == 0) { // tree section
in >> the_dim; // read dimension
in >> the_n_pts; // number of points
in >> the_bkt_size; // bucket size
the_bnd_box_lo = annAllocPt(the_dim); // allocate bounding box pts
the_bnd_box_hi = annAllocPt(the_dim);
for (j = 0; j < the_dim; j++) { // read bounding box low
in >> the_bnd_box_lo[j];
}
for (j = 0; j < the_dim; j++) { // read bounding box low
in >> the_bnd_box_hi[j];
}
the_pidx = new ANNidx[the_n_pts]; // allocate point index array
int next_idx = 0; // number of indices filled
// read the tree and indices
the_root = annReadTree(in, tree_type, the_pidx, next_idx);
if (next_idx != the_n_pts) { // didn't see all the points?
annError("Didn't see as many points as expected", ANNwarn);
}
}
else {
annError("Illegal dump format. Expecting section heading", ANNabort);
}
return the_root;
}
//----------------------------------------------------------------------
// annReadTree - input tree and return pointer
//
// annReadTree reads in a node of the tree, makes any recursive
// calls as needed to input the children of this node (if internal).
// It returns a pointer to the node that was created. An array
// of point indices is given along with a pointer to the next
// available location in the array. As leaves are read, their
// point indices are stored here, and the point buckets point
// to the first entry in the array.
//
// Recall that these are the formats. The tree is given in
// preorder.
//
// Leaf node:
// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
// Splitting nodes:
// split <cut_dim> <cut_val> <lo_bound> <hi_bound>
//
// For bd-trees:
//
// Shrinking nodes:
// shrink <n_bnds>
// <cut_dim> <cut_val> <side>
// <cut_dim> <cut_val> <side>
// ... (repeated n_bnds times)
//----------------------------------------------------------------------
static ANNkd_ptr annReadTree(
istream &in, // input stream
ANNtreeType tree_type, // type of tree expected
ANNidxArray the_pidx, // point indices (modified)
int &next_idx) // next index (modified)
{
char tag[STRING_LEN]; // tag (leaf, split, shrink)
int n_pts; // number of points in leaf
int cd; // cut dimension
ANNcoord cv; // cut value
ANNcoord lb; // low bound
ANNcoord hb; // high bound
int n_bnds; // number of bounding sides
int sd; // which side
in >> tag; // input node tag
if (strcmp(tag, "null") == 0) { // null tree
return NULL;
}
//------------------------------------------------------------------
// Read a leaf
//------------------------------------------------------------------
if (strcmp(tag, "leaf") == 0) { // leaf node
in >> n_pts; // input number of points
int old_idx = next_idx; // save next_idx
if (n_pts == 0) { // trivial leaf
return KD_TRIVIAL;
}
else {
for (int i = 0; i < n_pts; i++) { // input point indices
in >> the_pidx[next_idx++]; // store in array of indices
}
}
return new ANNkd_leaf(n_pts, &the_pidx[old_idx]);
}
//------------------------------------------------------------------
// Read a splitting node
//------------------------------------------------------------------
else if (strcmp(tag, "split") == 0) { // splitting node
in >> cd >> cv >> lb >> hb;
// read low and high subtrees
ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx);
ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx);
// create new node and return
return new ANNkd_split(cd, cv, lb, hb, lc, hc);
}
//------------------------------------------------------------------
// Read a shrinking node (bd-tree only)
//------------------------------------------------------------------
else if (strcmp(tag, "shrink") == 0) { // shrinking node
if (tree_type != BD_TREE) {
annError("Shrinking node not allowed in kd-tree", ANNabort);
}
in >> n_bnds; // number of bounding sides
// allocate bounds array
ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds];
for (int i = 0; i < n_bnds; i++) {
in >> cd >> cv >> sd; // input bounding halfspace
// copy to array
bds[i] = ANNorthHalfSpace(cd, cv, sd);
}
// read inner and outer subtrees
ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx);
ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx);
// create new node and return
return new ANNbd_shrink(n_bnds, bds, ic, oc);
}
else {
annError("Illegal node type in dump file", ANNabort);
exit(0); // to keep the compiler happy
}
}
//----------------------------------------------------------------------
// File: kd_fix_rad_search.cpp
// Programmer: Sunil Arya and David Mount
// Description: Standard kd-tree fixed-radius kNN search
// Last modified: 05/03/05 (Version 1.1)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 1.1 05/03/05
// Initial release
//----------------------------------------------------------------------
#include "kd_fix_rad_search.h" // kd fixed-radius search decls
//----------------------------------------------------------------------
// Approximate fixed-radius k nearest neighbor search
// The squared radius is provided, and this procedure finds the
// k nearest neighbors within the radius, and returns the total
// number of points lying within the radius.
//
// The method used for searching the kd-tree is a variation of the
// nearest neighbor search used in kd_search.cpp, except that the
// radius of the search ball is known. We refer the reader to that
// file for the explanation of the recursive search procedure.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// To keep argument lists short, a number of global variables
// are maintained which are common to all the recursive calls.
// These are given below.
//----------------------------------------------------------------------
int ANNkdFRDim; // dimension of space
ANNpoint ANNkdFRQ; // query point
ANNdist ANNkdFRSqRad; // squared radius search bound
double ANNkdFRMaxErr; // max tolerable squared error
ANNpointArray ANNkdFRPts; // the points
ANNmin_k* ANNkdFRPointMK; // set of k closest points
int ANNkdFRPtsVisited; // total points visited
int ANNkdFRPtsInRange; // number of points in the range
//----------------------------------------------------------------------
// annkFRSearch - fixed radius search for k nearest neighbors
//----------------------------------------------------------------------
int ANNkd_tree::annkFRSearch(
ANNpoint q, // the query point
ANNdist sqRad, // squared radius search bound
int k, // number of near neighbors to return
ANNidxArray nn_idx, // nearest neighbor indices (returned)
ANNdistArray dd, // the approximate nearest neighbor
double eps) // the error bound
{
ANNkdFRDim = dim; // copy arguments to static equivs
ANNkdFRQ = q;
ANNkdFRSqRad = sqRad;
ANNkdFRPts = pts;
ANNkdFRPtsVisited = 0; // initialize count of points visited
ANNkdFRPtsInRange = 0; // ...and points in the range
ANNkdFRMaxErr = ANN_POW(1.0 + eps);
ANN_FLOP(2) // increment floating op count
ANNkdFRPointMK = new ANNmin_k(k); // create set for closest k points
// search starting at the root
root->ann_FR_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
for (int i = 0; i < k; i++) { // extract the k-th closest points
if (dd != NULL)
dd[i] = ANNkdFRPointMK->ith_smallest_key(i);
if (nn_idx != NULL)
nn_idx[i] = ANNkdFRPointMK->ith_smallest_info(i);
}
delete ANNkdFRPointMK; // deallocate closest point set
return ANNkdFRPtsInRange; // return final point count
}
//----------------------------------------------------------------------
// kd_split::ann_FR_search - search a splitting node
// Note: This routine is similar in structure to the standard kNN
// search. It visits the subtree that is closer to the query point
// first. For fixed-radius search, there is no benefit in visiting
// one subtree before the other, but we maintain the same basic
// code structure for the sake of uniformity.
//----------------------------------------------------------------------
void ANNkd_split::ann_FR_search(ANNdist box_dist)
{
// check dist calc term condition
if (ANNmaxPtsVisited != 0 && ANNkdFRPtsVisited > ANNmaxPtsVisited) return;
// distance to cutting plane
ANNcoord cut_diff = ANNkdFRQ[cut_dim] - cut_val;
if (cut_diff < 0) { // left of cutting plane
child[ANN_LO]->ann_FR_search(box_dist);// visit closer child first
ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdFRQ[cut_dim];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
box_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
// visit further child if in range
if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
child[ANN_HI]->ann_FR_search(box_dist);
}
else { // right of cutting plane
child[ANN_HI]->ann_FR_search(box_dist);// visit closer child first
ANNcoord box_diff = ANNkdFRQ[cut_dim] - cd_bnds[ANN_HI];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
box_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
// visit further child if close enough
if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
child[ANN_LO]->ann_FR_search(box_dist);
}
ANN_FLOP(13) // increment floating ops
ANN_SPL(1) // one more splitting node visited
}
//----------------------------------------------------------------------
// kd_leaf::ann_FR_search - search points in a leaf node
// Note: The unreadability of this code is the result of
// some fine tuning to replace indexing by pointer operations.
//----------------------------------------------------------------------
void ANNkd_leaf::ann_FR_search(ANNdist box_dist)
{
register ANNdist dist; // distance to data point
register ANNcoord* pp; // data coordinate pointer
register ANNcoord* qq; // query coordinate pointer
register ANNcoord t;
register int d;
for (int i = 0; i < n_pts; i++) { // check points in bucket
pp = ANNkdFRPts[bkt[i]]; // first coord of next data point
qq = ANNkdFRQ; // first coord of query point
dist = 0;
for(d = 0; d < ANNkdFRDim; d++) {
ANN_COORD(1) // one more coordinate hit
ANN_FLOP(5) // increment floating ops
t = *(qq++) - *(pp++); // compute length and adv coordinate
// exceeds dist to k-th smallest?
if( (dist = ANN_SUM(dist, ANN_POW(t))) > ANNkdFRSqRad) {
break;
}
}
if (d >= ANNkdFRDim && // among the k best?
(ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
// add it to the list
ANNkdFRPointMK->insert(dist, bkt[i]);
ANNkdFRPtsInRange++; // increment point count
}
}
ANN_LEAF(1) // one more leaf node visited
ANN_PTS(n_pts) // increment points visited
ANNkdFRPtsVisited += n_pts; // increment number of points visited
}
//----------------------------------------------------------------------
// File: kd_fix_rad_search.h
// Programmer: Sunil Arya and David Mount
// Description: Standard kd-tree fixed-radius kNN search
// Last modified: ??/??/?? (Version 1.1)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 1.1 ??/??/??
// Initial release
//----------------------------------------------------------------------
#ifndef ANN_kd_fix_rad_search_H
#define ANN_kd_fix_rad_search_H
#include "kd_tree.h" // kd-tree declarations
#include "kd_util.h" // kd-tree utilities
#include "pr_queue_k.h" // k-element priority queue
#include <ANN/ANNperf.h> // performance evaluation
//----------------------------------------------------------------------
// Global variables
// These are active for the life of each call to
// annRangeSearch(). They are set to save the number of
// variables that need to be passed among the various search
// procedures.
//----------------------------------------------------------------------
extern ANNpoint ANNkdFRQ; // query point (static copy)
#endif
//----------------------------------------------------------------------
// File: kd_pr_search.cpp
// Programmer: Sunil Arya and David Mount
// Description: Priority search for kd-trees
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
//----------------------------------------------------------------------
#include "kd_pr_search.h" // kd priority search declarations
//----------------------------------------------------------------------
// Approximate nearest neighbor searching by priority search.
// The kd-tree is searched for an approximate nearest neighbor.
// The point is returned through one of the arguments, and the
// distance returned is the SQUARED distance to this point.
//
// The method used for searching the kd-tree is called priority
// search. (It is described in Arya and Mount, ``Algorithms for
// fast vector quantization,'' Proc. of DCC '93: Data Compression
// Conference}, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
// 381--390.)
//
// The cell of the kd-tree containing the query point is located,
// and cells are visited in increasing order of distance from the
// query point. This is done by placing each subtree which has
// NOT been visited in a priority queue, according to the closest
// distance of the corresponding enclosing rectangle from the
// query point. The search stops when the distance to the nearest
// remaining rectangle exceeds the distance to the nearest point
// seen by a factor of more than 1/(1+eps). (Implying that any
// point found subsequently in the search cannot be closer by more
// than this factor.)
//
// The main entry point is annkPriSearch() which sets things up and
// then call the recursive routine ann_pri_search(). This is a
// recursive routine which performs the processing for one node in
// the kd-tree. There are two versions of this virtual procedure,
// one for splitting nodes and one for leaves. When a splitting node
// is visited, we determine which child to continue the search on
// (the closer one), and insert the other child into the priority
// queue. When a leaf is visited, we compute the distances to the
// points in the buckets, and update information on the closest
// points.
//
// Some trickery is used to incrementally update the distance from
// a kd-tree rectangle to the query point. This comes about from
// the fact that which each successive split, only one component
// (along the dimension that is split) of the squared distance to
// the child rectangle is different from the squared distance to
// the parent rectangle.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// To keep argument lists short, a number of global variables
// are maintained which are common to all the recursive calls.
// These are given below.
//----------------------------------------------------------------------
double ANNprEps; // the error bound
int ANNprDim; // dimension of space
ANNpoint ANNprQ; // query point
double ANNprMaxErr; // max tolerable squared error
ANNpointArray ANNprPts; // the points
ANNpr_queue *ANNprBoxPQ; // priority queue for boxes
ANNmin_k *ANNprPointMK; // set of k closest points
//----------------------------------------------------------------------
// annkPriSearch - priority search for k nearest neighbors
//----------------------------------------------------------------------
void ANNkd_tree::annkPriSearch(
ANNpoint q, // query point
int k, // number of near neighbors to return
ANNidxArray nn_idx, // nearest neighbor indices (returned)
ANNdistArray dd, // dist to near neighbors (returned)
double eps) // error bound (ignored)
{
// max tolerable squared error
ANNprMaxErr = ANN_POW(1.0 + eps);
ANN_FLOP(2) // increment floating ops
ANNprDim = dim; // copy arguments to static equivs
ANNprQ = q;
ANNprPts = pts;
ANNptsVisited = 0; // initialize count of points visited
ANNprPointMK = new ANNmin_k(k); // create set for closest k points
// distance to root box
ANNdist box_dist = annBoxDistance(q,
bnd_box_lo, bnd_box_hi, dim);
ANNprBoxPQ = new ANNpr_queue(n_pts);// create priority queue for boxes
ANNprBoxPQ->insert(box_dist, root); // insert root in priority queue
while (ANNprBoxPQ->non_empty() &&
(!(ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited))) {
ANNkd_ptr np; // next box from prior queue
// extract closest box from queue
ANNprBoxPQ->extr_min(box_dist, (void *&) np);
ANN_FLOP(2) // increment floating ops
if (box_dist*ANNprMaxErr >= ANNprPointMK->max_key())
break;
np->ann_pri_search(box_dist); // search this subtree.
}
for (int i = 0; i < k; i++) { // extract the k-th closest points
dd[i] = ANNprPointMK->ith_smallest_key(i);
nn_idx[i] = ANNprPointMK->ith_smallest_info(i);
}
delete ANNprPointMK; // deallocate closest point set
delete ANNprBoxPQ; // deallocate priority queue
}
//----------------------------------------------------------------------
// kd_split::ann_pri_search - search a splitting node
//----------------------------------------------------------------------
void ANNkd_split::ann_pri_search(ANNdist box_dist)
{
ANNdist new_dist; // distance to child visited later
// distance to cutting plane
ANNcoord cut_diff = ANNprQ[cut_dim] - cut_val;
if (cut_diff < 0) { // left of cutting plane
ANNcoord box_diff = cd_bnds[ANN_LO] - ANNprQ[cut_dim];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
new_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
if (child[ANN_HI] != KD_TRIVIAL)// enqueue if not trivial
ANNprBoxPQ->insert(new_dist, child[ANN_HI]);
// continue with closer child
child[ANN_LO]->ann_pri_search(box_dist);
}
else { // right of cutting plane
ANNcoord box_diff = ANNprQ[cut_dim] - cd_bnds[ANN_HI];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
new_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
if (child[ANN_LO] != KD_TRIVIAL)// enqueue if not trivial
ANNprBoxPQ->insert(new_dist, child[ANN_LO]);
// continue with closer child
child[ANN_HI]->ann_pri_search(box_dist);
}
ANN_SPL(1) // one more splitting node visited
ANN_FLOP(8) // increment floating ops
}
//----------------------------------------------------------------------
// kd_leaf::ann_pri_search - search points in a leaf node
//
// This is virtually identical to the ann_search for standard search.
//----------------------------------------------------------------------
void ANNkd_leaf::ann_pri_search(ANNdist box_dist)
{
register ANNdist dist; // distance to data point
register ANNcoord* pp; // data coordinate pointer
register ANNcoord* qq; // query coordinate pointer
register ANNdist min_dist; // distance to k-th closest point
register ANNcoord t;
register int d;
min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far
for (int i = 0; i < n_pts; i++) { // check points in bucket
pp = ANNprPts[bkt[i]]; // first coord of next data point
qq = ANNprQ; // first coord of query point
dist = 0;
for(d = 0; d < ANNprDim; d++) {
ANN_COORD(1) // one more coordinate hit
ANN_FLOP(4) // increment floating ops
t = *(qq++) - *(pp++); // compute length and adv coordinate
// exceeds dist to k-th smallest?
if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
break;
}
}
if (d >= ANNprDim && // among the k best?
(ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
// add it to the list
ANNprPointMK->insert(dist, bkt[i]);
min_dist = ANNprPointMK->max_key();
}
}
ANN_LEAF(1) // one more leaf node visited
ANN_PTS(n_pts) // increment points visited
ANNptsVisited += n_pts; // increment number of points visited
}
//----------------------------------------------------------------------
// File: kd_pr_search.h
// Programmer: Sunil Arya and David Mount
// Description: Priority kd-tree search
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
//----------------------------------------------------------------------
#ifndef ANN_kd_pr_search_H
#define ANN_kd_pr_search_H
#include "kd_tree.h" // kd-tree declarations
#include "kd_util.h" // kd-tree utilities
#include "pr_queue.h" // priority queue declarations
#include "pr_queue_k.h" // k-element priority queue
#include <ANN/ANNperf.h> // performance evaluation
//----------------------------------------------------------------------
// Global variables
// Active for the life of each call to Appx_Near_Neigh() or
// Appx_k_Near_Neigh().
//----------------------------------------------------------------------
extern double ANNprEps; // the error bound
extern int ANNprDim; // dimension of space
extern ANNpoint ANNprQ; // query point
extern double ANNprMaxErr; // max tolerable squared error
extern ANNpointArray ANNprPts; // the points
extern ANNpr_queue *ANNprBoxPQ; // priority queue for boxes
extern ANNmin_k *ANNprPointMK; // set of k closest points
#endif
//----------------------------------------------------------------------
// File: kd_search.cpp
// Programmer: Sunil Arya and David Mount
// Description: Standard kd-tree search
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
// Revision 1.0 04/01/05
// Changed names LO, HI to ANN_LO, ANN_HI
//----------------------------------------------------------------------
#include "kd_search.h" // kd-search declarations
//----------------------------------------------------------------------
// Approximate nearest neighbor searching by kd-tree search
// The kd-tree is searched for an approximate nearest neighbor.
// The point is returned through one of the arguments, and the
// distance returned is the squared distance to this point.
//
// The method used for searching the kd-tree is an approximate
// adaptation of the search algorithm described by Friedman,
// Bentley, and Finkel, ``An algorithm for finding best matches
// in logarithmic expected time,'' ACM Transactions on Mathematical
// Software, 3(3):209-226, 1977).
//
// The algorithm operates recursively. When first encountering a
// node of the kd-tree we first visit the child which is closest to
// the query point. On return, we decide whether we want to visit
// the other child. If the box containing the other child exceeds
// 1/(1+eps) times the current best distance, then we skip it (since
// any point found in this child cannot be closer to the query point
// by more than this factor.) Otherwise, we visit it recursively.
// The distance between a box and the query point is computed exactly
// (not approximated as is often done in kd-tree), using incremental
// distance updates, as described by Arya and Mount in ``Algorithms
// for fast vector quantization,'' Proc. of DCC '93: Data Compression
// Conference, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
// 381-390.
//
// The main entry points is annkSearch() which sets things up and
// then call the recursive routine ann_search(). This is a recursive
// routine which performs the processing for one node in the kd-tree.
// There are two versions of this virtual procedure, one for splitting
// nodes and one for leaves. When a splitting node is visited, we
// determine which child to visit first (the closer one), and visit
// the other child on return. When a leaf is visited, we compute
// the distances to the points in the buckets, and update information
// on the closest points.
//
// Some trickery is used to incrementally update the distance from
// a kd-tree rectangle to the query point. This comes about from
// the fact that which each successive split, only one component
// (along the dimension that is split) of the squared distance to
// the child rectangle is different from the squared distance to
// the parent rectangle.
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// To keep argument lists short, a number of global variables
// are maintained which are common to all the recursive calls.
// These are given below.
//----------------------------------------------------------------------
int ANNkdDim; // dimension of space
ANNpoint ANNkdQ; // query point
double ANNkdMaxErr; // max tolerable squared error
ANNpointArray ANNkdPts; // the points
ANNmin_k *ANNkdPointMK; // set of k closest points
//----------------------------------------------------------------------
// annkSearch - search for the k nearest neighbors
//----------------------------------------------------------------------
void ANNkd_tree::annkSearch(
ANNpoint q, // the query point
int k, // number of near neighbors to return
ANNidxArray nn_idx, // nearest neighbor indices (returned)
ANNdistArray dd, // the approximate nearest neighbor
double eps) // the error bound
{
ANNkdDim = dim; // copy arguments to static equivs
ANNkdQ = q;
ANNkdPts = pts;
ANNptsVisited = 0; // initialize count of points visited
if (k > n_pts) { // too many near neighbors?
annError("Requesting more near neighbors than data points", ANNabort);
}
ANNkdMaxErr = ANN_POW(1.0 + eps);
ANN_FLOP(2) // increment floating op count
ANNkdPointMK = new ANNmin_k(k); // create set for closest k points
// search starting at the root
root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
for (int i = 0; i < k; i++) { // extract the k-th closest points
dd[i] = ANNkdPointMK->ith_smallest_key(i);
nn_idx[i] = ANNkdPointMK->ith_smallest_info(i);
}
delete ANNkdPointMK; // deallocate closest point set
}
//----------------------------------------------------------------------
// kd_split::ann_search - search a splitting node
//----------------------------------------------------------------------
void ANNkd_split::ann_search(ANNdist box_dist)
{
// check dist calc term condition
if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
// distance to cutting plane
ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val;
if (cut_diff < 0) { // left of cutting plane
child[ANN_LO]->ann_search(box_dist);// visit closer child first
ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
box_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
// visit further child if close enough
if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
child[ANN_HI]->ann_search(box_dist);
}
else { // right of cutting plane
child[ANN_HI]->ann_search(box_dist);// visit closer child first
ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
box_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
// visit further child if close enough
if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
child[ANN_LO]->ann_search(box_dist);
}
ANN_FLOP(10) // increment floating ops
ANN_SPL(1) // one more splitting node visited
}
//----------------------------------------------------------------------
// kd_leaf::ann_search - search points in a leaf node
// Note: The unreadability of this code is the result of
// some fine tuning to replace indexing by pointer operations.
//----------------------------------------------------------------------
void ANNkd_leaf::ann_search(ANNdist box_dist)
{
register ANNdist dist; // distance to data point
register ANNcoord* pp; // data coordinate pointer
register ANNcoord* qq; // query coordinate pointer
register ANNdist min_dist; // distance to k-th closest point
register ANNcoord t;
register int d;
min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far
for (int i = 0; i < n_pts; i++) { // check points in bucket
pp = ANNkdPts[bkt[i]]; // first coord of next data point
qq = ANNkdQ; // first coord of query point
dist = 0;
for(d = 0; d < ANNkdDim; d++) {
ANN_COORD(1) // one more coordinate hit
ANN_FLOP(4) // increment floating ops
t = *(qq++) - *(pp++); // compute length and adv coordinate
// exceeds dist to k-th smallest?
if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
break;
}
}
if (d >= ANNkdDim && // among the k best?
(ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
// add it to the list
ANNkdPointMK->insert(dist, bkt[i]);
min_dist = ANNkdPointMK->max_key();
}
}
ANN_LEAF(1) // one more leaf node visited
ANN_PTS(n_pts) // increment points visited
ANNptsVisited += n_pts; // increment number of points visited
}
//----------------------------------------------------------------------
// File: kd_search.h
// Programmer: Sunil Arya and David Mount
// Description: Standard kd-tree search
// Last modified: 01/04/05 (Version 1.0)
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount. All Rights Reserved.
//
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN). This software is provided under
// the provisions of the Lesser GNU Public License (LGPL). See the
// file ../ReadMe.txt for further information.
//
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose. It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
// Revision 0.1 03/04/98
// Initial release
//----------------------------------------------------------------------
#ifndef ANN_kd_search_H
#define ANN_kd_search_H
#include "kd_tree.h" // kd-tree declarations
#include "kd_util.h" // kd-tree utilities
#include "pr_queue_k.h" // k-element priority queue
#include <ANN/ANNperf.h> // performance evaluation
//----------------------------------------------------------------------
// More global variables
// These are active for the life of each call to annkSearch(). They
// are set to save the number of variables that need to be passed
// among the various search procedures.
//----------------------------------------------------------------------
extern int ANNkdDim; // dimension of space (static copy)
extern ANNpoint ANNkdQ; // query point (static copy)
extern double ANNkdMaxErr; // max tolerable squared error
extern ANNpointArray ANNkdPts; // the points (static copy)
extern ANNmin_k *ANNkdPointMK; // set of k closest points
extern int ANNptsVisited; // number of points visited
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment