qualia_core_db/solvers/number_theory/
primes.rs1use super::modular::mod_pow;
8
9#[inline]
10fn mulmod(a: u64, b: u64, m: u64) -> u64 {
11 ((a as u128 * b as u128) % m as u128) as u64
12}
13
14pub fn is_prime(n: u64) -> bool {
16 if n < 2 {
17 return false;
18 }
19 for &p in &[2u64, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] {
20 if n == p {
21 return true;
22 }
23 if n % p == 0 {
24 return false;
25 }
26 }
27 let mut d = n - 1;
29 let mut r = 0u32;
30 while d & 1 == 0 {
31 d >>= 1;
32 r += 1;
33 }
34 'witness: for &a in &[2u64, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] {
35 let mut x = mod_pow(a, d, n);
36 if x == 1 || x == n - 1 {
37 continue;
38 }
39 for _ in 0..r - 1 {
40 x = mulmod(x, x, n);
41 if x == n - 1 {
42 continue 'witness;
43 }
44 }
45 return false; }
47 true
48}
49
50pub fn next_prime(n: u64) -> u64 {
52 let mut c = n.saturating_add(1);
53 if c <= 2 {
54 return 2;
55 }
56 if c % 2 == 0 {
57 c += 1;
58 }
59 loop {
60 if is_prime(c) {
61 return c;
62 }
63 c = c.saturating_add(2);
64 }
65}
66
67fn pollard_rho(n: u64) -> u64 {
69 if n % 2 == 0 {
70 return 2;
71 }
72 let mut c = 1u64;
73 loop {
74 let f = |x: u64| (mulmod(x, x, n) + c) % n;
75 let mut x = 2u64;
76 let mut y = 2u64;
77 let mut d = 1u64;
78 while d == 1 {
79 x = f(x);
80 y = f(f(y));
81 d = super::modular::gcd(x.abs_diff(y), n);
82 }
83 if d != n {
84 return d;
85 }
86 c += 1; }
88}
89
90fn factor_into(n: u64, out: &mut Vec<u64>) {
91 if n == 1 {
92 return;
93 }
94 if is_prime(n) {
95 out.push(n);
96 return;
97 }
98 let d = pollard_rho(n);
99 factor_into(d, out);
100 factor_into(n / d, out);
101}
102
103pub fn prime_factors(n: u64) -> Vec<(u64, u32)> {
106 if n < 2 {
107 return Vec::new();
108 }
109 let mut flat = Vec::new();
110 factor_into(n, &mut flat);
111 flat.sort_unstable();
112 let mut out: Vec<(u64, u32)> = Vec::new();
113 for p in flat {
114 if let Some(last) = out.last_mut() {
115 if last.0 == p {
116 last.1 += 1;
117 continue;
118 }
119 }
120 out.push((p, 1));
121 }
122 out
123}
124
125pub fn divisors(n: u64) -> Vec<u64> {
127 if n == 0 {
128 return Vec::new();
129 }
130 let mut divs = vec![1u64];
131 for (p, e) in prime_factors(n) {
132 let mut pk = 1u64;
133 let base = divs.clone();
134 for _ in 0..e {
135 pk *= p;
136 for &d in &base {
137 divs.push(d * pk);
138 }
139 }
140 }
141 divs.sort_unstable();
142 divs
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn primality_known_cases() {
151 for p in [2u64, 3, 5, 7, 13, 97, 7919, 104729, 1_000_000_007] {
152 assert!(is_prime(p), "{p} should be prime");
153 }
154 for c in [0u64, 1, 4, 9, 15, 100, 7917, 1_000_000_011] {
155 assert!(!is_prime(c), "{c} should be composite");
156 }
157 assert!(!is_prime(561));
159 assert!(!is_prime(10_000_000_000_000_061 * 3));
161 }
162
163 #[test]
164 fn factorization_is_correct_and_reconstructs() {
165 assert_eq!(prime_factors(360), vec![(2, 3), (3, 2), (5, 1)]); assert_eq!(prime_factors(97), vec![(97, 1)]);
167 assert_eq!(prime_factors(1), vec![]);
168 let n = 1_000_000_007u64 * 1_000_000_009u64;
170 let f = prime_factors(n);
171 assert_eq!(f, vec![(1_000_000_007, 1), (1_000_000_009, 1)]);
172 let prod: u64 = f.iter().map(|&(p, e)| p.pow(e)).product();
174 assert_eq!(prod, n);
175 }
176
177 #[test]
178 fn divisors_of_28_are_perfect() {
179 let d = divisors(28);
180 assert_eq!(d, vec![1, 2, 4, 7, 14, 28]);
181 let proper: u64 = d.iter().filter(|&&x| x != 28).sum();
183 assert_eq!(proper, 28);
184 }
185
186 #[test]
187 fn next_prime_walks_forward() {
188 assert_eq!(next_prime(13), 17);
189 assert_eq!(next_prime(0), 2);
190 assert_eq!(next_prime(1), 2);
191 assert_eq!(next_prime(89), 97);
192 }
193}