19 templateClassImp(TKDTree);
269 template <
typename Index,
typename Value>
270 TKDTree<Index, Value>::TKDTree() :
291 template <
typename Index,
typename Value>
292 TKDTree<Index, Value>::TKDTree(Index npoints, Index ndim, UInt_t bsize) :
343 template <
typename Index,
typename Value>
344 TKDTree<Index, Value>::TKDTree(Index npoints, Index ndim, UInt_t bsize, Value **data) :
372 template <
typename Index,
typename Value>
373 TKDTree<Index, Value>::~TKDTree()
375 if (fAxis)
delete [] fAxis;
376 if (fValue)
delete [] fValue;
377 if (fIndPoints)
delete [] fIndPoints;
378 if (fRange)
delete [] fRange;
379 if (fBoundaries)
delete [] fBoundaries;
383 for(
int idim=0; idim<fNDim; idim++)
delete [] fData[idim];
410 template <
typename Index,
typename Value>
411 void TKDTree<Index, Value>::Build()
414 fNNodes = fNPoints/fBucketSize-1;
415 if (fNPoints%fBucketSize) fNNodes++;
416 fTotalNodes = fNNodes + fNPoints/fBucketSize + ((fNPoints%fBucketSize)?1:0);
419 for ( ;(fNNodes+1)>(1<<fRowT0);fRowT0++) {}
431 fRange =
new Value[2*fNDim];
432 fIndPoints=
new Index[fNPoints];
433 for (Index i=0; i<fNPoints; i++) fIndPoints[i] = i;
434 fAxis =
new UChar_t[fNNodes];
435 fValue =
new Value[fNNodes];
437 fCrossNode = (1<<(fRowT0+1))-1;
438 if (fCrossNode<fNNodes) fCrossNode = 2*fCrossNode+1;
441 Int_t over = (fNNodes+1)-(1<<fRowT0);
442 Int_t filled = ((1<<fRowT0)-over)*fBucketSize;
443 fOffset = fNPoints-filled;
454 Int_t nodeStack[128];
455 Int_t npointStack[128];
457 Int_t currentIndex = 0;
461 npointStack[0] = fNPoints;
464 Int_t nbucketsall =0;
465 while (currentIndex>=0){
468 Int_t npoints = npointStack[currentIndex];
469 if (npoints<=fBucketSize) {
475 Int_t crow = rowStack[currentIndex];
476 Int_t cpos = posStack[currentIndex];
477 Int_t cnode = nodeStack[currentIndex];
481 Int_t nbuckets0 = npoints/fBucketSize;
482 if (npoints%fBucketSize) nbuckets0++;
483 Int_t restRows = fRowT0-rowStack[currentIndex];
484 if (restRows<0) restRows =0;
485 for (;nbuckets0>(2<<restRows); restRows++) {}
486 Int_t nfull = 1<<restRows;
487 Int_t nrest = nbuckets0-nfull;
488 Int_t nleft =0, nright =0;
490 if (nrest>(nfull/2)){
491 nleft = nfull*fBucketSize;
492 nright = npoints-nleft;
494 nright = nfull*fBucketSize/2;
495 nleft = npoints-nright;
501 Value tempspread, min, max;
504 for (Int_t idim=0; idim<fNDim; idim++){
506 Spread(npoints, array, fIndPoints+cpos, min, max);
507 tempspread = max - min;
508 if (maxspread < tempspread) {
509 maxspread=tempspread;
514 fRange[2*idim] = min; fRange[2*idim+1] = max;
516 array = fData[axspread];
517 KOrdStat(npoints, array, nleft, fIndPoints+cpos);
518 fAxis[cnode] = axspread;
519 fValue[cnode] = array[fIndPoints[cpos+nleft]];
523 npointStack[currentIndex] = nleft;
524 rowStack[currentIndex] = crow+1;
525 posStack[currentIndex] = cpos;
526 nodeStack[currentIndex] = cnode*2+1;
528 npointStack[currentIndex] = nright;
529 rowStack[currentIndex] = crow+1;
530 posStack[currentIndex] = cpos+nleft;
531 nodeStack[currentIndex] = (cnode*2)+2;
535 Info(
"Build()",
"%s", Form(
"points %d left %d right %d", npoints, nleft, nright));
536 if (nleft<nright) Warning(
"Build",
"Problem Left-Right");
537 if (nleft<0 || nright<0) Warning(
"Build()",
"Problem Negative number");
547 template <
typename Index,
typename Value>
548 void TKDTree<Index, Value>::FindNearestNeighbors(
const Value *point,
const Int_t kNN, Index *ind, Value *dist)
552 Error(
"FindNearestNeighbors",
"Working arrays must be allocated by the user!");
555 for (Int_t i=0; i<kNN; i++){
556 dist[i]=std::numeric_limits<Value>::max();
559 MakeBoundariesExact();
560 UpdateNearestNeighbors(0, point, kNN, ind, dist);
567 template <
typename Index,
typename Value>
568 void TKDTree<Index, Value>::UpdateNearestNeighbors(Index inode,
const Value *point, Int_t kNN, Index *ind, Value *dist)
572 DistanceToNode(point, inode, min, max);
573 if (min > dist[kNN-1]){
577 if (IsTerminal(inode)) {
579 Index f1, l1, f2, l2;
580 GetNodePointsIndexes(inode, f1, l1, f2, l2);
581 for (Int_t ipoint=f1; ipoint<=l1; ipoint++){
582 Double_t d = Distance(point, fIndPoints[ipoint]);
586 while(ishift<kNN && d>dist[ishift])
590 for (Int_t i=kNN-1; i>ishift; i--){
595 ind[ishift]=fIndPoints[ipoint];
600 if (point[fAxis[inode]]<fValue[inode]){
602 UpdateNearestNeighbors(GetLeft(inode), point, kNN, ind, dist);
603 UpdateNearestNeighbors(GetRight(inode), point, kNN, ind, dist);
605 UpdateNearestNeighbors(GetRight(inode), point, kNN, ind, dist);
606 UpdateNearestNeighbors(GetLeft(inode), point, kNN, ind, dist);
614 template <
typename Index,
typename Value>
615 Double_t TKDTree<Index, Value>::Distance(
const Value *point, Index ind, Int_t type)
const
619 for (Int_t idim=0; idim<fNDim; idim++){
620 dist+=(point[idim]-fData[idim][ind])*(point[idim]-fData[idim][ind]);
622 return TMath::Sqrt(dist);
624 for (Int_t idim=0; idim<fNDim; idim++){
625 dist+=TMath::Abs(point[idim]-fData[idim][ind]);
639 template <
typename Index,
typename Value>
640 void TKDTree<Index, Value>::DistanceToNode(
const Value *point, Index inode, Value &min, Value &max, Int_t type)
642 Value *bound = GetBoundaryExact(inode);
645 Double_t dist1, dist2;
648 for (Int_t idim=0; idim<fNDimm; idim+=2){
649 dist1 = (point[idim/2]-bound[idim])*(point[idim/2]-bound[idim]);
650 dist2 = (point[idim/2]-bound[idim+1])*(point[idim/2]-bound[idim+1]);
652 if (point[idim/2]<bound[idim] || point[idim/2]>bound[idim+1])
653 min+= (dist1>dist2)? dist2 : dist1;
655 max+= (dist1>dist2)? dist1 : dist2;
657 min = TMath::Sqrt(min);
658 max = TMath::Sqrt(max);
660 for (Int_t idim=0; idim<fNDimm; idim+=2){
661 dist1 = TMath::Abs(point[idim/2]-bound[idim]);
662 dist2 = TMath::Abs(point[idim/2]-bound[idim+1]);
664 min+= (dist1>dist2)? dist2 : dist1;
666 max+= (dist1>dist2)? dist1 : dist2;
676 template <
typename Index,
typename Value>
677 Index TKDTree<Index, Value>::FindNode(
const Value * point)
const
679 Index stackNode[128], inode;
680 Int_t currentIndex =0;
682 while (currentIndex>=0){
683 inode = stackNode[currentIndex];
684 if (IsTerminal(inode))
return inode;
687 if (point[fAxis[inode]]<=fValue[inode]){
689 stackNode[currentIndex]=(inode<<1)+1;
691 if (point[fAxis[inode]]>=fValue[inode]){
693 stackNode[currentIndex]=(inode+1)<<1;
707 template <
typename Index,
typename Value>
708 void TKDTree<Index, Value>::FindPoint(Value * point, Index &index, Int_t &iter){
709 Int_t stackNode[128];
710 Int_t currentIndex =0;
714 while (currentIndex>=0){
716 Int_t inode = stackNode[currentIndex];
718 if (IsTerminal(inode)){
720 Int_t indexIP = (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNNodes)*fBucketSize+fOffset;
721 printf(
"terminal %d indexP %d\n", inode, indexIP);
722 for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
725 printf(
"ibucket %d index %d\n", ibucket, indexIP);
726 if (indexIP>=fNPoints)
continue;
727 Int_t index0 = fIndPoints[indexIP];
728 for (Int_t idim=0;idim<fNDim;idim++)
if (fData[idim][index0]!=point[idim]) isOK = kFALSE;
729 if (isOK) index = index0;
734 if (point[fAxis[inode]]<=fValue[inode]){
736 stackNode[currentIndex]=(inode*2)+1;
738 if (point[fAxis[inode]]>=fValue[inode]){
740 stackNode[currentIndex]=(inode*2)+2;
753 template <
typename Index,
typename Value>
754 void TKDTree<Index, Value>::FindInRange(Value * point, Value range, std::vector<Index> &res)
756 MakeBoundariesExact();
757 UpdateRange(0, point, range, res);
763 template <
typename Index,
typename Value>
764 void TKDTree<Index, Value>::UpdateRange(Index inode, Value* point, Value range, std::vector<Index> &res)
767 DistanceToNode(point, inode, min, max);
772 if (max<range && max>0) {
775 Index f1, l1, f2, l2;
776 GetNodePointsIndexes(inode, f1, l1, f2, l2);
778 for (Int_t ipoint=f1; ipoint<=l1; ipoint++){
779 res.push_back(fIndPoints[ipoint]);
781 for (Int_t ipoint=f2; ipoint<=l2; ipoint++){
782 res.push_back(fIndPoints[ipoint]);
788 if (IsTerminal(inode)){
790 Index f1, l1, f2, l2;
792 GetNodePointsIndexes(inode, f1, l1, f2, l2);
793 for (Int_t ipoint=f1; ipoint<=l1; ipoint++){
794 d = Distance(point, fIndPoints[ipoint]);
796 res.push_back(fIndPoints[ipoint]);
801 if (point[fAxis[inode]]<=fValue[inode]){
803 UpdateRange(GetLeft(inode),point, range, res);
804 UpdateRange(GetRight(inode),point, range, res);
806 UpdateRange(GetLeft(inode),point, range, res);
807 UpdateRange(GetRight(inode),point, range, res);
816 template <
typename Index,
typename Value>
817 Index* TKDTree<Index, Value>::GetPointsIndexes(Int_t node)
const
819 if (!IsTerminal(node)){
820 printf(
"GetPointsIndexes() only for terminal nodes, use GetNodePointsIndexes() instead\n");
823 Int_t offset = (node >= fCrossNode) ? (node-fCrossNode)*fBucketSize : fOffset+(node-fNNodes)*fBucketSize;
824 return &fIndPoints[offset];
845 template <
typename Index,
typename Value>
846 void TKDTree<Index, Value>::GetNodePointsIndexes(Int_t node, Int_t &first1, Int_t &last1, Int_t &first2, Int_t &last2)
const
849 if (IsTerminal(node)){
851 Index offset = (node >= fCrossNode) ? (node-fCrossNode)*fBucketSize : fOffset+(node-fNNodes)*fBucketSize;
853 last1 = offset + GetNPointsNode(node)-1;
859 Index firsttermnode = fNNodes;
862 Index f1, l1, f2, l2;
864 while (ileft<firsttermnode)
865 ileft = GetLeft(ileft);
867 while (iright<firsttermnode)
868 iright = GetRight(iright);
875 GetNodePointsIndexes(firsttermnode, f1, l1, f2, l2);
877 GetNodePointsIndexes(iright, f1, l1, f2, l2);
879 GetNodePointsIndexes(ileft, f1, l1, f2, l2);
881 GetNodePointsIndexes(fTotalNodes-1, f1, l1, f2, l2);
885 GetNodePointsIndexes(ileft, f1, l1, f2, l2);
887 GetNodePointsIndexes(iright, f1, l1, f2, l2);
899 template <
typename Index,
typename Value>
900 Index TKDTree<Index, Value>::GetNPointsNode(Int_t inode)
const
902 if (IsTerminal(inode)){
904 if (inode!=fTotalNodes-1)
return fBucketSize;
906 if (fOffset%fBucketSize==0)
return fBucketSize;
907 else return fOffset%fBucketSize;
911 Int_t f1, l1, f2, l2;
912 GetNodePointsIndexes(inode, f1, l1, f2, l2);
922 template <
typename Index,
typename Value>
923 void TKDTree<Index, Value>::SetData(Index npoints, Index ndim, UInt_t bsize, Value **data)
947 template <
typename Index,
typename Value>
948 Int_t TKDTree<Index, Value>::SetData(Index idim, Value *data)
950 if (fAxis || fValue) {
951 Error(
"SetData",
"The tree has already been built, no updates possible");
956 fData =
new Value*[fNDim];
967 template <
typename Index,
typename Value>
968 void TKDTree<Index, Value>::Spread(Index ntotal, Value *a, Index *index, Value &min, Value &max)
const
973 for (i=0; i<ntotal; i++){
974 if (a[index[i]]<min) min = a[index[i]];
975 if (a[index[i]]>max) max = a[index[i]];
984 template <
typename Index,
typename Value>
985 Value TKDTree<Index, Value>::KOrdStat(Index ntotal, Value *a, Index k, Index *index)
const
987 Index i, ir, j, l, mid;
996 if (ir == l+1 && a[index[ir]]<a[index[l]])
997 {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
998 Value tmp = a[index[rk]];
1002 {temp = index[mid]; index[mid]=index[l+1]; index[l+1]=temp;}
1003 if (a[index[l]]>a[index[ir]])
1004 {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
1006 if (a[index[l+1]]>a[index[ir]])
1007 {temp=index[l+1]; index[l+1]=index[ir]; index[ir]=temp;}
1009 if (a[index[l]]>a[index[l+1]])
1010 {temp = index[l]; index[l]=index[l+1]; index[l+1]=temp;}
1016 do i++;
while (a[index[i]]<a[arr]);
1017 do j--;
while (a[index[j]]>a[arr]);
1019 {temp=index[i]; index[i]=index[j]; index[j]=temp;}
1021 index[l+1]=index[j];
1023 if (j>=rk) ir = j-1;
1038 template <
typename Index,
typename Value>
1039 void TKDTree<Index, Value>::MakeBoundaries(Value *range)
1042 if(range) memcpy(fRange, range, fNDimm*
sizeof(Value));
1044 Int_t totNodes = fNNodes + fNPoints/fBucketSize + ((fNPoints%fBucketSize)?1:0);
1045 fBoundaries =
new Value[totNodes*fNDimm];
1050 Value *tbounds = 0x0, *cbounds = 0x0;
1052 for(
int inode=fNNodes-1; inode>=0; inode--){
1053 tbounds = &fBoundaries[inode*fNDimm];
1054 memcpy(tbounds, fRange, fNDimm*
sizeof(Value));
1058 if(IsTerminal(cn)) CookBoundaries(inode, kTRUE);
1059 cbounds = &fBoundaries[fNDimm*cn];
1060 for(
int idim=0; idim<fNDim; idim++) tbounds[idim<<1] = cbounds[idim<<1];
1064 if(IsTerminal(cn)) CookBoundaries(inode, kFALSE);
1065 cbounds = &fBoundaries[fNDimm*cn];
1066 for(
int idim=0; idim<fNDim; idim++) tbounds[(idim<<1)+1] = cbounds[(idim<<1)+1];
1073 template <
typename Index,
typename Value>
1074 void TKDTree<Index, Value>::CookBoundaries(
const Int_t node, Bool_t LEFT)
1076 Int_t index = (node<<1) + (LEFT ? 1 : 2);
1080 Value *tbounds = &fBoundaries[fNDimm*index];
1081 memcpy(tbounds, fRange, fNDimm*
sizeof(Value));
1083 memset(flag, kFALSE, fNDimm);
1088 while(pn >= 0 && nvals < fNDimm){
1090 index = (fAxis[pn]<<1)+1;
1092 tbounds[index] = fValue[pn];
1093 flag[index] = kTRUE;
1097 index = fAxis[pn]<<1;
1099 tbounds[index] = fValue[pn];
1100 flag[index] = kTRUE;
1118 template <
typename Index,
typename Value>
1119 void TKDTree<Index, Value>::MakeBoundariesExact()
1128 fBoundaries =
new Value[fTotalNodes*fNDimm];
1129 Value *min =
new Value[fNDim];
1130 Value *max =
new Value[fNDim];
1131 for (Index inode=fNNodes; inode<fTotalNodes; inode++){
1133 for (Index idim=0; idim<fNDim; idim++){
1134 min[idim]= std::numeric_limits<Value>::max();
1135 max[idim]=-std::numeric_limits<Value>::max();
1137 Index *points = GetPointsIndexes(inode);
1138 Index npoints = GetNPointsNode(inode);
1140 for (Index ipoint=0; ipoint<npoints; ipoint++){
1141 for (Index idim=0; idim<fNDim; idim++){
1142 if (fData[idim][points[ipoint]]<min[idim])
1143 min[idim]=fData[idim][points[ipoint]];
1144 if (fData[idim][points[ipoint]]>max[idim])
1145 max[idim]=fData[idim][points[ipoint]];
1148 for (Index idim=0; idim<fNDimm; idim+=2){
1149 fBoundaries[inode*fNDimm + idim]=min[idim/2];
1150 fBoundaries[inode*fNDimm + idim+1]=max[idim/2];
1158 for (Index inode=fNNodes-1; inode>=0; inode--){
1160 left = GetLeft(inode)*fNDimm;
1161 right = GetRight(inode)*fNDimm;
1162 for (Index idim=0; idim<fNDimm; idim+=2){
1164 fBoundaries[inode*fNDimm+idim]=TMath::Min(fBoundaries[left+idim], fBoundaries[right+idim]);
1166 fBoundaries[inode*fNDimm+idim+1]=TMath::Max(fBoundaries[left+idim+1], fBoundaries[right+idim+1]);
1177 template <
typename Index,
typename Value>
1178 void TKDTree<Index, Value>::FindBNodeA(Value *point, Value *delta, Int_t &inode){
1180 for (;inode<fNNodes;){
1181 if (TMath::Abs(point[fAxis[inode]] - fValue[inode])<delta[fAxis[inode]])
break;
1182 inode = (point[fAxis[inode]] < fValue[inode]) ? (inode*2)+1: (inode*2)+2;
1189 template <
typename Index,
typename Value>
1190 Value* TKDTree<Index, Value>::GetBoundaries()
1192 if(!fBoundaries) MakeBoundaries();
1200 template <
typename Index,
typename Value>
1201 Value* TKDTree<Index, Value>::GetBoundariesExact()
1203 if(!fBoundaries) MakeBoundariesExact();
1210 template <
typename Index,
typename Value>
1211 Value* TKDTree<Index, Value>::GetBoundary(
const Int_t node)
1213 if(!fBoundaries) MakeBoundaries();
1214 return &fBoundaries[node*2*fNDim];
1220 template <
typename Index,
typename Value>
1221 Value* TKDTree<Index, Value>::GetBoundaryExact(
const Int_t node)
1223 if(!fBoundaries) MakeBoundariesExact();
1224 return &fBoundaries[node*2*fNDim];
1233 TKDTreeIF *TKDTreeTestBuild(
const Int_t npoints,
const Int_t bsize){
1234 Float_t *data0 =
new Float_t[npoints*2];
1236 data[0] = &data0[0];
1237 data[1] = &data0[npoints];
1238 for (Int_t i=0;i<npoints;i++) {
1239 data[1][i]= gRandom->Rndm();
1240 data[0][i]= gRandom->Rndm();
1242 TKDTree<Int_t, Float_t> *kdtree =
new TKDTreeIF(npoints, 2, bsize, data);
1248 template class TKDTree<Int_t, Float_t>;
1249 template class TKDTree<Int_t, Double_t>;