Skip to main content

cas_poly/
factor_mv.rs

1//! 多变元因式分解(M5,设计 §5/D3)。
2//!
3//! 路由:
4//! - 1 变元 → M4(factor_univariate);
5//! - 2 变元 → **完全分解**:确定性平移搜索 z→z+c 取好赋值点,f₀ = S(v,0)
6//!   用 M4 分解,然后 **模 z^k 的线性 Hensel**(系数环 ℚ[v],与 M4 的 𝔽_p
7//!   版同构:模 p^k → 模 z^k,截断 = 丢弃 z 次数 ≥ k 的项)逐层提升至
8//!   ΠH_i 与目标**精确相等**(E==0 提前退出;无 monic 化、无 lc 幂吸收
9//!   ——整系数目标直接提升,子集积的精确性使组合仅需 pp+试除);
10//! - ≥3 变元 → 部分分解:ℚ 内容 + 主变元多项式内容(递归分解)+ 多变元
11//!   Yun 平方自由;完全分解(Wang EEZ 逐变元提升)挂 M5b。
12//!
13//! 确定性:平移常数按固定表顺序尝试,组合按子集基数升序——同输入恒得
14//! 同输出。
15
16use crate::factor::squarefree_parts;
17use crate::gcd::Uni;
18use crate::{Poly, PolyRing};
19use cas_domain::{Integer, Rational};
20use std::sync::Arc;
21
22// ── 2 变元辅助(vars = [v, z]:e[0]=v 次数,e[1]=z 次数)─────────
23
24/// z 次数恰为 k 的项 → ℚ[v](ring_v 为单变元环)。
25fn 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
34/// base + z^k·p(p ∈ ℚ[v] 嵌入为 z 次数 k)。
35fn 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
51/// z → z + c(单项式二项式展开;c=0 原样)。
52fn 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        // z^n → Σ_j C(n,j)·c^{n-j}·z^j
61        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
81/// ℚ[v] 上单变元带余除法(div_rem 域版在单变元环上即普通除法)。
82fn 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
87/// ℚ[v] 扩展 Euclid:(monic g, s, t),s·a + t·b = g。
88fn 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    // monic 归一
114    let lc = match r0.terms().last() {
115        Some((_, c)) => c.clone(),
116        None => return (r0, s0, t0), // a=b=0 不会出现
117    };
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
127// ── 双变元 Hensel(模 z^k,线性,二叉树)───────────────────────
128
129/// 两因子提升:Π(a0,b0) ≡ target (mod z);逐层至 Π ≡ target (mod z^k)。
130/// k 逐层递增,每当 k 超过目标的 z 次数即检查精确相等并提前退出。
131fn hensel2_bivar(
132    target: &Poly<Rational>, // ℚ[v,z],整系数
133    a0: &Poly<Rational>,     // ℚ[v](z=0 视角的因子)
134    b0: &Poly<Rational>,     // ℚ[v]
135    _s: &Poly<Rational>,     // 贝祖:s·a0 + t·b0 = 1(此公式只用 t)
136    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)); // 精确相等,提前退出
159        }
160        // 验证 err ∈ z^k:低次项必须为零
161        if err_full.terms().any(|(e, _)| e[1] < k) {
162            return None; // 不变量破坏:保守放弃
163        }
164        if k > deg_z_target + 1 {
165            return None; // 超界仍不精确:视为提升失败
166        }
167        let err = coeff_zk(&err_full, ring_v, k); // err/z^k 的 z^0 系数
168        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; // 校正整除性破坏
178                }
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
194/// 多因子二叉树提升。叶子次序与 facs 一致;返回精确因子(Π = target)。
195fn 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
215// ── 双变元平方自由部分的完全分解 ──────────────────────────────
216
217/// S:2 变元、整系数本原、关于 v 平方自由。返回不可约因子(本原、首项正)。
218fn 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        // 不含主变元:作为 ℚ[z] 单变元分解(由调用方递归处理,此处分流)
224        return vec![s.clone()];
225    }
226    // 确定性平移搜索好点:f0 次数保持 + 平方自由
227    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()]; // f0 不可约 ⇒ S 不可约
240        }
241        // M4 输出分离了 ℚ 常数内容:必须乘回,否则 Π 因子与 f0 差常数,
242        // Hensel 起点 mod z 不变量破坏(x²−y² 整体误判不可约的根因)
243        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; // 提升失败:换平移点
252        };
253        // 子集组合(基数升序;Π lifted 精确 = st,子集积 pp 后试除即真因子)
254        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        // 单因子:尝试下一平移点(或最终保守)
302    }
303    vec![s.clone()]
304}
305
306// ── 总控 ──────────────────────────────────────────────────────
307
308impl Poly<Rational> {
309    /// 多变元因式分解:返回(ℚ 常数内容, [(本原因子, 重数)]),
310    /// cont·Π 因子^重数 == self。1 变元完全;2 变元完全;≥3 变元
311    /// 部分分解(内容 + 平方自由;因子可能仍可约)。
312    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        // ℚ 内容 + 整系数本原化(首项正)
320        let pp = self.normalize_primitive();
321        let cont = if pp.is_constant() {
322            self.terms().next().unwrap().1.clone()
323        } else {
324            // 找 pp 与 self 的同次项系数比
325            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        // 主变元多项式内容(递归分解)
337        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        // 多变元 Yun(关于 var0)
350        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                // 不含主变元:递归到剩余变元环
359                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()] // ≥3 变元:部分分解
367            };
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
381/// 去掉第 0 个变元(指数 e[0] 恒为 0 的断言下重排)。
382fn 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
397/// 少一变元的多项式回嵌到全环(前插 0 指数)。
398fn 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        // x^2 − y^2 = (x−y)(x+y)
445        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        // x^2 + y^2 在 ℚ 上不可约
451        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        // (x + y)^2·(x^2 + 2y^2) = x⁴ + 2x³y + 3x²y² + 4xy³ + 2y⁴
456        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        // (x + y)(x + 2y)(x + 3y):3 个关于 x 的 1 次因子
479        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                // 指数 ≤ 2:底层 PRS 在高次上有系数膨胀问题(子结果式
505                // 修复挂 M5b,见 DESIGN §18),中低次下功能完全验证
506                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        // (x + y + z)^2·(x + 2y):内容/重数至少分离
537        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}