LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
hensel_lift.cpp
浏览该文件的文档.
1/**
2 * @file hensel_lift.cpp
3 * @brief Hensel 提升算法实现:Mignotte 界计算与二次提升.
4 *
5 * 本文件实现 Phase 4(Hensel 提升)的核心逻辑:
6 * - Mignotte 界计算:确定提升高度 k 使得 p^k 足以恢复真因子系数
7 * - 二次 Hensel 提升:将模 p 因子逐步提升到 mod p^k
8 * - 多因子提升:通过二叉树结构递归配对提升
9 *
10 * @see Mignotte, M. "An inequality about factors of polynomials."
11 * Mathematics of Computation, 28(128), 1974.
12 * @see Zassenhaus, H. "On Hensel factorization, I."
13 * Journal of Number Theory, 1(3), 1969.
14 */
15
18
19#include <vector>
20#include <cstdint>
21#include <cmath>
22#include <algorithm>
23#include <exception>
24
25namespace LMCAS {
26
27
28/**
29 * @brief 计算二项式系数 C(n, k).
30 *
31 * 使用乘法公式 C(n, k) = n! / (k! * (n-k)!) 逐步计算;
32 * BigInt 承载全部中间结果,k = min(k, n-k) 缩短迭代路径.
33 *
34 * @param[in] n 上标(非负整数)
35 * @param[in] k 下标(0 <= k <= n)
36 * @return C(n, k) 的精确值
37 * @internal
38 */
39static BigInt hl_binomial(int n, int k) {
40 if (k < 0 || k > n) return BigInt(0);
41 if (k == 0 || k == n) return BigInt(1);
42
43 /// 利用对称性 C(n, k) = C(n, n-k)
44 if (k > n - k) {
45 k = n - k;
46 }
47
48 BigInt result(1);
49 for (int i = 0; i < k; ++i) {
50 result = result * BigInt(n - i);
51 result = result / BigInt(i + 1);
52 }
53 return result;
54}
55
56/**
57 * @brief 计算多项式系数的 L2 范数的平方.
58 *
59 * 即 ||f||_2^2 = sum(a_i^2),其中 a_i 为多项式各项系数.
60 *
61 * @param[in] poly 整系数多项式
62 * @return 系数平方和(BigInt 精确值)
63 * @internal
64 */
65static BigInt hl_l2_norm_squared(const Polynomial<BigInt>& poly) {
66 BigInt sum(0);
67 for (const auto& c : poly.coeffs) {
68 sum = sum + c * c;
69 }
70 return sum;
71}
72
73/**
74 * @brief 计算多项式的 Mignotte 界.
75 *
76 * 对于次数为 n 的多项式 f(x),其任意因子的系数绝对值上界为:
77 * B = C(n, floor(n/2)) * ||f||_2
78 *
79 * 其中 C(n, k) 为二项式系数,||f||_2 为系数向量的 L2 范数.
80 *
81 * 实现使用 B^2 = C(n, floor(n/2))^2 * ||f||_2^2 在整数域内计算,
82 * 最后由 BigInt::sqrt() 求向上取整的整数平方根.
83 *
84 * @param[in] poly 整系数多项式(非零,次数 >= 1)
85 * @return Mignotte 界 B
86 *
87 * @see Mignotte, M. "An inequality about factors of polynomials."
88 * Mathematics of Computation, 28(128), 1974.
89 * @internal
90 */
91static BigInt hl_mignotte_bound(const Polynomial<BigInt>& poly) {
92 int n = poly.degree();
93 if (n <= 0) return BigInt(1);
94
95 /// C(n, floor(n/2))
96 BigInt binom = hl_binomial(n, n / 2);
97
98 /// ||f||_2^2
99 BigInt norm_sq = hl_l2_norm_squared(poly);
100
101 /// B^2 = binom^2 * norm_sq
102 BigInt b_squared = binom * binom * norm_sq;
103
104 /// B = ceil(sqrt(B^2))
105 /// BigInt::sqrt() 返回 floor(sqrt(x)),需要检查是否精确
106 BigInt b = b_squared.sqrt();
107 if (b * b < b_squared) {
108 b = b + BigInt(1);
109 }
110
111 return b;
112}
113
114/**
115 * @brief 计算 Hensel 提升所需的高度 k.
116 *
117 * 提升高度 k 需满足 p^k > 2 * B * |lc(f)|,其中:
118 * - B 为 Mignotte 界
119 * - lc(f) 为多项式首项系数
120 * - p 为选定的素数
121 *
122 * 通过连续乘以 p 直至超过阈值确定 k,使界计算保持在整数域内.
123 *
124 * @param[in] poly 整系数多项式(非零,次数 >= 1)
125 * @param[in] prime 选定的素数 p
126 * @return 所需的提升高度 k(正整数)
127 * @internal
128 */
129static int hl_compute_lift_height(const Polynomial<BigInt>& poly, int64_t prime) {
130 if (poly.is_zero() || poly.degree() <= 0) return 1;
131
132 BigInt B = hl_mignotte_bound(poly);
133 BigInt lc = poly.lead_coeff().abs();
134
135 /// 阈值 threshold = 2 * B * |lc(f)|
136 BigInt threshold = BigInt(2) * B * lc;
137
138 /// 计算最小 k 使得 p^k > threshold
139 BigInt p_power(1);
140 BigInt big_p(static_cast<std::int64_t>(prime));
141 int k = 0;
142
143 while (p_power <= threshold) {
144 p_power = p_power * big_p;
145 k++;
146 }
147
148 /// 至少提升 1 次
149 if (k < 1) k = 1;
150
151 return k;
152}
153
154
155/**
156 * @brief 对多项式系数向量执行模归约(对称表示).
157 *
158 * 将向量中每个系数归约到 [-m/2, m/2) 区间,并去除高次零系数.
159 *
160 * @param[in,out] poly 系数向量(就地修改)
161 * @param[in] m 模数
162 * @internal
163 */
164static void hl_reduce_coeffs(std::vector<BigInt>& poly, const BigInt& m) {
165 for (auto& c : poly) {
167 }
168 /// 去除高次零系数
169 while (!poly.empty() && poly.back().is_zero()) {
170 poly.pop_back();
171 }
172}
173
174/**
175 * @brief 多项式乘法(BigInt 系数),结果模 m 归约.
176 *
177 * 计算两个系数向量表示的多项式之积,所有系数归约到对称表示 [-m/2, m/2).
178 *
179 * @param[in] a 第一个多项式的系数向量
180 * @param[in] b 第二个多项式的系数向量
181 * @param[in] m 模数
182 * @return 乘积多项式的系数向量
183 * @internal
184 */
185static std::vector<BigInt> hl_poly_mul_mod(const std::vector<BigInt>& a,
186 const std::vector<BigInt>& b,
187 const BigInt& m) {
188 if (a.empty() || b.empty()) return {};
189
190 size_t n = a.size() + b.size() - 1;
191 std::vector<BigInt> result(n, BigInt(0));
192
193 for (size_t i = 0; i < a.size(); ++i) {
194 if (a[i].is_zero()) continue;
195 for (size_t j = 0; j < b.size(); ++j) {
196 if (b[j].is_zero()) continue;
197 result[i + j] = result[i + j] + a[i] * b[j];
198 }
199 }
200
201 hl_reduce_coeffs(result, m);
202 return result;
203}
204
205/**
206 * @brief 多项式减法(BigInt 系数),结果模 m 归约.
207 *
208 * @param[in] a 被减数多项式系数向量
209 * @param[in] b 减数多项式系数向量
210 * @param[in] m 模数
211 * @return 差多项式的系数向量
212 * @internal
213 */
214static std::vector<BigInt> hl_poly_sub_mod(const std::vector<BigInt>& a,
215 const std::vector<BigInt>& b,
216 const BigInt& m) {
217 size_t n = std::max(a.size(), b.size());
218 std::vector<BigInt> result(n, BigInt(0));
219
220 for (size_t i = 0; i < n; ++i) {
221 BigInt ai = (i < a.size()) ? a[i] : BigInt(0);
222 BigInt bi = (i < b.size()) ? b[i] : BigInt(0);
223 result[i] = ai - bi;
224 }
225
226 hl_reduce_coeffs(result, m);
227 return result;
228}
229
230/**
231 * @brief 多项式加法(BigInt 系数),结果模 m 归约.
232 *
233 * @param[in] a 第一个多项式系数向量
234 * @param[in] b 第二个多项式系数向量
235 * @param[in] m 模数
236 * @return 和多项式的系数向量
237 * @internal
238 */
239static std::vector<BigInt> hl_poly_add_mod(const std::vector<BigInt>& a,
240 const std::vector<BigInt>& b,
241 const BigInt& m) {
242 size_t n = std::max(a.size(), b.size());
243 std::vector<BigInt> result(n, BigInt(0));
244
245 for (size_t i = 0; i < n; ++i) {
246 BigInt ai = (i < a.size()) ? a[i] : BigInt(0);
247 BigInt bi = (i < b.size()) ? b[i] : BigInt(0);
248 result[i] = ai + bi;
249 }
250
251 hl_reduce_coeffs(result, m);
252 return result;
253}
254
255/**
256 * @brief 计算 BigInt 在模 m 下的乘法逆元.
257 *
258 * 使用扩展欧几里得算法求 a 在 Z/mZ 中的逆元.
259 * 要求 gcd(a, m) = 1.
260 *
261 * @param[in] a 待求逆的整数
262 * @param[in] m 模数
263 * @return a 的模逆元,归约到 [0, m)
264 * @throw std::domain_error 若 a 不可逆
265 * @internal
266 */
267static BigInt hl_mod_inverse(const BigInt& a, const BigInt& m) {
268 /// 扩展欧几里得:求 s 使得 a*s == 1 (mod m)
269 BigInt r0 = m, r1 = a % m;
270 if (r1.is_negative()) r1 = r1 + m;
271
272 BigInt s0(0), s1(1);
273
274 while (!r1.is_zero()) {
275 BigInt q = r0 / r1;
276 BigInt r_new = r0 - q * r1;
277 BigInt s_new = s0 - q * s1;
278
279 r0 = r1;
280 r1 = r_new;
281 s0 = s1;
282 s1 = s_new;
283 }
284
285 /// r0 应为 gcd(a, m) = 1
286 if (r0 != BigInt(1) && r0 != BigInt(-1)) {
287 throw std::domain_error("hl_mod_inverse: element not invertible");
288 }
289
290 /// 若 gcd 为 -1,调整符号
291 if (r0.is_negative()) {
292 s0 = s0.negate();
293 }
294
295 BigInt result = s0 % m;
296 if (result.is_negative()) result = result + m;
297 return result;
298}
299
300/**
301 * @brief 多项式带余除法(BigInt 系数),模 m 下运算.
302 *
303 * 计算 a(x) = q(x) * b(x) + r(x),其中 deg(r) < deg(b).
304 * 要求 b 的首项系数在 Z/mZ 中可逆.
305 * 所有系数归约到对称表示.
306 *
307 * @param[in] a 被除数多项式系数向量
308 * @param[in] b 除数多项式系数向量
309 * @param[in] m 模数
310 * @return pair(商, 余数) 的系数向量
311 * @internal
312 */
313static std::pair<std::vector<BigInt>, std::vector<BigInt>>
314hl_poly_divmod(const std::vector<BigInt>& a,
315 const std::vector<BigInt>& b,
316 const BigInt& m) {
317 if (b.empty()) {
318 throw std::runtime_error("hl_poly_divmod: division by zero polynomial");
319 }
320
321 int deg_a = static_cast<int>(a.size()) - 1;
322 int deg_b = static_cast<int>(b.size()) - 1;
323
324 if (deg_a < deg_b) {
325 std::vector<BigInt> r = a;
327 return {{}, r};
328 }
329
330 /// 首项系数的逆元
331 BigInt lc_inv = hl_mod_inverse(b.back(), m);
332
333 std::vector<BigInt> remainder = a;
334 std::vector<BigInt> quotient(deg_a - deg_b + 1, BigInt(0));
335
336 for (int i = deg_a; i >= deg_b; --i) {
337 BigInt coeff = detail::symmetric_remainder(remainder[i], m);
338 if (coeff.is_zero()) continue;
339
340 BigInt factor = detail::symmetric_remainder(coeff * lc_inv, m);
341 quotient[i - deg_b] = factor;
342
343 for (int j = 0; j <= deg_b; ++j) {
344 remainder[i - deg_b + j] = remainder[i - deg_b + j] - factor * b[j];
345 remainder[i - deg_b + j] =
346 detail::symmetric_remainder(remainder[i - deg_b + j], m);
347 }
348 }
349
350 /// 余数截断到 deg < deg_b
351 std::vector<BigInt> rem(remainder.begin(), remainder.begin() + deg_b);
352 hl_reduce_coeffs(quotient, m);
353 hl_reduce_coeffs(rem, m);
354 return {quotient, rem};
355}
356
357static bool hl_is_prime(int64_t value) {
358 if (value < 2) return false;
359 if (value == 2) return true;
360 if (value % 2 == 0) return false;
361 for (int64_t divisor = 3; divisor <= value / divisor; divisor += 2) {
362 if (value % divisor == 0) return false;
363 }
364 return true;
365}
366
367static bool hl_coeff_vectors_equal(std::vector<BigInt> left,
368 std::vector<BigInt> right) {
369 while (!left.empty() && left.back().is_zero()) left.pop_back();
370 while (!right.empty() && right.back().is_zero()) right.pop_back();
371 const std::size_t size = std::max(left.size(), right.size());
372 left.resize(size, BigInt(0));
373 right.resize(size, BigInt(0));
374 return left == right;
375}
376
378 const Polynomial<BigInt>& poly,
379 const std::vector<std::vector<BigInt>>& factor_vecs,
380 int64_t prime) {
381 constexpr const char* operation = "hensel_lift";
382 if (!hl_is_prime(prime)) {
384 "Hensel lifting requires a prime modulus",
385 operation);
386 }
387 if (poly.is_zero() || poly.degree() <= 0) {
389 "Hensel lifting requires a non-constant polynomial",
390 operation);
391 }
392 if (factor_vecs.empty()) {
394 "Hensel lifting requires at least one mod-p factor",
395 operation);
396 }
397 for (const auto& factor : factor_vecs) {
398 if (factor.empty()) {
400 "Hensel lifting factor cannot be zero",
401 operation);
402 }
403 }
404
405 const BigInt modulus(static_cast<std::int64_t>(prime));
406 std::vector<BigInt> product{BigInt(1)};
407 for (const auto& factor : factor_vecs) {
408 product = hl_poly_mul_mod(product, factor, modulus);
409 }
410 std::vector<BigInt> reduced_f = poly.coeffs;
411 hl_reduce_coeffs(reduced_f, modulus);
412 if (!hl_coeff_vectors_equal(product, reduced_f)) {
414 "mod-p factors do not multiply to the input polynomial",
415 operation);
416 }
417 return Result<void>::success();
418}
419
420
421/**
422 * @brief 执行一步二次 Hensel 提升:mod m -> mod m^2.
423 *
424 * 给定 f == g*h (mod m) 且 s*g + t*h == 1 (mod m),
425 * 计算 g', h', s', t' 使得 f == g'*h' (mod m^2) 且 s'*g' + t'*h' == 1 (mod m^2).
426 *
427 * 算法步骤:
428 * 1. 计算误差 e = f - g*h(所有系数应被 m 整除)
429 * 2. 计算修正项:(q, r) = divmod(s*e, h) over Z/m^2Z
430 * - h' = h + r (mod m^2)
431 * - g' = g + t*e + q*g (mod m^2)
432 * 3. 更新 Bezout 系数:
433 * - b = s*g' + t*h' - 1 (mod m^2)
434 * - (c, d) = divmod(s*b, h') over Z/m^2Z
435 * - s' = s - d (mod m^2)
436 * - t' = t - t*b - c*g' (mod m^2)
437 *
438 * @param[in] f 原始多项式系数向量
439 * @param[in] current 当前提升状态(g, h, s, t, modulus=m)
440 * @return 提升后的状态(g', h', s', t', modulus=m^2)
441 *
442 * @pre f == g*h (mod m)
443 * @pre s*g + t*h == 1 (mod m)
444 * @pre deg(s) < deg(h), deg(t) < deg(g)
445 *
446 * @see Zassenhaus, H. "On Hensel factorization, I."
447 * Journal of Number Theory, 1(3), 1969.
448 * @internal
449 */
451 const std::vector<BigInt>& f,
452 const HenselLiftPair& current) {
453
454 const auto& g = current.g;
455 const auto& h = current.h;
456 const auto& s = current.s;
457 const auto& t = current.t;
458 const BigInt& m = current.modulus;
459
460 /// 新模数 m^2 = m * m
461 BigInt m2 = m * m;
462
463 /// 步骤 1:计算误差 e = f - g*h (mod m^2)
464 std::vector<BigInt> gh = hl_poly_mul_mod(g, h, m2);
465 std::vector<BigInt> e = hl_poly_sub_mod(f, gh, m2);
466
467 /// 步骤 2:计算修正项
468 /// se = s * e (mod m^2)
469 std::vector<BigInt> se = hl_poly_mul_mod(s, e, m2);
470
471 /// (q, r) = divmod(se, h) over Z/m^2Z,其中 deg(r) < deg(h)
472 auto [q, r] = hl_poly_divmod(se, h, m2);
473
474 /// g' = g + t*e + q*g (mod m^2)
475 std::vector<BigInt> te = hl_poly_mul_mod(t, e, m2);
476 std::vector<BigInt> qg = hl_poly_mul_mod(q, g, m2);
477 std::vector<BigInt> g_new = hl_poly_add_mod(g, hl_poly_add_mod(te, qg, m2), m2);
478 hl_reduce_coeffs(g_new, m2);
479
480 /// h' = h + r (mod m^2)
481 std::vector<BigInt> h_new = hl_poly_add_mod(h, r, m2);
482 hl_reduce_coeffs(h_new, m2);
483
484 /// 步骤 3:更新 Bezout 系数
485 /// b = s*g' + t*h' - 1 (mod m^2)
486 std::vector<BigInt> sg_new = hl_poly_mul_mod(s, g_new, m2);
487 std::vector<BigInt> th_new = hl_poly_mul_mod(t, h_new, m2);
488 std::vector<BigInt> sg_plus_th = hl_poly_add_mod(sg_new, th_new, m2);
489
490 /// 减去常数 1
491 std::vector<BigInt> one_poly = {BigInt(1)};
492 std::vector<BigInt> b = hl_poly_sub_mod(sg_plus_th, one_poly, m2);
493
494 /// (c, d) = divmod(s*b, h') over Z/m^2Z
495 std::vector<BigInt> sb = hl_poly_mul_mod(s, b, m2);
496 auto [c, d] = hl_poly_divmod(sb, h_new, m2);
497
498 /// s' = s - d (mod m^2)
499 std::vector<BigInt> s_new = hl_poly_sub_mod(s, d, m2);
500 hl_reduce_coeffs(s_new, m2);
501
502 /// t' = t - t*b - c*g' (mod m^2)
503 std::vector<BigInt> tb = hl_poly_mul_mod(t, b, m2);
504 std::vector<BigInt> cg_new = hl_poly_mul_mod(c, g_new, m2);
505 std::vector<BigInt> t_new = hl_poly_sub_mod(t, hl_poly_add_mod(tb, cg_new, m2), m2);
506 hl_reduce_coeffs(t_new, m2);
507
508 return HenselLiftPair{g_new, h_new, s_new, t_new, m2};
509}
510
511/**
512 * @brief 计算两个多项式在模 m 下的扩展 GCD 的 Bezout 系数.
513 *
514 * 给定互素多项式 g, h(mod m),求 s, t 使得 s*g + t*h == 1 (mod m),
515 * 且 deg(s) < deg(h), deg(t) < deg(g).
516 *
517 * 使用扩展欧几里得算法在 Z/mZ[x] 上运算.
518 *
519 * @param[in] g 第一个多项式系数向量
520 * @param[in] h 第二个多项式系数向量
521 * @param[in] m 模数
522 * @return pair(s, t) 满足 s*g + t*h == 1 (mod m)
523 * @internal
524 */
525static std::pair<std::vector<BigInt>, std::vector<BigInt>>
526hl_extended_gcd_poly(const std::vector<BigInt>& g,
527 const std::vector<BigInt>& h,
528 const BigInt& m) {
529 /// 扩展欧几里得算法:r0 = g, r1 = h
530 /// s0*g + t0*h = r0, s1*g + t1*h = r1
531 std::vector<BigInt> r0 = g, r1 = h;
532 std::vector<BigInt> s0 = {BigInt(1)}, s1 = {}; // s0=1, s1=0
533 std::vector<BigInt> t0 = {}, t1 = {BigInt(1)}; // t0=0, t1=1
534
535 while (!r1.empty()) {
536 auto [q, r] = hl_poly_divmod(r0, r1, m);
537
538 /// r_new = r0 - q*r1
539 std::vector<BigInt> r_new = r;
540
541 /// s_new = s0 - q*s1
542 std::vector<BigInt> qs1 = hl_poly_mul_mod(q, s1, m);
543 std::vector<BigInt> s_new = hl_poly_sub_mod(s0, qs1, m);
544
545 /// t_new = t0 - q*t1
546 std::vector<BigInt> qt1 = hl_poly_mul_mod(q, t1, m);
547 std::vector<BigInt> t_new = hl_poly_sub_mod(t0, qt1, m);
548
549 r0 = r1; r1 = r_new;
550 s0 = s1; s1 = s_new;
551 t0 = t1; t1 = t_new;
552 }
553
554 /// r0 = gcd,应为常数(可逆元)
555 /// 归一化使 gcd = 1
556 if (!r0.empty() && r0[0] != BigInt(1)) {
557 BigInt inv = hl_mod_inverse(r0[0], m);
558 for (auto& c : s0) {
559 c = detail::symmetric_remainder(c * inv, m);
560 }
561 for (auto& c : t0) {
562 c = detail::symmetric_remainder(c * inv, m);
563 }
564 }
565
566 /// 去除高次零系数
567 while (!s0.empty() && s0.back().is_zero()) s0.pop_back();
568 while (!t0.empty() && t0.back().is_zero()) t0.pop_back();
569
570 return {s0, t0};
571}
572
573/**
574 * @brief 多因子 Hensel 提升:将 k 个模 p 因子同时提升到 mod p^target_k.
575 *
576 * 使用顺序剥离策略:
577 * 1. 将 f 分解为 g_1 和 h_1 = g_2*g₃*...*gₖ
578 * 2. 对 (g_1, h_1) 执行二因子提升
579 * 3. 递归对 h_1 继续剥离下一个因子
580 *
581 * 每步提升通过反复调用 hl_two_factor_lift 实现二次提升(mod p -> p^2 -> p^4 -> ...),
582 * 直到模数达到或超过 p^target_k.
583 *
584 * @param[in] f 原始多项式系数向量(升幂排列)
585 * @param[in] factors 模 p 下的因子列表(各因子系数向量)
586 * @param[in] prime 素数 p
587 * @param[in] target_k 目标提升高度(提升到 mod p^target_k)
588 * @return 提升后的因子列表(各因子系数在对称表示下)
589 *
590 * @pre f == factors[0] * factors[1] * ... * factors[k-1] (mod p)
591 * @pre 各因子两两互素 (mod p)
592 *
593 * @see Zassenhaus, H. "On Hensel factorization, I."
594 * Journal of Number Theory, 1(3), 1969.
595 * @internal
596 */
597static std::vector<std::vector<BigInt>> hl_multi_factor_lift(
598 const std::vector<BigInt>& f,
599 const std::vector<std::vector<BigInt>>& factors,
600 int64_t prime,
601 int target_k) {
602
603 if (factors.empty()) return {};
604 if (factors.size() == 1) {
605 /// 单因子:直接归约到目标模数
606 BigInt target_mod(1);
607 BigInt big_p(static_cast<std::int64_t>(prime));
608 for (int i = 0; i < target_k; ++i) {
609 target_mod = target_mod * big_p;
610 }
611 std::vector<BigInt> result = f;
612 hl_reduce_coeffs(result, target_mod);
613 return {result};
614 }
615
616 BigInt big_p(static_cast<std::int64_t>(prime));
617 BigInt initial_mod(static_cast<std::int64_t>(prime));
618
619 /// 计算目标模数 p^target_k
620 BigInt target_mod(1);
621 for (int i = 0; i < target_k; ++i) {
622 target_mod = target_mod * big_p;
623 }
624
625 /// 顺序剥离策略:逐个提升因子
626 std::vector<std::vector<BigInt>> lifted_factors;
627 lifted_factors.reserve(factors.size());
628
629 /// 当前待分解的多项式(初始为 f)
630 std::vector<BigInt> remaining = f;
631 hl_reduce_coeffs(remaining, target_mod);
632
633 /// 剩余因子列表
634 std::vector<std::vector<BigInt>> remaining_factors = factors;
635
636 for (size_t i = 0; i < factors.size() - 1; ++i) {
637 /// 取出第一个因子 g
638 std::vector<BigInt> g = remaining_factors[0];
639
640 /// 计算 h = 剩余因子的乘积 (mod p)
641 std::vector<BigInt> h = remaining_factors[1];
642 for (size_t j = 2; j < remaining_factors.size(); ++j) {
643 h = hl_poly_mul_mod(h, remaining_factors[j], initial_mod);
644 }
645
646 /// 计算 Bezout 系数 s, t 使得 s*g + t*h == 1 (mod p)
647 auto [s, t] = hl_extended_gcd_poly(g, h, initial_mod);
648
649 /// 构造初始提升状态
650 HenselLiftPair state{g, h, s, t, initial_mod};
651
652 /// 反复二次提升直到模数 >= target_mod
653 while (state.modulus < target_mod) {
654 state = hl_two_factor_lift(remaining, state);
655 }
656
657 /// 提取提升后的 g(已提升到 target_mod)
658 std::vector<BigInt> lifted_g = state.g;
659 hl_reduce_coeffs(lifted_g, target_mod);
660 lifted_factors.push_back(lifted_g);
661
662 /// 更新 remaining 为提升后的 h
663 remaining = state.h;
664 hl_reduce_coeffs(remaining, target_mod);
665
666 /// 更新 remaining_factors:去掉第一个,后续因子保持不变
667 remaining_factors.erase(remaining_factors.begin());
668 }
669
670 /// 最后一个因子就是 remaining
671 hl_reduce_coeffs(remaining, target_mod);
672 lifted_factors.push_back(remaining);
673
674 return lifted_factors;
675}
676
677
678/**
679 * @brief Hensel 提升:将模 p 因子提升到 mod p^k.
680 *
681 * 将 Berlekamp 分解得到的模 p 不可约因子通过二次 Hensel 提升
682 * 升至 mod p^k,其中 k 由 Mignotte 界确定.
683 *
684 * 流程:
685 * 1. 将 Polynomial<ModInt> 因子转换为 vector<BigInt> 内部表示
686 * 2. 调用 hl_multi_factor_lift 执行多因子提升
687 * 3. 将结果转换回 Polynomial<BigInt>
688 *
689 * @param[in] poly 整系数多项式
690 * @param[in] mod_factors 模 p 下的不可约因子
691 * @param[in] prime 素数 p
692 * @param[in] lift_bound 提升次数上界 k(若为 0 则自动计算)
693 * @return 提升后的整系数因子列表(系数在对称表示 [-p^k/2, p^k/2] 下)
694 */
696 const Polynomial<BigInt>& poly,
697 const std::vector<Polynomial<ModInt>>& mod_factors,
698 int64_t prime,
699 int lift_bound) {
700 constexpr const char* operation = "hensel_lift";
701
702 /// 将原始多项式转换为系数向量
703 std::vector<BigInt> f_vec = poly.coeffs;
704
705 /// 将 Polynomial<ModInt> 因子转换为 vector<BigInt> 表示
706 std::vector<std::vector<BigInt>> factor_vecs;
707 factor_vecs.reserve(mod_factors.size());
708 for (const auto& mf : mod_factors) {
709 std::vector<BigInt> fv;
710 fv.reserve(mf.coeffs.size());
711 for (const auto& c : mf.coeffs) {
712 fv.push_back(BigInt(static_cast<std::int64_t>(c.value())));
713 }
714 factor_vecs.push_back(std::move(fv));
715 }
716
717 auto valid = hl_validate_lift_inputs(poly, factor_vecs, prime);
718 if (!valid) return HenselLiftResult::failure(valid.error());
719
720 /// 若调用方未指定提升界,则自动计算
721 int k = lift_bound;
722 if (k <= 0) {
723 k = hl_compute_lift_height(poly, prime);
724 }
725
726 /// 执行多因子 Hensel 提升
727 std::vector<std::vector<BigInt>> lifted_vecs;
728 try {
729 lifted_vecs = hl_multi_factor_lift(f_vec, factor_vecs, prime, k);
730 } catch (const std::exception& ex) {
732 ex.what(),
733 operation);
734 }
735
736 /// 将结果转换回 Polynomial<BigInt>
737 std::vector<Polynomial<BigInt>> result;
738 result.reserve(lifted_vecs.size());
739 for (auto& lv : lifted_vecs) {
740 result.emplace_back(std::move(lv), poly.variable_name);
741 }
742
743 return HenselLiftResult::success(std::move(result));
744}
745
746
747} // namespace LMCAS
一元多项式模板类
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
BigInt symmetric_remainder(const BigInt &value, const BigInt &modulus)
static BigInt hl_mignotte_bound(const Polynomial< BigInt > &poly)
计算多项式的 Mignotte 界.
static bool hl_is_prime(int64_t value)
static int hl_compute_lift_height(const Polynomial< BigInt > &poly, int64_t prime)
计算 Hensel 提升所需的高度 k.
ExprResult e()
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
static std::vector< BigInt > hl_poly_add_mod(const std::vector< BigInt > &a, const std::vector< BigInt > &b, const BigInt &m)
多项式加法(BigInt 系数),结果模 m 归约.
std::vector< BigInt > g
第一个因子的系数。
static void hl_reduce_coeffs(std::vector< BigInt > &poly, const BigInt &m)
对多项式系数向量执行模归约(对称表示).
static Result< void > hl_validate_lift_inputs(const Polynomial< BigInt > &poly, const std::vector< std::vector< BigInt > > &factor_vecs, int64_t prime)
const VectorField const VectorField & c
HenselLiftResult hensel_lift_checked(const Polynomial< BigInt > &poly, const std::vector< Polynomial< ModInt > > &mod_factors, int64_t prime, int lift_bound)
Hensel 提升:将模 p 因子提升到 mod p^k.
static std::vector< BigInt > hl_poly_sub_mod(const std::vector< BigInt > &a, const std::vector< BigInt > &b, const BigInt &m)
多项式减法(BigInt 系数),结果模 m 归约.
const MultiPoly & b
static bool hl_coeff_vectors_equal(std::vector< BigInt > left, std::vector< BigInt > right)
static BigInt hl_mod_inverse(const BigInt &a, const BigInt &m)
计算 BigInt 在模 m 下的乘法逆元.
Result< std::vector< Polynomial< BigInt > > > HenselLiftResult
const std::vector< Polynomial< BigInt > > & lifted_factors
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
static std::vector< std::vector< BigInt > > hl_multi_factor_lift(const std::vector< BigInt > &f, const std::vector< std::vector< BigInt > > &factors, int64_t prime, int target_k)
多因子 Hensel 提升:将 k 个模 p 因子同时提升到 mod p^target_k.
static std::pair< std::vector< BigInt >, std::vector< BigInt > > hl_extended_gcd_poly(const std::vector< BigInt > &g, const std::vector< BigInt > &h, const BigInt &m)
计算两个多项式在模 m 下的扩展 GCD 的 Bezout 系数.
HenselLiftPair hl_two_factor_lift(const std::vector< BigInt > &f, const HenselLiftPair &current)
执行一步二次 Hensel 提升:mod m -> mod m^2.
std::vector< BigInt > t
h 的 Bezout 系数。
const ExprPtr & right
const std::vector< Polynomial< ModInt > > & mod_factors
static std::pair< std::vector< BigInt >, std::vector< BigInt > > hl_poly_divmod(const std::vector< BigInt > &a, const std::vector< BigInt > &b, const BigInt &m)
多项式带余除法(BigInt 系数),模 m 下运算.
std::vector< BigInt > h
第二个因子的系数。
const std::string const ExprPtr & value
std::vector< BigInt > s
g 的 Bezout 系数。
static BigInt hl_binomial(int n, int k)
计算二项式系数 C(n, k).
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & t
static std::vector< BigInt > hl_poly_mul_mod(const std::vector< BigInt > &a, const std::vector< BigInt > &b, const BigInt &m)
多项式乘法(BigInt 系数),结果模 m 归约.
const std::vector< Polynomial< ModInt > > int64_t int lift_bound
static BigInt hl_l2_norm_squared(const Polynomial< BigInt > &poly)
计算多项式系数的 L2 范数的平方.
二因子二次 Hensel 提升的状态结构.