fastjet 2.4.5
|
00001 //STARTHEADER 00002 // $Id: ClosestPair2D.cc 3157 2013-07-11 16:02:51Z soyez $ 00003 // 00004 // Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam 00005 // 00006 //---------------------------------------------------------------------- 00007 // This file is part of FastJet. 00008 // 00009 // FastJet is free software; you can redistribute it and/or modify 00010 // it under the terms of the GNU General Public License as published by 00011 // the Free Software Foundation; either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // The algorithms that underlie FastJet have required considerable 00015 // development and are described in hep-ph/0512210. If you use 00016 // FastJet as part of work towards a scientific publication, please 00017 // include a citation to the FastJet paper. 00018 // 00019 // FastJet is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00022 // GNU General Public License for more details. 00023 // 00024 // You should have received a copy of the GNU General Public License 00025 // along with FastJet; if not, write to the Free Software 00026 // Foundation, Inc.: 00027 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00028 //---------------------------------------------------------------------- 00029 //ENDHEADER 00030 00031 #include "fastjet/internal/ClosestPair2D.hh" 00032 00033 #include<limits> 00034 #include<iostream> 00035 #include<iomanip> 00036 #include<algorithm> 00037 00038 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh 00039 00040 const unsigned int huge_unsigned = 4294967295U; 00041 const unsigned int twopow31 = 2147483648U; 00042 00043 using namespace std; 00044 00045 //---------------------------------------------------------------------- 00047 void ClosestPair2D::_point2shuffle(Point & point, Shuffle & shuffle, 00048 unsigned int shift) { 00049 00050 Coord2D renorm_point = (point.coord - _left_corner)/_range; 00051 // make sure the point is sensible 00052 //cerr << point.coord.x <<" "<<point.coord.y<<endl; 00053 assert(renorm_point.x >=0); 00054 assert(renorm_point.x <=1); 00055 assert(renorm_point.y >=0); 00056 assert(renorm_point.y <=1); 00057 00058 shuffle.x = static_cast<unsigned int>(twopow31 * renorm_point.x) + shift; 00059 shuffle.y = static_cast<unsigned int>(twopow31 * renorm_point.y) + shift; 00060 shuffle.point = &point; 00061 } 00062 00063 //---------------------------------------------------------------------- 00065 bool ClosestPair2D::Shuffle::operator<(const Shuffle & q) const { 00066 00067 if (floor_ln2_less(x ^ q.x, y ^ q.y)) { 00068 // i = 2 in Chan's algorithm 00069 return (y < q.y); 00070 } else { 00071 // i = 1 in Chan's algorithm 00072 return (x < q.x); 00073 } 00074 } 00075 00076 00077 00078 //---------------------------------------------------------------------- 00079 void ClosestPair2D::_initialize(const std::vector<Coord2D> & positions, 00080 const Coord2D & left_corner, 00081 const Coord2D & right_corner, 00082 unsigned int max_size) { 00083 00084 unsigned int n_positions = positions.size(); 00085 assert(max_size >= n_positions); 00086 00087 //_points(positions.size()) 00088 00089 // allow the points array to grow to the following size 00090 _points.resize(max_size); 00091 // currently unused points are immediately made available on the 00092 // stack 00093 for (unsigned int i = n_positions; i < max_size; i++) { 00094 _available_points.push(&(_points[i])); 00095 } 00096 00097 _left_corner = left_corner; 00098 _range = max((right_corner.x - left_corner.x), 00099 (right_corner.y - left_corner.y)); 00100 00101 // initialise the coordinates for the points and create the zero-shifted 00102 // shuffle array 00103 vector<Shuffle> shuffles(n_positions); 00104 for (unsigned int i = 0; i < n_positions; i++) { 00105 // set up the points 00106 _points[i].coord = positions[i]; 00107 _points[i].neighbour_dist2 = numeric_limits<double>::max(); 00108 _points[i].review_flag = 0; 00109 00110 // create shuffle with 0 shift. 00111 _point2shuffle(_points[i], shuffles[i], 0); 00112 } 00113 00114 // establish what our shifts will be 00115 for (unsigned ishift = 0; ishift < _nshift; ishift++) { 00116 // make sure we use double-precision for calculating the shifts 00117 // since otherwise we will hit integer overflow. 00118 _shifts[ishift] = static_cast<unsigned int>(((twopow31*1.0)*ishift)/_nshift); 00119 if (ishift == 0) {_rel_shifts[ishift] = 0;} 00120 else {_rel_shifts[ishift] = _shifts[ishift] - _shifts[ishift-1];} 00121 } 00122 //_shifts[0] = 0; 00123 //_shifts[1] = static_cast<unsigned int>((twopow31*1.0)/3.0); 00124 //_shifts[2] = static_cast<unsigned int>((twopow31*2.0)/3.0); 00125 //_rel_shifts[0] = 0; 00126 //_rel_shifts[1] = _shifts[1]; 00127 //_rel_shifts[2] = _shifts[2]-_shifts[1]; 00128 00129 // and how we will search... 00130 //_cp_search_range = 49; 00131 _cp_search_range = 30; 00132 _points_under_review.reserve(_nshift * _cp_search_range); 00133 00134 // now initialise the three trees 00135 for (unsigned int ishift = 0; ishift < _nshift; ishift++) { 00136 00137 // shift the shuffles if need be. 00138 if (ishift > 0) { 00139 unsigned rel_shift = _rel_shifts[ishift]; 00140 for (unsigned int i = 0; i < shuffles.size(); i++) { 00141 shuffles[i] += rel_shift; } 00142 } 00143 00144 // sort the shuffles 00145 sort(shuffles.begin(), shuffles.end()); 00146 00147 // and create the search tree 00148 _trees[ishift] = auto_ptr<Tree>(new Tree(shuffles, max_size)); 00149 00150 // now we look for the closest-pair candidates on this tree 00151 circulator circ = _trees[ishift]->somewhere(), start=circ; 00152 // the actual range in which we search 00153 unsigned int CP_range = min(_cp_search_range, n_positions-1); 00154 do { 00155 Point * this_point = circ->point; 00156 //cout << _ID(this_point) << " "; 00157 this_point->circ[ishift] = circ; 00158 // run over all points within _cp_search_range of this_point on tree 00159 circulator other = circ; 00160 for (unsigned i=0; i < CP_range; i++) { 00161 ++other; 00162 double dist2 = this_point->distance2(*other->point); 00163 if (dist2 < this_point->neighbour_dist2) { 00164 this_point->neighbour_dist2 = dist2; 00165 this_point->neighbour = other->point; 00166 } 00167 } 00168 } while (++circ != start); 00169 //cout << endl<<endl; 00170 } 00171 00172 // now initialise the heap object... 00173 vector<double> mindists2(n_positions); 00174 for (unsigned int i = 0; i < n_positions; i++) { 00175 mindists2[i] = _points[i].neighbour_dist2;} 00176 00177 _heap = auto_ptr<MinHeap>(new MinHeap(mindists2, max_size)); 00178 } 00179 00180 00181 //----------------------------------------------------------------------= 00182 void ClosestPair2D::closest_pair(unsigned int & ID1, unsigned int & ID2, 00183 double & distance2) const { 00184 ID1 = _heap->minloc(); 00185 ID2 = _ID(_points[ID1].neighbour); 00186 distance2 = _points[ID1].neighbour_dist2; 00187 if (ID1 > ID2) std::swap(ID1,ID2); 00188 } 00189 00190 00191 //---------------------------------------------------------------------- 00192 inline void ClosestPair2D::_add_label(Point * point, unsigned int review_flag) { 00193 00194 // if it's not already under review, then put it on the list of 00195 // points needing review 00196 if (point->review_flag == 0) _points_under_review.push_back(point); 00197 00198 // OR the point's current flag with the requested review flag 00199 point->review_flag |= review_flag; 00200 } 00201 00202 //---------------------------------------------------------------------- 00203 inline void ClosestPair2D::_set_label(Point * point, unsigned int review_flag) { 00204 00205 // if it's not already under review, then put it on the list of 00206 // points needing review 00207 if (point->review_flag == 0) _points_under_review.push_back(point); 00208 00209 // SET the point's current flag to the requested review flag 00210 point->review_flag = review_flag; 00211 } 00212 00213 //---------------------------------------------------------------------- 00214 void ClosestPair2D::remove(unsigned int ID) { 00215 00216 //cout << "While removing " << ID <<endl; 00217 00218 Point * point_to_remove = & (_points[ID]); 00219 00220 // remove this point from the search tree 00221 _remove_from_search_tree(point_to_remove); 00222 00223 // the above statement labels certain points as needing "review" -- 00224 // deal with them... 00225 _deal_with_points_to_review(); 00226 } 00227 00228 00229 //---------------------------------------------------------------------- 00230 void ClosestPair2D::_remove_from_search_tree(Point * point_to_remove) { 00231 00232 // add this point to the list of "available" points (this is 00233 // relevant also from the point of view of determining the range 00234 // over which we circulate). 00235 _available_points.push(point_to_remove); 00236 00237 // label it so that it goes from the heap 00238 _set_label(point_to_remove, _remove_heap_entry); 00239 00240 // establish the range over which we search (a) for points that have 00241 // acquired a new neighbour and (b) for points which had ID as their 00242 // neighbour; 00243 00244 unsigned int CP_range = min(_cp_search_range, size()-1); 00245 00246 // then, for each shift 00247 for (unsigned int ishift = 0; ishift < _nshift; ishift++) { 00248 //cout << " ishift = " << ishift <<endl; 00249 // get the circulator for the point we'll remove and its successor 00250 circulator removed_circ = point_to_remove->circ[ishift]; 00251 circulator right_end = removed_circ.next(); 00252 // remove the point 00253 _trees[ishift]->remove(removed_circ); 00254 00255 // next find the point CP_range points to the left 00256 circulator left_end = right_end, orig_right_end = right_end; 00257 for (unsigned int i = 0; i < CP_range; i++) {left_end--;} 00258 00259 if (size()-1 < _cp_search_range) { 00260 // we have a smaller range now than before -- but when seeing who 00261 // could have had ID as a neighbour, we still need to use the old 00262 // range for seeing how far back we search (but new separation between 00263 // points). [cf CCN28-42] 00264 left_end--; right_end--; 00265 } 00266 00267 // and then for each left-end point: establish if the removed 00268 // point was its neighbour [in which case a new neighbour must be 00269 // found], otherwise see if the right-end point is a closer neighbour 00270 do { 00271 Point * left_point = left_end->point; 00272 00273 //cout << " visited " << setw(3)<<_ID(left_point)<<" (its neighbour was "<< setw(3)<< _ID(left_point->neighbour)<<")"<<endl; 00274 00275 if (left_point->neighbour == point_to_remove) { 00276 // we'll deal with it later... 00277 _add_label(left_point, _review_neighbour); 00278 } else { 00279 // check to see if right point has become its closest neighbour 00280 double dist2 = left_point->distance2(*right_end->point); 00281 if (dist2 < left_point->neighbour_dist2) { 00282 left_point->neighbour = right_end->point; 00283 left_point->neighbour_dist2 = dist2; 00284 // NB: (LESSER) REVIEW NEEDED HERE TOO... 00285 _add_label(left_point, _review_heap_entry); 00286 } 00287 } 00288 ++right_end; 00289 } while (++left_end != orig_right_end); 00290 } // ishift... 00291 00292 } 00293 00294 00295 //---------------------------------------------------------------------- 00296 void ClosestPair2D::_deal_with_points_to_review() { 00297 00298 // the range in which we carry out searches for new neighbours on 00299 // the search tree 00300 unsigned int CP_range = min(_cp_search_range, size()-1); 00301 00302 // now deal with the points that are "under review" in some way 00303 // (have lost their neighbour, or need their heap entry updating) 00304 while(_points_under_review.size() > 0) { 00305 // get the point to be considered 00306 Point * this_point = _points_under_review.back(); 00307 // remove it from the list 00308 _points_under_review.pop_back(); 00309 00310 if (this_point->review_flag & _remove_heap_entry) { 00311 // make sure no other flags are on (it wouldn't be consistent?) 00312 assert(!(this_point->review_flag ^ _remove_heap_entry)); 00313 _heap->remove(_ID(this_point)); 00314 } 00315 // check to see if the _review_neighbour flag is on 00316 else { 00317 if (this_point->review_flag & _review_neighbour) { 00318 this_point->neighbour_dist2 = numeric_limits<double>::max(); 00319 // among all three shifts 00320 for (unsigned int ishift = 0; ishift < _nshift; ishift++) { 00321 circulator other = this_point->circ[ishift]; 00322 // among points within CP_range 00323 for (unsigned i=0; i < CP_range; i++) { 00324 ++other; 00325 double dist2 = this_point->distance2(*other->point); 00326 if (dist2 < this_point->neighbour_dist2) { 00327 this_point->neighbour_dist2 = dist2; 00328 this_point->neighbour = other->point; 00329 } 00330 } 00331 } 00332 } 00333 00334 // for any non-zero review flag we'll have to update the heap 00335 _heap->update(_ID(this_point), this_point->neighbour_dist2); 00336 } 00337 00338 // "delabel" the point 00339 this_point->review_flag = 0; 00340 00341 } 00342 00343 } 00344 00345 //---------------------------------------------------------------------- 00346 unsigned int ClosestPair2D::insert(const Coord2D & new_coord) { 00347 00348 // get hold of a point 00349 assert(_available_points.size() > 0); 00350 Point * new_point = _available_points.top(); 00351 _available_points.pop(); 00352 00353 // set the point's coordinate 00354 new_point->coord = new_coord; 00355 00356 // now find it's neighbour in the search tree 00357 _insert_into_search_tree(new_point); 00358 00359 // sort out other points that may have been affected by this, 00360 // and/or for which the heap needs to be updated 00361 _deal_with_points_to_review(); 00362 00363 // 00364 return _ID(new_point); 00365 } 00366 00367 //---------------------------------------------------------------------- 00368 unsigned int ClosestPair2D::replace(unsigned int ID1, unsigned int ID2, 00369 const Coord2D & position) { 00370 00371 // deletion from tree... 00372 Point * point_to_remove = & (_points[ID1]); 00373 _remove_from_search_tree(point_to_remove); 00374 00375 point_to_remove = & (_points[ID2]); 00376 _remove_from_search_tree(point_to_remove); 00377 00378 // insertion into tree 00379 // get hold of a point 00380 Point * new_point = _available_points.top(); 00381 _available_points.pop(); 00382 00383 // set the point's coordinate 00384 new_point->coord = position; 00385 00386 // now find it's neighbour in the search tree 00387 _insert_into_search_tree(new_point); 00388 00389 // the above statement labels certain points as needing "review" -- 00390 // deal with them... 00391 _deal_with_points_to_review(); 00392 00393 // 00394 return _ID(new_point); 00395 00396 } 00397 00398 00399 //---------------------------------------------------------------------- 00400 void ClosestPair2D::replace_many( 00401 const std::vector<unsigned int> & IDs_to_remove, 00402 const std::vector<Coord2D> & new_positions, 00403 std::vector<unsigned int> & new_IDs) { 00404 00405 // deletion from tree... 00406 for (unsigned int i = 0; i < IDs_to_remove.size(); i++) { 00407 _remove_from_search_tree(& (_points[IDs_to_remove[i]])); 00408 } 00409 00410 // insertion into tree 00411 new_IDs.resize(0); 00412 for (unsigned int i = 0; i < new_positions.size(); i++) { 00413 Point * new_point = _available_points.top(); 00414 _available_points.pop(); 00415 // set the point's coordinate 00416 new_point->coord = new_positions[i]; 00417 // now find it's neighbour in the search tree 00418 _insert_into_search_tree(new_point); 00419 // record the ID 00420 new_IDs.push_back(_ID(new_point)); 00421 } 00422 00423 // the above statement labels certain points as needing "review" -- 00424 // deal with them... 00425 _deal_with_points_to_review(); 00426 00427 } 00428 00429 00430 //---------------------------------------------------------------------- 00431 void ClosestPair2D::_insert_into_search_tree(Point * new_point) { 00432 00433 // this point will have to have it's heap entry reviewed... 00434 _set_label(new_point, _review_heap_entry); 00435 00436 // set the current distance to "infinity" 00437 new_point->neighbour_dist2 = numeric_limits<double>::max(); 00438 00439 // establish how far we will be searching; 00440 unsigned int CP_range = min(_cp_search_range, size()-1); 00441 00442 for (unsigned ishift = 0; ishift < _nshift; ishift++) { 00443 // create the shuffle 00444 Shuffle new_shuffle; 00445 _point2shuffle(*new_point, new_shuffle, _shifts[ishift]); 00446 00447 // insert it into the tree 00448 circulator new_circ = _trees[ishift]->insert(new_shuffle); 00449 new_point->circ[ishift] = new_circ; 00450 00451 // now get hold of the right and left edges of the region we will be 00452 // looking at (cf CCN28-43) 00453 circulator right_edge = new_circ; right_edge++; 00454 circulator left_edge = new_circ; 00455 for (unsigned int i = 0; i < CP_range; i++) {left_edge--;} 00456 00457 // now 00458 do { 00459 Point * left_point = left_edge->point; 00460 Point * right_point = right_edge->point; 00461 00462 // see if the new point is closer to the left-edge than the latter's 00463 // current neighbour 00464 double new_dist2 = left_point->distance2(*new_point); 00465 if (new_dist2 < left_point->neighbour_dist2) { 00466 left_point->neighbour_dist2 = new_dist2; 00467 left_point->neighbour = new_point; 00468 _add_label(left_point, _review_heap_entry); 00469 } 00470 00471 // see if the right-point is closer to the new point than it's current 00472 // neighbour 00473 new_dist2 = new_point->distance2(*right_point); 00474 if (new_dist2 < new_point->neighbour_dist2) { 00475 new_point->neighbour_dist2 = new_dist2; 00476 new_point->neighbour = right_point; 00477 } 00478 00479 // if the right-edge point was the left-edge's neighbour, then 00480 // then it's just gone off-radar and the left-point will need to 00481 // have its neighbour recalculated [actually, this is overdoing 00482 // it a little, since right point may be an less "distant" 00483 // (circulator distance) in one of the other shifts -- but not 00484 // sure how to deal with this...] 00485 if (left_point->neighbour == right_point) { 00486 _add_label(left_point, _review_neighbour); 00487 } 00488 00489 // shift the left and right edges until left edge hits new_circ 00490 right_edge++; 00491 } while (++left_edge != new_circ); 00492 } 00493 } 00494 00495 FASTJET_END_NAMESPACE 00496