1use crate::traits::ExactRoots;
11use num_integer::{Integer, Roots};
12use num_modular::{ModularCoreOps, ModularUnaryOps};
13use num_traits::{CheckedAdd, FromPrimitive, NumRef, RefNum};
14use std::collections::BTreeMap;
15
16pub fn trial_division<
24 I: Iterator<Item = u64>,
25 T: Integer + Clone + Roots + NumRef + FromPrimitive,
26>(
27 primes: I,
28 target: T,
29 limit: Option<u64>,
30) -> (BTreeMap<u64, usize>, Result<T, T>)
31where
32 for<'r> &'r T: RefNum<T>,
33{
34 let tsqrt: T = Roots::sqrt(&target) + T::one();
35 let limit = if let Some(l) = limit {
36 tsqrt.clone().min(T::from_u64(l).unwrap())
37 } else {
38 tsqrt.clone()
39 };
40
41 let mut residual = target;
42 let mut result = BTreeMap::new();
43 let mut factored = false;
44 for (p, pt) in primes.map(|p| (p, T::from_u64(p).unwrap())) {
45 if &pt > &tsqrt {
46 factored = true;
47 }
48 if &pt > &limit {
49 break;
50 }
51
52 while residual.is_multiple_of(&pt) {
53 residual = residual / &pt;
54 *result.entry(p).or_insert(0) += 1;
55 }
56 if residual.is_one() {
57 factored = true;
58 break;
59 }
60 }
61
62 if factored {
63 (result, Ok(residual))
64 } else {
65 (result, Err(residual))
66 }
67}
68
69pub fn pollard_rho<
73 T: Integer
74 + FromPrimitive
75 + NumRef
76 + Clone
77 + for<'r> ModularCoreOps<&'r T, &'r T, Output = T>
78 + for<'r> ModularUnaryOps<&'r T, Output = T>,
79>(
80 target: &T,
81 start: T,
82 offset: T,
83 max_iter: usize,
84) -> (Option<T>, usize)
85where
86 for<'r> &'r T: RefNum<T>,
87{
88 let mut a = start.clone();
89 let mut b = start.clone();
90 let mut z = T::one() % target; let (mut i, mut j) = (0usize, 1usize);
94
95 let mut s = start;
97 let mut backtrace = false;
98
99 while i < max_iter {
100 i += 1;
101 a = a.sqm(&target).addm(&offset, &target);
102 if a == b {
103 return (None, i);
104 }
105
106 let diff = if b > a { &b - &a } else { &a - &b }; z = z.mulm(&diff, &target);
109 if z.is_zero() {
110 if backtrace {
112 return (None, i);
114 } else {
115 backtrace = true;
116 a = std::mem::replace(&mut s, T::one()); z = T::one() % target; continue;
119 }
120 }
121
122 if i == j || i & 127 == 0 || backtrace {
126 let d = z.gcd(target);
127 if !d.is_one() && &d != target {
128 return (Some(d), i);
129 }
130
131 s = a.clone();
133 }
134
135 if i == j {
137 b = a.clone();
138 j <<= 1;
139 }
140 }
141
142 (None, i)
143}
144
145pub fn squfof<T: Integer + NumRef + Clone + ExactRoots + std::fmt::Debug>(
158 target: &T,
159 mul_target: T,
160 max_iter: usize,
161) -> (Option<T>, usize)
162where
163 for<'r> &'r T: RefNum<T>,
164{
165 assert!(
166 &mul_target.is_multiple_of(&target),
167 "mul_target should be multiples of target"
168 );
169 let rd = Roots::sqrt(&mul_target); #[inline]
176 fn rho<T: Integer + Clone + NumRef>(rd: &T, p: &T, q: &mut T, qm1: &mut T) -> T
177 where
178 for<'r> &'r T: RefNum<T>,
179 {
180 let b = (rd + p).div_floor(&*q);
181 let new_p = &b * &*q - p;
182 let new_q = if p > &new_p {
183 &*qm1 + b * (p - &new_p)
184 } else {
185 &*qm1 - b * (&new_p - p)
186 };
187
188 *qm1 = std::mem::replace(q, new_q);
189 new_p
190 }
191
192 let (mut p, mut q, mut qm1) = (rd.clone(), &mul_target - &rd * &rd, T::one());
194 if q.is_zero() {
195 return (Some(rd), 0);
197 }
198
199 for i in 1..max_iter {
200 p = rho(&rd, &p, &mut q, &mut qm1);
201 if i.is_odd() {
202 if let Some(rq) = q.sqrt_exact() {
203 let b = (&rd - &p) / &rq;
204 let mut u = b * &rq + &p;
205 let (mut v, mut vm1) = ((&mul_target - &u * &u) / &rq, rq);
206
207 loop {
209 let new_u = rho(&rd, &u, &mut v, &mut vm1);
210 if new_u == u {
211 break;
212 } else {
213 u = new_u
214 }
215 }
216
217 let d = target.gcd(&u);
218 if d > T::one() && &d < target {
219 return (Some(d), i);
220 }
221 }
222 }
223 }
224 (None, max_iter)
225}
226
227pub const SQUFOF_MULTIPLIERS: [u16; 38] = [
231 3 * 5 * 7 * 11,
232 3 * 5 * 7,
233 3 * 5 * 7 * 11 * 13,
234 3 * 5 * 7 * 13,
235 3 * 5 * 7 * 11 * 17,
236 3 * 5 * 11,
237 3 * 5 * 7 * 17,
238 3 * 5,
239 3 * 5 * 7 * 11 * 19,
240 3 * 5 * 11 * 13,
241 3 * 5 * 7 * 19,
242 3 * 5 * 7 * 13 * 17,
243 3 * 5 * 13,
244 3 * 7 * 11,
245 3 * 7,
246 5 * 7 * 11,
247 3 * 7 * 13,
248 5 * 7,
249 3 * 5 * 17,
250 5 * 7 * 13,
251 3 * 5 * 19,
252 3 * 11,
253 3 * 7 * 17,
254 3,
255 3 * 11 * 13,
256 5 * 11,
257 3 * 7 * 19,
258 3 * 13,
259 5,
260 5 * 11 * 13,
261 5 * 7 * 19,
262 5 * 13,
263 7 * 11,
264 7,
265 3 * 17,
266 7 * 13,
267 11,
268 1,
269];
270
271pub fn one_line<T: Integer + NumRef + FromPrimitive + ExactRoots + CheckedAdd>(
285 target: &T,
286 mul_target: T,
287 max_iter: usize,
288) -> (Option<T>, usize)
289where
290 for<'r> &'r T: RefNum<T>,
291{
292 assert!(
293 &mul_target.is_multiple_of(&target),
294 "mul_target should be multiples of target"
295 );
296
297 let mut ikn = mul_target.clone();
298 for i in 1..max_iter {
299 let s = ikn.sqrt() + T::one(); let m = &s * &s - &ikn;
301 if let Some(t) = m.sqrt_exact() {
302 let g = target.gcd(&(s - t));
303 if !g.is_one() && &g != target {
304 return (Some(g), i);
305 }
306 }
307
308 ikn = if let Some(n) = (&ikn).checked_add(&mul_target) {
310 n
311 } else {
312 return (None, i);
313 }
314 }
315 return (None, max_iter);
316}
317
318fn pollard_pp1() {}
325fn williams_pp1() {}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330 use crate::mint::SmallMint;
331 use num_modular::MontgomeryInt;
332 use rand::random;
333
334 #[test]
335 fn pollard_rho_test() {
336 assert_eq!(pollard_rho(&8051u16, 2, 1, 100).0, Some(97));
337 assert!(matches!(pollard_rho(&8051u16, random(), 1, 100).0, Some(i) if i == 97 || i == 83));
338 assert_eq!(pollard_rho(&455459u32, 2, 1, 100).0, Some(743));
339
340 for _ in 0..10 {
342 let target = random::<u16>() | 1;
343 let start = random::<u16>() % target;
344 let offset = random::<u16>() % target;
345
346 let expect = pollard_rho(&target, start, offset, 65536);
347 let mint_result = pollard_rho(
348 &SmallMint::from(target),
349 MontgomeryInt::new(start, &target).into(),
350 MontgomeryInt::new(offset, &target).into(),
351 65536,
352 );
353 assert_eq!(expect.0, mint_result.0.map(|v| v.value()));
354 }
355 }
356
357 #[test]
358 fn squfof_test() {
359 assert_eq!(squfof(&11111u32, 11111u32, 100).0, Some(41));
361
362 let cases: Vec<u64> = vec![
364 2501,
365 12851,
366 13289,
367 75301,
368 120787,
369 967009,
370 997417,
371 7091569,
372 5214317,
373 20834839,
374 23515517,
375 33409583,
376 44524219,
377 13290059,
378 223553581,
379 2027651281,
380 11111111111,
381 100895598169,
382 60012462237239,
383 287129523414791,
384 9007199254740931,
385 11111111111111111,
386 314159265358979323,
387 384307168202281507,
388 419244183493398773,
389 658812288346769681,
390 922337203685477563,
391 1000000000000000127,
392 1152921505680588799,
393 1537228672809128917,
394 4558849,
396 ];
397 for n in cases {
398 let d = squfof(&n, n, 40000)
399 .0
400 .or(squfof(&n, 3 * n, 40000).0)
401 .or(squfof(&n, 5 * n, 40000).0)
402 .or(squfof(&n, 7 * n, 40000).0)
403 .or(squfof(&n, 11 * n, 40000).0);
404 assert!(matches!(d, Some(_)), "{}", n);
405 }
406 }
407
408 #[test]
409 fn one_line_test() {
410 assert_eq!(one_line(&11111u32, 11111u32, 100).0, Some(271));
411 }
412}