HIBF 1.0.0-rc.1
Loading...
Searching...
No Matches
hierarchical_interleaved_bloom_filter.hpp
1// SPDX-FileCopyrightText: 2006-2026, Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2026, Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
5#pragma once
6
7#include <algorithm> // for __sort, fill, sort
8#include <cassert> // for assert
9#include <cstddef> // for size_t
10#include <cstdint> // for uint64_t, uint16_t, uint32_t
11#include <limits> // for numeric_limits
12#include <memory> // for addressof
13#include <ranges> // for forward_range, integral, range, range_value_t, unsigned_integral
14#include <vector> // for vector, operator==
15
16#include <cereal/cereal.hpp> // for make_nvp
17#include <cereal/macros.hpp> // for CEREAL_SERIALIZE_FUNCTION_NAME
18#include <cereal/types/vector.hpp> // IWYU pragma: keep
19
20#include <hibf/cereal/concepts.hpp> // for cereal_archive
21#include <hibf/config.hpp> // for config
22#include <hibf/interleaved_bloom_filter.hpp> // for interleaved_bloom_filter
23#include <hibf/layout/layout.hpp> // for layout
24#include <hibf/misc/counting_vector.hpp> // for counting_vector
25#include <hibf/misc/timer.hpp> // for concurrent_timer
26#include <hibf/platform.hpp> // for HIBF_CONSTEXPR_VECTOR
27
28namespace seqan::hibf
29{
30
31namespace bin_kind
32{
33
35inline constexpr uint64_t merged{std::numeric_limits<uint64_t>::max()};
37inline constexpr uint64_t deleted{std::numeric_limits<uint64_t>::max() - 1u};
38
39} // namespace bin_kind
40
139{
140public:
144 size_t number_of_user_bins{};
145
152 template <std::integral value_t>
156
168
197
208
211
220
231
240
242 membership_agent_type membership_agent() const;
243
247 template <std::integral value_t = uint16_t>
248 counting_agent_type<value_t> counting_agent() const;
249
253 constexpr bool operator==(hierarchical_interleaved_bloom_filter const &) const;
255
259 static constexpr uint32_t version{1};
260
268 template <seqan::hibf::cereal_archive archive_t>
269 void CEREAL_SERIALIZE_FUNCTION_NAME(archive_t & archive)
270 {
271 uint32_t parsed_version{version};
272 archive(cereal::make_nvp("version", parsed_version));
273 archive(number_of_user_bins);
274 archive(ibf_vector);
275 archive(next_ibf_id);
276 archive(prev_ibf_id);
277 archive(ibf_bin_to_user_bin_id);
278 }
279
284 concurrent_timer layout_compute_sketches_timer{};
285 concurrent_timer layout_union_estimation_timer{};
286 concurrent_timer layout_rearrangement_timer{};
287 concurrent_timer layout_dp_algorithm_timer{};
288 concurrent_timer index_allocation_timer{};
289 concurrent_timer user_bin_io_timer{};
290 concurrent_timer merge_kmers_timer{};
291 concurrent_timer fill_ibf_timer{};
294};
295
298{
299 size_t ibf_idx{};
300 size_t bin_idx{};
301
302 friend constexpr auto operator<=>(previous_ibf_id_pair const &, previous_ibf_id_pair const &) = default;
303
304 template <seqan::hibf::cereal_archive archive_t>
305 void CEREAL_SERIALIZE_FUNCTION_NAME(archive_t & archive)
306 {
307 archive(ibf_idx);
308 archive(bin_idx);
309 }
310};
311
312constexpr bool
313hierarchical_interleaved_bloom_filter::operator==(hierarchical_interleaved_bloom_filter const &) const = default;
314
316{
317private:
319 hierarchical_interleaved_bloom_filter const * hibf_ptr{nullptr};
320
322 template <std::ranges::forward_range value_range_t>
323 void membership_for_impl(value_range_t && values, size_t const ibf_idx, uint16_t const threshold)
324 {
325 auto agent = hibf_ptr->ibf_vector[ibf_idx].template counting_agent<uint16_t>();
326 auto & result = agent.bulk_count(values);
327
328 uint16_t sum{};
329
330 for (size_t bin{}; bin < result.size(); ++bin)
331 {
332 sum += result[bin];
333
334 auto const user_bin_id = hibf_ptr->ibf_bin_to_user_bin_id[ibf_idx][bin];
335
336 // It does not seem to make a difference whether the following block is done via a switch or if-else.
337 // The switch is easier to read.
338 switch (user_bin_id)
339 {
340 case bin_kind::deleted: // GCOVR_EXCL_LINE
341 break; // GCOVR_EXCL_LINE
342 case bin_kind::merged:
343 if (sum >= threshold)
344 membership_for_impl(values, hibf_ptr->next_ibf_id[ibf_idx][bin], threshold);
345 sum = 0u;
346 break;
347 default:
348 if (bin + 1u == result.size() || user_bin_id != hibf_ptr->ibf_bin_to_user_bin_id[ibf_idx][bin + 1])
349 { // last bin || end of split bin
350 if (sum >= threshold)
351 result_buffer.emplace_back(user_bin_id);
352 sum = 0u;
353 }
354 }
355 }
356 }
357
359 std::vector<uint64_t> result_buffer;
360
361public:
371
376 explicit membership_agent_type(hierarchical_interleaved_bloom_filter const & hibf) : hibf_ptr(std::addressof(hibf))
377 {}
379
382 {
383 std::ranges::sort(result_buffer);
384 }
385
425 template <std::ranges::forward_range value_range_t>
426 [[nodiscard]] std::vector<uint64_t> const & membership_for(value_range_t && values,
427 uint16_t const threshold) & noexcept
428 {
429 assert(hibf_ptr != nullptr);
430
431 static_assert(std::ranges::forward_range<value_range_t>, "The values must model forward_range.");
433 "An individual value must be an unsigned integral.");
434
435 result_buffer.clear();
436
437 membership_for_impl(values, 0u, threshold);
438
439 return result_buffer;
440 }
441
443 template <std::ranges::range value_range_t>
444 [[nodiscard]] std::vector<uint64_t> const & membership_for(value_range_t && values,
445 uint16_t const threshold) && noexcept = delete;
447};
448
454
455template <std::integral value_t>
457{
458private:
460 hierarchical_interleaved_bloom_filter const * hibf_ptr{nullptr};
461
463 template <std::ranges::forward_range value_range_t>
464 void bulk_count_impl(value_range_t && values, size_t const ibf_idx, size_t const threshold)
465 {
466 auto agent = hibf_ptr->ibf_vector[ibf_idx].template counting_agent<value_t>();
467 auto & result = agent.bulk_count(values);
468
469 value_t sum{};
470
471 for (size_t bin{}; bin < result.size(); ++bin)
472 {
473 sum += result[bin];
474
475 auto const user_bin_id = hibf_ptr->ibf_bin_to_user_bin_id[ibf_idx][bin];
476
477 // It does not seem to make a difference whether the following block is done via a switch or if-else.
478 // The switch is easier to read.
479 switch (user_bin_id)
480 {
481 case bin_kind::deleted: // GCOVR_EXCL_LINE
482 break; // GCOVR_EXCL_LINE
483 case bin_kind::merged:
484 if (sum >= threshold)
485 bulk_count_impl(values, hibf_ptr->next_ibf_id[ibf_idx][bin], threshold);
486 sum = 0u;
487 break;
488 default:
489 if (bin + 1u == result.size() || user_bin_id != hibf_ptr->ibf_bin_to_user_bin_id[ibf_idx][bin + 1])
490 { // last bin || end of split bin
491 if (sum >= threshold)
492 result_buffer[user_bin_id] = sum;
493 sum = 0u;
494 }
495 }
496 }
497 }
498
500 counting_vector<value_t> result_buffer;
501
502public:
512
518 hibf_ptr(std::addressof(hibf)),
519 result_buffer(hibf_ptr->number_of_user_bins)
520 {}
522
550 template <std::ranges::forward_range value_range_t>
551 [[nodiscard]] counting_vector<value_t> const & bulk_count(value_range_t && values,
552 size_t const threshold) & noexcept
553 {
554 assert(hibf_ptr != nullptr);
555 assert(threshold > 0u);
556 assert(result_buffer.size() == hibf_ptr->number_of_user_bins);
557
558 static_assert(std::ranges::forward_range<value_range_t>, "The values must model forward_range.");
560 "An individual value must be an unsigned integral.");
561
562 std::ranges::fill(result_buffer, static_cast<value_t>(0));
563
564 bulk_count_impl(values, 0u, threshold);
565
566 return result_buffer;
567 }
568
570 template <std::ranges::range value_range_t>
571 [[nodiscard]] counting_vector<value_t> const & bulk_count(value_range_t && values,
572 size_t const threshold) && noexcept = delete;
574};
575
576template <std::integral value_t>
582
583} // namespace seqan::hibf
A timer with a thread-safe operator+=().
Definition timer.hpp:155
A data structure that behaves like a std::vector and can be used to consolidate the results of multip...
Definition counting_vector.hpp:145
Manages counting ranges of values for the seqan::hibf::hierarchical_interleaved_bloom_filter.
Definition hierarchical_interleaved_bloom_filter.hpp:457
counting_agent_type(counting_agent_type const &)=default
Defaulted.
counting_agent_type & operator=(counting_agent_type const &)=default
Defaulted.
counting_vector< value_t > const & bulk_count(value_range_t &&values, size_t const threshold) &&noexcept=delete
Deleted. Calling this function on a temporary would result in a dangling reference.
counting_agent_type & operator=(counting_agent_type &&)=default
Defaulted.
counting_vector< value_t > const & bulk_count(value_range_t &&values, size_t const threshold) &noexcept
Counts the occurrences in each bin for all values in a range.
Definition hierarchical_interleaved_bloom_filter.hpp:551
Definition hierarchical_interleaved_bloom_filter.hpp:316
membership_agent_type(membership_agent_type &&)=default
Defaulted.
std::vector< uint64_t > const & membership_for(value_range_t &&values, uint16_t const threshold) &&noexcept=delete
Deleted. Calling this function on a temporary would result in a dangling reference.
membership_agent_type & operator=(membership_agent_type &&)=default
Defaulted.
membership_agent_type & operator=(membership_agent_type const &)=default
Defaulted.
std::vector< uint64_t > const & membership_for(value_range_t &&values, uint16_t const threshold) &noexcept
Determines set membership for all user bins contained in this index, based on values and the threshol...
Definition hierarchical_interleaved_bloom_filter.hpp:426
void sort_results()
Sorts the results.
Definition hierarchical_interleaved_bloom_filter.hpp:381
membership_agent_type(membership_agent_type const &)=default
Defaulted.
The Hierarchical Interleaved Bloom Filter (HIBF) - Fast answers to set-membership queries for multipl...
Definition hierarchical_interleaved_bloom_filter.hpp:139
std::vector< previous_ibf_id_pair > prev_ibf_id
Stores for each IBF of the HIBF the ID of the parent IBF and the bin index of the parent IBF.
Definition hierarchical_interleaved_bloom_filter.hpp:230
hierarchical_interleaved_bloom_filter(config &configuration, layout::layout const &layout)
[Advanced] Constructs the HIBF from a config and layout.
std::vector< std::vector< uint64_t > > ibf_bin_to_user_bin_id
Stores for each bin in each IBF of the HIBF the user bin ID.
Definition hierarchical_interleaved_bloom_filter.hpp:239
hierarchical_interleaved_bloom_filter(config &configuration)
Constructs the HIBF from the given configuration.
hierarchical_interleaved_bloom_filter & operator=(hierarchical_interleaved_bloom_filter &&)=default
Defaulted.
std::vector< interleaved_bloom_filter > ibf_vector
The individual interleaved Bloom filters.
Definition hierarchical_interleaved_bloom_filter.hpp:210
counting_agent_type< value_t > counting_agent() const
Returns a counting_agent_type to be used for counting.
Definition hierarchical_interleaved_bloom_filter.hpp:578
membership_agent_type membership_agent() const
Returns a membership_agent to be used for counting.
Definition hierarchical_interleaved_bloom_filter.hpp:450
std::vector< std::vector< uint64_t > > next_ibf_id
Stores for each bin in each IBF of the HIBF the ID of the next IBF.
Definition hierarchical_interleaved_bloom_filter.hpp:219
hierarchical_interleaved_bloom_filter & operator=(hierarchical_interleaved_bloom_filter const &)=default
Defaulted.
hierarchical_interleaved_bloom_filter(hierarchical_interleaved_bloom_filter &&)=default
Defaulted.
hierarchical_interleaved_bloom_filter(hierarchical_interleaved_bloom_filter const &)=default
Defaulted.
static constexpr uint32_t version
The version of the HIBF.
Definition hierarchical_interleaved_bloom_filter.hpp:259
T clear(T... args)
Provides seqan::hibf::counting_vector.
T emplace_back(T... args)
T fill(T... args)
Provides seqan::hibf::interleaved_bloom_filter.
T is_base_of_v
T max(T... args)
Provides platform and dependency checks.
T size(T... args)
T sort(T... args)
The configuration used to build an (H)IBF.
Definition config.hpp:76
Contains information about the parent IBF and bin index.
Definition hierarchical_interleaved_bloom_filter.hpp:298
size_t ibf_idx
The index of the parent IBF in ibf_vector.
Definition hierarchical_interleaved_bloom_filter.hpp:299
size_t bin_idx
The index of the bin in the parent IBF of which an IBF is the child of.
Definition hierarchical_interleaved_bloom_filter.hpp:300
The layout.
Definition layout.hpp:36
Provides seqan::hibf::timer.