redistribute_elements.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. // Boost.Geometry Index
  2. //
  3. // R-tree R*-tree split algorithm implementation
  4. //
  5. // Copyright (c) 2011-2022 Adam Wulkiewicz, Lodz, Poland.
  6. //
  7. // This file was modified by Oracle on 2019-2020.
  8. // Modifications copyright (c) 2019-2020 Oracle and/or its affiliates.
  9. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  10. //
  11. // Use, modification and distribution is subject to the Boost Software License,
  12. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  13. // http://www.boost.org/LICENSE_1_0.txt)
  14. #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
  15. #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
  16. #include <boost/core/ignore_unused.hpp>
  17. #include <boost/geometry/core/static_assert.hpp>
  18. #include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
  19. #include <boost/geometry/index/detail/algorithms/margin.hpp>
  20. #include <boost/geometry/index/detail/algorithms/nth_element.hpp>
  21. #include <boost/geometry/index/detail/algorithms/union_content.hpp>
  22. #include <boost/geometry/index/detail/bounded_view.hpp>
  23. #include <boost/geometry/index/detail/rtree/node/node.hpp>
  24. #include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
  25. #include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
  26. namespace boost { namespace geometry { namespace index {
  27. namespace detail { namespace rtree {
  28. namespace rstar {
  29. template <typename Element, typename Parameters, typename Translator, typename Tag, size_t Corner, size_t AxisIndex>
  30. class element_axis_corner_less
  31. {
  32. typedef typename rtree::element_indexable_type<Element, Translator>::type indexable_type;
  33. typedef typename geometry::point_type<indexable_type>::type point_type;
  34. typedef geometry::model::box<point_type> bounds_type;
  35. typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
  36. typedef index::detail::bounded_view
  37. <
  38. indexable_type, bounds_type, strategy_type
  39. > bounded_view_type;
  40. public:
  41. element_axis_corner_less(Translator const& tr, strategy_type const& strategy)
  42. : m_tr(tr), m_strategy(strategy)
  43. {}
  44. bool operator()(Element const& e1, Element const& e2) const
  45. {
  46. indexable_type const& ind1 = rtree::element_indexable(e1, m_tr);
  47. indexable_type const& ind2 = rtree::element_indexable(e2, m_tr);
  48. return geometry::get<Corner, AxisIndex>(bounded_view_type(ind1, m_strategy))
  49. < geometry::get<Corner, AxisIndex>(bounded_view_type(ind2, m_strategy));
  50. }
  51. private:
  52. Translator const& m_tr;
  53. strategy_type const& m_strategy;
  54. };
  55. template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
  56. class element_axis_corner_less<Element, Parameters, Translator, box_tag, Corner, AxisIndex>
  57. {
  58. typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
  59. public:
  60. element_axis_corner_less(Translator const& tr, strategy_type const&)
  61. : m_tr(tr)
  62. {}
  63. bool operator()(Element const& e1, Element const& e2) const
  64. {
  65. return geometry::get<Corner, AxisIndex>(rtree::element_indexable(e1, m_tr))
  66. < geometry::get<Corner, AxisIndex>(rtree::element_indexable(e2, m_tr));
  67. }
  68. private:
  69. Translator const& m_tr;
  70. };
  71. template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
  72. class element_axis_corner_less<Element, Parameters, Translator, point_tag, Corner, AxisIndex>
  73. {
  74. typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
  75. public:
  76. element_axis_corner_less(Translator const& tr, strategy_type const& )
  77. : m_tr(tr)
  78. {}
  79. bool operator()(Element const& e1, Element const& e2) const
  80. {
  81. return geometry::get<AxisIndex>(rtree::element_indexable(e1, m_tr))
  82. < geometry::get<AxisIndex>(rtree::element_indexable(e2, m_tr));
  83. }
  84. private:
  85. Translator const& m_tr;
  86. };
  87. template <typename Box, size_t Corner, size_t AxisIndex>
  88. struct choose_split_axis_and_index_for_corner
  89. {
  90. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  91. typedef typename index::detail::default_content_result<Box>::type content_type;
  92. template <typename Elements, typename Parameters, typename Translator>
  93. static inline void apply(Elements const& elements,
  94. size_t & choosen_index,
  95. margin_type & sum_of_margins,
  96. content_type & smallest_overlap,
  97. content_type & smallest_content,
  98. Parameters const& parameters,
  99. Translator const& translator)
  100. {
  101. typedef typename Elements::value_type element_type;
  102. typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
  103. typedef typename tag<indexable_type>::type indexable_tag;
  104. BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements");
  105. typename index::detail::strategy_type<Parameters>::type const&
  106. strategy = index::detail::get_strategy(parameters);
  107. // copy elements
  108. Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy)
  109. size_t const index_first = parameters.get_min_elements();
  110. size_t const index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2;
  111. // sort elements
  112. element_axis_corner_less
  113. <
  114. element_type, Parameters, Translator, indexable_tag, Corner, AxisIndex
  115. > elements_less(translator, strategy);
  116. std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
  117. // {
  118. // typename Elements::iterator f = elements_copy.begin() + index_first;
  119. // typename Elements::iterator l = elements_copy.begin() + index_last;
  120. // // NOTE: for stdlibc++ shipped with gcc 4.8.2 std::nth_element is replaced with std::sort anyway
  121. // index::detail::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
  122. // index::detail::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
  123. // std::sort(f, l, elements_less); // MAY THROW, BASIC (copy)
  124. // }
  125. // init outputs
  126. choosen_index = index_first;
  127. sum_of_margins = 0;
  128. smallest_overlap = (std::numeric_limits<content_type>::max)();
  129. smallest_content = (std::numeric_limits<content_type>::max)();
  130. // calculate sum of margins for all distributions
  131. for ( size_t i = index_first ; i < index_last ; ++i )
  132. {
  133. // TODO - awulkiew: may be optimized - box of group 1 may be initialized with
  134. // box of min_elems number of elements and expanded for each iteration by another element
  135. Box box1 = rtree::elements_box<Box>(elements_copy.begin(), elements_copy.begin() + i,
  136. translator, strategy);
  137. Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(),
  138. translator, strategy);
  139. sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2);
  140. content_type ovl = index::detail::intersection_content(box1, box2, strategy);
  141. content_type con = index::detail::content(box1) + index::detail::content(box2);
  142. // TODO - shouldn't here be < instead of <= ?
  143. if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) )
  144. {
  145. choosen_index = i;
  146. smallest_overlap = ovl;
  147. smallest_content = con;
  148. }
  149. }
  150. ::boost::ignore_unused(parameters);
  151. }
  152. };
  153. //template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
  154. //struct choose_split_axis_and_index_for_axis
  155. //{
  156. // BOOST_GEOMETRY_STATIC_ASSERT_FALSE("Not implemented for this Tag type.", ElementIndexableTag);
  157. //};
  158. template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
  159. struct choose_split_axis_and_index_for_axis
  160. {
  161. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  162. typedef typename index::detail::default_content_result<Box>::type content_type;
  163. template <typename Elements, typename Parameters, typename Translator>
  164. static inline void apply(Elements const& elements,
  165. size_t & choosen_corner,
  166. size_t & choosen_index,
  167. margin_type & sum_of_margins,
  168. content_type & smallest_overlap,
  169. content_type & smallest_content,
  170. Parameters const& parameters,
  171. Translator const& translator)
  172. {
  173. size_t index1 = 0;
  174. margin_type som1 = 0;
  175. content_type ovl1 = (std::numeric_limits<content_type>::max)();
  176. content_type con1 = (std::numeric_limits<content_type>::max)();
  177. choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
  178. ::apply(elements, index1,
  179. som1, ovl1, con1,
  180. parameters, translator); // MAY THROW, STRONG
  181. size_t index2 = 0;
  182. margin_type som2 = 0;
  183. content_type ovl2 = (std::numeric_limits<content_type>::max)();
  184. content_type con2 = (std::numeric_limits<content_type>::max)();
  185. choose_split_axis_and_index_for_corner<Box, max_corner, AxisIndex>
  186. ::apply(elements, index2,
  187. som2, ovl2, con2,
  188. parameters, translator); // MAY THROW, STRONG
  189. sum_of_margins = som1 + som2;
  190. if ( ovl1 < ovl2 || (ovl1 == ovl2 && con1 <= con2) )
  191. {
  192. choosen_corner = min_corner;
  193. choosen_index = index1;
  194. smallest_overlap = ovl1;
  195. smallest_content = con1;
  196. }
  197. else
  198. {
  199. choosen_corner = max_corner;
  200. choosen_index = index2;
  201. smallest_overlap = ovl2;
  202. smallest_content = con2;
  203. }
  204. }
  205. };
  206. template <typename Box, size_t AxisIndex>
  207. struct choose_split_axis_and_index_for_axis<Box, AxisIndex, point_tag>
  208. {
  209. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  210. typedef typename index::detail::default_content_result<Box>::type content_type;
  211. template <typename Elements, typename Parameters, typename Translator>
  212. static inline void apply(Elements const& elements,
  213. size_t & choosen_corner,
  214. size_t & choosen_index,
  215. margin_type & sum_of_margins,
  216. content_type & smallest_overlap,
  217. content_type & smallest_content,
  218. Parameters const& parameters,
  219. Translator const& translator)
  220. {
  221. choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
  222. ::apply(elements, choosen_index,
  223. sum_of_margins, smallest_overlap, smallest_content,
  224. parameters, translator); // MAY THROW, STRONG
  225. choosen_corner = min_corner;
  226. }
  227. };
  228. template <typename Box, size_t Dimension>
  229. struct choose_split_axis_and_index
  230. {
  231. BOOST_STATIC_ASSERT(0 < Dimension);
  232. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  233. typedef typename index::detail::default_content_result<Box>::type content_type;
  234. template <typename Elements, typename Parameters, typename Translator>
  235. static inline void apply(Elements const& elements,
  236. size_t & choosen_axis,
  237. size_t & choosen_corner,
  238. size_t & choosen_index,
  239. margin_type & smallest_sum_of_margins,
  240. content_type & smallest_overlap,
  241. content_type & smallest_content,
  242. Parameters const& parameters,
  243. Translator const& translator)
  244. {
  245. typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
  246. choose_split_axis_and_index<Box, Dimension - 1>
  247. ::apply(elements, choosen_axis, choosen_corner, choosen_index,
  248. smallest_sum_of_margins, smallest_overlap, smallest_content,
  249. parameters, translator); // MAY THROW, STRONG
  250. margin_type sum_of_margins = 0;
  251. size_t corner = min_corner;
  252. size_t index = 0;
  253. content_type overlap_val = (std::numeric_limits<content_type>::max)();
  254. content_type content_val = (std::numeric_limits<content_type>::max)();
  255. choose_split_axis_and_index_for_axis<
  256. Box,
  257. Dimension - 1,
  258. typename tag<element_indexable_type>::type
  259. >::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW, STRONG
  260. if ( sum_of_margins < smallest_sum_of_margins )
  261. {
  262. choosen_axis = Dimension - 1;
  263. choosen_corner = corner;
  264. choosen_index = index;
  265. smallest_sum_of_margins = sum_of_margins;
  266. smallest_overlap = overlap_val;
  267. smallest_content = content_val;
  268. }
  269. }
  270. };
  271. template <typename Box>
  272. struct choose_split_axis_and_index<Box, 1>
  273. {
  274. typedef typename index::detail::default_margin_result<Box>::type margin_type;
  275. typedef typename index::detail::default_content_result<Box>::type content_type;
  276. template <typename Elements, typename Parameters, typename Translator>
  277. static inline void apply(Elements const& elements,
  278. size_t & choosen_axis,
  279. size_t & choosen_corner,
  280. size_t & choosen_index,
  281. margin_type & smallest_sum_of_margins,
  282. content_type & smallest_overlap,
  283. content_type & smallest_content,
  284. Parameters const& parameters,
  285. Translator const& translator)
  286. {
  287. typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
  288. choosen_axis = 0;
  289. choose_split_axis_and_index_for_axis<
  290. Box,
  291. 0,
  292. typename tag<element_indexable_type>::type
  293. >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW
  294. }
  295. };
  296. template <size_t Corner, size_t Dimension, size_t I = 0>
  297. struct nth_element
  298. {
  299. BOOST_STATIC_ASSERT(0 < Dimension);
  300. BOOST_STATIC_ASSERT(I < Dimension);
  301. template <typename Elements, typename Parameters, typename Translator>
  302. static inline void apply(Elements & elements, Parameters const& parameters,
  303. const size_t axis, const size_t index, Translator const& tr)
  304. {
  305. //BOOST_GEOMETRY_INDEX_ASSERT(axis < Dimension, "unexpected axis value");
  306. if ( axis != I )
  307. {
  308. nth_element<Corner, Dimension, I + 1>::apply(elements, parameters, axis, index, tr); // MAY THROW, BASIC (copy)
  309. }
  310. else
  311. {
  312. typedef typename Elements::value_type element_type;
  313. typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
  314. typedef typename tag<indexable_type>::type indexable_tag;
  315. typename index::detail::strategy_type<Parameters>::type
  316. strategy = index::detail::get_strategy(parameters);
  317. element_axis_corner_less
  318. <
  319. element_type, Parameters, Translator, indexable_tag, Corner, I
  320. > less(tr, strategy);
  321. index::detail::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
  322. }
  323. }
  324. };
  325. template <size_t Corner, size_t Dimension>
  326. struct nth_element<Corner, Dimension, Dimension>
  327. {
  328. template <typename Elements, typename Parameters, typename Translator>
  329. static inline void apply(Elements & /*elements*/, Parameters const& /*parameters*/,
  330. const size_t /*axis*/, const size_t /*index*/, Translator const& /*tr*/)
  331. {}
  332. };
  333. } // namespace rstar
  334. template <typename MembersHolder>
  335. struct redistribute_elements<MembersHolder, rstar_tag>
  336. {
  337. typedef typename MembersHolder::box_type box_type;
  338. typedef typename MembersHolder::parameters_type parameters_type;
  339. typedef typename MembersHolder::translator_type translator_type;
  340. typedef typename MembersHolder::allocators_type allocators_type;
  341. typedef typename MembersHolder::node node;
  342. typedef typename MembersHolder::internal_node internal_node;
  343. typedef typename MembersHolder::leaf leaf;
  344. static const size_t dimension = geometry::dimension<box_type>::value;
  345. typedef typename index::detail::default_margin_result<box_type>::type margin_type;
  346. typedef typename index::detail::default_content_result<box_type>::type content_type;
  347. template <typename Node>
  348. static inline void apply(
  349. Node & n,
  350. Node & second_node,
  351. box_type & box1,
  352. box_type & box2,
  353. parameters_type const& parameters,
  354. translator_type const& translator,
  355. allocators_type & allocators)
  356. {
  357. typedef typename rtree::elements_type<Node>::type elements_type;
  358. typedef typename elements_type::value_type element_type;
  359. elements_type & elements1 = rtree::elements(n);
  360. elements_type & elements2 = rtree::elements(second_node);
  361. // copy original elements - use in-memory storage (std::allocator)
  362. // TODO: move if noexcept
  363. typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
  364. container_type;
  365. container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG
  366. container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG
  367. size_t split_axis = 0;
  368. size_t split_corner = 0;
  369. size_t split_index = parameters.get_min_elements();
  370. margin_type smallest_sum_of_margins = (std::numeric_limits<margin_type>::max)();
  371. content_type smallest_overlap = (std::numeric_limits<content_type>::max)();
  372. content_type smallest_content = (std::numeric_limits<content_type>::max)();
  373. // NOTE: this function internally copies passed elements
  374. // why not pass mutable elements and use the same container for all axes/corners
  375. // and again, the same below calling partial_sort/nth_element
  376. // It would be even possible to not re-sort/find nth_element if the axis/corner
  377. // was found for the last sorting - last combination of axis/corner
  378. rstar::choose_split_axis_and_index<box_type, dimension>
  379. ::apply(elements_copy,
  380. split_axis, split_corner, split_index,
  381. smallest_sum_of_margins, smallest_overlap, smallest_content,
  382. parameters, translator); // MAY THROW, STRONG
  383. // TODO: awulkiew - get rid of following static_casts?
  384. BOOST_GEOMETRY_INDEX_ASSERT(split_axis < dimension, "unexpected value");
  385. BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast<size_t>(min_corner) || split_corner == static_cast<size_t>(max_corner), "unexpected value");
  386. BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value");
  387. // TODO: consider using nth_element
  388. if ( split_corner == static_cast<size_t>(min_corner) )
  389. {
  390. rstar::nth_element<min_corner, dimension>
  391. ::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
  392. }
  393. else
  394. {
  395. rstar::nth_element<max_corner, dimension>
  396. ::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
  397. }
  398. BOOST_TRY
  399. {
  400. typename index::detail::strategy_type<parameters_type>::type const&
  401. strategy = index::detail::get_strategy(parameters);
  402. // copy elements to nodes
  403. elements1.assign(elements_copy.begin(), elements_copy.begin() + split_index); // MAY THROW, BASIC
  404. elements2.assign(elements_copy.begin() + split_index, elements_copy.end()); // MAY THROW, BASIC
  405. // calculate boxes
  406. box1 = rtree::elements_box<box_type>(elements1.begin(), elements1.end(),
  407. translator, strategy);
  408. box2 = rtree::elements_box<box_type>(elements2.begin(), elements2.end(),
  409. translator, strategy);
  410. }
  411. BOOST_CATCH(...)
  412. {
  413. //elements_copy.clear();
  414. elements1.clear();
  415. elements2.clear();
  416. rtree::destroy_elements<MembersHolder>::apply(elements_backup, allocators);
  417. //elements_backup.clear();
  418. BOOST_RETHROW // RETHROW, BASIC
  419. }
  420. BOOST_CATCH_END
  421. }
  422. };
  423. }} // namespace detail::rtree
  424. }}} // namespace boost::geometry::index
  425. #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP