prime_formula/common/
mod.rs1pub const NON_ROOT_PRIMES: [u8; 4] = [2, 3, 5, 7];
9
10pub const PRIME_PERIOD: u8 = {
14 let mut product = 1;
15 let mut i = 0;
16 while i < NON_ROOT_PRIMES.len() {
17 product *= NON_ROOT_PRIMES[i];
18 i += 1;
19 }
20 product
21};
22
23pub const PRIME_ROOTS: [u8; 48] = {
28 let mut primes = [0u8; 48];
29 let mut num = 2;
30 let mut idx = 0;
31
32 while num < PRIME_PERIOD + 2 {
34 if num % 2 != 0 && num % 3 != 0 && num % 5 != 0 && num % 7 != 0 {
36 primes[idx] = num;
37 idx += 1;
38 }
39 num += 1;
40 }
41
42 if idx != 48 {
44 panic!("Prime roots count mismatch");
45 }
46
47 primes
48};
49
50pub const NUM_ROOTS: usize = PRIME_ROOTS.len();
52
53pub fn align_to_cycle(start: u128, end: u128) -> (u128, u128) {
55 let r_min = PRIME_ROOTS[0] as u128; let r_max = PRIME_ROOTS[NUM_ROOTS - 1] as u128; let b_start = (start.saturating_sub(r_max)).div_ceil(210); let b_end = 1 + (end - r_min) / 210; (b_start, b_end)
73}
74
75pub fn find_inv_prime_root_vec(root_idx: usize) -> Vec<u8> {
83 let r = PRIME_ROOTS[root_idx] as u32;
84 PRIME_ROOTS
85 .iter()
86 .copied()
87 .map(|q| {
88 let period = PRIME_PERIOD as u32;
89 let q = q as u32;
90 PRIME_ROOTS
91 .iter()
92 .copied()
93 .find(|&h_candidate| (q * h_candidate as u32) % period == r % period)
94 .expect("No inverse prime root found")
95 })
96 .collect()
97}
98
99pub fn get_cyclic_composite_vec(root_index: usize, inv_prime_root_table_row: &[u8]) -> Vec<u8> {
106 let r = PRIME_ROOTS[root_index] as u32;
107 let period = PRIME_PERIOD as u32;
108 PRIME_ROOTS
109 .iter()
110 .enumerate()
111 .map(|(j, &q)| {
112 let q_hat = inv_prime_root_table_row[j] as u32;
113 let q = q as u32;
114 let val = if r > (q * q_hat) {
115 1 + (period + q * q_hat - r) / period
116 } else {
117 1 + (q * q_hat - r) / period
118 };
119 val as u8
120 })
121 .collect()
122}
123
124pub fn get_small_primes(start: u128, end: u128) -> Vec<u128> {
126 [2, 3, 5, 7]
127 .iter()
128 .filter(|&&p| p >= start && p <= end)
129 .cloned()
130 .collect()
131}
132
133#[derive(Debug, Copy, Clone, PartialEq)]
135pub enum ConfigMode {
136 Sieve,
138 Window,
140 MillerRabinDeterministic,
142 MillerRabinProbabilistic,
144}
145
146pub fn get_auto_mode(_start: u128, end: u128) -> ConfigMode {
150 let big_o_sieve = end.isqrt(); let big_o_miller = end.ilog10().pow(6) as u128;
152
153 if big_o_sieve > big_o_miller {
154 if end > u64::MAX as u128 {
158 ConfigMode::MillerRabinProbabilistic
159 } else {
160 ConfigMode::MillerRabinDeterministic
161 }
162 } else {
163 ConfigMode::Sieve
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn test_constants() {
176 assert_eq!(NON_ROOT_PRIMES, [2, 3, 5, 7]);
178
179 assert_eq!(PRIME_PERIOD, 2 * 3 * 5 * 7);
181
182 assert_eq!(PRIME_ROOTS.len(), 48);
184 for &root in &PRIME_ROOTS {
185 assert!(root >= 11);
186 assert!(root <= 211);
187 assert_ne!(root % 2, 0);
188 assert_ne!(root % 3, 0);
189 assert_ne!(root % 5, 0);
190 assert_ne!(root % 7, 0);
191 }
192 }
193
194 #[test]
195 fn test_align_to_cycle() {
196 assert_eq!(align_to_cycle(0, 210), (0, 1));
198 assert_eq!(align_to_cycle(210, 420), (0, 2)); assert_eq!(align_to_cycle(100, 200), (0, 1));
202 assert_eq!(align_to_cycle(300, 500), (1, 3));
203
204 assert_eq!(align_to_cycle(211, 211), (0, 1)); assert_eq!(align_to_cycle(13, 13), (0, 1)); }
208
209 #[test]
210 fn test_inverse_prime_roots() {
211 let first_inverses = find_inv_prime_root_vec(0);
213 assert_eq!(first_inverses.len(), 48);
214
215 let last_inverses = find_inv_prime_root_vec(47);
216 assert_eq!(last_inverses.len(), 48);
217
218 let test_root = PRIME_ROOTS[10]; let inverses = find_inv_prime_root_vec(10);
221 for (i, &h) in inverses.iter().enumerate() {
222 let q = PRIME_ROOTS[i];
223 assert_eq!(
224 (q as u32 * h as u32) % PRIME_PERIOD as u32,
225 test_root as u32 % PRIME_PERIOD as u32
226 );
227 }
228 }
229
230 #[test]
231 fn test_cyclic_composites() {
232 let test_index = PRIME_ROOTS.iter().position(|&r| r == 11).unwrap();
234 let inverses = find_inv_prime_root_vec(test_index);
235 let composites = get_cyclic_composite_vec(test_index, &inverses);
236
237 assert_eq!(composites.len(), 48);
239 assert!(composites.iter().all(|&v| v > 0));
240 }
241
242 #[test]
243 fn test_small_primes() {
244 assert_eq!(get_small_primes(2, 10), vec![2, 3, 5, 7]);
246
247 assert_eq!(get_small_primes(5, 7), vec![5, 7]);
249
250 assert!(get_small_primes(8, 10).is_empty());
252 }
253
254 #[test]
255 fn test_auto_mode_selection() {
256 assert_eq!(get_auto_mode(0, 1_000), ConfigMode::Sieve);
258
259 assert_eq!(
261 get_auto_mode(0, u128::MAX),
262 ConfigMode::MillerRabinProbabilistic
263 );
264
265 let borderline = 10u128.pow(15);
267 let mode = get_auto_mode(0, borderline);
268 assert!(matches!(
269 mode,
270 ConfigMode::Sieve | ConfigMode::MillerRabinDeterministic
271 ));
272 }
273
274 #[test]
275 fn test_prime_root_validity() {
276 assert!(PRIME_ROOTS.iter().all(|&r| (11..=211).contains(&r)));
278
279 let mut sorted = PRIME_ROOTS.to_vec();
281 sorted.sort_unstable();
282 sorted.dedup();
283 assert_eq!(sorted.len(), 48);
284 }
285
286 #[test]
287 fn test_boundary_alignment() {
288 assert_eq!(align_to_cycle(209, 211), (0, 1));
290 assert_eq!(align_to_cycle(211, 421), (0, 2));
291
292 let big_num = 210u128.pow(10);
294 assert_eq!(
295 align_to_cycle(big_num, big_num + 100),
296 (big_num / 210 - 1, big_num / 210 + 1)
297 );
298 }
299}