Skip to main content

primefactor/
lib.rs

1//! Module for factorizing integers
2#![deny(unsafe_code)]
3pub mod candidates;
4
5use std::cmp::{min, Ordering};
6use std::fmt;
7use candidates::PrimeWheel210 as PrimeWheel;
8use candidates::{is_prime_candidate, miller_rabin};
9
10/// The threshold where Miller-Rabin primality checking becomes faster than
11/// naive trial division. Below this limit, testing wheel candidates up to
12/// the square root takes fewer CPU cycles than MR's modulus exponentiations.
13const MR_TRIAL_DIVISION_CROSSOVER: u128 = 10_000_000;
14
15/// The threshold below which our specific 12-base Miller-Rabin test is
16/// mathematically proven to be 100% accurate (no false positives).
17/// Above this limit, MR operates probabilistically and needs fallback verification.
18const MR_DETERMINISTIC_LIMIT: u128 = 3_317_044_064_679_887_385_961_981;
19
20/// A prime factor with its exponent (e.g., 2^3 means integer=2, exponent=3).
21#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
22pub struct IntFactor {
23    pub integer: u128,
24    pub exponent: u32,
25}
26
27impl IntFactor {
28    #[must_use]
29    pub fn to_vec(&self) -> Vec<u128> {
30        vec![self.integer; self.exponent as usize]
31    }
32}
33
34impl fmt::Display for IntFactor {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        if self.exponent > 1 {
37            write!(f, "{}^{}", self.integer, self.exponent)
38        } else {
39            write!(f, "{}", self.integer)
40        }
41    }
42}
43
44/// The prime factorization of an integer, represented as a list of
45/// prime factors with their exponents.
46#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
47pub struct PrimeFactors {
48    factors: Vec<IntFactor>
49}
50
51impl PrimeFactors {
52    fn new() -> Self {
53        PrimeFactors { factors: Vec::with_capacity(8) }
54    }
55    fn add(&mut self, integer: u128, exponent: u32) {
56        self.factors.push(IntFactor { integer, exponent })
57    }
58    /// Reconstruct the original integer from its prime factorization.
59    /// An empty factorization yields 1 (the empty product).
60    #[must_use]
61    pub fn value(&self) -> u128 {
62        self.factors.iter().map(|f| f.integer.pow(f.exponent)).product()
63    }
64    /// Return the number of distinct prime factors.
65    #[must_use]
66    pub fn len(&self) -> usize {
67        self.factors.len()
68    }
69    /// Return the total number of prime factors (counting multiplicities).
70    #[must_use]
71    pub fn count_factors(&self) -> u32 {
72        self.factors.iter().map(|f| f.exponent).sum()
73    }
74    #[must_use]
75    pub fn is_empty(&self) -> bool {
76        self.factors.is_empty()
77    }
78    #[must_use]
79    pub fn is_prime(&self) -> bool {
80        self.count_factors() == 1
81    }
82    /// Return a slice of the prime factors with exponents.
83    #[must_use]
84    pub fn factors(&self) -> &[IntFactor] {
85        &self.factors
86    }
87    /// Expand the factorization into a flat vector of prime factors.
88    #[must_use]
89    pub fn to_vec(&self) -> Vec<u128> {
90        self.factors.iter().flat_map(IntFactor::to_vec).collect()
91    }
92    /// Compute the GCD of two prime factorizations by intersecting common factors.
93    /// Returns an empty result if either factorization is empty.
94    #[must_use]
95    pub fn gcd(&self, other: &PrimeFactors) -> PrimeFactors {
96        let mut pf = PrimeFactors::new();
97        if self.is_empty() || other.is_empty() { return pf; }
98        let mut s_it = self.factors.iter();
99        let mut o_it = other.factors.iter();
100        let mut s = s_it.next().unwrap();
101        let mut o = o_it.next().unwrap();
102        loop {
103            match s.integer.cmp(&o.integer) {
104                Ordering::Equal => {
105                    pf.add(s.integer, min(o.exponent, s.exponent));
106                    s = match s_it.next() { Some(n) => n, None => break };
107                    o = match o_it.next() { Some(n) => n, None => break };
108                }
109                Ordering::Less => {
110                    s = match s_it.next() { Some(n) => n, None => break };
111                }
112                Ordering::Greater => {
113                    o = match o_it.next() { Some(n) => n, None => break };
114                }
115            }
116        }
117        pf
118    }
119    /// Check if n has any non-trivial factor using wheel factorization.
120    /// Returns true as soon as any factor is found, without full decomposition.
121    #[must_use]
122    pub fn has_any_factor(n: u128) -> bool {
123        if n < 4 { return false; }
124        let pw_iter = PrimeWheel::new();
125        for f in pw_iter {
126            if f * f > n {
127                return false;
128            }
129            if n.is_multiple_of(f) {
130                return true;
131            }
132        }
133        false
134    }
135    /// Compute the prime factorization of n using wheel factorization.
136    #[must_use]
137    pub fn factorize(n: u128) -> Self {
138        // If the number is large, we enable the Miller-Rabin fast paths
139        if n > MR_TRIAL_DIVISION_CROSSOVER {
140            Self::factorize_large(n)
141        } else {
142            // Hot path for small numbers: 100% pure trial division, no MR overhead
143            Self::factorize_small(n)
144        }
145    }
146    #[inline]
147    fn factorize_large(n: u128) -> Self {
148        let mut pf = PrimeFactors::new();
149        if n < 2 { return pf; }
150        let mut maxsq = n;
151        let mut x = n;
152        // --- 1. EARLY EXIT FOR PRIMES ---
153        if u128_is_prime(n) {
154            pf.add(n, 1);
155            return pf;
156        }
157        let pw_iter = PrimeWheel::new();
158        for f in pw_iter {
159            if f * f > maxsq { break; }
160            let mut c = 0;
161            while x.is_multiple_of(f) {
162                x /= f;
163                c += 1;
164            }
165            if c > 0 {
166                maxsq = x;
167                pf.add(f, c);
168                // --- 2. EARLY EXIT FOR INTERMEDIATE CHUNKS ---
169                if x > MR_TRIAL_DIVISION_CROSSOVER && u128_is_prime(x) {
170                    pf.add(x, 1);
171                    x = 1;
172                    break;
173                }
174            }
175            if x == 1 { break; }
176        }
177        if x > 1 {
178            pf.add(x, 1);
179        }
180        pf
181    }
182    #[inline]
183    fn factorize_small(n: u128) -> Self {
184        let mut pf = PrimeFactors::new();
185        if n < 2 { return pf; }
186        let mut maxsq = n;
187        let mut x = n;
188        let pw_iter = PrimeWheel::new();
189        for f in pw_iter {
190            if f * f > maxsq { break; }
191            let mut c = 0;
192            while x.is_multiple_of(f) {
193                x /= f;
194                c += 1;
195            }
196            if c > 0 {
197                maxsq = x;
198                pf.add(f, c);
199            }
200            if x == 1 { break; }
201        }
202        if x > 1 {
203            pf.add(x, 1);
204        }
205        pf
206    }
207}
208
209impl fmt::Display for PrimeFactors {
210    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211        for (i, factor) in self.factors.iter().enumerate() {
212            if i > 0 {
213                f.write_str(" * ")?;
214            }
215            write!(f, "{factor}")?;
216        }
217        Ok(())
218    }
219}
220
221/// Iterate over the prime factors with their exponents.
222impl<'a> IntoIterator for &'a PrimeFactors {
223    type Item = &'a IntFactor;
224    type IntoIter = std::slice::Iter<'a, IntFactor>;
225
226    fn into_iter(self) -> Self::IntoIter {
227        self.factors.iter()
228    }
229}
230
231/// Consume and iterate over the prime factors with their exponents.
232impl IntoIterator for PrimeFactors {
233    type Item = IntFactor;
234    type IntoIter = std::vec::IntoIter<IntFactor>;
235
236    fn into_iter(self) -> Self::IntoIter {
237        self.factors.into_iter()
238    }
239}
240
241/// An iterator that yields prime numbers in ascending order.
242/// Uses wheel factorization to generate candidates, filtering
243/// with Miller-Rabin (when available) for fast primality testing.
244#[derive(Clone, Debug)]
245pub struct PrimeNumbers {
246    wheel: PrimeWheel,
247}
248
249impl PrimeNumbers {
250    #[must_use]
251    pub fn new() -> Self {
252        Self { wheel: PrimeWheel::new() }
253    }
254    /// Create an iterator that yields primes >= `start`.
255    #[must_use]
256    pub fn from(start: u128) -> Self {
257        Self { wheel: PrimeWheel::from(start) }
258    }
259}
260
261impl Default for PrimeNumbers {
262    fn default() -> Self {
263        Self::new()
264    }
265}
266
267impl Iterator for PrimeNumbers {
268    type Item = u128;
269
270    fn next(&mut self) -> Option<Self::Item> {
271        self.wheel.by_ref().find(|&n| u128_is_prime(n))
272    }
273}
274
275/// An iterator that yields prime numbers in descending order.
276/// Uses wheel factorization to traverse candidates backwards, filtering
277/// with Miller-Rabin (when available) for fast primality testing.
278#[derive(Clone, Debug)]
279pub struct DescendingPrimes {
280    wheel: PrimeWheel,
281}
282
283impl DescendingPrimes {
284    /// Create an iterator that yields primes `<= start`.
285    #[must_use]
286    pub fn from(start: u128) -> Self {
287        Self { wheel: PrimeWheel::from(start.saturating_add(1)) }
288    }
289}
290
291impl Iterator for DescendingPrimes {
292    type Item = u128;
293
294    fn next(&mut self) -> Option<Self::Item> {
295        loop {
296            let candidate = self.wheel.prev()?;
297            if u128_is_prime(candidate) {
298                return Some(candidate);
299            }
300        }
301    }
302}
303
304/// Test if the value is a prime number.
305///
306/// Uses deterministic Miller-Rabin for numbers below `MR_DETERMINISTIC_LIMIT`
307/// (proven correct). For larger values, Miller-Rabin is used as a fast composite
308/// filter (it has no false negatives), and any candidate that passes is verified
309/// via trial-division factorization — guaranteeing correctness for all u128.
310///
311/// Note: for very large primes (above the Miller-Rabin threshold), the
312/// factorization fallback may be slow.
313#[must_use]
314pub fn u128_is_prime(n: u128) -> bool {
315    if !is_prime_candidate(n) { return false; }
316    // Trial division by subsequent small primes. Even though the wheel
317    // filters out multiples of 2, 3, 5, and 7, remaining composites are
318    // heavily stripped out by small integer division before hitting the 
319    // much slower Miller-Rabin steps.
320    const SMALL_PRIMES: &[u128] = &[
321        11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
322    ];
323    for &p in SMALL_PRIMES {
324        if n == p { return true; }
325        if n.is_multiple_of(p) { return false; }
326    }
327    if n < MR_DETERMINISTIC_LIMIT {
328        return miller_rabin(n);
329    }
330    // MR has no false negatives: if it says composite, it is composite.
331    if !miller_rabin(n) { return false; }
332    // Verify with guaranteed-correct trial division: if any factor
333    // exists, n is composite. Stops at the first factor found.
334    !PrimeFactors::has_any_factor(n)
335}
336
337/// Return the smallest prime >= n.
338///
339/// Uses the [`PrimeNumbers`] iterator starting from `n`.
340#[must_use]
341pub fn next_prime(n: u128) -> u128 {
342    PrimeNumbers::from(n).next().unwrap()
343}
344
345/// Return the largest prime <= n.
346///
347/// Uses the [`DescendingPrimes`] iterator starting from `n` and moving backwards.
348#[must_use]
349pub fn prev_prime(n: u128) -> Option<u128> {
350    if n < 2 {
351        return None;
352    }
353    DescendingPrimes::from(n).next()
354}
355
356/// Calculate the Greatest common divisor (GCD) between 2 unsigned integers,
357/// returned as a prime factorization.
358///
359/// Handles the identity gcd(0, n) = n by returning the other value's
360/// factorization. Since gcd(0, 0) = 0 has no prime factorization, it
361/// returns an empty result. For a simpler numeric GCD, use [`u128_gcd`].
362#[must_use]
363pub fn primefactor_gcd(this: u128, that: u128) -> PrimeFactors {
364    if this == 0 {
365        return PrimeFactors::factorize(that);
366    }
367    if that == 0 {
368        return PrimeFactors::factorize(this);
369    }
370    let pf_this = PrimeFactors::factorize(this);
371    let pf_that = PrimeFactors::factorize(that);
372    pf_this.gcd(&pf_that)
373}
374
375/// Calculate the Greatest common divisor (GCD) between 2 unsigned integers.
376/// Based on Euclid's algorithm pseudo code at:
377/// <https://en.wikipedia.org/wiki/Euclidean_algorithm>
378#[must_use]
379pub fn u128_gcd(this: u128, that: u128) -> u128 {
380    let mut a = this;
381    let mut b = that;
382    while b > 0 {
383        let c = b;
384        b = a % b;
385        a = c;
386    }
387    a
388}
389
390/// Calculate the Least common multiple (LCM) for 2 integers.
391#[must_use]
392pub fn u128_lcm(this: u128, that: u128) -> u128 {
393    checked_u128_lcm(this, that).expect("u128_lcm overflow")
394}
395
396#[must_use]
397pub fn checked_u128_lcm(this: u128, that: u128) -> Option<u128> {
398    if this == 0 || that == 0 {
399        return Some(0);
400    }
401    let gcd = u128_gcd(this, that);
402    (this / gcd).checked_mul(that)
403}