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
SweepStructure.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 
32 
33 #include <stdexcept>
34 
35 #include "lsst/utils/ieee.h"
36 #include "lsst/afw/geom/Angle.h"
37 
41 
42 
43 namespace lsst { namespace ap { namespace match { namespace detail {
44 
45 // -- SweepStructure implementation ---
46 
47 template <typename Node>
49 #ifndef NDEBUG
50  typedef typename std::vector<HeapEntry>::iterator Iter;
51  _root = 0;
52  for (Iter i = _heap.begin(), e = _heap.end(); i != e; ++i) {
53  i->second = 0;
54  }
55 #endif
56 }
57 
62 template <typename Node>
64  return _isBinarySearchTree(_root) &&
65  _isRedChildBlack(_root) &&
66  _isBalanced() &&
67  _isIntervalTree();
68 }
69 
72 template <typename Node>
74  if (_root == NULL) {
75  // tree is empty
76  _root = i;
77  i->color = BLACK;
78  return;
79  }
80  // top-down tree insertion algorithm
81  Node head; // dummy root
82  Node *ggp = &head; // great grand parent
83  Node *gp = 0; // grand parent
84  Node *p = 0; // parent
85  Node *n = _root; // iterator
86  double const maxCoord0 = i->maxCoord0;
87  int dir = 0;
88  int lastDir = 0;
89  head.link[1] = n;
90 
91  while (true) {
92  if (n == 0) {
93  // insert new node
94  p->link[dir] = i;
95  if (p != 0 && p->color != BLACK) {
96  // p and i are red: fix red violation
97  int d = (ggp->link[1] == gp);
98  if (i == p->link[lastDir]) {
99  ggp->link[d] = _rotate(gp, !lastDir);
100  } else {
101  ggp->link[d] = _doubleRotate(gp, !lastDir);
102  }
103  }
104  // done
105  break;
106  }
107  // update reach
108  if (maxCoord0 > n->reach) {
109  n->reach = maxCoord0;
110  }
111  Node *c0 = n->link[0];
112  Node *c1 = n->link[1];
113  if (c0 != 0 && c1 != 0 && c0->color != BLACK && c1->color != BLACK) {
114  // color flip
115  c0->color = BLACK;
116  c1->color = BLACK;
117  n->color = RED;
118  }
119  if (n->color != BLACK && p != 0 && p->color != BLACK) {
120  // fix red violation
121  int d = (ggp->link[1] == gp);
122  if (n == p->link[lastDir]) {
123  ggp->link[d] = _rotate(gp, !lastDir);
124  } else {
125  ggp->link[d] = _doubleRotate(gp, !lastDir);
126  }
127  }
128  lastDir = dir;
129  dir = lessThan(n, i);
130  if (gp != 0) {
131  ggp = gp;
132  }
133  gp = p;
134  p = n;
135  n = n->link[dir];
136  }
137  _root = head.link[1];
138  _root->color = BLACK;
139 }
140 
143 template <typename Node>
145  // top-down tree removal - push a red node down
146  // the tree such that the node to be removed
147  // is red. On the way down the tree, build a
148  // root to leaf path, and finally, fix up reaches
149  // bottom-up.
150  Node *stack[2*sizeof(size_t)*CHAR_BIT];
151  Node head; // dummy root
152  Node *gp = 0; // grand parent
153  Node *p = 0; // parent
154  Node *n = &head; // iterator
155  head.link[1] = _root;
156  int dir = 1;
157  int level = 0;
158 
159  while (n->link[dir] != 0) {
160  int lastDir = dir;
161  if (p != 0) {
162  stack[level++] = p;
163  }
164  gp = p;
165  p = n;
166  n = n->link[dir];
167  dir = lessThan(n, r);
168 
169  // push down red node
170  if (n->color == BLACK &&
171  (n->link[dir] == 0 || n->link[dir]->color == BLACK)) {
172  if (n->link[!dir] != 0 && n->link[!dir]->color != BLACK) {
173  stack[level++] = p;
174  p = p->link[lastDir] = _rotate(n, dir);
175  } else {
176  Node *s = p->link[!lastDir]; // sibling
177  if (s != 0) {
178  Node *sld = s->link[lastDir];
179  Node *snld = s->link[!lastDir];
180  if ((sld == 0 || sld->color == BLACK) &&
181  (snld == 0 || snld->color == BLACK)) {
182  // color flip
183  p->color = BLACK;
184  s->color = RED;
185  n->color = RED;
186  } else {
187  // double or single rotation
188  int d = (gp->link[1] == p);
189  if (sld != 0 && sld->color == RED) {
190  stack[level++] = sld;
191  s = _doubleRotate(p, lastDir);
192  } else {
193  stack[level++] = s;
194  s = _rotate(p, lastDir);
195  }
196  // fixup colors
197  gp->link[d] = s;
198  n->color = RED;
199  s->color = RED;
200  s->link[0]->color = BLACK;
201  s->link[1]->color = BLACK;
202  }
203  }
204  }
205  }
206  }
207 
208  p->link[p->link[1] == n] = n->link[n->link[0] == 0];
209 
210  // walk up the node stack, recomputing reaches. Note that
211  // either level == 0, or stack[0] == &head
212  for (; level > 0; p = stack[--level]) {
213  if (p == r) {
214  // reached node to remove, exchange it with n
215  n->link[0] = r->link[0];
216  n->link[1] = r->link[1];
217  n->color = r->color;
218  gp = stack[level - 1];
219  gp->link[gp->link[1] == r] = n;
220  p = n;
221  }
222  p->reach = _reach(p);
223  }
224 
225  // update root and color it black
226  _root = head.link[1];
227  if (_root != 0) {
228  _root->color = BLACK;
229  }
230 }
231 
235 template <typename Node>
237  typename std::vector<std::pair<double, Node *> >::size_type n)
238 {
239  if (_heap.max_size() - _heap.size() < n) {
240  throw std::length_error("cannot expand vector: "
241  "max_size() would be exceeded");
242  }
243  typename std::vector<std::pair<double, Node *> >::size_type c = 2*_heap.size();
244  if (c == 0) {
245  ++c;
246  }
247  if (c < _heap.size() || c > _heap.max_size()) {
248  c = _heap.max_size();
249  }
250  _heap.reserve(c);
251 }
252 
256 template <typename Node>
258  if (n == 0) {
259  return true;
260  }
261  if ((n->link[0] != 0 && lessThan(n, n->link[0])) ||
262  (n->link[1] != 0 && lessThan(n->link[1], n))) {
263  return false;
264  }
265  return _isBinarySearchTree(n->link[0]) &&
266  _isBinarySearchTree(n->link[1]);
267 }
268 
271 template <typename Node>
273  if (n == 0) {
274  return true;
275  }
276  if (n->color == RED) {
277  if ((n->link[0] != 0 && n->link[0]->color == RED) ||
278  (n->link[1] != 0 && n->link[1]->color == RED)) {
279  return false;
280  }
281  }
282  return _isRedChildBlack(n->link[0]) &&
283  _isRedChildBlack(n->link[1]);
284 }
285 
288 template <typename Node>
290  // count number of black nodes on path from root to minimum leaf
291  int numBlack = 0;
292  Node *n = _root;
293  while (n != 0) {
294  if (n->color == BLACK) {
295  ++numBlack;
296  }
297  n = n->link[0];
298  }
299  // check that all other paths agree
300  return _isBalanced(_root, numBlack);
301 }
302 
305 template <typename Node>
306 bool SweepStructure<Node>::_isBalanced(Node const *n, int numBlack) {
307  if (n == 0) {
308  return (numBlack == 0);
309  }
310  if (n->color == BLACK) {
311  --numBlack;
312  }
313  return _isBalanced(n->link[0], numBlack) &&
314  _isBalanced(n->link[1], numBlack);
315 }
316 
319 template <typename Node>
321  double reach = _checkReach(_root);
322  return !lsst::utils::isnan(reach);
323 }
324 
329 template <typename Node>
330 double SweepStructure<Node>::_checkReach(Node const *n) {
331  if (n == 0) {
332  return -std::numeric_limits<double>::infinity();
333  }
334  double r0 = _checkReach(n->link[0]);
335  if (lsst::utils::isnan(r0)) {
336  return r0;
337  }
338  double r1 = _checkReach(n->link[1]);
339  if (lsst::utils::isnan(r1)) {
340  return r1;
341  }
342  double r = std::max(std::max(r0, r1), n->maxCoord0);;
343  return (r == n->reach) ? r : std::numeric_limits<double>::quiet_NaN();
344 }
345 
346 
347 // -- SweepStructure<CartesianNode> method specializations ----
348 
352 template <>
354  if (b != 0) {
355  if (_heap.size() == _heap.capacity()) {
356  _grow(1);
357  }
358  CartesianNode *n = new (_arena) CartesianNode(b);
359  // after this point, no exception can be thrown
360  _insert(n);
361  _heap.push_back(HeapEntry(b->getMaxCoord1(), n));
362  std::push_heap(_heap.begin(), _heap.end());
363  }
364 }
365 
366 
367 // -- SweepStructure<SphericalNode> method specializations ----
368 
372 template <>
374  if (b == 0) {
375  return;
376  }
377  Angle min = b->getMinCoord0() * radians;
378  Angle max = b->getMaxCoord0() * radians;
380  if (min > max) {
381  // box wraps across the 0/2*M_PI longitude angle
382  // discontinuity - insert twin nodes for [0, min] and
383  // [max, 2*M_PI]
384  if (_heap.capacity() - _heap.size() < 2) {
385  _grow(2);
386  }
387  SphericalNode *n1 = new (_arena) SphericalNode(
388  b, 0.0, static_cast<double>(max));
389  SphericalNode *n2 = 0;
390  try {
391  n2 = new (_arena) SphericalNode(b, static_cast<double>(min), TWOPI);
392  } catch (...) {
393  // exception safety: if allocation for n2 fails, delete n1.
394  _arena.destroy(n1);
395  throw;
396  }
397  // after this point no exception can be thrown
398  n1->twin = n2;
399  n2->twin = n1;
400  _insert(n1);
401  _insert(n2);
402  double maxCoord1 = b->getMaxCoord1();
403  _heap.push_back(HeapEntry(maxCoord1, n1));
404  std::push_heap(_heap.begin(), _heap.end());
405  _heap.push_back(HeapEntry(maxCoord1, n2));
406  std::push_heap(_heap.begin(), _heap.end());
407  } else {
408  // box does not wrap - insert a single node.
409  if (_heap.size() == _heap.capacity()) {
410  _grow(1);
411  }
413  b, static_cast<double>(min), static_cast<double>(max));
414  // after this point no exception can be thrown
415  _insert(n);
416  _heap.push_back(HeapEntry(b->getMaxCoord1(), n));
417  std::push_heap(_heap.begin(), _heap.end());
418  }
419 }
420 
421 
422 // -- SweepStructure instantiations ---
423 
425 template class SweepStructure<CartesianNode>;
426 template class SweepStructure<SphericalNode>;
428 
429 }}}} // namespace lsst::ap::match::detail
430 
virtual double getMinCoord0() const =0
static bool _isBinarySearchTree(Node const *n)
static bool _isRedChildBlack(Node const *n)
AngleUnit const radians
constant with units of radians
Definition: Angle.h:91
virtual double getMaxCoord0() const =0
std::pair< double, Node * > HeapEntry
double const TWOPI
Definition: Angle.h:19
int isnan(T t)
Definition: ieee.h:110
virtual double getMaxCoord1() const =0
double min
Definition: attributes.cc:216
int d
Definition: KDTree.cc:89
double max
Definition: attributes.cc:218
bool lessThan(CartesianNode const *a, CartesianNode const *b)
std::vector< std::pair< Angle, Ref * > > _heap
lsst::afw::geom::Angle Angle
Definition: misc.h:42
Arena< MatchablePos > _arena
void _grow(typename std::vector< HeapEntry >::size_type n)
static double _checkReach(Node const *n)
afw::table::Key< double > b
Sweep line data structures useful for region-region matching.
void thetaRangeReduce(Angle &min, Angle &max)
Definition: SpatialUtils.cc:56