BitMagic-C++
bmaggregator.h
Go to the documentation of this file.
1#ifndef BMAGGREGATOR__H__INCLUDED__
2#define BMAGGREGATOR__H__INCLUDED__
3/*
4Copyright(c) 2002-2017 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18For more information please visit: http://bitmagic.io
19*/
20
21/*! \file bmaggregator.h
22 \brief Algorithms for fast aggregation of N bvectors
23*/
24
25
26#ifndef BM__H__INCLUDED__
27// BitMagic utility headers do not include main "bm.h" declaration
28// #include "bm.h" or "bm64.h" explicitly
29# error missing include (bm.h or bm64.h)
30#endif
31
32#include <stdio.h>
33#include <string.h>
34
35
36#include "bmfunc.h"
37#include "bmdef.h"
38
39#include "bmalgo_impl.h"
40#include "bmbuffer.h"
41
42
43namespace bm
44{
45
46/*! @name Aggregator traits and control constants
47 @ingroup setalgo
48*/
49//@{
50
52const bool agg_disable_result_bvectors = false;
53const bool agg_compute_counts = true;
54const bool agg_disable_counts = false;
55const bool agg_disable_search_masks = false;
56
57/**
58 Aggregation options to control execution
59 Default settings are to support only result bit-vector filters.
60 @ingroup setalgo
61 */
62template <bool OBvects=bm::agg_produce_result_bvectors,
63 bool OCounts=bm::agg_disable_counts,
64 bool OSearchMasks=bm::agg_disable_search_masks>
66{
67 /// make result(target) vectors (aggregation search results) (Default: true)
68 /// when false is used - means we want to only collect statistics (counts) for the targets
69 static constexpr bool is_make_results() BMNOEXCEPT { return OBvects; }
70
71 /// Compute counts for the target vectors, when set to true, population count is computed for
72 /// each result, results itself can be omitted (make_results flag set to false)
73 static constexpr bool is_compute_counts() BMNOEXCEPT { return OCounts; }
74
75 /// Support for masking operations (Default: false)
76 ///
77 static constexpr bool is_masks() BMNOEXCEPT { return OSearchMasks; }
78};
79
80/**
81 Pre-defined aggregator options to disable both intermediate results and counts
82 @ingroup setalgo
83 */
84typedef
87
88
89/**
90 Pre-defined aggregator options for counts-only (results dropped) operation
91 @ingroup setalgo
92 */
93typedef
96
97/**
98 Pre-defined aggregator options for results plus counts operation
99 @ingroup setalgo
100 */
101typedef
104
105//@}
106
107/**
108 Algorithms for fast aggregation of a group of bit-vectors
109
110 Algorithms of this class use cache locality optimizations and efficient
111 on cases, wehen we need to apply the same logical operation (aggregate)
112 more than 2x vectors.
113
114 TARGET = BV1 or BV2 or BV3 or BV4 ...
115
116 Aggregator supports OR, AND and AND-MINUS (AND-SUB) operations
117
118 @ingroup setalgo
119*/
120template<typename BV>
122{
123public:
124 typedef BV bvector_type;
125 typedef typename BV::size_type size_type;
126 typedef typename BV::allocator_type allocator_type;
129
131 typedef
132 bm::heap_vector<bvector_type_const_ptr, allocator_type, true> bv_vector_type;
133 typedef
134 bm::heap_vector<bvector_type*, allocator_type, true> bvect_vector_type;
135 typedef
136 bm::heap_vector<size_t, allocator_type, true> index_vector_type;
137
138
139 /// Codes for aggregation operations which can be pipelined for efficient execution
140 ///
142 {
145 };
146
148 {
152 op_done
153 };
154
155 /// Aggregator arg groups
157 {
158 bv_vector_type arg_bv0; ///< arg group 0
159 bv_vector_type arg_bv1; ///< arg group 1
160 index_vector_type arg_idx0; ///< indexes of vectors for arg group 0
162
163 /// Reset argument groups to zero
164 void reset()
165 {
166 arg_bv0.resize(0); // TODO: use reset not resize(0)
167 arg_bv1.resize(0);
168 arg_idx0.resize(0);
169 arg_idx1.resize(0);
170 }
171
172 /** Add bit-vector pointer to its aggregation group
173 \param bv - input bit-vector pointer to attach
174 \param agr_group - input argument group index (0 - default, 1 - fused op)
175
176 @return current arg group size (0 if vector was not added (empty))
177 */
178 size_t add(const bvector_type* bv, unsigned agr_group);
179 };
180
182 typedef
183 bm::heap_vector<arg_groups_type_ptr, allocator_type, true> arg_vector_type;
184 typedef
185 bm::heap_vector<unsigned, allocator_type, true> count_vector_type;
186 typedef
187 bm::heap_vector<size_type, allocator_type, true> bv_count_vector_type;
188 typedef
189 bm::heap_vector<bm::word_t*, allocator_type, true> blockptr_vector_type;
190 typedef
191 bm::heap_vector<bm::pair<unsigned, unsigned>, allocator_type, true> block_ij_vector_type;
192
193 /**
194 Block cache for pipeline execution
195 @internal
196 */
198 {
199 bv_vector_type bv_inp_vect_; ///< all input vectors from all groups
200 count_vector_type cnt_vect_; ///< usage count for bv_inp (all groups)
201 blockptr_vector_type blk_vect_; ///< cached block ptrs for bv_inp_vect_
202 block_ij_vector_type blk_ij_vect_; ///< current block coords
203 };
204
205 /**
206 Aggregation options for runtime control
207 */
209 {
210 /// Batch size sets number of argument groups processed at a time
211 /// Default: 0 means this parameter will be determined automatically
212 size_t batch_size = 0;
213 };
214
215 /**
216 Pipeline vector for running a group of aggregation operations on a family of vectors.
217 Pipeline is used to run multiple aggregation combinations (searches) for essencially same
218 set of vectors (different combinations of ANDs and SUBs for example).
219 Pipeline execution improves CPU cache reuse and caches the compressed blocks to re-use it
220 for more efficient execution. Essencially it is a tool to run thousads of runs at once faster.
221 */
222 template<class Opt = bm::agg_run_options<> >
224 {
225 public:
226 typedef Opt options_type;
227 public:
230
231 /// Set pipeline run options
233
234 /// Get pipeline run options
235 const run_options& get_options() const BMNOEXCEPT { return options_; }
236
237
238 // ------------------------------------------------------------------
239 /*! @name pipeline argument groups fill-in methods */
240 //@{
241
242 /** Add new arguments group
243 */
244 arg_groups* add();
245
246 /**
247 Attach OR (aggregator vector).
248 Pipeline results all will be OR-ed (UNION) into the OR target vector
249 @param bv_or - OR target vector
250 */
252 { bv_or_target_ = bv_or; }
253
254 /**
255 Set search limit for results. Requires that bit-counting to be enabled in the template parameters.
256 Warning: search limit is approximate (for performance reasons) so it can occasinally find more
257 than requested. It cannot find less.
258 @param limit - search limit (target population count to search for)
259 */
261 { search_count_limit_ = limit; }
262
263 /** Prepare pipeline for the execution (resize and init internal structures)
264 Once complete, you cannot add() to it.
265 */
266 void complete();
267
268 /** return true if pipeline is ready for execution (complete) */
269 bool is_complete() const BMNOEXCEPT { return is_complete_; }
270
271 /**Return size() of pileine */
272 size_type size() const BMNOEXCEPT { return arg_vect_.size(); }
273
274 //@}
275
276 // ------------------------------------------------------------------
277
278 /** Return argument vector used for pipeline execution */
280 { return arg_vect_; }
281
282 /** Return results vector used for pipeline execution */
284 { return bv_res_vect_; }
285
286 /** Return results vector count used for pipeline execution */
288 { return count_res_vect_; }
289
290
291 // ------------------------------------------------------------------
292 /*! @name access to internals */
293 //@{
294
296 { return bcache_.bv_inp_vect_; }
298 { return bcache_.cnt_vect_; }
299
300 /// Return number of unique vectors in the pipeline (after complete())
302 { return bcache_.bv_inp_vect_.size(); }
303
304 /// Function looks at the pipeline to apply euristics to suggest optimal run_batch parameter
306 //@}
307
308 protected:
309 /** @internal */
311 { return bcache_; }
312 /** Return number of top blocks after complete
313 @internal
314 */
315 unsigned get_top_blocks() const BMNOEXCEPT { return top_blocks_; }
316
317 private:
318 void complete_arg_group(arg_groups* ag);
319 void complete_arg_sub_group(index_vector_type& idx_vect,
320 const bvector_type_const_ptr* bv_src, size_t size);
321
322 protected:
323 friend class aggregator;
324
325 pipeline(const pipeline&) = delete;
326 pipeline& operator=(const pipeline&) = delete;
327
328 protected:
329 run_options options_; ///< execution parameters
330 bool is_complete_ = false; ///< ready to run state flag
331 size_t total_vect_= 0; ///< total number of vector mentions in all groups
332 arg_vector_type arg_vect_; ///< input arg. groups
333
334 bvect_vector_type bv_res_vect_; ///< results (bit-vector ptrs)
336 size_type search_count_limit_{bm::id_max}; ///< search limit by count
337
338 pipeline_bcache bcache_; ///< blocks cache structure
339 unsigned top_blocks_ = 1; ///< top-level structure size, max of all bvectors
340 bvector_type* bv_or_target_ = 0; ///< OR target bit-bector ptr
341 };
342
343public:
344
345 // -----------------------------------------------------------------------
346 /*! @name Construction and setup */
347 //@{
350
351 /**
352 \brief set on-the-fly bit-block compression
353 By default aggregator does not try to optimize result, but in some cases
354 it can be quite a lot faster than calling bvector<>::optimize() later
355 (because block data sits in CPU cache).
356
357 \param opt - optimization mode (full compression by default)
358 */
361 { opt_mode_ = opt; }
362
363 void set_compute_count(bool count_mode) BMNOEXCEPT
364 { compute_count_ = count_mode; count_ = 0; }
365
366 //@}
367
368
369 // -----------------------------------------------------------------------
370
371 /*! @name Methods to setup argument groups and run operations on groups */
372 //@{
373
374 /**
375 Attach source bit-vector to a argument group (0 or 1).
376 Arg group 1 used for fused operations like (AND-SUB)
377 \param bv - input bit-vector pointer to attach
378 \param agr_group - input argument group (0 - default, 1 - fused op)
379
380 @return current arg group size (0 if vector was not added (empty))
381 @sa reset
382 */
383 size_t add(const bvector_type* bv, unsigned agr_group = 0);
384
385 /**
386 Reset aggregate groups, forget all attached vectors
387 */
388 void reset();
389
390 /**
391 Aggregate added group of vectors using logical OR
392 Operation does NOT perform an explicit reset of arg group(s)
393
394 \param bv_target - target vector (input is arg group 0)
395
396 @sa add, reset
397 */
398 void combine_or(bvector_type& bv_target);
399
400 /**
401 Aggregate added group of vectors using logical AND
402 Operation does NOT perform an explicit reset of arg group(s)
403
404 \param bv_target - target vector (input is arg group 0)
405
406 @sa add, reset
407 */
408 void combine_and(bvector_type& bv_target);
409
410 /**
411 Aggregate added group of vectors using fused logical AND-SUB
412 Operation does NOT perform an explicit reset of arg group(s)
413
414 \param bv_target - target vector (input is arg group 0(AND), 1(SUB) )
415
416 \return true if anything was found
417
418 @sa add, reset
419 */
421
422 /**
423 Run AND-SUB: AND (groups1) AND NOT ( OR(group0)) for a pipeline
424 @param pipe - pipeline to run (should be prepared, filled and complete
425 */
426 template<class TPipe>
427 void combine_and_sub(TPipe& pipe);
428
429
430
431 /**
432 Aggregate added group of vectors using fused logical AND-SUB
433 Operation does NOT perform an explicit reset of arg group(s)
434 Operation can terminate early if anything was found.
435
436 \param bv_target - target vector (input is arg group 0(AND), 1(SUB) )
437 \param any - if true, search result will terminate of first found result
438
439 \return true if anything was found
440
441 @sa add, reset, find_first_and_sub
442 */
443 bool combine_and_sub(bvector_type& bv_target, bool any);
444
445 /**
446 Aggregate added group of vectors using fused logical AND-SUB.
447 search traget is back_inserter
448 */
449 template<typename BII>
450 bool combine_and_sub_bi(BII bi);
451
452 /**
453 Aggregate added group of vectors using fused logical AND-SUB,
454 find the first match
455
456 \param idx - [out] index of the first occurence
457 \return true if anything was found
458 @sa combine_and_sub
459 */
461
462
463 /**
464 Aggregate added group of vectors using SHIFT-RIGHT and logical AND
465 Operation does NOT perform an explicit reset of arg group(s)
466
467 \param bv_target - target vector (input is arg group 0)
468
469 @return bool if anything was found
470
471 @sa add, reset
472 */
474
475 /**
476 Set search hint for the range, where results needs to be searched
477 (experimental for internal use).
478 @internal
479 */
481
482 /**
483 Reset range hint to false
484 */
486
487 size_type count() const { return count_; }
488
489 //@}
490
491 // -----------------------------------------------------------------------
492
493 /*! @name Logical operations (C-style interface) */
494 //@{
495
496 /**
497 Aggregate group of vectors using logical OR
498 \param bv_target - target vector
499 \param bv_src - array of pointers on bit-vector aggregate arguments
500 \param src_size - size of bv_src (how many vectors to aggregate)
501 */
502 void combine_or(bvector_type& bv_target,
503 const bvector_type_const_ptr* bv_src, size_t src_size);
504
505 /**
506 Aggregate group of vectors using logical AND
507 \param bv_target - target vector
508 \param bv_src - array of pointers on bit-vector aggregate arguments
509 \param src_size - size of bv_src (how many vectors to aggregate)
510 */
511 void combine_and(bvector_type& bv_target,
512 const bvector_type_const_ptr* bv_src, size_t src_size);
513
514 /**
515 Fusion aggregate group of vectors using logical AND MINUS another set
516
517 \param bv_target - target vector
518 \param bv_src_and - array of pointers on bit-vectors for AND
519 \param src_and_size - size of AND group
520 \param bv_src_sub - array of pointers on bit-vectors for SUBstract
521 \param src_sub_size - size of SUB group
522 \param any - flag if caller needs any results asap (incomplete results)
523
524 \return true when found
525 */
527 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
528 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size,
529 bool any);
530
531 template<typename BII>
532 bool combine_and_sub(BII bi,
533 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
534 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size);
535
536
538 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
539 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size);
540
541 /**
542 Fusion aggregate group of vectors using SHIFT right with AND
543
544 \param bv_target - target vector
545 \param bv_src_and - array of pointers on bit-vectors for AND masking
546 \param src_and_size - size of AND group
547 \param any - flag if caller needs any results asap (incomplete results)
548
549 \return true when found
550 */
552 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
553 bool any);
554
555
556 //@}
557
558 // -----------------------------------------------------------------------
559
560 /*! @name Horizontal Logical operations used for tests (C-style interface) */
561 //@{
562
563 /**
564 Horizontal OR aggregation (potentially slower) method.
565 \param bv_target - target vector
566 \param bv_src - array of pointers on bit-vector aggregate arguments
567 \param src_size - size of bv_src (how many vectors to aggregate)
568 */
570 const bvector_type_const_ptr* bv_src,
571 size_t src_size);
572 /**
573 Horizontal AND aggregation (potentially slower) method.
574 \param bv_target - target vector
575 \param bv_src - array of pointers on bit-vector aggregate arguments
576 \param src_size - size of bv_src (how many vectors to aggregate)
577 */
579 const bvector_type_const_ptr* bv_src,
580 size_t src_size);
581
582 /**
583 Horizontal AND-SUB aggregation (potentially slower) method.
584 \param bv_target - target vector
585 \param bv_src_and - array of pointers on bit-vector to AND aggregate
586 \param src_and_size - size of bv_src_and
587 \param bv_src_sub - array of pointers on bit-vector to SUB aggregate
588 \param src_sub_size - size of bv_src_sub
589 */
591 const bvector_type_const_ptr* bv_src_and,
592 size_t src_and_size,
593 const bvector_type_const_ptr* bv_src_sub,
594 size_t src_sub_size);
595
596 //@}
597
598
599 // -----------------------------------------------------------------------
600
601 /*! @name Pipeline operations */
602 //@{
603
604 /** Get current operation code */
605 int get_operation() const BMNOEXCEPT { return operation_; }
606
607 /** Set operation code for the aggregator */
608 void set_operation(int op_code) BMNOEXCEPT { operation_ = op_code; }
609
610 /**
611 Prepare operation, create internal resources, analyse dependencies.
612 Prerequisites are: that operation is set and all argument vectors are added
613 */
614 void stage(bm::word_t* temp_block);
615
616 /**
617 Run a step of current arrgegation operation
618 */
619 operation_status run_step(unsigned i, unsigned j);
620
621 operation_status get_operation_status() const { return operation_status_; }
622
623 const bvector_type* get_target() const BMNOEXCEPT { return bv_target_; }
624
625 bm::word_t* get_temp_block() BMNOEXCEPT { return tb_ar_->tb1; }
626
627 //@}
628
629 // -----------------------------------------------------------------------
630
631 /*! @name Execition metrics and telemetry */
632 //@{
633 bm::id64_t get_cache_gap_hits() const BMNOEXCEPT { return gap_cache_cnt_; }
634 //@}
635
636protected:
638 typedef typename BV::block_idx_type block_idx_type;
639 typedef
640 bm::heap_vector<const bm::word_t*, allocator_type, true> block_ptr_vector_type;
641 typedef
642 bm::heap_vector<const bm::gap_word_t*, allocator_type, true> gap_block_ptr_vector_type;
643 typedef
644 bm::heap_vector<unsigned char, allocator_type, true> uchar_vector_type;
645
646
648
649
650 void combine_or(unsigned i, unsigned j,
651 bvector_type& bv_target,
652 const bvector_type_const_ptr* bv_src, size_t src_size);
653
654 void combine_and(unsigned i, unsigned j,
655 bvector_type& bv_target,
656 const bvector_type_const_ptr* bv_src, size_t src_size);
657
658 digest_type combine_and_sub(unsigned i, unsigned j,
659 const size_t* and_idx,
660 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
661 const size_t* sub_idx,
662 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size,
663 int* is_result_full);
664
666 const bvector_type_const_ptr* bv_src,
667 size_t src_size);
668
669 bool combine_shift_right_and(unsigned i, unsigned j,
670 bvector_type& bv_target,
671 const bvector_type_const_ptr* bv_src,
672 size_t src_size);
673
674 static
675 unsigned resize_target(bvector_type& bv_target,
676 const bvector_type_const_ptr* bv_src,
677 size_t src_size,
678 bool init_clear = true);
679
680 static
682 size_t src_size) BMNOEXCEPT;
683
684
685
686 /// Temporary operations vectors
687 struct arena
688 {
689 block_ptr_vector_type v_arg_tmp_blk; ///< source blocks list
690 block_ptr_vector_type v_arg_or_blk; ///< source blocks list (OR)
691 gap_block_ptr_vector_type v_arg_or_blk_gap; ///< source GAP blocks list (OR)
692 block_ptr_vector_type v_arg_and_blk; ///< source blocks list (AND)
693 gap_block_ptr_vector_type v_arg_and_blk_gap; ///< source GAP blocks list (AND)
694 uchar_vector_type carry_overs; ///< shift carry over flags
695
696
698 {
701 carry_overs.reset();
702 }
704 {
705 v_arg_and_blk.reset();
706 v_arg_and_blk_gap.reset();
707 }
709 {
710 v_arg_or_blk.reset();
711 v_arg_or_blk_gap.reset();
712 }
713
714 };
715
716
717 bm::word_t* sort_input_blocks_or(const size_t* src_idx,
718 const bvector_type_const_ptr* bv_src,
719 size_t src_size,
720 unsigned i, unsigned j);
721
722 bm::word_t* sort_input_blocks_and(const size_t* src_idx,
723 const bvector_type_const_ptr* bv_src,
724 size_t src_size,
725 unsigned i, unsigned j);
727 const size_t* src_idx,
728 size_t k,
729 unsigned i, unsigned j);
730
731
733 unsigned i, unsigned j, const arena& ar);
734
735 void process_gap_blocks_or(const arena& ar/*size_t block_count*/);
736
737 digest_type process_bit_blocks_and(const arena& ar, /*size_t block_count,*/ digest_type digest);
738
739 digest_type process_gap_blocks_and(const arena& ar, /*size_t block_count,*/ digest_type digest);
740
741 bool test_gap_blocks_and(size_t block_count, unsigned bit_idx);
742 bool test_gap_blocks_sub(size_t block_count, unsigned bit_idx);
743
744 digest_type process_bit_blocks_sub(const arena& ar, /*size_t block_count,*/ digest_type digest);
745
746 digest_type process_gap_blocks_sub(const arena& ar,/*size_t block_count,*/ digest_type digest);
747
748 static
749 unsigned find_effective_sub_block_size(unsigned i,
750 const bvector_type_const_ptr* bv_src,
751 size_t src_size,
752 bool top_null_as_zero) BMNOEXCEPT;
753
754 static
755 unsigned find_effective_sub_block_size(unsigned i,
756 const bvector_type_const_ptr* bv_src1,
757 size_t src_size1,
758 const bvector_type_const_ptr* bv_src2,
759 size_t src_size2) BMNOEXCEPT;
760
761 static
762 bool any_carry_overs(const unsigned char* carry_overs,
763 size_t co_size) BMNOEXCEPT;
764
765 /**
766 @return carry over
767 */
768 static
770 const bm::word_t* BMRESTRICT arg_blk,
771 digest_type& BMRESTRICT digest,
772 unsigned carry_over) BMNOEXCEPT;
773
774 static
776 unsigned k, unsigned i, unsigned j) BMNOEXCEPT;
777
779
780 // ---------------------------------------------------------
781
783 {
784 void* p = bm::aligned_new_malloc(sizeof(arena));
785 return new(p) arena();
786 }
787 static void free_arena(arena* ar) BMNOEXCEPT
788 {
789 if (!ar) return;
790 ar->~arena();
792 }
793
795 {
796 void* p = bm::aligned_new_malloc(sizeof(arg_groups));
797 return new(p) arg_groups();
798 }
799
800 static void free_arg_group(arg_groups* arg)
801 {
802 if (!arg) return;
803 arg->~arg_groups();
804 bm::aligned_free(arg);
805 }
806
807 // ---------------------------------------------------------
808
809private:
810 /// Alllocated blocka of scratch memory
811 struct tb_arena
812 {
814 BM_DECLARE_TEMP_BLOCK(tb_opt) ///< temp block for results optimization
815 };
816
817
818 aggregator(const aggregator&) = delete;
819 aggregator& operator=(const aggregator&) = delete;
820
821private:
822 arg_groups ag_; ///< aggregator argument groups
823 tb_arena* tb_ar_; ///< data arena ptr (heap allocated)
824 arena* ar_; ///< data arena ptr
825 allocator_pool_type pool_; ///< pool for operations with cyclic mem.use
826
827 bm::word_t* temp_blk_= 0; ///< external temp block ptr
828 int operation_ = 0; ///< operation code (default: not defined)
829 operation_status operation_status_ = op_undefined;
830 bvector_type* bv_target_ = 0; ///< target bit-vector
831 unsigned top_block_size_ = 0; ///< operation top block (i) size
832 pipeline_bcache* bcache_ptr_ = 0; /// pipeline blocks cache ptr
833
834 // search range setting (hint) [from, to]
835 bool range_set_ = false; ///< range flag
836 size_type range_from_ = bm::id_max; ///< search from
837 size_type range_to_ = bm::id_max; ///< search to
838
839 typename bvector_type::optmode opt_mode_; ///< perform search result optimization
840 bool compute_count_; ///< compute search result count
841 size_type count_; ///< search result count
842 //
843 // execution telemetry and metrics
844 bm::id64_t gap_cache_cnt_ = 0;
845};
846
847
848
849
850// ------------------------------------------------------------------------
851//
852// ------------------------------------------------------------------------
853
854/**
855 Experimental method ro run multiple aggregators in sync
856
857 Pipeleine algorithm walts the sequence of iterators (pointers on aggregators)
858 and run them all via aggregator<>::run_step() method
859
860 @param first - iterator (pointer on aggregator)
861 @param last - iterator (pointer on aggregator)
862 @ingroup setalgo
863*/
864template<typename Agg, typename It>
865void aggregator_pipeline_execute(It first, It last)
866{
867 bm::word_t* tb = (*first)->get_temp_block();
868
869 int pipeline_size = 0;
870 for (It it = first; it != last; ++it, ++pipeline_size)
871 {
872 Agg& agg = *(*it);
873 agg.stage(tb);
874 }
875 for (unsigned i = 0; i < bm::set_sub_array_size; ++i)
876 {
877 unsigned j = 0;
878 do
879 {
880 // run all aggregators for the [i,j] coordinate
881 unsigned w = 0;
882 for (It it = first; it != last; ++it, ++w)
883 {
884 Agg& agg = *(*it);
885 auto op_st = agg.get_operation_status();
886 if (op_st != Agg::op_done)
887 {
888 op_st = agg.run_step(i, j);
889 pipeline_size -= (op_st == Agg::op_done);
890 }
891 } // for it
892 if (pipeline_size <= 0)
893 return;
894
895 } while (++j < bm::set_sub_array_size);
896
897 } // for i
898}
899
900
901// ------------------------------------------------------------------------
902//
903// ------------------------------------------------------------------------
904
905
906template<typename BV>
908: opt_mode_(bvector_type::opt_none),
909 compute_count_(false),
910 count_(0)
911{
912 tb_ar_ = (tb_arena*) bm::aligned_new_malloc(sizeof(tb_arena));
913 ar_ = construct_arena();
914}
915
916// ------------------------------------------------------------------------
917
918template<typename BV>
920{
921 BM_ASSERT(ar_ && tb_ar_);
922 bm::aligned_free(tb_ar_);
923
924 free_arena(ar_);
925
926 delete bv_target_;
927}
928
929// ------------------------------------------------------------------------
930
931template<typename BV>
933{
934 reset_vars();
935 reset_range_hint();
936}
937
938// ------------------------------------------------------------------------
939
940template<typename BV>
942{
943 ag_.reset();
944 ar_->reset_all_blocks();
945 operation_ = top_block_size_ = 0;
946 operation_status_ = op_undefined;
947 count_ = 0; bcache_ptr_ = 0; gap_cache_cnt_ = 0;
948}
949
950// ------------------------------------------------------------------------
951
952template<typename BV>
954{
955 range_set_ = false;
956 range_from_ = range_to_ = bm::id_max;
957}
958
959
960// ------------------------------------------------------------------------
961
962template<typename BV>
964{
965 range_from_ = from; range_to_ = to;
966 range_set_ = true;
967}
968
969// ------------------------------------------------------------------------
970
971template<typename BV>
974{
975 if (!bv_target_)
976 {
977 bv_target_ = new bvector_type(); //TODO: get rid of "new"
978 bv_target_->init();
979 }
980 return bv_target_;
981}
982
983// ------------------------------------------------------------------------
984
985template<typename BV>
986size_t aggregator<BV>::add(const bvector_type* bv, unsigned agr_group)
987{
988 return ag_.add(bv, agr_group);
989}
990
991// ------------------------------------------------------------------------
992
993template<typename BV>
995{
996 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
997 combine_or(bv_target, ag_.arg_bv0.data(), ag_.arg_bv0.size());
998}
999
1000// ------------------------------------------------------------------------
1001
1002template<typename BV>
1004{
1005 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
1006 //combine_and(bv_target, ag_.arg_bv0.data(), ag_.arg_bv0.size());
1007 // implemented ad AND-SUB (with an empty MINUS set)
1008 combine_and_sub(bv_target,
1009 ag_.arg_bv0.data(), ag_.arg_bv0.size(),
1010 0, 0,
1011 false);
1012}
1013
1014// ------------------------------------------------------------------------
1015
1016template<typename BV>
1018{
1019 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
1020 return combine_and_sub(bv_target,
1021 ag_.arg_bv0.data(), ag_.arg_bv0.size(),
1022 ag_.arg_bv1.data(), ag_.arg_bv1.size(),
1023 false);
1024}
1025
1026// ------------------------------------------------------------------------
1027
1028template<typename BV>
1030{
1031 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
1032 return combine_and_sub(bv_target,
1033 ag_.arg_bv0.data(), ag_.arg_bv0.size(),
1034 ag_.arg_bv1.data(), ag_.arg_bv1.size(),
1035 any);
1036}
1037
1038// ------------------------------------------------------------------------
1039
1040template<typename BV> template<typename BII>
1042{
1043 return combine_and_sub(bi,
1044 ag_.arg_bv0.data(), ag_.arg_bv0.size(),
1045 ag_.arg_bv1.data(), ag_.arg_bv1.size());
1046}
1047
1048
1049// ------------------------------------------------------------------------
1050
1051template<typename BV>
1053{
1054 return find_first_and_sub(idx,
1055 ag_.arg_bv0.data(), ag_.arg_bv0.size(), //arg_group0_size,
1056 ag_.arg_bv1.data(), ag_.arg_bv1.size());//arg_group1_size);
1057}
1058
1059// ------------------------------------------------------------------------
1060
1061template<typename BV>
1063{
1064 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
1065 count_ = 0;
1066 ar_->reset_all_blocks();
1067 combine_shift_right_and(bv_target, ag_.arg_bv0.data(), ag_.arg_bv0.size(),//arg_group0_size,
1068 false);
1069}
1070
1071// ------------------------------------------------------------------------
1072
1073template<typename BV>
1075 const bvector_type_const_ptr* bv_src, size_t src_size)
1076{
1077 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
1078 if (!src_size)
1079 {
1080 bv_target.clear();
1081 return;
1082 }
1083 ag_.reset();
1084 ar_->reset_or_blocks();
1085 unsigned top_blocks = resize_target(bv_target, bv_src, src_size);
1086 for (unsigned i = 0; i < top_blocks; ++i)
1087 {
1088 unsigned set_array_max =
1089 find_effective_sub_block_size(i, bv_src, src_size, false);
1090 for (unsigned j = 0; j < set_array_max; ++j)
1091 {
1092 combine_or(i, j, bv_target, bv_src, src_size);
1093 } // for j
1094 } // for i
1095}
1096
1097// ------------------------------------------------------------------------
1098
1099template<typename BV>
1101 const bvector_type_const_ptr* bv_src,
1102 size_t src_size)
1103{
1104 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
1105 if (src_size == 1)
1106 {
1107 const bvector_type* bv = bv_src[0];
1108 bv_target = *bv;
1109 return;
1110 }
1111 if (!src_size)
1112 {
1113 bv_target.clear();
1114 return;
1115 }
1116 ag_.reset();
1117 ar_->reset_and_blocks();
1118 unsigned top_blocks = resize_target(bv_target, bv_src, src_size);
1119 for (unsigned i = 0; i < top_blocks; ++i)
1120 {
1121 // TODO: find range, not just size
1122 unsigned set_array_max =
1123 find_effective_sub_block_size(i, bv_src, src_size, true);
1124 for (unsigned j = 0; j < set_array_max; ++j)
1125 {
1126 // TODO: use block_managers not bvectors to avoid extra indirect
1127 combine_and(i, j, bv_target, bv_src, src_size);
1128 } // for j
1129 } // for i
1130}
1131
1132// ------------------------------------------------------------------------
1133
1134template<typename BV>
1136 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
1137 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size,
1138 bool any)
1139{
1140 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
1141 bool global_found = false;
1142
1143 if (!bv_src_and || !src_and_size)
1144 {
1145 bv_target.clear();
1146 return false;
1147 }
1148
1149 blocks_manager_type& bman_target = bv_target.get_blocks_manager();
1150
1151 unsigned top_blocks = resize_target(bv_target, bv_src_and, src_and_size);
1152 unsigned top_blocks2 = resize_target(bv_target, bv_src_sub, src_sub_size, false);
1153
1154 if (top_blocks2 > top_blocks)
1155 top_blocks = top_blocks2;
1156
1157 for (unsigned i = 0; i < top_blocks; ++i)
1158 {
1159 const unsigned set_array_max =
1160 find_effective_sub_block_size(i, bv_src_and, src_and_size,
1161 bv_src_sub, src_sub_size);
1162 for (unsigned j = 0; j < set_array_max; ++j)
1163 {
1164 int is_res_full;
1165 digest_type digest = combine_and_sub(i, j,
1166 0, bv_src_and, src_and_size,
1167 0, bv_src_sub, src_sub_size,
1168 &is_res_full);
1169 if (is_res_full)
1170 {
1171 bman_target.check_alloc_top_subblock(i);
1172 bman_target.set_block_ptr(i, j, (bm::word_t*)FULL_BLOCK_FAKE_ADDR);
1173 if (j == bm::set_sub_array_size-1)
1174 bman_target.validate_top_full(i);
1175 if (any)
1176 return any;
1177 }
1178 else
1179 {
1180 bool found = digest;
1181 if (found)
1182 {
1183 bman_target.opt_copy_bit_block(i, j, tb_ar_->tb1,
1184 bvector_type::opt_compress, tb_ar_->tb_opt);
1185 if (any)
1186 return found;
1187 }
1188 global_found |= found;
1189 }
1190 } // for j
1191 } // for i
1192 return global_found;
1193}
1194
1195// ------------------------------------------------------------------------
1196
1197template<typename BV> template<typename BII>
1199 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
1200 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size)
1201{
1202 bool global_found = false;
1203
1204 if (!bv_src_and || !src_and_size)
1205 return false;
1206
1207 unsigned top_blocks = 0;
1208
1209 // pre-scan to calculate top size
1210 for (unsigned i = 0; i < src_and_size; ++i)
1211 {
1212 const bvector_type* bv = bv_src_and[i];
1213 BM_ASSERT(bv);
1214 unsigned arg_top_blocks = bv->get_blocks_manager().top_block_size();
1215 if (arg_top_blocks > top_blocks)
1216 top_blocks = arg_top_blocks;
1217 } // for i
1218 for (unsigned i = 0; i < src_sub_size; ++i)
1219 {
1220 const bvector_type* bv = bv_src_sub[i];
1221 BM_ASSERT(bv);
1222 unsigned arg_top_blocks = bv->get_blocks_manager().top_block_size();
1223 if (arg_top_blocks > top_blocks)
1224 top_blocks = arg_top_blocks;
1225 } // for i
1226
1228 for (unsigned i = 0; i < top_blocks; ++i)
1229 {
1230 const unsigned set_array_max =
1231 find_effective_sub_block_size(i, bv_src_and, src_and_size,
1232 bv_src_sub, src_sub_size);
1233 for (unsigned j = 0; j < set_array_max; ++j)
1234 {
1235 int is_res_full;
1236 digest_type digest = combine_and_sub(i, j,
1237 0, bv_src_and, src_and_size,
1238 0, bv_src_sub, src_sub_size,
1239 &is_res_full);
1241 size_type base_idx = (r+j)*bm::bits_in_block;
1242 if (is_res_full)
1243 {
1244 for (size_type k = 0; k < 65536; ++k)
1245 *bi = base_idx + k;
1246 }
1247 else
1248 {
1249 bool found = digest;
1250 global_found |= found;
1251 if (found)
1252 bm::for_each_bit_blk(tb_ar_->tb1, base_idx, bit_functor);
1253 }
1254 } // for j
1255 } // for i
1256 return global_found;
1257
1258}
1259
1260
1261
1262// ------------------------------------------------------------------------
1263
1264template<typename BV> template<class TPipe>
1266{
1267 BM_ASSERT(pipe.is_complete());
1268
1269 const arg_vector_type& pipe_args = pipe.get_args_vector();
1270 size_t pipe_size = pipe_args.size();
1271 if (!pipe_size)
1272 return;
1273
1274 reset_vars();
1275
1276 bcache_ptr_ = &pipe.get_bcache(); // setup common cache block
1277
1278 unsigned top_blocks = pipe.get_top_blocks();
1279 BM_ASSERT(top_blocks);
1280
1281 if (pipe.bv_or_target_)
1282 pipe.bv_or_target_->get_blocks_manager().reserve_top_blocks(top_blocks);
1283
1284 unsigned i_from(0), j_from(0), i_to(0), j_to(0);
1285 if (range_set_)
1286 {
1287 typename bvector_type::block_idx_type nb;
1288 nb = (range_from_ >> bm::set_block_shift);
1289 bm::get_block_coord(nb, i_from, j_from);
1290 nb = (range_to_ >> bm::set_block_shift);
1291 bm::get_block_coord(nb, i_to, j_to);
1292 }
1293
1294
1295 size_t batch_size = pipe.get_options().batch_size;
1296 if (!batch_size)
1297 batch_size = pipe.compute_run_batch();
1298
1299 for (size_t batch_from(0), batch_to(0); batch_from < pipe_size;
1300 batch_from = batch_to)
1301 {
1302 batch_to = batch_from + batch_size;
1303 if (batch_to > pipe_size)
1304 batch_to = pipe_size;
1305 if (!batch_size)
1306 batch_size = 1;
1307 for (unsigned i = i_from; i < top_blocks; ++i)
1308 {
1309 unsigned j(0), sub_size(bm::set_sub_array_size);
1310 if constexpr(TPipe::options_type::is_masks())
1311 {
1312 if (range_set_)
1313 {
1314 if (i == i_from)
1315 j = j_from;
1316 if (i == i_to)
1317 sub_size = j_to+1;
1318 }
1319 }
1320
1321 for (; j < sub_size; ++j)
1322 {
1323 size_t p = batch_from;
1324 for (; p < batch_to; ++p)
1325 {
1326 const arg_groups* ag = pipe_args[p];
1327 size_t src_and_size = ag->arg_bv0.size();
1328 if (!src_and_size)
1329 continue;
1330
1331 const bvector_type_const_ptr* bv_src_and = ag->arg_bv0.data();
1332 const size_t* bv_src_and_idx = ag->arg_idx0.data();
1333
1334 const bvector_type_const_ptr* bv_src_sub = ag->arg_bv1.data();
1335 const size_t* bv_src_sub_idx = ag->arg_idx1.data();
1336 size_t src_sub_size = ag->arg_bv1.size();
1337
1338 if constexpr (TPipe::options_type::is_compute_counts())
1339 {
1340 // if search limit reached
1341 if (pipe.count_res_vect_[p] >= pipe.search_count_limit_)
1342 continue;
1343 }
1344
1345 int is_res_full;
1346 digest_type digest = combine_and_sub(i, j,
1347 bv_src_and_idx,
1348 bv_src_and, src_and_size,
1349 bv_src_sub_idx,
1350 bv_src_sub, src_sub_size,
1351 &is_res_full);
1352 if (digest || is_res_full)
1353 {
1354 if (pipe.bv_or_target_)
1355 {
1356 blocks_manager_type& bman =
1357 pipe.bv_or_target_->get_blocks_manager();
1358 const bm::word_t* arg_blk =
1359 (is_res_full) ? (bm::word_t*)FULL_BLOCK_FAKE_ADDR
1360 : tb_ar_->tb1;
1361 bman.check_alloc_top_subblock(i);
1362 bm::word_t* blk = bman.get_block_ptr(i, j);
1363 pipe.bv_or_target_->combine_operation_block_or(
1364 i, j, blk, arg_blk);
1365 }
1366 if constexpr (!TPipe::options_type::is_make_results()) // drop results
1367 {
1368 if constexpr (TPipe::options_type::is_compute_counts())
1369 {
1370 if (is_res_full)
1371 pipe.count_res_vect_[p]+=bm::gap_max_bits;
1372 else
1373 pipe.count_res_vect_[p]+=
1374 bm::bit_block_count(tb_ar_->tb1, digest);
1375 }
1376 }
1377 else // results requested
1378 {
1379 bvect_vector_type& bv_targets_vect =
1380 pipe.get_bv_res_vector();
1381 bvector_type* bv_target = bv_targets_vect[p];
1382 if (!bv_target)
1383 {
1384 BM_ASSERT(!bv_targets_vect[p]);
1385 bv_target = new bvector_type(bm::BM_GAP);
1386 bv_targets_vect[p] = bv_target;
1387 typename bvector_type::blocks_manager_type& bman =
1388 bv_target->get_blocks_manager();
1389
1390 bman.reserve_top_blocks(top_blocks);
1391 }
1392 blocks_manager_type& bman =
1393 bv_target->get_blocks_manager();
1394 if (is_res_full)
1395 {
1396 bman.check_alloc_top_subblock(i);
1397 bman.set_block_ptr(i, j,
1399 if (j == bm::set_sub_array_size-1)
1400 bman.validate_top_full(i);
1401 if constexpr (TPipe::options_type::is_compute_counts())
1402 pipe.count_res_vect_[p] += bm::gap_max_bits;
1403 }
1404 else
1405 {
1406 if constexpr (TPipe::options_type::is_compute_counts())
1407 pipe.count_res_vect_[p] +=
1408 bm::bit_block_count(tb_ar_->tb1, digest);
1409 bman.opt_copy_bit_block(i, j, tb_ar_->tb1,
1410 bvector_type::opt_compress, tb_ar_->tb_opt);
1411 }
1412 }
1413 } // if
1414 } // for p
1415 // optimize OR target to save memory
1416 if (pipe.bv_or_target_ && p == pipe_size) // last batch is done
1417 {
1418 blocks_manager_type& bman =
1419 pipe.bv_or_target_->get_blocks_manager();
1420 if (bm::word_t* blk = bman.get_block_ptr(i, j))
1421 bman.optimize_block(i, j, blk,
1422 tb_ar_->tb_opt, bvector_type::opt_compress, 0);
1423 }
1424 } // for j
1425 } // for i
1426 } // for batch
1427
1428 bcache_ptr_ = 0;
1429}
1430
1431// ------------------------------------------------------------------------
1432
1433template<typename BV>
1435 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
1436 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size)
1437{
1438 if (!bv_src_and || !src_and_size)
1439 return false;
1440
1441 unsigned top_blocks = max_top_blocks(bv_src_and, src_and_size);
1442 unsigned top_blocks2 = max_top_blocks(bv_src_sub, src_sub_size);
1443
1444 if (top_blocks2 > top_blocks)
1445 top_blocks = top_blocks2;
1446
1447 // compute range blocks coordinates
1448 //
1449 block_idx_type nblock_from = (range_from_ >> bm::set_block_shift);
1450 block_idx_type nblock_to = (range_to_ >> bm::set_block_shift);
1451 unsigned top_from = unsigned(nblock_from >> bm::set_array_shift);
1452 unsigned top_to = unsigned(nblock_to >> bm::set_array_shift);
1453
1454 if (range_set_)
1455 {
1456 if (nblock_from == nblock_to) // one block search
1457 {
1458 int is_res_full;
1459 unsigned i = top_from;
1460 unsigned j = unsigned(nblock_from & bm::set_array_mask);
1461 digest_type digest = combine_and_sub(i, j,
1462 0, bv_src_and, src_and_size,
1463 0, bv_src_sub, src_sub_size,
1464 &is_res_full);
1465 // is_res_full is not needed here, since it is just 1 block
1466 if (digest)
1467 {
1468 unsigned block_bit_idx = 0;
1469 bool found = bm::bit_find_first(tb_ar_->tb1, &block_bit_idx, digest);
1470 BM_ASSERT(found);
1471 idx = bm::block_to_global_index(i, j, block_bit_idx);
1472 return found;
1473 }
1474 return false;
1475 }
1476
1477 if (top_to < top_blocks)
1478 top_blocks = top_to+1;
1479 }
1480 else
1481 {
1482 top_from = 0;
1483 }
1484
1485 for (unsigned i = top_from; i < top_blocks; ++i)
1486 {
1487 unsigned set_array_max = bm::set_sub_array_size;
1488 unsigned j = 0;
1489 if (range_set_)
1490 {
1491 if (i == top_from)
1492 {
1493 j = nblock_from & bm::set_array_mask;
1494 }
1495 if (i == top_to)
1496 {
1497 set_array_max = 1 + unsigned(nblock_to & bm::set_array_mask);
1498 }
1499 }
1500 else
1501 {
1502 set_array_max = find_effective_sub_block_size(i, bv_src_and, src_and_size, true);
1503 if (!set_array_max)
1504 continue;
1505 if (src_sub_size)
1506 {
1507 unsigned set_array_max2 =
1508 find_effective_sub_block_size(i, bv_src_sub, src_sub_size, false);
1509 // TODO: should it be set_array_max2 < set_array_max ????
1510 //if (set_array_max2 > set_array_max)
1511 if (set_array_max2 < set_array_max)
1512 set_array_max = set_array_max2;
1513 }
1514 }
1515 for (; j < set_array_max; ++j)
1516 {
1517 int is_res_full;
1518 digest_type digest = combine_and_sub(i, j,
1519 0, bv_src_and, src_and_size,
1520 0, bv_src_sub, src_sub_size,
1521 &is_res_full);
1522 if (digest)
1523 {
1524 unsigned block_bit_idx = 0;
1525 bool found = bm::bit_find_first(tb_ar_->tb1, &block_bit_idx, digest);
1526 BM_ASSERT(found);
1527 idx = bm::block_to_global_index(i, j, block_bit_idx);
1528 return found;
1529 }
1530 } // for j
1531 //while (++j < set_array_max);
1532 } // for i
1533 return false;
1534}
1535
1536// ------------------------------------------------------------------------
1537
1538template<typename BV>
1539unsigned
1541 unsigned i,
1542 const bvector_type_const_ptr* bv_src,
1543 size_t src_size,
1544 bool top_null_as_zero) BMNOEXCEPT
1545{
1546 // quick hack to avoid scanning large, arrays, where such scan can be quite
1547 // expensive by itself (this makes this function approximate)
1548 if (src_size > 32)
1550
1551 unsigned max_size = 1;
1552 for (size_t k = 0; k < src_size; ++k)
1553 {
1554 const bvector_type* bv = bv_src[k];
1555 BM_ASSERT(bv);
1556 const typename bvector_type::blocks_manager_type& bman_arg =
1557 bv->get_blocks_manager();
1558 const bm::word_t* const* blk_blk_arg = bman_arg.get_topblock(i);
1559 if (!blk_blk_arg)
1560 {
1561 if (top_null_as_zero)
1562 return 0;
1563 continue;
1564 }
1565 if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
1567
1568 for (unsigned j = bm::set_sub_array_size - 1; j > max_size; --j)
1569 {
1570 if (blk_blk_arg[j])
1571 {
1572 max_size = j;
1573 break;
1574 }
1575 } // for j
1577 break;
1578 } // for k
1579 ++max_size;
1581
1582 return max_size;
1583}
1584
1585// ------------------------------------------------------------------------
1586
1587template<typename BV>
1589 const bvector_type_const_ptr* bv_src1,
1590 size_t src_size1,
1591 const bvector_type_const_ptr* bv_src2,
1592 size_t src_size2) BMNOEXCEPT
1593{
1594 unsigned set_array_max = find_effective_sub_block_size(i, bv_src1, src_size1, true);
1595 if (set_array_max && src_size2)
1596 {
1597 unsigned set_array_max2 =
1598 find_effective_sub_block_size(i, bv_src2, src_size2, false);
1599 if (set_array_max2 > set_array_max) // TODO: use range intersect
1600 set_array_max = set_array_max2;
1601 }
1602 return set_array_max;
1603}
1604
1605
1606// ------------------------------------------------------------------------
1607
1608template<typename BV>
1609void aggregator<BV>::combine_or(unsigned i, unsigned j,
1610 bvector_type& bv_target,
1611 const bvector_type_const_ptr* bv_src,
1612 size_t src_size)
1613{
1614 typename bvector_type::blocks_manager_type& bman_target =
1615 bv_target.get_blocks_manager();
1616
1617 ar_->reset_or_blocks();
1618 bm::word_t* blk = sort_input_blocks_or(0, bv_src, src_size, i, j);
1619
1620 BM_ASSERT(blk == 0 || blk == FULL_BLOCK_FAKE_ADDR);
1621
1622 if (blk == FULL_BLOCK_FAKE_ADDR) // nothing to do - golden block(!)
1623 {
1624 bman_target.check_alloc_top_subblock(i);
1625 bman_target.set_block_ptr(i, j, blk);
1626 if (++j == bm::set_sub_array_size)
1627 bman_target.validate_top_full(i);
1628 }
1629 else
1630 {
1631 size_t arg_blk_count = ar_->v_arg_or_blk.size();
1632 size_t arg_blk_gap_count = ar_->v_arg_or_blk_gap.size();
1633 if (arg_blk_count || arg_blk_gap_count)
1634 {
1635 bool all_one = process_bit_blocks_or(bman_target, i, j, *ar_);
1636 if (!all_one)
1637 {
1638 if (arg_blk_gap_count)
1639 process_gap_blocks_or(*ar_);
1640 // we have some results, allocate block and copy from temp
1641 bman_target.opt_copy_bit_block(i, j, tb_ar_->tb1,
1642 opt_mode_, tb_ar_->tb_opt);
1643 }
1644 }
1645 }
1646}
1647
1648// ------------------------------------------------------------------------
1649
1650template<typename BV>
1651void aggregator<BV>::combine_and(unsigned i, unsigned j,
1652 bvector_type& bv_target,
1653 const bvector_type_const_ptr* bv_src,
1654 size_t src_and_size)
1655{
1656 BM_ASSERT(src_and_size);
1657
1658 bm::word_t* blk = sort_input_blocks_and(0, bv_src, src_and_size, i, j);
1659 BM_ASSERT(blk == 0 || blk == FULL_BLOCK_FAKE_ADDR);
1660 if (!blk) // nothing to do - golden block(!)
1661 return;
1662
1663 size_t arg_blk_and_count = ar_->v_arg_and_blk.size();
1664 size_t arg_blk_and_gap_count = ar_->v_arg_and_blk_gap.size();
1665 if (arg_blk_and_count || arg_blk_and_gap_count)
1666 {
1667 if (!arg_blk_and_gap_count && (arg_blk_and_count == 1))
1668 {
1669 if (ar_->v_arg_and_blk[0] == FULL_BLOCK_REAL_ADDR)
1670 {
1671 // another nothing to do: one FULL block
1672 blocks_manager_type& bman_target = bv_target.get_blocks_manager();
1673 bman_target.check_alloc_top_subblock(i);
1674 bman_target.set_block_ptr(i, j, blk);
1675 if (++j == bm::set_sub_array_size)
1676 bman_target.validate_top_full(i);
1677 return;
1678 }
1679 }
1680 // AND bit-blocks
1681 //
1682 bm::id64_t digest = ~0ull;
1683 digest = process_bit_blocks_and(*ar_, digest);
1684 if (!digest)
1685 return;
1686
1687 // AND all GAP blocks (if any)
1688 //
1689 if (arg_blk_and_gap_count)
1690 {
1691 digest = process_gap_blocks_and(*ar_, digest);
1692 }
1693 if (digest) // we have results , allocate block and copy from temp
1694 {
1695 blocks_manager_type& bman_target = bv_target.get_blocks_manager();
1696 bman_target.opt_copy_bit_block(i, j, tb_ar_->tb1,
1697 opt_mode_, tb_ar_->tb_opt);
1698 }
1699 }
1700}
1701
1702// ------------------------------------------------------------------------
1703
1704template<typename BV>
1707 unsigned i, unsigned j,
1708 const size_t* and_idx,
1709 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
1710 const size_t* sub_idx,
1711 const bvector_type_const_ptr* bv_src_sub, size_t src_sub_size,
1712 int* is_result_full)
1713{
1714 BM_ASSERT(src_and_size);
1715 BM_ASSERT(is_result_full);
1716
1717 *is_result_full = 0;
1718 bm::word_t* blk = sort_input_blocks_and(and_idx, bv_src_and, src_and_size, i, j);
1719 BM_ASSERT(blk == 0 || blk == FULL_BLOCK_FAKE_ADDR);
1720 if (!blk)
1721 return 0; // nothing to do - golden block(!)
1722
1723 {
1724 size_t arg_blk_and_count = ar_->v_arg_and_blk.size();
1725 size_t arg_blk_and_gap_count = ar_->v_arg_and_blk_gap.size();
1726 if (!(arg_blk_and_count | arg_blk_and_gap_count))
1727 return 0; // nothing to do - golden block(!)
1728
1729 ar_->reset_or_blocks();
1730 if (src_sub_size)
1731 {
1732 blk = sort_input_blocks_or(sub_idx, bv_src_sub, src_sub_size, i, j);
1733 BM_ASSERT(blk == 0 || blk == FULL_BLOCK_FAKE_ADDR);
1734 if (blk == FULL_BLOCK_FAKE_ADDR)
1735 return 0; // nothing to do - golden block(!)
1736 }
1737 else
1738 {
1739 if (!arg_blk_and_gap_count && (arg_blk_and_count == 1))
1740 {
1741 if (ar_->v_arg_and_blk[0] == FULL_BLOCK_REAL_ADDR)
1742 {
1743 *is_result_full = 1;
1744 return ~0ull;
1745 }
1746 }
1747 }
1748 }
1749
1750 digest_type digest = ~0ull;
1751
1752 // AND-SUB bit-blocks
1753 //
1754 digest = process_bit_blocks_and(*ar_, digest);
1755 if (!digest)
1756 return digest;
1757 digest = process_bit_blocks_sub(*ar_, digest);
1758 if (!digest)
1759 return digest;
1760
1761 // AND all GAP block
1762 //
1763 digest = process_gap_blocks_and(*ar_, digest);
1764 if (!digest)
1765 return digest;
1766
1767 digest = process_gap_blocks_sub(*ar_, digest);
1768
1769 return digest;
1770}
1771
1772// ------------------------------------------------------------------------
1773
1774template<typename BV>
1775void aggregator<BV>::process_gap_blocks_or(const arena& ar)//size_t arg_blk_gap_count)
1776{
1777 size_t arg_blk_gap_count = ar.v_arg_or_blk_gap.size();
1778 bm::word_t* blk = tb_ar_->tb1;
1779 for (size_t k = 0; k < arg_blk_gap_count; ++k)
1781}
1782
1783// ------------------------------------------------------------------------
1784
1785template<typename BV>
1788 digest_type digest)
1789{
1790 bm::word_t* blk = tb_ar_->tb1;
1791 size_t arg_blk_gap_count = ar.v_arg_and_blk_gap.size();
1792 bool single_bit_found;
1793 unsigned single_bit_idx;
1794 for (size_t k = 0; k < arg_blk_gap_count; ++k)
1795 {
1796 bm::gap_and_to_bitset(blk, ar.v_arg_and_blk_gap[k], digest);
1797 digest = bm::update_block_digest0(blk, digest);
1798 if (!digest)
1799 {
1801 break;
1802 }
1803 if (bm::word_bitcount64(digest) == 1)
1804 {
1805 single_bit_found = bm::bit_find_first_if_1(blk, &single_bit_idx, digest);
1806 if (single_bit_found)
1807 {
1808 for (++k; k < arg_blk_gap_count; ++k)
1809 {
1810 bool b = bm::gap_test_unr(ar.v_arg_and_blk_gap[k], single_bit_idx);
1811 if (!b)
1812 return 0; // AND 0 causes result to turn 0
1813 } // for k
1814 break;
1815 }
1816 }
1817 }
1818 return digest;
1819}
1820
1821// ------------------------------------------------------------------------
1822
1823template<typename BV>
1826 digest_type digest)
1827{
1828 size_t arg_blk_gap_count = ar.v_arg_or_blk_gap.size();
1829 bm::word_t* blk = tb_ar_->tb1;
1830 bool single_bit_found;
1831 unsigned single_bit_idx;
1832 for (size_t k = 0; k < arg_blk_gap_count; ++k)
1833 {
1834 bm::gap_sub_to_bitset(blk, ar.v_arg_or_blk_gap[k], digest);
1835 digest = bm::update_block_digest0(blk, digest);
1836 if (!digest)
1837 {
1839 break;
1840 }
1841 // check if logical operation reduced to a corner case of one single bit
1842 if (bm::word_bitcount64(digest) == 1)
1843 {
1844 single_bit_found = bm::bit_find_first_if_1(blk, &single_bit_idx, digest);
1845 if (single_bit_found)
1846 {
1847 for (++k; k < arg_blk_gap_count; ++k)
1848 {
1849 bool b = bm::gap_test_unr(ar.v_arg_or_blk_gap[k], single_bit_idx);
1850 if (b)
1851 return 0; // AND-NOT causes search result to turn 0
1852 } // for k
1853 break;
1854 }
1855 }
1856 } // for k
1857 return digest;
1858}
1859
1860// ------------------------------------------------------------------------
1861
1862template<typename BV>
1863bool aggregator<BV>::test_gap_blocks_and(size_t arg_blk_gap_count,
1864 unsigned bit_idx)
1865{
1866 unsigned b = 1;
1867 for (size_t i = 0; i < arg_blk_gap_count && b; ++i)
1868 b = bm::gap_test_unr(ar_->v_arg_and_blk_gap[i], bit_idx);
1869 return b;
1870}
1871
1872// ------------------------------------------------------------------------
1873
1874template<typename BV>
1875bool aggregator<BV>::test_gap_blocks_sub(size_t arg_blk_gap_count,
1876 unsigned bit_idx)
1877{
1878 unsigned b = 1;
1879 for (size_t i = 0; i < arg_blk_gap_count; ++i)
1880 {
1881 b = bm::gap_test_unr(ar_->v_arg_or_blk_gap[i], bit_idx);
1882 if (b)
1883 return false;
1884 }
1885 return true;
1886}
1887
1888// ------------------------------------------------------------------------
1889
1890
1891template<typename BV>
1893 unsigned i, unsigned j,
1894 const arena& ar)
1895{
1896 size_t arg_blk_count = ar.v_arg_or_blk.size();
1897 bm::word_t* blk = tb_ar_->tb1;
1898 bool all_one;
1899
1900 size_t k = 0;
1901
1902 if (arg_blk_count) // copy the first block
1903 bm::bit_block_copy(blk, ar.v_arg_or_blk[k++]);
1904 else
1905 bm::bit_block_set(blk, 0);
1906
1907 // process all BIT blocks
1908 //
1909 size_t unroll_factor, len, len_unr;
1910
1911 unroll_factor = 4;
1912 len = arg_blk_count - k;
1913 len_unr = len - (len % unroll_factor);
1914 for( ;k < len_unr; k+=unroll_factor)
1915 {
1916 all_one = bm::bit_block_or_5way(blk,
1917 ar.v_arg_or_blk[k], ar.v_arg_or_blk[k+1],
1918 ar.v_arg_or_blk[k+2], ar.v_arg_or_blk[k+3]);
1919 if (all_one)
1920 {
1921 BM_ASSERT(blk == tb_ar_->tb1);
1923 bman_target.set_block(i, j, FULL_BLOCK_FAKE_ADDR, false);
1924 return true;
1925 }
1926 } // for k
1927
1928 unroll_factor = 2;
1929 len = arg_blk_count - k;
1930 len_unr = len - (len % unroll_factor);
1931 for( ;k < len_unr; k+=unroll_factor)
1932 {
1933 all_one = bm::bit_block_or_3way(blk, ar.v_arg_or_blk[k], ar.v_arg_or_blk[k+1]);
1934 if (all_one)
1935 {
1936 BM_ASSERT(blk == tb_ar_->tb1);
1938 bman_target.set_block(i, j, FULL_BLOCK_FAKE_ADDR, false);
1939 return true;
1940 }
1941 } // for k
1942
1943 for (; k < arg_blk_count; ++k)
1944 {
1945 all_one = bm::bit_block_or(blk, ar.v_arg_or_blk[k]);
1946 if (all_one)
1947 {
1948 BM_ASSERT(blk == tb_ar_->tb1);
1950 bman_target.set_block(i, j, FULL_BLOCK_FAKE_ADDR, false);
1951 return true;
1952 }
1953 } // for k
1954
1955 return false;
1956}
1957
1958// ------------------------------------------------------------------------
1959
1960template<typename BV>
1963 digest_type digest)
1964{
1965 bm::word_t* blk = tb_ar_->tb1;
1966 size_t k = 0;
1967 size_t arg_blk_count = ar.v_arg_and_blk.size();
1968
1969 const word_t** args = ar.v_arg_and_blk.data();
1970
1971 block_idx_type nb_from = (range_from_ >> bm::set_block_shift);
1972 block_idx_type nb_to = (range_to_ >> bm::set_block_shift);
1973 if (range_set_ && (nb_from == nb_to))
1974 {
1975 unsigned nbit_from = unsigned(range_from_ & bm::set_block_mask);
1976 unsigned nbit_to = unsigned(range_to_ & bm::set_block_mask);
1977 digest_type digest0 = bm::digest_mask(nbit_from, nbit_to);
1978 digest &= digest0;
1979 bm::block_init_digest0(blk, digest);
1980 }
1981 else
1982 {
1983 switch (arg_blk_count)
1984 {
1985 case 0:
1986 bm::block_init_digest0(blk, digest); // 0xFF... by default
1987 return digest;
1988 case 1:
1989 bm::bit_block_copy(blk, args[k]);
1990 return bm::calc_block_digest0(blk);
1991 default:
1992 digest = bm::bit_block_and_2way(blk, args[k], args[k+1], ~0ull);
1993 k += 2;
1994 break;
1995 } // switch
1996 }
1997
1998 size_t unroll_factor, len, len_unr;
1999 unsigned single_bit_idx;
2000
2001 unroll_factor = 4;
2002 len = arg_blk_count - k;
2003 len_unr = len - (len % unroll_factor);
2004 for (; k < len_unr; k += unroll_factor)
2005 {
2006 digest =
2008 args[k], args[k + 1],
2009 args[k + 2], args[k + 3],
2010 digest);
2011 if (!digest) // all zero
2012 return digest;
2013 if (bm::word_bitcount64(digest) == 1)
2014 {
2015 bool found = bm::bit_find_first_if_1(blk, &single_bit_idx, digest);
2016 if (found)
2017 {
2018 unsigned nword = unsigned(single_bit_idx >> bm::set_word_shift);
2019 unsigned mask = 1u << (single_bit_idx & bm::set_word_mask);
2020 for (++k; k < arg_blk_count; ++k)
2021 {
2022 if (!(mask & args[k][nword]))
2023 {
2024 blk[nword] = 0;
2025 return 0;
2026 }
2027 } // for k
2028 break;
2029 }
2030 }
2031 } // for k
2032
2033 for (; k < arg_blk_count; ++k)
2034 {/*
2035 if (ar_->v_arg_and_blk[k] == FULL_BLOCK_REAL_ADDR)
2036 continue;*/
2037 digest = bm::bit_block_and(blk, args[k], digest);
2038 if (!digest) // all zero
2039 return digest;
2040 } // for k
2041 return digest;
2042}
2043
2044// ------------------------------------------------------------------------
2045
2046template<typename BV>
2049 digest_type digest)
2050{
2051 size_t arg_blk_count = ar.v_arg_or_blk.size();
2052 bm::word_t* blk = tb_ar_->tb1;
2053 unsigned single_bit_idx;
2054 const word_t** args = ar.v_arg_or_blk.data();
2055
2056 size_t k = 0;
2057 for (; k < arg_blk_count; ++k)
2058 {
2059 /*
2060 if (ar.v_arg_or_blk[k] == FULL_BLOCK_REAL_ADDR) // golden block
2061 {
2062 digest = 0;
2063 break;
2064 } */
2065 digest = bm::bit_block_sub(blk, args[k], digest);
2066 if (!digest) // all zero
2067 break;
2068 if (bm::word_bitcount64(digest) == 1)
2069 {
2070 bool found = bm::bit_find_first_if_1(blk, &single_bit_idx, digest);
2071 if (found)
2072 {
2073 const unsigned mask = 1u << (single_bit_idx & bm::set_word_mask);
2074 unsigned nword = unsigned(single_bit_idx >> bm::set_word_shift);
2075 for (++k; k < arg_blk_count; ++k)
2076 {
2077 if (mask & args[k][nword])
2078 {
2079 blk[nword] = 0;
2080 return 0;
2081 }
2082 } // for k
2083 return digest;
2084 }
2085 }
2086 } // for k
2087 return digest;
2088}
2089
2090// ------------------------------------------------------------------------
2091
2092template<typename BV>
2094 const bvector_type_const_ptr* bv_src, size_t src_size,
2095 bool init_clear)
2096{
2097 typename bvector_type::blocks_manager_type& bman_target = bv_target.get_blocks_manager();
2098 if (init_clear)
2099 {
2100 if (bman_target.is_init())
2101 bman_target.deinit_tree();
2102 }
2103
2104 unsigned top_blocks = bman_target.top_block_size();
2105 size_type size = bv_target.size();
2106 bool need_realloc = false;
2107
2108 // pre-scan to do target size harmonization
2109 for (unsigned i = 0; i < src_size; ++i)
2110 {
2111 const bvector_type* bv = bv_src[i];
2112 BM_ASSERT(bv);
2113 const typename bvector_type::blocks_manager_type& bman_arg =
2114 bv->get_blocks_manager();
2115 unsigned arg_top_blocks = bman_arg.top_block_size();
2116 if (arg_top_blocks > top_blocks)
2117 {
2118 need_realloc = true;
2119 top_blocks = arg_top_blocks;
2120 }
2121 size_type arg_size = bv->size();
2122 if (arg_size > size)
2123 size = arg_size;
2124 } // for i
2125
2126 if (need_realloc)
2127 bman_target.reserve_top_blocks(top_blocks);
2128 if (!bman_target.is_init())
2129 bman_target.init_tree();
2130 if (size > bv_target.size())
2131 bv_target.resize(size);
2132
2133 return top_blocks;
2134}
2135
2136// ------------------------------------------------------------------------
2137
2138template<typename BV>
2139unsigned
2141 size_t src_size) BMNOEXCEPT
2142{
2143 unsigned top_blocks = 1;
2144
2145 // pre-scan to do target size harmonization
2146 for (unsigned i = 0; i < src_size; ++i)
2147 {
2148 const bvector_type* bv = bv_src[i];
2149 if (!bv)
2150 continue;
2151 const typename bvector_type::blocks_manager_type& bman_arg = bv->get_blocks_manager();
2152 unsigned arg_top_blocks = bman_arg.top_block_size();
2153 if (arg_top_blocks > top_blocks)
2154 top_blocks = arg_top_blocks;
2155 } // for i
2156 return top_blocks;
2157}
2158
2159// ------------------------------------------------------------------------
2160
2161template<typename BV>
2163 const size_t* src_idx,
2164 const bvector_type_const_ptr* bv_src,
2165 size_t src_size,
2166 unsigned i, unsigned j)
2167{
2168 bm::word_t* blk = 0;
2169 ar_->v_arg_or_blk.reset(); ar_->v_arg_or_blk_gap.reset();
2170 for (size_t k = 0; k < src_size; ++k)
2171 {
2172 const bm::word_t* arg_blk =
2173 bv_src[k]->get_blocks_manager().get_block_ptr(i, j);
2174 if (BM_IS_GAP(arg_blk))
2175 {
2176 (void)src_idx;
2177#if (0)
2178 if (bcache_ptr_)
2179 {
2180 BM_ASSERT(bv == bcache_ptr_->bv_inp_vect_[src_idx[k]]);
2181 bm::word_t* bit_blk = cache_gap_block(arg_blk, src_idx, k, i, j);
2182 if (bit_blk)
2183 {
2184 ar_->v_arg_or_blk.push_back(bit_blk); // use cached bit-block for operation
2185 continue;
2186 }
2187 } // bcache_ptr_
2188#endif
2189 ar_->v_arg_or_blk_gap.push_back(BMGAP_PTR(arg_blk));
2190 }
2191 else // FULL or bit block
2192 {
2193 if (!arg_blk)
2194 continue;
2195 if (arg_blk == FULL_BLOCK_FAKE_ADDR)
2196 return FULL_BLOCK_FAKE_ADDR;
2197 ar_->v_arg_or_blk.push_back(arg_blk);
2198 }
2199 } // for k
2200 return blk;
2201}
2202
2203// ------------------------------------------------------------------------
2204
2205template<typename BV>
2207 const size_t* src_idx,
2208 const bvector_type_const_ptr* bv_src,
2209 size_t src_size,
2210 unsigned i, unsigned j)
2211{
2212 ar_->v_arg_tmp_blk.resize_no_copy(src_size);
2213 auto blocks_arr = ar_->v_arg_tmp_blk.data();
2214 for (size_t k = 0; k < src_size; ++k)
2215 {
2216 const bm::word_t* arg_blk = blocks_arr[k] =
2217 bv_src[k]->get_blocks_manager().get_block_ptr(i, j);
2218 if (!arg_blk)
2219 return 0;
2220 }
2221
2222 bool has_full_blk = false;
2224 auto& bit_v = ar_->v_arg_and_blk;
2225 auto& gap_v = ar_->v_arg_and_blk_gap;
2226 bit_v.resize_no_copy(src_size);
2227 gap_v.resize_no_copy(src_size);
2228 size_t bc(0), gc(0);
2229
2230 auto bit_arr = bit_v.data();
2231 auto gap_arr = gap_v.data();
2232 for (size_t k = 0; k < src_size; ++k)
2233 {
2234 const bm::word_t* arg_blk = blocks_arr[k];
2235 if (BM_IS_GAP(arg_blk))
2236 {
2237 const bm::gap_word_t* gap_blk = BMGAP_PTR(arg_blk);
2238 (void)src_idx;
2239#if (0)
2240 if (bcache_ptr_)
2241 {
2242 unsigned len = bm::gap_length(gap_blk);
2243 size_t bv_idx = src_idx[k];
2244 auto cnt = bcache_ptr_->cnt_vect_[bv_idx];
2245 if (cnt && len > 1024 && bc < (src_size / 4))
2246 {
2247 bm::word_t* bit_blk = cache_gap_block(arg_blk, src_idx, k, i, j);
2248 if (bit_blk)
2249 {
2250 bit_arr[bc++] = bit_blk; // use cached bit-block for operation
2251 continue;
2252 }
2253 }
2254 } // bcache_ptr_
2255#endif
2256 gap_arr[gc++] = gap_blk;
2257 continue;
2258 }
2259 // FULL or bit block
2260 if (arg_blk == FULL_BLOCK_FAKE_ADDR)
2261 {
2262 has_full_blk = true;
2263 continue;
2264 }
2265 bit_arr[bc++] = arg_blk;
2266
2267 } // for k
2268
2269 bit_v.resize_no_copy(bc);
2270 gap_v.resize_no_copy(gc);
2271
2272 if (has_full_blk && (!bc && !gc))
2273 bit_v.push_back(FULL_BLOCK_REAL_ADDR);
2274
2275 return blk;
2276}
2277
2278// ------------------------------------------------------------------------
2279
2280template<typename BV>
2282 const size_t* src_idx,
2283 size_t k,
2284 unsigned i, unsigned j)
2285{
2286 BM_ASSERT(bcache_ptr_);
2287 BM_ASSERT(src_idx);
2288
2289 size_t bv_idx = src_idx[k];
2290 auto cnt = bcache_ptr_->cnt_vect_[bv_idx];
2291 if (cnt > 0) // frequent bector
2292 {
2293 bm::word_t* bit_blk = bcache_ptr_->blk_vect_[bv_idx];
2294 bm::pair<unsigned, unsigned> pair_ij = bcache_ptr_->blk_ij_vect_[bv_idx];
2295 if (!bit_blk)
2296 {
2298 pair_ij.first = i+1; // make it NOT match
2299 bcache_ptr_->blk_vect_[bv_idx] = bit_blk;
2300 }
2301 // block is allocated
2302 if (i != pair_ij.first || j != pair_ij.second) // not NB cached?
2303 {
2304 bm::gap_convert_to_bitset(bit_blk, BMGAP_PTR(arg_blk));
2305 pair_ij.first = i; pair_ij.second = j;
2306 bcache_ptr_->blk_ij_vect_[bv_idx] = pair_ij;
2307 }
2308 ++gap_cache_cnt_;
2309 return bit_blk; // use cached bit-block for operation
2310 }
2311 return 0;
2312}
2313
2314// ------------------------------------------------------------------------
2315
2316template<typename BV>
2318 const bvector_type_const_ptr* bv_src, size_t src_size)
2319{
2320 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
2321 BM_ASSERT(src_size);
2322
2323 if (src_size == 0)
2324 {
2325 bv_target.clear();
2326 return;
2327 }
2328 const bvector_type* bv = bv_src[0];
2329 bv_target.copy(*bv, bm::finalization::READWRITE);
2330 for (unsigned i = 1; i < src_size; ++i)
2331 {
2332 bv = bv_src[i];
2333 BM_ASSERT(bv);
2334 bv_target.bit_or(*bv);
2335 }
2336}
2337
2338// ------------------------------------------------------------------------
2339
2340template<typename BV>
2342 const bvector_type_const_ptr* bv_src, size_t src_size)
2343{
2344 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
2345 BM_ASSERT(src_size);
2346
2347 if (src_size == 0)
2348 {
2349 bv_target.clear();
2350 return;
2351 }
2352 const bvector_type* bv = bv_src[0];
2353 bv_target.copy(*bv, bm::finalization::READWRITE);
2354
2355 for (unsigned i = 1; i < src_size; ++i)
2356 {
2357 bv = bv_src[i];
2358 BM_ASSERT(bv);
2359 bv_target.bit_and(*bv);
2360 }
2361}
2362
2363// ------------------------------------------------------------------------
2364
2365template<typename BV>
2367 const bvector_type_const_ptr* bv_src_and,
2368 size_t src_and_size,
2369 const bvector_type_const_ptr* bv_src_sub,
2370 size_t src_sub_size)
2371{
2372 BM_ASSERT(src_and_size);
2373 BM_ASSERT(!bv_target.is_ro()); // immutable vector used as a target
2374
2375 combine_and_horizontal(bv_target, bv_src_and, src_and_size);
2376
2377 for (unsigned i = 0; i < src_sub_size; ++i)
2378 {
2379 const bvector_type* bv = bv_src_sub[i];
2380 BM_ASSERT(bv);
2381 bv_target -= *bv;
2382 }
2383}
2384
2385// ------------------------------------------------------------------------
2386
2387template<typename BV>
2389 const bvector_type_const_ptr* bv_src,
2390 size_t src_size)
2391{
2392 top_block_size_ = resize_target(bv_target, bv_src, src_size);
2393
2394 // set initial carry overs all to 0
2395 ar_->carry_overs.resize(src_size);
2396 for (unsigned i = 0; i < src_size; ++i) // reset co flags
2397 ar_->carry_overs[i] = 0;
2398}
2399
2400// ------------------------------------------------------------------------
2401
2402template<typename BV>
2404 bvector_type& bv_target,
2405 const bvector_type_const_ptr* bv_src_and, size_t src_and_size,
2406 bool any)
2407{
2408 if (!src_and_size)
2409 {
2410 bv_target.clear();
2411 return false;
2412 }
2413 prepare_shift_right_and(bv_target, bv_src_and, src_and_size);
2414
2415 for (unsigned i = 0; i < bm::set_top_array_size; ++i)
2416 {
2417 if (i > top_block_size_)
2418 {
2419 if (!any_carry_overs(ar_->carry_overs.data(), src_and_size))
2420 break; // quit early if there is nothing to carry on
2421 }
2422
2423 unsigned j = 0;
2424 do
2425 {
2426 bool found =
2427 combine_shift_right_and(i, j, bv_target, bv_src_and, src_and_size);
2428 if (found && any)
2429 return found;
2430 } while (++j < bm::set_sub_array_size);
2431
2432 } // for i
2433
2434 if (compute_count_)
2435 return bool(count_);
2436
2437 return bv_target.any();
2438}
2439
2440// ------------------------------------------------------------------------
2441
2442template<typename BV>
2444 bvector_type& bv_target,
2445 const bvector_type_const_ptr* bv_src,
2446 size_t src_size)
2447{
2448 bm::word_t* blk = temp_blk_ ? temp_blk_ : tb_ar_->tb1;
2449 unsigned char* carry_overs = ar_->carry_overs.data();
2450
2451 bm::id64_t digest = ~0ull; // start with a full content digest
2452
2453 bool blk_zero = false;
2454 // first initial block is just copied over from the first AND
2455 {
2456 const blocks_manager_type& bman_arg = bv_src[0]->get_blocks_manager();
2457 BM_ASSERT(bman_arg.is_init());
2458 const bm::word_t* arg_blk = bman_arg.get_block(i, j);
2459 if (BM_IS_GAP(arg_blk))
2460 {
2461 bm::bit_block_set(blk, 0);
2462 bm::gap_add_to_bitset(blk, BMGAP_PTR(arg_blk));
2463 }
2464 else
2465 {
2466 if (arg_blk)
2467 {
2468 bm::bit_block_copy(blk, arg_blk);
2469 }
2470 else
2471 {
2472 blk_zero = true; // set flag for delayed block init
2473 digest = 0;
2474 }
2475 }
2476 carry_overs[0] = 0;
2477 }
2478
2479 for (unsigned k = 1; k < src_size; ++k)
2480 {
2481 unsigned carry_over = carry_overs[k];
2482 if (!digest && !carry_over) // 0 into "00000" block >> 0
2483 continue;
2484 if (blk_zero) // delayed temp block 0-init requested
2485 {
2486 bm::bit_block_set(blk, 0);
2487 blk_zero = !blk_zero; // = false
2488 }
2489 const bm::word_t* arg_blk = get_arg_block(bv_src, k, i, j);
2490 carry_overs[k] = (unsigned char)
2491 process_shift_right_and(blk, arg_blk, digest, carry_over);
2492 BM_ASSERT(carry_overs[k] == 0 || carry_overs[k] == 1);
2493 } // for k
2494
2495 if (blk_zero) // delayed temp block 0-init
2496 {
2497 bm::bit_block_set(blk, 0);
2498 }
2499 // block now gets emitted into the target bit-vector
2500 if (digest)
2501 {
2503
2504 if (compute_count_)
2505 {
2506 unsigned cnt = bm::bit_block_count(blk, digest);
2507 count_ += cnt;
2508 }
2509 else
2510 {
2511 blocks_manager_type& bman_target = bv_target.get_blocks_manager();
2512 bman_target.opt_copy_bit_block(i, j, blk, opt_mode_, tb_ar_->tb_opt);
2513 }
2514 return true;
2515 }
2516 return false;
2517}
2518
2519// ------------------------------------------------------------------------
2520
2521template<typename BV>
2524 const bm::word_t* BMRESTRICT arg_blk,
2525 digest_type& BMRESTRICT digest,
2526 unsigned carry_over) BMNOEXCEPT
2527{
2528 BM_ASSERT(carry_over == 1 || carry_over == 0);
2529
2530 if (BM_IS_GAP(arg_blk)) // GAP argument
2531 {
2532 if (digest)
2533 {
2534 carry_over =
2535 bm::bit_block_shift_r1_and_unr(blk, carry_over,
2536 FULL_BLOCK_REAL_ADDR, &digest);
2537 }
2538 else // digest == 0, but carry_over can change that
2539 {
2540 blk[0] = carry_over;
2541 carry_over = 0;
2542 digest = blk[0]; // NOTE: this does NOT account for AND (yet)
2543 }
2544 BM_ASSERT(bm::calc_block_digest0(blk) == digest);
2545
2546 bm::gap_and_to_bitset(blk, BMGAP_PTR(arg_blk), digest);
2547 digest = bm::update_block_digest0(blk, digest);
2548 }
2549 else // 2 bit-blocks
2550 {
2551 if (arg_blk) // use fast fused SHIFT-AND operation
2552 {
2553 if (digest)
2554 {
2555 carry_over =
2556 bm::bit_block_shift_r1_and_unr(blk, carry_over, arg_blk,
2557 &digest);
2558 }
2559 else // digest == 0
2560 {
2561 blk[0] = carry_over & arg_blk[0];
2562 carry_over = 0;
2563 digest = blk[0];
2564 }
2565 BM_ASSERT(bm::calc_block_digest0(blk) == digest);
2566 }
2567 else // arg is zero - target block => zero
2568 {
2569 carry_over = blk[bm::set_block_size-1] >> 31; // carry out
2570 if (digest)
2571 {
2572 bm::bit_block_set(blk, 0); // TODO: digest based set
2573 digest = 0;
2574 }
2575 }
2576 }
2577 return carry_over;
2578}
2579
2580// ------------------------------------------------------------------------
2581
2582template<typename BV>
2584 const bvector_type_const_ptr* bv_src,
2585 unsigned k, unsigned i, unsigned j) BMNOEXCEPT
2586{
2587 return bv_src[k]->get_blocks_manager().get_block(i, j);
2588}
2589
2590// ------------------------------------------------------------------------
2591
2592template<typename BV>
2593bool aggregator<BV>::any_carry_overs(const unsigned char* carry_overs,
2594 size_t co_size) BMNOEXCEPT
2595{
2596 // TODO: loop unroll?
2597 unsigned acc = carry_overs[0];
2598 for (size_t i = 1; i < co_size; ++i)
2599 acc |= carry_overs[i];
2600 return acc;
2601}
2602
2603// ------------------------------------------------------------------------
2604
2605template<typename BV>
2607{
2608 bvector_type* bv_target = check_create_target(); // create target vector
2609 BM_ASSERT(bv_target);
2610
2611 temp_blk_ = temp_block;
2612
2613 switch (operation_)
2614 {
2615 case BM_NOT_DEFINED:
2616 break;
2617 case BM_SHIFT_R_AND:
2618 prepare_shift_right_and(*bv_target, ag_.arg_bv0.data(), ag_.arg_bv0.size());//arg_group0_size);
2619 operation_status_ = op_prepared;
2620 break;
2621 default:
2622 BM_ASSERT(0);
2623 } // switch
2624}
2625
2626// ------------------------------------------------------------------------
2627
2628template<typename BV>
2630aggregator<BV>::run_step(unsigned i, unsigned j)
2631{
2632 BM_ASSERT(operation_status_ == op_prepared || operation_status_ == op_in_progress);
2634
2635 switch (operation_)
2636 {
2637 case BM_NOT_DEFINED:
2638 break;
2639
2640 case BM_SHIFT_R_AND:
2641 {
2642 if (i > top_block_size_)
2643 {
2644 if (!this->any_carry_overs(ar_->carry_overs.data(), ag_.arg_bv0.size()))//arg_group0_size))
2645 {
2646 operation_status_ = op_done;
2647 return operation_status_;
2648 }
2649 }
2650 //bool found =
2651 this->combine_shift_right_and(i, j, *bv_target_,
2652 ag_.arg_bv0.data(), ag_.arg_bv0.size());//arg_group0_size);
2653 operation_status_ = op_in_progress;
2654 }
2655 break;
2656 default:
2657 BM_ASSERT(0);
2658 break;
2659 } // switch
2660
2661 return operation_status_;
2662}
2663
2664
2665// ------------------------------------------------------------------------
2666// aggregator::pipeline
2667// ------------------------------------------------------------------------
2668
2669template<typename BV> template<class Opt>
2671{
2672 size_t sz = arg_vect_.size();
2673 arg_groups** arr = arg_vect_.data();
2674 for (size_t i = 0; i < sz; ++i)
2675 free_arg_group(arr[i]);
2676 sz = bv_res_vect_.size();
2677 bvector_type** bv_arr = bv_res_vect_.data();
2678 for (size_t i = 0; i < sz; ++i)
2679 {
2680 bvector_type* bv = bv_arr[i];
2681 delete bv;
2682 } // for i
2683 sz = bcache_.blk_vect_.size();
2684 bm::word_t** blk_arr = bcache_.blk_vect_.data();
2685 for (size_t i = 0; i < sz; ++i)
2686 bm::aligned_free(blk_arr[i]);
2687}
2688
2689// ------------------------------------------------------------------------
2690
2691template<typename BV> template<class Opt>
2693{
2694 if (is_complete_)
2695 return;
2696
2697 if constexpr (Opt::is_make_results())
2698 {
2699 BM_ASSERT(!bv_res_vect_.size());
2700 size_t sz = arg_vect_.size();
2701 bv_res_vect_.resize(sz);
2702 bvector_type** bv_arr = bv_res_vect_.data();
2703 for (size_t i = 0; i < sz; ++i)
2704 bv_arr[i] = 0;
2705 }
2706 if constexpr (Opt::is_compute_counts())
2707 {
2708 size_t sz = arg_vect_.size();
2709 count_res_vect_.resize(sz);
2710 size_type* cnt_arr = count_res_vect_.data();
2711 ::memset(cnt_arr, 0, sz * sizeof(cnt_arr[0]));
2712 }
2713
2714 const arg_vector_type& pipe_args = get_args_vector();
2715 size_t pipe_size = pipe_args.size();
2716
2717 for (size_t p = 0; p < pipe_size; ++p)
2718 {
2719 arg_groups* ag = pipe_args[p];
2720 complete_arg_group(ag);
2721
2722 const bvector_type_const_ptr* bv_src_and = ag->arg_bv0.data();
2723 size_t src_and_size = ag->arg_bv0.size();
2724 unsigned top_blocks1 = max_top_blocks(bv_src_and, src_and_size);
2725 if (top_blocks1 > top_blocks_)
2726 top_blocks_ = top_blocks1;
2727
2728 const bvector_type_const_ptr* bv_src_sub = ag->arg_bv1.data();
2729 size_t src_sub_size = ag->arg_bv1.size();
2730 unsigned top_blocks2 = max_top_blocks(bv_src_sub, src_sub_size);
2731 if (top_blocks2 > top_blocks_)
2732 top_blocks_ = top_blocks2;
2733
2734 } // for p
2735 is_complete_ = true;
2736
2737 BM_ASSERT(bcache_.bv_inp_vect_.size() == bcache_.cnt_vect_.size());
2738 BM_ASSERT(bcache_.bv_inp_vect_.size() == bcache_.blk_vect_.size());
2739 BM_ASSERT(bcache_.bv_inp_vect_.size() == bcache_.blk_ij_vect_.size());
2740}
2741
2742// ------------------------------------------------------------------------
2743
2744template<typename BV> template<class Opt>
2746{
2747 BM_ASSERT(ag);
2748 auto sz = ag->arg_bv0.size();
2749 total_vect_ += sz;
2750 complete_arg_sub_group(ag->arg_idx0, ag->arg_bv0.data(), sz);
2751 sz = ag->arg_bv1.size();
2752 total_vect_ += sz;
2753 complete_arg_sub_group(ag->arg_idx1, ag->arg_bv1.data(), sz);
2754}
2755
2756// ------------------------------------------------------------------------
2757
2758template<typename BV> template<class Opt>
2760 index_vector_type& idx_vect,
2761 const bvector_type_const_ptr* bv_src, size_t size)
2762{
2763 BM_ASSERT(idx_vect.size() == 0);
2764
2765 for (size_t k = 0; k < size; ++k)
2766 {
2767 bool found(false); size_t bv_idx(0);
2768 const bvector_type* bv = bv_src[k];
2769 if (bv)
2770 {
2771 const bvector_type** bv_arr = bcache_.bv_inp_vect_.data();
2772 found =
2773 bm::find_ptr((void**)bv_arr, bcache_.bv_inp_vect_.size(),
2774 bv, &bv_idx);
2775 }
2776 if (found)
2777 bcache_.cnt_vect_[bv_idx]++; // increment vector usage counter
2778 else // not found (new one!)
2779 {
2780 bv_idx = bcache_.bv_inp_vect_.size();
2781 bcache_.bv_inp_vect_.push_back(bv); // register a new bv (0-cnt)
2782 bcache_.cnt_vect_.push_back(0);
2783 bcache_.blk_vect_.push_back(0); // NULL ptr
2784 bcache_.blk_ij_vect_.push_back(bm::pair<unsigned, unsigned>(0u, 0u));
2785 }
2786 // each arg group
2787 idx_vect.push_back(bv_idx);
2788 } // for k
2789
2790 BM_ASSERT(idx_vect.size() == size);
2791}
2792
2793// ------------------------------------------------------------------------
2794
2795template<typename BV> template<class Opt>
2796typename aggregator<BV>::arg_groups*
2798{
2799 BM_ASSERT(!is_complete_);
2800 arg_groups* arg = construct_arg_group();
2801 arg_vect_.push_back(arg);
2802 return arg;
2803}
2804
2805// ------------------------------------------------------------------------
2806
2807template<typename BV> template<class Opt>
2809{
2810 const size_t cache_size = 256 * 1024; // estimation-speculation (L2)
2811 // ad-hoc estimate (not correct!) uses 2/3 of bit-vectors size (some are GAPs)
2812 // TODO: need to use real sparse vector statistics (AVG block size)
2813 //
2814 const float block_size = 0.75f * (bm::set_block_size * sizeof(bm::word_t));
2815 const float bv_struct_overhead = (64 * 8); // 8 cache lines in bytes
2816 const float cached_vect = float(cache_size) / float(block_size + bv_struct_overhead);
2817
2818 size_t bv_count = unique_vectors();
2819 size_t args_total = arg_vect_.size(); // number of arg groups
2820 if ((bv_count < cached_vect) || (args_total < 2)) // worst case fit in L2
2821 return args_total;
2822
2823 size_t avg_vect_per_group = total_vect_ / args_total;
2824
2825 const float reuse_coeff = 0.7f; // spec. coeff of resue of vectors
2826 float f_batch_size =
2827 (1+reuse_coeff)*(float(avg_vect_per_group) / float(cached_vect) + 0.99f);
2828 size_t batch_size = size_t(f_batch_size);
2829
2830 return batch_size;
2831}
2832
2833
2834// ------------------------------------------------------------------------
2835// Arg Groups
2836// ------------------------------------------------------------------------
2837
2838template<typename BV>
2840 unsigned agr_group)
2841{
2842 BM_ASSERT_THROW(agr_group <= 1, BM_ERR_RANGE);
2843 BM_ASSERT(agr_group <= 1);
2844 switch (agr_group)
2845 {
2846 case 0:
2847 if (!bv)
2848 return arg_bv0.size();
2849 arg_bv0.push_back(bv);
2850 return arg_bv0.size();
2851 case 1:
2852 if (!bv)
2853 return arg_bv1.size();
2854 arg_bv1.push_back(bv);
2855 return arg_bv1.size();
2856 default:
2857 BM_ASSERT(0);
2858 }
2859 return 0;
2860}
2861
2862// ------------------------------------------------------------------------
2863
2864
2865} // bm
2866
2867
2868#endif
#define BM_DECLARE_TEMP_BLOCK(x)
Definition: bm.h:47
Algorithms for bvector<>
Definitions(internal)
#define BMRESTRICT
Definition: bmdef.h:203
#define BMNOEXCEPT
Definition: bmdef.h:82
#define BMGAP_PTR(ptr)
Definition: bmdef.h:189
#define BM_IS_GAP(ptr)
Definition: bmdef.h:191
#define BM_ASSERT
Definition: bmdef.h:139
#define BM_ASSERT_THROW(x, xerrcode)
Definition: bmdef.h:338
#define FULL_BLOCK_FAKE_ADDR
Definition: bmdef.h:158
#define FULL_BLOCK_REAL_ADDR
Definition: bmdef.h:157
Bit manipulation primitives (internal)
Pipeline vector for running a group of aggregation operations on a family of vectors.
Definition: bmaggregator.h:224
bool is_complete_
ready to run state flag
Definition: bmaggregator.h:330
bool is_complete() const BMNOEXCEPT
return true if pipeline is ready for execution (complete)
Definition: bmaggregator.h:269
size_type size() const BMNOEXCEPT
Return size() of pileine.
Definition: bmaggregator.h:272
size_t total_vect_
total number of vector mentions in all groups
Definition: bmaggregator.h:331
const arg_vector_type & get_args_vector() const BMNOEXCEPT
Return argument vector used for pipeline execution.
Definition: bmaggregator.h:279
bvect_vector_type & get_bv_res_vector() BMNOEXCEPT
Return results vector used for pipeline execution.
Definition: bmaggregator.h:283
void set_or_target(bvector_type *bv_or) BMNOEXCEPT
Attach OR (aggregator vector).
Definition: bmaggregator.h:251
size_t unique_vectors() const BMNOEXCEPT
Return number of unique vectors in the pipeline (after complete())
Definition: bmaggregator.h:301
pipeline_bcache & get_bcache() BMNOEXCEPT
Definition: bmaggregator.h:310
bvector_type * bv_or_target_
OR target bit-bector ptr.
Definition: bmaggregator.h:340
bv_count_vector_type & get_bv_count_vector() BMNOEXCEPT
Return results vector count used for pipeline execution.
Definition: bmaggregator.h:287
unsigned top_blocks_
top-level structure size, max of all bvectors
Definition: bmaggregator.h:339
bv_count_vector_type count_res_vect_
results (counts)
Definition: bmaggregator.h:335
unsigned get_top_blocks() const BMNOEXCEPT
Return number of top blocks after complete.
Definition: bmaggregator.h:315
arg_groups * add()
Add new arguments group.
size_type search_count_limit_
search limit by count
Definition: bmaggregator.h:336
pipeline(const pipeline &)=delete
pipeline & operator=(const pipeline &)=delete
void complete()
Prepare pipeline for the execution (resize and init internal structures) Once complete,...
pipeline_bcache bcache_
blocks cache structure
Definition: bmaggregator.h:338
arg_vector_type arg_vect_
input arg. groups
Definition: bmaggregator.h:332
run_options options_
execution parameters
Definition: bmaggregator.h:329
run_options & options() BMNOEXCEPT
Set pipeline run options.
Definition: bmaggregator.h:232
const bv_vector_type & get_all_input_vect() const BMNOEXCEPT
Definition: bmaggregator.h:295
void set_search_count_limit(size_type limit) BMNOEXCEPT
Set search limit for results.
Definition: bmaggregator.h:260
const count_vector_type & get_all_input_cnt_vect() const BMNOEXCEPT
Definition: bmaggregator.h:297
const run_options & get_options() const BMNOEXCEPT
Get pipeline run options.
Definition: bmaggregator.h:235
size_t compute_run_batch() const BMNOEXCEPT
Function looks at the pipeline to apply euristics to suggest optimal run_batch parameter.
bvect_vector_type bv_res_vect_
results (bit-vector ptrs)
Definition: bmaggregator.h:334
Algorithms for fast aggregation of a group of bit-vectors.
Definition: bmaggregator.h:122
BV::block_idx_type block_idx_type
Definition: bmaggregator.h:638
void combine_or(unsigned i, unsigned j, bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
void set_compute_count(bool count_mode) BMNOEXCEPT
Definition: bmaggregator.h:363
bm::word_t * cache_gap_block(const bm::word_t *arg_blk, const size_t *src_idx, size_t k, unsigned i, unsigned j)
digest_type combine_and_sub(unsigned i, unsigned j, const size_t *and_idx, const bvector_type_const_ptr *bv_src_and, size_t src_and_size, const size_t *sub_idx, const bvector_type_const_ptr *bv_src_sub, size_t src_sub_size, int *is_result_full)
bvector_type * check_create_target()
Definition: bmaggregator.h:973
bool test_gap_blocks_sub(size_t block_count, unsigned bit_idx)
arg_groups * arg_groups_type_ptr
Definition: bmaggregator.h:181
digest_type process_bit_blocks_sub(const arena &ar, digest_type digest)
bm::heap_vector< bm::pair< unsigned, unsigned >, allocator_type, true > block_ij_vector_type
Definition: bmaggregator.h:191
void combine_and(unsigned i, unsigned j, bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
void combine_or(bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
Aggregate group of vectors using logical OR.
void reset_range_hint() BMNOEXCEPT
Reset range hint to false.
Definition: bmaggregator.h:953
static unsigned process_shift_right_and(bm::word_t *BMRESTRICT blk, const bm::word_t *BMRESTRICT arg_blk, digest_type &BMRESTRICT digest, unsigned carry_over) BMNOEXCEPT
static unsigned find_effective_sub_block_size(unsigned i, const bvector_type_const_ptr *bv_src1, size_t src_size1, const bvector_type_const_ptr *bv_src2, size_t src_size2) BMNOEXCEPT
bm::heap_vector< bvector_type *, allocator_type, true > bvect_vector_type
Definition: bmaggregator.h:134
bm::heap_vector< bvector_type_const_ptr, allocator_type, true > bv_vector_type
Definition: bmaggregator.h:132
void combine_shift_right_and(bvector_type &bv_target)
Aggregate added group of vectors using SHIFT-RIGHT and logical AND Operation does NOT perform an expl...
bm::heap_vector< size_type, allocator_type, true > bv_count_vector_type
Definition: bmaggregator.h:187
BV::allocator_type allocator_type
Definition: bmaggregator.h:126
static void free_arg_group(arg_groups *arg)
Definition: bmaggregator.h:800
operation_status run_step(unsigned i, unsigned j)
Run a step of current arrgegation operation.
void combine_and_sub(TPipe &pipe)
Run AND-SUB: AND (groups1) AND NOT ( OR(group0)) for a pipeline.
void stage(bm::word_t *temp_block)
Prepare operation, create internal resources, analyse dependencies.
bool combine_and_sub(bvector_type &bv_target)
Aggregate added group of vectors using fused logical AND-SUB Operation does NOT perform an explicit r...
bm::heap_vector< size_t, allocator_type, true > index_vector_type
Definition: bmaggregator.h:136
bm::id64_t digest_type
Definition: bmaggregator.h:128
void reset()
Reset aggregate groups, forget all attached vectors.
Definition: bmaggregator.h:932
bvector_type::blocks_manager_type blocks_manager_type
Definition: bmaggregator.h:637
void combine_or(bvector_type &bv_target)
Aggregate added group of vectors using logical OR Operation does NOT perform an explicit reset of arg...
Definition: bmaggregator.h:994
bm::heap_vector< unsigned, allocator_type, true > count_vector_type
Definition: bmaggregator.h:185
BV::size_type size_type
Definition: bmaggregator.h:125
bool combine_and_sub(bvector_type &bv_target, bool any)
Aggregate added group of vectors using fused logical AND-SUB Operation does NOT perform an explicit r...
void combine_and(bvector_type &bv_target)
Aggregate added group of vectors using logical AND Operation does NOT perform an explicit reset of ar...
digest_type process_gap_blocks_sub(const arena &ar, digest_type digest)
void set_operation(int op_code) BMNOEXCEPT
Set operation code for the aggregator.
Definition: bmaggregator.h:608
bm::heap_vector< const bm::word_t *, allocator_type, true > block_ptr_vector_type
Definition: bmaggregator.h:640
bool combine_shift_right_and(bvector_type &bv_target, const bvector_type_const_ptr *bv_src_and, size_t src_and_size, bool any)
Fusion aggregate group of vectors using SHIFT right with AND.
bm::word_t * sort_input_blocks_or(const size_t *src_idx, const bvector_type_const_ptr *bv_src, size_t src_size, unsigned i, unsigned j)
const bvector_type * get_target() const BMNOEXCEPT
Definition: bmaggregator.h:623
static arg_groups * construct_arg_group()
Definition: bmaggregator.h:794
const bvector_type * bvector_type_const_ptr
Definition: bmaggregator.h:127
static const bm::word_t * get_arg_block(const bvector_type_const_ptr *bv_src, unsigned k, unsigned i, unsigned j) BMNOEXCEPT
void set_range_hint(size_type from, size_type to) BMNOEXCEPT
Set search hint for the range, where results needs to be searched (experimental for internal use).
Definition: bmaggregator.h:963
void set_optimization(typename bvector_type::optmode opt=bvector_type::opt_compress) BMNOEXCEPT
set on-the-fly bit-block compression By default aggregator does not try to optimize result,...
Definition: bmaggregator.h:359
static unsigned find_effective_sub_block_size(unsigned i, const bvector_type_const_ptr *bv_src, size_t src_size, bool top_null_as_zero) BMNOEXCEPT
bool find_first_and_sub(size_type &idx)
Aggregate added group of vectors using fused logical AND-SUB, find the first match.
size_t add(const bvector_type *bv, unsigned agr_group=0)
Attach source bit-vector to a argument group (0 or 1).
Definition: bmaggregator.h:986
bool combine_shift_right_and(unsigned i, unsigned j, bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
operation
Codes for aggregation operations which can be pipelined for efficient execution.
Definition: bmaggregator.h:142
int get_operation() const BMNOEXCEPT
Get current operation code.
Definition: bmaggregator.h:605
bm::heap_vector< unsigned char, allocator_type, true > uchar_vector_type
Definition: bmaggregator.h:644
static void free_arena(arena *ar) BMNOEXCEPT
Definition: bmaggregator.h:787
bool combine_and_sub(BII bi, const bvector_type_const_ptr *bv_src_and, size_t src_and_size, const bvector_type_const_ptr *bv_src_sub, size_t src_sub_size)
void combine_and_horizontal(bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
Horizontal AND aggregation (potentially slower) method.
bm::heap_vector< bm::word_t *, allocator_type, true > blockptr_vector_type
Definition: bmaggregator.h:189
digest_type process_gap_blocks_and(const arena &ar, digest_type digest)
bool test_gap_blocks_and(size_t block_count, unsigned bit_idx)
size_type count() const
Definition: bmaggregator.h:487
bool combine_and_sub_bi(BII bi)
Aggregate added group of vectors using fused logical AND-SUB.
bool find_first_and_sub(size_type &idx, const bvector_type_const_ptr *bv_src_and, size_t src_and_size, const bvector_type_const_ptr *bv_src_sub, size_t src_sub_size)
void prepare_shift_right_and(bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
void process_gap_blocks_or(const arena &ar)
static unsigned resize_target(bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size, bool init_clear=true)
bvector_type::allocator_type::allocator_pool_type allocator_pool_type
Definition: bmaggregator.h:130
static arena * construct_arena()
Definition: bmaggregator.h:782
static unsigned max_top_blocks(const bvector_type_const_ptr *bv_src, size_t src_size) BMNOEXCEPT
bm::id64_t get_cache_gap_hits() const BMNOEXCEPT
Definition: bmaggregator.h:633
bm::heap_vector< arg_groups_type_ptr, allocator_type, true > arg_vector_type
Definition: bmaggregator.h:183
bm::word_t * sort_input_blocks_and(const size_t *src_idx, const bvector_type_const_ptr *bv_src, size_t src_size, unsigned i, unsigned j)
bool combine_and_sub(bvector_type &bv_target, const bvector_type_const_ptr *bv_src_and, size_t src_and_size, const bvector_type_const_ptr *bv_src_sub, size_t src_sub_size, bool any)
Fusion aggregate group of vectors using logical AND MINUS another set.
bm::word_t * get_temp_block() BMNOEXCEPT
Definition: bmaggregator.h:625
static bool any_carry_overs(const unsigned char *carry_overs, size_t co_size) BMNOEXCEPT
bm::heap_vector< const bm::gap_word_t *, allocator_type, true > gap_block_ptr_vector_type
Definition: bmaggregator.h:642
digest_type process_bit_blocks_and(const arena &ar, digest_type digest)
void combine_or_horizontal(bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
Horizontal OR aggregation (potentially slower) method.
void combine_and_sub_horizontal(bvector_type &bv_target, const bvector_type_const_ptr *bv_src_and, size_t src_and_size, const bvector_type_const_ptr *bv_src_sub, size_t src_sub_size)
Horizontal AND-SUB aggregation (potentially slower) method.
void combine_and(bvector_type &bv_target, const bvector_type_const_ptr *bv_src, size_t src_size)
Aggregate group of vectors using logical AND.
operation_status get_operation_status() const
Definition: bmaggregator.h:621
bool process_bit_blocks_or(blocks_manager_type &bman_target, unsigned i, unsigned j, const arena &ar)
Bitvector Bit-vector container with runtime compression of bits.
Definition: bm.h:115
optmode
Optimization mode Every next level means additional checks (better compression vs time)
Definition: bm.h:133
@ opt_compress
compress blocks when possible (GAP/prefix sum)
Definition: bm.h:137
allocator_type::allocator_pool_type allocator_pool_type
Definition: bm.h:118
blocks_manager< Alloc > blocks_manager_type
Definition: bm.h:119
blocks_manager_type::block_idx_type block_idx_type
Definition: bm.h:120
bm::id64_t bit_block_and_5way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src0, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2, const bm::word_t *BMRESTRICT src3, bm::id64_t digest) BMNOEXCEPT
digest based bit-block AND 5-way
Definition: bmfunc.h:6916
void bit_block_copy(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Bitblock copy operation.
Definition: bmfunc.h:6743
void block_init_digest0(bm::word_t *const block, bm::id64_t digest) BMNOEXCEPT
Init block with 000111000 pattren based on digest.
Definition: bmfunc.h:1062
bm::id64_t bit_block_and(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Plain bitblock AND operation. Function does not analyse availability of source and destination blocks...
Definition: bmfunc.h:6824
bm::id_t bit_block_count(const bm::word_t *block) BMNOEXCEPT
Bitcount for bit block.
Definition: bmfunc.h:5017
int for_each_bit_blk(const bm::word_t *block, SIZE_TYPE offset, Func &bit_functor)
for-each visitor, calls a visitor functor for each 1 bit group
Definition: bmalgo_impl.h:1597
bool bit_block_or_5way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2, const bm::word_t *BMRESTRICT src3, const bm::word_t *BMRESTRICT src4) BMNOEXCEPT
5 way (target, source1, source2) bitblock OR operation. Function does not analyse availability of sou...
Definition: bmfunc.h:7836
bool bit_block_shift_r1_and_unr(bm::word_t *BMRESTRICT block, bm::word_t co_flag, const bm::word_t *BMRESTRICT mask_block, bm::id64_t *BMRESTRICT digest) BMNOEXCEPT
Right bit-shift bitblock by 1 bit (reference) + AND.
Definition: bmfunc.h:5928
BMFORCEINLINE unsigned word_bitcount64(bm::id64_t x) BMNOEXCEPT
Definition: bmutil.h:596
bm::id64_t calc_block_digest0(const bm::word_t *const block) BMNOEXCEPT
Compute digest for 64 non-zero areas.
Definition: bmfunc.h:1092
bm::id64_t bit_block_and_2way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2, bm::id64_t digest) BMNOEXCEPT
digest based bit-block AND
Definition: bmfunc.h:6983
bool bit_find_first(const bm::word_t *BMRESTRICT block, unsigned *BMRESTRICT pos) BMNOEXCEPT
BIT block find the first set bit.
Definition: bmfunc.h:8474
bool bit_block_or_3way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2) BMNOEXCEPT
3 way (target | source1 | source2) bitblock OR operation. Function does not analyse availability of s...
Definition: bmfunc.h:7792
void bit_block_set(bm::word_t *BMRESTRICT dst, bm::word_t value) BMNOEXCEPT
Bitblock memset operation.
Definition: bmfunc.h:4422
BMFORCEINLINE bm::id64_t digest_mask(unsigned from, unsigned to) BMNOEXCEPT
Compute digest mask for [from..to] positions.
Definition: bmfunc.h:1017
bool bit_block_or(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Plain bitblock OR operation. Function does not analyse availability of source and destination blocks.
Definition: bmfunc.h:7675
bool bit_is_all_zero(const bm::word_t *BMRESTRICT start) BMNOEXCEPT
Returns "true" if all bits in the block are 0.
Definition: bmfunc.h:1522
bool bit_find_first_if_1(const bm::word_t *BMRESTRICT block, unsigned *BMRESTRICT first, bm::id64_t digest) BMNOEXCEPT
BIT block find the first set bit if only 1 bit is set.
Definition: bmfunc.h:8547
bm::id64_t update_block_digest0(const bm::word_t *const block, bm::id64_t digest) BMNOEXCEPT
Compute digest for 64 non-zero areas based on existing digest (function revalidates zero areas)
Definition: bmfunc.h:1134
bm::id64_t bit_block_sub(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Plain bitblock SUB (AND NOT) operation. Function does not analyse availability of source and destinat...
Definition: bmfunc.h:7945
bool is_bits_one(const bm::wordop_t *start) BMNOEXCEPT
Returns "true" if all bits in the block are 1.
Definition: bmfunc.h:6047
@ READWRITE
mutable (read-write object)
@ BM_GAP
GAP compression is ON.
Definition: bmconst.h:147
unsigned gap_test_unr(const T *BMRESTRICT buf, const unsigned pos) BMNOEXCEPT
Tests if bit = pos is true. Analog of bm::gap_test with SIMD unrolling.
Definition: bmfunc.h:1784
void gap_and_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
ANDs GAP block to bitblock.
Definition: bmfunc.h:4067
void gap_convert_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT buf, unsigned len=0) BMNOEXCEPT
GAP block to bitblock conversion.
Definition: bmfunc.h:4441
void gap_sub_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
SUB (AND NOT) GAP block to bitblock.
Definition: bmfunc.h:3900
void gap_add_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr, unsigned len) BMNOEXCEPT
Adds(OR) GAP block to bitblock.
Definition: bmfunc.h:4016
BMFORCEINLINE bm::gap_word_t gap_length(const bm::gap_word_t *BMRESTRICT buf) BMNOEXCEPT
Returs GAP block length.
Definition: bmfunc.h:1575
bm::agg_run_options< agg_disable_result_bvectors, agg_disable_counts > agg_opt_disable_bvects_and_counts
Pre-defined aggregator options to disable both intermediate results and counts.
Definition: bmaggregator.h:86
void combine_and(BV &bv, It first, It last)
AND Combine bitvector and the iterable sequence.
Definition: bmalgo_impl.h:1365
const bool agg_disable_search_masks
Definition: bmaggregator.h:55
const bool agg_produce_result_bvectors
Definition: bmaggregator.h:51
bm::agg_run_options< agg_disable_result_bvectors, agg_compute_counts > agg_opt_only_counts
Pre-defined aggregator options for counts-only (results dropped) operation.
Definition: bmaggregator.h:95
void combine_or(BV &bv, It first, It last)
OR Combine bitvector and the iterable sequence.
Definition: bmalgo_impl.h:1080
void aggregator_pipeline_execute(It first, It last)
Experimental method ro run multiple aggregators in sync.
Definition: bmaggregator.h:865
const bool agg_disable_counts
Definition: bmaggregator.h:54
bm::agg_run_options< agg_produce_result_bvectors, agg_compute_counts > agg_opt_bvect_and_counts
Pre-defined aggregator options for results plus counts operation.
Definition: bmaggregator.h:103
const bool agg_disable_result_bvectors
Definition: bmaggregator.h:52
const bool agg_compute_counts
Definition: bmaggregator.h:53
Definition: bm.h:78
const unsigned set_array_mask
Definition: bmconst.h:97
const unsigned id_max
Definition: bmconst.h:109
unsigned int word_t
Definition: bmconst.h:39
const unsigned set_block_mask
Definition: bmconst.h:57
void aligned_free(void *ptr) BMNOEXCEPT
Aligned free.
Definition: bmalloc.h:465
const unsigned set_sub_array_size
Definition: bmconst.h:95
BMFORCEINLINE void get_block_coord(BI_TYPE nb, unsigned &i, unsigned &j) BMNOEXCEPT
Recalc linear bvector block index into 2D matrix coordinates.
Definition: bmfunc.h:172
void * aligned_new_malloc(size_t size)
Aligned malloc (unlike classic malloc it throws bad_alloc exception)
Definition: bmalloc.h:437
const unsigned set_word_shift
Definition: bmconst.h:72
const unsigned set_block_size
Definition: bmconst.h:55
unsigned long long int id64_t
Definition: bmconst.h:35
bool find_ptr(const void *const *p_arr, size_t arr_size, const void *ptr, size_t *idx) BMNOEXCEPT
Scan search for pointer value in unordered array.
Definition: bmfunc.h:9710
const unsigned set_array_shift
Definition: bmconst.h:96
bm::id_t block_to_global_index(unsigned i, unsigned j, unsigned block_idx) BMNOEXCEPT
calculate bvector<> global bit-index from block-local coords
Definition: bmfunc.h:9739
unsigned short gap_word_t
Definition: bmconst.h:78
const unsigned gap_max_bits
Definition: bmconst.h:81
const unsigned set_top_array_size
Definition: bmconst.h:110
const unsigned set_block_shift
Definition: bmconst.h:56
const unsigned set_word_mask
Definition: bmconst.h:73
const unsigned bits_in_block
Definition: bmconst.h:114
id64_t wordop_t
Definition: bmconst.h:130
Aggregation options to control execution Default settings are to support only result bit-vector filte...
Definition: bmaggregator.h:66
static constexpr bool is_make_results() BMNOEXCEPT
make result(target) vectors (aggregation search results) (Default: true) when false is used - means w...
Definition: bmaggregator.h:69
static constexpr bool is_masks() BMNOEXCEPT
Support for masking operations (Default: false)
Definition: bmaggregator.h:77
static constexpr bool is_compute_counts() BMNOEXCEPT
Compute counts for the target vectors, when set to true, population count is computed for each result...
Definition: bmaggregator.h:73
Temporary operations vectors.
Definition: bmaggregator.h:688
gap_block_ptr_vector_type v_arg_and_blk_gap
source GAP blocks list (AND)
Definition: bmaggregator.h:693
block_ptr_vector_type v_arg_and_blk
source blocks list (AND)
Definition: bmaggregator.h:692
block_ptr_vector_type v_arg_or_blk
source blocks list (OR)
Definition: bmaggregator.h:690
gap_block_ptr_vector_type v_arg_or_blk_gap
source GAP blocks list (OR)
Definition: bmaggregator.h:691
block_ptr_vector_type v_arg_tmp_blk
source blocks list
Definition: bmaggregator.h:689
uchar_vector_type carry_overs
shift carry over flags
Definition: bmaggregator.h:694
Aggregator arg groups.
Definition: bmaggregator.h:157
size_t add(const bvector_type *bv, unsigned agr_group)
Add bit-vector pointer to its aggregation group.
bv_vector_type arg_bv0
arg group 0
Definition: bmaggregator.h:158
bv_vector_type arg_bv1
arg group 1
Definition: bmaggregator.h:159
void reset()
Reset argument groups to zero.
Definition: bmaggregator.h:164
index_vector_type arg_idx0
indexes of vectors for arg group 0
Definition: bmaggregator.h:160
index_vector_type arg_idx1
Definition: bmaggregator.h:161
Block cache for pipeline execution.
Definition: bmaggregator.h:198
blockptr_vector_type blk_vect_
cached block ptrs for bv_inp_vect_
Definition: bmaggregator.h:201
count_vector_type cnt_vect_
usage count for bv_inp (all groups)
Definition: bmaggregator.h:200
bv_vector_type bv_inp_vect_
all input vectors from all groups
Definition: bmaggregator.h:199
block_ij_vector_type blk_ij_vect_
current block coords
Definition: bmaggregator.h:202
Aggregation options for runtime control.
Definition: bmaggregator.h:209
size_t batch_size
Batch size sets number of argument groups processed at a time Default: 0 means this parameter will be...
Definition: bmaggregator.h:212
functor-adaptor for back-inserter
Definition: bmalgo_impl.h:159
Pair type.
Definition: bmfunc.h:146
Second second
Definition: bmfunc.h:148
First first
Definition: bmfunc.h:147
const unsigned max_size
Definition: xsample01.cpp:58
bm::bvector bvector_type
Definition: xsample07a.cpp:94