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/// A prime factor with its exponent (e.g., 2^3 means integer=2, exponent=3).
11#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
12pub struct IntFactor {
13    pub integer: u128,
14    pub exponent: u32,
15}
16
17impl IntFactor {
18    #[must_use]
19    pub fn to_vec(&self) -> Vec<u128> {
20        vec![self.integer; self.exponent as usize]
21    }
22}
23
24impl fmt::Display for IntFactor {
25    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26        if self.exponent > 1 {
27            write!(f, "{}^{}", self.integer, self.exponent)
28        } else {
29            write!(f, "{}", self.integer)
30        }
31    }
32}
33
34/// The prime factorization of an integer, represented as a list of
35/// prime factors with their exponents.
36#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
37pub struct PrimeFactors {
38    factors: Vec<IntFactor>
39}
40
41impl PrimeFactors {
42    fn new() -> Self {
43        PrimeFactors { factors: Vec::with_capacity(8) }
44    }
45    fn add(&mut self, integer: u128, exponent: u32) {
46        self.factors.push(IntFactor { integer, exponent })
47    }
48    /// Reconstruct the original integer from its prime factorization.
49    /// An empty factorization yields 1 (the empty product).
50    #[must_use]
51    pub fn value(&self) -> u128 {
52        self.factors.iter().map(|f| f.integer.pow(f.exponent)).product()
53    }
54    /// Return the number of distinct prime factors.
55    #[must_use]
56    pub fn len(&self) -> usize {
57        self.factors.len()
58    }
59    /// Return the total number of prime factors (counting multiplicities).
60    #[must_use]
61    pub fn count_factors(&self) -> u32 {
62        self.factors.iter().map(|f| f.exponent).sum()
63    }
64    #[must_use]
65    pub fn is_empty(&self) -> bool {
66        self.factors.is_empty()
67    }
68    #[must_use]
69    pub fn is_prime(&self) -> bool {
70        self.count_factors() == 1
71    }
72    /// Return a slice of the prime factors with exponents.
73    #[must_use]
74    pub fn factors(&self) -> &[IntFactor] {
75        &self.factors
76    }
77    /// Expand the factorization into a flat vector of prime factors.
78    #[must_use]
79    pub fn to_vec(&self) -> Vec<u128> {
80        self.factors.iter().flat_map(IntFactor::to_vec).collect()
81    }
82    /// Compute the GCD of two prime factorizations by intersecting common factors.
83    /// Returns an empty result if either factorization is empty.
84    #[must_use]
85    pub fn gcd(&self, other: &PrimeFactors) -> PrimeFactors {
86        let mut pf = PrimeFactors::new();
87        if self.is_empty() || other.is_empty() { return pf; }
88        let mut s_it = self.factors.iter();
89        let mut o_it = other.factors.iter();
90        let mut s = s_it.next().unwrap();
91        let mut o = o_it.next().unwrap();
92        loop {
93            match s.integer.cmp(&o.integer) {
94                Ordering::Equal => {
95                    pf.add(s.integer, min(o.exponent, s.exponent));
96                    s = match s_it.next() { Some(n) => n, None => break };
97                    o = match o_it.next() { Some(n) => n, None => break };
98                }
99                Ordering::Less => {
100                    s = match s_it.next() { Some(n) => n, None => break };
101                }
102                Ordering::Greater => {
103                    o = match o_it.next() { Some(n) => n, None => break };
104                }
105            }
106        }
107        pf
108    }
109    /// Check if n has any non-trivial factor using wheel factorization.
110    /// Returns true as soon as any factor is found, without full decomposition.
111    #[must_use]
112    pub fn has_any_factor(n: u128) -> bool {
113        if n < 4 { return false; }
114        let pw_iter = PrimeWheel::new();
115        for f in pw_iter {
116            if f * f > n {
117                return false;
118            }
119            if n.is_multiple_of(f) {
120                return true;
121            }
122        }
123        false
124    }
125    /// Compute the prime factorization of n using wheel factorization.
126    #[must_use]
127    pub fn factorize(n: u128) -> Self {
128        let mut pf = PrimeFactors::new();
129        if n < 2 { return pf; }
130        // The smallest prime factor of n must be <= sqrt(n)
131        let mut maxsq = n;
132        let mut x = n;
133        let pw_iter = PrimeWheel::new();
134        for f in pw_iter {
135            if f * f > maxsq {
136                break;
137            }
138            let mut c = 0;
139            while x.is_multiple_of(f) {
140                x /= f;
141                c += 1;
142            }
143            if c > 0 {
144                // The smallest prime factor of x must be <= sqrt(x)
145                maxsq = x;
146                pf.add(f, c);
147            }
148            if x == 1 {
149                break;
150            }
151        }
152        if x > 1 || pf.is_empty() {
153            // Any remainder x > 1 must itself be prime.
154            pf.add(x, 1);
155        }
156        pf
157    }
158}
159
160impl fmt::Display for PrimeFactors {
161    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162        let parts: Vec<_> = self.factors.iter()
163            .map(|f| f.to_string())
164            .collect();
165        write!(f, "{}", parts.join(" * "))
166    }
167}
168
169/// Iterate over the prime factors with their exponents.
170impl<'a> IntoIterator for &'a PrimeFactors {
171    type Item = &'a IntFactor;
172    type IntoIter = std::slice::Iter<'a, IntFactor>;
173
174    fn into_iter(self) -> Self::IntoIter {
175        self.factors.iter()
176    }
177}
178
179/// Consume and iterate over the prime factors with their exponents.
180impl IntoIterator for PrimeFactors {
181    type Item = IntFactor;
182    type IntoIter = std::vec::IntoIter<IntFactor>;
183
184    fn into_iter(self) -> Self::IntoIter {
185        self.factors.into_iter()
186    }
187}
188
189/// An iterator that yields prime numbers in ascending order.
190/// Uses wheel factorization to generate candidates, filtering
191/// with Miller-Rabin (when available) for fast primality testing.
192#[derive(Clone, Debug)]
193pub struct PrimeNumbers {
194    wheel: PrimeWheel,
195}
196
197impl PrimeNumbers {
198    #[must_use]
199    pub fn new() -> Self {
200        Self { wheel: PrimeWheel::new() }
201    }
202    /// Create an iterator that yields primes >= `start`.
203    #[must_use]
204    pub fn from(start: u128) -> Self {
205        Self { wheel: PrimeWheel::from(start) }
206    }
207}
208
209impl Default for PrimeNumbers {
210    fn default() -> Self {
211        Self::new()
212    }
213}
214
215impl Iterator for PrimeNumbers {
216    type Item = u128;
217
218    fn next(&mut self) -> Option<Self::Item> {
219        self.wheel.by_ref().find(|&n| u128_is_prime(n))
220    }
221}
222
223/// Test if the value is a prime number.
224///
225/// Uses deterministic Miller-Rabin for numbers below 3,317,044,064,679,887,385,961,981
226/// (proven correct). For larger values, Miller-Rabin is used as a fast composite
227/// filter (it has no false negatives), and any candidate that passes is verified
228/// via trial-division factorization — guaranteeing correctness for all u128.
229///
230/// Note: for very large primes (above the Miller-Rabin threshold), the
231/// factorization fallback may be slow.
232#[must_use]
233pub fn u128_is_prime(n: u128) -> bool {
234    if !is_prime_candidate(n) { return false; }
235    if n < 3_317_044_064_679_887_385_961_981 {
236        return miller_rabin(n);
237    }
238    // MR has no false negatives: if it says composite, it is composite.
239    if !miller_rabin(n) { return false; }
240    // Verify with guaranteed-correct trial division: if any factor
241    // exists, n is composite. Stops at the first factor found.
242    !PrimeFactors::has_any_factor(n)
243}
244
245/// Return the smallest prime >= n.
246///
247/// Uses the [`PrimeNumbers`] iterator starting from `n`.
248#[must_use]
249pub fn next_prime(n: u128) -> u128 {
250    PrimeNumbers::from(n).next().unwrap()
251}
252
253/// Calculate the Greatest common divisor (GCD) between 2 unsigned integers,
254/// returned as a prime factorization.
255///
256/// Handles the identity gcd(0, n) = n by returning the other value's
257/// factorization. Since gcd(0, 0) = 0 has no prime factorization, it
258/// returns an empty result. For a simpler numeric GCD, use [`u128_gcd`].
259#[must_use]
260pub fn primefactor_gcd(this: u128, that: u128) -> PrimeFactors {
261    if this == 0 {
262        return PrimeFactors::factorize(that);
263    }
264    if that == 0 {
265        return PrimeFactors::factorize(this);
266    }
267    let pf_this = PrimeFactors::factorize(this);
268    let pf_that = PrimeFactors::factorize(that);
269    pf_this.gcd(&pf_that)
270}
271
272/// Calculate the Greatest common divisor (GCD) between 2 unsigned integers.
273/// Based on Euclid's algorithm pseudo code at:
274/// <https://en.wikipedia.org/wiki/Euclidean_algorithm>
275#[must_use]
276pub fn u128_gcd(this: u128, that: u128) -> u128 {
277    let mut a = this;
278    let mut b = that;
279    while b > 0 {
280        let c = b;
281        b = a % b;
282        a = c;
283    }
284    a
285}
286
287/// Calculate the Least common multiple (LCM) for 2 integers.
288#[must_use]
289pub fn u128_lcm(this: u128, that: u128) -> u128 {
290    checked_u128_lcm(this, that).expect("u128_lcm overflow")
291}
292
293#[must_use]
294pub fn checked_u128_lcm(this: u128, that: u128) -> Option<u128> {
295    if this == 0 || that == 0 {
296        return Some(0);
297    }
298    let gcd = u128_gcd(this, that);
299    (this / gcd).checked_mul(that)
300}