kd_split.cpp
上传用户:chinafayin
上传日期:2022-04-05
资源大小:153k
文件大小:16k
源码类别:

并行计算

开发平台:

Visual C++

  1. //----------------------------------------------------------------------
  2. // File: kd_split.cpp
  3. // Programmer: Sunil Arya and David Mount
  4. // Description: Methods for splitting kd-trees
  5. // Last modified: 01/04/05 (Version 1.0)
  6. //----------------------------------------------------------------------
  7. // Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
  8. // David Mount.  All Rights Reserved.
  9. // 
  10. // This software and related documentation is part of the Approximate
  11. // Nearest Neighbor Library (ANN).  This software is provided under
  12. // the provisions of the Lesser GNU Public License (LGPL).  See the
  13. // file ../ReadMe.txt for further information.
  14. // 
  15. // The University of Maryland (U.M.) and the authors make no
  16. // representations about the suitability or fitness of this software for
  17. // any purpose.  It is provided "as is" without express or implied
  18. // warranty.
  19. //----------------------------------------------------------------------
  20. // History:
  21. // Revision 0.1  03/04/98
  22. // Initial release
  23. // Revision 1.0  04/01/05
  24. //----------------------------------------------------------------------
  25. #include "kd_tree.h" // kd-tree definitions
  26. #include "kd_util.h" // kd-tree utilities
  27. #include "kd_split.h" // splitting functions
  28. //----------------------------------------------------------------------
  29. // Constants
  30. //----------------------------------------------------------------------
  31. const double ERR = 0.001; // a small value
  32. const double FS_ASPECT_RATIO = 3.0; // maximum allowed aspect ratio
  33. // in fair split. Must be >= 2.
  34. //----------------------------------------------------------------------
  35. // kd_split - Bentley's standard splitting routine for kd-trees
  36. // Find the dimension of the greatest spread, and split
  37. // just before the median point along this dimension.
  38. //----------------------------------------------------------------------
  39. void kd_split(
  40. ANNpointArray pa, // point array (permuted on return)
  41. ANNidxArray pidx, // point indices
  42. const ANNorthRect &,     // bounding rectangle for cell
  43. int n, // number of points
  44. int dim, // dimension of space
  45. int &cut_dim, // cutting dimension (returned)
  46. ANNcoord &cut_val, // cutting value (returned)
  47. int &n_lo) // num of points on low side (returned)
  48. {
  49. // find dimension of maximum spread
  50. cut_dim = annMaxSpread(pa, pidx, n, dim);
  51. n_lo = n/2; // median rank
  52. // split about median
  53. annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
  54. }
  55. //----------------------------------------------------------------------
  56. // midpt_split - midpoint splitting rule for box-decomposition trees
  57. //
  58. // This is the simplest splitting rule that guarantees boxes
  59. // of bounded aspect ratio.  It simply cuts the box with the
  60. // longest side through its midpoint.  If there are ties, it
  61. // selects the dimension with the maximum point spread.
  62. //
  63. // WARNING: This routine (while simple) doesn't seem to work
  64. // well in practice in high dimensions, because it tends to
  65. // generate a large number of trivial and/or unbalanced splits.
  66. // Either kd_split(), sl_midpt_split(), or fair_split() are
  67. // recommended, instead.
  68. //----------------------------------------------------------------------
  69. void midpt_split(
  70. ANNpointArray pa, // point array
  71. ANNidxArray pidx, // point indices (permuted on return)
  72. const ANNorthRect &bnds, // bounding rectangle for cell
  73. int n, // number of points
  74. int dim, // dimension of space
  75. int &cut_dim, // cutting dimension (returned)
  76. ANNcoord &cut_val, // cutting value (returned)
  77. int &n_lo) // num of points on low side (returned)
  78. {
  79. int d;
  80. ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
  81. for (d = 1; d < dim; d++) { // find length of longest box side
  82. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  83. if (length > max_length) {
  84. max_length = length;
  85. }
  86. }
  87. ANNcoord max_spread = -1; // find long side with most spread
  88. for (d = 0; d < dim; d++) {
  89. // is it among longest?
  90. if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
  91. // compute its spread
  92. ANNcoord spr = annSpread(pa, pidx, n, d);
  93. if (spr > max_spread) { // is it max so far?
  94. max_spread = spr;
  95. cut_dim = d;
  96. }
  97. }
  98. }
  99. // split along cut_dim at midpoint
  100. cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2;
  101. // permute points accordingly
  102. int br1, br2;
  103. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  104. //------------------------------------------------------------------
  105. // On return: pa[0..br1-1] < cut_val
  106. // pa[br1..br2-1] == cut_val
  107. // pa[br2..n-1] > cut_val
  108. //
  109. // We can set n_lo to any value in the range [br1..br2].
  110. // We choose split so that points are most evenly divided.
  111. //------------------------------------------------------------------
  112. if (br1 > n/2) n_lo = br1;
  113. else if (br2 < n/2) n_lo = br2;
  114. else n_lo = n/2;
  115. }
  116. //----------------------------------------------------------------------
  117. // sl_midpt_split - sliding midpoint splitting rule
  118. //
  119. // This is a modification of midpt_split, which has the nonsensical
  120. // name "sliding midpoint".  The idea is that we try to use the
  121. // midpoint rule, by bisecting the longest side.  If there are
  122. // ties, the dimension with the maximum spread is selected.  If,
  123. // however, the midpoint split produces a trivial split (no points
  124. // on one side of the splitting plane) then we slide the splitting
  125. // (maintaining its orientation) until it produces a nontrivial
  126. // split. For example, if the splitting plane is along the x-axis,
  127. // and all the data points have x-coordinate less than the x-bisector,
  128. // then the split is taken along the maximum x-coordinate of the
  129. // data points.
  130. //
  131. // Intuitively, this rule cannot generate trivial splits, and
  132. // hence avoids midpt_split's tendency to produce trees with
  133. // a very large number of nodes.
  134. //
  135. //----------------------------------------------------------------------
  136. void sl_midpt_split(
  137. ANNpointArray pa, // point array
  138. ANNidxArray pidx, // point indices (permuted on return)
  139. const ANNorthRect &bnds, // bounding rectangle for cell
  140. int n, // number of points
  141. int dim, // dimension of space
  142. int &cut_dim, // cutting dimension (returned)
  143. ANNcoord &cut_val, // cutting value (returned)
  144. int &n_lo) // num of points on low side (returned)
  145. {
  146. int d;
  147. ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
  148. for (d = 1; d < dim; d++) { // find length of longest box side
  149. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  150. if (length > max_length) {
  151. max_length = length;
  152. }
  153. }
  154. ANNcoord max_spread = -1; // find long side with most spread
  155. for (d = 0; d < dim; d++) {
  156. // is it among longest?
  157. if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
  158. // compute its spread
  159. ANNcoord spr = annSpread(pa, pidx, n, d);
  160. if (spr > max_spread) { // is it max so far?
  161. max_spread = spr;
  162. cut_dim = d;
  163. }
  164. }
  165. }
  166. // ideal split at midpoint
  167. ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2;
  168. ANNcoord min, max;
  169. annMinMax(pa, pidx, n, cut_dim, min, max); // find min/max coordinates
  170. if (ideal_cut_val < min) // slide to min or max as needed
  171. cut_val = min;
  172. else if (ideal_cut_val > max)
  173. cut_val = max;
  174. else
  175. cut_val = ideal_cut_val;
  176. // permute points accordingly
  177. int br1, br2;
  178. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  179. //------------------------------------------------------------------
  180. // On return: pa[0..br1-1] < cut_val
  181. // pa[br1..br2-1] == cut_val
  182. // pa[br2..n-1] > cut_val
  183. //
  184. // We can set n_lo to any value in the range [br1..br2] to satisfy
  185. // the exit conditions of the procedure.
  186. //
  187. // if ideal_cut_val < min (implying br2 >= 1),
  188. // then we select n_lo = 1 (so there is one point on left) and
  189. // if ideal_cut_val > max (implying br1 <= n-1),
  190. // then we select n_lo = n-1 (so there is one point on right).
  191. // Otherwise, we select n_lo as close to n/2 as possible within
  192. // [br1..br2].
  193. //------------------------------------------------------------------
  194. if (ideal_cut_val < min) n_lo = 1;
  195. else if (ideal_cut_val > max) n_lo = n-1;
  196. else if (br1 > n/2) n_lo = br1;
  197. else if (br2 < n/2) n_lo = br2;
  198. else n_lo = n/2;
  199. }
  200. //----------------------------------------------------------------------
  201. // fair_split - fair-split splitting rule
  202. //
  203. // This is a compromise between the kd-tree splitting rule (which
  204. // always splits data points at their median) and the midpoint
  205. // splitting rule (which always splits a box through its center.
  206. // The goal of this procedure is to achieve both nicely balanced
  207. // splits, and boxes of bounded aspect ratio.
  208. //
  209. // A constant FS_ASPECT_RATIO is defined. Given a box, those sides
  210. // which can be split so that the ratio of the longest to shortest
  211. // side does not exceed ASPECT_RATIO are identified.  Among these
  212. // sides, we select the one in which the points have the largest
  213. // spread. We then split the points in a manner which most evenly
  214. // distributes the points on either side of the splitting plane,
  215. // subject to maintaining the bound on the ratio of long to short
  216. // sides. To determine that the aspect ratio will be preserved,
  217. // we determine the longest side (other than this side), and
  218. // determine how narrowly we can cut this side, without causing the
  219. // aspect ratio bound to be exceeded (small_piece).
  220. //
  221. // This procedure is more robust than either kd_split or midpt_split,
  222. // but is more complicated as well.  When point distribution is
  223. // extremely skewed, this degenerates to midpt_split (actually
  224. // 1/3 point split), and when the points are most evenly distributed,
  225. // this degenerates to kd-split.
  226. //----------------------------------------------------------------------
  227. void fair_split(
  228. ANNpointArray pa, // point array
  229. ANNidxArray pidx, // point indices (permuted on return)
  230. const ANNorthRect &bnds, // bounding rectangle for cell
  231. int n, // number of points
  232. int dim, // dimension of space
  233. int &cut_dim, // cutting dimension (returned)
  234. ANNcoord &cut_val, // cutting value (returned)
  235. int &n_lo) // num of points on low side (returned)
  236. {
  237. int d;
  238. ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
  239. cut_dim = 0;
  240. for (d = 1; d < dim; d++) { // find length of longest box side
  241. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  242. if (length > max_length) {
  243. max_length = length;
  244. cut_dim = d;
  245. }
  246. }
  247. ANNcoord max_spread = 0; // find legal cut with max spread
  248. cut_dim = 0;
  249. for (d = 0; d < dim; d++) {
  250. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  251. // is this side midpoint splitable
  252. // without violating aspect ratio?
  253. if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
  254. // compute spread along this dim
  255. ANNcoord spr = annSpread(pa, pidx, n, d);
  256. if (spr > max_spread) { // best spread so far
  257. max_spread = spr;
  258. cut_dim = d; // this is dimension to cut
  259. }
  260. }
  261. }
  262. max_length = 0; // find longest side other than cut_dim
  263. for (d = 0; d < dim; d++) {
  264. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  265. if (d != cut_dim && length > max_length)
  266. max_length = length;
  267. }
  268. // consider most extreme splits
  269. ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
  270. ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
  271. ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
  272. int br1, br2;
  273. // is median below lo_cut ?
  274. if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
  275. cut_val = lo_cut; // cut at lo_cut
  276. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  277. n_lo = br1;
  278. }
  279. // is median above hi_cut?
  280. else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
  281. cut_val = hi_cut; // cut at hi_cut
  282. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  283. n_lo = br2;
  284. }
  285. else { // median cut preserves asp ratio
  286. n_lo = n/2; // split about median
  287. annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
  288. }
  289. }
  290. //----------------------------------------------------------------------
  291. // sl_fair_split - sliding fair split splitting rule
  292. //
  293. // Sliding fair split is a splitting rule that combines the
  294. // strengths of both fair split with sliding midpoint split.
  295. // Fair split tends to produce balanced splits when the points
  296. // are roughly uniformly distributed, but it can produce many
  297. // trivial splits when points are highly clustered.  Sliding
  298. // midpoint never produces trivial splits, and shrinks boxes
  299. // nicely if points are highly clustered, but it may produce
  300. // rather unbalanced splits when points are unclustered but not
  301. // quite uniform.
  302. //
  303. // Sliding fair split is based on the theory that there are two
  304. // types of splits that are "good": balanced splits that produce
  305. // fat boxes, and unbalanced splits provided the cell with fewer
  306. // points is fat.
  307. //
  308. // This splitting rule operates by first computing the longest
  309. // side of the current bounding box.  Then it asks which sides
  310. // could be split (at the midpoint) and still satisfy the aspect
  311. // ratio bound with respect to this side. Among these, it selects
  312. // the side with the largest spread (as fair split would).  It
  313. // then considers the most extreme cuts that would be allowed by
  314. // the aspect ratio bound.  This is done by dividing the longest
  315. // side of the box by the aspect ratio bound. If the median cut
  316. // lies between these extreme cuts, then we use the median cut.
  317. // If not, then consider the extreme cut that is closer to the
  318. // median.  If all the points lie to one side of this cut, then
  319. // we slide the cut until it hits the first point.  This may
  320. // violate the aspect ratio bound, but will never generate empty
  321. // cells. However the sibling of every such skinny cell is fat,
  322. // and hence packing arguments still apply.
  323. //
  324. //----------------------------------------------------------------------
  325. void sl_fair_split(
  326. ANNpointArray pa, // point array
  327. ANNidxArray pidx, // point indices (permuted on return)
  328. const ANNorthRect &bnds, // bounding rectangle for cell
  329. int n, // number of points
  330. int dim, // dimension of space
  331. int &cut_dim, // cutting dimension (returned)
  332. ANNcoord &cut_val, // cutting value (returned)
  333. int &n_lo) // num of points on low side (returned)
  334. {
  335. int d;
  336. ANNcoord min, max; // min/max coordinates
  337. int br1, br2; // split break points
  338. ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
  339. cut_dim = 0;
  340. for (d = 1; d < dim; d++) { // find length of longest box side
  341. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  342. if (length > max_length) {
  343. max_length = length;
  344. cut_dim = d;
  345. }
  346. }
  347. ANNcoord max_spread = 0; // find legal cut with max spread
  348. cut_dim = 0;
  349. for (d = 0; d < dim; d++) {
  350. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  351. // is this side midpoint splitable
  352. // without violating aspect ratio?
  353. if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
  354. // compute spread along this dim
  355. ANNcoord spr = annSpread(pa, pidx, n, d);
  356. if (spr > max_spread) { // best spread so far
  357. max_spread = spr;
  358. cut_dim = d; // this is dimension to cut
  359. }
  360. }
  361. }
  362. max_length = 0; // find longest side other than cut_dim
  363. for (d = 0; d < dim; d++) {
  364. ANNcoord length = bnds.hi[d] - bnds.lo[d];
  365. if (d != cut_dim && length > max_length)
  366. max_length = length;
  367. }
  368. // consider most extreme splits
  369. ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
  370. ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
  371. ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
  372. // find min and max along cut_dim
  373. annMinMax(pa, pidx, n, cut_dim, min, max);
  374. // is median below lo_cut?
  375. if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
  376. if (max > lo_cut) { // are any points above lo_cut?
  377. cut_val = lo_cut; // cut at lo_cut
  378. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  379. n_lo = br1; // balance if there are ties
  380. }
  381. else { // all points below lo_cut
  382. cut_val = max; // cut at max value
  383. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  384. n_lo = n-1;
  385. }
  386. }
  387. // is median above hi_cut?
  388. else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
  389. if (min < hi_cut) { // are any points below hi_cut?
  390. cut_val = hi_cut; // cut at hi_cut
  391. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  392. n_lo = br2; // balance if there are ties
  393. }
  394. else { // all points above hi_cut
  395. cut_val = min; // cut at min value
  396. annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
  397. n_lo = 1;
  398. }
  399. }
  400. else { // median cut is good enough
  401. n_lo = n/2; // split about median
  402. annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
  403. }
  404. }