31 #include "fastjet/internal/ClosestPair2D.hh"
38 FASTJET_BEGIN_NAMESPACE
40 const unsigned int twopow31 = 2147483648U;
46 void ClosestPair2D::_point2shuffle(Point & point, Shuffle & shuffle,
49 Coord2D renorm_point = (point.coord - _left_corner)/_range;
52 assert(renorm_point.x >=0);
53 assert(renorm_point.x <=1);
54 assert(renorm_point.y >=0);
55 assert(renorm_point.y <=1);
57 shuffle.x =
static_cast<unsigned int>(twopow31 * renorm_point.x) + shift;
58 shuffle.y =
static_cast<unsigned int>(twopow31 * renorm_point.y) + shift;
59 shuffle.point = &point;
64 bool ClosestPair2D::Shuffle::operator<(
const Shuffle & q)
const {
78 void ClosestPair2D::_initialize(
const std::vector<Coord2D> & positions,
79 const Coord2D & left_corner,
80 const Coord2D & right_corner,
81 unsigned int max_size) {
83 unsigned int n_positions = positions.size();
84 assert(max_size >= n_positions);
89 _points.resize(max_size);
92 for (
unsigned int i = n_positions; i < max_size; i++) {
93 _available_points.push(&(_points[i]));
96 _left_corner = left_corner;
97 _range = max((right_corner.x - left_corner.x),
98 (right_corner.y - left_corner.y));
102 vector<Shuffle> shuffles(n_positions);
103 for (
unsigned int i = 0; i < n_positions; i++) {
105 _points[i].coord = positions[i];
106 _points[i].neighbour_dist2 = numeric_limits<double>::max();
107 _points[i].review_flag = 0;
110 _point2shuffle(_points[i], shuffles[i], 0);
114 for (
unsigned ishift = 0; ishift < _nshift; ishift++) {
117 _shifts[ishift] =
static_cast<unsigned int>(((twopow31*1.0)*ishift)/_nshift);
118 if (ishift == 0) {_rel_shifts[ishift] = 0;}
119 else {_rel_shifts[ishift] = _shifts[ishift] - _shifts[ishift-1];}
130 _cp_search_range = 30;
131 _points_under_review.reserve(_nshift * _cp_search_range);
134 for (
unsigned int ishift = 0; ishift < _nshift; ishift++) {
138 unsigned rel_shift = _rel_shifts[ishift];
139 for (
unsigned int i = 0; i < shuffles.size(); i++) {
140 shuffles[i] += rel_shift; }
144 sort(shuffles.begin(), shuffles.end());
147 _trees[ishift] = auto_ptr<Tree>(
new Tree(shuffles, max_size));
150 circulator circ = _trees[ishift]->somewhere(), start=circ;
152 unsigned int CP_range = min(_cp_search_range, n_positions-1);
154 Point * this_point = circ->point;
156 this_point->circ[ishift] = circ;
158 circulator other = circ;
159 for (
unsigned i=0; i < CP_range; i++) {
161 double dist2 = this_point->distance2(*other->point);
162 if (dist2 < this_point->neighbour_dist2) {
163 this_point->neighbour_dist2 = dist2;
164 this_point->neighbour = other->point;
167 }
while (++circ != start);
172 vector<double> mindists2(n_positions);
173 for (
unsigned int i = 0; i < n_positions; i++) {
174 mindists2[i] = _points[i].neighbour_dist2;}
176 _heap = auto_ptr<MinHeap>(
new MinHeap(mindists2, max_size));
181 void ClosestPair2D::closest_pair(
unsigned int & ID1,
unsigned int & ID2,
182 double & distance2)
const {
183 ID1 = _heap->minloc();
184 ID2 = _ID(_points[ID1].neighbour);
185 distance2 = _points[ID1].neighbour_dist2;
190 if (ID1 > ID2) std::swap(ID1,ID2);
195 inline void ClosestPair2D::_add_label(Point * point,
unsigned int review_flag) {
199 if (point->review_flag == 0) _points_under_review.push_back(point);
202 point->review_flag |= review_flag;
206 inline void ClosestPair2D::_set_label(Point * point,
unsigned int review_flag) {
210 if (point->review_flag == 0) _points_under_review.push_back(point);
213 point->review_flag = review_flag;
217 void ClosestPair2D::remove(
unsigned int ID) {
221 Point * point_to_remove = & (_points[ID]);
224 _remove_from_search_tree(point_to_remove);
228 _deal_with_points_to_review();
233 void ClosestPair2D::_remove_from_search_tree(Point * point_to_remove) {
238 _available_points.push(point_to_remove);
241 _set_label(point_to_remove, _remove_heap_entry);
247 unsigned int CP_range = min(_cp_search_range, size()-1);
250 for (
unsigned int ishift = 0; ishift < _nshift; ishift++) {
253 circulator removed_circ = point_to_remove->circ[ishift];
254 circulator right_end = removed_circ.next();
256 _trees[ishift]->remove(removed_circ);
259 circulator left_end = right_end, orig_right_end = right_end;
260 for (
unsigned int i = 0; i < CP_range; i++) {left_end--;}
262 if (size()-1 < _cp_search_range) {
267 left_end--; right_end--;
274 Point * left_point = left_end->point;
278 if (left_point->neighbour == point_to_remove) {
280 _add_label(left_point, _review_neighbour);
283 double dist2 = left_point->distance2(*right_end->point);
284 if (dist2 < left_point->neighbour_dist2) {
285 left_point->neighbour = right_end->point;
286 left_point->neighbour_dist2 = dist2;
288 _add_label(left_point, _review_heap_entry);
292 }
while (++left_end != orig_right_end);
299 void ClosestPair2D::_deal_with_points_to_review() {
303 unsigned int CP_range = min(_cp_search_range, size()-1);
307 while(_points_under_review.size() > 0) {
309 Point * this_point = _points_under_review.back();
311 _points_under_review.pop_back();
313 if (this_point->review_flag & _remove_heap_entry) {
315 assert(!(this_point->review_flag ^ _remove_heap_entry));
316 _heap->remove(_ID(this_point));
320 if (this_point->review_flag & _review_neighbour) {
321 this_point->neighbour_dist2 = numeric_limits<double>::max();
323 for (
unsigned int ishift = 0; ishift < _nshift; ishift++) {
324 circulator other = this_point->circ[ishift];
326 for (
unsigned i=0; i < CP_range; i++) {
328 double dist2 = this_point->distance2(*other->point);
329 if (dist2 < this_point->neighbour_dist2) {
330 this_point->neighbour_dist2 = dist2;
331 this_point->neighbour = other->point;
338 _heap->update(_ID(this_point), this_point->neighbour_dist2);
342 this_point->review_flag = 0;
349 unsigned int ClosestPair2D::insert(
const Coord2D & new_coord) {
352 assert(_available_points.size() > 0);
353 Point * new_point = _available_points.top();
354 _available_points.pop();
357 new_point->coord = new_coord;
360 _insert_into_search_tree(new_point);
364 _deal_with_points_to_review();
367 return _ID(new_point);
371 unsigned int ClosestPair2D::replace(
unsigned int ID1,
unsigned int ID2,
372 const Coord2D & position) {
375 Point * point_to_remove = & (_points[ID1]);
376 _remove_from_search_tree(point_to_remove);
378 point_to_remove = & (_points[ID2]);
379 _remove_from_search_tree(point_to_remove);
383 Point * new_point = _available_points.top();
384 _available_points.pop();
387 new_point->coord = position;
390 _insert_into_search_tree(new_point);
394 _deal_with_points_to_review();
397 return _ID(new_point);
403 void ClosestPair2D::replace_many(
404 const std::vector<unsigned int> & IDs_to_remove,
405 const std::vector<Coord2D> & new_positions,
406 std::vector<unsigned int> & new_IDs) {
409 for (
unsigned int i = 0; i < IDs_to_remove.size(); i++) {
410 _remove_from_search_tree(& (_points[IDs_to_remove[i]]));
415 for (
unsigned int i = 0; i < new_positions.size(); i++) {
416 Point * new_point = _available_points.top();
417 _available_points.pop();
419 new_point->coord = new_positions[i];
421 _insert_into_search_tree(new_point);
423 new_IDs.push_back(_ID(new_point));
428 _deal_with_points_to_review();
434 void ClosestPair2D::_insert_into_search_tree(Point * new_point) {
437 _set_label(new_point, _review_heap_entry);
440 new_point->neighbour_dist2 = numeric_limits<double>::max();
443 unsigned int CP_range = min(_cp_search_range, size()-1);
445 for (
unsigned ishift = 0; ishift < _nshift; ishift++) {
448 _point2shuffle(*new_point, new_shuffle, _shifts[ishift]);
451 circulator new_circ = _trees[ishift]->insert(new_shuffle);
452 new_point->circ[ishift] = new_circ;
456 circulator right_edge = new_circ; right_edge++;
457 circulator left_edge = new_circ;
458 for (
unsigned int i = 0; i < CP_range; i++) {left_edge--;}
462 Point * left_point = left_edge->point;
463 Point * right_point = right_edge->point;
467 double new_dist2 = left_point->distance2(*new_point);
468 if (new_dist2 < left_point->neighbour_dist2) {
469 left_point->neighbour_dist2 = new_dist2;
470 left_point->neighbour = new_point;
471 _add_label(left_point, _review_heap_entry);
476 new_dist2 = new_point->distance2(*right_point);
477 if (new_dist2 < new_point->neighbour_dist2) {
478 new_point->neighbour_dist2 = new_dist2;
479 new_point->neighbour = right_point;
488 if (left_point->neighbour == right_point) {
489 _add_label(left_point, _review_neighbour);
494 }
while (++left_edge != new_circ);
498 FASTJET_END_NAMESPACE
bool floor_ln2_less(unsigned x, unsigned y)
returns true if floor(ln_base2(x)) < floor(ln_base2(y)), using Chan's neat trick...