LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
zassenhaus_combine.cpp
浏览该文件的文档.
1/** @file zassenhaus_combine.cpp
2 * @brief 在计算预算内对提升因子进行精确有理重构。
3 */
6
7#include <string>
8#include <vector>
9#include <unordered_set>
10#include <cmath>
11#include <limits>
12#include <cstdint>
13
14
15namespace LMCAS {
16
17
18
19/**
20 * 在模 m 下乘以按字典序枚举的提升因子子集.
21 */
23 const std::vector<Polynomial<BigInt>>& lifted_factors,
24 const std::vector<size_t>& indices,
25 const BigInt& mod,
27 std::vector<BigInt> product = {BigInt(1)};
28
29 for (size_t index : indices) {
30 auto step = context.consume_steps(1, "zassenhaus_combine");
31 if (!step) {
32 return Result<std::vector<BigInt>>::failure(step.error());
33 }
34 if (index >= lifted_factors.size() ||
35 lifted_factors[index].coeffs.empty()) {
36 return Result<std::vector<BigInt>>::failure(
37 CasErrc::InvalidArgument, "invalid lifted-factor index or zero factor",
38 "zassenhaus_combine");
39 }
40 const auto& factor_coeffs = lifted_factors[index].coeffs;
41 std::vector<BigInt> next(product.size() + factor_coeffs.size() - 1,
42 BigInt(0));
43 for (size_t i = 0; i < product.size(); ++i) {
44 if (product[i].is_zero()) continue;
45 for (size_t j = 0; j < factor_coeffs.size(); ++j) {
46 if (factor_coeffs[j].is_zero()) continue;
47 next[i + j] = next[i + j] + product[i] * factor_coeffs[j];
48 }
49 }
50 for (auto& coefficient : next) {
51 coefficient = detail::symmetric_remainder(coefficient, mod);
52 }
53 while (!next.empty() && next.back().is_zero()) next.pop_back();
54 product = std::move(next);
55 }
56 return Result<std::vector<BigInt>>::success(std::move(product));
57}
58
59/**
60 * @brief 将 BigInt 系数向量转换为有理系数多项式.
61 *
62 * 每个 BigInt 系数直接转换为 Rational(分母为 1).
63 *
64 * @param[in] coeffs BigInt 系数向量
65 * @param[in] var 变量名
66 * @return 有理系数多项式
67 * @internal
68 */
70 const std::vector<BigInt>& coeffs,
71 const std::string& var) {
72
73 std::vector<Rational> rat_coeffs;
74 rat_coeffs.reserve(coeffs.size());
75 for (const auto& c : coeffs) {
76 rat_coeffs.emplace_back(c);
77 }
78 return Polynomial<Rational>(rat_coeffs, var);
79}
80
81/**
82 * @brief 对 BigInt 系数执行有理数重构.
83 *
84 * 给定整数 a 和模数 m,使用扩展欧几里得算法寻找有理数 p/q 满足:
85 * - a == p/q (mod m)
86 * - |p| <= floor(sqrt(m/2)), |q| <= floor(sqrt(m/2))
87 *
88 * 当模数超出 int64_t 范围时使用 BigInt 算术;否则委托给
89 * modular_arithmetic.hpp 中的 int64_t 版本以获得更好性能.
90 *
91 * @param[in] a 待重构的整数系数(已归约到对称表示)
92 * @param[in] m 模数(正整数,通常为 p^k)
93 * @param[out] num 输出分子
94 * @param[out] den 输出分母
95 * @return 满足界约束且 gcd=1 时返回 true;false 表示重构未决
96 * @internal
97 */
99 const BigInt& a,
100 const BigInt& m,
101 BigInt& num,
102 BigInt& den) {
103
104 if (m.is_zero() || m.is_negative()) return false;
105
106 /// 对于可精确表示的小模数,委托给 int64_t 版本
107 const auto a_small = a.try_to_int64();
108 const auto m_small = m.try_to_int64();
109 if (a_small && m_small) {
110 const int64_t a_val = *a_small;
111 const int64_t m_val = *m_small;
112
113 auto reconstructed =
115 if (!reconstructed) return false;
116 const auto [p, q] = reconstructed.value();
117 num = BigInt(static_cast<std::int64_t>(p));
118 den = BigInt(static_cast<std::int64_t>(q));
119 return true;
120 }
121
122 /// BigInt 版本的有理重构
123 /// 将 a 归约到 [0, m)
124 BigInt a_mod = a % m;
125 if (a_mod.is_negative()) {
126 a_mod = a_mod + m;
127 }
128
129 /// 计算界 bound = floor(sqrt(m/2))
130 BigInt half_m = m / BigInt(2);
131 BigInt bound = half_m.sqrt();
132 if (bound.is_zero()) bound = BigInt(1);
133
134 /// 扩展欧几里得算法
135 BigInt r0 = m, r1 = a_mod;
136 BigInt s0 = BigInt(0), s1 = BigInt(1);
137
138 while (r1 > bound) {
139 BigInt q = r0 / r1;
140 BigInt r_new = r0 - q * r1;
141 BigInt s_new = s0 - q * s1;
142
143 r0 = r1;
144 r1 = r_new;
145 s0 = s1;
146 s1 = s_new;
147 }
148
149 BigInt p = r1;
150 BigInt q_val = s1;
151
152 /// 确保分母为正
153 if (q_val.is_negative()) {
154 p = -p;
155 q_val = -q_val;
156 }
157
158 /// 验证界约束
159 if (p.abs() > bound || q_val.is_zero() || q_val > bound) {
160 return false;
161 }
162
163 /// 验证 gcd(|p|, q) == 1
164 BigInt g = BigInt::gcd(p.abs(), q_val);
165 if (g != BigInt(1)) {
166 return false;
167 }
168
169 num = p;
170 den = q_val;
171 return true;
172}
173
174/**
175 * @brief 对子集乘积的所有系数执行有理重构,构造有理系数多项式.
176 *
177 * 对 product_coeffs 中的每个 BigInt 系数调用 zc_rational_reconstruction,
178 * 若所有系数均成功重构,则返回对应的有理系数多项式.
179 * 若任一系数重构失败,则回退到整数系数直接转换.
180 *
181 * @param[in] product_coeffs 子集乘积的 BigInt 系数向量(对称表示)
182 * @param[in] mod 模数 p^k
183 * @param[in] var 变量名
184 * @return 有理系数多项式(通过有理重构或整数直接转换)
185 * @internal
186 */
188 const std::vector<BigInt>& product_coeffs,
189 const BigInt& mod,
190 const std::string& var) {
191
192 std::vector<Rational> rat_coeffs;
193 rat_coeffs.reserve(product_coeffs.size());
194
195 /// 尝试对每个系数执行有理重构
196 for (const auto& c : product_coeffs) {
197 BigInt num, den;
198 if (zc_rational_reconstruction(c, mod, num, den)) {
199 rat_coeffs.emplace_back(num, den);
200 } else {
201 /// 任一系数重构失败,回退到整数系数
202 return zc_bigint_to_rational_poly(product_coeffs, var);
203 }
204 }
205
206 return Polynomial<Rational>(rat_coeffs, var);
207}
208
209/**
210 * @brief 检验候选因子是否整除原多项式(精确有理除法).
211 *
212 * 执行多项式带余除法 f / candidate,若余数为零则整除.
213 *
214 * @param[in] f 原多项式
215 * @param[in] candidate 候选因子
216 * @return 整除返回 true
217 * @internal
218 */
220 const Polynomial<Rational>& f,
221 const Polynomial<Rational>& candidate) {
222
223 if (candidate.is_zero()) return false;
224 if (candidate.degree() > f.degree()) return false;
225 if (candidate.degree() == 0) return true;
226
227 auto [quotient, remainder] = f.div_mod(candidate);
228 return remainder.is_zero();
229}
230
231/**
232 * @brief 使候选多项式首一化(首项系数归一).
233 *
234 * @param[in] poly 输入多项式
235 * @return 首一多项式
236 * @internal
237 */
239 if (poly.is_zero()) return poly;
240 return poly.make_monic();
241}
242
243static bool zc_next_combination(std::vector<size_t>& positions, size_t count) {
244 const size_t width = positions.size();
245 for (size_t cursor = width; cursor > 0; --cursor) {
246 const size_t i = cursor - 1;
247 if (positions[i] < count - width + i) {
248 ++positions[i];
249 for (size_t j = i + 1; j < width; ++j) {
250 positions[j] = positions[j - 1] + 1;
251 }
252 return true;
253 }
254 }
255 return false;
256}
257
258static std::vector<size_t> zc_select_indices(
259 const std::vector<size_t>& active,
260 const std::vector<size_t>& positions) {
261 std::vector<size_t> indices;
262 indices.reserve(positions.size());
263 for (size_t position : positions) indices.push_back(active[position]);
264 return indices;
265}
266
268 const Polynomial<Rational>& poly,
269 const std::vector<Polynomial<BigInt>>& lifted_factors,
270 const BigInt& modulus,
272 if (lifted_factors.empty()) {
273 return Result<void>::success();
274 }
275
276 std::vector<size_t> all_indices(lifted_factors.size());
277 for (size_t i = 0; i < all_indices.size(); ++i) {
278 all_indices[i] = i;
279 }
280 auto product_result =
281 zc_subset_product(lifted_factors, all_indices, modulus, context);
282 if (!product_result) {
283 return Result<void>::failure(product_result.error());
284 }
285 auto product = std::move(product_result.value());
286
287 BigInt denominator_lcm(1);
288 for (const Rational& coefficient : poly.coeffs) {
289 denominator_lcm =
290 BigInt::lcm(denominator_lcm, coefficient.get_denominator());
291 }
292 std::vector<BigInt> expected;
293 expected.reserve(poly.coeffs.size());
294 for (const Rational& coefficient : poly.coeffs) {
295 BigInt integer_coefficient =
296 coefficient.get_numerator() *
297 (denominator_lcm / coefficient.get_denominator());
298 expected.push_back(
299 detail::symmetric_remainder(integer_coefficient, modulus));
300 }
301 while (!expected.empty() && expected.back().is_zero()) {
302 expected.pop_back();
303 }
304 while (!product.empty() && product.back().is_zero()) {
305 product.pop_back();
306 }
307 if (!(product == expected)) {
310 "lifted factors are not congruent to the normalized polynomial",
311 "zassenhaus_combine");
312 }
313 return Result<void>::success();
314}
315
317 const Polynomial<Rational>& original,
318 std::vector<Polynomial<Rational>> factors,
319 Polynomial<Rational> remaining,
320 Completeness completeness,
321 std::string reason) {
322 if (!remaining.is_zero() && remaining.degree() > 0) {
323 factors.push_back(remaining.make_monic());
324 }
325
326 if (!original.is_zero()) {
327 Polynomial<Rational> product({Rational(1)}, original.variable_name);
328 for (const auto& factor : factors) product = product * factor;
329 if (!(product == original.make_monic())) {
332 "accepted Zassenhaus factors do not reconstruct the polynomial",
333 "zassenhaus_combine");
334 }
335 } else if (!factors.empty()) {
338 "zero polynomial cannot have a nonempty monic factorization",
339 "zassenhaus_combine");
340 }
341
343 MathResult<std::vector<Polynomial<Rational>>>{
344 std::move(factors), completeness, std::move(reason)});
345}
346
348 const std::vector<Polynomial<BigInt>>& lifted;
349 const BigInt& modulus;
352 std::vector<Polynomial<Rational>> factors;
353 std::vector<size_t> active;
354};
355
357 ZcFactorSearch& search, const std::vector<size_t>& positions) {
358 auto step = search.context.consume_steps(1, "zassenhaus_combine");
359 if (!step) {
360 return Result<bool>::failure(step.error());
361 }
362 auto indices = zc_select_indices(search.active, positions);
363 auto product = zc_subset_product(
364 search.lifted, indices, search.modulus, search.context);
365 if (!product) {
366 return Result<bool>::failure(product.error());
367 }
368 if (product.value().empty()) return Result<bool>::success(false);
370 product.value(), search.modulus, search.remaining.variable_name));
371 if (candidate.is_zero() || candidate.degree() <= 0 ||
372 candidate.degree() >= search.remaining.degree() ||
373 !zc_divides_exactly(search.remaining, candidate)) {
374 return Result<bool>::success(false);
375 }
376 auto [quotient, remainder] = search.remaining.div_mod(candidate);
377 if (!remainder.is_zero()) {
379 CasErrc::InternalInvariant, "exact divisor produced a nonzero remainder",
380 "zassenhaus_combine");
381 }
382 search.factors.push_back(candidate);
383 search.remaining = std::move(quotient);
384 for (size_t cursor = positions.size(); cursor > 0; --cursor) {
385 search.active.erase(search.active.begin() +
386 static_cast<std::ptrdiff_t>(positions[cursor - 1]));
387 }
388 return Result<bool>::success(true);
389}
390
392 for (size_t width = 1; width <= search.active.size() / 2; ++width) {
393 std::vector<size_t> positions(width);
394 for (size_t i = 0; i < width; ++i) positions[i] = i;
395 do {
396 auto candidate = zc_try_candidate(search, positions);
397 if (!candidate || candidate.value()) return candidate;
398 } while (zc_next_combination(positions, search.active.size()));
399 }
400 return Result<bool>::success(false);
401}
402
404 const Polynomial<Rational>& poly,
405 const std::vector<Polynomial<BigInt>>& lifted_factors,
406 const BigInt& modulus, ComputationContext& context) {
407 ZcFactorSearch search{lifted_factors, modulus, context, poly.make_monic(),
408 {}, std::vector<size_t>(lifted_factors.size())};
409 for (size_t i = 0; i < search.active.size(); ++i) search.active[i] = i;
410 while (search.active.size() > 1 && search.remaining.degree() > 1) {
411 auto found = zc_find_factor(search);
412 if (!found) return ZassenhausResult::failure(found.error());
413 if (!found.value()) break;
414 }
415 return zc_finalize(poly, std::move(search.factors), std::move(search.remaining),
417}
418
420 const Polynomial<Rational>& poly,
421 const std::vector<Polynomial<BigInt>>& lifted_factors,
422 const BigInt& reconstruction_modulus,
424 if (reconstruction_modulus.is_zero() ||
425 reconstruction_modulus.is_negative()) {
428 "reconstruction modulus must be positive",
429 "zassenhaus_combine");
430 }
431 if (poly.is_zero()) {
432 if (!lifted_factors.empty()) {
435 "zero polynomial requires an empty lifted-factor list",
436 "zassenhaus_combine");
437 }
439 MathResult<std::vector<Polynomial<Rational>>>{{},
441 }
442 if (lifted_factors.empty()) {
443 return zc_finalize(poly, {}, poly.make_monic(),
445 "no lifted factors were provided");
446 }
447
448 auto validation = zc_validate_lifted_product(
450 if (!validation) return ZassenhausResult::failure(validation.error());
451
453}
454
456 const Polynomial<Rational>& poly,
457 const std::vector<Polynomial<BigInt>>& lifted_factors,
458 const BigInt& reconstruction_modulus,
460 try {
463 } catch (const std::bad_alloc&) {
465 CasErrc::ResourceLimit, "allocation failed", "zassenhaus_combine");
466 } catch (const std::exception& error) {
468 CasErrc::InternalInvariant, error.what(), "zassenhaus_combine");
469 }
470}
471
480
481} // namespace LMCAS
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
一元多项式模板类
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
int degree() const
获取多项式的次数
Polynomial make_monic() const
首一化(使首项系数为 1)
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)
std::shared_ptr< SymbolicExpr > num(int value)
static bool zc_next_combination(std::vector< size_t > &positions, size_t count)
static Result< void > zc_validate_lifted_product(const Polynomial< Rational > &poly, const std::vector< Polynomial< BigInt > > &lifted_factors, const BigInt &modulus, ComputationContext &context)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
std::vector< Polynomial< Rational > > factors
const std::vector< Polynomial< BigInt > > & lifted
const VectorField const VectorField & c
static ZassenhausResult zassenhaus_combine_impl(const Polynomial< Rational > &poly, const std::vector< Polynomial< BigInt > > &lifted_factors, const BigInt &reconstruction_modulus, ComputationContext &context)
static Polynomial< Rational > zc_make_primitive(const Polynomial< Rational > &poly)
使候选多项式首一化(首项系数归一).
const std::vector< Polynomial< BigInt > > const BigInt & reconstruction_modulus
static Polynomial< Rational > zc_bigint_to_rational_poly(const std::vector< BigInt > &coeffs, const std::string &var)
将 BigInt 系数向量转换为有理系数多项式.
const std::vector< Polynomial< BigInt > > & lifted_factors
static bool zc_divides_exactly(const Polynomial< Rational > &f, const Polynomial< Rational > &candidate)
检验候选因子是否整除原多项式(精确有理除法).
__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 Polynomial< Rational > zc_reconstruct_candidate(const std::vector< BigInt > &product_coeffs, const BigInt &mod, const std::string &var)
对子集乘积的所有系数执行有理重构,构造有理系数多项式.
static bool zc_rational_reconstruction(const BigInt &a, const BigInt &m, BigInt &num, BigInt &den)
对 BigInt 系数执行有理数重构.
RationalReconstructionResult rational_reconstruction_checked(int64_t x, int64_t m, ComputationContext &context)
Checked rational reconstruction.
static ZassenhausResult zc_enumerate(const Polynomial< Rational > &poly, const std::vector< Polynomial< BigInt > > &lifted_factors, const BigInt &modulus, ComputationContext &context)
static std::vector< size_t > zc_select_indices(const std::vector< size_t > &active, const std::vector< size_t > &positions)
static Result< bool > zc_try_candidate(ZcFactorSearch &search, const std::vector< size_t > &positions)
static ZassenhausResult zc_finalize(const Polynomial< Rational > &original, std::vector< Polynomial< Rational > > factors, Polynomial< Rational > remaining, Completeness completeness, std::string reason)
static Result< std::vector< BigInt > > zc_subset_product(const std::vector< Polynomial< BigInt > > &lifted_factors, const std::vector< size_t > &indices, const BigInt &mod, ComputationContext &context)
在模 m 下乘以按字典序枚举的提升因子子集.
Result< MathResult< std::vector< Polynomial< Rational > > > > ZassenhausResult
ZassenhausResult zassenhaus_combine_checked(const Polynomial< Rational > &poly, const std::vector< Polynomial< BigInt > > &lifted_factors, const BigInt &reconstruction_modulus, ComputationContext &context)
static Result< bool > zc_find_factor(ZcFactorSearch &search)
Polynomial< Rational > remaining