/// Prime Factorization: trial division + Pollard's rho concept.
/// Trial division handles small factors; Pollard's rho concept for large n.
/// GCD (Euclidean) โ mirrors OCaml's elegant one-liner.
fn gcd(a: u64, b: u64) -> u64 {
if b == 0 { a } else { gcd(b, a % b) }
}
/// Trial division: returns sorted list of (prime, exponent) pairs.
fn factorize(mut n: u64) -> Vec<(u64, u32)> {
let mut factors = Vec::new();
// Factor out 2
if n % 2 == 0 {
let mut exp = 0u32;
while n % 2 == 0 { exp += 1; n /= 2; }
factors.push((2, exp));
}
// Odd factors from 3
let mut d = 3u64;
while d * d <= n {
if n % d == 0 {
let mut exp = 0u32;
while n % d == 0 { exp += 1; n /= d; }
factors.push((d, exp));
}
d += 2;
}
if n > 1 {
factors.push((n, 1));
}
factors
}
/// Pollard's rho: find a non-trivial factor of n (n composite, n > 1).
/// Uses Floyd's cycle detection with f(x) = (xยฒ + c) mod n.
fn pollard_rho(n: u64) -> u64 {
if n % 2 == 0 {
return 2;
}
let mut c = 1u64;
loop {
let mut x = 2u64;
let mut y = 2u64;
let mut d = 1u64;
while d == 1 {
x = (x.wrapping_mul(x).wrapping_add(c)) % n;
y = (y.wrapping_mul(y).wrapping_add(c)) % n;
y = (y.wrapping_mul(y).wrapping_add(c)) % n;
d = gcd(x.abs_diff(y), n);
}
if d != n {
return d;
}
c += 1; // Retry
}
}
/// Miller-Rabin primality (simple version for testing in Pollard context).
fn is_prime_trial(n: u64) -> bool {
if n < 2 { return false; }
if n == 2 { return true; }
if n % 2 == 0 { return false; }
let mut d = 3u64;
while d * d <= n {
if n % d == 0 { return false; }
d += 2;
}
true
}
/// Full factorization using Pollard's rho for large primes.
fn factorize_full(n: u64) -> Vec<u64> {
if n <= 1 { return vec![]; }
if is_prime_trial(n) { return vec![n]; }
let d = pollard_rho(n);
let mut a = factorize_full(d);
let mut b = factorize_full(n / d);
a.append(&mut b);
a.sort();
a
}
fn format_factors(factors: &[(u64, u32)]) -> String {
factors
.iter()
.map(|&(p, e)| if e == 1 { format!("{p}") } else { format!("{p}^{e}") })
.collect::<Vec<_>>()
.join(" ร ")
}
fn main() {
let tests = [12u64, 100, 360, 97, 1_234_567_890, 720_720];
for &n in &tests {
let f = factorize(n);
println!("factorize({n}) = {}", format_factors(&f));
}
println!("\nPollard rho examples:");
for &n in &[15u64, 35, 77, 8051, 1_000_003 * 1_000_033] {
let factors = factorize_full(n);
println!(" {n} = {:?}", factors);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_factorize_12() {
assert_eq!(factorize(12), vec![(2, 2), (3, 1)]);
}
#[test]
fn test_factorize_100() {
assert_eq!(factorize(100), vec![(2, 2), (5, 2)]);
}
#[test]
fn test_factorize_prime() {
assert_eq!(factorize(97), vec![(97, 1)]);
}
#[test]
fn test_factorize_1() {
assert_eq!(factorize(1), vec![]);
}
#[test]
fn test_factorize_360() {
// 360 = 2ยณ ร 3ยฒ ร 5
assert_eq!(factorize(360), vec![(2, 3), (3, 2), (5, 1)]);
}
#[test]
fn test_product_check() {
// Verify factors multiply back to original
for &n in &[12u64, 100, 360, 720720] {
let factors = factorize(n);
let product: u64 = factors.iter().map(|&(p, e)| p.pow(e)).product();
assert_eq!(product, n, "product mismatch for {n}");
}
}
#[test]
fn test_pollard_finds_factor() {
// 35 = 5 ร 7
let d = pollard_rho(35);
assert!(d == 5 || d == 7);
}
#[test]
fn test_is_prime_trial() {
assert!(is_prime_trial(97));
assert!(!is_prime_trial(100));
assert!(is_prime_trial(2));
}
}
(* Prime Factorization in OCaml โ trial division + Pollard rho concept *)
(* GCD โ the elegant one-liner *)
let rec gcd a b = if b = 0 then a else gcd b (a mod b)
(* Trial division factorization *)
let factorize (n : int) : (int * int) list =
let factors = ref [] in
let n = ref n in
(* Handle factor 2 separately *)
let cnt = ref 0 in
while !n mod 2 = 0 do
incr cnt; n := !n / 2
done;
if !cnt > 0 then factors := (2, !cnt) :: !factors;
(* Odd factors from 3 to sqrt(n) *)
let d = ref 3 in
while !d * !d <= !n do
cnt := 0;
while !n mod !d = 0 do
incr cnt; n := !n / !d
done;
if !cnt > 0 then factors := (!d, !cnt) :: !factors;
d := !d + 2
done;
(* Remaining factor is prime *)
if !n > 1 then factors := (!n, 1) :: !factors;
List.rev !factors
(* Pollard's rho: find a non-trivial factor of n (n must be composite) *)
let pollard_rho (n : int) : int =
if n mod 2 = 0 then 2
else begin
let x = ref 2 and y = ref 2 and c = ref 1 and d = ref 1 in
while !d = 1 do
x := (!x * !x + !c) mod n;
y := (!y * !y + !c) mod n;
y := (!y * !y + !c) mod n;
d := gcd (abs (!x - !y)) n;
if !d = n then begin
(* Retry with different c *)
c := !c + 1; x := 2; y := 2; d := 1
end
done;
!d
end
(* Pretty-print factorization *)
let pp_factors factors =
String.concat " ร " (List.map (fun (p, e) ->
if e = 1 then string_of_int p
else Printf.sprintf "%d^%d" p e
) factors)
let () =
let tests = [12; 100; 360; 97; 1234567890; 720720] in
List.iter (fun n ->
let f = factorize n in
Printf.printf "factorize(%d) = %s\n" n (pp_factors f)
) tests;
(* Verify: product should equal n *)
let n = 360 in
let f = factorize n in
let product = List.fold_left (fun acc (p, e) ->
let rec pow b e = if e = 0 then 1 else b * pow b (e-1) in
acc * pow p e
) 1 f in
Printf.printf "product check: %d = %d โ %b\n" n product (n = product)