ph_temp/phast/seed_chooser/
mod.rs1mod k;
2pub use k::SeedOnlyK;
3
4mod shift;
5pub use shift::{ShiftOnly};
6
7mod shift_wrap;
8pub use shift_wrap::{ShiftOnlyWrapped, ShiftSeedWrapped};
9
10use crate::phast::{cyclic::{GenericUsedValue, UsedValueSet}, Params, Weights};
11
12use super::conf::Conf;
13
14pub(crate) fn slice_len(output_without_shift_range: usize, bits_per_seed: u8, preferred_slice_len: u16) -> u16 {
16 match output_without_shift_range {
17 n @ 0..64 => (n/2+1).next_power_of_two() as u16,
18 64..1300 => 64,
19 1300..9500 => 128,
20 9500..12000 => 256,
21 12000..140000 => 512,
22 _ if bits_per_seed < 6 => if preferred_slice_len == 0 { 512 } else { preferred_slice_len },
23 _ if bits_per_seed < 12 => if preferred_slice_len == 0 { 1024 } else { preferred_slice_len }, _ => if preferred_slice_len == 0 { 2048 } else { preferred_slice_len }
25 }
26}
27
28pub trait SeedChooser: Copy {
30 const BUMPING: bool = true;
32
33 const FIRST_SEED: u16 = if Self::BUMPING { 1 } else { 0 };
35
36 const FUNCTION2_THRESHOLD: usize = 4096;
38
39 type UsedValues: GenericUsedValue;
40
41 #[inline(always)] fn k(self) -> u8 { 1 }
43
44 #[inline(always)] fn minimal_output_range(self, num_of_keys: usize) -> usize { num_of_keys }
46
47 #[inline] fn bucket_evaluator(&self, bits_per_seed: u8, slice_len: u16) -> Weights {
48 Weights::new(bits_per_seed, slice_len)
49 }
50
51 fn conf(self, output_range: usize, input_size: usize, bits_per_seed: u8, bucket_size_100: u16, preferred_slice_len: u16) -> Conf {
52 let max_shift = self.extra_shift(bits_per_seed);
53 let slice_len = slice_len(output_range.saturating_sub(max_shift as usize), bits_per_seed.into(), preferred_slice_len);
54 Conf::new(output_range, input_size, bucket_size_100, slice_len, max_shift)
55 }
56
57 #[inline(always)] fn conf_for_minimal(self, num_of_keys: usize, bits_per_seed: u8, bucket_size_100: u16, preferred_slice_len: u16) -> Conf {
58 self.conf(self.minimal_output_range(num_of_keys), num_of_keys, bits_per_seed, bucket_size_100, preferred_slice_len)
59 }
60
61 #[inline(always)] fn conf_for_minimal_p<SS: Copy+Into<u8>>(self, num_of_keys: usize, params: &Params<SS>) -> Conf {
62 self.conf_for_minimal(num_of_keys, params.seed_size.into(), params.bucket_size100, params.preferred_slice_len)
63 }
64
65 #[inline(always)] fn extra_shift(self, _bits_per_seed: u8) -> u16 { 0 }
67
68 fn f(self, primary_code: u64, seed: u16, conf: &Conf) -> usize;
70
71 fn best_seed(self, used_values: &mut Self::UsedValues, keys: &[u64], conf: &Conf, bits_per_seed: u8) -> u16;
73}
74
75#[inline(always)]
76fn best_seed_big<SC: SeedChooser>(seed_chooser: SC, best_value: &mut usize, best_seed: &mut u16, used_values: &mut UsedValueSet, keys: &[u64], conf: &Conf, seeds_num: u16) {
77 let mut values_used_by_seed = Vec::with_capacity(keys.len());
78 let simd_keys = keys.len() / 4 * 4;
79 'outer: for seed in SC::FIRST_SEED..seeds_num { values_used_by_seed.clear();
82 for i in (0..simd_keys).step_by(4) {
83 let values = [
84 seed_chooser.f(keys[i], seed, conf),
85 seed_chooser.f(keys[i+1], seed, conf),
86 seed_chooser.f(keys[i+2], seed, conf),
87 seed_chooser.f(keys[i+3], seed, conf),
88 ];
89 let contains = [
90 used_values.contain(values[0]),
91 used_values.contain(values[1]),
92 used_values.contain(values[2]),
93 used_values.contain(values[3]),
94 ];
95 if contains.iter().any(|b| *b) { continue 'outer; }
96 values_used_by_seed.push(values[0]);
98 values_used_by_seed.push(values[1]);
99 values_used_by_seed.push(values[2]);
100 values_used_by_seed.push(values[3]);
101 }
102 for i in simd_keys..keys.len() {
104 let value = seed_chooser.f(keys[i], seed, conf);
105 if used_values.contain(value) { continue 'outer; }
106 values_used_by_seed.push(value);
107 }
108 let seed_value = values_used_by_seed.iter().sum();
109 if seed_value < *best_value {
110 values_used_by_seed.sort();
111 if values_used_by_seed.windows(2).any(|v| v[0]==v[1]) {
112 continue;
116 }
117 *best_value = seed_value;
118 *best_seed = seed;
119 }
120 }
121}
122
123#[inline(always)]
124fn best_seed_small<SC: SeedChooser>(seed_chooser: SC, best_value: &mut usize, best_seed: &mut u16, used_values: &mut UsedValueSet, keys: &[u64], conf: &Conf, seeds_num: u16) {
125 assert!(keys.len() <= SMALL_BUCKET_LIMIT); let mut values_used_by_seed = arrayvec::ArrayVec::<_, SMALL_BUCKET_LIMIT>::new(); 'outer: for seed in SC::FIRST_SEED..seeds_num { values_used_by_seed.clear();
129 for key in keys.iter().copied() {
130 let value = seed_chooser.f(key, seed, conf);
131 if used_values.contain(value) { continue 'outer; }
132 values_used_by_seed.push(value);
133 }
134 let seed_value = values_used_by_seed.iter().sum();
135 if seed_value < *best_value {
136 values_used_by_seed.sort_unstable();
137 for i in 1..values_used_by_seed.len() {
138 if values_used_by_seed[i-1] == values_used_by_seed[i] {
139 continue 'outer;
143 }
144 }
145 *best_value = seed_value;
146 *best_seed = seed;
147 }
148 }
149}
150
151const SMALL_BUCKET_LIMIT: usize = 8;
152
153#[derive(Clone, Copy)]
160pub struct SeedOnly;
161
162impl SeedChooser for SeedOnly {
163 type UsedValues = UsedValueSet;
164
165 #[inline(always)] fn f(self, primary_code: u64, seed: u16, conf: &Conf) -> usize {
166 conf.f(primary_code, seed)
167 }
168
169 #[inline(always)]
174 fn best_seed(self, used_values: &mut Self::UsedValues, keys: &[u64], conf: &Conf, bits_per_seed: u8) -> u16 {
175 let mut best_seed = 0;
176 let mut best_value = usize::MAX;
177 if keys.len() <= SMALL_BUCKET_LIMIT {
178 best_seed_small(self, &mut best_value, &mut best_seed, used_values, keys, conf, 1<<bits_per_seed)
179 } else {
180 best_seed_big(self, &mut best_value, &mut best_seed, used_values, keys, conf, 1<<bits_per_seed)
181 };
182 if best_seed != 0 { for key in keys {
184 used_values.add(conf.f(*key, best_seed));
185 }
186 };
187 best_seed
188 }
189}
190
191#[derive(Clone, Copy)]
193pub struct SeedOnlyNoBump;
194
195impl SeedChooser for SeedOnlyNoBump {
196 const BUMPING: bool = false;
197 const FIRST_SEED: u16 = 0;
198
199 type UsedValues = UsedValueSet;
200
201 #[inline(always)] fn f(self, primary_code: u64, seed: u16, conf: &Conf) -> usize {
202 conf.f_nobump(primary_code, seed)
203 }
204
205 #[inline]
206 fn best_seed(self, used_values: &mut Self::UsedValues, keys: &[u64], conf: &Conf, bits_per_seed: u8) -> u16 {
207 let mut best_seed = u16::MAX;
209 let mut best_value = usize::MAX;
210 if keys.len() <= SMALL_BUCKET_LIMIT {
211 best_seed_small(self, &mut best_value, &mut best_seed, used_values, keys, conf, 1<<bits_per_seed)
212 } else {
213 best_seed_big(self, &mut best_value, &mut best_seed, used_values, keys, conf, 1<<bits_per_seed)
214 };
215 if best_seed != u16::MAX { for key in keys {
217 used_values.add(conf.f_nobump(*key, best_seed));
218 }
219 };
220 best_seed
221 }
222}
223
224