PPL  1.2
Parma_Polyhedra_Library::CO_Tree Class Reference

A cache-oblivious binary search tree of pairs. More...

#include <CO_Tree_defs.hh>

Collaboration diagram for Parma_Polyhedra_Library::CO_Tree:

Classes

class  const_iterator
 A const iterator on the tree elements, ordered by key. More...
 
class  iterator
 An iterator on the tree elements, ordered by key. More...
 
class  tree_iterator
 

Public Types

typedef Coefficient data_type
 The type of the data elements associated with keys. More...
 
typedef Coefficient_traits::const_reference data_type_const_reference
 

Public Member Functions

 CO_Tree ()
 Constructs an empty tree. More...
 
 CO_Tree (const CO_Tree &y)
 The copy constructor. More...
 
template<typename Iterator >
 CO_Tree (Iterator i, dimension_type n)
 A constructor from a sequence of n elements. More...
 
CO_Treeoperator= (const CO_Tree &y)
 The assignment operator. More...
 
void clear ()
 Removes all elements from the tree. More...
 
 ~CO_Tree ()
 The destructor. More...
 
bool empty () const
 Returns true if the tree has no elements. More...
 
dimension_type size () const
 Returns the number of elements stored in the tree. More...
 
void dump_tree () const
 Dumps the tree to stdout, for debugging purposes. More...
 
dimension_type external_memory_in_bytes () const
 Returns the size in bytes of the memory managed by *this. More...
 
iterator insert (dimension_type key)
 Inserts an element in the tree. More...
 
iterator insert (dimension_type key, data_type_const_reference data)
 Inserts an element in the tree. More...
 
iterator insert (iterator itr, dimension_type key)
 Inserts an element in the tree. More...
 
iterator insert (iterator itr, dimension_type key, data_type_const_reference data)
 Inserts an element in the tree. More...
 
iterator erase (dimension_type key)
 Erases the element with key key from the tree. More...
 
iterator erase (iterator itr)
 Erases the element pointed to by itr from the tree. More...
 
void erase_element_and_shift_left (dimension_type key)
 Removes the element with key key (if it exists) and decrements by 1 all elements' keys that were greater than key. More...
 
void increase_keys_from (dimension_type key, dimension_type n)
 Adds n to all keys greater than or equal to key. More...
 
void fast_shift (dimension_type i, iterator itr)
 
void m_swap (CO_Tree &x)
 Swaps x with *this. More...
 
iterator begin ()
 Returns an iterator that points at the first element. More...
 
const iteratorend ()
 Returns an iterator that points after the last element. More...
 
const_iterator begin () const
 Equivalent to cbegin(). More...
 
const const_iteratorend () const
 Equivalent to cend(). More...
 
const_iterator cbegin () const
 Returns a const_iterator that points at the first element. More...
 
const const_iteratorcend () const
 Returns a const_iterator that points after the last element. More...
 
iterator bisect (dimension_type key)
 Searches an element with key key using bisection. More...
 
const_iterator bisect (dimension_type key) const
 Searches an element with key key using bisection. More...
 
iterator bisect_in (iterator first, iterator last, dimension_type key)
 Searches an element with key key in [first, last] using bisection. More...
 
const_iterator bisect_in (const_iterator first, const_iterator last, dimension_type key) const
 Searches an element with key key in [first, last] using bisection. More...
 
iterator bisect_near (iterator hint, dimension_type key)
 Searches an element with key key near hint. More...
 
const_iterator bisect_near (const_iterator hint, dimension_type key) const
 Searches an element with key key near hint. More...
 

Static Public Member Functions

static dimension_type max_size ()
 Returns the size() of the largest possible CO_Tree. More...
 

Private Types

typedef unsigned height_t
 This is used for node heights and depths in the tree. More...
 

Private Member Functions

 PPL_COMPILE_TIME_CHECK (C_Integer< height_t >::max >=sizeof_to_bits(sizeof(dimension_type)),"height_t is too small to store depths.")
 
dimension_type dfs_index (const_iterator itr) const
 
dimension_type dfs_index (iterator itr) const
 
dimension_type bisect_in (dimension_type first, dimension_type last, dimension_type key) const
 Searches an element with key key in [first, last] using bisection. More...
 
dimension_type bisect_near (dimension_type hint, dimension_type key) const
 Searches an element with key key near hint. More...
 
tree_iterator insert_precise (dimension_type key, data_type_const_reference data, tree_iterator itr)
 Inserts an element in the tree. More...
 
tree_iterator insert_precise_aux (dimension_type key, data_type_const_reference data, tree_iterator itr)
 Helper for insert_precise. More...
 
void insert_in_empty_tree (dimension_type key, data_type_const_reference data)
 Inserts an element in the tree. More...
 
iterator erase (tree_iterator itr)
 Erases from the tree the element pointed to by itr . More...
 
void init (dimension_type n)
 Initializes a tree with reserved size at least n . More...
 
void destroy ()
 Deallocates the tree's dynamic arrays. More...
 
bool structure_OK () const
 Checks the internal invariants, but not the densities. More...
 
bool OK () const
 Checks the internal invariants. More...
 
void rebuild_bigger_tree ()
 Increases the tree's reserved size. More...
 
void rebuild_smaller_tree ()
 Decreases the tree's reserved size. More...
 
void refresh_cached_iterators ()
 Re-initializes the cached iterators. More...
 
tree_iterator rebalance (tree_iterator itr, dimension_type key, data_type_const_reference value)
 Rebalances the tree. More...
 
dimension_type compact_elements_in_the_rightmost_end (dimension_type last_in_subtree, dimension_type subtree_size, dimension_type key, data_type_const_reference value, bool add_element)
 Moves all elements of a subtree to the rightmost end. More...
 
void redistribute_elements_in_subtree (dimension_type root_index, dimension_type subtree_size, dimension_type last_used, dimension_type key, data_type_const_reference value, bool add_element)
 Redistributes the elements in the subtree rooted at root_index. More...
 
void move_data_from (CO_Tree &tree)
 Moves all data in the tree tree into *this. More...
 
void copy_data_from (const CO_Tree &tree)
 Copies all data in the tree tree into *this. More...
 

Static Private Member Functions

static unsigned integer_log2 (dimension_type n)
 Returns the floor of the base-2 logarithm of n . More...
 
static bool is_less_than_ratio (dimension_type numer, dimension_type denom, dimension_type ratio)
 Compares the fractions numer/denom with ratio/100. More...
 
static bool is_greater_than_ratio (dimension_type numer, dimension_type denom, dimension_type ratio)
 Compares the fractions numer/denom with ratio/100. More...
 
static void dump_subtree (tree_iterator itr)
 Dumps the subtree rooted at itr to stdout, for debugging purposes. More...
 
static dimension_type count_used_in_subtree (tree_iterator itr)
 Counts the number of used elements in the subtree rooted at itr. More...
 
static void move_data_element (data_type &to, data_type &from)
 Moves the value of from in to . More...
 

Private Attributes

iterator cached_end
 The iterator returned by end(). More...
 
const_iterator cached_const_end
 The iterator returned by the const version of end(). More...
 
height_t max_depth
 The depth of the leaves in the complete tree. More...
 
dimension_typeindexes
 The vector that contains the keys in the tree. More...
 
std::allocator< data_typedata_allocator
 The allocator used to allocate/deallocate data. More...
 
data_typedata
 The vector that contains the data of the keys in the tree. More...
 
dimension_type reserved_size
 The number of nodes in the complete tree. More...
 
dimension_type size_
 The number of values stored in the tree. More...
 

Static Private Attributes

static const dimension_type max_density_percent = 91
 The maximum density of used nodes. More...
 
static const dimension_type min_density_percent = 38
 The minimum density of used nodes. More...
 
static const dimension_type min_leaf_density_percent = 1
 The minimum density at the leaves' depth. More...
 
static const dimension_type unused_index = C_Integer<dimension_type>::max
 An index used as a marker for unused nodes in the tree. More...
 

Related Functions

(Note that these are not member functions.)

void swap (CO_Tree &x, CO_Tree &y)
 Swaps x with y. More...
 

Detailed Description

A cache-oblivious binary search tree of pairs.

This class implements a binary search tree with keys of dimension_type type and data of Coefficient type, laid out in a dynamically-sized array.

The array-based layout saves calls to new/delete (to insert $n$ elements only $O(\log n)$ allocations are performed) and, more importantly, is much more cache-friendly than a standard (pointer-based) tree, because the elements are stored sequentially in memory (leaving some holes to allow fast insertion of new elements). The downside of this representation is that all iterators are invalidated when an element is added or removed, because the array could have been enlarged or shrunk. This is partially addressed by providing references to internal end iterators that are updated when needed.

B-trees are cache-friendly too, but the cache size is fixed (usually at compile-time). This raises two problems: firstly the cache size must be known in advance and those data structures do not perform well with other cache sizes and, secondly, even if the cache size is known, the optimizations target only one level of cache. This kind of data structures are called cache aware. This implementation, instead, is cache oblivious: it performs well with every cache size, and thus exploits all of the available caches.

Assuming n is the number of elements in the tree and B is the number of (dimension_type, Coefficient) pairs that fit in a cache line, the time and cache misses complexities are the following:

  • Insertions/Queries/Deletions: $O(\log^2 n)$ time, $O(\log \frac{n}{B}))$ cache misses.
  • Tree traversal from begin() to end(), using an iterator: $O(n)$ time, $O(\frac{n}{B})$ cache misses.
  • Queries with a hint: $O(\log k)$ time and $O(\log \frac{k}{B})$ cache misses, where k is the distance between the given iterator and the searched element (or the position where it would have been).

The binary search tree is embedded in a (slightly bigger) complete tree, that is enlarged and shrunk when needed. The complete tree is laid out in an in-order DFS layout in two arrays: one for the keys and one for the associated data. The indexes and values are stored in different arrays to reduce cache-misses during key queries.

The tree can store up to $(-(dimension_type)1)/100$ elements. This limit allows faster density computations, but can be removed if needed.

Definition at line 103 of file CO_Tree_defs.hh.

Member Typedef Documentation

The type of the data elements associated with keys.

If this is changed, occurrences of Coefficient_zero() in the CO_Tree implementation have to be replaced with constants of the correct type.

Definition at line 148 of file CO_Tree_defs.hh.

typedef Coefficient_traits::const_reference Parma_Polyhedra_Library::CO_Tree::data_type_const_reference

Definition at line 149 of file CO_Tree_defs.hh.

This is used for node heights and depths in the tree.

Definition at line 107 of file CO_Tree_defs.hh.

Constructor & Destructor Documentation

Parma_Polyhedra_Library::CO_Tree::CO_Tree ( )
inline

Constructs an empty tree.

This constructor takes $O(1)$ time.

Definition at line 50 of file CO_Tree_inlines.hh.

References init(), and OK().

Referenced by clear().

50  {
51  init(0);
52  PPL_ASSERT(OK());
53 }
void init(dimension_type n)
Initializes a tree with reserved size at least n .
Definition: CO_Tree.cc:607
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
Parma_Polyhedra_Library::CO_Tree::CO_Tree ( const CO_Tree y)
inline

The copy constructor.

Parameters
yThe tree that will be copied.

This constructor takes $O(n)$ time.

Definition at line 56 of file CO_Tree_inlines.hh.

References copy_data_from(), data_allocator, init(), OK(), and reserved_size.

56  {
57  PPL_ASSERT(y.OK());
58  data_allocator = y.data_allocator;
59  init(y.reserved_size);
60  copy_data_from(y);
61 }
void init(dimension_type n)
Initializes a tree with reserved size at least n .
Definition: CO_Tree.cc:607
std::allocator< data_type > data_allocator
The allocator used to allocate/deallocate data.
void copy_data_from(const CO_Tree &tree)
Copies all data in the tree tree into *this.
Definition: CO_Tree.cc:1246
template<typename Iterator >
Parma_Polyhedra_Library::CO_Tree::CO_Tree ( Iterator  i,
dimension_type  n 
)

A constructor from a sequence of n elements.

Parameters
iAn iterator that points to the first element of the sequence.
nThe number of elements in the [i, i_end) sequence.

i must be an input iterator on a sequence of data_type elements, sorted by index. Objects of Iterator type must have an index() method that returns the index with which the element pointed to by the iterator must be inserted.

This constructor takes $O(n)$ time, so it is more efficient than the construction of an empty tree followed by n insertions, that would take $O(n*\log^2 n)$ time.

Definition at line 30 of file CO_Tree_templates.hh.

References Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_left_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_parent(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_right_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), init(), integer_log2(), is_greater_than_ratio(), max_density_percent, OK(), reserved_size, size_, sizeof_to_bits, and unused_index.

