1use std::array::from_fn;
3use std::hash::BuildHasher;
4use std::hash::BuildHasherDefault;
5use std::hash::DefaultHasher;
6
7use super::intrinsics;
8use crate::KmerHasher;
9use crate::S;
10use packed_seq::Seq;
11use packed_seq::complement_base;
12use packed_seq::u32x8;
13
14type SeedHasher = BuildHasherDefault<DefaultHasher>;
15
16const HASHES_F: [u32; 4] = [
19 0x3c8b_fbb3_95c6_0474u64 as u32,
20 0x3193_c185_62a0_2b4cu64 as u32,
21 0x2032_3ed0_8257_2324u64 as u32,
22 0x2955_49f5_4be2_4456u64 as u32,
23];
24
25pub trait CharHasher: Clone {
30 const CANONICAL: bool;
32 const R: u32;
34 const BITS_PER_CHAR: usize;
36
37 fn new(k: usize) -> Self {
38 Self::new_with_seed(k, None)
39 }
40 fn new_with_seed(k: usize, seed: Option<u32>) -> Self;
42 fn k(&self) -> usize;
44 fn f(&self, b: u8) -> u32;
46 fn c(&self, b: u8) -> u32;
48 fn f_rot(&self, b: u8) -> u32;
50 fn c_rot(&self, b: u8) -> u32;
52 fn simd_f(&self, b: u32x8) -> u32x8;
54 fn simd_c(&self, b: u32x8) -> u32x8;
56 fn simd_f_rot(&self, b: u32x8) -> u32x8;
58 fn simd_c_rot(&self, b: u32x8) -> u32x8;
60
61 fn fw_init(&self) -> u32;
62 fn rc_init(&self) -> u32;
63}
64
65#[derive(Clone)]
71pub struct NtHasher<const CANONICAL: bool = true, const R: u32 = 7> {
72 k: usize,
73 f: [u32; 4],
74 c: [u32; 4],
75 f_rot: [u32; 4],
76 c_rot: [u32; 4],
77 simd_f: u32x8,
78 simd_c: u32x8,
79 simd_f_rot: u32x8,
80 simd_c_rot: u32x8,
81 fw_init: u32,
82 rc_init: u32,
83}
84
85impl<const CANONICAL: bool, const R: u32> NtHasher<CANONICAL, R> {
86 #[inline(always)]
87 pub fn new(k: usize) -> Self {
88 CharHasher::new(k)
89 }
90 #[inline(always)]
91 pub fn new_with_seed(k: usize, seed: u32) -> Self {
92 CharHasher::new_with_seed(k, Some(seed))
93 }
94}
95
96impl<const CANONICAL: bool, const R: u32> CharHasher for NtHasher<CANONICAL, R> {
97 const CANONICAL: bool = CANONICAL;
98 const R: u32 = R;
99 const BITS_PER_CHAR: usize = 2;
100
101 #[inline(always)]
102 fn new_with_seed(k: usize, seed: Option<u32>) -> Self {
103 let rot = k as u32 - 1;
104 let hasher = SeedHasher::new();
105 let f = match seed {
106 None => HASHES_F,
107 Some(seed) => from_fn(|i| hasher.hash_one(HASHES_F[i] ^ seed) as u32),
108 };
109 let c = from_fn(|i| f[complement_base(i as u8) as usize]);
110 let f_rot = f.map(|h| h.rotate_left(rot * R));
111 let c_rot = c.map(|h| h.rotate_left(rot * R));
112 let idx = [0, 1, 2, 3, 0, 1, 2, 3];
113 let simd_f = idx.map(|i| f[i]).into();
114 let simd_c = idx.map(|i| c[i]).into();
115 let simd_f_rot = idx.map(|i| f_rot[i]).into();
116 let simd_c_rot = idx.map(|i| c_rot[i]).into();
117
118 let mut fw_init = 0u32;
120 for _ in 0..k - 1 {
121 fw_init = fw_init.rotate_left(Self::R) ^ f[0];
122 }
123
124 let mut rc_init = 0u32;
126 for _ in 0..k - 1 {
127 rc_init = rc_init.rotate_right(Self::R) ^ c_rot[0];
128 }
129
130 Self {
131 k,
132 f,
133 c,
134 f_rot,
135 c_rot,
136 simd_f,
137 simd_c,
138 simd_f_rot,
139 simd_c_rot,
140 fw_init,
141 rc_init,
142 }
143 }
144
145 #[inline(always)]
146 fn k(&self) -> usize {
147 self.k
148 }
149
150 #[inline(always)]
151 fn f(&self, b: u8) -> u32 {
152 unsafe { *self.f.get_unchecked(b as usize) }
153 }
154 #[inline(always)]
155 fn c(&self, b: u8) -> u32 {
156 unsafe { *self.c.get_unchecked(b as usize) }
157 }
158 #[inline(always)]
159 fn f_rot(&self, b: u8) -> u32 {
160 unsafe { *self.f_rot.get_unchecked(b as usize) }
161 }
162 #[inline(always)]
163 fn c_rot(&self, b: u8) -> u32 {
164 unsafe { *self.c_rot.get_unchecked(b as usize) }
165 }
166
167 #[inline(always)]
168 fn simd_f(&self, b: u32x8) -> u32x8 {
169 intrinsics::table_lookup(self.simd_f, b)
170 }
171 #[inline(always)]
172 fn simd_c(&self, b: u32x8) -> u32x8 {
173 intrinsics::table_lookup(self.simd_c, b)
174 }
175 #[inline(always)]
176 fn simd_f_rot(&self, b: u32x8) -> u32x8 {
177 intrinsics::table_lookup(self.simd_f_rot, b)
178 }
179 #[inline(always)]
180 fn simd_c_rot(&self, b: u32x8) -> u32x8 {
181 intrinsics::table_lookup(self.simd_c_rot, b)
182 }
183 #[inline(always)]
184 fn fw_init(&self) -> u32 {
185 self.fw_init
186 }
187 #[inline(always)]
188 fn rc_init(&self) -> u32 {
189 self.rc_init
190 }
191}
192
193#[derive(Clone)]
199pub struct MulHasher<const CANONICAL: bool = true, const R: u32 = 7> {
200 k: usize,
201 rot: u32,
202 mul: u32,
203 simd_mul: u32x8,
204 fw_init: u32,
205 rc_init: u32,
206}
207
208impl<const CANONICAL: bool, const R: u32> MulHasher<CANONICAL, R> {
209 #[inline(always)]
210 pub fn new(k: usize) -> Self {
211 CharHasher::new(k)
212 }
213 #[inline(always)]
214 pub fn new_with_seed(k: usize, seed: u32) -> Self {
215 CharHasher::new_with_seed(k, Some(seed))
216 }
217}
218
219const C: u32 = 0x517cc1b727220a95u64 as u32;
221
222impl<const CANONICAL: bool, const R: u32> CharHasher for MulHasher<CANONICAL, R> {
223 const CANONICAL: bool = CANONICAL;
224 const R: u32 = R;
225 const BITS_PER_CHAR: usize = 8;
226
227 #[inline(always)]
228 fn new_with_seed(k: usize, seed: Option<u32>) -> Self {
229 let rot = (k as u32 - 1) % 32;
230 let mul = C ^ match seed {
231 None => 0,
232 Some(seed) => (SeedHasher::new().hash_one(seed) as u32) << 1,
234 };
235 let simd_mul = u32x8::splat(mul);
236
237 let mut fw_init = 0u32;
239 for _ in 0..k - 1 {
240 fw_init = fw_init.rotate_left(Self::R) ^ 0u32.wrapping_mul(mul);
241 }
242
243 let mut rc_init = 0u32;
245 for _ in 0..k - 1 {
246 rc_init = rc_init.rotate_right(Self::R)
247 ^ (complement_base(0) as u32)
248 .wrapping_mul(mul)
249 .rotate_left(rot * R);
250 }
251
252 Self {
253 k,
254 rot,
255 mul,
256 simd_mul,
257 fw_init,
258 rc_init,
259 }
260 }
261
262 #[inline(always)]
263 fn k(&self) -> usize {
264 self.k
265 }
266
267 #[inline(always)]
268 fn f(&self, b: u8) -> u32 {
269 (b as u32).wrapping_mul(self.mul)
270 }
271 #[inline(always)]
272 fn c(&self, b: u8) -> u32 {
273 (complement_base(b) as u32).wrapping_mul(self.mul)
274 }
275 #[inline(always)]
276 fn f_rot(&self, b: u8) -> u32 {
277 (b as u32).wrapping_mul(self.mul).rotate_left(self.rot * R)
278 }
279 #[inline(always)]
280 fn c_rot(&self, b: u8) -> u32 {
281 (complement_base(b) as u32)
282 .wrapping_mul(self.mul)
283 .rotate_left(self.rot * R)
284 }
285
286 #[inline(always)]
287 fn simd_f(&self, b: u32x8) -> u32x8 {
288 b * self.simd_mul
289 }
290 #[inline(always)]
291 fn simd_c(&self, b: u32x8) -> u32x8 {
292 packed_seq::complement_base_simd(b) * self.simd_mul
293 }
294 #[inline(always)]
295 fn simd_f_rot(&self, b: u32x8) -> u32x8 {
296 let r = b * self.simd_mul;
297 let rot = self.rot * R % 32;
298 (r << rot) | (r >> (32 - rot))
299 }
300 #[inline(always)]
301 fn simd_c_rot(&self, b: u32x8) -> u32x8 {
302 let r = packed_seq::complement_base_simd(b) * self.simd_mul;
303 let rot = self.rot * R % 32;
304 (r << rot) | (r >> (32 - rot))
305 }
306 #[inline(always)]
307 fn fw_init(&self) -> u32 {
308 self.fw_init
309 }
310 #[inline(always)]
311 fn rc_init(&self) -> u32 {
312 self.rc_init
313 }
314}
315
316impl<CH: CharHasher> KmerHasher for CH {
317 const CANONICAL: bool = CH::CANONICAL;
318
319 fn new(k: usize) -> Self {
320 Self::new(k)
321 }
322
323 fn k(&self) -> usize {
324 self.k()
325 }
326
327 #[inline(always)]
328 fn in_out_mapper_scalar<'s>(&self, seq: impl Seq<'s>) -> impl FnMut((u8, u8)) -> u32 {
329 assert!(seq.bits_per_char() <= CH::BITS_PER_CHAR);
330
331 let mut fw = self.fw_init();
332 let mut rc = self.rc_init();
333
334 move |(a, r)| {
335 let fw_out = fw.rotate_left(CH::R) ^ self.f(a);
336 fw = fw_out ^ self.f_rot(r);
337 if Self::CANONICAL {
338 let rc_out = rc.rotate_right(CH::R) ^ self.c_rot(a);
339 rc = rc_out ^ self.c(r);
340 fw_out.wrapping_add(rc_out)
341 } else {
342 fw_out
343 }
344 }
345 }
346
347 #[inline(always)]
348 fn in_out_mapper_simd<'s>(&self, seq: impl Seq<'s>) -> impl FnMut((S, S)) -> S {
349 assert!(seq.bits_per_char() <= CH::BITS_PER_CHAR);
350 let mut fw = S::splat(self.fw_init());
351 let mut rc = S::splat(self.rc_init());
352 let shl = S::splat(CH::R);
353 let shr = S::splat(32 - CH::R);
354
355 move |(a, r)| {
356 let fw_out = ((fw << shl) | (fw >> shr)) ^ self.simd_f(a);
357 fw = fw_out ^ self.simd_f_rot(r);
358 if Self::CANONICAL {
359 let rc_out = ((rc >> shl) | (rc << shr)) ^ self.simd_c_rot(a);
360 rc = rc_out ^ self.simd_c(r);
361 fw_out + rc_out
363 } else {
364 fw_out
365 }
366 }
367 }
368
369 #[inline(always)]
370 fn mapper<'s>(&self, seq: impl Seq<'s>) -> impl FnMut(u8) -> u32 {
371 assert!(seq.bits_per_char() <= CH::BITS_PER_CHAR);
372
373 let mut fw = 0u32;
374 let mut rc = 0u32;
375 move |a| {
376 fw = fw.rotate_left(CH::R) ^ self.f(a);
377 if Self::CANONICAL {
378 rc = rc.rotate_right(CH::R) ^ self.c_rot(a);
379 fw.wrapping_add(rc)
380 } else {
381 fw
382 }
383 }
384 }
385}