<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nthash on CuriousCoding</title><link>https://curiouscoding.nl/tags/nthash/</link><description>Recent content in Nthash on CuriousCoding</description><generator>Hugo</generator><language>en</language><lastBuildDate>Tue, 12 Aug 2025 00:00:00 +0200</lastBuildDate><atom:link href="https://curiouscoding.nl/tags/nthash/index.xml" rel="self" type="application/rss+xml"/><item><title>SimdMinimizers: Computing random minimizers, fast</title><link>https://curiouscoding.nl/posts/simd-minimizers/</link><pubDate>Fri, 12 Jul 2024 00:00:00 +0200</pubDate><guid>https://curiouscoding.nl/posts/simd-minimizers/</guid><description>&lt;div class="ox-hugo-toc toc has-section-numbers"&gt;
&lt;div class="heading"&gt;Table of Contents&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;1&lt;/span&gt; &lt;a href="#introduction" &gt;Introduction&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;1.1&lt;/span&gt; &lt;a href="#intro-results" &gt;Results&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;2&lt;/span&gt; &lt;a href="#random-minimizers" &gt;Random minimizers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3&lt;/span&gt; &lt;a href="#algorithms" &gt;Algorithms&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3.1&lt;/span&gt; &lt;a href="#problem-statement" &gt;Problem statement&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#problem-a-only-the-set-of-minimizers" &gt;Problem A: Only the set of minimizers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#problem-b-the-minimizer-of-each-window" &gt;Problem B: The minimizer of each window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#problem-c-super-k-mers" &gt;Problem C: Super-k-mers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#which-problem-to-solve" &gt;Which problem to solve&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#canonical-k-mers" &gt;Canonical k-mers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3.2&lt;/span&gt; &lt;a href="#the-naive-algorithm" &gt;The naive algorithm&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#naive-performance" &gt;Performance characteristics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3.3&lt;/span&gt; &lt;a href="#rephrasing-as-sliding-window-minimum" &gt;Rephrasing as sliding window minimum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3.4&lt;/span&gt; &lt;a href="#the-queue" &gt;The queue&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#queue-performance" &gt;Performance characteristics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3.5&lt;/span&gt; &lt;a href="#jumping-away-with-the-queue" &gt;Jumping: Away with the queue&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#jumping-performance" &gt;Performance characteristics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3.6&lt;/span&gt; &lt;a href="#re-scan" &gt;Re-scan&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#rescan-performance" &gt;Performance characteristics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;3.7&lt;/span&gt; &lt;a href="#split-windows" &gt;Split windows&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#split-perfomance" &gt;Performance characteristics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;4&lt;/span&gt; &lt;a href="#analysing-what-we-have-so-far" &gt;Analysing what we have so far&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;4.1&lt;/span&gt; &lt;a href="#counting-comparisons" &gt;Counting comparisons&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#open-problem-theoretical-lower-bounds" &gt;Open problem: Theoretical lower bounds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;4.2&lt;/span&gt; &lt;a href="#setting-up-benchmarking" &gt;Setting up benchmarking&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#adding-criterion" &gt;Adding criterion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#making-criterion-fast" &gt;Making criterion fast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#a-note-on-cpu-frequency" &gt;A note on CPU frequency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;4.3&lt;/span&gt; &lt;a href="#runtime-comparison-with-other-implementations" &gt;Runtime comparison with other implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;4.4&lt;/span&gt; &lt;a href="#deeper-inspection-using-perf-stat" &gt;Deeper inspection using &lt;code&gt;perf stat&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;4.5&lt;/span&gt; &lt;a href="#a-first-optimization-pass" &gt;A first optimization pass&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#optimizing-buffered-reducing-branch-misses" &gt;Optimizing &lt;code&gt;Buffered&lt;/code&gt;: reducing branch misses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#queue-is-hopelessly-branchy" &gt;&lt;code&gt;Queue&lt;/code&gt; is hopelessly branchy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#jumping-is-already-very-efficient" &gt;&lt;code&gt;Jumping&lt;/code&gt; is already very efficient&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#optimizing-rescan" &gt;Optimizing &lt;code&gt;Rescan&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#optimizing-split" &gt;Optimizing &lt;code&gt;Split&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;4.6&lt;/span&gt; &lt;a href="#a-new-performance-comparison" &gt;A new performance comparison&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5&lt;/span&gt; &lt;a href="#rolling-our-own-hash" &gt;Rolling our own hash&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.1&lt;/span&gt; &lt;a href="#fxhash" &gt;FxHash&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#wyhash" &gt;WyHash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.2&lt;/span&gt; &lt;a href="#nthash-a-rolling-hash" &gt;NtHash: a rolling hash&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#the-nthash-crate" &gt;The &lt;code&gt;nthash&lt;/code&gt; crate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#buffered-hash-values" &gt;Buffered hash values&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.3&lt;/span&gt; &lt;a href="#making-nthash-fast-going-branchless" &gt;Making ntHash fast: going branchless&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#drop-sanity-checks" &gt;Drop sanity checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#drop-bound-checks" &gt;Drop bound checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#efficiently-collecting-to-a-vector" &gt;Efficiently collecting to a vector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.4&lt;/span&gt; &lt;a href="#rolling-a-bit-less" &gt;Rolling a bit less&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#analysing-the-assembly-code" &gt;Analysing the assembly code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.5&lt;/span&gt; &lt;a href="#parallel-it-is" &gt;Parallel it is&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#more-parallel" &gt;More parallel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.6&lt;/span&gt; &lt;a href="#actual-simd-at-last" &gt;Actual SIMD, at last&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#simd-table-lookups" &gt;SIMD table lookups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#32-bit-hashes" &gt;32-bit hashes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#shared-offsets" &gt;Shared offsets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.7&lt;/span&gt; &lt;a href="#simd-the-gathering" &gt;SIMD: The Gathering&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#gathering-4-characters-at-a-time" &gt;Gathering 4 characters at a time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#gathering-8-characters-at-a-time" &gt;Gathering 8 characters at a time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#gathering-32-characters-at-a-time" &gt;Gathering 32 characters at a time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reusing-the-gathers" &gt;Reusing the gathers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.8&lt;/span&gt; &lt;a href="#cached-vec" &gt;Fixing the benchmark&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#one-last-branch" &gt;One last branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.9&lt;/span&gt; &lt;a href="#analysis-machine-code-analysis" &gt;Analysis: Machine code analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;5.10&lt;/span&gt; &lt;a href="#finals-thoughts" &gt;Finals thoughts&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#doubling-down-again" &gt;Doubling down again&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#16-bit-hashes" &gt;16-bit hashes?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#what-about-a-simple-multiply-hash" &gt;What about a simple multiply hash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;6&lt;/span&gt; &lt;a href="#simd-sliding-window" &gt;SIMD sliding window&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;6.1&lt;/span&gt; &lt;a href="#sliding-window-results" &gt;Results&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#human-genome-results" &gt;Human genome results&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;7&lt;/span&gt; &lt;a href="#extending-into-something-useful" &gt;Extending into something useful&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;7.1&lt;/span&gt; &lt;a href="#collecting-minimizer-positions" &gt;Collecting minimizer positions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;7.2&lt;/span&gt; &lt;a href="#deduplicating-the-minimizer-positions" &gt;Deduplicating the minimizer positions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;7.3&lt;/span&gt; &lt;a href="#super-k-mers" &gt;Super-k-mers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;7.4&lt;/span&gt; &lt;a href="#canonical-k-mers" &gt;Canonical k-mers&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#nthash" &gt;NtHash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#leftmost-rightmost-sliding-min" &gt;Leftmost-rightmost sliding min&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#tiebreaking" &gt;Tiebreaking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#further-reusing-iterated-bases" &gt;Further reusing iterated bases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;7.5&lt;/span&gt; &lt;a href="#antilex-hash" &gt;AntiLex hash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span class="section-num"&gt;8&lt;/span&gt; &lt;a href="#conclusion" &gt;Conclusion&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="section-num"&gt;8.1&lt;/span&gt; &lt;a href="#future-work" &gt;Future work&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!--endtoc--&gt;
&lt;p&gt;A 90 min recording of a talk I gave on this post can be found &lt;a href="https://curiouscoding.nl/talks/minimizer-talk.mp4" &gt;here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Perfect NtHash for Robust Minimizers</title><link>https://curiouscoding.nl/posts/nthash/</link><pubDate>Sun, 31 Dec 2023 00:00:00 +0100</pubDate><guid>https://curiouscoding.nl/posts/nthash/</guid><description>&lt;div class="ox-hugo-toc toc"&gt;
&lt;div class="heading"&gt;Table of Contents&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#nthash" &gt;NtHash&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#minimizers" &gt;Minimizers&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#robust-minimizers" &gt;Robust minimizers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#is-nthash-injective-on-kmers" &gt;Is NtHash injective on kmers?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#searching-for-a-collision" &gt;Searching for a collision&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#proving-perfection" &gt;Proving perfection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#alternatives" &gt;Alternatives&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#smhasher-results" &gt;SmHasher results&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!--endtoc--&gt;
&lt;h2 id="nthash"&gt;
 NtHash
 &lt;a class="heading-link" href="#nthash"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;NtHash (&lt;a href="#citeproc_bib_item_3"&gt;Mohamadi et al. 2016&lt;/a&gt;) is a rolling hash suitable for hashing any kind of text, but made for DNA originally.
For a string of length \(k\) it is a \(64\) bit value computed as:&lt;/p&gt;</description></item></channel></rss>