30  {
31 
32  if (n == 0) {
33  init(0);
34  PPL_ASSERT(OK());
35  return;
36  }
37 
38  const dimension_type new_max_depth = integer_log2(n) + 1;
39  reserved_size = (static_cast<dimension_type>(1) << new_max_depth) - 1;
40 
42  && reserved_size != 3) {
44  }
45 
47 
48  tree_iterator root(*this);
49 
50  // This is static and with static allocation, to improve performance.
51  // sizeof_to_bits(sizeof(dimension_type)) is the maximum k such that
52  // 2^k-1 is a dimension_type, so it is the maximum tree height.
53  // For each node level, the stack may contain up to 4 elements: two elements
54  // with operation 0, one element with operation 2 and one element
55  // with operation 3. An additional element with operation 1 can be at the
56  // top of the tree.
57  static std::pair<dimension_type, signed char>
58  stack[4U * sizeof_to_bits(sizeof(dimension_type)) + 1U];
59 
60  dimension_type stack_first_empty = 0;
61 
62  // A pair (n, operation) in the stack means:
63  //
64  // * Go to the parent, if operation is 0.
65  // * Go to the left child, then fill the current tree with n elements, if
66  // operation is 1.
67  // * Go to the right child, then fill the current tree with n elements, if
68  // operation is 2.
69  // * Fill the current tree with n elements, if operation is 3.
70 
71  stack[0].first = n;
72  stack[0].second = 3;
73  ++stack_first_empty;
74 
75  while (stack_first_empty != 0) {
76 
77  // Implement
78  //
79  // <CODE>
80  // top_n = stack.top().first;
81  // top_operation = stack.top().second;
82  // </CODE>
83  const dimension_type top_n = stack[stack_first_empty - 1].first;
84  const signed char top_operation = stack[stack_first_empty - 1].second;
85 
86  switch (top_operation) {
87 
88  case 0:
89  root.get_parent();
90  --stack_first_empty;
91  continue;
92 
93  case 1:
94  root.get_left_child();
95  break;
96 
97  case 2:
98  root.get_right_child();
99  break;
100 #ifndef NDEBUG
101  case 3:
102  break;
103 
104  default:
105  // We should not be here
106  PPL_UNREACHABLE;
107 #endif
108  }
109 
110  // We now visit the current tree
111 
112  if (top_n == 0) {
113  --stack_first_empty;
114  }
115  else {
116  if (top_n == 1) {
117  PPL_ASSERT(root.index() == unused_index);
118  root.index() = i.index();
119  new(&(*root)) data_type(*i);
120  ++i;
121  --stack_first_empty;
122  }
123  else {
124  PPL_ASSERT(stack_first_empty + 3 < sizeof(stack)/sizeof(stack[0]));
125 
126  const dimension_type half = (top_n + 1) / 2;
127  stack[stack_first_empty - 1].second = 0;
128  stack[stack_first_empty ] = std::make_pair(top_n - half, 2);
129  stack[stack_first_empty + 1] = std::make_pair(1, 3);
130  stack[stack_first_empty + 2].second = 0;
131  stack[stack_first_empty + 3] = std::make_pair(half - 1, 1);
132  stack_first_empty += 4;
133  }
134  }
135  }
136  size_ = n;
137  PPL_ASSERT(OK());
138 }
Coefficient data_type
The type of the data elements associated with keys.
void init(dimension_type n)
Initializes a tree with reserved size at least n .
Definition: CO_Tree.cc:607
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
static unsigned integer_log2(dimension_type n)
Returns the floor of the base-2 logarithm of n .
Definition: CO_Tree.cc:787
static bool is_greater_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
static const dimension_type max_density_percent
The maximum density of used nodes.
dimension_type reserved_size
The number of nodes in the complete tree.
#define sizeof_to_bits(size)
Definition: compiler.hh:80
dimension_type size_
The number of values stored in the tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
Parma_Polyhedra_Library::CO_Tree::~CO_Tree ( )
inline

The destructor.

This destructor takes $O(n)$ time.

Definition at line 80 of file CO_Tree_inlines.hh.

References destroy().

80  {
81 
82  destroy();
83 }
void destroy()
Deallocates the tree's dynamic arrays.
Definition: CO_Tree.cc:649

Member Function Documentation

CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::begin ( )
inline

Returns an iterator that points at the first element.

This method takes $O(1)$ time.

Definition at line 196 of file CO_Tree_inlines.hh.

Referenced by Parma_Polyhedra_Library::Sparse_Row::begin(), bisect(), and external_memory_in_bytes().

196  {
197  return iterator(*this);
198 }
CO_Tree::const_iterator Parma_Polyhedra_Library::CO_Tree::begin ( ) const
inline

Equivalent to cbegin().

Definition at line 206 of file CO_Tree_inlines.hh.

206  {
207  return const_iterator(*this);
208 }
CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::bisect ( dimension_type  key)
inline

Searches an element with key key using bisection.

Parameters
keyThe key that will be searched for.

If the element is found, an iterator pointing to that element is returned; otherwise, the returned iterator refers to the immediately preceding or succeeding value. If the tree is empty, end() is returned.

This method takes $O(\log n)$ time.

Definition at line 226 of file CO_Tree_inlines.hh.

References begin(), bisect_in(), empty(), and end().

Referenced by bisect_near(), Parma_Polyhedra_Library::Sparse_Row::find(), and Parma_Polyhedra_Library::Sparse_Row::lower_bound().

226  {
227  if (empty()) {
228  return end();
229  }
230  iterator last = end();
231  --last;
232  return bisect_in(begin(), last, key);
233 }
iterator begin()
Returns an iterator that points at the first element.
const iterator & end()
Returns an iterator that points after the last element.
iterator bisect_in(iterator first, iterator last, dimension_type key)
Searches an element with key key in [first, last] using bisection.
bool empty() const
Returns true if the tree has no elements.
CO_Tree::const_iterator Parma_Polyhedra_Library::CO_Tree::bisect ( dimension_type  key) const
inline

Searches an element with key key using bisection.

Parameters
keyThe key that will be searched for.

If the element is found, an iterator pointing to that element is returned; otherwise, the returned iterator refers to the immediately preceding or succeeding value. If the tree is empty, end() is returned.

This method takes $O(\log n)$ time.

Definition at line 236 of file CO_Tree_inlines.hh.

References begin(), bisect_in(), empty(), and end().

236  {
237  if (empty()) {
238  return end();
239  }
240  const_iterator last = end();
241  --last;
242  return bisect_in(begin(), last, key);
243 }
iterator begin()
Returns an iterator that points at the first element.
const iterator & end()
Returns an iterator that points after the last element.
iterator bisect_in(iterator first, iterator last, dimension_type key)
Searches an element with key key in [first, last] using bisection.
bool empty() const
Returns true if the tree has no elements.
CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::bisect_in ( iterator  first,
iterator  last,
dimension_type  key 
)
inline

Searches an element with key key in [first, last] using bisection.

Parameters
firstAn iterator pointing to the first element in the range. It must not be end().
lastAn iterator pointing to the last element in the range. Note that this is included in the search. It must not be end().
keyThe key that will be searched for.
Returns
If the specified key is found, an iterator pointing to that element is returned; otherwise, the returned iterator refers to the immediately preceding or succeeding value. If the tree is empty, end() is returned.

This method takes $O(\log(last - first + 1))$ time.

Definition at line 246 of file CO_Tree_inlines.hh.

References dfs_index(), and end().

Referenced by bisect(), and bisect_in().

