ROOT  6.06/08
Reference Guide
TKDTree.cxx
Go to the documentation of this file.
1 // @(#)root/mathcore:$Id$
2 // Authors: Marian Ivanov and Alexandru Bercuci 04/03/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TKDTree.h"
13 #include "TRandom.h"
14 
15 #include "TString.h"
16 #include <string.h>
17 #include <limits>
18 
20 
21 
22 /**
23 
24 \class TKDTree
25 \brief Class implementing a kd-tree
26 
27 
28 
29 Contents:
30 1. What is kd-tree
31 2. How to cosntruct kdtree - Pseudo code
32 3. Using TKDTree
33  a. Creating the kd-tree and setting the data
34  b. Navigating the kd-tree
35 4. TKDTree implementation - technical details
36  a. The order of nodes in internal arrays
37  b. Division algorithm
38  c. The order of nodes in boundary related arrays
39 
40 
41 
42 ### 1. What is kdtree ? ( [http://en.wikipedia.org/wiki/Kd-tree] )
43 
44 In computer science, a kd-tree (short for k-dimensional tree) is a space-partitioning data structure
45 for organizing points in a k-dimensional space. kd-trees are a useful data structure for several
46 applications, such as searches involving a multidimensional search key (e.g. range searches and
47 nearest neighbour searches). kd-trees are a special case of BSP trees.
48 
49 A kd-tree uses only splitting planes that are perpendicular to one of the coordinate system axes.
50 This differs from BSP trees, in which arbitrary splitting planes can be used.
51 In addition, in the typical definition every node of a kd-tree, from the root to the leaves, stores a point.
52 This differs from BSP trees, in which leaves are typically the only nodes that contain points
53 (or other geometric primitives). As a consequence, each splitting plane must go through one of
54 the points in the kd-tree. kd-trees are a variant that store data only in leaf nodes.
55 
56 ### 2. Constructing a classical kd-tree ( Pseudo code)
57 
58 Since there are many possible ways to choose axis-aligned splitting planes, there are many different ways
59 to construct kd-trees. The canonical method of kd-tree construction has the following constraints:
60 
61 * As one moves down the tree, one cycles through the axes used to select the splitting planes.
62  (For example, the root would have an x-aligned plane, the root's children would both have y-aligned
63  planes, the root's grandchildren would all have z-aligned planes, and so on.)
64 * At each step, the point selected to create the splitting plane is the median of the points being
65  put into the kd-tree, with respect to their coordinates in the axis being used. (Note the assumption
66  that we feed the entire set of points into the algorithm up-front.)
67 
68 This method leads to a balanced kd-tree, in which each leaf node is about the same distance from the root.
69 However, balanced trees are not necessarily optimal for all applications.
70 The following pseudo-code illustrates this canonical construction procedure (NOTE, that the procedure used
71 by the TKDTree class is a bit different, the following pseudo-code is given as a simple illustration of the
72 concept):
73 
74 ~~~~
75 function kdtree (list of points pointList, int depth)
76 {
77  if pointList is empty
78  return nil;
79  else
80  {
81  // Select axis based on depth so that axis cycles through all valid values
82  var int axis := depth mod k;
83 
84  // Sort point list and choose median as pivot element
85  select median from pointList;
86 
87  // Create node and construct subtrees
88  var tree_node node;
89  node.location := median;
90  node.leftChild := kdtree(points in pointList before median, depth+1);
91  node.rightChild := kdtree(points in pointList after median, depth+1);
92  return node;
93  }
94 }
95 ~~~~
96 
97 Our construction method is optimized to save memory, and differs a bit from the constraints above.
98 In particular, the division axis is chosen as the one with the biggest spread, and the point to create the
99 splitting plane is chosen so, that one of the two subtrees contains exactly 2^k terminal nodes and is a
100 perfectly balanced binary tree, and, while at the same time, trying to keep the number of terminal nodes
101 in the 2 subtrees as close as possible. The following section gives more details about our implementation.
102 
103 ### 3. Using TKDTree
104 
105 #### 3a. Creating the tree and setting the data
106  The interface of the TKDTree, that allows to set input data, has been developped to simplify using it
107  together with TTree::Draw() functions. That's why the data has to be provided column-wise. For example:
108 
109 \code{.cpp}
110  {
111  TTree *datatree = ...
112  ...
113  datatree->Draw("x:y:z", "selection", "goff");
114  //now make a kd-tree on the drawn variables
115  TKDTreeID *kdtree = new TKDTreeID(npoints, 3, 1);
116  kdtree->SetData(0, datatree->GetV1());
117  kdtree->SetData(1, datatree->GetV2());
118  kdtree->SetData(2, datatree->GetV3());
119  kdtree->Build();
120  }
121  NOTE, that this implementation of kd-tree doesn't support adding new points after the tree has been built
122  Of course, it's not necessary to use TTree::Draw(). What is important, is to have data columnwise.
123  An example with regular arrays:
124  {
125  Int_t npoints = 100000;
126  Int_t ndim = 3;
127  Int_t bsize = 1;
128  Double_t xmin = -0.5;
129  Double_t xmax = 0.5;
130  Double_t *data0 = new Double_t[npoints];
131  Double_t *data1 = new Double_t[npoints];
132  Double_t *data2 = new Double_t[npoints];
133  Double_t *y = new Double_t[npoints];
134  for (Int_t i=0; i<npoints; i++){
135  data0[i]=gRandom->Uniform(xmin, xmax);
136  data1[i]=gRandom->Uniform(xmin, xmax);
137  data2[i]=gRandom->Uniform(xmin, xmax);
138  }
139  TKDTreeID *kdtree = new TKDTreeID(npoints, ndim, bsize);
140  kdtree->SetData(0, data0);
141  kdtree->SetData(1, data1);
142  kdtree->SetData(2, data2);
143  kdtree->Build();
144  }
145 \endcode
146 
147  By default, the kd-tree doesn't own the data and doesn't delete it with itself. If you want the
148  data to be deleted together with the kd-tree, call TKDTree::SetOwner(kTRUE).
149 
150  Most functions of the kd-tree don't require the original data to be present after the tree
151  has been built. Check the functions documentation for more details.
152 
153 #### 3b. Navigating the kd-tree
154 
155  Nodes of the tree are indexed top to bottom, left to right. The root node has index 0. Functions
156  TKDTree::GetLeft(Index inode), TKDTree::GetRight(Index inode) and TKDTree::GetParent(Index inode)
157  allow to find the children and the parent of a given node.
158 
159  For a given node, one can find the indexes of the original points, contained in this node,
160  by calling the GetNodePointsIndexes(Index inode) function. Additionally, for terminal nodes,
161  there is a function GetPointsIndexes(Index inode) that returns a pointer to the relevant
162  part of the index array. To find the number of point in the node
163  (not only terminal), call TKDTree::GetNpointsNode(Index inode).
164 
165 ### 4. TKDtree implementation details - internal information, not needed to use the kd-tree.
166 
167 #### 4a. Order of nodes in the node information arrays:
168 
169 TKDtree is optimized to minimize memory consumption.
170 Nodes of the TKDTree do not store pointers to the left and right children or to the parent node,
171 but instead there are several 1-d arrays of size fNNodes with information about the nodes.
172 The order of the nodes information in the arrays is described below. It's important to understand
173 it, if one's class needs to store some kind of additional information on the per node basis, for
174 example, the fit function parameters.
175 
176 - Drawback: Insertion to the TKDtree is not supported.
177 - Advantage: Random access is supported
178 
179 As noted above, the construction of the kd-tree involves choosing the axis and the point on
180 that axis to divide the remaining points approximately in half. The exact algorithm for choosing
181 the division point is described in the next section. The sequence of divisions is
182 recorded in the following arrays:
183 ~~~~
184 fAxix[fNNodes] - Division axis (0,1,2,3 ...)
185 fValue[fNNodes] - Division value
186 ~~~~
187 
188 Given the index of a node in those arrays, it's easy to find the indices, corresponding to
189 children nodes or the parent node:
190 Suppose, the parent node is stored under the index inode. Then:
191 - Left child `index = inode*2+1`
192 - Right child `index = (inode+1)*2`
193 
194 Suppose, that the child node is stored under the index inode. Then:
195 - Parent `index = inode/2`
196 
197 Number of division nodes and number of terminals :
198 `fNNodes = (fNPoints/fBucketSize)`
199 
200 The nodes are filled always from left side to the right side:
201 Let inode be the index of a node, and irow - the index of a row
202 The TKDTree looks the following way:
203 Ideal case:
204 ~~~~
205 Number of _terminal_ nodes = 2^N, N=3
206 
207  INode
208 irow 0 0 - 1 inode
209 irow 1 1 2 - 2 inodes
210 irow 2 3 4 5 6 - 4 inodes
211 irow 3 7 8 9 10 11 12 13 14 - 8 inodes
212 ~~~~
213 
214 Non ideal case:
215 ~~~~
216 Number of _terminal_ nodes = 2^N+k, N=3 k=1
217 
218  INode
219 irow 0 0 - 1 inode
220 irow 1 1 2 - 2 inodes
221 irow 2 3 4 5 6 - 3 inodes
222 irow 3 7 8 9 10 11 12 13 14 - 8 inodes
223 irow 4 15 16 - 2 inodes
224 ~~~~
225 
226 #### 4b. The division algorithm:
227 
228 As described above, the kd-tree is built by repeatingly dividing the given set of points into
229 2 smaller sets. The cut is made on the axis with the biggest spread, and the value on the axis,
230 on which the cut is performed, is chosen based on the following formula:
231 Suppose, we want to divide n nodes into 2 groups, left and right. Then the left and right
232 will have the following number of nodes:
233 
234 ~~~~
235 n=2^k+rest
236 
237 Left = 2^k-1 + ((rest>2^k-2) ? 2^k-2 : rest)
238 Right = 2^k-1 + ((rest>2^k-2) ? rest-2^k-2 : 0)
239 ~~~~
240 
241 For example, let `n_nodes=67`. Then, the closest `2^k=64, 2^k-1=32, 2^k-2=16`.
242 Left node gets `32+3=35` sub-nodes, and the right node gets 32 sub-nodes
243 
244 The division process continues until all the nodes contain not more than a predefined number
245 of points.
246 
247 #### 4c. The order of nodes in boundary-related arrays
248 
249 Some kd-tree based algorithms need to know the boundaries of each node. This information can
250 be computed by calling the TKDTree::MakeBoundaries() function. It fills the following arrays:
251 
252 - `fRange` : array containing the boundaries of the domain:
253  `| 1st dimension (min + max) | 2nd dimension (min + max) | ...`
254 `fBoundaries` : nodes boundaries
255  `| 1st node {1st dim * 2 elements | 2nd dim * 2 elements | ...} | 2nd node {...} | ...`
256 
257 
258 The nodes are arranged in the order described in section 3a.
259 
260 
261 - **Note**: the storage of the TKDTree in a file which include also the contained data is not
262  supported. One must store the data separatly in a file (e.g. using a TTree) and then
263  re-creating the TKDTree from the data, after having read them from the file
264 
265 @ingroup Random
266 
267 
268 */
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Default constructor. Nothing is built
271 
272 template <typename Index, typename Value>
273 TKDTree<Index, Value>::TKDTree() :
274  TObject()
275  ,fDataOwner(kFALSE)
276  ,fNNodes(0)
277  ,fTotalNodes(0)
278  ,fNDim(0)
279  ,fNDimm(0)
280  ,fNPoints(0)
281  ,fBucketSize(0)
282  ,fAxis(0x0)
283  ,fValue(0x0)
284  ,fRange(0x0)
285  ,fData(0x0)
286  ,fBoundaries(0x0)
287  ,fIndPoints(0x0)
288  ,fRowT0(0)
289  ,fCrossNode(0)
290  ,fOffset(0)
291 {
292 }
293 
294 template <typename Index, typename Value>
296  TObject()
297  ,fDataOwner(0)
298  ,fNNodes(0)
299  ,fTotalNodes(0)
300  ,fNDim(ndim)
301  ,fNDimm(2*ndim)
302  ,fNPoints(npoints)
303  ,fBucketSize(bsize)
304  ,fAxis(0x0)
305  ,fValue(0x0)
306  ,fRange(0x0)
307  ,fData(0x0)
308  ,fBoundaries(0x0)
309  ,fIndPoints(0x0)
310  ,fRowT0(0)
311  ,fCrossNode(0)
312  ,fOffset(0)
313 {
314 // Create the kd-tree of npoints from ndim-dimensional space. Parameter bsize stands for the
315 // maximal number of points in the terminal nodes (buckets).
316 // Proceed by calling one of the SetData() functions and then the Build() function
317 // Note, that updating the tree with new data after the Build() function has been called is
318 // not possible!
319 
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Create a kd-tree from the provided data array. This function only sets the data,
324 /// call Build() to build the tree!!!
325 /// Parameteres:
326 /// - npoints - total number of points. Adding points after the tree is built is not supported
327 /// - ndim - number of dimensions
328 /// - bsize - maximal number of points in the terminal nodes
329 /// - data - the data array
330 ///
331 /// The data should be placed columnwise (like in a TTree).
332 /// The columnwise orientation is chosen to simplify the usage together with TTree::GetV1() like functions.
333 /// An example of filling such an array for a 2d case:
334 /// Double_t **data = new Double_t*[2];
335 /// data[0] = new Double_t[npoints];
336 /// data[1] = new Double_t[npoints];
337 /// for (Int_t i=0; i<npoints; i++){
338 /// data[0][i]=gRandom->Uniform(-1, 1); //fill the x-coordinate
339 /// data[1][i]=gRandom->Uniform(-1, 1); //fill the y-coordinate
340 /// }
341 ///
342 /// By default, the kd-tree doesn't own the data. If you want the kd-tree to delete the data array, call
343 /// kdtree->SetOwner(kTRUE).
344 ///
345 
346 template <typename Index, typename Value>
348  TObject()
349  ,fDataOwner(0)
350  ,fNNodes(0)
351  ,fTotalNodes(0)
352  ,fNDim(ndim)
353  ,fNDimm(2*ndim)
354  ,fNPoints(npoints)
355  ,fBucketSize(bsize)
356  ,fAxis(0x0)
357  ,fValue(0x0)
358  ,fRange(0x0)
359  ,fData(data) //Columnwise!!!!!
360  ,fBoundaries(0x0)
361  ,fIndPoints(0x0)
362  ,fRowT0(0)
363  ,fCrossNode(0)
364  ,fOffset(0)
365 {
366 
367  //Build();
368 }
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// Destructor
372 /// By default, the original data is not owned by kd-tree and is not deleted with it.
373 /// If you want to delete the data along with the kd-tree, call SetOwner(kTRUE).
374 
375 template <typename Index, typename Value>
377 {
378  if (fAxis) delete [] fAxis;
379  if (fValue) delete [] fValue;
380  if (fIndPoints) delete [] fIndPoints;
381  if (fRange) delete [] fRange;
382  if (fBoundaries) delete [] fBoundaries;
383  if (fData) {
384  if (fDataOwner==1){
385  //the tree owns all the data
386  for(int idim=0; idim<fNDim; idim++) delete [] fData[idim];
387  }
388  if (fDataOwner>0) {
389  //the tree owns the array of pointers
390  delete [] fData;
391  }
392  }
393 // if (fDataOwner && fData){
394 // for(int idim=0; idim<fNDim; idim++) delete [] fData[idim];
395 // delete [] fData;
396 // }
397 }
398 
399 
400 ////////////////////////////////////////////////////////////////////////////////
401 ///
402 /// Build the kd-tree
403 ///
404 /// 1. calculate number of nodes
405 /// 2. calculate first terminal row
406 /// 3. initialize index array
407 /// 4. non recursive building of the binary tree
408 ///
409 ///
410 /// The tree is divided recursively. See class description, section 4b for the details
411 /// of the division alogrithm
412 
413 template <typename Index, typename Value>
415 {
416  //1.
419  fTotalNodes = fNNodes + fNPoints/fBucketSize + ((fNPoints%fBucketSize)?1:0);
420  //2.
421  fRowT0=0;
422  for ( ;(fNNodes+1)>(1<<fRowT0);fRowT0++) {}
423  fRowT0-=1;
424  // 2 = 2**0 + 1
425  // 3 = 2**1 + 1
426  // 4 = 2**1 + 2
427  // 5 = 2**2 + 1
428  // 6 = 2**2 + 2
429  // 7 = 2**2 + 3
430  // 8 = 2**2 + 4
431 
432  //3.
433  // allocate space for boundaries
434  fRange = new Value[2*fNDim];
435  fIndPoints= new Index[fNPoints];
436  for (Index i=0; i<fNPoints; i++) fIndPoints[i] = i;
437  fAxis = new UChar_t[fNNodes];
438  fValue = new Value[fNNodes];
439  //
440  fCrossNode = (1<<(fRowT0+1))-1;
442  //
443  // fOffset = (((fNNodes+1)-(1<<fRowT0)))*2;
444  Int_t over = (fNNodes+1)-(1<<fRowT0);
445  Int_t filled = ((1<<fRowT0)-over)*fBucketSize;
446  fOffset = fNPoints-filled;
447 
448  //
449  // printf("Row0 %d\n", fRowT0);
450  // printf("CrossNode %d\n", fCrossNode);
451  // printf("Offset %d\n", fOffset);
452  //
453  //
454  //4.
455  // stack for non recursive build - size 128 bytes enough
456  Int_t rowStack[128];
457  Int_t nodeStack[128];
458  Int_t npointStack[128];
459  Int_t posStack[128];
460  Int_t currentIndex = 0;
461  Int_t iter =0;
462  rowStack[0] = 0;
463  nodeStack[0] = 0;
464  npointStack[0] = fNPoints;
465  posStack[0] = 0;
466  //
467  Int_t nbucketsall =0;
468  while (currentIndex>=0){
469  iter++;
470  //
471  Int_t npoints = npointStack[currentIndex];
472  if (npoints<=fBucketSize) {
473  //printf("terminal node : index %d iter %d\n", currentIndex, iter);
474  currentIndex--;
475  nbucketsall++;
476  continue; // terminal node
477  }
478  Int_t crow = rowStack[currentIndex];
479  Int_t cpos = posStack[currentIndex];
480  Int_t cnode = nodeStack[currentIndex];
481  //printf("currentIndex %d npoints %d node %d\n", currentIndex, npoints, cnode);
482  //
483  // divide points
484  Int_t nbuckets0 = npoints/fBucketSize; //current number of buckets
485  if (npoints%fBucketSize) nbuckets0++; //
486  Int_t restRows = fRowT0-rowStack[currentIndex]; // rest of fully occupied node row
487  if (restRows<0) restRows =0;
488  for (;nbuckets0>(2<<restRows); restRows++) {}
489  Int_t nfull = 1<<restRows;
490  Int_t nrest = nbuckets0-nfull;
491  Int_t nleft =0, nright =0;
492  //
493  if (nrest>(nfull/2)){
494  nleft = nfull*fBucketSize;
495  nright = npoints-nleft;
496  }else{
497  nright = nfull*fBucketSize/2;
498  nleft = npoints-nright;
499  }
500 
501  //
502  //find the axis with biggest spread
503  Value maxspread=0;
504  Value tempspread, min, max;
505  Index axspread=0;
506  Value *array;
507  for (Int_t idim=0; idim<fNDim; idim++){
508  array = fData[idim];
509  Spread(npoints, array, fIndPoints+cpos, min, max);
510  tempspread = max - min;
511  if (maxspread < tempspread) {
512  maxspread=tempspread;
513  axspread = idim;
514  }
515  if(cnode) continue;
516  //printf("set %d %6.3f %6.3f\n", idim, min, max);
517  fRange[2*idim] = min; fRange[2*idim+1] = max;
518  }
519  array = fData[axspread];
520  KOrdStat(npoints, array, nleft, fIndPoints+cpos);
521  fAxis[cnode] = axspread;
522  fValue[cnode] = array[fIndPoints[cpos+nleft]];
523  //printf("Set node %d : ax %d val %f\n", cnode, node->fAxis, node->fValue);
524  //
525  //
526  npointStack[currentIndex] = nleft;
527  rowStack[currentIndex] = crow+1;
528  posStack[currentIndex] = cpos;
529  nodeStack[currentIndex] = cnode*2+1;
530  currentIndex++;
531  npointStack[currentIndex] = nright;
532  rowStack[currentIndex] = crow+1;
533  posStack[currentIndex] = cpos+nleft;
534  nodeStack[currentIndex] = (cnode*2)+2;
535  //
536  if (0){
537  // consistency check
538  Info("Build()", "%s", Form("points %d left %d right %d", npoints, nleft, nright));
539  if (nleft<nright) Warning("Build", "Problem Left-Right");
540  if (nleft<0 || nright<0) Warning("Build()", "Problem Negative number");
541  }
542  }
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 ///Find kNN nearest neighbors to the point in the first argument
547 ///Returns 1 on success, 0 on failure
548 ///Arrays ind and dist are provided by the user and are assumed to be at least kNN elements long
549 
550 template <typename Index, typename Value>
552 {
553 
554  if (!ind || !dist) {
555  Error("FindNearestNeighbors", "Working arrays must be allocated by the user!");
556  return;
557  }
558  for (Int_t i=0; i<kNN; i++){
560  ind[i]=-1;
561  }
563  UpdateNearestNeighbors(0, point, kNN, ind, dist);
564 
565 }
566 
567 ////////////////////////////////////////////////////////////////////////////////
568 ///Update the nearest neighbors values by examining the node inode
569 
570 template <typename Index, typename Value>
572 {
573  Value min=0;
574  Value max=0;
575  DistanceToNode(point, inode, min, max);
576  if (min > dist[kNN-1]){
577  //there are no closer points in this node
578  return;
579  }
580  if (IsTerminal(inode)) {
581  //examine points one by one
582  Index f1, l1, f2, l2;
583  GetNodePointsIndexes(inode, f1, l1, f2, l2);
584  for (Int_t ipoint=f1; ipoint<=l1; ipoint++){
585  Double_t d = Distance(point, fIndPoints[ipoint]);
586  if (d<dist[kNN-1]){
587  //found a closer point
588  Int_t ishift=0;
589  while(ishift<kNN && d>dist[ishift])
590  ishift++;
591  //replace the neighbor #ishift with the found point
592  //and shift the rest 1 index value to the right
593  for (Int_t i=kNN-1; i>ishift; i--){
594  dist[i]=dist[i-1];
595  ind[i]=ind[i-1];
596  }
597  dist[ishift]=d;
598  ind[ishift]=fIndPoints[ipoint];
599  }
600  }
601  return;
602  }
603  if (point[fAxis[inode]]<fValue[inode]){
604  //first examine the node that contains the point
605  UpdateNearestNeighbors(GetLeft(inode), point, kNN, ind, dist);
606  UpdateNearestNeighbors(GetRight(inode), point, kNN, ind, dist);
607  } else {
608  UpdateNearestNeighbors(GetRight(inode), point, kNN, ind, dist);
609  UpdateNearestNeighbors(GetLeft(inode), point, kNN, ind, dist);
610  }
611 }
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 ///Find the distance between point of the first argument and the point at index value ind
615 ///Type argument specifies the metric: type=2 - L2 metric, type=1 - L1 metric
616 
617 template <typename Index, typename Value>
619 {
620  Double_t dist = 0;
621  if (type==2){
622  for (Int_t idim=0; idim<fNDim; idim++){
623  dist+=(point[idim]-fData[idim][ind])*(point[idim]-fData[idim][ind]);
624  }
625  return TMath::Sqrt(dist);
626  } else {
627  for (Int_t idim=0; idim<fNDim; idim++){
628  dist+=TMath::Abs(point[idim]-fData[idim][ind]);
629  }
630 
631  return dist;
632  }
633  return -1;
634 
635 }
636 
637 ////////////////////////////////////////////////////////////////////////////////
638 ///Find the minimal and maximal distance from a given point to a given node.
639 ///Type argument specifies the metric: type=2 - L2 metric, type=1 - L1 metric
640 ///If the point is inside the node, both min and max are set to 0.
641 
642 template <typename Index, typename Value>
644 {
645  Value *bound = GetBoundaryExact(inode);
646  min = 0;
647  max = 0;
648  Double_t dist1, dist2;
649 
650  if (type==2){
651  for (Int_t idim=0; idim<fNDimm; idim+=2){
652  dist1 = (point[idim/2]-bound[idim])*(point[idim/2]-bound[idim]);
653  dist2 = (point[idim/2]-bound[idim+1])*(point[idim/2]-bound[idim+1]);
654  //min+=TMath::Min(dist1, dist2);
655  if (point[idim/2]<bound[idim] || point[idim/2]>bound[idim+1])
656  min+= (dist1>dist2)? dist2 : dist1;
657  // max+=TMath::Max(dist1, dist2);
658  max+= (dist1>dist2)? dist1 : dist2;
659  }
660  min = TMath::Sqrt(min);
661  max = TMath::Sqrt(max);
662  } else {
663  for (Int_t idim=0; idim<fNDimm; idim+=2){
664  dist1 = TMath::Abs(point[idim/2]-bound[idim]);
665  dist2 = TMath::Abs(point[idim/2]-bound[idim+1]);
666  //min+=TMath::Min(dist1, dist2);
667  min+= (dist1>dist2)? dist2 : dist1;
668  // max+=TMath::Max(dist1, dist2);
669  max+= (dist1>dist2)? dist1 : dist2;
670  }
671  }
672 }
673 
674 ////////////////////////////////////////////////////////////////////////////////
675 /// returns the index of the terminal node to which point belongs
676 /// (index in the fAxis, fValue, etc arrays)
677 /// returns -1 in case of failure
678 
679 template <typename Index, typename Value>
681 {
682  Index stackNode[128], inode;
683  Int_t currentIndex =0;
684  stackNode[0] = 0;
685  while (currentIndex>=0){
686  inode = stackNode[currentIndex];
687  if (IsTerminal(inode)) return inode;
688 
689  currentIndex--;
690  if (point[fAxis[inode]]<=fValue[inode]){
691  currentIndex++;
692  stackNode[currentIndex]=(inode<<1)+1; //GetLeft()
693  }
694  if (point[fAxis[inode]]>=fValue[inode]){
695  currentIndex++;
696  stackNode[currentIndex]=(inode+1)<<1; //GetRight()
697  }
698  }
699 
700  return -1;
701 }
702 
703 
704 
705 ////////////////////////////////////////////////////////////////////////////////
706 ///
707 /// find the index of point
708 /// works only if we keep fData pointers
709 
710 template <typename Index, typename Value>
711 void TKDTree<Index, Value>::FindPoint(Value * point, Index &index, Int_t &iter){
712  Int_t stackNode[128];
713  Int_t currentIndex =0;
714  stackNode[0] = 0;
715  iter =0;
716  //
717  while (currentIndex>=0){
718  iter++;
719  Int_t inode = stackNode[currentIndex];
720  currentIndex--;
721  if (IsTerminal(inode)){
722  // investigate terminal node
723  Int_t indexIP = (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNNodes)*fBucketSize+fOffset;
724  printf("terminal %d indexP %d\n", inode, indexIP);
725  for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
726  Bool_t isOK = kTRUE;
727  indexIP+=ibucket;
728  printf("ibucket %d index %d\n", ibucket, indexIP);
729  if (indexIP>=fNPoints) continue;
730  Int_t index0 = fIndPoints[indexIP];
731  for (Int_t idim=0;idim<fNDim;idim++) if (fData[idim][index0]!=point[idim]) isOK = kFALSE;
732  if (isOK) index = index0;
733  }
734  continue;
735  }
736 
737  if (point[fAxis[inode]]<=fValue[inode]){
738  currentIndex++;
739  stackNode[currentIndex]=(inode*2)+1;
740  }
741  if (point[fAxis[inode]]>=fValue[inode]){
742  currentIndex++;
743  stackNode[currentIndex]=(inode*2)+2;
744  }
745  }
746  //
747  // printf("Iter\t%d\n",iter);
748 }
749 
750 ////////////////////////////////////////////////////////////////////////////////
751 ///Find all points in the sphere of a given radius "range" around the given point
752 ///1st argument - the point
753 ///2nd argument - radius of the shere
754 ///3rd argument - a vector, in which the results will be returned
755 
756 template <typename Index, typename Value>
757 void TKDTree<Index, Value>::FindInRange(Value * point, Value range, std::vector<Index> &res)
758 {
760  UpdateRange(0, point, range, res);
761 }
762 
763 ////////////////////////////////////////////////////////////////////////////////
764 ///Internal recursive function with the implementation of range searches
765 
766 template <typename Index, typename Value>
767 void TKDTree<Index, Value>::UpdateRange(Index inode, Value* point, Value range, std::vector<Index> &res)
768 {
769  Value min, max;
770  DistanceToNode(point, inode, min, max);
771  if (min>range) {
772  //all points of this node are outside the range
773  return;
774  }
775  if (max<range && max>0) {
776  //all points of this node are inside the range
777 
778  Index f1, l1, f2, l2;
779  GetNodePointsIndexes(inode, f1, l1, f2, l2);
780 
781  for (Int_t ipoint=f1; ipoint<=l1; ipoint++){
782  res.push_back(fIndPoints[ipoint]);
783  }
784  for (Int_t ipoint=f2; ipoint<=l2; ipoint++){
785  res.push_back(fIndPoints[ipoint]);
786  }
787  return;
788  }
789 
790  //this node intersects with the range
791  if (IsTerminal(inode)){
792  //examine the points one by one
793  Index f1, l1, f2, l2;
794  Double_t d;
795  GetNodePointsIndexes(inode, f1, l1, f2, l2);
796  for (Int_t ipoint=f1; ipoint<=l1; ipoint++){
797  d = Distance(point, fIndPoints[ipoint]);
798  if (d <= range){
799  res.push_back(fIndPoints[ipoint]);
800  }
801  }
802  return;
803  }
804  if (point[fAxis[inode]]<=fValue[inode]){
805  //first examine the node that contains the point
806  UpdateRange(GetLeft(inode),point, range, res);
807  UpdateRange(GetRight(inode),point, range, res);
808  } else {
809  UpdateRange(GetLeft(inode),point, range, res);
810  UpdateRange(GetRight(inode),point, range, res);
811  }
812 }
813 
814 ////////////////////////////////////////////////////////////////////////////////
815 ///return the indices of the points in that terminal node
816 ///for all the nodes except last, the size is fBucketSize
817 ///for the last node it's fOffset%fBucketSize
818 
819 template <typename Index, typename Value>
821 {
822  if (!IsTerminal(node)){
823  printf("GetPointsIndexes() only for terminal nodes, use GetNodePointsIndexes() instead\n");
824  return 0;
825  }
826  Int_t offset = (node >= fCrossNode) ? (node-fCrossNode)*fBucketSize : fOffset+(node-fNNodes)*fBucketSize;
827  return &fIndPoints[offset];
828 }
829 
830 ////////////////////////////////////////////////////////////////////////////////
831 ///Return the indices of points in that node
832 ///Indices are returned as the first and last value of the part of indices array, that belong to this node
833 ///Sometimes points are in 2 intervals, then the first and last value for the second one are returned in
834 ///third and fourth parameter, otherwise first2 is set to 0 and last2 is set to -1
835 ///To iterate over all the points of the node #inode, one can do, for example:
836 ///Index *indices = kdtree->GetPointsIndexes();
837 ///Int_t first1, last1, first2, last2;
838 ///kdtree->GetPointsIndexes(inode, first1, last1, first2, last2);
839 ///for (Int_t ipoint=first1; ipoint<=last1; ipoint++){
840 /// point = indices[ipoint];
841 /// //do something with point;
842 ///}
843 ///for (Int_t ipoint=first2; ipoint<=last2; ipoint++){
844 /// point = indices[ipoint];
845 /// //do something with point;
846 ///}
847 
848 template <typename Index, typename Value>
849 void TKDTree<Index, Value>::GetNodePointsIndexes(Int_t node, Int_t &first1, Int_t &last1, Int_t &first2, Int_t &last2) const
850 {
851 
852  if (IsTerminal(node)){
853  //the first point in the node is computed by the following formula:
854  Index offset = (node >= fCrossNode) ? (node-fCrossNode)*fBucketSize : fOffset+(node-fNNodes)*fBucketSize;
855  first1 = offset;
856  last1 = offset + GetNPointsNode(node)-1;
857  first2 = 0;
858  last2 = -1;
859  return;
860  }
861 
862  Index firsttermnode = fNNodes;
863  Index ileft = node;
864  Index iright = node;
865  Index f1, l1, f2, l2;
866 //this is the left-most node
867  while (ileft<firsttermnode)
868  ileft = GetLeft(ileft);
869 //this is the right-most node
870  while (iright<firsttermnode)
871  iright = GetRight(iright);
872 
873  if (ileft>iright){
874 // first1 = firsttermnode;
875 // last1 = iright;
876 // first2 = ileft;
877 // last2 = fTotalNodes-1;
878  GetNodePointsIndexes(firsttermnode, f1, l1, f2, l2);
879  first1 = f1;
880  GetNodePointsIndexes(iright, f1, l1, f2, l2);
881  last1 = l1;
882  GetNodePointsIndexes(ileft, f1, l1, f2, l2);
883  first2 = f1;
884  GetNodePointsIndexes(fTotalNodes-1, f1, l1, f2, l2);
885  last2 = l1;
886 
887  } else {
888  GetNodePointsIndexes(ileft, f1, l1, f2, l2);
889  first1 = f1;
890  GetNodePointsIndexes(iright, f1, l1, f2, l2);
891  last1 = l1;
892  first2 = 0;
893  last2 = -1;
894  }
895 }
896 
897 ////////////////////////////////////////////////////////////////////////////////
898 ///Get number of points in this node
899 ///for all the terminal nodes except last, the size is fBucketSize
900 ///for the last node it's fOffset%fBucketSize, or if fOffset%fBucketSize==0, it's also fBucketSize
901 
902 template <typename Index, typename Value>
904 {
905  if (IsTerminal(inode)){
906 
907  if (inode!=fTotalNodes-1) return fBucketSize;
908  else {
909  if (fOffset%fBucketSize==0) return fBucketSize;
910  else return fOffset%fBucketSize;
911  }
912  }
913 
914  Int_t f1, l1, f2, l2;
915  GetNodePointsIndexes(inode, f1, l1, f2, l2);
916  Int_t sum = l1-f1+1;
917  sum += l2-f2+1;
918  return sum;
919 }
920 
921 
922 ////////////////////////////////////////////////////////////////////////////////
923 /// Set the data array. See the constructor function comments for details
924 
925 template <typename Index, typename Value>
927 {
928 // TO DO
929 //
930 // Check reconstruction/reallocation of memory of data. Maybe it is not
931 // necessary to delete and realocate space but only to use the same space
932 
933  Clear();
934 
935  //Columnwise!!!!
936  fData = data;
937  fNPoints = npoints;
938  fNDim = ndim;
939  fBucketSize = bsize;
940 
941  Build();
942 }
943 
944 ////////////////////////////////////////////////////////////////////////////////
945 ///Set the coordinate #ndim of all points (the column #ndim of the data matrix)
946 ///After setting all the data columns, proceed by calling Build() function
947 ///Note, that calling this function after Build() is not possible
948 ///Note also, that no checks on the array sizes is performed anywhere
949 
950 template <typename Index, typename Value>
952 {
953  if (fAxis || fValue) {
954  Error("SetData", "The tree has already been built, no updates possible");
955  return 0;
956  }
957 
958  if (!fData) {
959  fData = new Value*[fNDim];
960  }
961  fData[idim]=data;
962  fDataOwner = 2;
963  return 1;
964 }
965 
966 
967 ////////////////////////////////////////////////////////////////////////////////
968 ///Calculate spread of the array a
969 
970 template <typename Index, typename Value>
972 {
973  Index i;
974  min = a[index[0]];
975  max = a[index[0]];
976  for (i=0; i<ntotal; i++){
977  if (a[index[i]]<min) min = a[index[i]];
978  if (a[index[i]]>max) max = a[index[i]];
979  }
980 }
981 
982 
983 ////////////////////////////////////////////////////////////////////////////////
984 ///
985 ///copy of the TMath::KOrdStat because I need an Index work array
986 
987 template <typename Index, typename Value>
989 {
990  Index i, ir, j, l, mid;
991  Index arr;
992  Index temp;
993 
994  Index rk = k;
995  l=0;
996  ir = ntotal-1;
997  for(;;) {
998  if (ir<=l+1) { //active partition contains 1 or 2 elements
999  if (ir == l+1 && a[index[ir]]<a[index[l]])
1000  {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
1001  Value tmp = a[index[rk]];
1002  return tmp;
1003  } else {
1004  mid = (l+ir) >> 1; //choose median of left, center and right
1005  {temp = index[mid]; index[mid]=index[l+1]; index[l+1]=temp;}//elements as partitioning element arr.
1006  if (a[index[l]]>a[index[ir]]) //also rearrange so that a[l]<=a[l+1]
1007  {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
1008 
1009  if (a[index[l+1]]>a[index[ir]])
1010  {temp=index[l+1]; index[l+1]=index[ir]; index[ir]=temp;}
1011 
1012  if (a[index[l]]>a[index[l+1]])
1013  {temp = index[l]; index[l]=index[l+1]; index[l+1]=temp;}
1014 
1015  i=l+1; //initialize pointers for partitioning
1016  j=ir;
1017  arr = index[l+1];
1018  for (;;) {
1019  do i++; while (a[index[i]]<a[arr]);
1020  do j--; while (a[index[j]]>a[arr]);
1021  if (j<i) break; //pointers crossed, partitioning complete
1022  {temp=index[i]; index[i]=index[j]; index[j]=temp;}
1023  }
1024  index[l+1]=index[j];
1025  index[j]=arr;
1026  if (j>=rk) ir = j-1; //keep active the partition that
1027  if (j<=rk) l=i; //contains the k_th element
1028  }
1029  }
1030 }
1031 
1032 ////////////////////////////////////////////////////////////////////////////////
1033 /// Build boundaries for each node. Note, that the boundaries here are built
1034 /// based on the splitting planes of the kd-tree, and don't necessarily pass
1035 /// through the points of the original dataset. For the latter functionality
1036 /// see function MakeBoundariesExact()
1037 /// Boundaries can be retrieved by calling GetBoundary(inode) function that would
1038 /// return an array of boundaries for the specified node, or GetBoundaries() function
1039 /// that would return the complete array.
1040 
1041 template <typename Index, typename Value>
1043 {
1044 
1045  if(range) memcpy(fRange, range, fNDimm*sizeof(Value));
1046  // total number of nodes including terminal nodes
1047  Int_t totNodes = fNNodes + fNPoints/fBucketSize + ((fNPoints%fBucketSize)?1:0);
1048  fBoundaries = new Value[totNodes*fNDimm];
1049  //Info("MakeBoundaries(Value*)", Form("Allocate boundaries for %d nodes", totNodes));
1050 
1051 
1052  // loop
1053  Value *tbounds = 0x0, *cbounds = 0x0;
1054  Int_t cn;
1055  for(int inode=fNNodes-1; inode>=0; inode--){
1056  tbounds = &fBoundaries[inode*fNDimm];
1057  memcpy(tbounds, fRange, fNDimm*sizeof(Value));
1058 
1059  // check left child node
1060  cn = (inode<<1)+1;
1061  if(IsTerminal(cn)) CookBoundaries(inode, kTRUE);
1062  cbounds = &fBoundaries[fNDimm*cn];
1063  for(int idim=0; idim<fNDim; idim++) tbounds[idim<<1] = cbounds[idim<<1];
1064 
1065  // check right child node
1066  cn = (inode+1)<<1;
1067  if(IsTerminal(cn)) CookBoundaries(inode, kFALSE);
1068  cbounds = &fBoundaries[fNDimm*cn];
1069  for(int idim=0; idim<fNDim; idim++) tbounds[(idim<<1)+1] = cbounds[(idim<<1)+1];
1070  }
1071 }
1072 
1073 ////////////////////////////////////////////////////////////////////////////////
1074 /// define index of this terminal node
1075 
1076 template <typename Index, typename Value>
1078 {
1079  Int_t index = (node<<1) + (LEFT ? 1 : 2);
1080  //Info("CookBoundaries()", Form("Node %d", index));
1081 
1082  // build and initialize boundaries for this node
1083  Value *tbounds = &fBoundaries[fNDimm*index];
1084  memcpy(tbounds, fRange, fNDimm*sizeof(Value));
1085  Bool_t flag[256]; // cope with up to 128 dimensions
1086  memset(flag, kFALSE, fNDimm);
1087  Int_t nvals = 0;
1088 
1089  // recurse parent nodes
1090  Int_t pn = node;
1091  while(pn >= 0 && nvals < fNDimm){
1092  if(LEFT){
1093  index = (fAxis[pn]<<1)+1;
1094  if(!flag[index]) {
1095  tbounds[index] = fValue[pn];
1096  flag[index] = kTRUE;
1097  nvals++;
1098  }
1099  } else {
1100  index = fAxis[pn]<<1;
1101  if(!flag[index]) {
1102  tbounds[index] = fValue[pn];
1103  flag[index] = kTRUE;
1104  nvals++;
1105  }
1106  }
1107  LEFT = pn&1;
1108  pn = (pn - 1)>>1;
1109  }
1110 }
1111 
1112 ////////////////////////////////////////////////////////////////////////////////
1113 /// Build boundaries for each node. Unlike MakeBoundaries() function
1114 /// the boundaries built here always pass through a point of the original dataset
1115 /// So, for example, for a terminal node with just one point minimum and maximum for each
1116 /// dimension are the same.
1117 /// Boundaries can be retrieved by calling GetBoundaryExact(inode) function that would
1118 /// return an array of boundaries for the specified node, or GetBoundaries() function
1119 /// that would return the complete array.
1120 
1121 template <typename Index, typename Value>
1123 {
1124 
1125  // total number of nodes including terminal nodes
1126  //Int_t totNodes = fNNodes + fNPoints/fBucketSize + ((fNPoints%fBucketSize)?1:0);
1127  if (fBoundaries){
1128  //boundaries were already computed for this tree
1129  return;
1130  }
1132  Value *min = new Value[fNDim];
1133  Value *max = new Value[fNDim];
1134  for (Index inode=fNNodes; inode<fTotalNodes; inode++){
1135  //go through the terminal nodes
1136  for (Index idim=0; idim<fNDim; idim++){
1137  min[idim]= std::numeric_limits<Value>::max();
1138  max[idim]=-std::numeric_limits<Value>::max();
1139  }
1140  Index *points = GetPointsIndexes(inode);
1141  Index npoints = GetNPointsNode(inode);
1142  //find max and min in each dimension
1143  for (Index ipoint=0; ipoint<npoints; ipoint++){
1144  for (Index idim=0; idim<fNDim; idim++){
1145  if (fData[idim][points[ipoint]]<min[idim])
1146  min[idim]=fData[idim][points[ipoint]];
1147  if (fData[idim][points[ipoint]]>max[idim])
1148  max[idim]=fData[idim][points[ipoint]];
1149  }
1150  }
1151  for (Index idim=0; idim<fNDimm; idim+=2){
1152  fBoundaries[inode*fNDimm + idim]=min[idim/2];
1153  fBoundaries[inode*fNDimm + idim+1]=max[idim/2];
1154  }
1155  }
1156 
1157  delete [] min;
1158  delete [] max;
1159 
1160  Index left, right;
1161  for (Index inode=fNNodes-1; inode>=0; inode--){
1162  //take the min and max of left and right
1163  left = GetLeft(inode)*fNDimm;
1164  right = GetRight(inode)*fNDimm;
1165  for (Index idim=0; idim<fNDimm; idim+=2){
1166  //take the minimum on each dimension
1167  fBoundaries[inode*fNDimm+idim]=TMath::Min(fBoundaries[left+idim], fBoundaries[right+idim]);
1168  //take the maximum on each dimension
1169  fBoundaries[inode*fNDimm+idim+1]=TMath::Max(fBoundaries[left+idim+1], fBoundaries[right+idim+1]);
1170 
1171  }
1172  }
1173 }
1174 
1175 ////////////////////////////////////////////////////////////////////////////////
1176 ///
1177 /// find the smallest node covering the full range - start
1178 ///
1179 
1180 template <typename Index, typename Value>
1181  void TKDTree<Index, Value>::FindBNodeA(Value *point, Value *delta, Int_t &inode){
1182  inode =0;
1183  for (;inode<fNNodes;){
1184  if (TMath::Abs(point[fAxis[inode]] - fValue[inode])<delta[fAxis[inode]]) break;
1185  inode = (point[fAxis[inode]] < fValue[inode]) ? (inode*2)+1: (inode*2)+2;
1186  }
1187 }
1188 
1189 ////////////////////////////////////////////////////////////////////////////////
1190 /// Get the boundaries
1191 
1192 template <typename Index, typename Value>
1194 {
1195  if(!fBoundaries) MakeBoundaries();
1196  return fBoundaries;
1197 }
1198 
1199 
1200 ////////////////////////////////////////////////////////////////////////////////
1201 /// Get the boundaries
1202 
1203 template <typename Index, typename Value>
1205 {
1207  return fBoundaries;
1208 }
1209 
1210 ////////////////////////////////////////////////////////////////////////////////
1211 /// Get a boundary
1212 
1213 template <typename Index, typename Value>
1215 {
1216  if(!fBoundaries) MakeBoundaries();
1217  return &fBoundaries[node*2*fNDim];
1218 }
1219 
1220 ////////////////////////////////////////////////////////////////////////////////
1221 /// Get a boundary
1222 
1223 template <typename Index, typename Value>
1225 {
1227  return &fBoundaries[node*2*fNDim];
1228 }
1229 
1230 
1231 ////////////////////////////////////////////////////////////////////////////////
1232 ///
1233 /// Example function to
1234 ///
1235 
1236 TKDTreeIF *TKDTreeTestBuild(const Int_t npoints, const Int_t bsize){
1237  Float_t *data0 = new Float_t[npoints*2];
1238  Float_t *data[2];
1239  data[0] = &data0[0];
1240  data[1] = &data0[npoints];
1241  for (Int_t i=0;i<npoints;i++) {
1242  data[1][i]= gRandom->Rndm();
1243  data[0][i]= gRandom->Rndm();
1244  }
1245  TKDTree<Int_t, Float_t> *kdtree = new TKDTreeIF(npoints, 2, bsize, data);
1246  return kdtree;
1247 }
1248 
1249 
1250 
1251 template class TKDTree<Int_t, Float_t>;
1252 template class TKDTree<Int_t, Double_t>;
virtual void Clear(Option_t *="")
Definition: TObject.h:110
double dist(Rotation3D const &r1, Rotation3D const &r2)
Definition: 3DDistances.cxx:48
void Spread(Index ntotal, Value *a, Index *index, Value &min, Value &max) const
Calculate spread of the array a.
Definition: TKDTree.cxx:971
Int_t fOffset
cross node - node that begins the last row (with terminal nodes only)
Definition: TKDTree.h:97
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:892
static Vc_ALWAYS_INLINE int_v min(const int_v &x, const int_v &y)
Definition: vector.h:433
void SetData(Index npoints, Index ndim, UInt_t bsize, Value **data)
Set the data array. See the constructor function comments for details.
Definition: TKDTree.cxx:926
Index FindNode(const Value *point) const
returns the index of the terminal node to which point belongs (index in the fAxis, fValue, etc arrays) returns -1 in case of failure
Definition: TKDTree.cxx:680
Int_t fDataOwner
Definition: TKDTree.h:79
Index * GetPointsIndexes(Int_t node) const
return the indices of the points in that terminal node for all the nodes except last, the size is fBucketSize for the last node it&#39;s fOffsetfBucketSize
Definition: TKDTree.cxx:820
TKDTree< Int_t, Float_t > TKDTreeIF
Definition: TKDTree.h:107
float Float_t
Definition: RtypesCore.h:53
virtual Double_t Rndm(Int_t i=0)
Machine independent random number generator.
Definition: TRandom.cxx:512
Bool_t IsTerminal(Index inode) const
Definition: TKDTree.h:58
Int_t fTotalNodes
Definition: TKDTree.h:81
void FindBNodeA(Value *point, Value *delta, Int_t &inode)
find the smallest node covering the full range - start
Definition: TKDTree.cxx:1181
Index fNPoints
Definition: TKDTree.h:84
void FindInRange(Value *point, Value range, std::vector< Index > &res)
Find all points in the sphere of a given radius "range" around the given point 1st argument - the poi...
Definition: TKDTree.cxx:757
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:170
int Int_t
Definition: RtypesCore.h:41
Index fBucketSize
Definition: TKDTree.h:85
bool Bool_t
Definition: RtypesCore.h:59
void MakeBoundariesExact()
Build boundaries for each node.
Definition: TKDTree.cxx:1122
TArc * a
Definition: textangle.C:12
const Bool_t kFALSE
Definition: Rtypes.h:92
Index GetNPointsNode(Int_t node) const
Get number of points in this node for all the terminal nodes except last, the size is fBucketSize for...
Definition: TKDTree.cxx:903
Double_t Distance(const Value *point, Index ind, Int_t type=2) const
Find the distance between point of the first argument and the point at index value ind Type argument ...
Definition: TKDTree.cxx:618
Value * fRange
Definition: TKDTree.h:89
Short_t Abs(Short_t d)
Definition: TMathBase.h:110
void Build()
Build the kd-tree.
Definition: TKDTree.cxx:414
Index fNDim
Definition: TKDTree.h:82
#define templateClassImp(name)
Definition: Rtypes.h:325
Int_t GetRight(Int_t inode) const
Definition: TKDTree.h:27
void FindPoint(Value *point, Index &index, Int_t &iter)
find the index of point works only if we keep fData pointers
Definition: TKDTree.cxx:711
Int_t bsize[]
Definition: SparseFit4.cxx:31
TKDTree()
Default constructor. Nothing is built.
Definition: TKDTree.cxx:273
TKDTreeIF * TKDTreeTestBuild(const Int_t npoints, const Int_t bsize)
Example function to.
Definition: TKDTree.cxx:1236
Index * fIndPoints
nodes boundaries
Definition: TKDTree.h:94
Class implementing a kd-tree.
Definition: TKDTree.h:11
point * points
Definition: X3DBuffer.c:20
UChar_t * fAxis
Definition: TKDTree.h:86
void UpdateNearestNeighbors(Index inode, const Value *point, Int_t kNN, Index *ind, Value *dist)
Update the nearest neighbors values by examining the node inode.
Definition: TKDTree.cxx:571
Int_t fRowT0
array of points indexes
Definition: TKDTree.h:95
~TKDTree()
Destructor By default, the original data is not owned by kd-tree and is not deleted with it...
Definition: TKDTree.cxx:376
Value KOrdStat(Index ntotal, Value *a, Index k, Index *index) const
copy of the TMath::KOrdStat because I need an Index work array
Definition: TKDTree.cxx:988
PyObject * fValue
Int_t GetLeft(Int_t inode) const
Definition: TKDTree.h:26
unsigned int UInt_t
Definition: RtypesCore.h:42
void GetNodePointsIndexes(Int_t node, Int_t &first1, Int_t &last1, Int_t &first2, Int_t &last2) const
Return the indices of points in that node Indices are returned as the first and last value of the par...
Definition: TKDTree.cxx:849
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
char * Form(const char *fmt,...)
void FindNearestNeighbors(const Value *point, Int_t k, Index *ind, Value *dist)
Find kNN nearest neighbors to the point in the first argument Returns 1 on success, 0 on failure Arrays ind and dist are provided by the user and are assumed to be at least kNN elements long.
Definition: TKDTree.cxx:551
TLine * l
Definition: textangle.C:4
void CookBoundaries(const Int_t node, Bool_t left)
define index of this terminal node
Definition: TKDTree.cxx:1077
R__EXTERN TRandom * gRandom
Definition: TRandom.h:62
void DistanceToNode(const Value *point, Index inode, Value &min, Value &max, Int_t type=2)
Find the minimal and maximal distance from a given point to a given node.
Definition: TKDTree.cxx:643
Value * fValue
Definition: TKDTree.h:87
void MakeBoundaries(Value *range=0x0)
Build boundaries for each node.
Definition: TKDTree.cxx:1042
RooCmdArg Index(RooCategory &icat)
Value * GetBoundariesExact()
Get the boundaries.
Definition: TKDTree.cxx:1204
double Double_t
Definition: RtypesCore.h:55
Int_t fCrossNode
smallest terminal row - first row that contains terminal nodes
Definition: TKDTree.h:96
int type
Definition: TGX11.cxx:120
Index fNDimm
Definition: TKDTree.h:83
Value ** fData
Definition: TKDTree.h:90
static Vc_ALWAYS_INLINE int_v max(const int_v &x, const int_v &y)
Definition: vector.h:440
Mother of all ROOT objects.
Definition: TObject.h:58
double f2(const double *x)
void UpdateRange(Index inode, Value *point, Value range, std::vector< Index > &res)
Internal recursive function with the implementation of range searches.
Definition: TKDTree.cxx:767
Int_t fNNodes
0 - not owner, 2 - owner of the pointer array, 1 - owner of the whole 2-d array
Definition: TKDTree.h:80
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:202
TF1 * f1
Definition: legend1.C:11
Value * GetBoundaries()
Get the boundaries.
Definition: TKDTree.cxx:1193
unsigned char UChar_t
Definition: RtypesCore.h:34
Double_t Sqrt(Double_t x)
Definition: TMath.h:464
const Bool_t kTRUE
Definition: Rtypes.h:91
Value * GetBoundaryExact(const Int_t node)
Get a boundary.
Definition: TKDTree.cxx:1224
Value * fBoundaries
data points
Definition: TKDTree.h:91
Value * GetBoundary(const Int_t node)
Get a boundary.
Definition: TKDTree.cxx:1214
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:904
const char * Value
Definition: TXMLSetup.cxx:73