📄 kdtree2.cpp
字号:
//// (c) Matthew B. Kennel, Institute for Nonlinear Science, UCSD (2004)//// Licensed under the Academic Free License version 1.1 found in file LICENSE// with additional provisions in that same file.#include "kdtree2.hpp"#include <algorithm> #include <iostream>// utilityinline float squared(const float x) { return(x*x);}inline void swap(int& a, int&b) { int tmp; tmp = a; a = b; b = tmp; }inline void swap(float& a, float&b) { float tmp; tmp = a; a = b; b = tmp; }//// KDTREE2_RESULT implementation// inline bool operator<(const kdtree2_result& e1, const kdtree2_result& e2) { return (e1.dis < e2.dis);}//// KDTREE2_RESULT_VECTOR implementation// float kdtree2_result_vector::max_value() { return( (*begin()).dis ); // very first element}void kdtree2_result_vector::push_element_and_heapify(kdtree2_result& e) { push_back(e); // what a vector does. push_heap( begin(), end() ); // and now heapify it, with the new elt.}float kdtree2_result_vector::replace_maxpri_elt_return_new_maxpri(kdtree2_result& e) { // remove the maximum priority element on the queue and replace it // with 'e', and return its priority. // // here, it means replacing the first element [0] with e, and re heapifying. pop_heap( begin(), end() ); pop_back(); push_back(e); // insert new push_heap(begin(), end() ); // and heapify. return( (*this)[0].dis );}//// KDTREE2 implementation//// constructorkdtree2::kdtree2(kdtree2_array& data_in,bool rearrange_in,int dim_in) : the_data(data_in), N ( data_in.shape()[0] ), dim( data_in.shape()[1] ), sort_results(false), rearrange(rearrange_in), root(NULL), data(NULL), ind(N){ // // initialize the constant references using this unusual C++ // feature. // if (dim_in > 0) dim = dim_in; build_tree(); if (rearrange) { // if we have a rearranged tree. // allocate the memory for it. printf("rearranging\n"); rearranged_data.resize( extents[N][dim] ); // permute the data for it. for (int i=0; i<N; i++) { for (int j=0; j<dim; j++) { rearranged_data[i][j] = the_data[ind[i]][j]; // wouldn't F90 be nice here? } } data = &rearranged_data; } else { data = &the_data; }}// destructorkdtree2::~kdtree2() { delete root;}// building routinesvoid kdtree2::build_tree() { for (int i=0; i<N; i++) ind[i] = i; root = build_tree_for_range(0,N-1,NULL); }kdtree2_node* kdtree2::build_tree_for_range(int l, int u, kdtree2_node* parent) { // recursive function to build kdtree2_node* node = new kdtree2_node(dim); // the newly created node. if (u<l) { return(NULL); // no data in this node. } if ((u-l) <= bucketsize) { // create a terminal node. // always compute true bounding box for terminal node. for (int i=0;i<dim;i++) { spread_in_coordinate(i,l,u,node->box[i]); } node->cut_dim = 0; node->cut_val = 0.0; node->l = l; node->u = u; node->left = node->right = NULL; } else { // // Compute an APPROXIMATE bounding box for this node. // if parent == NULL, then this is the root node, and // we compute for all dimensions. // Otherwise, we copy the bounding box from the parent for // all coordinates except for the parent's cut dimension. // That, we recompute ourself. // int c = -1; float maxspread = 0.0; int m; for (int i=0;i<dim;i++) { if ((parent == NULL) || (parent->cut_dim == i)) { spread_in_coordinate(i,l,u,node->box[i]); } else { node->box[i] = parent->box[i]; } float spread = node->box[i].upper - node->box[i].lower; if (spread>maxspread) { maxspread = spread; c=i; } } // // now, c is the identity of which coordinate has the greatest spread // if (false) { m = (l+u)/2; select_on_coordinate(c,m,l,u); } else { float sum; float average; if (true) { sum = 0.0; for (int k=l; k <= u; k++) { sum += the_data[ind[k]][c]; } average = sum / static_cast<float> (u-l+1); } else { // average of top and bottom nodes. average = (node->box[c].upper + node->box[c].lower)*0.5; } m = select_on_coordinate_value(c,average,l,u); } // move the indices around to cut on dim 'c'. node->cut_dim=c; node->l = l; node->u = u; node->left = build_tree_for_range(l,m,node); node->right = build_tree_for_range(m+1,u,node); if (node->right == NULL) { for (int i=0; i<dim; i++) node->box[i] = node->left->box[i]; node->cut_val = node->left->box[c].upper; node->cut_val_left = node->cut_val_right = node->cut_val; } else if (node->left == NULL) { for (int i=0; i<dim; i++) node->box[i] = node->right->box[i]; node->cut_val = node->right->box[c].upper; node->cut_val_left = node->cut_val_right = node->cut_val; } else { node->cut_val_right = node->right->box[c].lower; node->cut_val_left = node->left->box[c].upper; node->cut_val = (node->cut_val_left + node->cut_val_right) / 2.0; // // now recompute true bounding box as union of subtree boxes. // This is now faster having built the tree, being logarithmic in // N, not linear as would be from naive method. // for (int i=0; i<dim; i++) { node->box[i].upper = max(node->left->box[i].upper, node->right->box[i].upper); node->box[i].lower = min(node->left->box[i].lower, node->right->box[i].lower); } } } return(node);}void kdtree2:: spread_in_coordinate(int c, int l, int u, interval& interv){ // return the minimum and maximum of the indexed data between l and u in // smin_out and smax_out. float smin, smax; float lmin, lmax; int i; smin = the_data[ind[l]][c]; smax = smin; // process two at a time. for (i=l+2; i<= u; i+=2) { lmin = the_data[ind[i-1]] [c]; lmax = the_data[ind[i] ] [c]; if (lmin > lmax) { swap(lmin,lmax); // float t = lmin; // lmin = lmax; // lmax = t; } if (smin > lmin) smin = lmin; if (smax <lmax) smax = lmax; } // is there one more element? if (i == u+1) { float last = the_data[ind[u]] [c]; if (smin>last) smin = last; if (smax<last) smax = last; } interv.lower = smin; interv.upper = smax; // printf("Spread in coordinate %d=[%f,%f]\n",c,smin,smax);}void kdtree2::select_on_coordinate(int c, int k, int l, int u) { // // Move indices in ind[l..u] so that the elements in [l .. k] // are less than the [k+1..u] elmeents, viewed across dimension 'c'. // while (l < u) { int t = ind[l]; int m = l; for (int i=l+1; i<=u; i++) { if ( the_data[ ind[i] ] [c] < the_data[t][c]) { m++; swap(ind[i],ind[m]); } } // for i swap(ind[l],ind[m]); if (m <= k) l = m+1; if (m >= k) u = m-1; } // while loop}int kdtree2::select_on_coordinate_value(int c, float alpha, int l, int u) { // // Move indices in ind[l..u] so that the elements in [l .. return] // are <= alpha, and hence are less than the [return+1..u] // elmeents, viewed across dimension 'c'. // int lb = l, ub = u; while (lb < ub) { if (the_data[ind[lb]][c] <= alpha) { lb++; // good where it is. } else { swap(ind[lb],ind[ub]); ub--; } } // here ub=lb if (the_data[ind[lb]][c] <= alpha) return(lb); else return(lb-1); }// void kdtree2::dump_data() {// int upper1, upper2; // upper1 = N;// upper2 = dim;// printf("Rearrange=%d\n",rearrange);// printf("N=%d, dim=%d\n", upper1, upper2);// for (int i=0; i<upper1; i++) {// printf("the_data[%d][*]=",i); // for (int j=0; j<upper2; j++)// printf("%f,",the_data[i][j]); // printf("\n"); // }// for (int i=0; i<upper1; i++)// printf("Indexes[%d]=%d\n",i,ind[i]); // for (int i=0; i<upper1; i++) {// printf("data[%d][*]=",i); // for (int j=0; j<upper2; j++)// printf("%f,",(*data)[i][j]); // printf("\n"); // }// }//// search record substructure//// one of these is created for each search.// this holds useful information to be used// during the searchstatic const float infinity = 1.0e38;class searchrecord {private: friend class kdtree2; friend class kdtree2_node; vector<float>& qv; int dim; bool rearrange; unsigned int nn; // , nfound; float ballsize; int centeridx, correltime; kdtree2_result_vector& result; // results const kdtree2_array* data; const vector<int>& ind; // constructorpublic: searchrecord(vector<float>& qv_in, kdtree2& tree_in, kdtree2_result_vector& result_in) : qv(qv_in), result(result_in), data(tree_in.data), ind(tree_in.ind) { dim = tree_in.dim; rearrange = tree_in.rearrange; ballsize = infinity; nn = 0; };};void kdtree2::n_nearest_brute_force(vector<float>& qv, int nn, kdtree2_result_vector& result) { result.clear(); for (int i=0; i<N; i++) { float dis = 0.0; kdtree2_result e;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -