1use crate::factor::squarefree_parts;
17use crate::gcd::Uni;
18use crate::{Poly, PolyRing};
19use cas_domain::{Integer, Rational};
20use std::sync::Arc;
21
22fn coeff_zk(p: &Poly<Rational>, ring_v: &Arc<PolyRing>, k: u32) -> Poly<Rational> {
26 let items: Vec<(Vec<u32>, Rational)> = p
27 .terms()
28 .filter(|(e, _)| e[1] == k)
29 .map(|(e, c)| (vec![e[0]], c.clone()))
30 .collect();
31 Poly::from_terms(ring_v.clone(), items)
32}
33
34fn add_zk_pow(base: &Poly<Rational>, p: &Poly<Rational>, k: u32) -> Poly<Rational> {
36 if p.is_zero() {
37 return base.clone();
38 }
39 let items: Vec<(Vec<u32>, Rational)> = p
40 .terms()
41 .map(|(e, c)| {
42 let mut full = vec![0u32; 2];
43 full[0] = e[0];
44 full[1] = k;
45 (full, c.clone())
46 })
47 .collect();
48 base.add(&Poly::from_terms(base.ring().clone(), items))
49}
50
51fn shift_z(p: &Poly<Rational>, c: i64) -> Poly<Rational> {
53 if c == 0 {
54 return p.clone();
55 }
56 let cint = Integer::from_i64(c);
57 let mut items: Vec<(Vec<u32>, Rational)> = Vec::new();
58 for (e, coef) in p.terms() {
59 let n = e[1] as u64;
60 let mut binom = 1i128;
62 for j in 0..=n {
63 if binom != 0 {
64 let factor = Rational::from_ints(&Integer::from_i64(binom as i64), &Integer::one())
65 .unwrap()
66 .mul(&Rational::from_integer(&cint.pow((n - j) as u32)))
67 .mul(coef);
68 if !factor.is_zero() {
69 let mut full = vec![0u32; 2];
70 full[0] = e[0];
71 full[1] = j as u32;
72 items.push((full, factor));
73 }
74 }
75 binom = binom * (n - j) as i128 / (j + 1) as i128;
76 }
77 }
78 Poly::from_terms(p.ring().clone(), items)
79}
80
81fn divrem1(a: &Poly<Rational>, b: &Poly<Rational>) -> (Poly<Rational>, Poly<Rational>) {
83 let (mut qs, r) = a.div_rem(&[b]);
84 (qs.pop().expect("单除子"), r)
85}
86
87fn rat_xgcd1(
89 a: &Poly<Rational>,
90 b: &Poly<Rational>,
91) -> (Poly<Rational>, Poly<Rational>, Poly<Rational>) {
92 let ring = a.ring().clone();
93 let (mut r0, mut r1) = (a.clone(), b.clone());
94 let (mut s0, mut s1) = (
95 Poly::constant(ring.clone(), Rational::one()),
96 Poly::zero(ring.clone()),
97 );
98 let (mut t0, mut t1) = (
99 Poly::zero(ring.clone()),
100 Poly::constant(ring.clone(), Rational::one()),
101 );
102 while !r1.is_zero() {
103 let (q, r) = divrem1(&r0, &r1);
104 r0 = r1;
105 r1 = r;
106 let s2 = s0.sub(&q.mul(&s1));
107 s0 = s1;
108 s1 = s2;
109 let t2 = t0.sub(&q.mul(&t1));
110 t0 = t1;
111 t1 = t2;
112 }
113 let lc = match r0.terms().last() {
115 Some((_, c)) => c.clone(),
116 None => return (r0, s0, t0), };
118 let inv = lc.inv_reduced().unwrap_or_else(Rational::one);
119 let scale = |p: &Poly<Rational>| -> Poly<Rational> {
120 let items: Vec<(Vec<u32>, Rational)> =
121 p.terms().map(|(e, c)| (e.to_vec(), c.mul(&inv))).collect();
122 Poly::from_terms(ring.clone(), items)
123 };
124 (scale(&r0), scale(&s0), scale(&t0))
125}
126
127fn hensel2_bivar(
132 target: &Poly<Rational>, a0: &Poly<Rational>, b0: &Poly<Rational>, _s: &Poly<Rational>, t: &Poly<Rational>,
137 k_max: u32,
138 ring_v: &Arc<PolyRing>,
139) -> Option<(Poly<Rational>, Poly<Rational>)> {
140 let mut a = Poly::from_terms(
141 target.ring().clone(),
142 a0.terms()
143 .map(|(e, c)| (vec![e[0], 0], c.clone()))
144 .collect::<Vec<_>>(),
145 );
146 let mut b = Poly::from_terms(
147 target.ring().clone(),
148 b0.terms()
149 .map(|(e, c)| (vec![e[0], 0], c.clone()))
150 .collect::<Vec<_>>(),
151 );
152 let deg_z_target: u32 = target.terms().map(|(e, _)| e[1]).max().unwrap_or(0);
153 let mut k: u32 = 1;
154 while k < k_max {
155 let prod = a.mul(&b);
156 let err_full = target.sub(&prod);
157 if err_full.is_zero() {
158 return Some((a, b)); }
160 if err_full.terms().any(|(e, _)| e[1] < k) {
162 return None; }
164 if k > deg_z_target + 1 {
165 return None; }
167 let err = coeff_zk(&err_full, ring_v, k); if !err.is_zero() {
169 let sig = {
170 let (_, r) = divrem1(&err.mul(t), a0);
171 r
172 };
173 let tau = {
174 let pr = err.sub(&sig.mul(b0));
175 let (q, r) = divrem1(&pr, a0);
176 if !r.is_zero() {
177 return None; }
179 q
180 };
181 a = add_zk_pow(&a, &sig, k);
182 b = add_zk_pow(&b, &tau, k);
183 }
184 k += 1;
185 }
186 let prod = a.mul(&b);
187 if target.sub(&prod).is_zero() {
188 Some((a, b))
189 } else {
190 None
191 }
192}
193
194fn hensel_all_bivar(
196 target: &Poly<Rational>,
197 facs: &[Poly<Rational>],
198 k_max: u32,
199 ring_v: &Arc<PolyRing>,
200) -> Option<Vec<Poly<Rational>>> {
201 if facs.len() == 1 {
202 return Some(vec![target.clone()]);
203 }
204 let mid = facs.len() / 2;
205 let (left, right) = facs.split_at(mid);
206 let a0 = left.iter().cloned().reduce(|x, y| x.mul(&y)).unwrap();
207 let b0 = right.iter().cloned().reduce(|x, y| x.mul(&y)).unwrap();
208 let (_, s, t) = rat_xgcd1(&a0, &b0);
209 let (al, br) = hensel2_bivar(target, &a0, &b0, &s, &t, k_max, ring_v)?;
210 let mut out = hensel_all_bivar(&al, left, k_max, ring_v)?;
211 out.extend(hensel_all_bivar(&br, right, k_max, ring_v)?);
212 Some(out)
213}
214
215fn factor_sqfree_bivar(s: &Poly<Rational>) -> Vec<Poly<Rational>> {
219 let ring_v = PolyRing::new([s.ring().vars[0].to_string()], crate::MonOrder::DegRevLex);
220 let deg_v = s.terms().map(|(e, _)| e[0]).max().unwrap_or(0);
221 let deg_z = s.terms().map(|(e, _)| e[1]).max().unwrap_or(0);
222 if deg_v == 0 {
223 return vec![s.clone()];
225 }
226 for c in [0i64, 1, -1, 2, -2, 3, -3, 5, -5, 7, -7] {
228 let st = shift_z(s, c);
229 let f0 = coeff_zk(&st, &ring_v, 0);
230 if f0.is_zero() || f0.degree() < deg_v as u64 {
231 continue;
232 }
233 let df0 = f0.deriv(0);
234 if !f0.gcd(&df0).is_constant() {
235 continue;
236 }
237 let (cont0, facs0) = f0.factor_univariate();
238 if facs0.len() <= 1 {
239 return vec![s.clone()]; }
241 let mut facs_only: Vec<Poly<Rational>> = facs0.iter().map(|(g, _)| g.clone()).collect();
244 if !cont0.is_one() {
245 if let Some(first) = facs_only.first_mut() {
246 *first = first.mul(&Poly::constant(ring_v.clone(), cont0));
247 }
248 }
249 let k_max = deg_z + 4;
250 let Some(lifted) = hensel_all_bivar(&st, &facs_only, k_max, &ring_v) else {
251 continue; };
253 let r = lifted.len();
255 if r > 16 {
256 return vec![s.clone()];
257 }
258 let mut masks: Vec<u64> = (1..(1u64 << (r - 1))).collect();
259 masks.sort_by_key(|m| m.count_ones());
260 let mut factors: Vec<Poly<Rational>> = vec![];
261 let mut used = vec![false; r];
262 let mut f_cur = st.clone();
263 loop {
264 let mut found = false;
265 for &mask in &masks {
266 if (0..r - 1).any(|i| mask >> i & 1 == 1 && used[i]) {
267 continue;
268 }
269 let mut cand = Poly::constant(s.ring().clone(), Rational::one());
270 for (i, g) in lifted.iter().enumerate().take(r - 1) {
271 if mask >> i & 1 == 1 {
272 cand = cand.mul(g);
273 }
274 }
275 let pp = cand.normalize_primitive();
276 if pp.is_constant() || pp.degree() > f_cur.degree() {
277 continue;
278 }
279 if let Some(q) = f_cur.exact_div(&pp) {
280 factors.push(shift_z(&pp, -c));
281 f_cur = q;
282 for (i, u) in used.iter_mut().enumerate().take(r - 1) {
283 if mask >> i & 1 == 1 {
284 *u = true;
285 }
286 }
287 found = true;
288 break;
289 }
290 }
291 if !found {
292 break;
293 }
294 }
295 if !f_cur.is_constant() {
296 factors.push(shift_z(&f_cur, -c));
297 }
298 if factors.len() >= 2 {
299 return factors;
300 }
301 }
303 vec![s.clone()]
304}
305
306impl Poly<Rational> {
309 pub fn factor(&self) -> (Rational, Vec<(Self, u32)>) {
313 if self.ring().nvars() == 1 {
314 return self.factor_univariate();
315 }
316 if self.is_zero() {
317 return (Rational::zero(), vec![]);
318 }
319 let pp = self.normalize_primitive();
321 let cont = if pp.is_constant() {
322 self.terms().next().unwrap().1.clone()
323 } else {
324 let (e0, c_self) = self.terms().last().unwrap();
326 let c_pp = pp
327 .terms()
328 .find(|(e, _)| e == &e0)
329 .map(|(_, c)| c.clone())
330 .unwrap_or_else(Rational::one);
331 c_self.div(&c_pp).unwrap_or_else(Rational::one)
332 };
333 if pp.is_constant() {
334 return (cont, vec![]);
335 }
336 let ring = self.ring().clone();
338 let ring0 = PolyRing::new(ring.vars[1..].iter().map(|v| v.to_string()), ring.order);
339 let uni = Uni::from_poly(&pp, &ring0);
340 let c_poly = uni.content();
341 let mut factors: Vec<(Self, u32)> = vec![];
342 if !c_poly.is_constant() {
343 let (_cc, sub) = c_poly.factor();
344 for (g, m) in sub {
345 factors.push((embed_tail(&g, &ring), m));
346 }
347 }
348 let pp0 = uni.exact_div_content(&c_poly).to_poly(ring.clone());
349 for (sp, m) in squarefree_parts(&pp0) {
351 if sp.is_constant() {
352 continue;
353 }
354 let deg_v = sp.terms().map(|(e, _)| e[0]).max().unwrap_or(0);
355 let sub = if ring.nvars() == 2 && deg_v > 0 {
356 factor_sqfree_bivar(&sp)
357 } else if deg_v == 0 {
358 let (_cc, sub) = strip_var0(&sp).factor();
360 let mut out: Vec<Poly<Rational>> = vec![];
361 for (g, _mm) in sub {
362 out.push(embed_tail(&g, &ring));
363 }
364 out
365 } else {
366 vec![sp.clone()] };
368 for g in sub {
369 factors.push((g, m));
370 }
371 }
372 factors.sort_by(|a, b| {
373 let da = a.0.degree();
374 let db = b.0.degree();
375 da.cmp(&db).then_with(|| a.1.cmp(&b.1))
376 });
377 (cont, factors)
378 }
379}
380
381fn strip_var0(p: &Poly<Rational>) -> Poly<Rational> {
383 let ring0 = PolyRing::new(
384 p.ring().vars[1..].iter().map(|v| v.to_string()),
385 p.ring().order,
386 );
387 let items: Vec<(Vec<u32>, Rational)> = p
388 .terms()
389 .map(|(e, c)| {
390 debug_assert_eq!(e[0], 0);
391 (e[1..].to_vec(), c.clone())
392 })
393 .collect();
394 Poly::from_terms(ring0, items)
395}
396
397fn embed_tail(p: &Poly<Rational>, ring: &Arc<PolyRing>) -> Poly<Rational> {
399 let items: Vec<(Vec<u32>, Rational)> = p
400 .terms()
401 .map(|(e, c)| {
402 let mut full = vec![0u32; ring.nvars()];
403 full[1..].copy_from_slice(e);
404 (full, c.clone())
405 })
406 .collect();
407 Poly::from_terms(ring.clone(), items)
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413
414 fn ring(names: &[&str]) -> Arc<PolyRing> {
415 PolyRing::new(names.iter().copied(), crate::MonOrder::DegRevLex)
416 }
417
418 fn from_i_terms(ringv: &Arc<PolyRing>, terms: &[(Vec<u32>, i64)]) -> Poly<Rational> {
419 let items: Vec<(Vec<u32>, Rational)> = terms
420 .iter()
421 .filter(|(_, c)| *c != 0)
422 .map(|(e, c)| {
423 (
424 e.clone(),
425 Rational::from_ints(&Integer::from_i64(*c), &Integer::one()).unwrap(),
426 )
427 })
428 .collect();
429 Poly::from_terms(ringv.clone(), items)
430 }
431
432 fn check_refold(f: &Poly<Rational>) {
433 let (cont, facs) = f.factor();
434 let mut prod = Poly::constant(f.ring().clone(), cont);
435 for (g, m) in &facs {
436 prod = prod.mul(&g.pow(*m));
437 }
438 assert_eq!(&prod, f, "重展开不等于原式: f={f:?}");
439 }
440
441 #[test]
442 fn 双变元_已知分解() {
443 let r2 = ring(&["x", "y"]);
444 let f = from_i_terms(&r2, &[(vec![2, 0], 1), (vec![0, 2], -1)]);
446 let (_, facs) = f.factor();
447 assert_eq!(facs.len(), 2, "{facs:?}");
448 check_refold(&f);
449
450 let f = from_i_terms(&r2, &[(vec![2, 0], 1), (vec![0, 2], 1)]);
452 let (_, facs) = f.factor();
453 assert_eq!(facs.len(), 1);
454
455 let f = from_i_terms(
457 &r2,
458 &[
459 (vec![4, 0], 1),
460 (vec![3, 1], 2),
461 (vec![2, 2], 3),
462 (vec![1, 3], 4),
463 (vec![0, 4], 2),
464 ],
465 );
466 let (c, facs) = f.factor();
467 let mut prod = Poly::constant(r2.clone(), c);
468 for (g, m) in &facs {
469 prod = prod.mul(&g.pow(*m));
470 }
471 assert_eq!(prod, f);
472 assert_eq!(facs.len(), 2, "{facs:?}");
473 }
474
475 #[test]
476 fn 定点_r3() {
477 let r2 = ring(&["x", "y"]);
478 let f = from_i_terms(
480 &r2,
481 &[
482 (vec![3, 0], 1),
483 (vec![2, 1], 6),
484 (vec![1, 2], 11),
485 (vec![0, 3], 6),
486 ],
487 );
488 let (c, facs) = f.factor();
489 eprintln!("cont={c:?} n={}", facs.len());
490 for (g, m) in &facs {
491 eprintln!(" deg={} m={m}", g.degree());
492 }
493 assert!(facs.len() >= 3, "r=3 应完全分解: {facs:?}");
494 }
495
496 #[test]
497 fn 双变元_随机积() {
498 let mut det = crate::factor::Det::new();
499 let r2 = ring(&["x", "y"]);
500 for _ in 0..120 {
501 let nf = 2 + det.next() % 2;
502 let mut f = Poly::constant(r2.clone(), Rational::one());
503 for _ in 0..nf {
504 let nt = 1 + det.next() % 3;
507 let mut terms = vec![];
508 for _ in 0..nt {
509 let r = det.next();
510 terms.push((
511 vec![(r % 3) as u32, ((r >> 8) % 3) as u32],
512 ((r >> 16) % 11) as i64 - 5,
513 ));
514 }
515 let g = from_i_terms(&r2, &terms);
516 if g.is_zero() {
517 continue;
518 }
519 f = f.mul(&g);
520 }
521 let scale = Rational::from_ints(
522 &Integer::from_i64((det.next() % 7) as i64 - 3),
523 &Integer::from_i64(1 + (det.next() % 5) as i64),
524 )
525 .unwrap();
526 let f = f.mul(&Poly::constant(r2.clone(), scale));
527 if !f.is_zero() && !f.is_constant() {
528 check_refold(&f);
529 }
530 }
531 }
532
533 #[test]
534 fn 三变元_部分分解与恒等() {
535 let r3 = ring(&["x", "y", "z"]);
536 let g1 = from_i_terms(
538 &r3,
539 &[(vec![1, 0, 0], 1), (vec![0, 1, 0], 1), (vec![0, 0, 1], 1)],
540 );
541 let g2 = from_i_terms(&r3, &[(vec![1, 0, 0], 1), (vec![0, 1, 0], 2)]);
542 let f = g1.pow(2).mul(&g2);
543 let (c, facs) = f.factor();
544 let mut prod = Poly::constant(r3.clone(), c);
545 for (g, m) in &facs {
546 prod = prod.mul(&g.pow(*m));
547 }
548 assert_eq!(prod, f, "≥3 变元:恒等必须保持");
549 }
550}