1use crate::Poly;
12use cas_domain::{Integer, Rational};
13use std::sync::Arc;
14
15const PRIMES: &[u64] = &[
16 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
17];
18
19pub(crate) struct Det(u64);
21impl Det {
22 pub(crate) fn new() -> Self {
23 Det(0xC0FF_EE01)
24 }
25 pub(crate) fn next(&mut self) -> u64 {
26 let mut x = self.0 | 1;
27 x ^= x << 13;
28 x ^= x >> 7;
29 x ^= x << 17;
30 self.0 = x;
31 x
32 }
33}
34
35type IPoly = Vec<i128>;
38
39fn ip_trim(v: &mut IPoly) {
40 while v.last() == Some(&0) {
41 v.pop();
42 }
43}
44
45fn ip_deg(v: &IPoly) -> i32 {
46 v.len() as i32 - 1
47}
48
49fn ip_exact_div(a: &IPoly, b: &IPoly) -> Option<IPoly> {
51 if b.is_empty() {
52 return None;
53 }
54 if a.is_empty() {
55 return Some(vec![]);
56 }
57 if ip_deg(a) < ip_deg(b) {
58 return None;
59 }
60 let db = ip_deg(b) as usize;
61 let lb = *b.last()?;
62 let mut r = a.clone();
63 let mut q = vec![0i128; a.len() - b.len() + 1];
64 while ip_deg(&r) >= ip_deg(b) && !r.is_empty() {
65 let dr = ip_deg(&r) as usize;
66 let lr = *r.last()?;
67 if lr % lb != 0 {
68 return None;
69 }
70 let t = lr / lb;
71 q[dr - db] = t;
72 for (i, &c) in b.iter().enumerate() {
73 r[dr - db + i] = r[dr - db + i].checked_sub(t.checked_mul(c)?)?;
76 }
77 ip_trim(&mut r);
78 }
79 if r.is_empty() { Some(q) } else { None }
80}
81
82fn ip_primitive(f: &IPoly) -> (i128, IPoly) {
84 if f.is_empty() {
85 return (0, vec![]);
86 }
87 let mut g: i128 = 0;
88 for &c in f {
89 g = gcd_i128(g, c.abs());
90 }
91 if g == 0 {
92 g = 1;
93 }
94 let mut pp: IPoly = f.iter().map(|&c| c / g).collect();
95 if *pp.last().unwrap() < 0 {
96 for c in &mut pp {
97 *c = -*c;
98 }
99 g = -g;
100 }
101 (g, pp)
102}
103
104fn gcd_i128(mut a: i128, mut b: i128) -> i128 {
105 while b != 0 {
106 let r = a % b;
107 a = b;
108 b = r;
109 }
110 a
111}
112
113type Fp = Vec<u64>;
116
117fn fp_trim(v: &mut Fp) {
118 while v.last() == Some(&0) {
119 v.pop();
120 }
121}
122
123fn fp_deg(v: &Fp) -> i32 {
124 v.len() as i32 - 1
125}
126
127fn fp_monic(mut v: Fp, p: u64) -> Fp {
128 fp_trim(&mut v);
129 if let Some(&l) = v.last() {
130 let inv = fp_pow(l, p - 2, p);
131 for c in &mut v {
132 *c = *c % p * inv % p;
133 }
134 }
135 v
136}
137
138fn fp_pow(mut b: u64, mut e: u64, p: u64) -> u64 {
139 let mut r = 1u64;
140 b %= p;
141 while e > 0 {
142 if e & 1 == 1 {
143 r = r * b % p;
144 }
145 b = b * b % p;
146 e >>= 1;
147 }
148 r
149}
150
151fn fp_sub(a: &Fp, b: &Fp, p: u64) -> Fp {
152 let mut out = vec![0u64; a.len().max(b.len())];
153 for (i, &x) in a.iter().enumerate() {
154 out[i] = x;
155 }
156 for (i, &y) in b.iter().enumerate() {
157 out[i] = (out[i] + p - y % p) % p;
158 }
159 fp_trim(&mut out);
160 out
161}
162
163fn fp_mul(a: &Fp, b: &Fp, p: u64) -> Fp {
164 if a.is_empty() || b.is_empty() {
165 return vec![];
166 }
167 let mut out = vec![0u64; a.len() + b.len() - 1];
168 for (i, &x) in a.iter().enumerate() {
169 if x == 0 {
170 continue;
171 }
172 for (j, &y) in b.iter().enumerate() {
173 out[i + j] =
174 ((out[i + j] as u128 + x as u128 * y as u128 % p as u128) % p as u128) as u64;
175 }
176 }
177 fp_trim(&mut out);
178 out
179}
180
181fn fp_divrem(a: &Fp, b: &Fp, p: u64) -> (Fp, Fp) {
182 assert!(!b.is_empty(), "fp 除式为零");
183 let mut r = a.clone();
184 let mut q = vec![0u64; (a.len() as i32 - fp_deg(b)).max(0) as usize + 1];
185 let db = fp_deg(b) as usize;
186 let inv = fp_pow(*b.last().unwrap(), p - 2, p);
187 while !r.is_empty() && fp_deg(&r) >= db as i32 {
188 let dr = r.len() - 1;
189 let t = *r.last().unwrap() * inv % p;
190 q[dr - db] = t;
191 for (i, &c) in b.iter().enumerate() {
192 r[dr - db + i] = (r[dr - db + i] + p - t * c % p) % p;
193 }
194 fp_trim(&mut r);
195 }
196 fp_trim(&mut q);
197 (q, r)
198}
199
200fn fp_xgcd(a: &Fp, b: &Fp, p: u64) -> (Fp, Fp, Fp) {
202 let (mut r0, mut r1) = (a.to_vec(), b.to_vec());
203 let (mut s0, mut s1) = (vec![1u64], vec![]);
204 let (mut t0, mut t1) = (vec![], vec![1u64]);
205 while !r1.is_empty() {
206 let (q, r) = fp_divrem(&r0, &r1, p);
207 r0 = r1;
208 r1 = r;
209 let s2 = fp_sub(&s0, &fp_mul(&q, &s1, p), p);
210 s0 = s1;
211 s1 = s2;
212 let t2 = fp_sub(&t0, &fp_mul(&q, &t1, p), p);
213 t0 = t1;
214 t1 = t2;
215 }
216 if r0.is_empty() {
217 return (vec![], vec![], vec![]);
218 }
219 let inv = fp_pow(*r0.last().unwrap(), p - 2, p);
220 let mul = |v: &Fp| -> Fp { v.iter().map(|&c| c * inv % p).collect() };
221 (mul(&r0), mul(&s0), mul(&t0))
222}
223
224fn fp_gcd(a: &Fp, b: &Fp, p: u64) -> Fp {
225 fp_xgcd(a, b, p).0
226}
227
228fn fp_deriv(a: &Fp, p: u64) -> Fp {
229 let mut out = vec![0u64; a.len().saturating_sub(1)];
230 for i in 1..a.len() {
231 out[i - 1] = a[i] * (i as u64) % p;
232 }
233 fp_trim(&mut out);
234 out
235}
236
237fn fp_powmod(mut b: Fp, mut e: u128, f: &Fp, p: u64) -> Fp {
239 let mut r: Fp = vec![1];
240 fn rem(v: Fp, f: &Fp, p: u64) -> Fp {
241 let (_, r) = fp_divrem(&v, f, p);
242 r
243 }
244 b = rem(b, f, p);
245 while e > 0 {
246 if e & 1 == 1 {
247 r = rem(fp_mul(&r, &b, p), f, p);
248 }
249 b = rem(fp_mul(&b, &b, p), f, p);
250 e >>= 1;
251 }
252 r
253}
254
255fn fp_rand(n: usize, p: u64, det: &mut Det) -> Fp {
257 let mut v: Fp = (0..n).map(|_| det.next() % p).collect();
258 fp_trim(&mut v);
259 v
260}
261
262fn ddf(f: &Fp, p: u64) -> Vec<(Fp, u32)> {
264 let mut out = vec![];
265 let mut fcur = f.clone();
266 let mut h: Fp = vec![0, 1]; let mut d = 1u32;
268 loop {
269 h = fp_powmod(h, p as u128, &fcur, p); let xx: Fp = vec![0, 1];
272 let g = fp_gcd(&fcur, &fp_sub(&h, &xx, p), p);
273 if fp_deg(&g) > 0 {
274 let q = fp_monic(g, p);
275 let (quot, rem) = fp_divrem(&fcur, &q, p);
277 debug_assert!(rem.is_empty(), "ddf 因子必整除");
278 out.push((q.clone(), d));
279 fcur = quot;
280 h = {
284 let (_, r) = fp_divrem(&h, &fcur, p);
285 r
286 };
287 }
288 let df = fp_deg(&fcur);
289 if df <= 0 {
290 break;
291 }
292 if df <= d as i32 {
293 if df > 0 {
294 out.push((fcur.clone(), df as u32));
295 }
296 break;
297 }
298 d += 1;
299 }
300 out
301}
302
303fn edf(f: &Fp, d: u32, p: u64, det: &mut Det) -> Vec<Fp> {
305 let n = fp_deg(f);
306 if n <= d as i32 {
307 return vec![f.clone()];
308 }
309 loop {
310 let q = fp_rand(f.len(), p, det);
311 if q.is_empty() {
312 continue;
313 }
314 let e = ((p as u128).pow(d) - 1) / 2;
316 let t = fp_powmod(q, e, f, p);
317 if t.is_empty() {
318 continue;
319 }
320 let one: Fp = vec![1];
321 let g = fp_gcd(f, &fp_sub(&t, &one, p), p);
322 let dg = fp_deg(&g);
323 if dg > 0 && dg < n {
324 let (quot, rem) = fp_divrem(f, &g, p);
326 debug_assert!(rem.is_empty(), "edf 因子必整除");
327 let mut out = edf(&fp_monic(g, p), d, p, det);
328 out.extend(edf(&fp_monic(quot, p), d, p, det));
329 return out;
330 }
331 }
332}
333
334fn cz_factor(f_monic_sqfree: &Fp, p: u64, det: &mut Det) -> Vec<Fp> {
336 let mut out = vec![];
337 for (g, d) in ddf(f_monic_sqfree, p) {
338 out.extend(edf(&g, d, p, det));
339 }
340 out
341}
342
343#[allow(clippy::too_many_arguments)]
348fn hensel2(
351 target: &[u64],
352 a0: &Fp,
353 b0: &Fp,
354 _s: &Fp,
355 t: &Fp,
356 p: u64,
357 k: u32,
358 pk: u64,
359) -> Option<(Vec<u64>, Vec<u64>)> {
360 let mut a: Vec<u64> = a0.to_vec();
361 let mut b: Vec<u64> = b0.to_vec();
362 let mut step_mod = p; for _step in 1..k {
364 let next_mod = step_mod * p; let prod = umul(&a, &b, next_mod);
367 let mut err: Fp = vec![];
369 for i in 0..prod.len().max(target.len()) {
370 let ai = target.get(i).copied().unwrap_or(0) % next_mod;
371 let pi = prod.get(i).copied().unwrap_or(0);
372 let diff = (ai + next_mod - pi) % next_mod;
373 if diff % step_mod != 0 {
374 return None; }
376 err.push(diff / step_mod % p);
377 }
378 fp_trim(&mut err);
379 if !err.is_empty() {
380 let sig = {
383 let prod_e = fp_mul(&err, t, p);
384 let (_, r) = fp_divrem(&prod_e, a0, p);
385 r
386 };
387 let tau = {
388 let pr = fp_sub(&err, &fp_mul(&sig, b0, p), p);
389 let (q, r) = fp_divrem(&pr, a0, p);
390 if !r.is_empty() {
391 return None; }
393 q
394 };
395 for (i, &c) in sig.iter().enumerate() {
396 a[i] = (a[i] + step_mod % pk * c % pk) % pk;
397 }
398 for (i, &c) in tau.iter().enumerate() {
399 b[i] = (b[i] + step_mod % pk * c % pk) % pk;
400 }
401 }
402 step_mod = next_mod;
403 }
404 trim_u(&mut a);
405 trim_u(&mut b);
406 Some((a, b))
407}
408
409fn trim_u(v: &mut Vec<u64>) {
410 while v.last() == Some(&0) {
411 v.pop();
412 }
413}
414
415fn umul(a: &[u64], b: &[u64], m: u64) -> Vec<u64> {
416 if a.is_empty() || b.is_empty() {
417 return vec![];
418 }
419 let mut out = vec![0u64; a.len() + b.len() - 1];
420 for (i, &x) in a.iter().enumerate() {
421 if x == 0 {
422 continue;
423 }
424 for (j, &y) in b.iter().enumerate() {
425 out[i + j] = (out[i + j] as u128 + x as u128 * y as u128 % m as u128) as u64 % m;
426 }
427 }
428 trim_u(&mut out);
429 out
430}
431
432fn hensel_all(target: &[u64], facs: &[Fp], p: u64, k: u32, pk: u64) -> Vec<Vec<u64>> {
435 if facs.len() == 1 {
436 return vec![target.to_vec()];
437 }
438 let mid = facs.len() / 2;
439 let (left, right) = facs.split_at(mid);
440 let a0 = left
441 .iter()
442 .cloned()
443 .reduce(|x, y| fp_mul(&x, &y, p))
444 .unwrap();
445 let b0 = right
446 .iter()
447 .cloned()
448 .reduce(|x, y| fp_mul(&x, &y, p))
449 .unwrap();
450 let (_, s, t) = fp_xgcd(&a0, &b0, p);
451 let Some((al, br)) = hensel2(target, &a0, &b0, &s, &t, p, k, pk) else {
452 return vec![target.to_vec(); facs.len()];
454 };
455 let mut out = hensel_all(&al, left, p, k, pk);
456 out.extend(hensel_all(&br, right, p, k, pk));
457 out
458}
459
460fn zassenhaus(s: &IPoly) -> Vec<IPoly> {
464 let d = ip_deg(s);
465 if d <= 1 {
466 return vec![s.to_vec()];
467 }
468 let lc = *s.last().unwrap() as i64; let amax: i128 = s.iter().map(|c| c.abs()).max().unwrap();
470 let mut chosen: Option<(u64, Fp)> = None;
472 for &p in PRIMES {
473 if lc % p as i64 == 0 {
474 continue;
475 }
476 let fmod: Fp = s
477 .iter()
478 .map(|&c| (c.rem_euclid(p as i128)) as u64)
479 .collect();
480 let fmod = fp_monic(fmod, p);
481 let df = fp_deriv(&fmod, p);
482 if fp_gcd(&fmod, &df, p).len() <= 1 {
483 chosen = Some((p, fmod));
484 break;
485 }
486 }
487 let (p, fmod) = match chosen {
488 Some(x) => x,
489 None => {
490 return vec![s.to_vec()]; }
492 };
493 let mut det = Det::new();
494 let facs_p = cz_factor(&fmod, p, &mut det);
495 if facs_p.len() <= 1 {
496 return vec![s.to_vec()]; }
498 let b_bound: u128 = (2u128 << d.min(120)) * amax as u128 * lc.unsigned_abs() as u128;
501 let mut pk = p as u128;
502 let mut k = 1u32;
503 while pk <= 2 * b_bound {
504 pk *= p as u128;
505 k += 1;
506 if pk > 1 << 60 {
507 return vec![s.to_vec()];
508 }
509 }
510 let pk = pk as u64;
511 let lc_inv = inv_mod(lc.rem_euclid(pk as i64) as u64, pk);
513 let a: Vec<u64> = s
516 .iter()
517 .map(|&c| ((c.rem_euclid(pk as i128) as u64 as u128 * lc_inv as u128) % pk as u128) as u64)
518 .collect();
519 let lifted = hensel_all(&a, &facs_p, p, k, pk);
520 combine(s, &lifted, pk, lc)
522}
523
524fn inv_mod(a: u64, m: u64) -> u64 {
525 let (mut r0, mut r1) = (m as i128, a as i128 % m as i128);
527 let (mut s0, mut s1) = (0i128, 1i128);
528 while r1 != 0 {
529 let q = r0 / r1;
530 let r2 = r0 - q * r1;
531 r0 = r1;
532 r1 = r2;
533 let s2 = s0 - q * s1;
534 s0 = s1;
535 s1 = s2;
536 }
537 debug_assert_eq!(r0, 1, "逆元不存在");
538 s0.rem_euclid(m as i128) as u64
539}
540
541fn combine(f: &IPoly, lifted: &[Vec<u64>], pk: u64, lc: i64) -> Vec<IPoly> {
543 let r = lifted.len();
544 if r > 16 {
545 return vec![f.to_vec()]; }
547 let half = pk / 2;
548 let sym = |v: Vec<u64>| -> IPoly {
549 v.iter()
550 .map(|&c| {
551 if c > half {
552 c as i128 - pk as i128
553 } else {
554 c as i128
555 }
556 })
557 .collect()
558 };
559 let mut factors: Vec<IPoly> = vec![];
560 let mut used = vec![false; r];
561 let mut f_cur = f.clone();
562 let mut masks: Vec<u64> = (1..(1u64 << (r - 1))).collect();
564 masks.sort_by_key(|m| m.count_ones());
565 loop {
566 let mut found = false;
567 for &mask in &masks {
568 if (0..r - 1).any(|i| mask >> i & 1 == 1 && used[i]) {
570 continue;
571 }
572 if mask.count_ones() as usize > ip_deg(&f_cur).max(0) as usize {
573 continue;
574 }
575 let mut cand: Vec<u64> = vec![1];
578 for (i, g) in lifted.iter().enumerate().take(r - 1) {
579 if mask >> i & 1 == 1 {
580 cand = umul(&cand, g, pk);
581 }
582 }
583 let lc_u = (lc as i128).rem_euclid(pk as i128) as u64;
586 let k = mask.count_ones();
587 let mut hit = None;
588 let mut scaled = cand.clone();
589 for j in 0..=k {
590 if j > 0 {
591 scaled = umul(&scaled, &[lc_u], pk);
592 }
593 let cand_ip = ip_trim_mut(sym(scaled.clone()));
594 if cand_ip.is_empty() {
595 continue;
596 }
597 let (_, pp) = ip_primitive(&cand_ip);
598 if pp.is_empty() || ip_deg(&pp) == 0 || ip_deg(&pp) > ip_deg(&f_cur) {
599 continue;
600 }
601 if let Some(q) = ip_exact_div(&f_cur, &pp) {
602 hit = Some((pp, q));
603 break;
604 }
605 }
606 if let Some((pp, q)) = hit {
607 factors.push(pp);
608 f_cur = q;
609 for (i, u) in used.iter_mut().enumerate().take(r - 1) {
610 if mask >> i & 1 == 1 {
611 *u = true;
612 }
613 }
614 found = true;
615 break;
616 }
617 }
618 if !found {
619 break;
620 }
621 }
622 if !f_cur.is_empty() && ip_deg(&f_cur) > 0 {
623 factors.push(f_cur);
624 }
625 factors
626}
627
628fn ip_trim_mut(mut v: IPoly) -> IPoly {
629 ip_trim(&mut v);
630 v
631}
632
633pub(crate) fn squarefree_parts(f: &Poly<Rational>) -> Vec<(Poly<Rational>, u32)> {
636 let df = f.deriv(0);
637 if df.is_zero() {
638 return vec![(f.clone(), 1)];
639 }
640 let c = f.gcd(&df);
641 let mut w = match f.exact_div(&c) {
642 Some(v) => v,
643 None => return vec![(f.clone(), 1)],
644 };
645 let mut z = match df.exact_div(&c) {
646 Some(v) => v.sub(&w.deriv(0)),
647 None => return vec![(f.clone(), 1)],
648 };
649 let mut out = vec![];
650 let mut i = 1u32;
651 while !w.is_constant() {
652 let g = w.gcd(&z);
653 if !g.is_constant() {
654 out.push((g.clone(), i));
655 w = w.exact_div(&g).expect("Yun 整除");
656 z = z.exact_div(&g).expect("Yun 整除").sub(&w.deriv(0));
657 } else {
658 z = z.sub(&w.deriv(0));
659 }
660 i += 1;
661 }
662 out
663}
664
665impl Poly<Rational> {
668 pub fn factor_univariate(&self) -> (Rational, Vec<(Poly<Rational>, u32)>) {
671 assert_eq!(self.ring().nvars(), 1, "factor_univariate 仅支持一元");
672 if self.is_zero() {
673 return (Rational::zero(), vec![]);
674 }
675 if self.is_constant() {
676 return (self.terms().next().unwrap().1.clone(), vec![]);
677 }
678 let mut den_lcm = Integer::one();
680 for (_, c) in self.terms() {
681 den_lcm = den_lcm.mul(&c.den());
682 }
683 let mut num_gcd = Integer::zero();
684 for (_, c) in self.terms() {
685 let scaled = c.num().mul(&den_lcm.div_exact(&c.den()));
686 num_gcd = if num_gcd.is_zero() {
687 scaled
688 } else {
689 num_gcd.gcd(&scaled)
690 };
691 }
692 if num_gcd.is_zero() {
693 num_gcd = Integer::one();
694 }
695 let cont = Rational::from_ints(&num_gcd, &den_lcm).unwrap();
696 let mut dense: IPoly = {
697 let mut v = vec![0i128; self.degree() as usize + 1];
698 for (e, c) in self.terms() {
699 let scaled = c.mul(&Rational::from_integer(&den_lcm));
700 let r = scaled.div(&Rational::from_integer(&num_gcd)).unwrap();
701 assert!(r.den().is_one(), "本原化后必为整系数");
702 v[e[0] as usize] = r.num().to_i64().expect("本原化后系数落 i64") as i128;
703 }
704 v
705 };
706 let mut cont = cont;
708 if *dense.last().unwrap() < 0 {
709 for c in &mut dense {
710 *c = -*c;
711 }
712 cont = cont.neg();
713 }
714 let ring = self.ring().clone();
716 let mut factors: Vec<(Poly<Rational>, u32)> = vec![];
717 for (s, m) in squarefree_parts(&from_dense(&dense, &ring)) {
718 if s.is_constant() {
719 continue;
720 }
721 let dense_s = to_dense(&s);
722 for h in zassenhaus(&dense_s) {
723 factors.push((from_dense(&h, &ring), m));
724 }
725 }
726 factors.sort_by(|a, b| cmp_dense(&to_dense(&a.0), &to_dense(&b.0)));
728 (cont, factors)
729 }
730}
731
732fn to_dense(p: &Poly<Rational>) -> IPoly {
733 let mut v = vec![0i128; p.degree() as usize + 1];
734 for (e, c) in p.terms() {
735 assert!(c.den().is_one(), "to_dense 需整系数");
736 v[e[0] as usize] = c.num().to_i64().expect("整系数落 i64") as i128;
737 }
738 v
739}
740
741fn from_dense(v: &IPoly, ring: &Arc<crate::PolyRing>) -> Poly<Rational> {
742 let items: Vec<(Vec<u32>, Rational)> = v
743 .iter()
744 .enumerate()
745 .filter(|(_, c)| **c != 0)
746 .map(|(i, &c)| {
747 (
748 vec![i as u32],
749 Rational::from_integer(&Integer::from_i64(c as i64)),
750 )
751 })
752 .collect();
753 Poly::from_terms(ring.clone(), items)
754}
755
756fn cmp_dense(a: &IPoly, b: &IPoly) -> std::cmp::Ordering {
757 use std::cmp::Ordering;
758 match ip_deg(a).cmp(&ip_deg(b)) {
759 Ordering::Equal => {}
760 o => return o,
761 }
762 for i in (0..a.len()).rev() {
763 match a[i].cmp(&b[i]) {
764 Ordering::Equal => {}
765 o => return o,
766 }
767 }
768 std::cmp::Ordering::Equal
769}
770
771#[cfg(test)]
772mod tests {
773 use super::*;
774 use crate::{MonOrder, PolyRing};
775
776 fn ring() -> Arc<PolyRing> {
777 PolyRing::new(["x"], MonOrder::DegRevLex)
778 }
779
780 fn from_coeffs(cs: &[i64]) -> Poly<Rational> {
781 let items: Vec<(Vec<u32>, Rational)> = cs
782 .iter()
783 .enumerate()
784 .filter(|(_, c)| **c != 0)
785 .map(|(i, &c)| {
786 (
787 vec![i as u32],
788 Rational::from_ints(&Integer::from_i64(c), &Integer::from_i64(1)).unwrap(),
789 )
790 })
791 .collect();
792 Poly::from_terms(ring(), items)
793 }
794
795 fn check_refold(f: &Poly<Rational>) {
796 let (cont, facs) = f.factor_univariate();
797 let mut prod = Poly::constant(ring(), cont);
798 for (g, m) in &facs {
799 prod = prod.mul(&g.pow(*m));
800 }
801 assert_eq!(prod, *f, "重展开不等于原式: f={f:?} factors={facs:?}");
802 }
803
804 #[test]
805 fn 二项式与已知分解() {
806 let f = from_coeffs(&[-1, 0, 1]); let (c, facs) = f.factor_univariate();
808 assert_eq!(facs.len(), 2);
809 let mut prod = Poly::constant(ring(), c);
810 for (g, m) in &facs {
811 prod = prod.mul(&g.pow(*m));
812 }
813 assert_eq!(prod, f);
814
815 let f = from_coeffs(&[4, 0, 0, 0, 1]);
817 let (_, facs) = f.factor_univariate();
818 assert_eq!(facs.len(), 2, "x^4+4 应分解为两个二次因子: {facs:?}");
819 check_refold(&f);
820
821 let f = from_coeffs(&[1, 0, 0, 0, 1]);
823 let (_, facs) = f.factor_univariate();
824 assert_eq!(facs.len(), 1);
825 }
826
827 #[test]
828 fn x_n_minus_1_全族() {
829 for n in 1..=64u32 {
830 let mut cs = vec![0i64; n as usize + 1];
831 cs[0] = -1;
832 cs[n as usize] = 1;
833 let f = from_coeffs(&cs);
834 check_refold(&f);
835 }
836 let mut cs = vec![0i64; 13];
838 cs[0] = -1;
839 cs[12] = 1;
840 let (_, facs) = from_coeffs(&cs).factor_univariate();
841 assert_eq!(facs.len(), 6);
842 }
843
844 #[test]
845 fn 随机积重展开() {
846 let mut det = Det::new();
847 for _ in 0..600 {
848 let nf = 2 + det.next() % 2; let mut f = Poly::constant(ring(), Rational::one());
850 for _ in 0..nf {
851 let deg = 1 + det.next() % 6;
852 let cs: Vec<i64> = (0..=deg).map(|_| (det.next() % 13) as i64 - 6).collect();
853 let g = from_coeffs(&cs);
854 if g.is_zero() {
855 continue;
856 }
857 f = f.mul(&g);
858 }
859 let scale = Rational::from_ints(
861 &Integer::from_i64((det.next() % 7) as i64 - 3),
862 &Integer::from_i64(1 + (det.next() % 5) as i64),
863 )
864 .unwrap();
865 let f = f.mul(&Poly::constant(ring(), scale));
866 if !f.is_zero() && !f.is_constant() {
867 check_refold(&f);
868 }
869 }
870 }
871
872 #[test]
873 fn 重数与内容() {
874 let f = from_coeffs(&[-8, 24, -24, 8]);
876 let (c, facs) = f.factor_univariate();
877 assert_eq!(facs.len(), 1);
878 assert_eq!(facs[0].1, 3);
879 assert_eq!(
880 c,
881 Rational::from_ints(&Integer::from_i64(8), &Integer::from_i64(1)).unwrap()
882 );
883 check_refold(&f);
884 }
885}
886
887#[cfg(test)]
888mod hensel_regression {
889 use super::*;
890
891 #[test]
894 fn 溢出回归_符号翻转() {
895 let f1: IPoly = vec![-1, 2, 5, 2, -6];
896 let f2: IPoly = vec![6, -3, 1, 1, 6, 3, -4];
897 let f3: IPoly = vec![4, -6, 0, -1, -5];
898 let mut f = vec![0i128; 15];
899 for (i, &x) in f1.iter().enumerate() {
900 for (j, &y) in f2.iter().enumerate() {
901 for (k, &z) in f3.iter().enumerate() {
902 f[i + j + k] += x * y * z;
903 }
904 }
905 }
906 ip_trim(&mut f);
907 assert_eq!(zassenhaus(&f).len(), 3, "原始版本");
908 let mut neg = f.clone();
909 for c in &mut neg {
910 *c = -*c;
911 }
912 assert_eq!(zassenhaus(&neg).len(), 3, "符号翻转版本(曾触发 u64 溢出)");
913 }
914}