7 templateClassImp(TKDTree)
8 templateClassImp(TKDNode)
10 //////////////////////////////////////////////////////////////////////
11 // Memory setup of protected data members:
13 // kDataOwner; // Toggle ownership of the data
15 // size of branch node array, and index of first terminal node
16 // fNDim; // number of variables
17 // fNpoints; // number of multidimensional points
18 // fBucketSize; // number of data points per terminal node
20 // fIndPoints : array containing rearanged indexes according to nodes:
21 // | point indexes from 1st terminal node (fBucketSize elements) | ... | point indexes from the last terminal node (<= fBucketSize elements)
24 // fRange : array containing the boundaries of the domain:
25 // | 1st dimension (min + max) | 2nd dimension (min + max) | ...
26 // fBoundaries : nodes boundaries
27 // | 1st node {1st dim * 2 elements | 2nd dim * 2 elements | ...} | 2nd node {...} | ...
28 // the nodes are arranged in the following order :
29 // - first fNnodes are primary nodes
30 // - after are the terminal nodes
31 // fNodes : array of primary nodes
32 ///////////////////////////////////////////////////////////////////////
33 //_________________________________________________________________
34 template <typename Index, typename Value>
35 TKDTree<Index, Value>::TKDTree() :
57 // Default constructor. Nothing is built
61 //_________________________________________________________________
62 template <typename Index, typename Value>
63 TKDTree<Index, Value>::TKDTree(Index npoints, Index ndim, UInt_t bsize, Value **data) :
73 ,fData(data) //Columnwise!!!!!
85 // Allocate data by hand. See TKDTree(TTree*, const Char_t*) for an automatic method.
90 //_________________________________________________________________
91 template <typename Index, typename Value>
92 TKDTree<Index, Value>::~TKDTree()
94 if (fIndBuffer) delete [] fIndBuffer;
95 if (fDistBuffer) delete [] fDistBuffer;
96 if (fkNNdist) delete [] fkNNdist;
97 if (fkNN) delete [] fkNN;
98 if (fNodes) delete [] fNodes;
99 if (fIndPoints) delete [] fIndPoints;
100 if (fRange) delete [] fRange;
101 if (fBoundaries) delete [] fBoundaries;
102 if (kDataOwner && fData){
103 for(int idim=0; idim<fNDim; idim++) delete [] fData[idim];
109 //_________________________________________________________________
110 template <typename Index, typename Value>
111 void TKDTree<Index, Value>::Build(){
115 // 1. calculate number of nodes
116 // 2. calculate first terminal row
117 // 3. initialize index array
118 // 4. non recursive building of the binary tree
121 fNnodes = fNpoints/fBucketSize-1;
122 if (fNpoints%fBucketSize) fNnodes++;
126 for (;(fNnodes+1)>(1<<fRowT0);fRowT0++);
137 // allocate space for boundaries
138 fRange = new Value[2*fNDim];
139 fIndPoints= new Index[fNpoints];
140 for (Index i=0; i<fNpoints; i++) fIndPoints[i] = i;
141 fNodes = new TKDNode<Index, Value>[fNnodes];
143 fCrossNode = (1<<(fRowT0+1))-1;
144 if (fCrossNode<fNnodes) fCrossNode = 2*fCrossNode+1;
146 // fOffset = (((fNnodes+1)-(1<<fRowT0)))*2;
147 Int_t over = (fNnodes+1)-(1<<fRowT0);
148 Int_t filled = ((1<<fRowT0)-over)*fBucketSize;
149 fOffset = fNpoints-filled;
151 // printf("Row0 %d\n", fRowT0);
152 // printf("CrossNode %d\n", fCrossNode);
153 // printf("Offset %d\n", fOffset);
157 // stack for non recursive build - size 128 bytes enough
159 Int_t nodeStack[128];
160 Int_t npointStack[128];
162 Int_t currentIndex = 0;
166 npointStack[0] = fNpoints;
169 Int_t nbucketsall =0;
170 while (currentIndex>=0){
173 Int_t npoints = npointStack[currentIndex];
174 if (npoints<=fBucketSize) {
175 //printf("terminal node : index %d iter %d\n", currentIndex, iter);
178 continue; // terminal node
180 Int_t crow = rowStack[currentIndex];
181 Int_t cpos = posStack[currentIndex];
182 Int_t cnode = nodeStack[currentIndex];
183 TKDNode<Index, Value> * node = &(fNodes[cnode]);
184 //printf("currentIndex %d npoints %d node %d\n", currentIndex, npoints, cnode);
187 Int_t nbuckets0 = npoints/fBucketSize; //current number of buckets
188 if (npoints%fBucketSize) nbuckets0++; //
189 Int_t restRows = fRowT0-rowStack[currentIndex]; // rest of fully occupied node row
190 if (restRows<0) restRows =0;
191 for (;nbuckets0>(2<<restRows); restRows++);
192 Int_t nfull = 1<<restRows;
193 Int_t nrest = nbuckets0-nfull;
194 Int_t nleft =0, nright =0;
196 if (nrest>(nfull/2)){
197 nleft = nfull*fBucketSize;
198 nright = npoints-nleft;
200 nright = nfull*fBucketSize/2;
201 nleft = npoints-nright;
205 //find the axis with biggest spread
207 Value tempspread, min, max;
210 for (Int_t idim=0; idim<fNDim; idim++){
212 Spread(npoints, array, fIndPoints+cpos, min, max);
213 tempspread = max - min;
214 if (maxspread < tempspread) {
215 maxspread=tempspread;
218 if(cnode==0) {fRange[2*idim] = min; fRange[2*idim+1] = max;}
220 array = fData[axspread];
221 KOrdStat(npoints, array, nleft, fIndPoints+cpos);
222 node->fAxis = axspread;
223 node->fValue = array[fIndPoints[cpos+nleft]];
224 //printf("Set node %d : ax %d val %f\n", cnode, node->fAxis, node->fValue);
227 npointStack[currentIndex] = nleft;
228 rowStack[currentIndex] = crow+1;
229 posStack[currentIndex] = cpos;
230 nodeStack[currentIndex] = cnode*2+1;
232 npointStack[currentIndex] = nright;
233 rowStack[currentIndex] = crow+1;
234 posStack[currentIndex] = cpos+nleft;
235 nodeStack[currentIndex] = (cnode*2)+2;
239 Info("Build()", Form("points %d left %d right %d", npoints, nleft, nright));
240 if (nleft<nright) Warning("Build", "Problem Left-Right");
241 if (nleft<0 || nright<0) Warning("Build()", "Problem Negative number");
245 //printf("NBuckets\t%d\n", nbucketsall);
250 //_________________________________________________________________
251 template <typename Index, typename Value>
252 Int_t TKDTree<Index, Value>::FindNearestNeighbors(const Value *point, const Int_t k, Index *&in, Value *&d)
254 // Find "k" nearest neighbors to "point".
256 // Return true in case of success and false in case of failure.
257 // The indexes of the nearest k points are stored in the array "in" in
258 // increasing order of the distance to "point" and the maxim distance
261 // The array "in" is managed internally by the TKDTree.
263 Index inode = FindNode(point);
265 Error("FindNearestNeighbors()", "Point outside data range.");
270 Int_t nCalculations = 0;
272 // allocate working memory
274 fDistBuffer = new Value[fBucketSize];
275 fIndBuffer = new Index[fBucketSize];
279 if(fkNN) printf("Reallocate memory %d -> %d \n", fkNNdim, 2*k);
280 else printf("Allocate %d memory\n", 2*k);
287 fkNN = new Index[fkNNdim];
288 fkNNdist = new Value[fkNNdim];
290 memset(fkNN, -1, k*sizeof(Index));
291 for(int i=0; i<k; i++) fkNNdist[i] = 9999.;
292 Index itmp, jtmp; Value ftmp, gtmp;
294 // calculate number of boundaries with the data domain.
296 if(!fBoundaries) MakeBoundaries();
297 Value *bounds = &fBoundaries[inode*2*fNDim];
298 for(int idim=0; idim<fNDim; idim++){
299 if(bounds[2*idim] == fRange[2*idim]) nBounds++;
300 if(bounds[2*idim+1] == fRange[2*idim+1]) nBounds++;
302 if(debug>=1) printf("Calculate boundaries [nBounds = %d]\n", nBounds);
305 TKDNode<Index, Value> *node;
306 Int_t nodeStack[128], nodeIn[128];
307 Index currentIndex = 0;
308 nodeStack[0] = inode;
310 while(currentIndex>=0){
311 Int_t tnode = nodeStack[currentIndex];
312 Int_t entry = nodeIn[currentIndex];
314 if(debug>=1) printf("Analyse tnode %d entry %d\n", tnode, entry);
316 // check if node is still eligible
317 node = &fNodes[tnode/2 + (tnode%2) - 1];
318 if((TMath::Abs(point[node->fAxis] - node->fValue) > fkNNdist[k-1])
320 ((point[node->fAxis] > node->fValue && tnode%2) ||
321 (point[node->fAxis] < node->fValue && !tnode%2))) {
322 //printf("\tREMOVE NODE %d\n", tnode/2 + (tnode%2) - 1);
326 // end all recursions
327 if(nBounds==2 * fNDim) break;
331 if(IsTerminal(tnode)){
332 if(debug>=2) printf("\tProcess terminal node %d\n", tnode);
333 // Link data to terminal node
334 Int_t offset = (tnode >= fCrossNode) ? (tnode-fCrossNode)*fBucketSize : fOffset+(tnode-fNnodes)*fBucketSize;
335 Index *indexPoints = &fIndPoints[offset];
336 Int_t nbs = (tnode == 2*fNnodes) ? fNpoints%fBucketSize : fBucketSize;
337 nbs = nbs ? nbs : fBucketSize;
338 nCalculations += nbs;
341 for(int idx=0; idx<nbs; idx++){
342 // calculate distance in the L1 metric
343 fDistBuffer[npoints] = 0.;
344 for(int idim=0; idim<fNDim; idim++) fDistBuffer[npoints] += TMath::Abs(point[idim] - fData[idim][indexPoints[idx]]);
345 // register candidate neighbor
346 if(fDistBuffer[npoints] < fkNNdist[k-1]){
347 fIndBuffer[npoints] = indexPoints[idx];
351 for(int ibrowse=0; ibrowse<npoints; ibrowse++){
352 if(fDistBuffer[ibrowse] >= fkNNdist[k-1]) continue;
355 while(fDistBuffer[ibrowse] >= fkNNdist[iNN]) iNN++;
356 if(debug>=2) printf("\t\tinsert data %d @ %d distance %f\n", fIndBuffer[ibrowse], iNN, fDistBuffer[ibrowse]);
358 itmp = fkNN[iNN]; ftmp = fkNNdist[iNN];
359 fkNN[iNN] = fIndBuffer[ibrowse];
360 fkNNdist[iNN] = fDistBuffer[ibrowse];
361 for(int ireplace=iNN+1; ireplace<k; ireplace++){
362 jtmp = fkNN[ireplace]; gtmp = fkNNdist[ireplace];
363 fkNN[ireplace] = itmp; fkNNdist[ireplace] = ftmp;
364 itmp = jtmp; ftmp = gtmp;
365 if(ftmp == 9999.) break;
368 for(int i=0; i<k; i++){
369 if(fkNNdist[i] == 9999.) break;
370 printf("\t\tfkNNdist[%d] = %f\n", i, fkNNdist[i]);
377 Int_t parent_node = tnode/2 + (tnode%2) - 1;
378 if(parent_node >= 0 && entry != parent_node){
379 // check if parent node is eligible at all
380 node = &fNodes[parent_node];
381 if(TMath::Abs(point[node->fAxis] - node->fValue) > fkNNdist[k-1]){
384 // end all recursions
385 if(nBounds==2 * fNDim) break;
388 nodeStack[currentIndex]=tnode/2 + (tnode%2) - 1;
389 nodeIn[currentIndex]=tnode;
390 if(debug>=2) printf("\tregister %d\n", nodeStack[currentIndex]);
393 // register children nodes
395 Bool_t kAllow[] = {kTRUE, kTRUE};
396 node = &fNodes[tnode];
397 if(TMath::Abs(point[node->fAxis] - node->fValue) > fkNNdist[k-1]){
398 if(point[node->fAxis] > node->fValue) kAllow[0] = kFALSE;
399 else kAllow[1] = kFALSE;
401 for(int ic=1; ic<=2; ic++){
402 if(!kAllow[ic-1]) continue;
403 child_node = (tnode*2)+ic;
404 if(child_node < fNnodes + GetNTerminalNodes() && entry != child_node){
406 nodeStack[currentIndex] = child_node;
407 nodeIn[currentIndex]=tnode;
408 if(debug>=2) printf("\tregister %d\n", nodeStack[currentIndex]);
416 return nCalculations; //kTRUE;
421 //_________________________________________________________________
422 template <typename Index, typename Value>
423 Index TKDTree<Index, Value>::FindNode(const Value * point){
425 // find the terminal node to which point belongs
427 Index stackNode[128], inode;
428 Int_t currentIndex =0;
431 while (currentIndex>=0){
432 inode = stackNode[currentIndex];
434 if (IsTerminal(inode)) return inode;
436 TKDNode<Index, Value> & node = fNodes[inode];
437 if (point[node.fAxis]<=node.fValue){
439 stackNode[currentIndex]=(inode*2)+1;
441 if (point[node.fAxis]>=node.fValue){
443 stackNode[currentIndex]=(inode*2)+2;
452 //_________________________________________________________________
453 template <typename Index, typename Value>
454 void TKDTree<Index, Value>::FindPoint(Value * point, Index &index, Int_t &iter){
456 // find the index of point
457 // works only if we keep fData pointers
459 Int_t stackNode[128];
460 Int_t currentIndex =0;
464 while (currentIndex>=0){
466 Int_t inode = stackNode[currentIndex];
468 if (IsTerminal(inode)){
469 // investigate terminal node
470 Int_t indexIP = (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNnodes)*fBucketSize+fOffset;
471 printf("terminal %d indexP %d\n", inode, indexIP);
472 for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
475 printf("ibucket %d index %d\n", ibucket, indexIP);
476 if (indexIP>=fNpoints) continue;
477 Int_t index0 = fIndPoints[indexIP];
478 for (Int_t idim=0;idim<fNDim;idim++) if (fData[idim][index0]!=point[idim]) isOK = kFALSE;
479 if (isOK) index = index0;
484 TKDNode<Index, Value> & node = fNodes[inode];
485 if (point[node.fAxis]<=node.fValue){
487 stackNode[currentIndex]=(inode*2)+1;
489 if (point[node.fAxis]>=node.fValue){
491 stackNode[currentIndex]=(inode*2)+2;
495 // printf("Iter\t%d\n",iter);
498 //_________________________________________________________________
499 template <typename Index, typename Value>
500 void TKDTree<Index, Value>::FindInRangeA(Value * point, Value * delta, Index *res , Index &npoints, Index & iter, Int_t bnode)
503 // Find all points in the range specified by (point +- range)
504 // res - Resulting indexes are stored in res array
505 // npoints - Number of selected indexes in range
507 // For some cases it is better to don't keep data - because of memory consumption
508 // If the data are not kept - only boundary conditions are investigated
509 // some of the data can be outside of the range
510 // What is guranteed in this mode: All of the points in the range are selected + some fraction of others (but close)
512 Index stackNode[128];
514 Index currentIndex = 0;
515 stackNode[currentIndex] = bnode;
516 while (currentIndex>=0){
518 Int_t inode = stackNode[currentIndex];
521 if (!IsTerminal(inode)){
523 TKDNode<Index, Value> * node = &(fNodes[inode]);
524 if (point[node->fAxis] - delta[node->fAxis] < node->fValue) {
526 stackNode[currentIndex]= (inode*2)+1;
528 if (point[node->fAxis] + delta[node->fAxis] >= node->fValue){
530 stackNode[currentIndex]= (inode*2)+2;
534 (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNnodes)*fBucketSize+fOffset;
535 for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
536 if (indexIP+ibucket>=fNpoints) break;
537 res[npoints] = fIndPoints[indexIP+ibucket];
544 // compress rest if data still accesible
546 Index npoints2 = npoints;
548 for (Index i=0; i<npoints2;i++){
550 for (Index idim = 0; idim< fNDim; idim++){
551 if (TMath::Abs(fData[idim][res[i]]- point[idim])>delta[idim])
555 res[npoints] = res[i];
563 //_________________________________________________________________
564 template <typename Index, typename Value>
565 void TKDTree<Index, Value>::FindInRangeB(Value * point, Value * delta, Index *res , Index &npoints,Index & iter, Int_t bnode)
568 Long64_t goldStatus = (1<<(2*fNDim))-1; // gold status
569 Index stackNode[128];
570 Long64_t stackStatus[128];
572 Index currentIndex = 0;
573 stackNode[currentIndex] = bnode;
574 stackStatus[currentIndex] = 0;
575 while (currentIndex>=0){
576 Int_t inode = stackNode[currentIndex];
577 Long64_t status = stackStatus[currentIndex];
580 if (IsTerminal(inode)){
582 (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNnodes)*fBucketSize+fOffset;
583 for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
584 if (indexIP+ibucket>=fNpoints) break;
585 res[npoints] = fIndPoints[indexIP+ibucket];
591 if (status == goldStatus){
593 Int_t iright = inode;
594 for (;ileft<fNnodes; ileft = (ileft<<1)+1);
595 for (;iright<fNnodes; iright = (iright<<1)+2);
597 (ileft >= fCrossNode) ? (ileft-fCrossNode)*fBucketSize : (ileft-fNnodes)*fBucketSize+fOffset;
599 (iright >= fCrossNode) ? (iright-fCrossNode)*fBucketSize : (iright-fNnodes)*fBucketSize+fOffset;
601 Int_t endpoint = indexR+fBucketSize;
602 if (endpoint>fNpoints) endpoint=fNpoints;
603 for (Int_t ipoint=indexL;ipoint<endpoint;ipoint++){
604 res[npoints] = fIndPoints[ipoint];
611 TKDNode<Index, Value> * node = &(fNodes[inode]);
612 if (point[node->fAxis] - delta[node->fAxis] < node->fValue) {
614 stackNode[currentIndex]= (inode<<1)+1;
615 if (point[node->fAxis] + delta[node->fAxis] > node->fValue)
616 stackStatus[currentIndex]= status | (1<<(2*node->fAxis));
618 if (point[node->fAxis] + delta[node->fAxis] >= node->fValue){
620 stackNode[currentIndex]= (inode<<1)+2;
621 if (point[node->fAxis] - delta[node->fAxis]<node->fValue)
622 stackStatus[currentIndex]= status | (1<<(2*node->fAxis+1));
627 Index npoints2 = npoints;
629 for (Index i=0; i<npoints2;i++){
631 for (Index idim = 0; idim< fNDim; idim++){
632 if (TMath::Abs(fData[idim][res[i]]- point[idim])>delta[idim])
636 res[npoints] = res[i];
645 //_________________________________________________________________
646 template <typename Index, typename Value>
647 void TKDTree<Index, Value>::SetData(Index npoints, Index ndim, UInt_t bsize, Value **data)
651 // Check reconstruction/reallocation of memory of data. Maybe it is not
652 // necessary to delete and realocate space but only to use the same space
667 //_________________________________________________________________
668 template <typename Index, typename Value>
669 void TKDTree<Index, Value>::Spread(Index ntotal, Value *a, Index *index, Value &min, Value &max)
675 for (i=0; i<ntotal; i++){
676 if (a[index[i]]<min) min = a[index[i]];
677 if (a[index[i]]>max) max = a[index[i]];
682 //_________________________________________________________________
683 template <typename Index, typename Value>
684 Value TKDTree<Index, Value>::KOrdStat(Index ntotal, Value *a, Index k, Index *index)
687 //copy of the TMath::KOrdStat because I need an Index work array
689 Index i, ir, j, l, mid;
697 if (ir<=l+1) { //active partition contains 1 or 2 elements
698 if (ir == l+1 && a[index[ir]]<a[index[l]])
699 {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
700 Value tmp = a[index[rk]];
703 mid = (l+ir) >> 1; //choose median of left, center and right
704 {temp = index[mid]; index[mid]=index[l+1]; index[l+1]=temp;}//elements as partitioning element arr.
705 if (a[index[l]]>a[index[ir]]) //also rearrange so that a[l]<=a[l+1]
706 {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
708 if (a[index[l+1]]>a[index[ir]])
709 {temp=index[l+1]; index[l+1]=index[ir]; index[ir]=temp;}
711 if (a[index[l]]>a[index[l+1]])
712 {temp = index[l]; index[l]=index[l+1]; index[l+1]=temp;}
714 i=l+1; //initialize pointers for partitioning
718 do i++; while (a[index[i]]<a[arr]);
719 do j--; while (a[index[j]]>a[arr]);
720 if (j<i) break; //pointers crossed, partitioning complete
721 {temp=index[i]; index[i]=index[j]; index[j]=temp;}
725 if (j>=rk) ir = j-1; //keep active the partition that
726 if (j<=rk) l=i; //contains the k_th element
731 //_________________________________________________________________
732 template <typename Index, typename Value>
733 void TKDTree<Index, Value>::MakeBoundaries(Value *range)
735 // Build boundaries for each node.
738 if(range) memcpy(fRange, range, 2*fNDim*sizeof(Value));
739 // total number of nodes including terminal nodes
740 Int_t totNodes = fNnodes + GetNTerminalNodes();
741 fBoundaries = new Value[totNodes*2*fNDim];
742 Info("MakeBoundaries(Value*)", Form("Allocate boundaries for %d nodes", totNodes));
746 for(int inode=fNnodes-1; inode>=0; inode--){
747 memcpy(&fBoundaries[inode*2*fNDim], fRange, 2*fNDim*sizeof(Value));
749 // check left child node
750 child_index = 2*inode+1;
751 if(IsTerminal(child_index)) CookBoundaries(inode, kTRUE);
752 for(int idim=0; idim<fNDim; idim++) fBoundaries[2*fNDim*inode+2*idim] = fBoundaries[2*fNDim*child_index+2*idim];
754 // check right child node
755 child_index = 2*inode+2;
756 if(IsTerminal(child_index)) CookBoundaries(inode, kFALSE);
757 for(int idim=0; idim<fNDim; idim++) fBoundaries[2*fNDim*inode+2*idim+1] = fBoundaries[2*fNDim*child_index+2*idim+1];
761 //_________________________________________________________________
762 template <typename Index, typename Value>
763 void TKDTree<Index, Value>::CookBoundaries(Int_t parent_node, Bool_t LEFT)
765 // define index of this terminal node
766 Int_t index = 2 * parent_node + (LEFT ? 1 : 2);
768 // build and initialize boundaries for this node
769 //printf("\tAllocate terminal node %d\n", index);
770 memcpy(&fBoundaries[2*fNDim*index], fRange, 2*fNDim*sizeof(Value));
771 Bool_t flag[256]; // cope with up to 128 dimensions
772 memset(flag, kFALSE, 2*fNDim);
775 // recurse parent nodes
776 TKDNode<Index, Value> *node = 0x0;
777 while(parent_node >= 0 && nvals < 2 * fNDim){
778 node = &(fNodes[parent_node]);
780 if(!flag[2*node->fAxis+1]) {
781 fBoundaries[2*fNDim*index+2*node->fAxis+1] = node->fValue;
782 flag[2*node->fAxis+1] = kTRUE;
786 if(!flag[2*node->fAxis]) {
787 fBoundaries[2*fNDim*index+2*node->fAxis] = node->fValue;
788 flag[2*node->fAxis] = kTRUE;
792 LEFT = parent_node%2;
793 parent_node = parent_node/2 + (parent_node%2) - 1;
797 template class TKDTree<Int_t, Float_t>;
798 template class TKDTree<Int_t, Double_t>;