BitMagic-C++
sample11.cpp
Go to the documentation of this file.
1/*
2Copyright(c) 2002-2017 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15
16For more information please visit: http://bitmagic.io
17*/
18
19/** \example sample11.cpp
20 Example of how to use various bit counting techniques
21
22 \sa bm::bvector::count()
23 \sa bm::bvector::count_range()
24 \sa bm::bvector::count_to()
25 \sa bm::bvector::count_to_test()
26 \sa bm::count_and()
27 \sa bm::bvector::counted_enumerator
28 */
29
30/*! \file sample11.cpp
31 \brief Example: bvector<> bit-counting techniques analysis
32*/
33
34#include <iostream>
35#include <random>
36#include <memory>
37
38#include "bm.h"
39#include "bmalgo.h"
40#include "bmtimer.h"
41#include "bmundef.h" /* clear the pre-proc defines from BM */
42
43using namespace std;
44
45// timing storage for benchmarking
47
48const unsigned benchmark_count = 10000;
49unsigned vector_max = 400000000;
50
51std::random_device rand_dev;
52std::mt19937 gen(rand_dev()); // mersenne_twister_engine
53std::uniform_int_distribution<> rand_dis(1, int(vector_max)); // generate uniform numebrs for [1, vector_max]
54
55
56/// generate pseudo-random bit-vector, mix of blocks
57///
58static
60{
62 for (i = 0; i < vector_max;)
63 {
64 // generate bit-blocks
65 for (j = 0; j < 65535*8; i += 10, j++)
66 {
67 bv.set(i);
68 }
69 if (i > vector_max)
70 break;
71 // generate GAP (compressed) blocks
72 for (j = 0; j < 65535; i += 120, j++)
73 {
74 unsigned len = rand() % 64;
75 bv.set_range(i, i + len);
76 i += len;
77 if (i > vector_max)
78 break;
79 }
80 }
81
82 // compress vector
84 bv.optimize(tb);
85
86 // compute bit-vector statistics
88 bv.calc_stat(&st);
89
90 std::cout << "Bit-vector statistics: GAP (compressed blocks)=" << st.gap_blocks
91 << ", BIT (uncompressed blocks)=" << st.bit_blocks
92 << std::endl << std::endl;
93}
94
95/// "pre-heat" CPU to minimize dynamic overclocking effects
96///
97static
99{
102 for (unsigned i = 0; i < benchmark_count; ++i)
103 {
104 cnt += bv.count();
105 m+=cnt*cnt;
106 }
107 return m;
108}
109
110
111
112/// simple population count for the whole vector
113///
114static
116{
118
119 {
120 bm::chrono_taker tt1(cout, "1. bvector<>::count()", benchmark_count / 2, &timing_map);
121 for (unsigned i = 0; i < benchmark_count / 2; ++i)
122 {
123 cnt += bv.count();
124 }
125 }
126 // this is mostly to prevent compiler to optimize loop away
127 std::cout << "Count test finished." << cnt << "\r";
128}
129
130/// count_range() test
131///
132static
134{
136 {
137 bm::chrono_taker tt1(cout, "2. bvector<>::count_range()", benchmark_count, &timing_map);
138 for (unsigned i = 0; i < benchmark_count; ++i)
139 {
140 unsigned from = unsigned(rand_dis(gen));
141 unsigned to = unsigned(rand_dis(gen));
142 if (from > to)
143 swap(from, to);
144 cnt += bv.count_range(from, to);
145 }
146 }
147 // this is mostly to prevent compiler to optimize loop away
148 std::cout << "Count range test finished." << cnt << "\r";
149}
150
151/// count_range() test using pre-calculated blocks bit count
152///
153static
155{
157
158 std::unique_ptr<bm::bvector<>::rs_index_type> rs(new bm::bvector<>::rs_index_type());
159 bv.build_rs_index(rs.get());
160
161 {
162 bm::chrono_taker tt1(cout, "3. bvector<>::count_range() with rs_index", benchmark_count, &timing_map);
163 cnt = 0;
164 for (unsigned i = 0; i < benchmark_count; ++i)
165 {
166 unsigned from = unsigned(rand_dis(gen));
167 unsigned to = unsigned(rand_dis(gen));
168 if (from > to)
169 swap(from, to);
170 cnt += bv.count_range(from, to, *rs); // use rs index for acceleration
171 } // for i
172 }
173 // this is mostly to prevent compiler to optimize loop away
174 std::cout << "Count range with blocks test finished." << cnt << "\r";
175}
176
177/// count_to() test using pre-calculated rank-select index
178///
179static
181{
183
184 // build a block population count list, used for count_to() acceleration
185 std::unique_ptr<bm::bvector<>::rs_index_type> rs(new bm::bvector<>::rs_index_type());
186 bv.build_rs_index(rs.get());
187
188 {
189 bm::chrono_taker tt1(cout, "4. bvector<>::count_to() with rs_index", benchmark_count, &timing_map);
190
191 for (unsigned i = 0; i < benchmark_count; ++i)
192 {
193 unsigned to = unsigned(rand_dis(gen));
194 cnt += bv.count_to(to, *rs); // use rank-select index for acceleration
195 }
196 }
197 // this is mostly to prevent compiler to optimize loop away
198 std::cout << "Count to with blocks test finished." << cnt << "\r";
199}
200
201
202/// count_range implemented via two count_to() calls using pre-calculated
203/// rank-select index
204///
205static
207{
209
210 // build a block population count list, used for count_to() acceleration
211 std::unique_ptr<bm::bvector<>::rs_index_type> rs(new bm::bvector<>::rs_index_type());
212 bv.build_rs_index(rs.get());
213
214 {
215 bm::chrono_taker tt1(cout, "5. bvector<>::count_to to simulate count_range()", benchmark_count, &timing_map);
216
217 for (unsigned i = 0; i < benchmark_count; ++i)
218 {
219 unsigned from = unsigned(rand_dis(gen));
220 unsigned to = unsigned(rand_dis(gen));
221 if (from > to)
222 swap(from, to);
223
224 bm::bvector<>::size_type cnt_to = bv.count_to(to, *rs);
225 bm::bvector<>::size_type cnt_from = bv.count_to(from - 1, *rs);
226 bm::bvector<>::size_type cnt_r = cnt_to - cnt_from;
227 cnt += cnt_r;
228 }
229 }
230 // this is mostly to prevent compiler to optimize loop away
231 std::cout << "Count range via count_to test finished." << cnt << "\r";
232}
233
234/// count_range implemented via bm::count_and
235///
236/// this method can be used, when we need co compute multiple ranges in one call
237///
238static
240{
242 {
243 bm::chrono_taker tt1(cout, "6. bm::count_and with mask vector", benchmark_count, &timing_map);
244
245 bm::bvector<> mask_bv(bm::BM_GAP); // use compressed mask, better seluts on long ranges
246 for (unsigned i = 0; i < benchmark_count; ++i)
247 {
248 unsigned from = unsigned(rand_dis(gen));
249 unsigned to = unsigned(rand_dis(gen));
250 if (from > to)
251 swap(from, to);
252
253 mask_bv.set_range(from, to, true); // set mask vector
254
255 cnt += bm::count_and(bv, mask_bv);
256 mask_bv.clear(true); // clear and free memory (faster)
257 }
258 }
259 // this is mostly to prevent compiler to optimize loop away
260 std::cout << "count AND finished." << cnt << "\r";
261}
262
263/// count_to implemented via bm::bvector<>::counted_enumerator
264///
265/// Counted enumerator is an iterator automata, which counts the running population count
266/// along the iteration sequence
267///
268static
270{
272 {
273 // This is a slow method so we use less iterators
274 bm::chrono_taker tt1(cout, "7. bm::bvector<>::counted_enumerator", benchmark_count/20, &timing_map);
275
276 for (unsigned i = 0; i < benchmark_count/20; ++i)
277 {
278 unsigned to = unsigned(rand_dis(gen));
280 for (; en.valid(); ++en)
281 {
282 if (*en > to)
283 break;
284 }
285 cnt += en.count();
286 }
287 }
288 std::cout << "counted_enumerator finished." << cnt << "\r";
289}
290
291
292
293
294int main(void)
295{
296 try
297 {
298 bm::bvector<> bv;
300
301 /// pre-heat CPU to minimize dynamic overclocking
302 unsigned s = pre_heat(bv);
303 std::cout << s << "\r";
304
305
306 // Test 1.
307 // Uses plain bvector<>::count() to compute global population count
308 // This function would benefit from SIMD (SSE42 / AVX2) acceleration
309 //
310 bv_count_test(bv);
311
312 // Test 2.
313 // Uses bvector<>::count_range() to compute population count in a randomly generated
314 // region of a bit-vector.
315 // This is should be naturally faster than Test 1, because it range is less than the whole
316 //
317 bv_count_range(bv);
318
319 // Test 3.
320 // Uses bvector<>::count_range() together with bvector<>::count_blocks()
321 // (pre-calculated bit-count for each block).
322 // It make sense to use this method if bit-vector is constant (or chnages infrequently)
323 // and we need to do many range counting calculations
324 //
326
327 // Test 4.
328 // Uses bvector<>::count_to() to compute population count to a specified element.
329 // Equivalent of count_range(0, to);
330 // This method uses acceleration structure using bvector<>::running_count_blocks()
331 // It is similar to count_range acceleration, but uses a different (faster) algorithm
332 //
333 bv_count_to_acc(bv);
334
335 // Test 5.
336 // Uses bvector<>::count_to() twice to simulate count_range()
337 // using counting difference:
338 // count_r = count_to(0, from) - count_to(0, to-1)
339 // This method can actually be faster than count_range()
340 //
342
343 // Test 6.
344 // Compute range population count via a mask vector and logical AND operation.
345 // Not the fastest method, but can be useful, when multiple ranges needs to be computed
346 //
347 bv_count_and(bv);
348
349 // Test 7.
350 // Compute cout using counted_enumerator iterator
351 // method combines iteratrion over bit vector and sliding population count
353
354
355 // print all test timing results
356 //
357 std::cout << " "
358 << std::endl;
359
361 }
362 catch(std::exception& ex)
363 {
364 std::cerr << ex.what() << std::endl;
365 return 1;
366 }
367
368 return 0;
369}
370
Compressed bit-vector bvector<> container, set algebraic methods, traversal iterators.
#define BM_DECLARE_TEMP_BLOCK(x)
Definition: bm.h:47
Algorithms for bvector<> (main include)
Timing utilities for benchmarking (internal)
pre-processor un-defines to avoid global space pollution (internal)
Constant iterator designed to enumerate "ON" bits counted_enumerator keeps bitcount,...
Definition: bm.h:734
size_type count() const BMNOEXCEPT
Number of bits ON starting from the .
Definition: bm.h:775
bool valid() const BMNOEXCEPT
Checks if iterator is still valid.
Definition: bm.h:283
Bitvector Bit-vector container with runtime compression of bits.
Definition: bm.h:115
size_type count() const BMNOEXCEPT
population count (count of ON bits)
Definition: bm.h:2366
bvector< Alloc > & set(size_type n, bool val=true)
Sets bit n if val is true, clears bit n if val is false.
Definition: bm.h:4153
void optimize(bm::word_t *temp_block=0, optmode opt_mode=opt_compress, statistics *stat=0)
Optimize memory bitvector's memory allocation.
Definition: bm.h:3600
bvector_size_type size_type
Definition: bm.h:121
enumerator first() const
Returns enumerator pointing on the first non-zero bit.
Definition: bm.h:1849
size_type count_range(size_type left, size_type right, const rs_index_type &rs_idx) const BMNOEXCEPT
Returns count of 1 bits in the given range [left..right] Uses rank-select index to accelerate the sea...
Definition: bm.h:3481
bvector< Alloc > & set_range(size_type left, size_type right, bool value=true)
Sets all bits in the specified closed interval [left,right] Interval must be inside the bvector's siz...
Definition: bm.h:2333
void clear(const size_type *ids, size_type ids_size, bm::sort_order so=bm::BM_UNKNOWN)
clear list of bits in this bitset
Definition: bm.h:4114
rs_index< allocator_type > rs_index_type
Definition: bm.h:816
size_type count_to(size_type n, const rs_index_type &rs_idx) const BMNOEXCEPT
Returns count of 1 bits (population) in [0..right] range.
Definition: bm.h:3053
void build_rs_index(rs_index_type *rs_idx, bvector< Alloc > *bv_blocks=0) const
compute running total of all blocks in bit vector (rank-select index)
Definition: bm.h:2466
void calc_stat(struct bm::bvector< Alloc >::statistics *st) const BMNOEXCEPT
Calculates bitvector statistics.
Definition: bm.h:3943
Utility class to collect performance measurements and statistics.
Definition: bmtimer.h:41
std::map< std::string, statistics > duration_map_type
test name to duration map
Definition: bmtimer.h:66
static void print_duration_map(TOut &tout, const duration_map_type &dmap, format fmt=ct_time)
Definition: bmtimer.h:150
@ BM_GAP
GAP compression is ON.
Definition: bmconst.h:147
BV::size_type count_and(const BV &bv1, const BV &bv2) BMNOEXCEPT
Computes bitcount of AND operation of two bitsets.
Definition: bmalgo.h:49
unsigned vector_max
Definition: sample11.cpp:49
const unsigned benchmark_count
Definition: sample11.cpp:48
static void bv_count_range(const bm::bvector<> &bv)
count_range() test
Definition: sample11.cpp:133
static bm::bvector ::size_type pre_heat(const bm::bvector<> &bv)
"pre-heat" CPU to minimize dynamic overclocking effects
Definition: sample11.cpp:98
static void bv_count_to_range_acc(const bm::bvector<> &bv)
count_range implemented via two count_to() calls using pre-calculated rank-select index
Definition: sample11.cpp:206
std::random_device rand_dev
Definition: sample11.cpp:51
static void bv_count_range_acc(const bm::bvector<> &bv)
count_range() test using pre-calculated blocks bit count
Definition: sample11.cpp:154
int main(void)
Definition: sample11.cpp:294
std::uniform_int_distribution rand_dis(1, int(vector_max))
bm::chrono_taker ::duration_map_type timing_map
Definition: sample11.cpp:46
std::mt19937 gen(rand_dev())
static void bv_count_test(const bm::bvector<> &bv)
simple population count for the whole vector
Definition: sample11.cpp:115
static void generate_bvector(bm::bvector<> &bv)
generate pseudo-random bit-vector, mix of blocks
Definition: sample11.cpp:59
static void bv_count_and(const bm::bvector<> &bv)
count_range implemented via bm::count_and
Definition: sample11.cpp:239
static void bv_count_to_acc(const bm::bvector<> &bv)
count_to() test using pre-calculated rank-select index
Definition: sample11.cpp:180
static void bv_counted_enumerator(const bm::bvector<> &bv)
count_to implemented via bm::bvector<>::counted_enumerator
Definition: sample11.cpp:269
size_t gap_blocks
Number of GAP blocks.
Definition: bmfunc.h:58
size_t bit_blocks
Number of bit blocks.
Definition: bmfunc.h:57
Statistical information about bitset's memory allocation details.
Definition: bm.h:125