• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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