STXXL  1.4-dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
winner_tree.h
Go to the documentation of this file.
1 /***************************************************************************
2  * include/stxxl/bits/common/winner_tree.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2014 Thomas Keh <[email protected]>
7  * Copyright (C) 2014 Timo Bingmann <[email protected]>
8  *
9  * Distributed under the Boost Software License, Version 1.0.
10  * (See accompanying file LICENSE_1_0.txt or copy at
11  * http://www.boost.org/LICENSE_1_0.txt)
12  **************************************************************************/
13 
14 #ifndef STXXL_COMMON_WINNER_TREE_HEADER
15 #define STXXL_COMMON_WINNER_TREE_HEADER
16 
17 #include <vector>
18 #include <limits>
19 
22 #include <stxxl/bits/verbose.h>
23 
25 
26 /*!
27  * The class winner_tree is a binary tournament tree. There are n=2^k so
28  * called players which compete for the winning position. The winner is the
29  * smallest one regarding the comparator m_less. Each player is identified with
30  * it's index. The comparator should use this index in order to compare the
31  * actual values.
32  *
33  * A change of one players value results in O(log n) operations. The winner
34  * can be determined in O(1) operations.
35  *
36  * There is a number of fixed players which remain at the same index forever,
37  * even if they were deactivated in between. Additionally any number of players
38  * can be added dynamically. They are assigned to a free slot and if one gets
39  * removed the slot will be marked free again.
40  */
41 template <typename Comparator>
43 {
44 protected:
45  //! the binary tree of size 2^(k+1)-1
46  std::vector<unsigned_type> m_tree;
47 
48  //! the comparator object of this tree
49  Comparator& m_less;
50 
51  //! number of slots for the players (2^k)
53 
54  //! Defines if statistics are gathered: fake_timer or timer
56 
57  //! Collection of stats from the winner_tree
58  struct stats_type
59  {
63 
64  friend std::ostream& operator << (std::ostream& os, const stats_type& o)
65  {
66  return os << "replay_time=" << o.replay_time << std::endl
67  << "double_num_slots_time=" << o.double_num_slots_time << std::endl
68  << "remove_player_time=" << o.remove_player_time << std::endl;
69  }
70  };
71 
72  //! Collection of stats from the winner_tree
73  stats_type m_stats;
74 
76 
77 public:
78  /**
79  * Constructor. Reserves space, registers free slots. No games are played
80  * here! All players and slots are deactivated in the beginning.
81  *
82  * \param num_players Number of fixed players. Fixed players remain at the
83  * same index forever, even if they were deactivated in between.
84  *
85  * \param less The comparator. It should use two given indices, compare the
86  * corresponding values and return the index of one with the smaller value.
87  */
88  winner_tree(unsigned_type num_players, Comparator& less)
89  : m_less(less)
90  {
91  STXXL_ASSERT(num_players > 0 && num_players <= invalid_key);
92 
93  m_num_slots = (1 << ilog2_ceil(num_players));
94  unsigned_type treesize = (m_num_slots << 1) - 1;
95  m_tree.resize(treesize, invalid_key);
96  }
97 
98  //! activate one of the static players or add a new one and replay
99  inline void activate_player(unsigned_type index)
100  {
101  STXXL_ASSERT(index != invalid_key);
102  while (index >= m_num_slots)
103  double_num_slots();
104  replay_on_change(index);
105  }
106 
107  //! activate a player and resize if necessary
109  {
110  STXXL_ASSERT(index != invalid_key);
111  while (index >= m_num_slots)
112  double_num_slots();
113  m_tree[((m_tree.size() / 2) + index)] = index;
114  }
115 
116  //! deactivate a player
118  {
119  STXXL_ASSERT(index != invalid_key);
120  STXXL_ASSERT(index < m_num_slots);
121  m_tree[((m_tree.size() / 2) + index)] = invalid_key;
122  }
123 
124  //! deactivate a player and replay.
125  inline void deactivate_player(unsigned_type index)
126  {
127  STXXL_ASSERT(index != invalid_key);
128  STXXL_ASSERT(index < m_num_slots);
129  replay_on_change(index, true);
130  }
131 
132  /**
133  * deactivate one player in a batch of deactivations run
134  * replay_on_deactivation() afterwards. If there are multiple consecutive
135  * removes you should run deactivate_player_step() for all of them first and
136  * afterwards run replay_on_deactivation() for each one of them.
137  */
139  {
140  STXXL_ASSERT(index != invalid_key);
141  STXXL_ASSERT(index < m_num_slots);
142 
143  m_stats.remove_player_time.start();
144  unsigned_type p = (m_tree.size() / 2) + index;
145 
146  // Needed for following deactivations...
147  while (p > 0 && m_tree[p] == index) {
148  m_tree[p] = invalid_key;
149  p -= (p + 1) % 2; // move to left sibling if necessary
150  p /= 2; // move to parent
151  }
152 
153  if (m_tree[0] == index)
154  m_tree[0] = invalid_key;
155 
156  m_stats.remove_player_time.stop();
157  }
158 
159  //! Replay after the player at index has been deactivated.
161  {
162  STXXL_ASSERT(index != invalid_key);
163  STXXL_ASSERT(index < m_num_slots);
164  replay_on_change(index, true);
165  }
166 
167  //! Notify that the value of the player at index has changed.
168  inline void notify_change(unsigned_type index)
169  {
170  STXXL_ASSERT(index != invalid_key);
171  replay_on_change(index);
172  }
173 
174  //! Returns the winner.
175  //! Remember running replay_on_pop() if the value of the winner changes.
176  inline unsigned_type top() const
177  {
178  return m_tree[0];
179  }
180 
181  //! Returns if all players are deactivated.
182  inline bool empty() const
183  {
184  return (m_tree[0] == invalid_key);
185  }
186 
187  //! Return the current number of slots
188  size_t num_slots() const
189  {
190  return m_num_slots;
191  }
192 
193  //! Replay after the value of the winning player has changed.
194  inline void replay_on_pop()
195  {
196  STXXL_ASSERT(!empty());
197  replay_on_change(m_tree[0]);
198  }
199 
200  /**
201  * Replays all games the player with the given index is involved in. This
202  * corresponds to the path from leaf [index] to root. If only the value of
203  * player [index] has changed the result is a valid winner tree.
204  *
205  * \param index The player whose value has changed.
206  *
207  * \param done Set done to true if the player has been deactivated
208  * or removed. All games will be lost then.
209  */
210  inline void replay_on_change(unsigned_type index, bool done = false)
211  {
212  STXXL_ASSERT(index != invalid_key);
213  m_stats.replay_time.start();
214 
215  unsigned_type top;
216  unsigned_type p = (m_tree.size() / 2) + index;
217 
218  if (!done)
219  top = index;
220  else
221  top = invalid_key;
222 
223  while (p > 0) {
224  m_tree[p] = top;
225  p -= (p + 1) % 2; // round down to left node position
226 
227  if (m_tree[p] == invalid_key)
228  top = m_tree[p + 1];
229  else if (m_tree[p + 1] == invalid_key)
230  top = m_tree[p];
231  else if (m_less(m_tree[p], m_tree[p + 1]))
232  top = m_tree[p];
233  else
234  top = m_tree[p + 1];
235 
236  p /= 2;
237  }
238 
239  m_tree[p] = top;
240  m_stats.replay_time.stop();
241  }
242 
243  //! Doubles the number of slots and adapts the tree so it's a valid winner
244  //! tree again.
245  inline void double_num_slots()
246  {
247  m_stats.double_num_slots_time.start();
248 
249  m_num_slots = m_num_slots << 1;
250  size_t old_tree_size = m_tree.size();
251  size_t tree_size = (m_num_slots << 1) - 1;
252  m_tree.resize(tree_size, invalid_key);
253 
254  for (unsigned_type i = old_tree_size - 1; i >= 0; --i) {
255  size_t old_index = i;
256  size_t old_level = ilog2_floor(old_index + 1);
257  size_t new_index = old_index + (1 << old_level);
258  m_tree[new_index] = m_tree[old_index];
259  }
260 
261  size_t step_size = (1 << ilog2_floor(old_tree_size));
262  size_t index = tree_size - 1;
263 
264  while (step_size > 0) {
265  for (size_t i = 0; i < step_size; ++i) {
266  m_tree[index] = invalid_key;
267  --index;
268  }
269  index -= step_size;
270  step_size /= 2;
271  }
272 
273  m_stats.double_num_slots_time.stop();
274  }
275 
276  //! Deactivate all players
277  inline void clear()
278  {
279  std::fill(m_tree.begin(), m_tree.end(), invalid_key);
280  }
281 
282  inline void resize(unsigned_type num_players)
283  {
284  m_num_slots = (1 << ilog2_ceil(num_players));
285  unsigned_type treesize = (m_num_slots << 1) - 1;
286  m_tree.resize(treesize, invalid_key);
287  }
288 
289  //! Deactivate all players and resize the tree.
290  inline void resize_and_clear(unsigned_type num_players)
291  {
292  resize(num_players);
293  clear();
294  }
295 
296  inline void resize_and_rebuild(unsigned_type num_players)
297  {
298  //resize(num_players);
299  STXXL_ASSERT(num_players > 0);
300  resize_and_clear(num_players);
301  for (unsigned_type i = 0; i < num_players; ++i)
302  activate_without_replay(i);
303  //for (unsigned_type i=num_players; i<m_num_slots; ++i)
304  // deactivate_without_replay(i);
305  rebuild();
306  }
307 
308  //! Build from winner tree from scratch.
309  inline void rebuild()
310  {
311  unsigned_type i = (m_tree.size() / 2);
312 
313  if (i == 0)
314  return;
315 
316  do {
317  --i;
318  const unsigned_type lc = i * 2 + 1; // m_tree.size() is uneven -> index OK
319  const unsigned_type rc = i * 2 + 2;
320  unsigned_type winner;
321 
322  if (m_tree[lc] == invalid_key)
323  winner = m_tree[rc];
324  else if (m_tree[rc] == invalid_key)
325  winner = m_tree[lc];
326  else if (m_less(m_tree[lc], m_tree[rc]))
327  winner = m_tree[lc];
328  else
329  winner = m_tree[rc];
330 
331  m_tree[i] = winner;
332  } while (i > 0);
333  }
334 
335  //! Returns a readable representation of the winner tree as string.
336  std::string to_string() const
337  {
338  std::ostringstream ss;
339  unsigned_type levelsize = 1;
340  unsigned_type j = 0;
341  for (unsigned_type i = 0; i < m_tree.size(); ++i) {
342  if (i >= j + levelsize) {
343  ss << "\n";
344  j = i;
345  levelsize *= 2;
346  }
347  if (m_tree[i] != invalid_key)
348  ss << m_tree[i] << " ";
349  else
350  ss << "~ ";
351  }
352  ss << "\n";
353  return ss.str();
354  }
355 
356  //! Print statistical data.
357  void print_stats() const
358  {
359  STXXL_VARDUMP(m_num_slots);
360  STXXL_MSG(m_stats);
361  }
362 };
363 
365 
366 #endif // !STXXL_COMMON_WINNER_TREE_HEADER
void double_num_slots()
Doubles the number of slots and adapts the tree so it&#39;s a valid winner tree again.
Definition: winner_tree.h:245
#define STXXL_ASSERT(condition)
Definition: verbose.h:220
friend std::ostream & operator<<(std::ostream &os, const uint_pair &a)
make a uint_pair outputtable via iostreams, using unsigned long long.
Definition: uint_types.h:228
std::string to_string() const
Returns a readable representation of the winner tree as string.
Definition: winner_tree.h:336
void replay_on_pop()
Replay after the value of the winning player has changed.
Definition: winner_tree.h:194
stats_type m_stats
Collection of stats from the winner_tree.
Definition: winner_tree.h:73
void activate_player(unsigned_type index)
activate one of the static players or add a new one and replay
Definition: winner_tree.h:99
void deactivate_player(unsigned_type index)
deactivate a player and replay.
Definition: winner_tree.h:125
Comparator & m_less
the comparator object of this tree
Definition: winner_tree.h:49
The class winner_tree is a binary tournament tree.
Definition: winner_tree.h:42
void notify_change(unsigned_type index)
Notify that the value of the player at index has changed.
Definition: winner_tree.h:168
void replay_on_change(unsigned_type index, bool done=false)
Definition: winner_tree.h:210
bool empty() const
Returns if all players are deactivated.
Definition: winner_tree.h:182
Class fake_timer is a drop-in replacement for timer, which does nothing.
Definition: timer.h:170
void clear()
Deactivate all players.
Definition: winner_tree.h:277
void deactivate_player_step(unsigned_type index)
Definition: winner_tree.h:138
size_t num_slots() const
Return the current number of slots.
Definition: winner_tree.h:188
unsigned_type top() const
Returns the winner. Remember running replay_on_pop() if the value of the winner changes.
Definition: winner_tree.h:176
unsigned_type m_num_slots
number of slots for the players (2^k)
Definition: winner_tree.h:52
void activate_without_replay(unsigned_type index)
activate a player and resize if necessary
Definition: winner_tree.h:108
winner_tree(unsigned_type num_players, Comparator &less)
Definition: winner_tree.h:88
void resize_and_rebuild(unsigned_type num_players)
Definition: winner_tree.h:296
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
void resize(unsigned_type num_players)
Definition: winner_tree.h:282
void rebuild()
Build from winner tree from scratch.
Definition: winner_tree.h:309
static uint_pair max()
return an uint_pair instance containing the largest value possible
Definition: uint_types.h:241
std::vector< unsigned_type > m_tree
the binary tree of size 2^(k+1)-1
Definition: winner_tree.h:46
#define STXXL_VARDUMP(x)
Definition: verbose.h:81
unsigned int ilog2_floor(IntegerType i)
calculate the log2 floor of an integer type (by repeated bit shifts)
Definition: utils.h:178
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
Definition: types.h:64
unsigned int ilog2_ceil(const IntegerType &i)
calculate the log2 ceiling of an integer type (by repeated bit shifts)
Definition: utils.h:188
#define STXXL_MSG(x)
Definition: verbose.h:73
void resize_and_clear(unsigned_type num_players)
Deactivate all players and resize the tree.
Definition: winner_tree.h:290
void replay_on_deactivations(unsigned_type index)
Replay after the player at index has been deactivated.
Definition: winner_tree.h:160
fake_timer stats_timer
Defines if statistics are gathered: fake_timer or timer.
Definition: winner_tree.h:55
Collection of stats from the winner_tree.
Definition: winner_tree.h:58
void print_stats() const
Print statistical data.
Definition: winner_tree.h:357
void deactivate_without_replay(unsigned_type index)
deactivate a player
Definition: winner_tree.h:117
#define STXXL_END_NAMESPACE
Definition: namespace.h:17