1use crate::factor::{pollard_rho, trial_division};
14use crate::nt_funcs::{
15 factorize128, is_prime64, next_prime, nth_prime_bounds, nth_prime_est, prev_prime,
16};
17use crate::primality::{PrimalityBase, PrimalityRefBase};
18use crate::tables::{SMALL_PRIMES, SMALL_PRIMES_NEXT};
19use crate::traits::{
20 FactorizationConfig, Primality, PrimalityTestConfig, PrimalityUtils, PrimeBuffer,
21};
22use bitvec::{bitvec, prelude::Msb0};
23use lru::LruCache;
24use num_integer::Roots;
25use rand::random;
26use std::collections::BTreeMap;
27use std::num::NonZeroUsize;
28
29pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
31 fn is_prime<T: PrimalityBase>(
40 &self,
41 target: &T,
42 config: Option<PrimalityTestConfig>,
43 ) -> Primality
44 where
45 for<'r> &'r T: PrimalityRefBase<T>,
46 {
47 if target.is_even() {
49 return if target == &T::from_u8(2u8).unwrap() {
50 Primality::Yes
51 } else {
52 Primality::No
53 };
54 }
55
56 if let Some(x) = target.to_u64() {
58 return match is_prime64(x) {
59 true => Primality::Yes,
60 false => Primality::No,
61 };
62 }
63
64 let config = config.unwrap_or_default();
65 let mut probability = 1.;
66
67 let mut witness_list: Vec<u64> = Vec::new();
69 if config.sprp_trials > 0 {
70 witness_list.extend(self.iter().take(config.sprp_trials));
71 probability *= 1. - 0.25f32.powi(config.sprp_trials as i32);
72 }
73 if config.sprp_random_trials > 0 {
74 for _ in 0..config.sprp_random_trials {
75 let mut w: u64 = rand::random();
77 while witness_list.iter().any(|x| x == &w) {
78 w = rand::random();
79 }
80 witness_list.push(w);
81 }
82 probability *= 1. - 0.25f32.powi(config.sprp_random_trials as i32);
83 }
84 if !witness_list
85 .into_iter()
86 .all(|x| target.is_sprp(T::from_u64(x).unwrap()))
87 {
88 return Primality::No;
89 }
90
91 if config.slprp_test {
93 probability *= 1. - 4f32 / 15f32;
94 if !target.is_slprp(None, None) {
95 return Primality::No;
96 }
97 }
98 if config.eslprp_test {
99 probability *= 1. - 4f32 / 15f32;
100 if !target.is_eslprp(None) {
101 return Primality::No;
102 }
103 }
104
105 Primality::Probable(probability)
106 }
107
108 fn factors<T: PrimalityBase>(
118 &self,
119 target: T,
120 config: Option<FactorizationConfig>,
121 ) -> (BTreeMap<T, usize>, Option<Vec<T>>)
122 where
123 for<'r> &'r T: PrimalityRefBase<T>,
124 {
125 if let Some(x) = target.to_u128() {
127 let factors = factorize128(x)
128 .into_iter()
129 .map(|(k, v)| (T::from_u128(k).unwrap(), v))
130 .collect();
131 return (factors, None);
132 }
133 let config = config.unwrap_or_default();
134
135 let (result, factored) = trial_division(self.iter().copied(), target, config.td_limit);
137 let mut result: BTreeMap<T, usize> = result
138 .into_iter()
139 .map(|(k, v)| (T::from_u64(k).unwrap(), v))
140 .collect();
141
142 let mut failed = Vec::new();
146 let mut config = config;
147 config.td_limit = Some(0); match factored {
149 Ok(res) => {
150 if !res.is_one() {
151 result.insert(res, 1);
152 }
153 }
154 Err(res) => {
155 let mut todo = vec![res];
156 while let Some(target) = todo.pop() {
157 if self
158 .is_prime(&target, Some(config.primality_config))
159 .probably()
160 {
161 *result.entry(target).or_insert(0) += 1;
162 } else if let Some(divisor) = self.divisor(&target, &mut config) {
163 todo.push(divisor.clone());
164 todo.push(target / divisor);
165 } else {
166 failed.push(target);
167 }
168 }
169 }
170 };
171
172 if failed.is_empty() {
173 (result, None)
174 } else {
175 (result, Some(failed))
176 }
177 }
178
179 fn factorize<T: PrimalityBase>(&self, target: T) -> BTreeMap<T, usize>
184 where
185 for<'r> &'r T: PrimalityRefBase<T>,
186 {
187 loop {
189 let (result, remainder) = self.factors(target.clone(), None);
190 if remainder.is_none() {
191 break result;
192 }
193 }
194 }
195
196 fn divisor<T: PrimalityBase>(&self, target: &T, config: &mut FactorizationConfig) -> Option<T>
201 where
202 for<'r> &'r T: PrimalityRefBase<T>,
203 {
204 if matches!(config.td_limit, Some(0)) {
205 let tsqrt: T = Roots::sqrt(target) + T::one();
207 let limit = if let Some(l) = config.td_limit {
208 tsqrt.clone().min(T::from_u64(l).unwrap())
209 } else {
210 tsqrt.clone()
211 };
212
213 for p in self.iter().map(|p| T::from_u64(*p).unwrap()) {
214 if p > tsqrt {
215 return None; }
217 if p > limit {
218 break;
219 }
220 if target.is_multiple_of(&p) {
221 return Some(p);
222 }
223 }
224 }
225
226 let below64 = target.to_u64().is_some();
228 while config.rho_trials > 0 {
229 let (start, offset) = if below64 {
230 (
231 T::from_u8(random::<u8>()).unwrap() % target,
232 T::from_u8(random::<u8>()).unwrap() % target,
233 )
234 } else {
235 (
236 T::from_u64(random::<u64>()).unwrap() % target,
237 T::from_u64(random::<u64>()).unwrap() % target,
238 )
239 };
240 config.rho_trials -= 1;
241 if let (Some(p), _) = pollard_rho(target, start, offset, 1_048_576) {
244 return Some(p);
245 }
246 }
247
248 None
249 }
250}
251
252impl<T> PrimeBufferExt for T where for<'a> T: PrimeBuffer<'a> {}
253
254pub struct NaiveBuffer {
256 list: Vec<u64>, next: u64, }
259
260impl Default for NaiveBuffer {
261 fn default() -> Self {
262 Self::new()
263 }
264}
265
266impl NaiveBuffer {
267 #[inline]
268 #[must_use]
269 pub fn new() -> Self {
270 let list = SMALL_PRIMES.iter().map(|&p| u64::from(p)).collect();
271 NaiveBuffer {
272 list,
273 next: SMALL_PRIMES_NEXT,
274 }
275 }
276}
277
278impl<'a> PrimeBuffer<'a> for NaiveBuffer {
279 type PrimeIter = std::slice::Iter<'a, u64>;
280
281 fn contains(&self, num: u64) -> bool {
282 self.list.binary_search(&num).is_ok()
283 }
284
285 fn clear(&mut self) {
286 self.list.truncate(16);
287 self.list.shrink_to_fit();
288 self.next = 55; }
290
291 fn iter(&'a self) -> Self::PrimeIter {
292 self.list.iter()
293 }
294
295 fn bound(&self) -> u64 {
296 *self.list.last().unwrap()
297 }
298
299 fn reserve(&mut self, limit: u64) {
300 let sieve_limit = (limit | 1) + 2; let current = self.next; debug_assert!(current % 2 == 1);
303 if sieve_limit < current {
304 return;
305 }
306
307 let mut sieve = bitvec![usize, Msb0; 0; ((sieve_limit - current) / 2) as usize];
309 for p in self.list.iter().skip(1) {
310 let start = if p * p < current {
312 p * ((current / p) | 1) } else {
314 p * p
315 };
316 for multi in (start..sieve_limit).step_by(2 * (*p as usize)) {
317 if multi >= current {
318 sieve.set(((multi - current) / 2) as usize, true);
319 }
320 }
321 }
322
323 for p in (current..Roots::sqrt(&sieve_limit) + 1).step_by(2) {
325 for multi in (p * p..sieve_limit).step_by(2 * (p as usize)) {
326 if multi >= current {
327 sieve.set(((multi - current) / 2) as usize, true);
328 }
329 }
330 }
331
332 self.list
334 .extend(sieve.iter_zeros().map(|x| (x as u64) * 2 + current));
335 self.next = sieve_limit;
336 }
337}
338
339impl NaiveBuffer {
340 pub fn primorial<T: PrimalityBase + std::iter::Product>(&mut self, n: usize) -> T {
345 self.nprimes(n).map(|&p| T::from_u64(p).unwrap()).product()
346 }
347
348 pub fn primes(&mut self, limit: u64) -> std::iter::Take<<Self as PrimeBuffer<'_>>::PrimeIter> {
354 self.reserve(limit);
355 let position = match self.list.binary_search(&limit) {
356 Ok(p) => p + 1,
357 Err(p) => p,
358 }; self.list.iter().take(position)
360 }
361
362 #[must_use]
364 pub fn into_primes(mut self, limit: u64) -> std::vec::IntoIter<u64> {
365 self.reserve(limit);
366 let position = match self.list.binary_search(&limit) {
367 Ok(p) => p + 1,
368 Err(p) => p,
369 }; self.list.truncate(position);
371 self.list.into_iter()
372 }
373
374 pub fn nprimes(
376 &mut self,
377 count: usize,
378 ) -> std::iter::Take<<Self as PrimeBuffer<'_>>::PrimeIter> {
379 let (_, bound) = nth_prime_bounds(&(count as u64))
380 .expect("Estimated size of the largest prime will be larger than u64 limit");
381 self.reserve(bound);
382 debug_assert!(self.list.len() >= count);
383 self.list.iter().take(count)
384 }
385
386 #[must_use]
388 pub fn into_nprimes(mut self, count: usize) -> std::vec::IntoIter<u64> {
389 let (_, bound) = nth_prime_bounds(&(count as u64))
390 .expect("Estimated size of the largest prime will be larger than u64 limit");
391 self.reserve(bound);
392 debug_assert!(self.list.len() >= count);
393 self.list.truncate(count);
394 self.list.into_iter()
395 }
396
397 pub fn nth_prime(&mut self, n: u64) -> u64 {
402 if n < self.list.len() as u64 {
403 return self.list[n as usize - 1];
404 }
405
406 const THRESHOLD_NTH_PRIME_SIEVE: u64 = 4096;
408 if n <= THRESHOLD_NTH_PRIME_SIEVE {
409 return *self.nprimes(n as usize).next_back().unwrap();
410 }
411
412 let mut x = prev_prime(&nth_prime_est(&n).unwrap(), None).unwrap();
414 let mut pi = self.prime_pi(x);
415
416 while pi > n {
417 x = prev_prime(&x, None).unwrap();
418 pi -= 1;
419 }
420 while pi < n {
421 x = next_prime(&x, None).unwrap();
422 pi += 1;
423 }
424 x
425 }
426
427 pub fn prime_phi(&mut self, x: u64, a: usize, cache: &mut LruCache<(u64, usize), u64>) -> u64 {
429 if a == 1 {
430 return crate::util::div_ceil_u64(x, 2);
432 }
433 if let Some(v) = cache.get(&(x, a)) {
434 return *v;
435 }
436 let t1 = self.prime_phi(x, a - 1, cache);
437 let pa = self.nth_prime(a as u64);
438 let t2 = self.prime_phi(x / pa, a - 1, cache);
439 let t = t1 - t2;
440 cache.put((x, a), t);
441 t
442 }
443
444 pub fn prime_pi(&mut self, limit: u64) -> u64 {
448 const THRESHOLD_PRIME_PI_SIEVE: u64 = 38873; if &limit <= self.list.last().unwrap() || limit <= THRESHOLD_PRIME_PI_SIEVE {
451 self.reserve(limit);
452
453 return match self.list.binary_search(&limit) {
454 Ok(pos) => (pos + 1) as u64,
455 Err(pos) => pos as u64,
456 };
457 }
458
459 let b = limit.sqrt();
461 let a = b.sqrt();
462 let c = limit.cbrt();
463 self.reserve(b);
464
465 let a = self.prime_pi(a);
466 let b = self.prime_pi(b);
467 let c = self.prime_pi(c);
468
469 let cache_cap = NonZeroUsize::new(a as usize).unwrap(); let mut phi_cache = LruCache::new(cache_cap);
471 let mut sum =
472 self.prime_phi(limit, a as usize, &mut phi_cache) + (b + a - 2) * (b - a + 1) / 2;
473 for i in (a + 1)..=b {
474 let w = limit / self.nth_prime(i);
475 sum -= self.prime_pi(w);
476 if i <= c {
477 let l = self.prime_pi(w.sqrt());
478 sum += (l * (l - 1) - i * (i - 3)) / 2 - 1;
479 for j in i..=l {
480 let pj = self.nth_prime(j);
481 sum -= self.prime_pi(w / pj);
482 }
483 }
484 }
485 sum
486 }
487}
488
489#[cfg(test)]
490mod tests {
491 use super::*;
492 use crate::mint::SmallMint;
493 #[cfg(feature = "num-bigint")]
494 use core::str::FromStr;
495 #[cfg(feature = "num-bigint")]
496 use num_bigint::BigUint;
497 use rand::random;
498
499 #[test]
500 fn prime_generation_test() {
501 const PRIME50: [u64; 15] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47];
502 const PRIME300: [u64; 62] = [
503 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
504 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179,
505 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271,
506 277, 281, 283, 293,
507 ];
508
509 let mut pb = NaiveBuffer::new();
510 assert_eq!(pb.primes(50).copied().collect::<Vec<_>>(), PRIME50);
511 assert_eq!(pb.primes(300).copied().collect::<Vec<_>>(), PRIME300);
512
513 pb.clear();
515 assert_eq!(pb.primes(293).copied().collect::<Vec<_>>(), PRIME300);
516 pb = NaiveBuffer::new();
517 assert_eq!(*pb.primes(257).next_back().unwrap(), 257); pb = NaiveBuffer::new();
519 assert_eq!(*pb.primes(8167).next_back().unwrap(), 8167); }
521
522 #[test]
523 fn nth_prime_test() {
524 let mut pb = NaiveBuffer::new();
525 assert_eq!(pb.nth_prime(10000), 104_729);
526 assert_eq!(pb.nth_prime(20000), 224_737);
527 assert_eq!(pb.nth_prime(10000), 104_729); assert_eq!(pb.nth_prime(10u64.pow(4)), 104_729);
531 assert_eq!(pb.nth_prime(10u64.pow(5)), 1_299_709);
532 assert_eq!(pb.nth_prime(10u64.pow(6)), 15_485_863);
533 assert_eq!(pb.nth_prime(10u64.pow(7)), 179_424_673);
534 }
535
536 #[test]
537 fn prime_pi_test() {
538 let mut pb = NaiveBuffer::new();
539 assert_eq!(pb.prime_pi(8161), 1024); assert_eq!(pb.prime_pi(10000), 1229);
541 assert_eq!(pb.prime_pi(20000), 2262);
542 assert_eq!(pb.prime_pi(38873), 4096);
543
544 pb.clear(); assert_eq!(pb.prime_pi(8161), 1024);
546 assert_eq!(pb.prime_pi(10000), 1229);
547 assert_eq!(pb.prime_pi(20000), 2262);
548 assert_eq!(pb.prime_pi(10000), 1229); assert_eq!(pb.prime_pi(10u64.pow(5)), 9592);
552 assert_eq!(pb.prime_pi(10u64.pow(6)), 78498);
553 assert_eq!(pb.prime_pi(10u64.pow(7)), 664_579);
554 assert_eq!(pb.prime_pi(10u64.pow(8)), 5_761_455);
555 }
556
557 #[test]
558 fn is_prime_test() {
559 let pb = NaiveBuffer::new();
561
562 assert_eq!(pb.is_prime(&(2u32.pow(19) - 1), None), Primality::Yes);
564 assert_eq!(pb.is_prime(&(2u32.pow(23) - 1), None), Primality::No);
565 assert!(matches!(
566 pb.is_prime(&(2u128.pow(89) - 1), None),
567 Primality::Probable(_)
568 ));
569 assert!(matches!(
570 pb.is_prime(&SmallMint::from(2u128.pow(89) - 1), None),
571 Primality::Probable(_)
572 ));
573
574 for _ in 0..100 {
576 let target = random::<u64>();
577 assert_eq!(
578 !is_prime64(target),
579 matches!(
580 pb.is_prime(&target, Some(PrimalityTestConfig::bpsw())),
581 Primality::No
582 )
583 );
584 }
585
586 const P: u128 = 18_699_199_384_836_356_663; assert!(matches!(pb.is_prime(&P, None), Primality::Probable(_)));
589 assert!(matches!(
590 pb.is_prime(&P, Some(PrimalityTestConfig::bpsw())),
591 Primality::Probable(_)
592 ));
593 assert!(matches!(
594 pb.is_prime(&SmallMint::from(P), None),
595 Primality::Probable(_)
596 ));
597 assert!(matches!(
598 pb.is_prime(&SmallMint::from(P), Some(PrimalityTestConfig::bpsw())),
599 Primality::Probable(_)
600 ));
601
602 const P2: u128 = 2_019_922_777_445_599_503_530_083;
603 assert!(matches!(pb.is_prime(&P2, None), Primality::Probable(_)));
604 assert!(matches!(
605 pb.is_prime(&P2, Some(PrimalityTestConfig::bpsw())),
606 Primality::Probable(_)
607 ));
608 assert!(matches!(
609 pb.is_prime(&SmallMint::from(P2), None),
610 Primality::Probable(_)
611 ));
612 assert!(matches!(
613 pb.is_prime(&SmallMint::from(P2), Some(PrimalityTestConfig::bpsw())),
614 Primality::Probable(_)
615 ));
616
617 #[cfg(feature = "num-bigint")]
618 {
619 let large_primes = [
620 "98920366548084643601728869055592650835572950932266967461790948584315647051443",
621 "94560208308847015747498523884063394671606671904944666360068158221458669711639",
622
623 "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
625 "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
626 "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
627 "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
628 "3618502788666131106986593281521497120414687020801267626233049500247285301239", "57896044618658097711785492504343953926634992332820282019728792003956564819949", "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", "169511182982703321453314585423962898651587669459838234386506572286328885534468792292646838949809616446341407457141008401355628947670484184607678853094537849610289912805960069455687743151708433319901176932959509872662610091644590437761688516626993416011399330087939042347256922771590903190536793274742859624657"
637 ];
638 for pstr in large_primes {
639 assert!(
640 pb.is_prime(&BigUint::from_str(pstr).unwrap(), None)
641 .probably(),
642 "false negative prime {}",
643 pstr
644 )
645 }
646
647 let large_composites = [
648 "21284175091214687912771199898307297748211672914763848041968395774954376176754",
649 "6084766654921918907427900243509372380954290099172559290432744450051395395951",
650 "84594350493221918389213352992032324280367711247940675652888030554255915464401",
651 "82793403787388584738507275144194252681",
652
653 "1195068768795265792518361315725116351898245581", "8038374574536394912570796143419421081388376882875581458374889175222974273765333652186502336163960045457915042023603208766569966760987284043965408232928738791850869166857328267761771029389697739470167082304286871099974399765441448453411558724506334092790222752962294149842306881685404326457534018329786111298960644845216191652872597534901",
658 ];
659 for cstr in large_composites {
660 assert!(
661 !pb.is_prime(
662 &BigUint::from_str(cstr).unwrap(),
663 Some(PrimalityTestConfig::bpsw())
664 )
665 .probably(),
666 "false positive prime {}",
667 cstr
668 )
669 }
670 }
671 }
672
673 #[test]
674 fn pb_factors_test() {
675 #[cfg(feature = "num-bigint")]
676 {
677 let pb = NaiveBuffer::new();
678 let m131 = BigUint::from(2u8).pow(131) - 1u8; let (fac, r) = pb.factors(m131, None);
680 assert!(fac.len() == 2 && r.is_none());
681 }
682 }
683
684 #[test]
686 fn test_clear_and_re_reserve() {
687 let mut pb = NaiveBuffer::new();
688 pb.reserve(100);
689 assert!(pb.bound() >= 100);
690 assert!(pb.contains(97));
691 pb.clear();
692 assert_eq!(pb.bound(), 53);
694 assert!(!pb.contains(97)); pb.reserve(100);
697 assert!(pb.bound() >= 100);
698 assert!(pb.contains(97));
699 }
700
701 #[test]
703 fn test_into_primes() {
704 let pb = NaiveBuffer::new();
705 let primes: Vec<u64> = pb.into_primes(20).collect();
706 assert_eq!(primes, vec![2, 3, 5, 7, 11, 13, 17, 19]);
707 }
708
709 #[test]
710 fn test_into_primes_exact_boundary() {
711 let pb = NaiveBuffer::new();
712 let primes: Vec<u64> = pb.into_primes(23).collect();
714 assert_eq!(*primes.last().unwrap(), 23);
715 }
716
717 #[test]
719 fn test_into_nprimes() {
720 let pb = NaiveBuffer::new();
721 let primes: Vec<u64> = pb.into_nprimes(10).collect();
722 assert_eq!(primes.len(), 10);
723 assert_eq!(primes[0], 2);
724 assert_eq!(primes[9], 29);
725 }
726
727 #[test]
729 fn test_primorial() {
730 let mut pb = NaiveBuffer::new();
731 let result: u64 = pb.primorial(4);
733 assert_eq!(result, 210);
734 let result: u64 = pb.primorial(1);
736 assert_eq!(result, 2);
737 }
738
739 #[test]
741 fn test_is_prime_eslprp_config() {
742 let pb = NaiveBuffer::new();
743 let config = PrimalityTestConfig {
744 sprp_trials: 1,
745 sprp_random_trials: 0,
746 slprp_test: false,
747 eslprp_test: true,
748 };
749 let p: u128 = 18_699_199_384_836_356_663;
750 assert!(pb.is_prime(&p, Some(config)).probably());
751 }
752
753 #[test]
755 fn test_is_prime_strict_config() {
756 let pb = NaiveBuffer::new();
757 let p: u128 = 2_019_922_777_445_599_503_530_083;
758 assert!(pb
759 .is_prime(&p, Some(PrimalityTestConfig::strict()))
760 .probably());
761
762 let c: u128 = 2_019_922_777_445_599_503_530_083 * 3;
764 assert!(!pb
765 .is_prime(&c, Some(PrimalityTestConfig::strict()))
766 .probably());
767 }
768
769 #[test]
771 fn test_factors_u128() {
772 let pb = NaiveBuffer::new();
773 let (factors, remainder) = pb.factors(360u128, None);
775 assert!(remainder.is_none());
776 assert_eq!(factors[&2], 3);
777 assert_eq!(factors[&3], 2);
778 assert_eq!(factors[&5], 1);
779 }
780
781 #[test]
782 fn test_factors_u128_large() {
783 let pb = NaiveBuffer::new();
784 let n: u128 = (1u128 << 64) + 1;
786 let (factors, remainder) = pb.factors(n, None);
787 assert!(remainder.is_none());
788 assert!(factors.contains_key(&274177u128));
789 }
790
791 #[test]
793 fn test_is_prime_even() {
794 let pb = NaiveBuffer::new();
795 assert_eq!(pb.is_prime(&2u128, None), Primality::Yes);
796 assert_eq!(pb.is_prime(&4u128, None), Primality::No);
797 }
798
799 #[test]
801 fn test_factors_with_strict_config() {
802 let pb = NaiveBuffer::new();
803 let (factors, remainder) = pb.factors(100u64, Some(FactorizationConfig::strict()));
804 assert!(remainder.is_none());
805 assert_eq!(factors[&2], 2);
806 assert_eq!(factors[&5], 2);
807 }
808}