Skip to content

feat: use wyhash for minhashes - #347

Merged
eseiler merged 10 commits into
seqan:mainfrom
smehringer:wyhash
Oct 26, 2026
Merged

eseiler merged 10 commits into
seqan:mainfrom
smehringer:wyhash

Conversation

@smehringer

Copy link
Copy Markdown
Member

Solves #346

@seqan-actions seqan-actions added lint and removed lint labels Oct 23, 2026
@seqan-actions

Copy link
Copy Markdown
Member

Documentation preview available at https://docs.seqan.de/preview/seqan/hibf/347

@codecov

codecov Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.76%. Comparing base (384a5ac) to head (e27b700).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #347   +/-   ##
=======================================
  Coverage   99.76%   99.76%           
=======================================
  Files          53       54    +1     
  Lines        2154     2155    +1     
  Branches        8        8           
=======================================
+ Hits         2149     2150    +1     
  Misses          5        5           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@seqan-actions seqan-actions added lint and removed lint labels Oct 23, 2026
@eseiler
eseiler self-requested a review October 26, 2026 12:33
smehringer and others added 10 commits October 26, 2026 17:48
seqan::hibf::sketch::wyhash is declared in hibf/sketch/wyhash.hpp and defined in
src/sketch/wyhash.cpp instead of being an inline function local to hyperloglog.cpp.

Adds the add_many benchmark to test/performance/sketch/hyperloglog_benchmark.cpp: each iteration
adds 2^20 pseudo-random uint64_t values (mt19937_64, seed 42, generated outside the timed region)
and reports items per second.

Benchmark against the previous commit (same compiler g++-16, Release, identical flags incl.
-O3 -flto=auto -march=native, HIBF_LTO_BUILD=ON):
- The timed loop of add_many is identical in both binaries up to addresses and the operand order
  of one cmp. With LTO, add and wyhash are fully inlined (mulx, xor, shrx/shlx, lzcnt, cmovb);
  there is no call.
- Timings (5 repetitions, interleaved, pinned to one core; the machine was loaded, so throughput
  switched between ~430 M/s and ~670 M/s regardless of binary). Medians of the first round:

    bits   before      after
       5   427.6 M/s   426.7 M/s
       8   431.2 M/s   429.7 M/s
      12   428.4 M/s   430.0 M/s

No measurable difference. Not measured: HIBF_LTO_BUILD=OFF, where the out-of-line wyhash likely
costs a call per add().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Define seqan::hibf::sketch::wyhash as a constexpr function in hibf/sketch/wyhash.hpp and remove
src/sketch/wyhash.cpp. The function is three instructions; inlining it no longer depends on LTO
(HIBF_LTO_BUILD=OFF would otherwise cost a call per hyperloglog::add and per pushed minhash value).

__uint128_t, unlike `unsigned __int128`, passes -pedantic -Werror with GCC 14/16 and Clang 20/23.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The header was copied from hyperloglog.hpp. wyhash was written for hibf in c0408ba (replacing
xxHash) and is not derived from Ohno's MIT-licensed HyperLogLog, so the file is BSD-3-Clause only,
as src/sketch/wyhash.cpp was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the links from the file documentation to the function documentation and note that
wyhash(0) == 0, what this does to the sketches, and how a constant XOR would avoid it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the smallest 1000 hashes did not fill every minhash sketch, the refill pushed all kmers into
the previous heap again, so the larger heap held its values twice and fill_incomplete_sketches
appended duplicates. The refill now starts from an empty heap.

Also:
- With fewer than 1000 kmers, the heap kept max() placeholders, which filled sketch 15 with
  max() >> 4 instead of throwing. The heap is now at most as large as the set of kmers.
- The heap grew to 2 * heap_size or threw if that exceeded the number of kmers, even though fewer
  hashes might have sufficed. It now grows to at most the number of kmers and throws only when all
  kmers did not suffice.
- The uniqueness assert in fill_incomplete_sketches compared `hash` with the stored `hash >> 4`.

Random user bins (uniform 64-bit values) were affected in about 1 % of cases for 3,000 to 100,000
kmers (duplicates) and 13 of 2000 for 1500 kmers (spurious exception).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reverts the version bump of 0b34275. Nothing checks the version on loading, so bumping it would
suggest handling that does not exist. Archives written before the wyhash mixing still load; their
values are not mixed and not comparable with newly computed sketches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`#if __AVX512F__ && __AVX512BW__` warns with -Wundef when AVX-512 is not enabled, which is an error
with -Werror for every user of a public header. GCC 14/16, Clang 23 and icpx define both macros
as 1 if the feature is enabled and leave them undefined otherwise (also with -mno-avx512f), so
`defined(...)` is equivalent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With HIBF_NATIVE_BUILD=OFF, this would have caught the AVX-512 check in platform.hpp
(19 translation units). The option is PRIVATE, so tests and other targets are not affected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@eseiler eseiler left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude found some bugs that were not introduced in this PR, but I let them fix it.

@eseiler
eseiler enabled auto-merge October 26, 2026 16:57
@eseiler
eseiler disabled auto-merge October 26, 2026 16:57
@eseiler eseiler changed the title Feature: Wyhash for minHashes feat: use wyhash for minhashes Oct 26, 2026
@eseiler
eseiler enabled auto-merge October 26, 2026 16:58
@eseiler
eseiler disabled auto-merge October 26, 2026 17:03
@eseiler
eseiler merged commit ff91bd1 into seqan:main Oct 26, 2026
51 checks passed
@smehringer
smehringer deleted the wyhash branch October 30, 2026 08:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants