redistribute_elements.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Boost.Geometry Index
  2. //
  3. // R-tree quadratic split algorithm implementation
  4. //
  5. // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
  6. //
  7. // This file was modified by Oracle on 2019.
  8. // Modifications copyright (c) 2019 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_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
  15. #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
  16. #include <algorithm>
  17. #include <boost/core/ignore_unused.hpp>
  18. #include <boost/geometry/index/detail/algorithms/content.hpp>
  19. #include <boost/geometry/index/detail/algorithms/union_content.hpp>
  20. #include <boost/geometry/index/detail/bounded_view.hpp>
  21. #include <boost/geometry/index/detail/rtree/node/node.hpp>
  22. #include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
  23. #include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
  24. namespace boost { namespace geometry { namespace index {
  25. namespace detail { namespace rtree {
  26. namespace quadratic {
  27. template <typename Box, typename Elements, typename Parameters, typename Translator>
  28. inline void pick_seeds(Elements const& elements,
  29. Parameters const& parameters,
  30. Translator const& tr,
  31. size_t & seed1,
  32. size_t & seed2)
  33. {
  34. typedef typename Elements::value_type element_type;
  35. typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
  36. typedef Box box_type;
  37. typedef typename index::detail::default_content_result<box_type>::type content_type;
  38. typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
  39. typedef index::detail::bounded_view
  40. <
  41. indexable_type, box_type, strategy_type
  42. > bounded_indexable_view;
  43. const size_t elements_count = parameters.get_max_elements() + 1;
  44. BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "wrong number of elements");
  45. BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
  46. strategy_type const& strategy = index::detail::get_strategy(parameters);
  47. content_type greatest_free_content = 0;
  48. seed1 = 0;
  49. seed2 = 1;
  50. for ( size_t i = 0 ; i < elements_count - 1 ; ++i )
  51. {
  52. for ( size_t j = i + 1 ; j < elements_count ; ++j )
  53. {
  54. indexable_type const& ind1 = rtree::element_indexable(elements[i], tr);
  55. indexable_type const& ind2 = rtree::element_indexable(elements[j], tr);
  56. box_type enlarged_box;
  57. index::detail::bounds(ind1, enlarged_box, strategy);
  58. index::detail::expand(enlarged_box, ind2, strategy);
  59. bounded_indexable_view bounded_ind1(ind1, strategy);
  60. bounded_indexable_view bounded_ind2(ind2, strategy);
  61. content_type free_content = ( index::detail::content(enlarged_box)
  62. - index::detail::content(bounded_ind1) )
  63. - index::detail::content(bounded_ind2);
  64. if ( greatest_free_content < free_content )
  65. {
  66. greatest_free_content = free_content;
  67. seed1 = i;
  68. seed2 = j;
  69. }
  70. }
  71. }
  72. ::boost::ignore_unused(parameters);
  73. }
  74. } // namespace quadratic
  75. template <typename MembersHolder>
  76. struct redistribute_elements<MembersHolder, quadratic_tag>
  77. {
  78. typedef typename MembersHolder::box_type box_type;
  79. typedef typename MembersHolder::parameters_type parameters_type;
  80. typedef typename MembersHolder::translator_type translator_type;
  81. typedef typename MembersHolder::allocators_type allocators_type;
  82. typedef typename MembersHolder::node node;
  83. typedef typename MembersHolder::internal_node internal_node;
  84. typedef typename MembersHolder::leaf leaf;
  85. typedef typename index::detail::default_content_result<box_type>::type content_type;
  86. template <typename Node>
  87. static inline void apply(Node & n,
  88. Node & second_node,
  89. box_type & box1,
  90. box_type & box2,
  91. parameters_type const& parameters,
  92. translator_type const& translator,
  93. allocators_type & allocators)
  94. {
  95. typedef typename rtree::elements_type<Node>::type elements_type;
  96. typedef typename elements_type::value_type element_type;
  97. typedef typename rtree::element_indexable_type<element_type, translator_type>::type indexable_type;
  98. elements_type & elements1 = rtree::elements(n);
  99. elements_type & elements2 = rtree::elements(second_node);
  100. BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == parameters.get_max_elements() + 1, "unexpected elements number");
  101. // copy original elements - use in-memory storage (std::allocator)
  102. // TODO: move if noexcept
  103. typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
  104. container_type;
  105. container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
  106. container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
  107. // calculate initial seeds
  108. size_t seed1 = 0;
  109. size_t seed2 = 0;
  110. quadratic::pick_seeds<box_type>(elements_copy, parameters, translator, seed1, seed2);
  111. // prepare nodes' elements containers
  112. elements1.clear();
  113. BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "second node's elements container should be empty");
  114. BOOST_TRY
  115. {
  116. typename index::detail::strategy_type<parameters_type>::type const&
  117. strategy = index::detail::get_strategy(parameters);
  118. // add seeds
  119. elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
  120. elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
  121. // calculate boxes
  122. detail::bounds(rtree::element_indexable(elements_copy[seed1], translator),
  123. box1, strategy);
  124. detail::bounds(rtree::element_indexable(elements_copy[seed2], translator),
  125. box2, strategy);
  126. // remove seeds
  127. if (seed1 < seed2)
  128. {
  129. rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
  130. elements_copy.pop_back();
  131. rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
  132. elements_copy.pop_back();
  133. }
  134. else
  135. {
  136. rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
  137. elements_copy.pop_back();
  138. rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
  139. elements_copy.pop_back();
  140. }
  141. // initialize areas
  142. content_type content1 = index::detail::content(box1);
  143. content_type content2 = index::detail::content(box2);
  144. size_t remaining = elements_copy.size();
  145. // redistribute the rest of the elements
  146. while ( !elements_copy.empty() )
  147. {
  148. typename container_type::reverse_iterator el_it = elements_copy.rbegin();
  149. bool insert_into_group1 = false;
  150. size_t elements1_count = elements1.size();
  151. size_t elements2_count = elements2.size();
  152. // if there is small number of elements left and the number of elements in node is lesser than min_elems
  153. // just insert them to this node
  154. if ( elements1_count + remaining <= parameters.get_min_elements() )
  155. {
  156. insert_into_group1 = true;
  157. }
  158. else if ( elements2_count + remaining <= parameters.get_min_elements() )
  159. {
  160. insert_into_group1 = false;
  161. }
  162. // insert the best element
  163. else
  164. {
  165. // find element with minimum groups areas increses differences
  166. content_type content_increase1 = 0;
  167. content_type content_increase2 = 0;
  168. el_it = pick_next(elements_copy.rbegin(), elements_copy.rend(),
  169. box1, box2, content1, content2,
  170. translator, strategy,
  171. content_increase1, content_increase2);
  172. if ( content_increase1 < content_increase2 ||
  173. ( content_increase1 == content_increase2 && ( content1 < content2 ||
  174. ( content1 == content2 && elements1_count <= elements2_count ) )
  175. ) )
  176. {
  177. insert_into_group1 = true;
  178. }
  179. else
  180. {
  181. insert_into_group1 = false;
  182. }
  183. }
  184. // move element to the choosen group
  185. element_type const& elem = *el_it;
  186. indexable_type const& indexable = rtree::element_indexable(elem, translator);
  187. if ( insert_into_group1 )
  188. {
  189. elements1.push_back(elem); // MAY THROW, STRONG (copy)
  190. index::detail::expand(box1, indexable, strategy);
  191. content1 = index::detail::content(box1);
  192. }
  193. else
  194. {
  195. elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
  196. index::detail::expand(box2, indexable, strategy);
  197. content2 = index::detail::content(box2);
  198. }
  199. BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements");
  200. typename container_type::iterator el_it_base = el_it.base();
  201. rtree::move_from_back(elements_copy, --el_it_base); // MAY THROW, STRONG (copy)
  202. elements_copy.pop_back();
  203. BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
  204. --remaining;
  205. }
  206. }
  207. BOOST_CATCH(...)
  208. {
  209. //elements_copy.clear();
  210. elements1.clear();
  211. elements2.clear();
  212. rtree::destroy_elements<MembersHolder>::apply(elements_backup, allocators);
  213. //elements_backup.clear();
  214. BOOST_RETHROW // RETHROW, BASIC
  215. }
  216. BOOST_CATCH_END
  217. }
  218. // TODO: awulkiew - change following function to static member of the pick_next class?
  219. template <typename It>
  220. static inline It pick_next(It first, It last,
  221. box_type const& box1, box_type const& box2,
  222. content_type const& content1, content_type const& content2,
  223. translator_type const& translator,
  224. typename index::detail::strategy_type<parameters_type>::type const& strategy,
  225. content_type & out_content_increase1, content_type & out_content_increase2)
  226. {
  227. typedef typename boost::iterator_value<It>::type element_type;
  228. typedef typename rtree::element_indexable_type<element_type, translator_type>::type indexable_type;
  229. content_type greatest_content_incrase_diff = 0;
  230. It out_it = first;
  231. out_content_increase1 = 0;
  232. out_content_increase2 = 0;
  233. // find element with greatest difference between increased group's boxes areas
  234. for ( It el_it = first ; el_it != last ; ++el_it )
  235. {
  236. indexable_type const& indexable = rtree::element_indexable(*el_it, translator);
  237. // calculate enlarged boxes and areas
  238. box_type enlarged_box1(box1);
  239. box_type enlarged_box2(box2);
  240. index::detail::expand(enlarged_box1, indexable, strategy);
  241. index::detail::expand(enlarged_box2, indexable, strategy);
  242. content_type enlarged_content1 = index::detail::content(enlarged_box1);
  243. content_type enlarged_content2 = index::detail::content(enlarged_box2);
  244. content_type content_incrase1 = (enlarged_content1 - content1);
  245. content_type content_incrase2 = (enlarged_content2 - content2);
  246. content_type content_incrase_diff = content_incrase1 < content_incrase2 ?
  247. content_incrase2 - content_incrase1 : content_incrase1 - content_incrase2;
  248. if ( greatest_content_incrase_diff < content_incrase_diff )
  249. {
  250. greatest_content_incrase_diff = content_incrase_diff;
  251. out_it = el_it;
  252. out_content_increase1 = content_incrase1;
  253. out_content_increase2 = content_incrase2;
  254. }
  255. }
  256. return out_it;
  257. }
  258. };
  259. }} // namespace detail::rtree
  260. }}} // namespace boost::geometry::index
  261. #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP