DataTransferKit - Multiphysics Solution Transfer Services  2.0
DTK_nanoflann.hpp
1 /***********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
5  * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
6  * Copyright 2011-2013 Jose Luis Blanco (joseluisblancoc@gmail.com).
7  * All rights reserved.
8  *
9  * THE BSD LICENSE
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in the
19  * documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *************************************************************************/
32 
33 #ifndef DTK_NANOFLANN_HPP_
34 #define DTK_NANOFLANN_HPP_
35 
36 #include <algorithm>
37 #include <cassert>
38 #include <cmath> // for fabs(),...
39 #include <cstdio> // for fwrite()
40 #include <limits>
41 #include <stdexcept>
42 
43 #include <Teuchos_Array.hpp>
44 
45 // Avoid conflicting declaration of min/max macros in windows headers
46 #if !defined( NOMINMAX ) && ( defined( _WIN32 ) || defined( _WIN32_ ) || \
47  defined( WIN32 ) || defined( _WIN64 ) )
48 #define NOMINMAX
49 #ifdef max
50 #undef max
51 #undef min
52 #endif
53 #endif
54 
55 // Adding DTK namespace to avoid conflicting with other potential nanoflann
56 // libraries that may link against this one.
57 namespace DataTransferKit
58 {
59 
60 namespace nanoflann
61 {
66 #define NANOFLANN_VERSION 0x117
67 
70 template <typename DistanceType, typename IndexType = size_t,
71  typename CountType = size_t>
72 class KNNResultSet
73 {
74  IndexType *indices;
75  DistanceType *dists;
76  CountType capacity;
77  CountType count;
78 
79  public:
80  inline KNNResultSet( CountType capacity_ )
81  : capacity( capacity_ )
82  , count( 0 )
83  {
84  }
85 
86  inline void init( IndexType *indices_, DistanceType *dists_ )
87  {
88  indices = indices_;
89  dists = dists_;
90  count = 0;
91  dists[capacity - 1] = ( std::numeric_limits<DistanceType>::max )();
92  }
93 
94  inline CountType size() const { return count; }
95 
96  inline bool full() const { return count == capacity; }
97 
98  inline void addPoint( DistanceType dist, IndexType index )
99  {
100  CountType i;
101  for ( i = count; i > 0; --i )
102  {
103 #ifdef NANOFLANN_FIRST_MATCH // If defined and two poins have the same distance,
104  // the one with the lowest-index will be returned
105  // first.
106  if ( ( dists[i - 1] > dist ) ||
107  ( ( dist == dists[i - 1] ) && ( indices[i - 1] > index ) ) )
108  {
109 #else
110  if ( dists[i - 1] > dist )
111  {
112 #endif
113  if ( i < capacity )
114  {
115  dists[i] = dists[i - 1];
116  indices[i] = indices[i - 1];
117  }
118  }
119  else
120  break;
121  }
122  if ( i < capacity )
123  {
124  dists[i] = dist;
125  indices[i] = index;
126  }
127  if ( count < capacity )
128  count++;
129  }
130 
131  inline DistanceType worstDist() const { return dists[capacity - 1]; }
132 };
133 
137 template <typename DistanceType, typename IndexType = size_t>
139 {
140  public:
141  const DistanceType radius;
142 
143  Teuchos::Array<std::pair<IndexType, DistanceType>> &m_indices_dists;
144 
145  inline RadiusResultSet(
146  DistanceType radius_,
147  Teuchos::Array<std::pair<IndexType, DistanceType>> &indices_dists )
148  : radius( radius_ )
149  , m_indices_dists( indices_dists )
150  {
151  init();
152  }
153 
154  inline ~RadiusResultSet() {}
155 
156  inline void init() { clear(); }
157  inline void clear() { m_indices_dists.clear(); }
158 
159  inline size_t size() const { return m_indices_dists.size(); }
160 
161  inline bool full() const { return true; }
162 
163  inline void addPoint( DistanceType dist, IndexType index )
164  {
165  if ( dist < radius )
166  m_indices_dists.push_back( std::make_pair( index, dist ) );
167  }
168 
169  inline DistanceType worstDist() const { return radius; }
170 
172  inline void set_radius_and_clear( const DistanceType r )
173  {
174  radius = r;
175  clear();
176  }
177 
182  std::pair<IndexType, DistanceType> worst_item() const
183  {
184  if ( m_indices_dists.empty() )
185  throw std::runtime_error( "Cannot invoke "
186  "RadiusResultSet::worst_item() on an "
187  "empty list of results." );
188  typedef typename Teuchos::Array<
189  std::pair<IndexType, DistanceType>>::const_iterator DistIt;
190  DistIt it =
191  std::max_element( m_indices_dists.begin(), m_indices_dists.end() );
192  return *it;
193  }
194 };
195 
198 {
200  template <typename PairType>
201  inline bool operator()( const PairType &p1, const PairType &p2 ) const
202  {
203  return p1.second < p2.second;
204  }
205 };
206 
211 template <typename T>
212 void save_value( FILE *stream, const T &value, size_t count = 1 )
213 {
214  fwrite( &value, sizeof( value ), count, stream );
215 }
216 
217 template <typename T>
218 void save_value( FILE *stream, const Teuchos::Array<T> &value )
219 {
220  size_t size = value.size();
221  fwrite( &size, sizeof( size_t ), 1, stream );
222  fwrite( &value[0], sizeof( T ), size, stream );
223 }
224 
225 template <typename T>
226 void load_value( FILE *stream, T &value, size_t count = 1 )
227 {
228  size_t read_cnt = fread( &value, sizeof( value ), count, stream );
229  if ( read_cnt != count )
230  {
231  throw std::runtime_error( "Cannot read from file" );
232  }
233 }
234 
235 template <typename T>
236 void load_value( FILE *stream, Teuchos::Array<T> &value )
237 {
238  size_t size;
239  size_t read_cnt = fread( &size, sizeof( size_t ), 1, stream );
240  if ( read_cnt != 1 )
241  {
242  throw std::runtime_error( "Cannot read from file" );
243  }
244  value.resize( size );
245  read_cnt = fread( &value[0], sizeof( T ), size, stream );
246  if ( read_cnt != size )
247  {
248  throw std::runtime_error( "Cannot read from file" );
249  }
250 }
256 template <typename T>
257 inline T abs( T x )
258 {
259  return ( x < 0 ) ? -x : x;
260 }
261 template <>
262 inline int abs<int>( int x )
263 {
264  return ::abs( x );
265 }
266 template <>
267 inline float abs<float>( float x )
268 {
269  return fabsf( x );
270 }
271 template <>
272 inline double abs<double>( double x )
273 {
274  return fabs( x );
275 }
276 template <>
277 inline long double abs<long double>( long double x )
278 {
279  return fabsl( x );
280 }
281 
289 template <class T, class DataSource, typename _DistanceType = T>
291 {
292  typedef T ElementType;
293  typedef _DistanceType DistanceType;
294 
295  const DataSource &data_source;
296 
297  L1_Adaptor( const DataSource &_data_source )
298  : data_source( _data_source )
299  {
300  }
301 
302  inline DistanceType operator()( const T *a, const size_t b_idx, size_t size,
303  DistanceType worst_dist = -1 ) const
304  {
305  DistanceType result = DistanceType();
306  const T *last = a + size;
307  const T *lastgroup = last - 3;
308  size_t d = 0;
309 
310  /* Process 4 items with each loop for efficiency. */
311  while ( a < lastgroup )
312  {
313  const DistanceType diff0 = nanoflann::abs(
314  a[0] - data_source.kdtree_get_pt( b_idx, d++ ) );
315  const DistanceType diff1 = nanoflann::abs(
316  a[1] - data_source.kdtree_get_pt( b_idx, d++ ) );
317  const DistanceType diff2 = nanoflann::abs(
318  a[2] - data_source.kdtree_get_pt( b_idx, d++ ) );
319  const DistanceType diff3 = nanoflann::abs(
320  a[3] - data_source.kdtree_get_pt( b_idx, d++ ) );
321  result += diff0 + diff1 + diff2 + diff3;
322  a += 4;
323  if ( ( worst_dist > 0 ) && ( result > worst_dist ) )
324  {
325  return result;
326  }
327  }
328  /* Process last 0-3 components. Not needed for standard vector lengths.
329  */
330  while ( a < last )
331  {
332  result += nanoflann::abs( *a++ -
333  data_source.kdtree_get_pt( b_idx, d++ ) );
334  }
335  return result;
336  }
337 
338  template <typename U, typename V>
339  inline DistanceType accum_dist( const U a, const V b, int ) const
340  {
341  return nanoflann::abs( a - b );
342  }
343 };
344 
352 template <class T, class DataSource, typename _DistanceType = T>
354 {
355  typedef T ElementType;
356  typedef _DistanceType DistanceType;
357 
358  const DataSource &data_source;
359 
360  L2_Adaptor( const DataSource &_data_source )
361  : data_source( _data_source )
362  {
363  }
364 
365  inline DistanceType operator()( const T *a, const size_t b_idx, size_t size,
366  DistanceType worst_dist = -1 ) const
367  {
368  DistanceType result = DistanceType();
369  const T *last = a + size;
370  const T *lastgroup = last - 3;
371  size_t d = 0;
372 
373  /* Process 4 items with each loop for efficiency. */
374  while ( a < lastgroup )
375  {
376  const DistanceType diff0 =
377  a[0] - data_source.kdtree_get_pt( b_idx, d++ );
378  const DistanceType diff1 =
379  a[1] - data_source.kdtree_get_pt( b_idx, d++ );
380  const DistanceType diff2 =
381  a[2] - data_source.kdtree_get_pt( b_idx, d++ );
382  const DistanceType diff3 =
383  a[3] - data_source.kdtree_get_pt( b_idx, d++ );
384  result +=
385  diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
386  a += 4;
387  if ( ( worst_dist > 0 ) && ( result > worst_dist ) )
388  {
389  return result;
390  }
391  }
392  /* Process last 0-3 components. Not needed for standard vector lengths.
393  */
394  while ( a < last )
395  {
396  const DistanceType diff0 =
397  *a++ - data_source.kdtree_get_pt( b_idx, d++ );
398  result += diff0 * diff0;
399  }
400  return result;
401  }
402 
403  template <typename U, typename V>
404  inline DistanceType accum_dist( const U a, const V b, int ) const
405  {
406  return ( a - b ) * ( a - b );
407  }
408 };
409 
417 template <class T, class DataSource, typename _DistanceType = T>
419 {
420  typedef T ElementType;
421  typedef _DistanceType DistanceType;
422 
423  const DataSource &data_source;
424 
425  L2_Simple_Adaptor( const DataSource &_data_source )
426  : data_source( _data_source )
427  {
428  }
429 
430  inline DistanceType operator()( const T *a, const size_t b_idx,
431  size_t size ) const
432  {
433  return data_source.kdtree_distance( a, b_idx, size );
434  }
435 
436  template <typename U, typename V>
437  inline DistanceType accum_dist( const U a, const V b, int ) const
438  {
439  return ( a - b ) * ( a - b );
440  }
441 };
442 
444 struct metric_L1
445 {
446  template <class T, class DataSource>
447  struct traits
448  {
449  typedef L1_Adaptor<T, DataSource> distance_t;
450  };
451 };
453 struct metric_L2
454 {
455  template <class T, class DataSource>
456  struct traits
457  {
458  typedef L2_Adaptor<T, DataSource> distance_t;
459  };
460 };
463 {
464  template <class T, class DataSource>
465  struct traits
466  {
467  typedef L2_Simple_Adaptor<T, DataSource> distance_t;
468  };
469 };
470 
480 {
481  KDTreeSingleIndexAdaptorParams( size_t _leaf_max_size = 10, int dim_ = -1 )
482  : leaf_max_size( _leaf_max_size )
483  , dim( dim_ )
484  {
485  }
486 
487  size_t leaf_max_size;
488  int dim;
489 };
490 
493 {
496  SearchParams( int checks_IGNORED_ = 32, float eps_ = 0,
497  bool sorted_ = true )
498  : checks( checks_IGNORED_ )
499  , eps( eps_ )
500  , sorted( sorted_ )
501  {
502  }
503 
504  int checks;
505  float eps;
507  bool sorted;
508 };
522 template <typename T>
523 inline T *allocate( size_t count = 1 )
524 {
525  T *mem = (T *)::malloc( sizeof( T ) * count );
526  return mem;
527 }
528 
544 const size_t WORDSIZE = 16;
545 const size_t BLOCKSIZE = 8192;
546 
547 class PooledAllocator
548 {
549  /* We maintain memory alignment to word boundaries by requiring that all
550  allocations be in multiples of the machine wordsize. */
551  /* Size of machine word in bytes. Must be power of 2. */
552  /* Minimum number of bytes requested at a time from the system. Must
553  * be multiple of WORDSIZE. */
554 
555  size_t remaining; /* Number of bytes left in current block of storage. */
556  void *base; /* Pointer to base of current block of storage. */
557  void *loc; /* Current location in block to next allocate memory. */
558  size_t blocksize;
559 
560  void internal_init()
561  {
562  remaining = 0;
563  base = NULL;
564  usedMemory = 0;
565  wastedMemory = 0;
566  }
567 
568  public:
569  size_t usedMemory;
570  size_t wastedMemory;
571 
575  PooledAllocator( const size_t blocksize_ = BLOCKSIZE )
576  : blocksize( blocksize_ )
577  {
578  internal_init();
579  }
580 
584  ~PooledAllocator() { free_all(); }
585 
587  void free_all()
588  {
589  while ( base != NULL )
590  {
591  void *prev = *( (void **)base ); /* Get pointer to prev block. */
592  ::free( base );
593  base = prev;
594  }
595  internal_init();
596  }
597 
602  void *malloc( const size_t req_size )
603  {
604  /* Round size up to a multiple of wordsize. The following expression
605  only works for WORDSIZE that is a power of 2, by masking last bits
606  of
607  incremented size to zero.
608  */
609  const size_t size = ( req_size + ( WORDSIZE - 1 ) ) & ~( WORDSIZE - 1 );
610 
611  /* Check whether a new block must be allocated. Note that the first
612  word
613  of a block is reserved for a pointer to the previous block.
614  */
615  if ( size > remaining )
616  {
617 
618  wastedMemory += remaining;
619 
620  /* Allocate new storage. */
621  const size_t blocksize =
622  ( size + sizeof( void * ) + ( WORDSIZE - 1 ) > BLOCKSIZE )
623  ? size + sizeof( void * ) + ( WORDSIZE - 1 )
624  : BLOCKSIZE;
625 
626  // use the standard C malloc to allocate memory
627  void *m = ::malloc( blocksize );
628  if ( !m )
629  {
630  fprintf( stderr, "Failed to allocate memory.\n" );
631  return NULL;
632  }
633 
634  /* Fill first word of new block with pointer to previous block. */
635  ( (void **)m )[0] = base;
636  base = m;
637 
638  size_t shift = 0;
639  // int size_t = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) &
640  // (WORDSIZE-1))) & (WORDSIZE-1);
641 
642  remaining = blocksize - sizeof( void * ) - shift;
643  loc = ( (char *)m + sizeof( void * ) + shift );
644  }
645  void *rloc = loc;
646  loc = (char *)loc + size;
647  remaining -= size;
648 
649  usedMemory += size;
650 
651  return rloc;
652  }
653 
661  template <typename T>
662  T *allocate( const size_t count = 1 )
663  {
664  T *mem = (T *)this->malloc( sizeof( T ) * count );
665  return mem;
666  }
667 };
673 // ---------------- CArray -------------------------
701 template <typename T, std::size_t N>
702 class CArray
703 {
704  public:
705  T elems[N]; // fixed-size array of elements of type T
706 
707  public:
708  // type definitions
709  typedef T value_type;
710  typedef T *iterator;
711  typedef const T *const_iterator;
712  typedef T &reference;
713  typedef const T &const_reference;
714  typedef std::size_t size_type;
715  typedef std::ptrdiff_t difference_type;
716 
717  // iterator support
718  inline iterator begin() { return elems; }
719  inline const_iterator begin() const { return elems; }
720  inline iterator end() { return elems + N; }
721  inline const_iterator end() const { return elems + N; }
722 
723 // reverse iterator support
724 #if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && \
725  !defined( BOOST_MSVC_STD_ITERATOR ) && \
726  !defined( BOOST_NO_STD_ITERATOR_TRAITS )
727  typedef std::reverse_iterator<iterator> reverse_iterator;
728  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
729 #elif defined( _MSC_VER ) && ( _MSC_VER == 1300 ) && \
730  defined( BOOST_DINKUMWARE_STDLIB ) && ( BOOST_DINKUMWARE_STDLIB == 310 )
731  // workaround for broken reverse_iterator in VC7
732  typedef std::reverse_iterator<std::_Ptrit<
733  value_type, difference_type, iterator, reference, iterator, reference>>
734  reverse_iterator;
735  typedef std::reverse_iterator<
736  std::_Ptrit<value_type, difference_type, const_iterator,
737  const_reference, iterator, reference>>
738  const_reverse_iterator;
739 #else
740  // workaround for broken reverse_iterator implementations
741  typedef std::reverse_iterator<iterator, T> reverse_iterator;
742  typedef std::reverse_iterator<const_iterator, T> const_reverse_iterator;
743 #endif
744 
745  reverse_iterator rbegin() { return reverse_iterator( end() ); }
746  const_reverse_iterator rbegin() const
747  {
748  return const_reverse_iterator( end() );
749  }
750  reverse_iterator rend() { return reverse_iterator( begin() ); }
751  const_reverse_iterator rend() const
752  {
753  return const_reverse_iterator( begin() );
754  }
755  // operator[]
756  inline reference operator[]( size_type i ) { return elems[i]; }
757  inline const_reference operator[]( size_type i ) const { return elems[i]; }
758  // at() with range check
759  reference at( size_type i )
760  {
761  rangecheck( i );
762  return elems[i];
763  }
764  const_reference at( size_type i ) const
765  {
766  rangecheck( i );
767  return elems[i];
768  }
769  // front() and back()
770  reference front() { return elems[0]; }
771  const_reference front() const { return elems[0]; }
772  reference back() { return elems[N - 1]; }
773  const_reference back() const { return elems[N - 1]; }
774  // size is constant
775  static inline size_type size() { return N; }
776  static bool empty() { return false; }
777  static size_type max_size() { return N; }
778  enum
779  {
780  static_size = N
781  };
784  inline void resize( const size_t nElements )
785  {
786  if ( nElements != N )
787  throw std::logic_error( "Try to change the size of a CArray." );
788  }
789  // swap (note: linear complexity in N, constant for given instantiation)
790  void swap( CArray<T, N> &y )
791  {
792  std::swap_ranges( begin(), end(), y.begin() );
793  }
794  // direct access to data (read-only)
795  const T *data() const { return elems; }
796  // use array as C array (direct read/write access to data)
797  T *data() { return elems; }
798  // assignment with type conversion
799  template <typename T2>
800  CArray<T, N> &operator=( const CArray<T2, N> &rhs )
801  {
802  std::copy( rhs.begin(), rhs.end(), begin() );
803  return *this;
804  }
805  // assign one value to all elements
806  inline void assign( const T &value )
807  {
808  for ( size_t i = 0; i < N; i++ )
809  elems[i] = value;
810  }
811  // assign (compatible with Teuchos::Array's one) (by JLBC for MRPT)
812  void assign( const size_t n, const T &value )
813  {
814  assert( N == n );
815  for ( size_t i = 0; i < N; i++ )
816  elems[i] = value;
817  }
818 
819  private:
820  // check range (may be private because it is static)
821  static void rangecheck( size_type i )
822  {
823  if ( i >= size() )
824  {
825  throw std::out_of_range( "CArray<>: index out of range" );
826  }
827  }
828 }; // end of CArray
829 
834 template <int DIM, typename T>
836 {
837  typedef CArray<T, DIM> container_t;
838 };
840 template <typename T>
842 {
843  typedef Teuchos::Array<T> container_t;
844 };
889 template <typename Distance, class DatasetAdaptor, int DIM = -1,
890  typename IndexType = size_t>
892 {
893  public:
894  typedef typename Distance::ElementType ElementType;
895  typedef typename Distance::DistanceType DistanceType;
896 
897  protected:
901  Teuchos::Array<IndexType> vind;
902 
903  size_t m_leaf_max_size;
904 
908  const DatasetAdaptor &dataset;
909 
910  const KDTreeSingleIndexAdaptorParams index_params;
911 
912  size_t m_size;
913  int dim;
914 
915  /*--------------------- Internal Data Structures
916  * --------------------------*/
917  struct Node
918  {
919  union {
920  struct
921  {
925  IndexType left, right;
926  } lr;
927  struct
928  {
932  int divfeat;
936  DistanceType divlow, divhigh;
937  } sub;
938  };
942  Node *child1, *child2;
943  };
944  typedef Node *NodePtr;
945 
946  struct Interval
947  {
948  ElementType low, high;
949  };
950 
955 
960 
965  template <typename T, typename DistanceType>
967  {
968  T node; /* Tree node at which search resumes */
969  DistanceType
970  mindist; /* Minimum distance to query for all nodes below. */
971 
972  BranchStruct() {}
973  BranchStruct( const T &aNode, DistanceType dist )
974  : node( aNode )
975  , mindist( dist )
976  {
977  }
978 
979  inline bool operator<( const BranchStruct<T, DistanceType> &rhs ) const
980  {
981  return mindist < rhs.mindist;
982  }
983  };
984 
988  NodePtr root_node;
990  typedef BranchSt *Branch;
991 
992  BoundingBox root_bbox;
993 
1001  PooledAllocator pool;
1002 
1003  public:
1004  Distance distance;
1005 
1014  KDTreeSingleIndexAdaptor( const int dimensionality,
1015  const DatasetAdaptor &inputData,
1016  const KDTreeSingleIndexAdaptorParams &params =
1018  : dataset( inputData )
1019  , index_params( params )
1020  , root_node( NULL )
1021  , distance( inputData )
1022  {
1023  m_size = dataset.kdtree_get_point_count();
1024  dim = dimensionality;
1025  if ( DIM > 0 )
1026  dim = DIM;
1027  else
1028  {
1029  if ( params.dim > 0 )
1030  dim = params.dim;
1031  }
1032  m_leaf_max_size = params.leaf_max_size;
1033 
1034  // Create a permutable array of indices to the input vectors.
1035  init_vind();
1036  }
1037 
1042 
1045  void freeIndex()
1046  {
1047  pool.free_all();
1048  root_node = NULL;
1049  }
1050 
1054  void buildIndex()
1055  {
1056  init_vind();
1057  computeBoundingBox( root_bbox );
1058  freeIndex();
1059  root_node = divideTree( 0, m_size, root_bbox ); // construct the tree
1060  }
1061 
1065  size_t size() const { return m_size; }
1066 
1070  size_t veclen() const { return static_cast<size_t>( DIM > 0 ? DIM : dim ); }
1071 
1076  size_t usedMemory() const
1077  {
1078  return pool.usedMemory + pool.wastedMemory +
1079  dataset.kdtree_get_point_count() *
1080  sizeof( IndexType ); // pool memory and vind array memory
1081  }
1082 
1099  template <typename RESULTSET>
1100  void findNeighbors( RESULTSET &result, const ElementType *vec,
1101  const SearchParams &searchParams ) const
1102  {
1103  assert( vec );
1104  if ( !root_node )
1105  throw std::runtime_error( "[nanoflann] findNeighbors() called "
1106  "before building the index." );
1107  float epsError = 1 + searchParams.eps;
1108 
1110  dists; // fixed or variable-sized container (depending on DIM)
1111  dists.assign( ( DIM > 0 ? DIM : dim ), 0 ); // Fill it with zeros.
1112  DistanceType distsq = computeInitialDistances( vec, dists );
1113  searchLevel( result, vec, root_node, distsq, dists,
1114  epsError ); // "count_leaf" parameter removed since was
1115  // neither used nor returned to the user.
1116  }
1117 
1126  inline void knnSearch( const ElementType *query_point,
1127  const size_t num_closest, IndexType *out_indices,
1128  DistanceType *out_distances_sq,
1129  const int nChecks_IGNORED = 10 ) const
1130  {
1131  nanoflann::KNNResultSet<DistanceType, IndexType> resultSet(
1132  num_closest );
1133  resultSet.init( out_indices, out_distances_sq );
1134  this->findNeighbors( resultSet, query_point,
1136  }
1137 
1156  const ElementType *query_point, const DistanceType radius,
1157  Teuchos::Array<std::pair<IndexType, DistanceType>> &IndicesDists,
1158  const SearchParams &searchParams ) const
1159  {
1160  RadiusResultSet<DistanceType, IndexType> resultSet( radius,
1161  IndicesDists );
1162  this->findNeighbors( resultSet, query_point, searchParams );
1163 
1164  if ( searchParams.sorted )
1165  std::sort( IndicesDists.begin(), IndicesDists.end(),
1166  IndexDist_Sorter() );
1167 
1168  return resultSet.size();
1169  }
1170 
1173  private:
1176  void init_vind()
1177  {
1178  // Create a permutable array of indices to the input vectors.
1179  m_size = dataset.kdtree_get_point_count();
1180  if ( Teuchos::as<std::size_t>( vind.size() ) !=
1181  Teuchos::as<std::size_t>( m_size ) )
1182  vind.resize( m_size );
1183  for ( size_t i = 0; i < m_size; i++ )
1184  vind[i] = i;
1185  }
1186 
1188  inline ElementType dataset_get( size_t idx, int component ) const
1189  {
1190  return dataset.kdtree_get_pt( idx, component );
1191  }
1192 
1193  void save_tree( FILE *stream, NodePtr tree )
1194  {
1195  save_value( stream, *tree );
1196  if ( tree->child1 != NULL )
1197  {
1198  save_tree( stream, tree->child1 );
1199  }
1200  if ( tree->child2 != NULL )
1201  {
1202  save_tree( stream, tree->child2 );
1203  }
1204  }
1205 
1206  void load_tree( FILE *stream, NodePtr &tree )
1207  {
1208  tree = pool.allocate<Node>();
1209  load_value( stream, *tree );
1210  if ( tree->child1 != NULL )
1211  {
1212  load_tree( stream, tree->child1 );
1213  }
1214  if ( tree->child2 != NULL )
1215  {
1216  load_tree( stream, tree->child2 );
1217  }
1218  }
1219 
1220  void computeBoundingBox( BoundingBox &bbox )
1221  {
1222  bbox.resize( ( DIM > 0 ? DIM : dim ) );
1223  if ( dataset.kdtree_get_bbox( bbox ) )
1224  {
1225  // Done! It was implemented in derived class
1226  }
1227  else
1228  {
1229  for ( int i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1230  {
1231  bbox[i].low = bbox[i].high = dataset_get( 0, i );
1232  }
1233  const size_t N = dataset.kdtree_get_point_count();
1234  for ( size_t k = 1; k < N; ++k )
1235  {
1236  for ( int i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1237  {
1238  if ( dataset_get( k, i ) < bbox[i].low )
1239  bbox[i].low = dataset_get( k, i );
1240  if ( dataset_get( k, i ) > bbox[i].high )
1241  bbox[i].high = dataset_get( k, i );
1242  }
1243  }
1244  }
1245  }
1246 
1256  NodePtr divideTree( const IndexType left, const IndexType right,
1257  BoundingBox &bbox )
1258  {
1259  NodePtr node = pool.allocate<Node>(); // allocate memory
1260 
1261  /* If too few exemplars remain, then make this a leaf node. */
1262  if ( ( right - left ) <= m_leaf_max_size )
1263  {
1264  node->child1 = node->child2 = NULL; /* Mark as leaf node. */
1265  node->lr.left = left;
1266  node->lr.right = right;
1267 
1268  // compute bounding-box of leaf points
1269  for ( int i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1270  {
1271  bbox[i].low = dataset_get( vind[left], i );
1272  bbox[i].high = dataset_get( vind[left], i );
1273  }
1274  for ( IndexType k = left + 1; k < right; ++k )
1275  {
1276  for ( int i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1277  {
1278  if ( bbox[i].low > dataset_get( vind[k], i ) )
1279  bbox[i].low = dataset_get( vind[k], i );
1280  if ( bbox[i].high < dataset_get( vind[k], i ) )
1281  bbox[i].high = dataset_get( vind[k], i );
1282  }
1283  }
1284  }
1285  else
1286  {
1287  IndexType idx;
1288  int cutfeat;
1289  DistanceType cutval;
1290  middleSplit_( &vind[0] + left, right - left, idx, cutfeat, cutval,
1291  bbox );
1292 
1293  node->sub.divfeat = cutfeat;
1294 
1295  BoundingBox left_bbox( bbox );
1296  left_bbox[cutfeat].high = cutval;
1297  node->child1 = divideTree( left, left + idx, left_bbox );
1298 
1299  BoundingBox right_bbox( bbox );
1300  right_bbox[cutfeat].low = cutval;
1301  node->child2 = divideTree( left + idx, right, right_bbox );
1302 
1303  node->sub.divlow = left_bbox[cutfeat].high;
1304  node->sub.divhigh = right_bbox[cutfeat].low;
1305 
1306  for ( int i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1307  {
1308  bbox[i].low = std::min( left_bbox[i].low, right_bbox[i].low );
1309  bbox[i].high =
1310  std::max( left_bbox[i].high, right_bbox[i].high );
1311  }
1312  }
1313 
1314  return node;
1315  }
1316 
1317  void computeMinMax( IndexType *ind, IndexType count, int element,
1318  ElementType &min_elem, ElementType &max_elem )
1319  {
1320  min_elem = dataset_get( ind[0], element );
1321  max_elem = dataset_get( ind[0], element );
1322  for ( IndexType i = 1; i < count; ++i )
1323  {
1324  ElementType val = dataset_get( ind[i], element );
1325  if ( val < min_elem )
1326  min_elem = val;
1327  if ( val > max_elem )
1328  max_elem = val;
1329  }
1330  }
1331 
1332  void middleSplit( IndexType *ind, IndexType count, IndexType &index,
1333  int &cutfeat, DistanceType &cutval,
1334  const BoundingBox &bbox )
1335  {
1336  // find the largest span from the approximate bounding box
1337  ElementType max_span = bbox[0].high - bbox[0].low;
1338  cutfeat = 0;
1339  cutval = ( bbox[0].high + bbox[0].low ) / 2;
1340  for ( int i = 1; i < ( DIM > 0 ? DIM : dim ); ++i )
1341  {
1342  ElementType span = bbox[i].low - bbox[i].low;
1343  if ( span > max_span )
1344  {
1345  max_span = span;
1346  cutfeat = i;
1347  cutval = ( bbox[i].high + bbox[i].low ) / 2;
1348  }
1349  }
1350 
1351  // compute exact span on the found dimension
1352  ElementType min_elem, max_elem;
1353  computeMinMax( ind, count, cutfeat, min_elem, max_elem );
1354  cutval = ( min_elem + max_elem ) / 2;
1355  max_span = max_elem - min_elem;
1356 
1357  // check if a dimension of a largest span exists
1358  size_t k = cutfeat;
1359  for ( size_t i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1360  {
1361  if ( i == k )
1362  continue;
1363  ElementType span = bbox[i].high - bbox[i].low;
1364  if ( span > max_span )
1365  {
1366  computeMinMax( ind, count, i, min_elem, max_elem );
1367  span = max_elem - min_elem;
1368  if ( span > max_span )
1369  {
1370  max_span = span;
1371  cutfeat = i;
1372  cutval = ( min_elem + max_elem ) / 2;
1373  }
1374  }
1375  }
1376  IndexType lim1, lim2;
1377  planeSplit( ind, count, cutfeat, cutval, lim1, lim2 );
1378 
1379  if ( lim1 > count / 2 )
1380  index = lim1;
1381  else if ( lim2 < count / 2 )
1382  index = lim2;
1383  else
1384  index = count / 2;
1385  }
1386 
1387  void middleSplit_( IndexType *ind, IndexType count, IndexType &index,
1388  int &cutfeat, DistanceType &cutval,
1389  const BoundingBox &bbox )
1390  {
1391  const DistanceType epsilon = static_cast<DistanceType>( 0.00001 );
1392  ElementType max_span = bbox[0].high - bbox[0].low;
1393  for ( int i = 1; i < ( DIM > 0 ? DIM : dim ); ++i )
1394  {
1395  ElementType span = bbox[i].high - bbox[i].low;
1396  if ( span > max_span )
1397  {
1398  max_span = span;
1399  }
1400  }
1401  ElementType max_spread = -1;
1402  cutfeat = 0;
1403  for ( int i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1404  {
1405  ElementType span = bbox[i].high - bbox[i].low;
1406  if ( span > ( 1 - epsilon ) * max_span )
1407  {
1408  ElementType min_elem, max_elem;
1409  computeMinMax( ind, count, cutfeat, min_elem, max_elem );
1410  ElementType spread = max_elem - min_elem;
1411  ;
1412  if ( spread > max_spread )
1413  {
1414  cutfeat = i;
1415  max_spread = spread;
1416  }
1417  }
1418  }
1419  // split in the middle
1420  DistanceType split_val = ( bbox[cutfeat].low + bbox[cutfeat].high ) / 2;
1421  ElementType min_elem, max_elem;
1422  computeMinMax( ind, count, cutfeat, min_elem, max_elem );
1423 
1424  if ( split_val < min_elem )
1425  cutval = min_elem;
1426  else if ( split_val > max_elem )
1427  cutval = max_elem;
1428  else
1429  cutval = split_val;
1430 
1431  IndexType lim1, lim2;
1432  planeSplit( ind, count, cutfeat, cutval, lim1, lim2 );
1433 
1434  if ( lim1 > count / 2 )
1435  index = lim1;
1436  else if ( lim2 < count / 2 )
1437  index = lim2;
1438  else
1439  index = count / 2;
1440  }
1441 
1452  void planeSplit( IndexType *ind, const IndexType count, int cutfeat,
1453  DistanceType cutval, IndexType &lim1, IndexType &lim2 )
1454  {
1455  /* Move vector indices for left subtree to front of list. */
1456  IndexType left = 0;
1457  IndexType right = count - 1;
1458  for ( ;; )
1459  {
1460  while ( left <= right &&
1461  dataset_get( ind[left], cutfeat ) < cutval )
1462  ++left;
1463  while ( right && left <= right &&
1464  dataset_get( ind[right], cutfeat ) >= cutval )
1465  --right;
1466  if ( left > right || !right )
1467  break; // "!right" was added to support unsigned Index types
1468  std::swap( ind[left], ind[right] );
1469  ++left;
1470  --right;
1471  }
1472  /* If either list is empty, it means that all remaining features
1473  * are identical. Split in the middle to maintain a balanced tree.
1474  */
1475  lim1 = left;
1476  right = count - 1;
1477  for ( ;; )
1478  {
1479  while ( left <= right &&
1480  dataset_get( ind[left], cutfeat ) <= cutval )
1481  ++left;
1482  while ( right && left <= right &&
1483  dataset_get( ind[right], cutfeat ) > cutval )
1484  --right;
1485  if ( left > right || !right )
1486  break; // "!right" was added to support unsigned Index types
1487  std::swap( ind[left], ind[right] );
1488  ++left;
1489  --right;
1490  }
1491  lim2 = left;
1492  }
1493 
1494  DistanceType computeInitialDistances( const ElementType *vec,
1495  distance_vector_t &dists ) const
1496  {
1497  assert( vec );
1498  DistanceType distsq = 0.0;
1499 
1500  for ( int i = 0; i < ( DIM > 0 ? DIM : dim ); ++i )
1501  {
1502  if ( vec[i] < root_bbox[i].low )
1503  {
1504  dists[i] = distance.accum_dist( vec[i], root_bbox[i].low, i );
1505  distsq += dists[i];
1506  }
1507  if ( vec[i] > root_bbox[i].high )
1508  {
1509  dists[i] = distance.accum_dist( vec[i], root_bbox[i].high, i );
1510  distsq += dists[i];
1511  }
1512  }
1513 
1514  return distsq;
1515  }
1516 
1521  template <class RESULTSET>
1522  void searchLevel( RESULTSET &result_set, const ElementType *vec,
1523  const NodePtr node, DistanceType mindistsq,
1524  distance_vector_t &dists, const float epsError ) const
1525  {
1526  /* If this is a leaf node, then do check and return. */
1527  if ( ( node->child1 == NULL ) && ( node->child2 == NULL ) )
1528  {
1529  // count_leaf += (node->lr.right-node->lr.left); // Removed since
1530  // was neither used nor returned to the user.
1531  DistanceType worst_dist = result_set.worstDist();
1532  for ( IndexType i = node->lr.left; i < node->lr.right; ++i )
1533  {
1534  const IndexType index = vind[i]; // reorder... : i;
1535  DistanceType dist =
1536  distance( vec, index, ( DIM > 0 ? DIM : dim ) );
1537  if ( dist < worst_dist )
1538  {
1539  result_set.addPoint( dist, vind[i] );
1540  }
1541  }
1542  return;
1543  }
1544 
1545  /* Which child branch should be taken first? */
1546  int idx = node->sub.divfeat;
1547  ElementType val = vec[idx];
1548  DistanceType diff1 = val - node->sub.divlow;
1549  DistanceType diff2 = val - node->sub.divhigh;
1550 
1551  NodePtr bestChild;
1552  NodePtr otherChild;
1553  DistanceType cut_dist;
1554  if ( ( diff1 + diff2 ) < 0 )
1555  {
1556  bestChild = node->child1;
1557  otherChild = node->child2;
1558  cut_dist = distance.accum_dist( val, node->sub.divhigh, idx );
1559  }
1560  else
1561  {
1562  bestChild = node->child2;
1563  otherChild = node->child1;
1564  cut_dist = distance.accum_dist( val, node->sub.divlow, idx );
1565  }
1566 
1567  /* Call recursively to search next level down. */
1568  searchLevel( result_set, vec, bestChild, mindistsq, dists, epsError );
1569 
1570  DistanceType dst = dists[idx];
1571  mindistsq = mindistsq + cut_dist - dst;
1572  dists[idx] = cut_dist;
1573  if ( mindistsq * epsError <= result_set.worstDist() )
1574  {
1575  searchLevel( result_set, vec, otherChild, mindistsq, dists,
1576  epsError );
1577  }
1578  dists[idx] = dst;
1579  }
1580 
1581  public:
1588  void saveIndex( FILE *stream )
1589  {
1590  save_value( stream, m_size );
1591  save_value( stream, dim );
1592  save_value( stream, root_bbox );
1593  save_value( stream, m_leaf_max_size );
1594  save_value( stream, vind );
1595  save_tree( stream, root_node );
1596  }
1597 
1604  void loadIndex( FILE *stream )
1605  {
1606  load_value( stream, m_size );
1607  load_value( stream, dim );
1608  load_value( stream, root_bbox );
1609  load_value( stream, m_leaf_max_size );
1610  load_value( stream, vind );
1611  load_tree( stream, root_node );
1612  }
1613 
1614 }; // class KDTree
1615 
1640 template <class MatrixType, int DIM = -1, class Distance = nanoflann::metric_L2,
1641  typename IndexType = size_t>
1643 {
1645  self_t;
1646  typedef typename MatrixType::Scalar num_t;
1647  typedef
1648  typename Distance::template traits<num_t, self_t>::distance_t metric_t;
1650 
1651  index_t *index;
1652 
1655  KDTreeEigenMatrixAdaptor( const int dimensionality, const MatrixType &mat,
1656  const int leaf_max_size = 10 )
1657  : m_data_matrix( mat )
1658  {
1659  const size_t dims = mat.cols();
1660  if ( DIM > 0 && static_cast<int>( dims ) != DIM )
1661  throw std::runtime_error( "Data set dimensionality does not match "
1662  "the 'DIM' template argument" );
1663  index = new index_t(
1664  dims, *this /* adaptor */,
1665  nanoflann::KDTreeSingleIndexAdaptorParams( leaf_max_size, dims ) );
1666  index->buildIndex();
1667  }
1668 
1669  ~KDTreeEigenMatrixAdaptor() { delete index; }
1670 
1671  const MatrixType &m_data_matrix;
1672 
1680  inline void query( const num_t *query_point, const size_t num_closest,
1681  IndexType *out_indices, num_t *out_distances_sq,
1682  const int nChecks_IGNORED = 10 ) const
1683  {
1684  nanoflann::KNNResultSet<typename MatrixType::Scalar, IndexType>
1685  resultSet( num_closest );
1686  resultSet.init( out_indices, out_distances_sq );
1687  index->findNeighbors( resultSet, query_point,
1689  }
1690 
1694  const self_t &derived() const { return *this; }
1695  self_t &derived() { return *this; }
1696 
1697  // Must return the number of data points
1698  inline size_t kdtree_get_point_count() const
1699  {
1700  return m_data_matrix.rows();
1701  }
1702 
1703  // Returns the distance between the vector "p1[0:size-1]" and the data point
1704  // with index "idx_p2" stored in the class:
1705  inline num_t kdtree_distance( const num_t *p1, const size_t idx_p2,
1706  size_t size ) const
1707  {
1708  num_t s = 0;
1709  for ( size_t i = 0; i < size; i++ )
1710  {
1711  const num_t d = p1[i] - m_data_matrix.coeff( idx_p2, i );
1712  s += d * d;
1713  }
1714  return s;
1715  }
1716 
1717  // Returns the dim'th component of the idx'th point in the class:
1718  inline num_t kdtree_get_pt( const size_t idx, int dim ) const
1719  {
1720  return m_data_matrix.coeff( idx, dim );
1721  }
1722 
1723  // Optional bounding-box computation: return false to default to a standard
1724  // bbox computation loop.
1725  // Return true if the BBOX was already computed by the class and returned
1726  // in "bb" so it can be avoided to redo it again.
1727  // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3
1728  // for point clouds)
1729  template <class BBOX>
1730  bool kdtree_get_bbox( BBOX &bb ) const
1731  {
1732  return false;
1733  }
1734 
1737 }; // end of KDTreeEigenMatrixAdaptor // end of grouping
1741 } // end of NS
1742 
1743 } // end namespace DataTransferKit
1744 
1745 #endif /* DTK_NANOFLANN_HPP_ */
SearchParams(int checks_IGNORED_=32, float eps_=0, bool sorted_=true)
void resize(const size_t nElements)
size_t radiusSearch(const ElementType *query_point, const DistanceType radius, Teuchos::Array< std::pair< IndexType, DistanceType >> &IndicesDists, const SearchParams &searchParams) const
KDTreeEigenMatrixAdaptor(const int dimensionality, const MatrixType &mat, const int leaf_max_size=10)
Constructor: takes a const ref to the matrix object with the data points.
void findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParams &searchParams) const
int dim
Dimensionality of each data point.
float eps
search for eps-approximate neighbours (default: 0)
array_or_vector_selector< DIM, Interval >::container_t BoundingBox
void knnSearch(const ElementType *query_point, const size_t num_closest, IndexType *out_indices, DistanceType *out_distances_sq, const int nChecks_IGNORED=10) const
T * allocate(size_t count=1)
const DatasetAdaptor & dataset
The source of our data.
std::pair< IndexType, DistanceType > worst_item() const
bool operator()(const PairType &p1, const PairType &p2) const
void query(const num_t *query_point, const size_t num_closest, IndexType *out_indices, num_t *out_distances_sq, const int nChecks_IGNORED=10) const
KDTreeSingleIndexAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params=KDTreeSingleIndexAdaptorParams())
array_or_vector_selector< DIM, DistanceType >::container_t distance_vector_t
DTK_BasicEntitySet.cpp.
void set_radius_and_clear(const DistanceType r)