knnbench.cpp
Go to the documentation of this file.
1 /*
2 
3 Copyright (c) 2010--2011, Stephane Magnenat, ASL, ETHZ, Switzerland
4 You can contact the author at <stephane at magnenat dot net>
5 
6 All rights reserved.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10  * Redistributions of source code must retain the above copyright
11  notice, this list of conditions and the following disclaimer.
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15  * Neither the name of the <organization> nor the
16  names of its contributors may be used to endorse or promote products
17  derived from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL ETH-ASL BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 */
31 
32 // currently disable FLANN
33 #undef HAVE_FLANN
34 
35 #include "nabo/nabo.h"
37 #include "helpers.h"
38 #ifdef HAVE_ANN
39  #include "ANN.h"
40 #endif // HAVE_ANN
41 #ifdef HAVE_FLANN
42  #include "flann/flann.hpp"
43 #endif // HAVE_FLANN
44 #include <iostream>
45 #include <fstream>
46 #include <stdexcept>
47 
48 using namespace std;
49 using namespace Nabo;
50 
61 // typedef Nabo::KDTreeBalancedPtInNodesPQ<double> KDTD1;
62 // typedef Nabo::KDTreeBalancedPtInNodesStack<double> KDTD2;
63 // struct KDTD3: public Nabo::KDTreeBalancedPtInLeavesStack<double>
64 // {
65 // KDTD3(const Matrix& cloud):
66 // Nabo::KDTreeBalancedPtInLeavesStack<double>(cloud, true)
67 // {}
68 // };
69 // struct KDTD4: public Nabo::KDTreeBalancedPtInLeavesStack<double>
70 // {
71 // KDTD4(const Matrix& cloud):
72 // Nabo::KDTreeBalancedPtInLeavesStack<double>(cloud, false)
73 // {}
74 // };
75 // typedef Nabo::KDTreeUnbalancedPtInLeavesImplicitBoundsStack<double,IndexHeapSTL<int,double>> KDTD5A;
76 // typedef Nabo::KDTreeUnbalancedPtInLeavesImplicitBoundsStack<double,IndexHeapBruteForceVector<int,double>> KDTD5B;
77 // typedef Nabo::KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapBruteForceVector<int,double>> KDTD5OB;
78 // typedef Nabo::KDTreeUnbalancedPtInLeavesImplicitBoundsStackOpt<double,IndexHeapSTL<int,double>> KDTD5OA;
79 // typedef Nabo::KDTreeUnbalancedPtInLeavesExplicitBoundsStack<double> KDTD6;
80 
81 
82 
83 
85 {
88  double visitCount;
89  double totalCount;
90 
92  creationDuration(0),
93  executionDuration(0),
94  visitCount(0),
95  totalCount(0)
96  {}
97 
98  void operator +=(const BenchResult& that)
99  {
100  creationDuration += that.creationDuration;
101  executionDuration += that.executionDuration;
102  visitCount += that.visitCount;
103  totalCount += that.totalCount;
104  }
105 
106  void operator /=(const double factor)
107  {
108  creationDuration /= factor;
109  executionDuration /= factor;
110  visitCount /= factor;
111  totalCount /= factor;
112  }
113 };
114 typedef vector<BenchResult> BenchResults;
115 
116 // template<typename T>
117 // BenchResult doBench(const Matrix& d, const Matrix& q, const Index K, const int itCount)
118 // {
119 // BenchResult result;
120 // timer t;
121 // T nns(d);
122 // result.creationDuration = t.elapsed();
123 //
124 // t.restart();
125 // nns.knnM(q, K, 0, 0);
126 // result.executionDuration = t.elapsed();
127 //
128 // result.visitCount = double(nns.getStatistics().totalVisitCount);
129 // result.totalCount = double(itCount) * double(d.cols());
130 //
131 // return result;
132 // }
133 
134 template<typename T>
136  const unsigned creationOptionFlags,
137  const typename NearestNeighbourSearch<T>::Matrix& d,
138  const typename NearestNeighbourSearch<T>::Matrix& q,
139  const int K,
140  const int /*itCount*/,
141  const int searchCount)
142 {
143  typedef NearestNeighbourSearch<T> nnsT;
144  typedef typename NearestNeighbourSearch<T>::Matrix Matrix;
145  typedef typename NearestNeighbourSearch<T>::IndexMatrix IndexMatrix;
146 
147  BenchResult result;
148  timer t;
149  nnsT* nns(nnsT::create(d, d.rows(), type, creationOptionFlags));
150  result.creationDuration = t.elapsed();
151 
152  for (int s = 0; s < searchCount; ++s)
153  {
154  t.restart();
155  IndexMatrix indices(K, q.cols());
156  Matrix dists2(K, q.cols());
157  const unsigned long visitCount = nns->knn(q, indices, dists2, K, 0, 0);
158  result.executionDuration += t.elapsed();
159  result.visitCount += double(visitCount);
160  }
161  result.executionDuration /= double(searchCount);
162  result.visitCount /= double(searchCount);
163 
164  delete nns;
165 
166  result.totalCount = double(q.cols()) * double(d.cols());
167 
168  return result;
169 }
170 
171 #ifdef HAVE_ANN
172 
173 BenchResult doBenchANNStack(const MatrixD& d, const MatrixD& q, const int K, const int itCount, const int searchCount)
174 {
175  BenchResult result;
176  timer t;
177  const int ptCount(d.cols());
178  const double **pa = new const double *[d.cols()];
179  for (int i = 0; i < ptCount; ++i)
180  pa[i] = &d.coeff(0, i);
181  ANNkd_tree* ann_kdt = new ANNkd_tree(const_cast<double**>(pa), ptCount, d.rows(), 8);
182  result.creationDuration = t.elapsed();
183 
184  for (int s = 0; s < searchCount; ++s)
185  {
186  t.restart();
187  ANNidx nnIdx[K];
188  ANNdist dists[K];
189  for (int i = 0; i < itCount; ++i)
190  {
191  const VectorD& tq(q.col(i));
192  ANNpoint queryPt(const_cast<double*>(&tq.coeff(0)));
193  ann_kdt->annkSearch( // search
194  queryPt, // query point
195  K, // number of near neighbours
196  nnIdx, // nearest neighbours (returned)
197  dists, // distance (returned)
198  0); // error bound
199  }
200  result.executionDuration += t.elapsed();
201  }
202  result.executionDuration /= double(searchCount);
203 
204  return result;
205 }
206 
207 BenchResult doBenchANNPriority(const MatrixD& d, const MatrixD& q, const int K, const int itCount, const int searchCount)
208 {
209  BenchResult result;
210  timer t;
211  const int ptCount(d.cols());
212  const double **pa = new const double *[d.cols()];
213  for (int i = 0; i < ptCount; ++i)
214  pa[i] = &d.coeff(0, i);
215  ANNkd_tree* ann_kdt = new ANNkd_tree(const_cast<double**>(pa), ptCount, d.rows(), 8);
216  result.creationDuration = t.elapsed();
217 
218  for (int s = 0; s < searchCount; ++s)
219  {
220  t.restart();
221  ANNidx nnIdx[K];
222  ANNdist dists[K];
223  for (int i = 0; i < itCount; ++i)
224  {
225  const VectorD& tq(q.col(i));
226  ANNpoint queryPt(const_cast<double*>(&tq.coeff(0)));
227  ann_kdt->annkPriSearch( // search
228  queryPt, // query point
229  K, // number of near neighbours
230  nnIdx, // nearest neighbours (returned)
231  dists, // distance (returned)
232  0); // error bound
233  }
234  result.executionDuration += t.elapsed();
235  }
236  result.executionDuration /= double(searchCount);
237 
238  return result;
239 }
240 
241 #endif // HAVE_ANN
242 
243 #ifdef HAVE_FLANN
244 
245 template<typename T>
246 BenchResult doBenchFLANN(const Matrix& d, const Matrix& q, const Index K, const int itCount)
247 {
248  BenchResult result;
249  const int dimCount(d.rows());
250  const int dPtCount(d.cols());
251  const int qPtCount(itCount);
252 
253  flann::Matrix<T> dataset(new T[dPtCount*dimCount], dPtCount, dimCount);
254  for (int point = 0; point < dPtCount; ++point)
255  for (int dim = 0; dim < dimCount; ++dim)
256  dataset[point][dim] = d(dim, point);
257  flann::Matrix<T> query(new T[qPtCount*dimCount], qPtCount, dimCount);
258  for (int point = 0; point < qPtCount; ++point)
259  for (int dim = 0; dim < dimCount; ++dim)
260  query[point][dim] = q(dim, point);
261 
262  flann::Matrix<int> indices(new int[query.rows*K], query.rows, K);
263  flann::Matrix<float> dists(new float[query.rows*K], query.rows, K);
264 
265  // construct an randomized kd-tree index using 4 kd-trees
266  timer t;
267  flann::Index<T> index(dataset, flann::KDTreeIndexParams(4) /*flann::AutotunedIndexParams(0.9)*/); // exact search
268  index.buildIndex();
269  result.creationDuration = t.elapsed();
270 
271  t.restart();
272  // do a knn search, using 128 checks
273  index.knnSearch(query, indices, dists, int(K), flann::SearchParams(128)); // last parameter ignored because of autotuned
274  result.executionDuration = t.elapsed();
275 
276  dataset.free();
277  query.free();
278  indices.free();
279  dists.free();
280 
281  return result;
282 }
283 
284 #endif // HAVE_FLANN
285 
286 
287 int main(int argc, char* argv[])
288 {
289  if (argc != 6)
290  {
291  cerr << "Usage " << argv[0] << " DATA K METHOD RUN_COUNT SEARCH_COUNT" << endl;
292  return 1;
293  }
294 
295  const MatrixD dD(load<double>(argv[1]));
296  const MatrixF dF(load<float>(argv[1]));
297  const int K(atoi(argv[2]));
298  const int method(atoi(argv[3]));
299  const int itCount(method >= 0 ? method : dD.cols() * 2);
300  const int runCount(atoi(argv[4]));
301  const int searchCount(atoi(argv[5]));
302 
303  // compare KDTree with brute force search
304  if (K >= dD.cols())
305  {
306  cerr << "Requested more nearest neighbour than points in the data set" << endl;
307  return 2;
308  }
309 
310  // create queries
311  MatrixD qD(createQuery<double>(dD, itCount, method));
312  MatrixF qF(createQuery<float>(dF, itCount, method));
313 
314  const char* benchLabels[] =
315  {
316  //doBench<KDTD1>("Nabo, pt in nodes, priority, balance variance",
317  //doBench<KDTD2>("Nabo, pt in nodes, stack, balance variance",
318  //doBench<KDTD3>("Nabo, balanced, stack, pt in leaves only, balance variance",
319  //"Nabo, balanced, stack, pt in leaves only, balance cell aspect ratio",
320  //"Nabo, unbalanced, stack, pt in leaves only, implicit bounds, ANN_KD_SL_MIDPT, STL heap",
321  //"Nabo, unbalanced, stack, pt in leaves only, implicit bounds, ANN_KD_SL_MIDPT, brute-force vector heap",
322  "Nabo, double, unbalanced, stack, pt in leaves only, implicit bounds, ANN_KD_SL_MIDPT, brute-force vector heap, opt",
323  "Nabo, double, unbalanced, stack, pt in leaves only, implicit bounds, ANN_KD_SL_MIDPT, STL heap, opt",
324  "Nabo, float, unbalanced, stack, pt in leaves only, implicit bounds, ANN_KD_SL_MIDPT, brute-force vector heap, opt",
325  "Nabo, float, unbalanced, stack, pt in leaves only, implicit bounds, ANN_KD_SL_MIDPT, STL heap, opt",
326  "Nabo, float, unbalanced, stack, pt in leaves only, implicit bounds, ANN_KD_SL_MIDPT, STL heap, opt, stats",
327  #ifdef HAVE_OPENCL
328  "Nabo, float, OpenCL, GPU, balanced, points in nodes, stack, implicit bounds, balance aspect ratio, stats",
329  "Nabo, float, OpenCL, GPU, balanced, points in leaves, stack, implicit bounds, balance aspect ratio, stats",
330  //"Nabo, float, OpenCL, GPU, brute force",
331  #endif // HAVE_OPENCL
332  //"Nabo, unbalanced, points in leaves, stack, explicit bounds, ANN_KD_SL_MIDPT",
333  #ifdef HAVE_ANN
334  "ANN stack, double",
335  //"ANN priority",
336  #endif // HAVE_ANN
337  #ifdef HAVE_FLANN
338  "FLANN, double",
339  "FLANN, float",
340  #endif // HAVE_FLANN
341  };
342 
343  // do bench themselves, accumulate over several times
344  size_t benchCount(sizeof(benchLabels) / sizeof(const char *));
345  cout << "Doing " << benchCount << " different benches " << runCount << " times, with " << searchCount << " query per run" << endl;
346  BenchResults results(benchCount);
347  for (int run = 0; run < runCount; ++run)
348  {
349  size_t i = 0;
350  //results.at(i++) += doBench<KDTD1>(d, q, K, itCount, searchCount);
351  //results.at(i++) += doBench<KDTD2>(d, q, K, itCount, searchCount);
352  //results.at(i++) += doBench<KDTD3>(d, q, K, itCount, searchCount);
353  //results.at(i++) += doBench<KDTD4>(d, q, K, itCount, searchCount);
354  //results.at(i++) += doBench<KDTD5A>(d, q, K, itCount, searchCount);
355  //results.at(i++) += doBench<KDTD5B>(d, q, K, itCount, searchCount);
356  results.at(i++) += doBenchType<double>(NNSearchD::KDTREE_LINEAR_HEAP, 0, dD, qD, K, itCount, searchCount);
357  results.at(i++) += doBenchType<double>(NNSearchD::KDTREE_TREE_HEAP, 0, dD, qD, K, itCount, searchCount);
358  results.at(i++) += doBenchType<float>(NNSearchF::KDTREE_LINEAR_HEAP, 0, dF, qF, K, itCount, searchCount);
359  results.at(i++) += doBenchType<float>(NNSearchF::KDTREE_TREE_HEAP, 0, dF, qF, K, itCount, searchCount);
360  results.at(i++) += doBenchType<float>(NNSearchF::KDTREE_TREE_HEAP, NNSearchF::TOUCH_STATISTICS, dF, qF, K, itCount, searchCount);
361  #ifdef HAVE_OPENCL
362  results.at(i++) += doBenchType<float>(NNSearchF::KDTREE_CL_PT_IN_NODES, NNSearchF::TOUCH_STATISTICS, dF, qF, K, itCount, searchCount);
363  results.at(i++) += doBenchType<float>(NNSearchF::KDTREE_CL_PT_IN_LEAVES, NNSearchF::TOUCH_STATISTICS, dF, qF, K, itCount, searchCount);
364  //results.at(i++) += doBenchType<float>(NNSearchF::BRUTE_FORCE_CL, dF, qF, K, itCount, searchCount);
365  #endif // HAVE_OPENCL
366  #ifdef HAVE_ANN
367  results.at(i++) += doBenchANNStack(dD, qD, K, itCount, searchCount);
368  //results.at(i++) += doBenchANNPriority(d, q, K, itCount);
369  #endif // HAVE_ANN
370  #ifdef HAVE_FLANN
371  results.at(i++) += doBenchFLANN<double>(dD, qD, K, itCount, searchCount);
372  results.at(i++) += doBenchFLANN<float>(dF, qF, K, itCount, searchCount);
373  #endif // HAVE_FLANN
374  }
375 
376  // print results
377  cout << "Showing average over " << runCount << " runs\n\n";
378  for (size_t i = 0; i < benchCount; ++i)
379  {
380  results[i] /= double(runCount);
381  cout << "Method " << benchLabels[i] << ":\n";
382  cout << " creation duration: " << results[i].creationDuration << "\n";
383  cout << " execution duration: " << results[i].executionDuration << "\n";
384  if (results[i].totalCount != 0)
385  {
386  cout << " visit count: " << results[i].visitCount << "\n";
387  cout << " total count: " << results[i].totalCount << "\n";
388  cout << " precentage visit: " << (results[i].visitCount * 100.) / results[i].totalCount << "\n";
389  }
390  else
391  cout << " no stats for visits\n";
392  cout << endl;
393  }
394 
395  return 0;
396 }
Nabo
Namespace for Nabo.
Definition: experimental/kdtree_cpu.cpp:40
IndexVectorF
Nabo::NearestNeighbourSearch< float >::IndexVector IndexVectorF
Definition: knnbench.cpp:58
BenchResult::creationDuration
double creationDuration
Definition: knnbench.cpp:86
BenchResults
vector< BenchResult > BenchResults
Definition: knnbench.cpp:114
timer
Definition: helpers.h:128
nabo.h
public interface
IndexF
Nabo::NearestNeighbourSearch< float >::Index IndexF
Definition: knnbench.cpp:57
nabo_experimental.h
MatrixD
Nabo::NearestNeighbourSearch< double >::Matrix MatrixD
Definition: knnbench.cpp:51
IndexD
Nabo::NearestNeighbourSearch< double >::Index IndexD
Definition: knnbench.cpp:53
Index
NNSNabo::Index Index
Definition: python/nabo.cpp:11
BenchResult
Definition: knnbench.cpp:84
VectorD
Nabo::NearestNeighbourSearch< double >::Vector VectorD
Definition: knnbench.cpp:52
timer::restart
void restart()
Definition: helpers.h:134
Nabo::NearestNeighbourSearch::IndexVector
Eigen::Matrix< Index, Eigen::Dynamic, 1 > IndexVector
a vector of indices to data points
Definition: nabo.h:269
BenchResult::visitCount
double visitCount
Definition: knnbench.cpp:88
Nabo::NearestNeighbourSearch::Matrix
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > Matrix
a column-major Eigen matrix in which each column is a point; this matrix has dim rows
Definition: nabo.h:263
doBenchType
BenchResult doBenchType(const typename NearestNeighbourSearch< T >::SearchType type, const unsigned creationOptionFlags, const typename NearestNeighbourSearch< T >::Matrix &d, const typename NearestNeighbourSearch< T >::Matrix &q, const int K, const int, const int searchCount)
Definition: knnbench.cpp:135
MatrixF
Nabo::NearestNeighbourSearch< float >::Matrix MatrixF
Definition: knnbench.cpp:55
BFSF
Nabo::BruteForceSearch< float > BFSF
Definition: knnbench.cpp:60
Nabo::NearestNeighbourSearch
Nearest neighbour search interface, templatized on scalar type.
Definition: nabo.h:258
BenchResult::executionDuration
double executionDuration
Definition: knnbench.cpp:87
BFSD
Nabo::BruteForceSearch< double > BFSD
Definition: knnbench.cpp:59
helpers.h
test.nns
nns
Definition: test.py:7
Nabo::NearestNeighbourSearch::Vector
Eigen::Matrix< T, Eigen::Dynamic, 1 > Vector
an Eigen vector of type T, to hold the coordinates of a point
Definition: nabo.h:261
main
int main(int argc, char *argv[])
Definition: knnbench.cpp:287
timer::elapsed
double elapsed() const
Definition: helpers.h:135
std
Definition: any.hpp:450
Nabo::NearestNeighbourSearch::Index
int Index
an index to a Vector or a Matrix, for refering to data points
Definition: nabo.h:267
IndexVectorD
Nabo::NearestNeighbourSearch< double >::IndexVector IndexVectorD
Definition: knnbench.cpp:54
test.q
q
Definition: test.py:8
VectorF
Nabo::NearestNeighbourSearch< float >::Vector VectorF
Definition: knnbench.cpp:56
BenchResult::totalCount
double totalCount
Definition: knnbench.cpp:89
Nabo::BruteForceSearch
Brute-force nearest neighbour.
Definition: nabo_private.h:72
BenchResult::BenchResult
BenchResult()
Definition: knnbench.cpp:91


libnabo
Author(s): Stéphane Magnenat
autogenerated on Fri Aug 2 2024 08:39:11