LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
berlekamp_modular.cpp
浏览该文件的文档.
2#include <algorithm>
3#include <limits>
4
6
7/**
8 * @brief Berlekamp 模分解的小素数候选表。
9 * 按升序选取首个不整除首项系数且使模约化结果无平方因子的素数。
10 * @internal
11 */
12static constexpr int64_t BK_SMALL_PRIMES[] = {
13 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
14 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
15 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
16 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
17 179, 181, 191, 193, 197, 199, 211, 223, 227, 229
18};
19static constexpr size_t BK_NUM_SMALL_PRIMES =
20 sizeof(BK_SMALL_PRIMES) / sizeof(BK_SMALL_PRIMES[0]);
21
22/**
23 * @brief 以系数分母的 LCM 清除分母,再逐项取模 p。
24 * @param[in] poly 有理系数多项式
25 * @param[in] p 素数模数
26 * @return 升幂排列的模 p 系数向量,去除高次零系数。
27 * @internal
28 */
29std::vector<int64_t> bk_reduce_to_mod_coeffs(
30 const Polynomial<Rational>& poly,
31 int64_t p) {
32
33 if (poly.is_zero()) {
34 return {};
35 }
36
37 BigInt lcm_den(1);
38 for (const auto& c : poly.coeffs) {
39 BigInt den = c.get_denominator();
40 BigInt g = BigInt::gcd(lcm_den, den);
41 lcm_den = lcm_den * (den / g);
42 }
43
44 BigInt big_p(static_cast<std::int64_t>(p));
45
46 std::vector<int64_t> mod_coeffs;
47 mod_coeffs.reserve(poly.coeffs.size());
48
49 for (const auto& c : poly.coeffs) {
50 BigInt num = c.get_numerator();
51 BigInt den = c.get_denominator();
52 BigInt integer_coeff = num * (lcm_den / den);
53
54 BigInt rem = integer_coeff % big_p;
55 int64_t rem_val = rem.try_to_int64().value();
56 if (rem_val < 0) rem_val += p;
57
58 mod_coeffs.push_back(rem_val);
59 }
60
61 while (!mod_coeffs.empty() && mod_coeffs.back() == 0) {
62 mod_coeffs.pop_back();
63 }
64
65 return mod_coeffs;
66}
67
68/**
69 * @brief 计算模 p 多项式的形式导数.
70 *
71 * @param[in] f 模 p 系数向量
72 * @param[in] p 素数模数
73 * @return f' 的系数向量
74 * @internal
75 */
76static std::vector<int64_t> bk_derivative_mod(
77 const std::vector<int64_t>& f,
78 int64_t p) {
79
80 if (f.size() <= 1) {
81 return {};
82 }
83
84 std::vector<int64_t> deriv;
85 deriv.reserve(f.size() - 1);
86
87 for (size_t i = 1; i < f.size(); ++i) {
88 const auto index_residue = static_cast<std::int64_t>(
89 i % static_cast<std::uint64_t>(p));
90 int64_t coeff = (f[i] * index_residue) % p;
91 deriv.push_back(coeff);
92 }
93
94 while (!deriv.empty() && deriv.back() == 0) {
95 deriv.pop_back();
96 }
97
98 return deriv;
99}
100
101/**
102 * @brief 模 p 下求乘法逆元.
103 *
104 * 使用扩展欧几里得算法计算 a^(-1) mod p.
105 *
106 * @param[in] a 待求逆的值(非零)
107 * @param[in] p 素数模数
108 * @return a 在模 p 下的逆元
109 * @internal
110 */
111int64_t bk_mod_inverse(int64_t a, int64_t p) {
112 int64_t s, t;
113 extended_gcd(((a % p) + p) % p, p, s, t);
114 return ((s % p) + p) % p;
115}
116
117/**
118 * @brief 模 p 多项式带余除法.
119 *
120 * 计算 a / b 的商和余数,使得 a = q * b + r,deg(r) < deg(b).
121 *
122 * @param[in] a 被除数系数向量
123 * @param[in] b 除数系数向量(非空)
124 * @param[in] p 素数模数
125 * @param[out] q 商系数向量
126 * @param[out] r 余数系数向量
127 * @internal
128 */
130 const std::vector<int64_t>& a,
131 const std::vector<int64_t>& b,
132 int64_t p,
133 std::vector<int64_t>& q,
134 std::vector<int64_t>& r) {
135
136 q.clear();
137 r = a;
138
139 if (b.empty()) return;
140
141 int deg_b = static_cast<int>(b.size()) - 1;
142 int64_t lc_b_inv = bk_mod_inverse(b.back(), p);
143
144 int deg_r = static_cast<int>(r.size()) - 1;
145
146 if (deg_r < deg_b) {
147 return;
148 }
149
150 q.resize(deg_r - deg_b + 1, 0);
151
152 while (deg_r >= deg_b) {
153 int64_t factor = (r[deg_r] * lc_b_inv) % p;
154 int shift = deg_r - deg_b;
155 q[shift] = factor;
156
157 for (int i = 0; i <= deg_b; ++i) {
158 r[shift + i] = (r[shift + i] - factor * b[i] % p + p) % p;
159 }
160
161 while (deg_r >= 0 && r[deg_r] == 0) {
162 r.pop_back();
163 deg_r--;
164 }
165 }
166}
167
168/**
169 * @brief 计算两个模 p 多项式的最大公因式.
170 *
171 * 使用欧几里得算法.结果为首一多项式.
172 *
173 * @param[in] a 第一个多项式系数向量
174 * @param[in] b 第二个多项式系数向量
175 * @param[in] p 素数模数
176 * @return gcd(a, b) 的首一化系数向量
177 * @internal
178 */
179std::vector<int64_t> bk_gcd_mod(
180 std::vector<int64_t> a,
181 std::vector<int64_t> b,
182 int64_t p) {
183
184 while (!b.empty()) {
185 std::vector<int64_t> q, r;
186 bk_div_mod(a, b, p, q, r);
187 a = std::move(b);
188 b = std::move(r);
189 }
190
191 if (!a.empty()) {
192 int64_t lc_inv = bk_mod_inverse(a.back(), p);
193 for (auto& c : a) {
194 c = (c * lc_inv) % p;
195 }
196 }
197
198 return a;
199}
200
201/**
202 * @brief 检查模 p 多项式是否为 无平方因子.
203 *
204 * 多项式 f 在 F_p 上 无平方因子 当且仅当 gcd(f, f') 的次数为 0.
205 *
206 * @param[in] f 模 p 系数向量
207 * @param[in] p 素数模数
208 * @return f 为 无平方因子 返回 true
209 * @internal
210 */
212 const std::vector<int64_t>& f,
213 int64_t p) {
214
215 if (f.size() <= 1) return true;
216
217 std::vector<int64_t> f_prime = bk_derivative_mod(f, p);
218 if (f_prime.empty()) return false;
219
220 std::vector<int64_t> g = bk_gcd_mod(f, f_prime, p);
221 return g.size() <= 1;
222}
223
224/**
225 * @brief 判断素数是否保持多项式次数和无平方性质。
226 *
227 * Berlekamp 分解要求模约化仍位于同一次数的多项式环中,并且
228 * gcd(f mod p, f' mod p) 为常数。显式和自动素数选择共用此检查。
229 *
230 * @param[in] poly 非零有理系数多项式,次数 >= 1。
231 * @param[in] prime 候选模数。
232 * @return 候选为内核支持的素数且满足分解前置条件时返回 true。
233 * @internal
234 */
236 const Polynomial<Rational>& poly,
237 int64_t prime) {
238 if (poly.is_zero() || poly.degree() < 1 ||
239 prime < 2 ||
240 prime > std::numeric_limits<std::int64_t>::max() / prime ||
241 !lmmp_is_prime_ulong_(static_cast<ulong>(prime))) {
242 return false;
243 }
244
245 auto reduced = bk_reduce_to_mod_coeffs(poly, prime);
246 if (static_cast<int>(reduced.size()) - 1 != poly.degree()) {
247 return false;
248 }
249 return bk_is_square_free_mod(reduced, prime);
250}
251
252/**
253 * @brief 从小素数表中选取适合 Berlekamp 分解的素数。
254 * @param[in] poly 非零有理系数多项式,次数 >= 1。
255 * @return 首个合适的素数 p;候选均不满足时返回 -1。
256 * @internal
257 */
259 if (poly.is_zero() || poly.degree() < 1) {
260 return -1;
261 }
262 for (size_t i = 0; i < BK_NUM_SMALL_PRIMES; ++i) {
264 return BK_SMALL_PRIMES[i];
265 }
266 }
267 return -1;
268}
269
270}
一元多项式模板类
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
int degree() const
获取多项式的次数
int64_t bk_mod_inverse(int64_t a, int64_t p)
模 p 下求乘法逆元.
static bool bk_is_square_free_mod(const std::vector< int64_t > &f, int64_t p)
检查模 p 多项式是否为 无平方因子.
static constexpr int64_t BK_SMALL_PRIMES[]
Berlekamp 模分解的小素数候选表。 按升序选取首个不整除首项系数且使模约化结果无平方因子的素数。
static constexpr size_t BK_NUM_SMALL_PRIMES
std::vector< int64_t > bk_gcd_mod(std::vector< int64_t > a, std::vector< int64_t > b, int64_t p)
计算两个模 p 多项式的最大公因式.
void bk_div_mod(const std::vector< int64_t > &a, const std::vector< int64_t > &b, int64_t p, std::vector< int64_t > &q, std::vector< int64_t > &r)
模 p 多项式带余除法.
bool bk_is_suitable_prime(const Polynomial< Rational > &poly, int64_t prime)
判断素数是否保持多项式次数和无平方性质。
std::vector< int64_t > bk_reduce_to_mod_coeffs(const Polynomial< Rational > &poly, int64_t p)
以系数分母的 LCM 清除分母,再逐项取模 p。
static std::vector< int64_t > bk_derivative_mod(const std::vector< int64_t > &f, int64_t p)
计算模 p 多项式的形式导数.
int64_t bk_select_prime(const Polynomial< Rational > &poly)
从小素数表中选取适合 Berlekamp 分解的素数。
std::shared_ptr< SymbolicExpr > num(int value)
__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
const VectorField const VectorField & c
const MultiPoly & b
__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
__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
int64_t extended_gcd(int64_t a, int64_t b, int64_t &s, int64_t &t)
用扩展欧几里得算法求 gcd(a,b) 及 Bezout 系数。