implementation.qbk 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. [/
  2. Copyright (c) 2008-2009 Joachim Faulhaber
  3. Distributed under the Boost Software License, Version 1.0.
  4. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt)
  6. ]
  7. [section Implementation]
  8. The [link boost_icl.interface previous section] gave an overview over the interface
  9. of the *icl* outlining
  10. [link boost_icl.interface.class_templates class templates],
  11. [link boost_icl.interface.associated_types associated types]
  12. and polymorphic
  13. [link boost_icl.interface.function_synopsis functions and operators].
  14. In preparation to the
  15. [link boost_icl.function_reference next section],
  16. that describes the *icl's* polymorphic functions in
  17. more detail together with ['*complexity characteristics*],
  18. this section summarizes some general information on
  19. implementation and performance.
  20. [h5 STL based implementation]
  21. The *implementation* of the *icl's* containers is based on
  22. [*std::set] and [*std::map]. So the underlying data structure of
  23. interval containers is a red black tree of intervals or
  24. interval value pairs.
  25. The element containers __icl_set__ and __icl_map__ are wrapper
  26. classes of `std::set` and `std::map`.
  27. Interval containers are then using __icl_sets__ of intervals
  28. or __icl_maps__ of interval value pairs as implementing
  29. containers.
  30. So all the ['*complexity characteristics*] of icl containers
  31. are based on and limited by the ['*red-black tree implementation*]
  32. of the underlying std::AssociativeContainers.
  33. [section Iterative size]
  34. Throughout the documentation on complexity,
  35. big /O/ expressions like __On__ or __Omlgn__ refer to container sizes
  36. /n/ and /m/. In this documentation these sizes ['*do not*] denote
  37. to the familiar `size` function that returns
  38. the ['*number of elements*] of a container. Because for an interval container
  39. ``
  40. interval_set<int> mono;
  41. mono += interval<int>::closed(1,5); // {[1 ... 5]}
  42. mono.size() == 5; // true, 5 elements
  43. mono.interval_count() == 1; // true, only one interval
  44. ``
  45. it's size and the number of contained intervals is usually different.
  46. To refer uniformly to a /size/ that matters for iteration, which is
  47. the decisive kind of size concerning algorithmic behavior there is a function
  48. ``
  49. bool T::iterative_size()const; // Number of entities that can be iterated over.
  50. ``
  51. for all element and interval containers of the icl. So for
  52. complexity statements throughout the icl's documentation
  53. the sizes will be `iterative_sizes` and big /O/ expressions like
  54. __Omlgn__ will refer to sizes
  55. ``
  56. n = y.iterative_size();
  57. m = x.iterative_size();
  58. ``
  59. for containers `y` and `x`.
  60. Note that ``iterative_size`` refers to the primary entities,
  61. that we can iterate over. For interval containers these
  62. are intervals or segments. ``Itervative_size`` never refers
  63. to element iteration for interval containers.
  64. [endsect][/ Iterative size]
  65. [section Complexity]
  66. [h4 Complexity of element containers]
  67. Since ['element containers] __icl_set__ and __icl_map__ are only extensions of
  68. stl::set and stl::map, their complexity characteristics are
  69. accordingly. So their major operations insertion (addition),
  70. deletion and search are all using logarithmic time.
  71. [h4 Complexity of interval containers]
  72. The operations on ['interval containers] behave differently
  73. due to the fact that intervals unlike elements can overlap
  74. any number of other intervals in a container. As long as
  75. intervals are relatively small or just singleton, interval
  76. containers behave like containers of elements.
  77. For large intervals however time consumption of operations
  78. on interval containers may be worse, because most or all
  79. intervals of a container may have to be visited.
  80. As an example, time complexity of __biLAddition__ on
  81. interval containers is briefly discussed.
  82. More information on ['*complexity characteristics*]
  83. of *icl's* functions is contained in section
  84. [link boost_icl.function_reference Function Reference]
  85. [h5 Time Complexity of Addition]
  86. The next table
  87. gives the time complexities for the overloaded
  88. `operator +=` on interval containers.
  89. The instance types of `T` are given as column headers.
  90. Instances of type parameter `P` are denoted in
  91. the second column.
  92. The third column contains the specific kind of complexity statement.
  93. If column three is empty ['*worst case*] complexity is given
  94. in the related row.
  95. [table Time Complexity of Addition:
  96. [[] [`P`] [][interval\nset][separate\ninterval\nset][split\ninterval\nset][interval\nmap][split\ninterval\nmap]]
  97. [/ 1operation 2granul. 3case 4itvset 5se_itvset 6sp_itvset 7itv_map 8sp_itvmap]
  98. [[`T& operator +=(T& object, const P& addend)`] [`T::element_type`] [] [__Olgn__] [__Olgn__] [__Olgn__] [__Olgn__] [__Olgn__] ]
  99. [[] [`T::segment_type`] [best case] [__Olgn__] [__Olgn__] [__Olgn__] [__Olgn__] [__Olgn__] ]
  100. [[] [] [worst case] [__On__] [__On__] [__On__] [__On__] [__On__] ]
  101. [[] [] [amortized] [__Olgn__] [__Olgn__] [] [] [] ]
  102. [[] [`interval_sets`] [] [__Omlgnpm__] [__Omlgnpm__] [__Omlgnpm__] [ ] [ ] ]
  103. [[] [`interval_maps`] [] [ ] [ ] [ ] [__Omlgnpm__] [__Omlgnpm__] ]
  104. ]
  105. Adding an /element/ or
  106. /element value pair/ is always done in /logarithmic time/,
  107. where /n/ is the number of intervals in the interval container.
  108. The same row of complexities applies to the insertion
  109. of a /segment/ (an interval or an interval value pair)
  110. in the ['*best case*], where the inserted segment does overlap
  111. with only a ['*small*] number of intervals in the container.
  112. In the ['*worst case*], where the inserted segment overlaps with
  113. all intervals in the container, the algorithms
  114. iterate over all the overlapped segments.
  115. Using inplace manipulations of segments and
  116. hinted inserts, it is possible to perform
  117. all necessary operations on each iteration step
  118. in /constant time/.
  119. This results in ['*linear worst case time*] complexity for
  120. segment addition for all interval containers.
  121. After performing
  122. a worst case addition
  123. for an __itv_set__ or a __sep_itv_sets__
  124. adding an interval that overlaps /n/
  125. intervals, we
  126. need /n/ non overlapping additions of
  127. /logarithmic time/ before we can launch
  128. another __On__ worst case addition.
  129. So we have only a ['*logarithmic amortized
  130. time*] for the addition of an interval or interval value pair.
  131. For the addition of ['*interval containers*] complexity is __Omlgnpm__.
  132. So for the ['*worst case*], where the container sizes /n/ and /m/
  133. are equal and both containers cover the same ranges,
  134. the complexity of container addition is ['*loglinear*].
  135. For other cases, that occur frequently in real world applications
  136. performance can be much better.
  137. If the added container `operand` is much smaller than
  138. `object` and the intervals in `operand` are relatively
  139. small, performance can be /logarithmic/.
  140. If /m/ is small compared with /n/ and intervals in `operand`
  141. are large, performance tends to be /linear/.
  142. [endsect][/ Complexity]
  143. [section Inplace and infix operators]
  144. For the major operations /addition, subtraction, intersection/
  145. of *icl* containers and for /symmetric difference/
  146. inplace `operator`s `+= |=, -=, &=` and `^=`
  147. are provided.
  148. For every ['*inplace*] operator
  149. ``
  150. T& operator o= (T& object, const P& operand)
  151. ``
  152. the *icl* provides corresponding ['*infix*] operators.
  153. ``
  154. T operator o (T object, const P& operand){ return object o= operand; }
  155. T operator o (const P& operand, T object){ return object o= operand; }
  156. ``
  157. From this implementation of the infix `operator o`
  158. the compiler will hopefully use return value optimization
  159. [@http://en.wikipedia.org/wiki/Return_value_optimization (RVO)]
  160. creating no temporary object and performing one copy of
  161. the first argument `object`.
  162. [caution
  163. Compared to the /inplace/ `operator o=` every use of an
  164. /infix/ `operator o` requires ['*one extra copy*]
  165. of the first argument `object` that passes a container.]
  166. Use infix operators only, if
  167. * efficiency is not crucial, e.g. the containers copied are small.
  168. * a concise and short notation is more important than efficiency in your context.
  169. * you need the result of operator `o=` as a copy anyway.
  170. [h5 Time Complexity of infix `operators o`]
  171. The time complexity of all infix operators of the *icl*
  172. is biased by the extra copy of the `object` argument.
  173. So all infix `operators o` are at least
  174. /linear/ in `n = object.iterative_size()`.
  175. Taking this into account, the complexities of all
  176. infix operators can be determined
  177. from the corresponding inplace `operators o=` they depend
  178. on.
  179. [endsect][/ Inplace and infix operators]
  180. [endsect][/ Implementation]