246  {
247  PPL_ASSERT(first != end());
248  PPL_ASSERT(last != end());
249  const dimension_type index
250  = bisect_in(dfs_index(first), dfs_index(last), key);
251  return iterator(*this, index);
252 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
const iterator & end()
Returns an iterator that points after the last element.
iterator bisect_in(iterator first, iterator last, dimension_type key)
Searches an element with key key in [first, last] using bisection.
dimension_type dfs_index(const_iterator itr) const
CO_Tree::const_iterator Parma_Polyhedra_Library::CO_Tree::bisect_in ( const_iterator  first,
const_iterator  last,
dimension_type  key 
) const
inline

Searches an element with key key in [first, last] using bisection.

Parameters
firstAn iterator pointing to the first element in the range. It must not be end().
lastAn iterator pointing to the last element in the range. Note that this is included in the search. It must not be end().
keyThe key that will be searched for.
Returns
If the specified key is found, an iterator pointing to that element is returned; otherwise, the returned iterator refers to the immediately preceding or succeeding value. If the tree is empty, end() is returned.

This method takes $O(\log(last - first + 1))$ time.

Definition at line 255 of file CO_Tree_inlines.hh.

References bisect_in(), dfs_index(), and end().

256  {
257  PPL_ASSERT(first != end());
258  PPL_ASSERT(last != end());
259  const dimension_type index
260  = bisect_in(dfs_index(first), dfs_index(last), key);
261  return const_iterator(*this, index);
262 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
const iterator & end()
Returns an iterator that points after the last element.
iterator bisect_in(iterator first, iterator last, dimension_type key)
Searches an element with key key in [first, last] using bisection.
dimension_type dfs_index(const_iterator itr) const
PPL::dimension_type Parma_Polyhedra_Library::CO_Tree::bisect_in ( dimension_type  first,
dimension_type  last,
dimension_type  key 
) const
private

Searches an element with key key in [first, last] using bisection.

Parameters
firstThe index of the first element in the range. It must be the index of an element with a value.
lastThe index of the last element in the range. It must be the index of an element with a value. Note that this is included in the search.
keyThe key that will be searched for.
Returns
If the element is found, the index of that element is returned; otherwise, the returned index refers to the immediately preceding or succeeding value.

This method takes $O(\log n)$ time.

Definition at line 215 of file CO_Tree.cc.

216  {
217  PPL_ASSERT(first != 0);
218  PPL_ASSERT(last <= reserved_size);
219  PPL_ASSERT(first <= last);
220  PPL_ASSERT(indexes[first] != unused_index);
221  PPL_ASSERT(indexes[last] != unused_index);
222 
223  while (first < last) {
224  dimension_type half = (first + last) / 2;
225  dimension_type new_half = half;
226 
227  while (indexes[new_half] == unused_index) {
228  ++new_half;
229  }
230 
231  if (indexes[new_half] == key) {
232  return new_half;
233  }
234 
235  if (indexes[new_half] > key) {
236 
237  while (indexes[half] == unused_index) {
238  --half;
239  }
240 
241  last = half;
242 
243  }
244  else {
245 
246  ++new_half;
247  while (indexes[new_half] == unused_index) {
248  ++new_half;
249  }
250 
251  first = new_half;
252  }
253  }
254 
255  // It is important that last is returned instead of first, because first
256  // may have increased beyond last, even beyond the original value of last
257  // at the beginning of this method.
258  return last;
259 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type * indexes
The vector that contains the keys in the tree.
dimension_type reserved_size
The number of nodes in the complete tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::bisect_near ( iterator  hint,
dimension_type  key 
)
inline

Searches an element with key key near hint.

Parameters
hintAn iterator used as a hint.
keyThe key that will be searched for.

If the element is found, the returned iterator points to that element; otherwise, it points to the immediately preceding or succeeding value. If the tree is empty, end() is returned.

The value of itr does not affect the result of this method, as long it is a valid iterator for this tree. itr may even be end().

This method takes $O(\log n)$ time. If the distance between the returned position and hint is $O(1)$ it takes $O(1)$ time.

Definition at line 265 of file CO_Tree_inlines.hh.

References bisect(), dfs_index(), and end().

Referenced by bisect_near(), Parma_Polyhedra_Library::Sparse_Row::find(), and Parma_Polyhedra_Library::Sparse_Row::lower_bound().

265  {
266  if (hint == end()) {
267  return bisect(key);
268  }
269  const dimension_type index
270  = bisect_near(dfs_index(hint), key);
271  return iterator(*this, index);
272 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
const iterator & end()
Returns an iterator that points after the last element.
iterator bisect(dimension_type key)
Searches an element with key key using bisection.
dimension_type dfs_index(const_iterator itr) const
iterator bisect_near(iterator hint, dimension_type key)
Searches an element with key key near hint.
CO_Tree::const_iterator Parma_Polyhedra_Library::CO_Tree::bisect_near ( const_iterator  hint,
dimension_type  key 
) const
inline

Searches an element with key key near hint.

Parameters
hintAn iterator used as a hint.
keyThe key that will be searched for.

If the element is found, the returned iterator points to that element; otherwise, it points to the immediately preceding or succeeding value. If the tree is empty, end() is returned.

The value of itr does not affect the result of this method, as long it is a valid iterator for this tree. itr may even be end().

This method takes $O(\log n)$ time. If the distance between the returned position and hint is $O(1)$ it takes $O(1)$ time.

Definition at line 275 of file CO_Tree_inlines.hh.

References bisect(), bisect_near(), dfs_index(), and end().

275  {
276  if (hint == end()) {
277  return bisect(key);
278  }
279  const dimension_type index = bisect_near(dfs_index(hint), key);
280  return const_iterator(*this, index);
281 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
const iterator & end()
Returns an iterator that points after the last element.
iterator bisect(dimension_type key)
Searches an element with key key using bisection.
dimension_type dfs_index(const_iterator itr) const
iterator bisect_near(iterator hint, dimension_type key)
Searches an element with key key near hint.
PPL::dimension_type Parma_Polyhedra_Library::CO_Tree::bisect_near ( dimension_type  hint,
dimension_type  key 
) const
private

Searches an element with key key near hint.

Parameters
hintAn index used as a hint. It must be the index of an element with a value.
keyThe key that will be searched for.
Returns
If the element is found, the index of that element is returned; otherwise, the returned index refers to the immediately preceding or succeeding value.

This uses a binary progression and then a bisection, so this method is $O(\log n)$, and it is $O(1)$ if the distance between the returned position and hint is $O(1)$.

This method takes $O(\log n)$ time. If the distance between the returned position and hint is $O(1)$ it takes $O(1)$ time.

Definition at line 262 of file CO_Tree.cc.

References Parma_Polyhedra_Library::swap().

262  {
263  PPL_ASSERT(hint != 0);
264  PPL_ASSERT(hint <= reserved_size);
265  PPL_ASSERT(indexes[hint] != unused_index);
266 
267  if (indexes[hint] == key) {
268  return hint;
269  }
270 
271  dimension_type new_hint;
272  dimension_type offset = 1;
273 
274  if (indexes[hint] > key) {
275  // The searched element is before `hint'.
276 
277  while (true) {
278 
279  if (hint <= offset) {
280  // The searched element is in (0,hint).
281  new_hint = hint;
282  hint = 1;
283  // The searched element is in [hint,new_hint).
284  while (indexes[hint] == unused_index) {
285  ++hint;
286  }
287 
288  if (indexes[hint] >= key) {
289  return hint;
290  }
291  // The searched element is in (hint,new_hint) and both indexes point
292  // to valid elements.
293  break;
294  }
295  else {
296  new_hint = hint - offset;
297  }
298 
299  PPL_ASSERT(new_hint > 0);
300  PPL_ASSERT(new_hint <= reserved_size);
301 
302  // Find the element at `new_hint' (or the first after it).
303  while (indexes[new_hint] == unused_index) {
304  ++new_hint;
305  }
306 
307  PPL_ASSERT(new_hint <= hint);
308 
309  if (indexes[new_hint] == key) {
310  return new_hint;
311  }
312  else
313  if (indexes[new_hint] < key) {
314  // The searched element is in (new_hint,hint)
315  using std::swap;
316  swap(hint, new_hint);
317  // The searched element is now in (hint,new_hint).
318  break;
319  }
320 
321  hint = new_hint;
322  offset *= 2;
323  }
324 
325  }
326  else {
327  // The searched element is after `hint'.
328  while (true) {
329 
330  if (hint + offset > reserved_size) {
331  // The searched element is in (hint,reserved_size+1).
332  new_hint = reserved_size;
333  // The searched element is in (hint,new_hint].
334  while (indexes[new_hint] == unused_index) {
335  --new_hint;
336  }
337  if (indexes[new_hint] <= key) {
338  return new_hint;
339  }
340  // The searched element is in (hint,new_hint) and both indexes point
341  // to valid elements.
342  break;
343  }
344  else {
345  new_hint = hint + offset;
346  }
347 
348  PPL_ASSERT(new_hint > 0);
349  PPL_ASSERT(new_hint <= reserved_size);
350 
351  // Find the element at `new_hint' (or the first after it).
352  while (indexes[new_hint] == unused_index) {
353  --new_hint;
354  }
355 
356  PPL_ASSERT(hint <= new_hint);
357 
358  if (indexes[new_hint] == key) {
359  return new_hint;
360  }
361  else {
362  if (indexes[new_hint] > key) {
363  // The searched element is in (hint,new_hint).
364  break;
365  }
366  }
367  hint = new_hint;
368  offset *= 2;
369  }
370  }
371  // The searched element is in (hint,new_hint).
372  PPL_ASSERT(hint > 0);
373  PPL_ASSERT(hint < new_hint);
374  PPL_ASSERT(new_hint <= reserved_size);
375  PPL_ASSERT(indexes[hint] != unused_index);
376  PPL_ASSERT(indexes[new_hint] != unused_index);
377 
378  ++hint;
379  while (indexes[hint] == unused_index) {
380  ++hint;
381  }
382 
383  if (hint == new_hint) {
384  return hint;
385  }
386 
387  --new_hint;
388 
389  while (indexes[new_hint] == unused_index) {
390  --new_hint;
391  }
392 
393  PPL_ASSERT(hint <= new_hint);
394  PPL_ASSERT(indexes[hint] != unused_index);
395  PPL_ASSERT(indexes[new_hint] != unused_index);
396 
397  return bisect_in(hint, new_hint, key);
398 }
void swap(CO_Tree &x, CO_Tree &y)
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type * indexes
The vector that contains the keys in the tree.
iterator bisect_in(iterator first, iterator last, dimension_type key)
Searches an element with key key in [first, last] using bisection.
dimension_type reserved_size
The number of nodes in the complete tree.
void swap(CO_Tree &x, CO_Tree &y)
Swaps x with y.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
CO_Tree::const_iterator Parma_Polyhedra_Library::CO_Tree::cbegin ( ) const
inline

Returns a const_iterator that points at the first element.

This method takes $O(1)$ time.

Definition at line 216 of file CO_Tree_inlines.hh.

Referenced by Parma_Polyhedra_Library::Sparse_Row::begin(), and Parma_Polyhedra_Library::Sparse_Row::cbegin().

216  {
217  return const_iterator(*this);
218 }
const CO_Tree::const_iterator & Parma_Polyhedra_Library::CO_Tree::cend ( ) const
inline

Returns a const_iterator that points after the last element.

This method always returns a reference to the same internal iterator, that is updated at each operation that modifies the structure. Client code can keep a const reference to that iterator instead of keep updating a local iterator.

This method takes $O(1)$ time.

Definition at line 221 of file CO_Tree_inlines.hh.

References cached_const_end.

Referenced by Parma_Polyhedra_Library::Sparse_Row::cend(), and Parma_Polyhedra_Library::Sparse_Row::end().

221  {
222  return cached_const_end;
223 }
const_iterator cached_const_end
The iterator returned by the const version of end().
void Parma_Polyhedra_Library::CO_Tree::clear ( )
inline

Removes all elements from the tree.

This method takes $O(n)$ time.

Definition at line 75 of file CO_Tree_inlines.hh.

References CO_Tree().

Referenced by Parma_Polyhedra_Library::Sparse_Row::clear().

75  {
76  *this = CO_Tree();
77 }
CO_Tree()
Constructs an empty tree.
PPL::dimension_type Parma_Polyhedra_Library::CO_Tree::compact_elements_in_the_rightmost_end ( dimension_type  last_in_subtree,
dimension_type  subtree_size,
dimension_type  key,
data_type_const_reference  value,
bool  add_element 
)
private

Moves all elements of a subtree to the rightmost end.

Returns
The index of the rightmost unused node in the subtree after the process.
Parameters
last_in_subtreeIt is the index of the last element in the subtree.
subtree_sizeIt is the number of valid elements in the subtree. It must be greater than zero.
keyThe key that may be added to the tree if add_element is true.
valueThe value that may be added to the tree if add_element is true.
add_elementIf it is true, it tries to add an element with key key and value value in the process (but it may not).

This method takes $O(k)$ time, where k is subtree_size.

Definition at line 951 of file CO_Tree.cc.

955  {
956 
957  PPL_ASSERT(subtree_size != 0);
958 
959  PPL_ASSERT(subtree_size != 1 || !add_element);
960 
961  dimension_type* last_index_in_subtree = &(indexes[last_in_subtree]);
962  data_type* last_data_in_subtree = &(data[last_in_subtree]);
963 
964  dimension_type* first_unused_index = last_index_in_subtree;
965  data_type* first_unused_data = last_data_in_subtree;
966 
967  while (*last_index_in_subtree == unused_index) {
968  --last_index_in_subtree;
969  --last_data_in_subtree;
970  }
971 
972  // From now on, last_index_in_subtree and last_data_in_subtree point to the
973  // rightmost node with a value in the subtree. first_unused_index and
974  // first_unused_data point to the rightmost unused node in the subtree.
975 
976  if (add_element) {
977  while (subtree_size != 0) {
978  --subtree_size;
979  if (last_index_in_subtree == indexes || key > *last_index_in_subtree) {
980  if (last_index_in_subtree == indexes
981  || last_index_in_subtree != first_unused_index) {
982  PPL_ASSERT(first_unused_index != indexes);
983  PPL_ASSERT(*first_unused_index == unused_index);
984  new(first_unused_data) data_type(value);
985  // Set the index only if the construction was successful.
986  *first_unused_index = key;
987  --first_unused_index;
988  --first_unused_data;
989  }
990  break;
991  }
992  else {
993  if (last_index_in_subtree != first_unused_index) {
994  PPL_ASSERT(first_unused_index != indexes);
995  PPL_ASSERT(last_index_in_subtree != indexes);
996  PPL_ASSERT(*first_unused_index == unused_index);
997  *first_unused_index = *last_index_in_subtree;
998  *last_index_in_subtree = unused_index;
999  move_data_element(*first_unused_data, *last_data_in_subtree);
1000  }
1001  --last_index_in_subtree;
1002  --last_data_in_subtree;
1003  while (*last_index_in_subtree == unused_index) {
1004  --last_index_in_subtree;
1005  --last_data_in_subtree;
1006  }
1007  --first_unused_index;
1008  --first_unused_data;
1009  }
1010  }
1011  }
1012  while (subtree_size != 0) {
1013  if (last_index_in_subtree != first_unused_index) {
1014  PPL_ASSERT(first_unused_index != indexes);
1015  PPL_ASSERT(last_index_in_subtree != indexes);
1016  PPL_ASSERT(*first_unused_index == unused_index);
1017  *first_unused_index = *last_index_in_subtree;
1018  *last_index_in_subtree = unused_index;
1019  move_data_element(*first_unused_data, *last_data_in_subtree);
1020  }
1021  --last_index_in_subtree;
1022  --last_data_in_subtree;
1023  while (*last_index_in_subtree == unused_index) {
1024  --last_index_in_subtree;
1025  --last_data_in_subtree;
1026  }
1027  --first_unused_index;
1028  --first_unused_data;
1029  --subtree_size;
1030  }
1031 
1032  const std::ptrdiff_t distance = first_unused_index - indexes;
1033  PPL_ASSERT(distance >= 0);
1034  return static_cast<dimension_type>(distance);
1035 }
Coefficient data_type
The type of the data elements associated with keys.
size_t dimension_type
An unsigned integral type for representing space dimensions.
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
Coefficient value
Definition: PIP_Tree.cc:618
static void move_data_element(data_type &to, data_type &from)
Moves the value of from in to .
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::copy_data_from ( const CO_Tree tree)
private

Copies all data in the tree tree into *this.

Parameters
treeThe tree from which the element will be copied into *this.

this must be empty and must have the same reserved size of tree. this->OK() may return false before this method is called, but this->structure_OK() must return true.

This method takes $O(n)$ time.

Definition at line 1246 of file CO_Tree.cc.

References data, indexes, reserved_size, and size_.

Referenced by CO_Tree(), and operator=().

1246  {
1247  PPL_ASSERT(size_ == 0);
1248  PPL_ASSERT(reserved_size == x.reserved_size);
1249  PPL_ASSERT(structure_OK());
1250 
1251  if (x.size_ == 0) {
1252  PPL_ASSERT(OK());
1253  return;
1254  }
1255 
1256  dimension_type i;
1257  try {
1258  for (i = x.reserved_size; i > 0; --i) {
1259  if (x.indexes[i] != unused_index) {
1260  indexes[i] = x.indexes[i];
1261  new(&(data[i])) data_type(x.data[i]);
1262  }
1263  else {
1264  PPL_ASSERT(indexes[i] == unused_index);
1265  }
1266  }
1267  } catch (...) {
1268  // The (used) data elements in (i,x.reserved_size] have been constructed
1269  // successfully.
1270  // The constructor of data[i] has thrown an exception, so data[i] has not
1271  // been constructed.
1272 
1273  // 1. Destroy the data elements that have been constructed successfully.
1274  for (dimension_type j = x.reserved_size; j > i; --j) {
1275  if (indexes[j] != unused_index) {
1276  data[j].~data_type();
1277  }
1278  }
1279 
1280  // 2. Deallocate index[] and data[]
1281  delete[] indexes;
1282  data_allocator.deallocate(data, reserved_size + 1);
1283 
1284  // 3. Set the tree to an empty tree and rethrow exception.
1285  init(0);
1286  throw;
1287  }
1288 
1289  size_ = x.size_;
1290  PPL_ASSERT(OK());
1291 }
Coefficient data_type
The type of the data elements associated with keys.
void init(dimension_type n)
Initializes a tree with reserved size at least n .
Definition: CO_Tree.cc:607
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
std::allocator< data_type > data_allocator
The allocator used to allocate/deallocate data.
dimension_type reserved_size
The number of nodes in the complete tree.
dimension_type size_
The number of values stored in the tree.
bool structure_OK() const
Checks the internal invariants, but not the densities.
Definition: CO_Tree.cc:664
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
PPL::dimension_type Parma_Polyhedra_Library::CO_Tree::count_used_in_subtree ( tree_iterator  itr)
staticprivate

Counts the number of used elements in the subtree rooted at itr.

Parameters
itrAn iterator pointing to the root of the desired subtree.

This method takes $O(k)$ time, where k is the number of elements in the subtree.

Definition at line 1294 of file CO_Tree.cc.

References Parma_Polyhedra_Library::CO_Tree::tree_iterator::dfs_index(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_offset(), indexes, and Parma_Polyhedra_Library::CO_Tree::tree_iterator::tree.

1294  {
1295  dimension_type n = 0;
1296 
1297  const dimension_type k = itr.get_offset();
1298  const dimension_type root_index = itr.dfs_index();
1299 
1300  // The complete subtree rooted at itr has 2*k - 1 nodes.
1301 
1302  PPL_ASSERT(root_index > (k - 1));
1303 
1304  const dimension_type* current_index
1305  = &(itr.tree.indexes[root_index - (k - 1)]);
1306 
1307  for (dimension_type j = 2*k - 1; j > 0; --j, ++current_index) {
1308  if (*current_index != unused_index) {
1309  ++n;
1310  }
1311  }
1312 
1313  return n;
1314 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::destroy ( )
private

Deallocates the tree's dynamic arrays.

After this call, the tree fields are uninitialized, so init() must be called again before using the tree.

This method takes $O(n)$ time.

Definition at line 649 of file CO_Tree.cc.

Referenced by operator=(), and ~CO_Tree().

649  {
650 
651  if (reserved_size != 0) {
652  for (dimension_type i = 1; i <= reserved_size; ++i) {
653  if (indexes[i] != unused_index) {
654  data[i].~data_type();
655  }
656  }
657 
658  delete[] indexes;
659  data_allocator.deallocate(data, reserved_size + 1);
660  }
661 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
std::allocator< data_type > data_allocator
The allocator used to allocate/deallocate data.
dimension_type reserved_size
The number of nodes in the complete tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
dimension_type Parma_Polyhedra_Library::CO_Tree::dfs_index ( const_iterator  itr) const
inlineprivate

Returns the index of the current element in the DFS layout of the complete tree.

Returns
the index of the current element in the DFS layout of the complete tree.
Parameters
itrthe iterator that points to the desired element.

Definition at line 32 of file CO_Tree_inlines.hh.

References Parma_Polyhedra_Library::CO_Tree::const_iterator::current_index, indexes, and reserved_size.

Referenced by bisect_in(), bisect_near(), and fast_shift().

32  {
33  PPL_ASSERT(itr.current_index != 0);
34  PPL_ASSERT(itr.current_index >= indexes + 1);
35  PPL_ASSERT(itr.current_index <= indexes + reserved_size);
36  const std::ptrdiff_t index = itr.current_index - indexes;
37  return static_cast<dimension_type>(index);
38 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type * indexes
The vector that contains the keys in the tree.
dimension_type reserved_size
The number of nodes in the complete tree.
dimension_type Parma_Polyhedra_Library::CO_Tree::dfs_index ( iterator  itr) const
inlineprivate

Returns the index of the current element in the DFS layout of the complete tree.

Returns
the index of the current element in the DFS layout of the complete tree.
Parameters
itrthe iterator that points to the desired element.

Definition at line 41 of file CO_Tree_inlines.hh.

References Parma_Polyhedra_Library::CO_Tree::iterator::current_index, indexes, and reserved_size.

41  {
42  PPL_ASSERT(itr.current_index != 0);
43  PPL_ASSERT(itr.current_index >= indexes + 1);
44  PPL_ASSERT(itr.current_index <= indexes + reserved_size);
45  const std::ptrdiff_t index = itr.current_index - indexes;
46  return static_cast<dimension_type>(index);
47 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type * indexes
The vector that contains the keys in the tree.
dimension_type reserved_size
The number of nodes in the complete tree.
void Parma_Polyhedra_Library::CO_Tree::dump_subtree ( tree_iterator  itr)
staticprivate

Dumps the subtree rooted at itr to stdout, for debugging purposes.

Parameters
itrA tree_iterator pointing to the root of the desired subtree.

Definition at line 798 of file CO_Tree.cc.

References Parma_Polyhedra_Library::CO_Tree::tree_iterator::depth(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_left_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_parent(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_right_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), and Parma_Polyhedra_Library::CO_Tree::tree_iterator::is_leaf().

Referenced by dump_tree().

798  {
799  if (!itr.is_leaf()) {
800  itr.get_left_child();
801  dump_subtree(itr);
802  itr.get_parent();
803  }
804  std::cout << "At depth: " << itr.depth();
805  if (itr.index() == unused_index) {
806  std::cout << " (no data)" << std::endl;
807  }
808  else {
809  std::cout << " pair (" << itr.index() << "," << *itr << ")" << std::endl;
810  }
811  if (!itr.is_leaf()) {
812  itr.get_right_child();
813  dump_subtree(itr);
814  itr.get_parent();
815  }
816 }
static void dump_subtree(tree_iterator itr)
Dumps the subtree rooted at itr to stdout, for debugging purposes.
Definition: CO_Tree.cc:798
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::dump_tree ( ) const
inline

Dumps the tree to stdout, for debugging purposes.

Definition at line 101 of file CO_Tree_inlines.hh.

References dump_subtree(), and empty().

101  {
102  if (empty()) {
103  std::cout << "(empty tree)" << std::endl;
104  }
105  else {
106  dump_subtree(tree_iterator(*const_cast<CO_Tree*>(this)));
107  }
108 }
static void dump_subtree(tree_iterator itr)
Dumps the subtree rooted at itr to stdout, for debugging purposes.
Definition: CO_Tree.cc:798
bool empty() const
Returns true if the tree has no elements.
bool Parma_Polyhedra_Library::CO_Tree::empty ( ) const
inline

Returns true if the tree has no elements.

This method takes $O(1)$ time.

Definition at line 86 of file CO_Tree_inlines.hh.

References size_.

Referenced by bisect(), Parma_Polyhedra_Library::CO_Tree::const_iterator::const_iterator(), dump_tree(), erase(), Parma_Polyhedra_Library::Sparse_Row::get(), insert(), insert_in_empty_tree(), and Parma_Polyhedra_Library::CO_Tree::iterator::iterator().

86  {
87  return size_ == 0;
88 }
dimension_type size_
The number of values stored in the tree.
const CO_Tree::iterator & Parma_Polyhedra_Library::CO_Tree::end ( )
inline

Returns an iterator that points after the last element.

This method always returns a reference to the same internal iterator, that is updated at each operation that modifies the structure. Client code can keep a const reference to that iterator instead of keep updating a local iterator.

This method takes $O(1)$ time.

Definition at line 201 of file CO_Tree_inlines.hh.

References cached_end.

Referenced by bisect(), bisect_in(), bisect_near(), Parma_Polyhedra_Library::Sparse_Row::end(), erase(), external_memory_in_bytes(), and fast_shift().

201  {
202  return cached_end;
203 }
iterator cached_end
The iterator returned by end().
const CO_Tree::const_iterator & Parma_Polyhedra_Library::CO_Tree::end ( ) const
inline

Equivalent to cend().

Definition at line 211 of file CO_Tree_inlines.hh.

References cached_const_end.

211  {
212  return cached_const_end;
213 }
const_iterator cached_const_end
The iterator returned by the const version of end().
CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::erase ( dimension_type  key)
inline

Erases the element with key key from the tree.

This operation invalidates existing iterators.

Returns
an iterator to the next element (or end() if there are no elements with key greater than key ).
Parameters
keyThe key of the element that will be erased from the tree.

This method takes $O(\log n)$ time if the element already exists, and $O(\log^2 n)$ amortized time otherwise.

Definition at line 143 of file CO_Tree_inlines.hh.

References empty(), end(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::go_down_searching_key(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), and unused_index.

Referenced by erase(), and Parma_Polyhedra_Library::Sparse_Row::reset().

143  {
144  PPL_ASSERT(key != unused_index);
145 
146  if (empty()) {
147  return end();
148  }
149 
150  tree_iterator itr(*this);
151  itr.go_down_searching_key(key);
152 
153  if (itr.index() == key) {
154  return erase(itr);
155  }
156 
157  iterator result(itr);
158  if (result.index() < key) {
159  ++result;
160  }
161 
162  PPL_ASSERT(result == end() || result.index() > key);
163 #ifndef NDEBUG
164  iterator last = end();
165  --last;
166  PPL_ASSERT((result == end()) == (last.index() < key));
167 #endif
168 
169  return result;
170 }
const iterator & end()
Returns an iterator that points after the last element.
bool empty() const
Returns true if the tree has no elements.
iterator erase(dimension_type key)
Erases the element with key key from the tree.
dimension_type index() const
Returns the index of the element pointed to by *this.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::erase ( iterator  itr)
inline

Erases the element pointed to by itr from the tree.

This operation invalidates existing iterators.

Returns
an iterator to the next element (or end() if there are no elements with key greater than key ).
Parameters
itrAn iterator pointing to the element that will be erased from the tree.

This method takes $O(\log n)$ time if the element already exists, and $O(\log^2 n)$ amortized time otherwise.

Definition at line 173 of file CO_Tree_inlines.hh.

References end(), and erase().

173  {
174  PPL_ASSERT(itr != end());
175  return erase(tree_iterator(itr, *this));
176 }
const iterator & end()
Returns an iterator that points after the last element.
iterator erase(dimension_type key)
Erases the element with key key from the tree.
PPL::CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::erase ( tree_iterator  itr)
private

Erases from the tree the element pointed to by itr .

This operation invalidates existing iterators.

Returns
An iterator to the next element (or end() if there are no elements with key greater than key ).
Parameters
itrAn iterator pointing to the element that will be erased.

This method takes $O(\log^2 n)$ amortized time.

Definition at line 503 of file CO_Tree.cc.

References Parma_Polyhedra_Library::Coefficient_zero(), Parma_Polyhedra_Library::Implementation::BD_Shapes::empty, Parma_Polyhedra_Library::CO_Tree::tree_iterator::follow_left_children_with_value(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::follow_right_children_with_value(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_left_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_offset(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_parent(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_right_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_root(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::go_down_searching_key(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::is_leaf(), and Parma_Polyhedra_Library::swap().

503  {
504  PPL_ASSERT(itr.index() != unused_index);
505 
506  PPL_ASSERT(size_ != 0);
507 
508  if (size_ == 1) {
509  // Deleting the only element of this tree, now it is empty.
510  clear();
511  return end();
512  }
513 
517 
518  const dimension_type key = itr.index();
519 
522 
524  itr.get_root();
525  itr.go_down_searching_key(key);
526 
527  PPL_ASSERT(itr.index() == key);
528  }
529 
530 #ifndef NDEBUG
531  if (size_ > 1) {
532  PPL_ASSERT(!is_less_than_ratio(size_ - 1, reserved_size,
536  }
537 #endif
538 
539  const dimension_type deleted_key = itr.index();
540  tree_iterator deleted_node = itr;
541  (*itr).~data_type();
542  while (true) {
543  dimension_type& current_key = itr.index();
544  data_type& current_data = *itr;
545  if (itr.is_leaf()) {
546  break;
547  }
548  itr.get_left_child();
549  if (itr.index() != unused_index) {
550  // The left child has a value.
551  itr.follow_right_children_with_value();
552  }
553  else {
554  // The left child has not a value, try the right child.
555  itr.get_parent();
556  itr.get_right_child();
557  if (itr.index() != unused_index) {
558  // The right child has a value.
559  itr.follow_left_children_with_value();
560  }
561  else {
562  // The right child has not a value, too.
563  itr.get_parent();
564  break;
565  }
566  }
567  using std::swap;
568  swap(current_key, itr.index());
569  move_data_element(current_data, *itr);
570  }
571 
572  PPL_ASSERT(itr.index() != unused_index);
573  itr.index() = unused_index;
574  --size_;
575 
576  PPL_ASSERT(OK());
577 
578  itr = rebalance(itr, 0, Coefficient_zero());
579 
580  if (itr.get_offset() < deleted_node.get_offset()) {
581  // deleted_node is an ancestor of itr
582  itr = deleted_node;
583  }
584 
585  itr.go_down_searching_key(deleted_key);
586 
587  iterator result(itr);
588 
589  if (result.index() < deleted_key) {
590  ++result;
591  }
592 
593  PPL_ASSERT(OK());
594  PPL_ASSERT(result == end() || result.index() > deleted_key);
595 #ifndef NDEBUG
596  if (!empty()) {
597  iterator last = end();
598  --last;
599  PPL_ASSERT((result == end()) == (last.index() < deleted_key));
600  }
601 #endif
602 
603  return result;
604 }
void swap(CO_Tree &x, CO_Tree &y)
Coefficient data_type
The type of the data elements associated with keys.
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
static bool is_greater_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
static const dimension_type max_density_percent
The maximum density of used nodes.
const iterator & end()
Returns an iterator that points after the last element.
tree_iterator rebalance(tree_iterator itr, dimension_type key, data_type_const_reference value)
Rebalances the tree.
Definition: CO_Tree.cc:868
bool empty() const
Returns true if the tree has no elements.
dimension_type reserved_size
The number of nodes in the complete tree.
static const dimension_type min_density_percent
The minimum density of used nodes.
static bool is_less_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
void clear()
Removes all elements from the tree.
void swap(CO_Tree &x, CO_Tree &y)
Swaps x with y.
static void move_data_element(data_type &to, data_type &from)
Moves the value of from in to .
dimension_type size_
The number of values stored in the tree.
dimension_type index() const
Returns the index of the element pointed to by *this.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void rebuild_smaller_tree()
Decreases the tree's reserved size.
void Parma_Polyhedra_Library::CO_Tree::erase_element_and_shift_left ( dimension_type  key)

Removes the element with key key (if it exists) and decrements by 1 all elements' keys that were greater than key.

Parameters
keyThe key of the element that will be erased from the tree.

This operation invalidates existing iterators.

This method takes $O(k+\log^2 n)$ expected time, where k is the number of elements with keys greater than key.

Definition at line 179 of file CO_Tree.cc.

Referenced by Parma_Polyhedra_Library::Sparse_Row::delete_element_and_shift().

179  {
180  iterator itr = erase(key);
181  if (itr == end()) {
182  return;
183  }
184  const dimension_type i = dfs_index(itr);
185  dimension_type* p = indexes + i;
186  const dimension_type* const p_end = indexes + (reserved_size + 1);
187  for ( ; p != p_end; ++p) {
188  if (*p != unused_index) {
189  --(*p);
190  }
191  }
192  PPL_ASSERT(OK());
193 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
dimension_type * indexes
The vector that contains the keys in the tree.
const iterator & end()
Returns an iterator that points after the last element.
dimension_type reserved_size
The number of nodes in the complete tree.
dimension_type dfs_index(const_iterator itr) const
iterator erase(dimension_type key)
Erases the element with key key from the tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
PPL::dimension_type Parma_Polyhedra_Library::CO_Tree::external_memory_in_bytes ( ) const

Returns the size in bytes of the memory managed by *this.

This method takes $O(n)$ time.

Definition at line 30 of file CO_Tree.cc.

References begin(), data, end(), Parma_Polyhedra_Library::external_memory_in_bytes(), indexes, and reserved_size.

Referenced by Parma_Polyhedra_Library::Sparse_Row::external_memory_in_bytes().

30  {
31  dimension_type memory_size = 0;
32  if (reserved_size != 0) {
33  // Add the size of data[]
34  memory_size += (reserved_size + 1)*sizeof(data[0]);
35  // Add the size of indexes[]
36  memory_size += (reserved_size + 2)*sizeof(indexes[0]);
37  for (const_iterator itr = begin(), itr_end = end();
38  itr != itr_end; ++itr) {
39  memory_size += PPL::external_memory_in_bytes(*itr);
40  }
41  }
42  return memory_size;
43 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
iterator begin()
Returns an iterator that points at the first element.
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
const iterator & end()
Returns an iterator that points after the last element.
dimension_type reserved_size
The number of nodes in the complete tree.
Enable_If< Is_Native< T >::value, memory_size_type >::type external_memory_in_bytes(const T &)
For native types, returns the size in bytes of the memory managed by the type of the (unused) paramet...
void Parma_Polyhedra_Library::CO_Tree::fast_shift ( dimension_type  i,
iterator  itr 
)
inline

Sets to i the key of *itr. Assumes that i<=itr.index() and that there are no elements with keys in [i,itr.index()).

All existing iterators remain valid.

This method takes $O(1)$ time.

Definition at line 284 of file CO_Tree_inlines.hh.

References dfs_index(), end(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), indexes, and OK().

Referenced by Parma_Polyhedra_Library::Sparse_Row::fast_swap().

284  {
285  PPL_ASSERT(itr != end());
286  PPL_ASSERT(i <= itr.index());
287  indexes[dfs_index(itr)] = i;
288  PPL_ASSERT(OK());
289 }
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
dimension_type * indexes
The vector that contains the keys in the tree.
const iterator & end()
Returns an iterator that points after the last element.
dimension_type dfs_index(const_iterator itr) const
void Parma_Polyhedra_Library::CO_Tree::increase_keys_from ( dimension_type  key,
dimension_type  n 
)

Adds n to all keys greater than or equal to key.

Parameters
keyThe key of the first element whose key will be increased.
nSpecifies how much the keys will be increased.

This method takes $O(k+\log n)$ expected time, where k is the number of elements with keys greater than or equal to key.

Definition at line 196 of file CO_Tree.cc.

References Parma_Polyhedra_Library::Implementation::BD_Shapes::empty.

Referenced by Parma_Polyhedra_Library::Sparse_Row::add_zeroes_and_shift().

196  {
197  if (empty()) {
198  return;
199  }
201  while (*p == unused_index) {
202  --p;
203  }
204  while (p != indexes && *p >= key) {
205  *p += n;
206  --p;
207  while (*p == unused_index) {
208  --p;
209  }
210  }
211  PPL_ASSERT(OK());
212 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
dimension_type * indexes
The vector that contains the keys in the tree.
bool empty() const
Returns true if the tree has no elements.
dimension_type reserved_size
The number of nodes in the complete tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::init ( dimension_type  n)
private

Initializes a tree with reserved size at least n .

Parameters
nA lower bound on the tree's desired reserved size.

This method takes $O(n)$ time.

Definition at line 607 of file CO_Tree.cc.

Referenced by CO_Tree(), operator=(), and rebuild_smaller_tree().

607  {
608  indexes = NULL;
609  data = NULL;
610  size_ = 0;
611  reserved_size = 0;
612  max_depth = 0;
613 
614  if (n > 0) {
615  const dimension_type max_d = integer_log2(n) + 1;
616  const height_t new_max_depth = static_cast<height_t>(max_d);
617  const dimension_type new_reserved_size
618  = (static_cast<dimension_type>(1) << new_max_depth) - 1;
619  // If this throws, *this will be the empty tree.
620  indexes = new dimension_type[new_reserved_size + 2];
621  try {
622  data = data_allocator.allocate(new_reserved_size + 1);
623  }
624  catch (...) {
625  delete[] indexes;
626  indexes = 0;
627  PPL_ASSERT(OK());
628  throw;
629  }
630  max_depth = new_max_depth;
631  reserved_size = new_reserved_size;
632 
633  // Mark all pairs as unused.
634  for (dimension_type i = 1; i <= reserved_size; ++i) {
635  indexes[i] = unused_index;
636  }
637 
638  // These are used as markers by iterators.
639  indexes[0] = 0;
640  indexes[reserved_size + 1] = 0;
641  }
642 
644 
645  PPL_ASSERT(structure_OK());
646 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
static unsigned integer_log2(dimension_type n)
Returns the floor of the base-2 logarithm of n .
Definition: CO_Tree.cc:787
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
unsigned height_t
This is used for node heights and depths in the tree.
std::allocator< data_type > data_allocator
The allocator used to allocate/deallocate data.
dimension_type reserved_size
The number of nodes in the complete tree.
void refresh_cached_iterators()
Re-initializes the cached iterators.
dimension_type size_
The number of values stored in the tree.
bool structure_OK() const
Checks the internal invariants, but not the densities.
Definition: CO_Tree.cc:664
height_t max_depth
The depth of the leaves in the complete tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::insert ( dimension_type  key)
inline

Inserts an element in the tree.

Returns
An iterator that points to the inserted pair.
Parameters
keyThe key that will be inserted into the tree, associated with the default data.

If such a pair already exists, an iterator pointing to that pair is returned.

This operation invalidates existing iterators.

This method takes $O(\log n)$ time if the element already exists, and $O(\log^2 n)$ amortized time otherwise.

Definition at line 111 of file CO_Tree_inlines.hh.

References Parma_Polyhedra_Library::Coefficient_zero(), empty(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::go_down_searching_key(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), and insert_precise().

Referenced by Parma_Polyhedra_Library::Sparse_Row::insert().

111  {
112  if (empty()) {
113  return insert(key, Coefficient_zero());
114  }
115  else {
116  tree_iterator itr(*this);
117  itr.go_down_searching_key(key);
118  if (itr.index() == key) {
119  return iterator(itr);
120  }
121  else {
122  return iterator(insert_precise(key, Coefficient_zero(), itr));
123  }
124  }
125 }
bool empty() const
Returns true if the tree has no elements.
iterator insert(dimension_type key)
Inserts an element in the tree.
tree_iterator insert_precise(dimension_type key, data_type_const_reference data, tree_iterator itr)
Inserts an element in the tree.
Definition: CO_Tree.cc:401
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::insert ( dimension_type  key,
data_type_const_reference  data 
)
inline

Inserts an element in the tree.

Returns
An iterator that points to the inserted element.
Parameters
keyThe key that will be inserted into the tree..
dataThe data that will be inserted into the tree.

If an element with the specified key already exists, its associated data is set to data and an iterator pointing to that pair is returned.

This operation invalidates existing iterators.

This method takes $O(\log n)$ time if the element already exists, and $O(\log^2 n)$ amortized time otherwise.amortized

Definition at line 128 of file CO_Tree_inlines.hh.

References empty(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::go_down_searching_key(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), insert_in_empty_tree(), insert_precise(), and unused_index.

128  {
129  if (empty()) {
130  insert_in_empty_tree(key, data1);
131  tree_iterator itr(*this);
132  PPL_ASSERT(itr.index() != unused_index);
133  return iterator(itr);
134  }
135  else {
136  tree_iterator itr(*this);
137  itr.go_down_searching_key(key);
138  return iterator(insert_precise(key, data1, itr));
139  }
140 }
bool empty() const
Returns true if the tree has no elements.
tree_iterator insert_precise(dimension_type key, data_type_const_reference data, tree_iterator itr)
Inserts an element in the tree.
Definition: CO_Tree.cc:401
void insert_in_empty_tree(dimension_type key, data_type_const_reference data)
Inserts an element in the tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
PPL::CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::insert ( iterator  itr,
dimension_type  key 
)

Inserts an element in the tree.

Returns
An iterator that points to the inserted element.
Parameters
itrThe iterator used as hint
keyThe key that will be inserted into the tree, associated with the default data.

This will be faster if itr points near to the place where the new element will be inserted (or where is already stored). However, the value of itr does not affect the result of this method, as long it is a valid iterator for this tree. itr may even be end().

If an element with the specified key already exists, an iterator pointing to that pair is returned.

This operation invalidates existing iterators.

This method takes $O(\log n)$ time if the element already exists, and $O(\log^2 n)$ amortized time otherwise.

Definition at line 46 of file CO_Tree.cc.

References Parma_Polyhedra_Library::Coefficient_zero(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::depth(), Parma_Polyhedra_Library::Implementation::BD_Shapes::empty, Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_offset(), and Parma_Polyhedra_Library::CO_Tree::iterator::index().

46  {
47  PPL_ASSERT(key1 != unused_index);
48 
49  if (empty()) {
51  return iterator(*this);
52  }
53 
54  if (itr == end()) {
55  return insert(key1);
56  }
57 
58  iterator candidate1 = bisect_near(itr, key1);
59 
60  if (key1 == candidate1.index()) {
61  return candidate1;
62  }
63 
64  dimension_type candidate2_index = dfs_index(candidate1);
65 
66  if (key1 < candidate1.index()) {
67  --candidate2_index;
68  while (indexes[candidate2_index] == unused_index) {
69  --candidate2_index;
70  }
71  }
72  else {
73  ++candidate2_index;
74  while (indexes[candidate2_index] == unused_index) {
75  ++candidate2_index;
76  }
77  }
78 
79  tree_iterator candidate1_node(candidate1, *this);
80 
81  PPL_ASSERT(candidate2_index <= reserved_size + 1);
82 
83  if (candidate2_index == 0 || candidate2_index > reserved_size) {
84  // Use candidate1
85  return iterator(insert_precise(key1, Coefficient_zero(),
86  candidate1_node));
87  }
88 
89  tree_iterator candidate2_node(*this, candidate2_index);
90 
91  // Adjacent nodes in an in-order visit of a tree always have different
92  // heights. This fact can be easily proven by induction on the tree's
93  // height, using the definition of the in-order layout.
94  PPL_ASSERT(candidate1_node.get_offset() != candidate2_node.get_offset());
95 
96  if (candidate1_node.get_offset() < candidate2_node.get_offset()) {
97  PPL_ASSERT(candidate1_node.depth() > candidate2_node.depth());
98  // candidate1_node is deeper in the tree than candidate2_node, so use
99  // candidate1_node.
100  return iterator(insert_precise(key1, Coefficient_zero(),
101  candidate1_node));
102  }
103  else {
104  PPL_ASSERT(candidate1_node.depth() < candidate2_node.depth());
105  // candidate2_node is deeper in the tree than candidate1_node, so use
106  // candidate2_node.
107  return iterator(insert_precise(key1, Coefficient_zero(),
108  candidate2_node));
109  }
110 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type * indexes
The vector that contains the keys in the tree.
const iterator & end()
Returns an iterator that points after the last element.
bool empty() const
Returns true if the tree has no elements.
iterator insert(dimension_type key)
Inserts an element in the tree.
dimension_type reserved_size
The number of nodes in the complete tree.
dimension_type dfs_index(const_iterator itr) const
tree_iterator insert_precise(dimension_type key, data_type_const_reference data, tree_iterator itr)
Inserts an element in the tree.
Definition: CO_Tree.cc:401
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
void insert_in_empty_tree(dimension_type key, data_type_const_reference data)
Inserts an element in the tree.
iterator bisect_near(iterator hint, dimension_type key)
Searches an element with key key near hint.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
PPL::CO_Tree::iterator Parma_Polyhedra_Library::CO_Tree::insert ( iterator  itr,
dimension_type  key,
data_type_const_reference  data 
)

Inserts an element in the tree.

Returns
An iterator that points to the inserted element.
Parameters
itrThe iterator used as hint
keyThe key that will be inserted into the tree.
dataThe data that will be inserted into the tree.

This will be faster if itr points near to the place where the new element will be inserted (or where is already stored). However, the value of itr does not affect the result of this method, as long it is a valid iterator for this tree. itr may even be end().

If an element with the specified key already exists, its associated data is set to data and an iterator pointing to that pair is returned.

This operation invalidates existing iterators.

This method takes $O(\log n)$ time if the element already exists, and $O(\log^2 n)$ amortized time otherwise.

Definition at line 113 of file CO_Tree.cc.

References Parma_Polyhedra_Library::CO_Tree::tree_iterator::depth(), Parma_Polyhedra_Library::Implementation::BD_Shapes::empty, Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_offset(), and Parma_Polyhedra_Library::CO_Tree::iterator::index().

114  {
115  PPL_ASSERT(key1 != unused_index);
116 
117  if (empty()) {
118  insert_in_empty_tree(key1, data1);
119  return iterator(*this);
120  }
121 
122  if (itr == end()) {
123  return insert(key1, data1);
124  }
125 
126  iterator candidate1 = bisect_near(itr, key1);
127 
128  if (key1 == candidate1.index()) {
129  *candidate1 = data1;
130  return candidate1;
131  }
132 
133  dimension_type candidate2_index = dfs_index(candidate1);
134 
135  if (key1 < candidate1.index()) {
136  --candidate2_index;
137  while (indexes[candidate2_index] == unused_index) {
138  --candidate2_index;
139  }
140 
141  }
142  else {
143  ++candidate2_index;
144  while (indexes[candidate2_index] == unused_index) {
145  ++candidate2_index;
146  }
147 
148  }
149 
150  tree_iterator candidate1_node(candidate1, *this);
151 
152  if (candidate2_index == 0 || candidate2_index > reserved_size) {
153  // Use candidate1
154  return iterator(insert_precise(key1, data1, candidate1_node));
155  }
156 
157  tree_iterator candidate2_node(*this, candidate2_index);
158 
159  // Adjacent nodes in an in-order visit of a tree always have different
160  // heights. This fact can be easily proven by induction on the tree's
161  // height, using the definition of the in-order layout.
162  PPL_ASSERT(candidate1_node.get_offset() != candidate2_node.get_offset());
163 
164  if (candidate1_node.get_offset() < candidate2_node.get_offset()) {
165  PPL_ASSERT(candidate1_node.depth() > candidate2_node.depth());
166  // candidate1_node is deeper in the tree than candidate2_node, so
167  // use candidate1_node.
168  return iterator(insert_precise(key1, data1, candidate1_node));
169  }
170  else {
171  PPL_ASSERT(candidate1_node.depth() < candidate2_node.depth());
172  // candidate2_node is deeper in the tree than candidate1_node, so
173  // use candidate2_node.
174  return iterator(insert_precise(key1, data1, candidate2_node));
175  }
176 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
dimension_type * indexes
The vector that contains the keys in the tree.
const iterator & end()
Returns an iterator that points after the last element.
bool empty() const
Returns true if the tree has no elements.
iterator insert(dimension_type key)
Inserts an element in the tree.
dimension_type reserved_size
The number of nodes in the complete tree.
dimension_type dfs_index(const_iterator itr) const
tree_iterator insert_precise(dimension_type key, data_type_const_reference data, tree_iterator itr)
Inserts an element in the tree.
Definition: CO_Tree.cc:401
void insert_in_empty_tree(dimension_type key, data_type_const_reference data)
Inserts an element in the tree.
iterator bisect_near(iterator hint, dimension_type key)
Searches an element with key key near hint.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::insert_in_empty_tree ( dimension_type  key,
data_type_const_reference  data 
)
inlineprivate

Inserts an element in the tree.

Parameters
keyThe key that will be inserted into the tree.
dataThe data that will be associated with key.

The tree must be empty.

This operation invalidates existing iterators.

This method takes $O(1)$ time.

Definition at line 292 of file CO_Tree_inlines.hh.

References empty(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), OK(), rebuild_bigger_tree(), size_, and unused_index.

Referenced by insert().

293  {
294  PPL_ASSERT(empty());
296  tree_iterator itr(*this);
297  PPL_ASSERT(itr.index() == unused_index);
298  new(&(*itr)) data_type(data1);
299  // Set the index afterwards, so that if the constructor above throws
300  // the tree's structure is consistent.
301  itr.index() = key;
302  ++size_;
303 
304  PPL_ASSERT(OK());
305 }
Coefficient data_type
The type of the data elements associated with keys.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
bool empty() const
Returns true if the tree has no elements.
void rebuild_bigger_tree()
Increases the tree's reserved size.
Definition: CO_Tree.cc:819
dimension_type size_
The number of values stored in the tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
PPL::CO_Tree::tree_iterator Parma_Polyhedra_Library::CO_Tree::insert_precise ( dimension_type  key,
data_type_const_reference  data,
tree_iterator  itr 
)
private

Inserts an element in the tree.

If there is already an element with key key in the tree, its associated data is set to data.

This operation invalidates existing iterators.

Returns
An iterator that points to the inserted element.
Parameters
keyThe key that will be inserted into the tree.
dataThe data that will be associated with key.
itrIt must point to the element in the tree with key key or, if no such element exists, it must point to the node that would be his parent.

This method takes $O(1)$ time if the element already exists, and $O(\log^2 n)$ amortized time otherwise.

Definition at line 401 of file CO_Tree.cc.

References Parma_Polyhedra_Library::Coefficient_zero(), Parma_Polyhedra_Library::Implementation::BD_Shapes::empty, Parma_Polyhedra_Library::CO_Tree::tree_iterator::go_down_searching_key(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), and Parma_Polyhedra_Library::swap().

Referenced by insert().

403  {
404  PPL_ASSERT(key1 != unused_index);
405  PPL_ASSERT(!empty());
406 
407 #ifndef NDEBUG
408  // Check that `itr' is a correct hint.
409  tree_iterator itr2(*this);
410  itr2.go_down_searching_key(key1);
411  PPL_ASSERT(itr == itr2);
412 #endif
413 
414  if (itr.index() == key1) {
415  // Replacement, rather than insertion.
416  *itr = data1;
417  PPL_ASSERT(OK());
418  return itr;
419  }
420 
421  // Proper insertion: check if it would invalidate `data1'.
422  const bool invalidating
423  = (data <= &data1) && (&data1 < data + (reserved_size + 1));
424 
425  if (!invalidating) {
426  return insert_precise_aux(key1, data1, itr);
427  }
428  // `data1' could be invalidated by the insert, because it is
429  // a coefficient of this row. Avoid the issue by copying it.
430  data_type data1_copy = data1;
431 
432 #ifndef NDEBUG
433  dimension_type i = &data1 - data;
434  dimension_type key2 = indexes[i];
435  PPL_ASSERT(key2 != unused_index);
436  // This is true since `key1' is not in the tree.
437  PPL_ASSERT(key2 != key1);
438 #endif
439 
440  // Insert a dummy coefficient.
441  // NOTE: this may invalidate `data1', because it may reallocate the tree
442  // and/or move coefficients during rebalancing.
443  itr = insert_precise_aux(key1, Coefficient_zero(), itr);
444 
445  PPL_ASSERT(itr.index() == key1);
446 
447  // Swap the correct coefficient in place.
448  using std::swap;
449  swap(*itr, data1_copy);
450 
451  PPL_ASSERT(OK());
452  return itr;
453 }
void swap(CO_Tree &x, CO_Tree &y)
Coefficient data_type
The type of the data elements associated with keys.
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
tree_iterator insert_precise_aux(dimension_type key, data_type_const_reference data, tree_iterator itr)
Helper for insert_precise.
Definition: CO_Tree.cc:456
bool empty() const
Returns true if the tree has no elements.
dimension_type reserved_size
The number of nodes in the complete tree.
Coefficient_traits::const_reference Coefficient_zero()
Returns a const reference to a Coefficient with value 0.
void swap(CO_Tree &x, CO_Tree &y)
Swaps x with y.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
PPL::CO_Tree::tree_iterator Parma_Polyhedra_Library::CO_Tree::insert_precise_aux ( dimension_type  key,
data_type_const_reference  data,
tree_iterator  itr 
)
private

Helper for insert_precise.

This helper method takes the same arguments as insert_precise, but besides assuming that itr is a correct hint, it also assumes that key and data are not in the tree; namely, a proper insertion has to be done and the insertion can not invalidate data.

Definition at line 456 of file CO_Tree.cc.

References Parma_Polyhedra_Library::Implementation::BD_Shapes::empty, Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_left_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_right_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_root(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::go_down_searching_key(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), and Parma_Polyhedra_Library::CO_Tree::tree_iterator::is_leaf().

458  {
459  PPL_ASSERT(key1 != unused_index);
460  PPL_ASSERT(!empty());
461  // This is a proper insert.
462  PPL_ASSERT(itr.index() != key1);
463  // `data1' is not going to be invalidated.
464  PPL_ASSERT(!(data <= &data1 && &data1 < data + (reserved_size + 1)));
465 
468  // `itr' was invalidated by the rebuild operation
469  itr.get_root();
470  itr.go_down_searching_key(key1);
471  PPL_ASSERT(itr.index() != key1);
472  }
473 
474  PPL_ASSERT(!is_greater_than_ratio(size_ + 1, reserved_size,
476 
477  ++size_;
478 
479  if (!itr.is_leaf()) {
480  if (key1 < itr.index()) {
481  itr.get_left_child();
482  }
483  else {
484  itr.get_right_child();
485  }
486  PPL_ASSERT(itr.index() == unused_index);
487 
488  new(&(*itr)) data_type(data1);
489  // Set the index only if the construction was successful.
490  itr.index() = key1;
491  }
492  else {
493  itr = rebalance(itr, key1, data1);
494  itr.go_down_searching_key(key1);
495  PPL_ASSERT(itr.index() == key1);
496  }
497  PPL_ASSERT(OK());
498 
499  return itr;
500 }
Coefficient data_type
The type of the data elements associated with keys.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
static bool is_greater_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
static const dimension_type max_density_percent
The maximum density of used nodes.
data_type * data
The vector that contains the data of the keys in the tree.
tree_iterator rebalance(tree_iterator itr, dimension_type key, data_type_const_reference value)
Rebalances the tree.
Definition: CO_Tree.cc:868
bool empty() const
Returns true if the tree has no elements.
dimension_type reserved_size
The number of nodes in the complete tree.
void rebuild_bigger_tree()
Increases the tree's reserved size.
Definition: CO_Tree.cc:819
dimension_type size_
The number of values stored in the tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
unsigned Parma_Polyhedra_Library::CO_Tree::integer_log2 ( dimension_type  n)
staticprivate

Returns the floor of the base-2 logarithm of n .

Parameters
nIt must be greater than zero.

This method takes $O(\log n)$ time.

Definition at line 787 of file CO_Tree.cc.

Referenced by CO_Tree(), and Parma_Polyhedra_Library::CO_Tree::tree_iterator::depth().

787  {
788  PPL_ASSERT(n != 0);
789  unsigned result = 0;
790  while (n != 1) {
791  n /= 2;
792  ++result;
793  }
794  return result;
795 }
bool Parma_Polyhedra_Library::CO_Tree::is_greater_than_ratio ( dimension_type  numer,
dimension_type  denom,
dimension_type  ratio 
)
inlinestaticprivate

Compares the fractions numer/denom with ratio/100.

Returns
Returns true if the fraction numer/denom is greater than the fraction ratio/100.
Parameters
ratioIt must be less than or equal to 100.
numerThe numerator of the fraction.
denomThe denominator of the fraction.

This method takes $O(1)$ time.

Definition at line 318 of file CO_Tree_inlines.hh.

References unused_index.

Referenced by CO_Tree().

319  {
320  PPL_ASSERT(ratio <= 100);
321  // If these are true, no overflows are possible.
322  PPL_ASSERT(denom <= unused_index/100);
323  PPL_ASSERT(numer <= unused_index/100);
324  return 100*numer > ratio*denom;
325 }
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
bool Parma_Polyhedra_Library::CO_Tree::is_less_than_ratio ( dimension_type  numer,
dimension_type  denom,
dimension_type  ratio 
)
inlinestaticprivate

Compares the fractions numer/denom with ratio/100.

Returns
Returns true if the fraction numer/denom is less than the fraction ratio/100.
Parameters
ratioIt must be less than or equal to 100.
numerThe numerator of the fraction.
denomThe denominator of the fraction.

This method takes $O(1)$ time.

Definition at line 308 of file CO_Tree_inlines.hh.

References unused_index.

309  {
310  PPL_ASSERT(ratio <= 100);
311  // If these are true, no overflows are possible.
312  PPL_ASSERT(denom <= unused_index/100);
313  PPL_ASSERT(numer <= unused_index/100);
314  return 100*numer < ratio*denom;
315 }
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::m_swap ( CO_Tree x)
inline

Swaps x with *this.

Parameters
xThe tree that will be swapped with *this.

This operation invalidates existing iterators.

This method takes $O(1)$ time.

Definition at line 179 of file CO_Tree_inlines.hh.

References data, data_allocator, indexes, max_depth, refresh_cached_iterators(), reserved_size, size_, structure_OK(), Parma_Polyhedra_Library::swap(), and swap().

Referenced by Parma_Polyhedra_Library::Sparse_Row::linear_combine(), rebuild_smaller_tree(), and Parma_Polyhedra_Library::swap().

179  {
180  using std::swap;
181  swap(max_depth, x.max_depth);
182  swap(indexes, x.indexes);
183  swap(data_allocator, x.data_allocator);
184  swap(data, x.data);
185  swap(reserved_size, x.reserved_size);
186  swap(size_, x.size_);
187  // Cached iterators have been invalidated by the swap,
188  // they must be refreshed here.
190  x.refresh_cached_iterators();
191  PPL_ASSERT(structure_OK());
192  PPL_ASSERT(x.structure_OK());
193 }
void swap(CO_Tree::iterator &x, CO_Tree::iterator &y)
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
std::allocator< data_type > data_allocator
The allocator used to allocate/deallocate data.
dimension_type reserved_size
The number of nodes in the complete tree.
void swap(CO_Tree &x, CO_Tree &y)
Swaps x with y.
void refresh_cached_iterators()
Re-initializes the cached iterators.
dimension_type size_
The number of values stored in the tree.
bool structure_OK() const
Checks the internal invariants, but not the densities.
Definition: CO_Tree.cc:664
height_t max_depth
The depth of the leaves in the complete tree.
dimension_type Parma_Polyhedra_Library::CO_Tree::max_size ( )
inlinestatic

Returns the size() of the largest possible CO_Tree.

Definition at line 96 of file CO_Tree_inlines.hh.

Referenced by Parma_Polyhedra_Library::Sparse_Row::max_size().

96  {
97  return C_Integer<dimension_type>::max/100;
98 }
void Parma_Polyhedra_Library::CO_Tree::move_data_element ( data_type to,
data_type from 
)
inlinestaticprivate

Moves the value of from in to .

Parameters
fromIt must be a valid value.
toIt must be a non-constructed chunk of memory.

After the move, from becomes a non-constructed chunk of memory and to gets the value previously stored by from.

The implementation of this method assumes that data_type values do not keep pointers to themselves nor to their fields.

This method takes $O(1)$ time.

Definition at line 345 of file CO_Tree_inlines.hh.

345  {
346  /*
347  The following code is equivalent (but slower):
348 
349  <CODE>
350  new(&to) data_type(from);
351  from.~data_type();
352  </CODE>
353  */
354  std::memcpy(&to, &from, sizeof(data_type));
355 }
Coefficient data_type
The type of the data elements associated with keys.
void Parma_Polyhedra_Library::CO_Tree::move_data_from ( CO_Tree tree)
private

Moves all data in the tree tree into *this.

Parameters
treeThe tree from which the element will be moved into *this.

this must be empty and big enough to contain all of tree's data without exceeding max_density.

This method takes $O(n)$ time.

Definition at line 1133 of file CO_Tree.cc.

References data, Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_left_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_parent(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_right_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), indexes, reserved_size, size_, sizeof_to_bits, and structure_OK().

Referenced by rebuild_smaller_tree().

1133  {
1134  PPL_ASSERT(size_ == 0);
1135  if (tree.size_ == 0) {
1136  return;
1137  }
1138 
1139  tree_iterator root(*this);
1140 
1141  dimension_type source_index = 1;
1142  while (tree.indexes[source_index] == unused_index) {
1143  ++source_index;
1144  }
1145 
1146  // This is static and with static allocation, to improve performance.
1147  // sizeof_to_bits(sizeof(dimension_type)) is the maximum k such that 2^k-1 is a
1148  // dimension_type, so it is the maximum tree height.
1149  // For each node level, the stack may contain up to 4 elements: two elements
1150  // with operation 0, one element with operation 2 and one element
1151  // with operation 3. An additional element with operation 1 can be at the
1152  // top of the tree.
1153  static std::pair<dimension_type, signed char>
1154  stack[5U * sizeof_to_bits(sizeof(dimension_type))];
1155 
1156  dimension_type stack_first_empty = 0;
1157 
1158  // A pair (n, operation) in the stack means:
1159  //
1160  // * Go to the parent, if operation is 0.
1161  // * Go to the left child, then visit the current tree (with size n), if
1162  // operation is 1.
1163  // * Go to the right child, then visit the current tree (with size n), if
1164  // operation is 2.
1165  // * Visit the current tree (with size n), if operation is 3.
1166 
1167  stack[0].first = tree.size_;
1168  stack[0].second = 3;
1169  ++stack_first_empty;
1170 
1171  while (stack_first_empty != 0) {
1172 
1173  // Implement
1174  //
1175  // <CODE>
1176  // top_n = stack.top().first;
1177  // top_operation = stack.top().second;
1178  // </CODE>
1179  const dimension_type top_n = stack[stack_first_empty - 1].first;
1180  const signed char top_operation = stack[stack_first_empty - 1].second;
1181 
1182  switch (top_operation) {
1183 
1184  case 0:
1185  root.get_parent();
1186  --stack_first_empty;
1187  continue;
1188 
1189  case 1:
1190  root.get_left_child();
1191  break;
1192 
1193  case 2:
1194  root.get_right_child();
1195  break;
1196 
1197 #ifndef NDEBUG
1198  case 3:
1199  break;
1200 
1201  default:
1202  PPL_UNREACHABLE;
1203  break;
1204 #endif
1205  }
1206 
1207  // We now visit the current tree
1208 
1209  if (top_n == 0) {
1210  --stack_first_empty;
1211  }
1212  else {
1213  if (top_n == 1) {
1214  PPL_ASSERT(root.index() == unused_index);
1215  PPL_ASSERT(tree.indexes[source_index] != unused_index);
1216  root.index() = tree.indexes[source_index];
1217  tree.indexes[source_index] = unused_index;
1218  move_data_element(*root, tree.data[source_index]);
1219  PPL_ASSERT(source_index <= tree.reserved_size);
1220  ++source_index;
1221  while (tree.indexes[source_index] == unused_index) {
1222  ++source_index;
1223  }
1224  --stack_first_empty;
1225  }
1226  else {
1227  PPL_ASSERT(stack_first_empty + 3 < sizeof(stack)/sizeof(stack[0]));
1228 
1229  const dimension_type half = (top_n + 1) / 2;
1230  stack[stack_first_empty - 1].second = 0;
1231  stack[stack_first_empty ] = std::make_pair(top_n - half, 2);
1232  stack[stack_first_empty + 1] = std::make_pair(1, 3);
1233  stack[stack_first_empty + 2].second = 0;
1234  stack[stack_first_empty + 3] = std::make_pair(half - 1, 1);
1235  stack_first_empty += 4;
1236  }
1237  }
1238  }
1239  size_ = tree.size_;
1240  tree.size_ = 0;
1241  PPL_ASSERT(tree.structure_OK());
1242  PPL_ASSERT(structure_OK());
1243 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
#define sizeof_to_bits(size)
Definition: compiler.hh:80
static void move_data_element(data_type &to, data_type &from)
Moves the value of from in to .
dimension_type size_
The number of values stored in the tree.
bool structure_OK() const
Checks the internal invariants, but not the densities.
Definition: CO_Tree.cc:664
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
bool Parma_Polyhedra_Library::CO_Tree::OK ( ) const
private

Checks the internal invariants.

Definition at line 752 of file CO_Tree.cc.

Referenced by CO_Tree(), Parma_Polyhedra_Library::CO_Tree::const_iterator::const_iterator(), fast_shift(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::follow_left_children_with_value(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::follow_right_children_with_value(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_left_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_parent(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_right_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_root(), Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), Parma_Polyhedra_Library::CO_Tree::iterator::index(), insert_in_empty_tree(), Parma_Polyhedra_Library::CO_Tree::iterator::iterator(), Parma_Polyhedra_Library::CO_Tree::const_iterator::m_swap(), Parma_Polyhedra_Library::CO_Tree::iterator::m_swap(), Parma_Polyhedra_Library::CO_Tree::const_iterator::operator*(), Parma_Polyhedra_Library::CO_Tree::iterator::operator*(), Parma_Polyhedra_Library::CO_Tree::const_iterator::operator++(), Parma_Polyhedra_Library::CO_Tree::iterator::operator++(), Parma_Polyhedra_Library::CO_Tree::const_iterator::operator--(), Parma_Polyhedra_Library::CO_Tree::iterator::operator--(), Parma_Polyhedra_Library::CO_Tree::const_iterator::operator=(), Parma_Polyhedra_Library::CO_Tree::iterator::operator=(), Parma_Polyhedra_Library::CO_Tree::const_iterator::operator==(), and Parma_Polyhedra_Library::CO_Tree::iterator::operator==().

752  {
753 
754  if (!structure_OK()) {
755  return false;
756  }
757  {
758  dimension_type real_size = 0;
759 
760  for (const_iterator itr = begin(), itr_end = end(); itr != itr_end; ++itr) {
761  ++real_size;
762  }
763 
764  if (real_size != size_) {
765  // There are \p real_size elements in the tree, but size is \p size.
766  return false;
767  }
768  }
769 
770  if (reserved_size > 0) {
772  && reserved_size != 3) {
773  // Found too high density.
774  return false;
775  }
778  // Found too low density
779  return false;
780  }
781  }
782 
783  return true;
784 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
static bool is_greater_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
static const dimension_type max_density_percent
The maximum density of used nodes.
iterator begin()
Returns an iterator that points at the first element.
const iterator & end()
Returns an iterator that points after the last element.
dimension_type reserved_size
The number of nodes in the complete tree.
static const dimension_type min_density_percent
The minimum density of used nodes.
static bool is_less_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
dimension_type size_
The number of values stored in the tree.
bool structure_OK() const
Checks the internal invariants, but not the densities.
Definition: CO_Tree.cc:664
CO_Tree & Parma_Polyhedra_Library::CO_Tree::operator= ( const CO_Tree y)
inline

The assignment operator.

Parameters
yThe tree that will be assigned to *this.

This method takes $O(n)$ time.

Definition at line 64 of file CO_Tree_inlines.hh.

References copy_data_from(), data_allocator, destroy(), init(), and reserved_size.

64  {
65  if (this != &y) {
66  destroy();
67  data_allocator = y.data_allocator;
68  init(y.reserved_size);
69  copy_data_from(y);
70  }
71  return *this;
72 }
void init(dimension_type n)
Initializes a tree with reserved size at least n .
Definition: CO_Tree.cc:607
void destroy()
Deallocates the tree's dynamic arrays.
Definition: CO_Tree.cc:649
std::allocator< data_type > data_allocator
The allocator used to allocate/deallocate data.
void copy_data_from(const CO_Tree &tree)
Copies all data in the tree tree into *this.
Definition: CO_Tree.cc:1246
Parma_Polyhedra_Library::CO_Tree::PPL_COMPILE_TIME_CHECK ( C_Integer< height_t >::max >=  sizeof_to_bitssizeof(dimension_type),
"height_t is too small to store depths."   
)
private
PPL::CO_Tree::tree_iterator Parma_Polyhedra_Library::CO_Tree::rebalance ( tree_iterator  itr,
dimension_type  key,
data_type_const_reference  value 
)
private

Rebalances the tree.

For insertions, it adds the pair (key, value) in the process.

This operation invalidates existing iterators that point to nodes in the rebalanced subtree.

Returns
an iterator pointing to the root of the subtree that was rebalanced.
Parameters
itrIt points to the node where the new element has to be inserted or where an element has just been deleted.
keyThe index that will be inserted in the tree (for insertions only).
valueThe value that will be inserted in the tree (for insertions only).

This method takes $O(\log^2 n)$ amortized time.

Definition at line 868 of file CO_Tree.cc.

References Parma_Polyhedra_Library::CO_Tree::tree_iterator::depth(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::dfs_index(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_left_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_offset(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_parent(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::get_right_child(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::index(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::is_leaf(), Parma_Polyhedra_Library::CO_Tree::tree_iterator::is_right_child(), and value.

869  {
870  // Trees with reserved size 3 need not to be rebalanced.
871  // This check is needed because they can't be shrunk, so they may violate
872  // the density thresholds, and this would prevent the following while from
873  // working correctly.
874  if (reserved_size == 3) {
875  PPL_ASSERT(OK());
876  return tree_iterator(*this);
877  }
878  PPL_ASSERT(itr.index() == unused_index || itr.is_leaf());
879  height_t itr_depth_minus_1 = itr.depth() - 1;
880  const height_t height = max_depth - itr_depth_minus_1;
881  dimension_type subtree_size;
882  dimension_type subtree_reserved_size = (static_cast<dimension_type>(1)
883  << height) - 1;
884  const bool deleting = itr.index() == unused_index;
885  PPL_ASSERT(deleting || key != unused_index);
886  if (deleting) {
887  subtree_size = 0;
888  }
889  else {
890  // The existing element and the element with index key we want to add.
891  subtree_size = 2;
892  }
893 
894  while (is_greater_than_ratio(subtree_size, subtree_reserved_size,
896  + ((itr_depth_minus_1
897  * (100 - max_density_percent))
898  / (max_depth - 1)))
899  || is_less_than_ratio(subtree_size, subtree_reserved_size,
901  - ((itr_depth_minus_1
904  / (max_depth - 1)))) {
905  // The density in the tree is correct, so the while condition is always
906  // false for the root.
907  PPL_ASSERT(itr_depth_minus_1 != 0);
908  const bool is_right_brother = itr.is_right_child();
909  itr.get_parent();
910  if (is_right_brother) {
911  itr.get_left_child();
912  }
913  else {
914  itr.get_right_child();
915  }
916  subtree_size += count_used_in_subtree(itr);
917  itr.get_parent();
918  PPL_ASSERT(itr.index() != unused_index);
919  ++subtree_size;
920  subtree_reserved_size = 2*subtree_reserved_size + 1;
921  --itr_depth_minus_1;
922  PPL_ASSERT(itr.depth() - 1 == itr_depth_minus_1);
923  }
924 
925  // Now the subtree rooted at itr has been chosen as the subtree to be
926  // rebalanced.
927 
928  // Step 1: compact elements of this subtree in the rightmost end, from right
929  // to left.
930  const dimension_type last_index_in_subtree
931  = itr.dfs_index() + itr.get_offset() - 1;
932 
933  const dimension_type first_unused
934  = compact_elements_in_the_rightmost_end(last_index_in_subtree,
935  subtree_size, key, value,
936  !deleting);
937 
938  // Step 2: redistribute the elements, from left to right.
939  redistribute_elements_in_subtree(itr.dfs_index(), subtree_size,
940  first_unused + 1, key, value,
941  first_unused != last_index_in_subtree
942  - subtree_size);
943 
944  PPL_ASSERT(OK());
945 
946  return itr;
947 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
bool OK() const
Checks the internal invariants.
Definition: CO_Tree.cc:752
static bool is_greater_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
static const dimension_type max_density_percent
The maximum density of used nodes.
static const dimension_type min_leaf_density_percent
The minimum density at the leaves' depth.
unsigned height_t
This is used for node heights and depths in the tree.
dimension_type reserved_size
The number of nodes in the complete tree.
static const dimension_type min_density_percent
The minimum density of used nodes.
dimension_type compact_elements_in_the_rightmost_end(dimension_type last_in_subtree, dimension_type subtree_size, dimension_type key, data_type_const_reference value, bool add_element)
Moves all elements of a subtree to the rightmost end.
Definition: CO_Tree.cc:951
Coefficient value
Definition: PIP_Tree.cc:618
static bool is_less_than_ratio(dimension_type numer, dimension_type denom, dimension_type ratio)
Compares the fractions numer/denom with ratio/100.
static dimension_type count_used_in_subtree(tree_iterator itr)
Counts the number of used elements in the subtree rooted at itr.
Definition: CO_Tree.cc:1294
height_t max_depth
The depth of the leaves in the complete tree.
void redistribute_elements_in_subtree(dimension_type root_index, dimension_type subtree_size, dimension_type last_used, dimension_type key, data_type_const_reference value, bool add_element)
Redistributes the elements in the subtree rooted at root_index.
Definition: CO_Tree.cc:1038
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::rebuild_bigger_tree ( )
private

Increases the tree's reserved size.

This is called when the density is about to exceed the maximum density (specified by max_density_percent).

This method takes $O(n)$ time.

Definition at line 819 of file CO_Tree.cc.

Referenced by insert_in_empty_tree().

819  {
820  if (reserved_size == 0) {
821  init(3);
822  PPL_ASSERT(structure_OK());
823  return;
824  }
825 
826  const dimension_type new_reserved_size = reserved_size*2 + 1;
827 
828  dimension_type* const new_indexes = new dimension_type[new_reserved_size + 2];
829 
830  data_type* new_data;
831 
832  try {
833  new_data = data_allocator.allocate(new_reserved_size + 1);
834  } catch (...) {
835  delete[] new_indexes;
836  throw;
837  }
838 
839  new_indexes[1] = unused_index;
840 
841  for (dimension_type i = 1, j = 2; i <= reserved_size; ++i, ++j) {
842  new_indexes[j] = indexes[i];
843  if (indexes[i] != unused_index) {
844  move_data_element(new_data[j], data[i]);
845  }
846  ++j;
847  new_indexes[j] = unused_index;
848  }
849 
850  // These are used as markers by iterators.
851  new_indexes[0] = 0;
852  new_indexes[new_reserved_size + 1] = 0;
853 
854  delete[] indexes;
855  data_allocator.deallocate(data, reserved_size + 1);
856 
857  indexes = new_indexes;
858  data = new_data;
859  reserved_size = new_reserved_size;
860  ++max_depth;
861 
863 
864  PPL_ASSERT(structure_OK());
865 }
Coefficient data_type
The type of the data elements associated with keys.
void init(dimension_type n)
Initializes a tree with reserved size at least n .
Definition: CO_Tree.cc:607
size_t dimension_type
An unsigned integral type for representing space dimensions.
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
std::allocator< data_type > data_allocator
The allocator used to allocate/deallocate data.
dimension_type reserved_size
The number of nodes in the complete tree.
static void move_data_element(data_type &to, data_type &from)
Moves the value of from in to .
void refresh_cached_iterators()
Re-initializes the cached iterators.
bool structure_OK() const
Checks the internal invariants, but not the densities.
Definition: CO_Tree.cc:664
height_t max_depth
The depth of the leaves in the complete tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::rebuild_smaller_tree ( )
inlineprivate

Decreases the tree's reserved size.

This is called when the density is about to become less than the minimum allowed density (specified by min_density_percent).

reserved_size must be greater than 3 (otherwise the tree can just be cleared).

This method takes $O(n)$ time.

Definition at line 328 of file CO_Tree_inlines.hh.

References init(), m_swap(), move_data_from(), reserved_size, and structure_OK().

328  {
329  PPL_ASSERT(reserved_size > 3);
330  CO_Tree new_tree;
331  new_tree.init(reserved_size / 2);
332  new_tree.move_data_from(*this);
333  m_swap(new_tree);
334  PPL_ASSERT(new_tree.structure_OK());
335  PPL_ASSERT(structure_OK());
336 }
void m_swap(CO_Tree &x)
Swaps x with *this.
dimension_type reserved_size
The number of nodes in the complete tree.
bool structure_OK() const
Checks the internal invariants, but not the densities.
Definition: CO_Tree.cc:664
CO_Tree()
Constructs an empty tree.
void Parma_Polyhedra_Library::CO_Tree::redistribute_elements_in_subtree ( dimension_type  root_index,
dimension_type  subtree_size,
dimension_type  last_used,
dimension_type  key,
data_type_const_reference  value,
bool  add_element 
)
private

Redistributes the elements in the subtree rooted at root_index.

The subtree's elements must be compacted to the rightmost end.

Parameters
root_indexThe index of the subtree's root node.
subtree_sizeIt is the number of used elements in the subtree. It must be greater than zero.
last_usedIt points to the leftmost element with a value in the subtree.
add_elementIf it is true, this method adds an element with the specified key and value in the process.
keyThe key that will be added to the tree if add_element is true.
valueThe data that will be added to the tree if add_element is true.

This method takes $O(k)$ time, where k is subtree_size.

Definition at line 1038 of file CO_Tree.cc.

References sizeof_to_bits.

1044  {
1045 
1046  // This is static and with static allocation, to improve performance.
1047  // sizeof_to_bits(sizeof(dimension_type)) is the maximum k such that
1048  // 2^k-1 is a dimension_type, so it is the maximum tree height.
1049  // For each node level, the stack may contain up to two element (one for the
1050  // subtree rooted at the right son of a node of that level, and one for the
1051  // node itself). An additional element can be at the top of the tree.
1052  static std::pair<dimension_type,dimension_type>
1053  stack[2U * sizeof_to_bits(sizeof(dimension_type)) + 1U];
1054 
1055  std::pair<dimension_type,dimension_type>* stack_first_empty = stack;
1056 
1057  // A pair (n, i) in the stack means to visit the subtree with root index i
1058  // and size n.
1059 
1060  PPL_ASSERT(subtree_size != 0);
1061 
1062  stack_first_empty->first = subtree_size;
1063  stack_first_empty->second = root_index;
1064  ++stack_first_empty;
1065 
1066  while (stack_first_empty != stack) {
1067 
1068  --stack_first_empty;
1069 
1070  // Implement
1071  //
1072  // <CODE>
1073  // top_n = stack.top().first;
1074  // top_i = stack.top().second;
1075  // </CODE>
1076  const dimension_type top_n = stack_first_empty->first;
1077  const dimension_type top_i = stack_first_empty->second;
1078 
1079  PPL_ASSERT(top_n != 0);
1080  if (top_n == 1) {
1081  if (add_element
1082  && (last_used > reserved_size || indexes[last_used] > key)) {
1083  PPL_ASSERT(last_used != top_i);
1084  PPL_ASSERT(indexes[top_i] == unused_index);
1085  add_element = false;
1086  new(&(data[top_i])) data_type(value);
1087  // Set the index only if the construction was successful.
1088  indexes[top_i] = key;
1089  }
1090  else {
1091  if (last_used != top_i) {
1092  PPL_ASSERT(indexes[top_i] == unused_index);
1093  indexes[top_i] = indexes[last_used];
1094  indexes[last_used] = unused_index;
1095  move_data_element(data[top_i], data[last_used]);
1096  }
1097  ++last_used;
1098  }
1099  }
1100  else {
1101  PPL_ASSERT(stack_first_empty + 2
1102  < stack + sizeof(stack)/sizeof(stack[0]));
1103 
1104  const dimension_type offset = (top_i & -top_i) / 2;
1105  const dimension_type half = (top_n + 1) / 2;
1106 
1107  PPL_ASSERT(half > 0);
1108 
1109  // Right subtree
1110  PPL_ASSERT(top_n - half > 0);
1111  stack_first_empty->first = top_n - half;
1112  stack_first_empty->second = top_i + offset;
1113  ++stack_first_empty;
1114 
1115  // Root of the current subtree
1116  stack_first_empty->first = 1;
1117  stack_first_empty->second = top_i;
1118  ++stack_first_empty;
1119 
1120  // Left subtree
1121  if (half - 1 != 0) {
1122  stack_first_empty->first = half - 1;
1123  stack_first_empty->second = top_i - offset;
1124  ++stack_first_empty;
1125  }
1126  }
1127  }
1128 
1129  PPL_ASSERT(!add_element);
1130 }
Coefficient data_type
The type of the data elements associated with keys.
size_t dimension_type
An unsigned integral type for representing space dimensions.
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
dimension_type reserved_size
The number of nodes in the complete tree.
#define sizeof_to_bits(size)
Definition: compiler.hh:80
Coefficient value
Definition: PIP_Tree.cc:618
static void move_data_element(data_type &to, data_type &from)
Moves the value of from in to .
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.
void Parma_Polyhedra_Library::CO_Tree::refresh_cached_iterators ( )
inlineprivate

Re-initializes the cached iterators.

This method must be called when the indexes[] and data[] vector are reallocated.

This method takes $O(1)$ time.

Definition at line 339 of file CO_Tree_inlines.hh.

References cached_const_end, cached_end, and reserved_size.

Referenced by m_swap().

339  {
340  cached_end = iterator(*this, reserved_size + 1);
341  cached_const_end = const_iterator(*this, reserved_size + 1);
342 }
dimension_type reserved_size
The number of nodes in the complete tree.
iterator cached_end
The iterator returned by end().
const_iterator cached_const_end
The iterator returned by the const version of end().
dimension_type Parma_Polyhedra_Library::CO_Tree::size ( ) const
inline

Returns the number of elements stored in the tree.

This method takes $O(1)$ time.

Definition at line 91 of file CO_Tree_inlines.hh.

References size_.

Referenced by Parma_Polyhedra_Library::Sparse_Row::num_stored_elements().

91  {
92  return size_;
93 }
dimension_type size_
The number of values stored in the tree.
bool Parma_Polyhedra_Library::CO_Tree::structure_OK ( ) const
private

Checks the internal invariants, but not the densities.

Definition at line 664 of file CO_Tree.cc.

References Parma_Polyhedra_Library::CO_Tree::const_iterator::index(), and Parma_Polyhedra_Library::CO_Tree::tree_iterator::index().

Referenced by m_swap(), move_data_from(), and rebuild_smaller_tree().

664  {
665 
666  if (size_ > reserved_size) {
667  return false;
668  }
669 
670  if (reserved_size == 0) {
671  if (indexes != NULL) {
672  return false;
673  }
674  if (data != NULL) {
675  return false;
676  }
677  if (max_depth != 0) {
678  return false;
679  }
680 
681  return true;
682  }
683 
684  if (reserved_size < 3) {
685  return false;
686  }
687  if (reserved_size != (static_cast<dimension_type>(1) << max_depth) - 1) {
688  return false;
689  }
690 
691  if (data == NULL) {
692  return false;
693  }
694 
695  if (indexes == NULL) {
696  return false;
697  }
698 
699  if (max_depth == 0) {
700  return false;
701  }
702 
703  if (size_ == 0) {
704 
705  // This const_cast could be removed by adding a const_tree_iterator,
706  // but it would add much code duplication without a real need.
707  tree_iterator itr(*const_cast<CO_Tree*>(this));
708  if (itr.index() != unused_index) {
709  return false;
710  }
711 
712  }
713  else {
714  // This const_cast could be removed by adding a const_tree_iterator,
715  // but it would add much code duplication without a real need.
716  tree_iterator itr(*const_cast<CO_Tree*>(this));
717  const dimension_type real_size = count_used_in_subtree(itr);
718  if (real_size != size_) {
719  // There are \p real_size elements in the tree that are reachable by the
720  // root, but size is \p size.
721  return false;
722  }
723  }
724 
725  if (size_ != 0) {
726  const_iterator itr = begin();
727  const_iterator itr_end = end();
728 
729  if (itr != itr_end) {
730  dimension_type last_index = itr.index();
731  for (++itr; itr != itr_end; ++itr) {
732  if (last_index >= itr.index()) {
733  // Found index \p itr->first after index \p last_index.
734  return false;
735  }
736  last_index = itr.index();
737  }
738  }
739  }
740 
741  if (const_iterator(cached_end) != const_iterator(*this, reserved_size + 1)) {
742  return false;
743  }
744  if (cached_const_end != const_iterator(*this, reserved_size + 1)) {
745  return false;
746  }
747 
748  return true;
749 }
size_t dimension_type
An unsigned integral type for representing space dimensions.
iterator begin()
Returns an iterator that points at the first element.
data_type * data
The vector that contains the data of the keys in the tree.
dimension_type * indexes
The vector that contains the keys in the tree.
const iterator & end()
Returns an iterator that points after the last element.
dimension_type reserved_size
The number of nodes in the complete tree.
iterator cached_end
The iterator returned by end().
const_iterator cached_const_end
The iterator returned by the const version of end().
static dimension_type count_used_in_subtree(tree_iterator itr)
Counts the number of used elements in the subtree rooted at itr.
Definition: CO_Tree.cc:1294
dimension_type size_
The number of values stored in the tree.
height_t max_depth
The depth of the leaves in the complete tree.
static const dimension_type unused_index
An index used as a marker for unused nodes in the tree.

Friends And Related Function Documentation

void swap ( CO_Tree x,
CO_Tree y 
)
related

Swaps x with y.

Definition at line 873 of file CO_Tree_inlines.hh.

Referenced by Parma_Polyhedra_Library::CO_Tree::const_iterator::m_swap(), Parma_Polyhedra_Library::CO_Tree::iterator::m_swap(), and m_swap().

873  {
874  x.m_swap(y);
875 }

Member Data Documentation

const_iterator Parma_Polyhedra_Library::CO_Tree::cached_const_end
private

The iterator returned by the const version of end().

It is updated when needed, to keep it valid.

Definition at line 1289 of file CO_Tree_defs.hh.

Referenced by cend(), end(), and refresh_cached_iterators().

iterator Parma_Polyhedra_Library::CO_Tree::cached_end
private

The iterator returned by end().

It is updated when needed, to keep it valid.

Definition at line 1283 of file CO_Tree_defs.hh.

Referenced by end(), and refresh_cached_iterators().

data_type* Parma_Polyhedra_Library::CO_Tree::data
private

The vector that contains the data of the keys in the tree.

If index[i] is unused_index, data[i] is unused. Otherwise, data[i] contains the data associated to the indexes[i] key.

Its size is reserved_size + 1, because the first element is not used (to allow using the same index in both indexes[] and data[] instead of adding 1 to access data[]).

Definition at line 1316 of file CO_Tree_defs.hh.

Referenced by copy_data_from(), external_memory_in_bytes(), m_swap(), move_data_from(), and Parma_Polyhedra_Library::CO_Tree::iterator::operator=().

std::allocator<data_type> Parma_Polyhedra_Library::CO_Tree::data_allocator
private

The allocator used to allocate/deallocate data.

Definition at line 1305 of file CO_Tree_defs.hh.

Referenced by CO_Tree(), m_swap(), and operator=().

dimension_type* Parma_Polyhedra_Library::CO_Tree::indexes
private

The vector that contains the keys in the tree.

If an element of this vector is unused_index , it means that that element and the corresponding element of data[] are not used.

Its size is reserved_size + 2, because the first and the last elements are used as markers for iterators.

Definition at line 1302 of file CO_Tree_defs.hh.

Referenced by Parma_Polyhedra_Library::CO_Tree::const_iterator::const_iterator(), copy_data_from(), count_used_in_subtree(), dfs_index(), external_memory_in_bytes(), fast_shift(), Parma_Polyhedra_Library::CO_Tree::iterator::iterator(), m_swap(), move_data_from(), and Parma_Polyhedra_Library::CO_Tree::iterator::operator=().

const dimension_type Parma_Polyhedra_Library::CO_Tree::max_density_percent = 91
staticprivate

The maximum density of used nodes.

This must be greater than or equal to 50 and lower than 100.

Definition at line 1255 of file CO_Tree_defs.hh.

Referenced by CO_Tree().

height_t Parma_Polyhedra_Library::CO_Tree::max_depth
private

The depth of the leaves in the complete tree.

Definition at line 1292 of file CO_Tree_defs.hh.

Referenced by m_swap().

const dimension_type Parma_Polyhedra_Library::CO_Tree::min_density_percent = 38
staticprivate

The minimum density of used nodes.

Must be strictly lower than the half of max_density_percent.

Definition at line 1261 of file CO_Tree_defs.hh.

const dimension_type Parma_Polyhedra_Library::CO_Tree::min_leaf_density_percent = 1
staticprivate

The minimum density at the leaves' depth.

Must be greater than zero and strictly lower than min_density_percent.

Increasing the value is safe but leads to time inefficiencies (measured against ppl_lpsol on 24 August 2010), because it forces trees to be more balanced, increasing the cost of rebalancing.

Definition at line 1271 of file CO_Tree_defs.hh.

dimension_type Parma_Polyhedra_Library::CO_Tree::reserved_size
private
dimension_type Parma_Polyhedra_Library::CO_Tree::size_
private

The number of values stored in the tree.

Definition at line 1326 of file CO_Tree_defs.hh.

Referenced by CO_Tree(), copy_data_from(), empty(), insert_in_empty_tree(), m_swap(), move_data_from(), and size().


The documentation for this class was generated from the following files: