CMS 3D CMS Logo

KDTreeLinkerAlgo.h
Go to the documentation of this file.
1 #ifndef KDTreeLinkerAlgoTemplated_h
2 #define KDTreeLinkerAlgoTemplated_h
3 
4 #include "KDTreeLinkerTools.h"
5 
6 #include <cassert>
7 #include <vector>
8 
9 // Class that implements the KDTree partition of 2D space and
10 // a closest point search algorithme.
11 
12 template <typename DATA>
14 public:
16 
17  // Dtor calls clear()
19 
20  // Here we build the KD tree from the "eltList" in the space define by "region".
21  void build(std::vector<KDTreeNodeInfo<DATA> > &eltList, const KDTreeBox &region);
22 
23  // Here we search in the KDTree for all points that would be
24  // contained in the given searchbox. The founded points are stored in resRecHitList.
25  void search(const KDTreeBox &searchBox, std::vector<DATA> &resRecHitList);
26 
27  // This reurns true if the tree is empty
28  bool empty() { return nodePool_.empty(); }
29 
30  // This returns the number of nodes + leaves in the tree
31  // (nElements should be (size() +1)/2)
32  int size() { return nodePool_.size(); }
33 
34  // This method clears all allocated structures.
35  void clear();
36 
37 private:
38  // The node pool allow us to do just 1 call to new for each tree building.
40 
41  std::vector<DATA> *closestNeighbour;
42  std::vector<KDTreeNodeInfo<DATA> > *initialEltList;
43 
44 private:
45  //Fast median search with Wirth algorithm in eltList between low and high indexes.
46  int medianSearch(int low, int high, int treeDepth);
47 
48  // Recursif kdtree builder. Is called by build()
49  int recBuild(int low, int hight, int depth);
50 
51  // Recursif kdtree search. Is called by search()
52  void recSearch(int current, float dimCurrMin, float dimCurrMax, float dimOtherMin, float dimOtherMax);
53 
54  // This method frees the KDTree.
55  void clearTree();
56 };
57 
58 //Implementation
59 
60 template <typename DATA>
61 void KDTreeLinkerAlgo<DATA>::build(std::vector<KDTreeNodeInfo<DATA> > &eltList, const KDTreeBox &region) {
62  if (!eltList.empty()) {
63  initialEltList = &eltList;
64 
65  size_t size = initialEltList->size();
66  nodePool_.build(size);
67 
68  // Here we build the KDTree
69  int root = recBuild(0, size, 0);
70  assert(root == 0);
71 
72  initialEltList = nullptr;
73  }
74 }
75 
76 //Fast median search with Wirth algorithm in eltList between low and high indexes.
77 template <typename DATA>
78 int KDTreeLinkerAlgo<DATA>::medianSearch(int low, int high, int treeDepth) {
79  int nbrElts = high - low;
80  int median = (nbrElts & 1) ? nbrElts / 2 : nbrElts / 2 - 1;
81  median += low;
82 
83  int l = low;
84  int m = high - 1;
85 
86  while (l < m) {
87  KDTreeNodeInfo<DATA> elt = (*initialEltList)[median];
88  int i = l;
89  int j = m;
90 
91  do {
92  // The even depth is associated to dim1 dimension
93  // The odd one to dim2 dimension
94  if (treeDepth & 1) {
95  while ((*initialEltList)[i].dim[1] < elt.dim[1])
96  i++;
97  while ((*initialEltList)[j].dim[1] > elt.dim[1])
98  j--;
99  } else {
100  while ((*initialEltList)[i].dim[0] < elt.dim[0])
101  i++;
102  while ((*initialEltList)[j].dim[0] > elt.dim[0])
103  j--;
104  }
105 
106  if (i <= j) {
108  i++;
109  j--;
110  }
111  } while (i <= j);
112  if (j < median)
113  l = i;
114  if (i > median)
115  m = j;
116  }
117 
118  return median;
119 }
120 
121 template <typename DATA>
122 void KDTreeLinkerAlgo<DATA>::search(const KDTreeBox &trackBox, std::vector<DATA> &recHits) {
123  if (!empty()) {
124  closestNeighbour = &recHits;
125  recSearch(0, trackBox.dim1min, trackBox.dim1max, trackBox.dim2min, trackBox.dim2max);
126  closestNeighbour = nullptr;
127  }
128 }
129 
130 template <typename DATA>
132  int current, float dimCurrMin, float dimCurrMax, float dimOtherMin, float dimOtherMax) {
133  // Iterate until leaf is found, or there are no children in the
134  // search window. If search has to proceed on both children, proceed
135  // the search to left child via recursion. Swap search window
136  // dimension on alternate levels.
137  while (true) {
138  int right = nodePool_.right[current];
139  if (nodePool_.isLeaf(right)) {
140  float dimCurr = nodePool_.median[current];
141 
142  // If point inside the rectangle/area
143  // Use intentionally bit-wise & instead of logical && for better
144  // performance. It is faster to always do all comparisons than to
145  // allow use of branches to not do some if any of the first ones
146  // is false.
147  if ((dimCurr >= dimCurrMin) & (dimCurr <= dimCurrMax)) {
148  float dimOther = nodePool_.dimOther[current];
149  if ((dimOther >= dimOtherMin) & (dimOther <= dimOtherMax)) {
150  closestNeighbour->push_back(nodePool_.data[current]);
151  }
152  }
153  break;
154  } else {
155  float median = nodePool_.median[current];
156 
157  bool goLeft = (dimCurrMin <= median);
158  bool goRight = (dimCurrMax >= median);
159 
160  // Swap dimension for the next search level
161  std::swap(dimCurrMin, dimOtherMin);
162  std::swap(dimCurrMax, dimOtherMax);
163  if (goLeft & goRight) {
164  int left = current + 1;
165  recSearch(left, dimCurrMin, dimCurrMax, dimOtherMin, dimOtherMax);
166  // continue with right
167  current = right;
168  } else if (goLeft) {
169  ++current;
170  } else if (goRight) {
171  current = right;
172  } else {
173  break;
174  }
175  }
176  }
177 }
178 
179 template <typename DATA>
181 
182 template <typename DATA>
184  clear();
185 }
186 
187 template <typename DATA>
189  nodePool_.clear();
190 }
191 
192 template <typename DATA>
194  clearTree();
195 }
196 
197 template <typename DATA>
198 int KDTreeLinkerAlgo<DATA>::recBuild(int low, int high, int depth) {
199  int portionSize = high - low;
200  int dimIndex = depth & 1;
201 
202  if (portionSize == 1) { // Leaf case
203  int leaf = nodePool_.getNextNode();
204  const KDTreeNodeInfo<DATA> &info = (*initialEltList)[low];
205  nodePool_.right[leaf] = 0;
206  nodePool_.median[leaf] = info.dim[dimIndex]; // dimCurrent
207  nodePool_.dimOther[leaf] = info.dim[1 - dimIndex];
208  nodePool_.data[leaf] = info.data;
209  return leaf;
210 
211  } else { // Node case
212 
213  // The even depth is associated to dim1 dimension
214  // The odd one to dim2 dimension
215  int medianId = medianSearch(low, high, depth);
216  float medianVal = (*initialEltList)[medianId].dim[dimIndex];
217 
218  // We create the node
219  int nodeInd = nodePool_.getNextNode();
220  nodePool_.median[nodeInd] = medianVal;
221 
222  ++depth;
223  ++medianId;
224 
225  // We recursively build the son nodes
226  int left = recBuild(low, medianId, depth);
227  assert(nodeInd + 1 == left);
228  nodePool_.right[nodeInd] = recBuild(medianId, high, depth);
229 
230  return nodeInd;
231  }
232 }
233 
234 #endif
static const TGPicture * info(bool iBackgroundIsBlack)
int recBuild(int low, int hight, int depth)
std::vector< DATA > * closestNeighbour
std::vector< KDTreeNodeInfo< DATA > > * initialEltList
KDTreeNodes< DATA > nodePool_
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
void search(const KDTreeBox &searchBox, std::vector< DATA > &resRecHitList)
void build(std::vector< KDTreeNodeInfo< DATA > > &eltList, const KDTreeBox &region)
int medianSearch(int low, int high, int treeDepth)
void recSearch(int current, float dimCurrMin, float dimCurrMax, float dimOtherMin, float dimOtherMax)