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