31#include "fastjet/internal/ClosestPair2D.hh"
38FASTJET_BEGIN_NAMESPACE
40const unsigned int twopow31 = 2147483648U;
46void 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;
64bool ClosestPair2D::Shuffle::operator<(
const Shuffle & q)
const {
78void 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] = SharedPtr<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 = SharedPtr<MinHeap>(
new MinHeap(mindists2, max_size));
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);
195inline 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;
206inline 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;
221 Point * point_to_remove = & (_points[ID]);
224 _remove_from_search_tree(point_to_remove);
228 _deal_with_points_to_review();
233void 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);
299void 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;
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);
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);
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();
434void 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);
Coord2D coord
the point's coordinates
void closest_pair(unsigned int &ID1, unsigned int &ID2, double &distance2) const
provides the IDs of the closest pair as well as the distance between them
unsigned int insert(const Coord2D &)
inserts the position into the closest pair structure and returns the ID that has been allocated for t...
void remove(unsigned int ID)
removes the entry labelled by ID from the object;
virtual unsigned int replace(unsigned int ID1, unsigned int ID2, const Coord2D &position)
removes ID1 and ID2 and inserts position, returning the ID corresponding to position....
virtual void replace_many(const std::vector< unsigned int > &IDs_to_remove, const std::vector< Coord2D > &new_positions, std::vector< unsigned int > &new_IDs)
replaces IDs_to_remove with points at the new_positions indicating the IDs allocated to the new point...
bool floor_ln2_less(unsigned x, unsigned y)
returns true if floor(ln_base2(x)) < floor(ln_base2(y)), using Chan's neat trick.....