Skip to main content

ph_temp/phast/seed_chooser/
shift_wrap.rs

1use crate::phast::{conf::{mix_key_seed, Conf}, cyclic::{CyclicSet, GenericUsedValue, UsedValueSet}, Weights};
2use super::SeedChooser;
3
4
5/// Calculates a mask that has 0 only at positions divided by `multiplier`.
6const fn zero_at_each(multiplier: u8) -> u64 {
7    let mut result = u64::MAX;
8    let mut i = 0;
9    while i < 64 {
10        result ^= 1<<i;
11        i += multiplier;
12    }
13    result
14}
15
16/// Common code for checking each `MULTIPLIER` position.
17pub(crate) struct Multiplier<const MULTIPLIER: u8>;
18
19impl<const MULTIPLIER: u8> Multiplier<MULTIPLIER> {
20    pub(crate) const MASK: u64 = zero_at_each(MULTIPLIER); // mask that has 0 only at positions divided by `MULTIPLIER`
21    pub(crate) const STEP: usize = 64 - 64 % MULTIPLIER as usize;  // number of bits to use from each 64-bit fragment of used bitmap.
22
23    /**
24     * Returns the lowest collision-free shift which is lower than `shift_end`.
25     * or `None` if there are no collision-free shifts lower than `shift_end`.
26     * 
27     * For each key, `without_shift` contains begin index of the key slice and initial key position in this slice.
28     * The final value for each key is: its slice begin index + its initial position in slice + returned shift.
29     * 
30     * `used_values` shows values already used by the keys from other buckets.
31     */
32    #[inline]
33    pub(crate) fn best_in_range<const UVS: usize>(shift_end: u16, without_shift: &mut [(usize, u16)], used_values: &CyclicSet<UVS>) -> Option<u16> {
34        without_shift.sort_unstable_by_key(|(sb, sh0)| sb+*sh0 as usize);  // maybe it is better to postpone self-collision test?
35        if without_shift.windows(2).any(|v| v[0].0+v[0].1 as usize==v[1].0+v[1].1 as usize) {
36            return None;
37        }
38        for shift in (0..shift_end).step_by(Self::STEP) {
39            let mut used = Self::MASK;
40            for &(sb, sh0) in without_shift.iter() {
41                used |= used_values.get64(sb + sh0 as usize + shift as usize);
42            }
43            if used != u64::MAX {
44                let total_shift = shift + used.trailing_ones() as u16;
45                if total_shift >= shift_end { return None; }
46
47                /*without_shift.sort_unstable_by_key(|(sb, sh0)| sb+*sh0 as usize);  // maybe it is better to postpone self-collision test?
48                if without_shift.windows(2).any(|v| v[0].0+v[0].1 as usize==v[1].0+v[1].1 as usize) {
49                    return None;
50                }*/
51
52                return Some(total_shift);
53            }
54        }
55        None
56    }
57
58    pub(crate) fn multiple_rounded_up(mut shift_end: u16) -> u16 {
59        if MULTIPLIER != 1 {    // round up shift_end to MULTIPLIER
60            let r = shift_end % MULTIPLIER as u16;
61            if r != 0 {
62                shift_end -= r;
63                shift_end += MULTIPLIER as u16;
64            }
65        }
66        shift_end
67    }
68}
69
70
71/// [`SeedChooser`] to build (1-)perfect functions called *PHast+ with wrapping*.
72/// 
73/// Can be used with any function type: [`Function`], [`Function2`], [`Perfect`].
74/// 
75/// It chooses best seed using only shifting with wrapping,
76/// which leads to quite small size and quite fast construction.
77/// 
78/// `MULTIPLIER` should be 1, 2, or 3.
79/// Typically, increasing `MULTIPLIER` reduces size but slows down construction.
80/// `MULTIPLIER=1` works very well with large `bits_per_seed` (10+),
81/// larger values (2 and 3) works well with `bits_per_seed=8`.
82#[derive(Clone, Copy)]
83pub struct ShiftOnlyWrapped<const MULTIPLIER: u8 = 1>;
84
85fn shift_only_wrapped_bucket_evaluator_m1(bits_per_seed: u8, slice_len: u16) -> [i32; 7] {
86    match (bits_per_seed, slice_len) {
87        (_, ..=64) => [-76520, 97960, 103626, 106759, 109053, 110149, 112662],   // 8, 4.1, 64
88        (_, ..=128) => [-80872, 90492, 100641, 105939, 109960, 112290, 118119], // 8, 4.1, 128
89        (..=6, ..=256) => [-76632, 59701, 89939, 103115, 111040, 117906, 283652], // 6, 3.0, slice=256
90        (..=6, ..=512) => [-102171, 30195, 95877, 122987, 138980, 152173, 206055],  // 6, 3.0, slice=512
91        (_, ..=256) => [-84425, 81165, 96951, 106065, 112137, 117421, 122309],  // 7, 3.5, slice=256
92        (7, ..=512) => [-69271, 61152, 101770, 119869, 132454, 141236, 148273],  // 7, 3.5, slice=512
93        (8, ..=512) => [-66903, 81776, 107154, 122354, 132033, 140641, 146584], // 4.1, slice=512
94        (8, ..=1024) => [-50666, 55977, 116129, 145446, 164172, 180129, 192120],  // 4.1, slice=1024
95        (_, ..=512) => [-45845, 91690, 122225, 138169, 149160, 155706, 164757],  // 5.1, slice=512
96        (9, ..=1024) => [-51695, 68190, 121468, 146481, 164082, 178054, 186488],  // 5.1, slice=1024
97        (..=9, ..=2048) => [-3365, 12300, 85113, 138418, 170087, 197668, 215654],  // 9, 5.1, slice=2048
98        (10, ..=1024) => [-4011, 15045, 106558, 112844, 133305, 145623, 154991], // 5.7, slice=1024
99        (..=10, ..=2048) => [-3301, 12449, 83323, 139924, 169323, 198105, 212187],   // 10, 5.7, slice=2048
100        (11, ..=1024) => [-1524, 23928, 115028, 153353, 187370, 191075, 197861],    // 6.3, slice=1024 USELESS
101        (11, ..=2048) => [-1777, 22788, 106158, 139632, 174143, 200775, 214797],  // 6.3, slice=2048
102        (11, _) => [-4924, 19116, 22394, 59714, 110668, 154482, 181404],
103        (_, ..=1024) => [-2190, 30393, 114587, 141471, 162103, 177602, 183787], // 12, 6.8, slice=1024 USELESS
104        (_, ..=2048) => [-2355, 16099, 113987, 153868, 183912, 213486, 226897],   // 12, 6.8, slice=2048 USELESS
105        (_, _) => [-3938, 38130, 29589, 52311, 96328, 147014, 172193], // 12, 6.8, 4096
106    }
107}
108
109fn shift_only_wrapped_bucket_evaluator_m2(bits_per_seed: u8, slice_len: u16) -> [i32; 7] {
110    match (bits_per_seed, slice_len) {
111        (_, ..=64) => [-78586, 98418, 103824, 106532, 108539, 109981, 111063],  // 8, 4.1, 64
112        (_, ..=128) => [-85534, 90593, 100261, 105362, 108728, 111329, 113115], // 8, 4.1, 128
113        (..=6, ..=256) => [-113309, 70659, 92719, 103205, 111784, 117218, 121395], // 6, 3.0, slice=256
114        (..=6, ..=512) => [-113437, 36479, 87740, 109716, 124793, 137012, 209528], // 6, 3.0, slice=512
115        (_, ..=256) => [-83108, 76805, 93889, 104574, 111919, 117701, 137200],  // 7, 3.5, slice=256
116        (7, ..=512) => [-11364, 71851, 100238, 116988, 128732, 138656, 145275],  // 7, 3.5, slice=512
117        (8, ..=512) => [-67763, 78133, 104489, 121464, 133392, 140946, 155107], // 4.1, slice=512
118        (8, ..=1024) => [-50137, 65904, 111782, 139890, 159029, 175922, 186995],  // 4.1, slice=1024
119        (..=8, ..=2048) => [-3445, 11224, 85129, 138005, 176794, 209479, 234058], // 8, 4.1, slice=2048
120        (_, ..=512) => [-45845, 91690, 122225, 138169, 149160, 155706, 164757],  // 5.1, slice=512
121        (9, ..=1024) => [-49692, 70537, 115707, 143201, 163216, 178981, 188448],  // 5.1, slice=1024
122        (..=9, ..=2048) => [-3514, 12002, 85880, 136849, 171127, 197699, 215787],  // 9, 5.1, slice=2048
123        (10, ..=1024) => [-4383, 16783, 82867, 112554, 131931, 148281, 156013], // 5.7, slice=1024 USELESS
124        (..=10, ..=2048) => [-3386, 13051, 82525, 133516, 169004, 198445, 214518],   // 10, 5.7, slice=2048
125        (11, ..=1024) => [-1562, 24796, 122828, 155722, 174139, 191420, 198085],    // 6.3, slice=1024 USELESS
126        (11, ..=2048) => [-2243, 21043, 83146, 136599, 172186, 200713, 215298],  // 6.3, slice=2048 USELESS
127        (11, _) => [-4045, 8964, 9362, 21128, 86855, 136683, 166640],   // 11, 6.3, slice=4096
128        (_, ..=1024) => [-2244, 32777, 107196, 142051, 161424, 177763, 183475], // 12, 6.8, slice=1024 USELESS
129        (_, ..=2048) => [-2808, 16026, 90346, 150206, 185508, 214963, 227887],   // 12, 6.8, slice=2048 USELESS
130        (_, _ /*..=4096*/) => [-4044, 7164, 10158, 22096, 92563, 142914, 171123],    // 12, 6.8, slice=4096  USELESS?? pure performance
131        //(_, _) => [-4849, 12371, 19420, 27337, 28560, 51301, 103428]    // 12, 6.8, slice=8192, TODO optimize
132    }
133}
134
135fn shift_only_wrapped_bucket_evaluator_m3(bits_per_seed: u8, slice_len: u16) -> [i32; 7] {
136    match (bits_per_seed, slice_len) { // multiplier=3, almost the same result as for multiplier=2 weights
137        (_, ..=64) => [-81342, 97738, 103193, 106305, 108524, 109876, 112382],  // 8, 4.1, 64
138        (_, ..=128) => [-82883, 89250, 99246, 105030, 108983, 111224, 117058], // 8, 4.1, 128
139        (..=6, ..=256) => [-143420, 70364, 89794, 100431, 107778, 113842, 253543], // 6, 3.0, slice=256
140        (..=6, ..=512) => [-118906, 41451, 83177, 104570, 119520, 131788, 197543], // 6, 3.0, slice=512
141        (_, ..=256) => [-82828, 77192, 94710, 105243, 112716, 118768, 136225],  // 7, 3.5, slice=256
142        (7, ..=512) => [-11540, 68580, 98218, 115370, 128607, 139118, 145832],  // 7, 3.5, slice=512
143        (_, ..=512) => [25100, 89361, 117113, 134755, 147369, 154606, 172378], // 4.1, slice=512
144        (8, ..=1024) => [-50649, 63792, 110014, 139267, 161285, 176594, 188305],  // 4.1, slice=1024
145        (..=8, ..=2048) => [-3427, 10388, 90470, 141895, 179413, 208576, 232553], // 8, 4.1, slice=2048
146        (9, ..=1024) => [-41757, 60279, 113069, 143467, 162892, 179091, 188139],  // 5.1, slice=1024
147        (..=9, ..=2048) => [-3753, 11840, 77702, 132696, 169641, 200687, 218764],  // 9, 5.1, slice=2048
148        (10, ..=1024) => [-2394, 29640, 81921, 108732, 126229, 141102, 150457], // 5.7, slice=1024 USELESS
149        (..=10, ..=2048) => [-3417, 13564, 81208, 133035, 168506, 198114, 214382],   // 10, 5.7, slice=2048
150        (11, ..=1024) => [-1555, 25982, 126717, 155711, 174202, 191358, 198247],    // 6.3, slice=1024 USELESS
151        (11, ..=2048) => [-2229, 21208, 88554, 137643, 169905, 200075, 213746],  // 6.3, slice=2048 USELESS
152        (11, _) => [-3267, 25041, 24325, 40786, 100528, 155125, 182822],  // 11, 6.3, slice=4096
153        (_, ..=1024) => [-2206, 33628, 110901, 143147, 161228, 177559, 183794], // 12, 6.8, slice=1024 USELESS
154        (_, ..=2048) => [-2665, 16252, 98048, 149519, 183487, 214959, 227347],   // 12, 6.8, slice=2048 USELESS
155        (_, _) => [-3356, 26074, 26278, 44692, 94747, 143426, 168599],  // 12, 6.8, slice=4096  USELESS
156    }
157}
158
159impl<const MULTIPLIER: u8> SeedChooser for ShiftOnlyWrapped<MULTIPLIER> {
160
161    type UsedValues = UsedValueSet;
162
163    //type UsedValues = UsedValueSetLarge;
164    //const FUNCTION2_THRESHOLD: usize = 4096*2;
165
166    fn bucket_evaluator(&self, bits_per_seed: u8, slice_len: u16) -> Weights {
167        Weights(match MULTIPLIER {
168            1 => shift_only_wrapped_bucket_evaluator_m1(bits_per_seed, slice_len),
169            2 => shift_only_wrapped_bucket_evaluator_m2(bits_per_seed, slice_len),
170            _ => shift_only_wrapped_bucket_evaluator_m3(bits_per_seed, slice_len)
171        })
172    }
173
174    fn conf(self, output_range: usize, input_size: usize, bits_per_seed: u8, bucket_size_100: u16, preferred_slice_len: u16) -> Conf {
175        let max_shift = self.extra_shift(bits_per_seed);
176        let slice_len = match output_range.saturating_sub(max_shift as usize) {
177            n @ 0..4096 => (n/2+1).next_power_of_two() as u16,
178            /*64..1300 => 64,
179            1300..1750 => 128,
180            1750..7500 => 256,
181            7500..150000 => 512,
182            150000..250000 => 1024,*/
183            //_ => 2048,
184            _ => /* 2* */ 4096,
185        }.min(if preferred_slice_len != 0 { preferred_slice_len } else { match MULTIPLIER {
186            1 => match bits_per_seed {
187                ..=5 => 256,
188                ..=7 => 512,   // or 6 => 256 for smaller size
189                ..=9 => 1024,   // or 8 => 512 for smaller size
190                ..=11 => 2048,   // or 10 => 1024 for smaller size(?)
191                _ => 4096,
192                //_ => 2*4096
193            },
194            2 => match bits_per_seed {
195                ..=5 => 256,
196                ..=7 => 512,
197                8 => 1024,
198                ..=10 => 2048,   // or 9 => 1024 for smaller size
199                _ => 4096   // only 11, do not use 12
200                //_ => 2*4096
201            },
202            _ => match bits_per_seed {
203                ..=4 => 256,
204                ..=7 => 512,
205                8 => 1024,
206                ..=10 => 2048,  // or (for MULTIPLIER=3) 10 => 4096 for faster construction
207                _ => 4096
208            },
209        }});        
210        Conf::new(output_range, input_size, bucket_size_100, slice_len, max_shift)
211    }
212
213    #[inline(always)] fn f(self, primary_code: u64, seed: u16, conf: &Conf) -> usize {
214        conf.slice_begin(primary_code) + ((primary_code as u16).wrapping_add(seed.wrapping_mul(MULTIPLIER as u16)) & conf.slice_len_minus_one) as usize
215        //conf.slice_begin(primary_code) + ((primary_code as usize).wrapping_add(seed as usize*MULTIPLIER as usize) & conf.slice_len_minus_one as usize)
216    }
217
218    /*#[inline(always)] fn f_slice<SS: SeedSize>(primary_code: u64, slice_begin: usize, seed: u16, conf: &Conf<SS>) -> usize {
219        slice_begin + ((primary_code as usize).wrapping_add((seed-1) as usize*MULTIPLIER as usize) & conf.slice_len_minus_one as usize)
220    }*/
221
222    #[inline]
223    fn best_seed(self, used_values: &mut Self::UsedValues, keys: &[u64], conf: &Conf, bits_per_seed: u8) -> u16 {
224        let mut without_shift_arrayvec: arrayvec::ArrayVec::<(usize, u16), 16>;
225        let mut without_shift_box: Box<[(usize, u16)]>;
226        let without_shift: &mut [(usize, u16)] = if keys.len() > 16 {   // we add MULTIPLIER to key as shift=0 is invalid (reserved for bumping)
227            without_shift_box = keys.iter().map(|key| (conf.slice_begin(*key), (*key as u16).wrapping_add(MULTIPLIER as u16) & conf.slice_len_minus_one)).collect();
228            &mut without_shift_box
229        } else {
230            without_shift_arrayvec = keys.iter().map(|key| (conf.slice_begin(*key), (*key as u16).wrapping_add(MULTIPLIER as u16) & conf.slice_len_minus_one)).collect();
231            &mut without_shift_arrayvec
232        };
233
234        let slice_len = conf.slice_len();
235        let mut score_without_shift: usize = 1<<20; // this is not a real score as we only need relative scores
236        let mut best_score = usize::MAX;
237        let mut total_end_shift = ((MULTIPLIER as u16) << bits_per_seed) - MULTIPLIER as u16;
238        // note that total_last_shift itself is not allowed
239        let mut shift_sum = 0;
240        let mut best_total_shift = u16::MAX;
241        loop {  // while total_last_shift > 0
242            let max_sh0 = without_shift.iter().map(|(_, sh0)| *sh0).max().unwrap();
243            let mut shift_end = Multiplier::<MULTIPLIER>::multiple_rounded_up(slice_len - max_sh0);
244            let last = shift_end >= total_end_shift;
245            if last { shift_end = total_end_shift; }
246            if score_without_shift < best_score {
247                if let Some(best_shift) = Multiplier::<MULTIPLIER>::best_in_range(shift_end, without_shift, used_values) {
248                    let new_score = score_without_shift + best_shift as usize * keys.len();
249                    if new_score < best_score {
250                        best_total_shift = shift_sum + best_shift;
251                        best_score = new_score;
252                    }
253                }
254            }
255            if last { break; }
256            score_without_shift += shift_end as usize * keys.len();
257            for (_, sh0) in without_shift.iter_mut() {
258                *sh0 += shift_end;
259                if *sh0 >= slice_len {
260                    *sh0 -= slice_len;
261                    score_without_shift -= slice_len as usize;
262                }
263            }
264            total_end_shift -= shift_end;
265            shift_sum += shift_end;
266        }
267        if best_total_shift == u16::MAX {
268            0
269        } else {
270            let best_plus_multiplier = best_total_shift as usize + MULTIPLIER as usize;
271            for key in keys {
272                used_values.add(conf.slice_begin(*key) + ((*key as usize).wrapping_add(best_plus_multiplier)&conf.slice_len_minus_one as usize));
273            }
274            (best_plus_multiplier / MULTIPLIER as usize) as u16
275        }
276    }
277}
278
279
280
281/// [`SeedChooser`] to build (1-)perfect functions which uses both shifting with wrapping and regular hashing.
282/// The parameter points the number of bits of seed used for regular hashing.
283/// Increasing it reduces size but slows down construction.
284/// 
285/// Can be used with any function type: [`Function`], [`Function2`], [`Perfect`].
286/// 
287/// It chooses best seed using both shifting with wrapping and hashing,
288/// which leads to small size and medium speed constrictions,
289/// but quite slow evaluation.
290/// 
291/// `MULTIPLIER` should be 1, 2, or 3.
292/// Typically, increasing `MULTIPLIER` reduces size but slows down construction.
293#[derive(Clone, Copy)]
294pub struct ShiftSeedWrapped<const MULTIPLIER: u8>(pub u8);
295
296impl<const MULTIPLIER: u8> SeedChooser for ShiftSeedWrapped<MULTIPLIER> {
297    type UsedValues = UsedValueSet;
298
299    fn conf(self, output_range: usize, input_size: usize, bits_per_seed: u8, bucket_size_100: u16, preferred_slice_len: u16) -> Conf {
300        let max_shift = self.extra_shift(bits_per_seed);
301        let slice_len = match output_range.saturating_sub(max_shift as usize) {
302            n @ 0..64 => (n/2+1).next_power_of_two() as u16,
303            64..1300 => 64,
304            1300..1750 => 128,
305            1750..7500 => 256,
306            7500..150000 => 512,
307            150000..250000 => 1024,
308            _ => 2048,
309        }.min(if preferred_slice_len != 0 { preferred_slice_len } else { 1024 });    // TODO tune 1024
310        Conf::new(output_range, input_size, bucket_size_100, slice_len, max_shift)
311    }
312
313    #[inline(always)] fn f(self, primary_code: u64, seed: u16, conf: &Conf) -> usize {
314        conf.slice_begin(primary_code) +
315            ((mix_key_seed(primary_code, (seed>>self.0) + 1)
316             + MULTIPLIER as u16 * seed) & conf.slice_len_minus_one) as usize
317    }
318
319    #[inline]
320    fn best_seed(self, used_values: &mut Self::UsedValues, keys: &[u64], conf: &Conf, bits_per_seed: u8) -> u16 {
321        //TODO check; what with seed=0, shift=0?
322        let slice_len = conf.slice_len();
323        let mut best_score = usize::MAX;
324        let mut best_total_shift = u16::MAX;
325        let mut best_seed = u16::MAX;
326        let mut without_shift_arrayvec: arrayvec::ArrayVec::<(usize, u16), 16>;
327        let mut without_shift_box: Box<[(usize, u16)]>;
328        let without_shift: &mut [(usize, u16)] = if keys.len() > 16 {
329            without_shift_box = keys.iter().map(|_| (0, 0)).collect();
330            &mut without_shift_box
331        } else {
332            without_shift_arrayvec = keys.iter().map(|_| (0, 0)).collect();
333            &mut without_shift_arrayvec
334        };
335
336        for seed in 0..1<<(bits_per_seed - self.0) {
337            for ((slice_begin, in_slice), key) in without_shift.iter_mut().zip(keys) {
338                *slice_begin = conf.slice_begin(*key);
339                *in_slice = mix_key_seed(*key, seed+1).wrapping_add((MULTIPLIER as u16*seed) << self.0);
340                if seed == 0 { *in_slice = in_slice.wrapping_add(MULTIPLIER as u16); }   // minimal shift for seed = 0 is 1
341                *in_slice &= conf.slice_len_minus_one;
342            }
343            let mut score_without_shift: usize = without_shift.iter().map(|(sb, is)| *sb + *is as usize).sum();
344            let mut total_end_shift = (1u16 << self.0) * MULTIPLIER as u16;
345            if seed == 0 { total_end_shift -= MULTIPLIER as u16; }
346            let mut shift_sum = 0; //if seed == 0 { MULTIPLIER as u16 } else { 0 };
347            loop {  // while total_last_shift > 0
348                let max_sh0 = without_shift.iter().map(|(_, sh0)| *sh0).max().unwrap();
349                let mut shift_end = Multiplier::<MULTIPLIER>::multiple_rounded_up(slice_len - max_sh0);
350                let last = shift_end >= total_end_shift;
351                if last { shift_end = total_end_shift; }
352                if score_without_shift < best_score {
353                    if let Some(best_shift) = Multiplier::<MULTIPLIER>::best_in_range(shift_end, without_shift, used_values) {
354                        let new_score = score_without_shift + best_shift as usize * keys.len();
355                        if new_score < best_score {
356                            best_total_shift = shift_sum + best_shift;
357                            if seed == 0 { best_total_shift += MULTIPLIER as u16; }
358                            best_seed = seed;
359                            best_score = new_score;
360                        }
361                    }
362                }
363                if last { break; }
364                score_without_shift += shift_end as usize * keys.len();
365                for (_, sh0) in without_shift.iter_mut() {
366                    *sh0 += shift_end;
367                    if *sh0 >= slice_len {
368                        *sh0 -= slice_len;
369                        score_without_shift -= slice_len as usize;
370                    }
371                }
372                total_end_shift -= shift_end;
373                shift_sum += shift_end;
374            }
375        }
376        if best_total_shift == u16::MAX {
377            0
378        } else {
379            let result = (best_seed << self.0) | (best_total_shift / MULTIPLIER as u16);
380            for key in keys {
381                used_values.add(conf.slice_begin(*key) +
382                    ((mix_key_seed(*key, best_seed + 1)
383                    + MULTIPLIER as u16 * result) & conf.slice_len_minus_one) as usize
384                );
385            }
386            result
387        }
388    }
389}
390
391/*pub struct ShiftSeedWrapped<const BITS_PER_SEED: u8, const MULTIPLIER: u8>;
392
393impl<const BITS_PER_SEED: u8, const MULTIPLIER: u8> SeedChooser for ShiftSeedWrapped<BITS_PER_SEED, MULTIPLIER> {
394    #[inline(always)] fn f<SS: SeedSize>(primary_code: u64, seed: u16, conf: &Conf<SS>) -> usize {
395        let shift  = (seed >> BITS_PER_SEED) * MULTIPLIER as u16;
396        let seed = (seed & ((1<<BITS_PER_SEED)-1)) + 1;
397        conf.slice_begin(primary_code) + conf.in_slice_seed_shift(primary_code, seed, shift)
398    }
399
400    #[inline(always)]
401    fn best_seed<SS: SeedSize>(used_values: &mut UsedValues, keys: &[u64], conf: &Conf<SS>) -> u16 {
402        let mut best_seed = 0;
403        let mut best_value = usize::MAX;
404        if keys.len() <= SMALL_BUCKET_LIMIT {
405            best_seed_small::<Self, _>(&mut best_value, &mut best_seed, used_values, keys, conf)
406        } else {
407            best_seed_big::<Self, _>(&mut best_value, &mut best_seed, used_values, keys, conf)
408        };
409        if best_seed != 0 { // can assign seed to the bucket
410            for key in keys {
411                used_values.add(Self::f(*key, best_seed, conf));
412            }
413        };
414        best_seed
415    }
416}*/