LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
LSSTDataManagementBasePackage
KDTree.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
31 #ifndef LSST_AP_CLUSTER_DETAIL_KDTREE_CC
32 #define LSST_AP_CLUSTER_DETAIL_KDTREE_CC
33 
34 #include "KDTree.h"
35 
36 #include <algorithm>
37 #include <utility>
38 
39 
40 namespace lsst { namespace ap { namespace cluster { namespace detail {
41 
42 namespace {
43 
54 template <int K, typename DataT>
55 std::pair<double, int> maxExtentAndDim(Point<K, DataT> const * const points,
56  int const numPoints)
57 {
58  typedef Eigen::Matrix<double, K, 1> Vector;
59 
60  double minv[K];
61  double maxv[K];
62  for (int d = 0; d < K; ++d) {
63  minv[d] = std::numeric_limits<double>::infinity();
64  maxv[d] = -std::numeric_limits<double>::infinity();
65  }
66  for (int i = 0; i < numPoints; ++i) {
67  Vector const & v = points[i].coords;
68  for (int d = 0; d < K; ++d) {
69  minv[d] = std::min(minv[d], v.coeff(d));
70  maxv[d] = std::max(maxv[d], v.coeff(d));
71  }
72  }
73  double maxExtent = maxv[0] - minv[0];
74  int maxD = 0;
75  for (int d = 1; d < K; ++d) {
76  double extent = maxv[d] - minv[d];
77  if (extent > maxExtent) {
78  maxExtent = extent;
79  maxD = d;
80  }
81  }
82  return std::make_pair(maxExtent, maxD);
83 }
84 
88 struct PointCmp {
89  int d;
90 
91  PointCmp(int dim) : d(dim) { }
92 
93  template <int K, typename DataT>
94  bool operator()(Point<K, DataT> const & p1, Point<K, DataT> const & p2) const {
95  return p1.coords.coeff(d) < p2.coords.coeff(d);
96  }
97 };
98 
99 } // namespace
100 
101 
114 template <int K, typename DataT>
116  int numPoints,
117  int pointsPerLeaf,
118  double leafExtentThreshold) :
119  _points(points),
120  _numPoints(numPoints),
121  _nodes()
122 {
123  if (points == 0) {
124  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
125  "pointer to Point array is null");
126  }
127  if (numPoints <= 0) {
128  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
129  "number of input points must be > 0");
130  }
131  if (pointsPerLeaf < 1) {
132  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
133  "target number of points per leaf must be > 0");
134  }
135  // compute tree height
136  int h = 0;
137  for (; h < MAX_HEIGHT && numPoints / (1 << h) > pointsPerLeaf; ++h) { }
138  _height = h;
139  int n = (1 << (h + 1)) - 1;
140  // allocate tree nodes and build the tree
141  boost::scoped_array<KDTreeNode> nodes(new KDTreeNode[n]);
142  using std::swap;
143  swap(_nodes, nodes);
144  build(leafExtentThreshold);
145 }
146 
147 template <int K, typename DataT>
149 
166 template <int K, typename DataT>
167  template <typename MetricT>
169  double const dist,
170  MetricT const & metric)
171 {
172  bool descend[MAX_HEIGHT];
173  int node = 0;
174  int h = 0;
175  int head = -1;
176  int tail = -1;
177  while (true) {
178  if (_nodes[node].splitDim == -1) {
179  // reached a leaf
180  int left = 0;
181  int right = _nodes[node].right;
182  if ((node & (node + 1)) != 0) {
183  // node has a left sibling - use it to obtain
184  // index of first point in leaf.
185  left = _nodes[node - 1].right;
186  }
187  for (int i = left; i < right; ++i) {
188  _points[i].dist = metric(v, _points[i].coords);
189  }
190  // append results to embedded linked list
191  for (int i = left; i < right; ++i) {
192  if (_points[i].dist <= dist) {
193  if (tail == -1) {
194  head = i;
195  } else {
196  _points[tail].next = i;
197  }
198  tail = i;
199  }
200  }
201  // move back up the tree
202  node = (node - 1) >> 1;
203  --h;
204  for (; h >= 0 && !descend[h]; --h) {
205  node = (node - 1) >> 1;
206  }
207  if (h < 0) {
208  // finished tree traversal
209  break;
210  }
211  descend[h] = false;
212  node = (node << 1) + 2;
213  ++h;
214  } else {
215  // determine which children must be visited
216  double split = _nodes[node].split;
217  double vd = v.coeff(_nodes[node].splitDim);
218  if (metric(vd, split) <= dist) {
219  // both children must be visited
220  descend[h] = true;
221  node = (node << 1) + 1;
222  ++h;
223  } else if (vd < split) {
224  // visit left child
225  descend[h] = false;
226  node = (node << 1) + 1;
227  ++h;
228  } else {
229  // visit right child
230  descend[h] = false;
231  node = (node << 1) + 2;
232  ++h;
233  }
234  }
235  }
236  return head;
237 }
238 
242 template <int K, typename DataT>
243 void KDTree<K, DataT>::build(double leafExtentThreshold)
244 {
245  int node = 0;
246  int left = 0;
247  int right = _numPoints;
248  int h = 0;
249  while (true) {
250  _nodes[node].right = right;
251  if (h < _height) {
252  // find splitting dimension
253  std::pair<double, int> extDim = maxExtentAndDim(_points + left,
254  right - left);
255  if (extDim.first > leafExtentThreshold) {
256  _nodes[node].splitDim = extDim.second;
257  // find median of array
258  int median = left + ((right - left) >> 1);
259  std::nth_element(_points + left, _points + median,
260  _points + right, PointCmp(extDim.second));
261  right = median;
262  _nodes[node].split = _points[right].coords.coeff(extDim.second);
263  // process left child
264  node = (node << 1) + 1;
265  ++h;
266  continue;
267  }
268  // node extent is below the subdivision limit: set right index for
269  // all right children of node as their left siblings may be valid
270  int h2 = h;
271  int c = node;
272  do {
273  c = (c << 1) + 2;
274  ++h2;
275  _nodes[c].right = right;
276  } while (h2 < _height);
277  }
278  // move up the tree until a left child is found
279  left = right;
280  for (; h > 0 && (node & 1) == 0; --h) {
281  node = (node - 1) >> 1;
282  }
283  if (h == 0) {
284  // tree construction complete!
285  break;
286  }
287  // node is now the index of a left child - process its right sibling
288  right = _nodes[(node - 1) >> 1].right;
289  node += 1;
290  }
291 }
292 
293 }}}} // namespace lsst::ap::cluster::detail
294 
295 #endif // LSST_AP_CLUSTER_DETAIL_KDTREE_CC
void swap(Ellipse< DataT > &a, Ellipse< DataT > &b)
Definition: EllipseTypes.h:90
void swap(ImageBase< PixelT > &a, ImageBase< PixelT > &b)
Definition: Image.cc:291
Low-level k-d tree class used by the OPTICS implementation.
std::vector< SourceCatalog > const cluster(SourceCatalog const &sources, ClusteringControl const &control)
Definition: clustering.cc:578
boost::scoped_array< KDTreeNode > _nodes
Definition: KDTree.h:162
Eigen::Matrix< double, K, 1 > coords
Point coordinates.
Definition: KDTree.h:86
double min
Definition: attributes.cc:216
int d
Definition: KDTree.cc:89
int inRange(Vector const &v, double const distance, MetricT const &metric)
Definition: KDTree.cc:168
double max
Definition: attributes.cc:218
KDTree(Point< K, DataT > *points, int numPoints, int pointsPerLeaf, double leafExtentThreshold)
Definition: KDTree.cc:115
void build(double leafExtentThreshold)
Definition: KDTree.cc:243
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
Eigen::Matrix< double, K, 1 > Vector
Definition: KDTree.h:135
static int const MAX_HEIGHT
Maximum tree height.
Definition: KDTree.h:137