LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
polynomial.hpp
浏览该文件的文档.
1/**
2 * @file polynomial.hpp
3 * @brief 一元多项式模板类 Polynomial<T>,支持四则运算,GCD,求导,求值.
4 */
5#pragma once
6
7#include <vector>
8#include <string>
9#include <iostream>
10#include <algorithm>
11#include <stdexcept>
12#include <numeric>
13#include "bigint.hpp"
14#include "rational.hpp"
15
16namespace LMCAS {
17
18/**
19 * @brief 计算两个系数的最大公约数(泛型实现)
20 * @tparam T 系数类型
21 * @param a 第一个系数
22 * @param b 第二个系数
23 * @return gcd(a, b)
24 */
25template<typename T>
26T gcd_coeff_impl(const T& a, const T& b) {
27 if constexpr (std::is_integral_v<T>) {
28 return std::abs(std::gcd(a, b));
29 }
30 else if constexpr (std::is_same_v<T, BigInt>) {
31 return BigInt::gcd(a, b);
32 }
33 else if constexpr (std::is_same_v<T, Rational>) {
34 return Rational(1);
35 }
36 else {
37 return T(1);
38 }
39}
40
41/**
42 * @brief 一元多项式模板类
43 * @tparam CoeffType 系数类型(支持 BigInt,Rational,int 等)
44 *
45 * 系数按升幂存储:coeffs[i] 对应 x^i 的系数.
46 * 非零操作数必须属于同一命名变量环(包括显式常数),否则算术、
47 * 带余除法、伪除法和 GCD 抛出 std::invalid_argument,判等返回 false。
48 * 加减乘中的零元素嵌入非零侧变量环;双方为零时保留左侧变量环。
49 * 零被除数的商和余数采用除数变量环;零除数始终非法。
50 */
51template <typename CoeffType>
53public:
54
55 std::vector<CoeffType> coeffs; ///< 系数数组,coeffs[i] 为 x^i 的系数
56 std::string variable_name; ///< 变量名
57
58 /**
59 * @brief 构造零多项式
60 * @param var 变量名,默认 "x"
61 */
62 Polynomial(const std::string& var = "x") : variable_name(var) {}
63
64 /**
65 * @brief 从系数向量构造多项式
66 * @param c 系数向量(升幂排列)
67 * @param var 变量名
68 */
69 Polynomial(const std::vector<CoeffType>& c, const std::string& var = "x")
70 : coeffs(c), variable_name(var) {
71 trim();
72 }
73
74 /**
75 * @brief 从单个常数构造常数多项式
76 * @param c 常数值
77 * @param var 变量名
78 */
79 Polynomial(const CoeffType& c, const std::string& var = "x")
80 : coeffs{c}, variable_name(var) {
81 trim();
82 }
83
84 /** @brief 去除高次零系数 */
85 void trim() {
86 while (coeffs.size() > 0 && coeffs.back() == CoeffType(0)) {
87 coeffs.pop_back();
88 }
89 }
90
91 /** @brief 判断是否为零多项式 */
92 bool is_zero() const {
93 return coeffs.empty();
94 }
95
96 /**
97 * @brief 获取多项式的次数
98 * @return 次数;零多项式返回 -1
99 */
100 int degree() const {
101 if (coeffs.empty()) return -1;
102 return static_cast<int>(coeffs.size()) - 1;
103 }
104
105 /**
106 * @brief 获取首项系数
107 * @return 最高次项的系数;零多项式返回 0
108 */
109 CoeffType lead_coeff() const {
110 if (coeffs.empty()) return CoeffType(0);
111 return coeffs.back();
112 }
113
114 /**
115 * @brief 多项式加法
116 * @param other 加数
117 * @return 和多项式
118 */
119 Polynomial operator+(const Polynomial& other) const {
120 require_compatible_variables(other, "Polynomial::operator+");
121 const auto& result_var = is_zero() && !other.is_zero()
123 Polynomial res(result_var);
124 size_t n = std::max(coeffs.size(), other.coeffs.size());
125 res.coeffs.resize(n);
126
127 for (size_t i = 0; i < n; ++i) {
128 CoeffType a = (i < coeffs.size()) ? coeffs[i] : CoeffType(0);
129 CoeffType b = (i < other.coeffs.size()) ? other.coeffs[i] : CoeffType(0);
130 res.coeffs[i] = a + b;
131 }
132 res.trim();
133 return res;
134 }
135
136 /**
137 * @brief 多项式减法
138 * @param other 减数
139 * @return 差多项式
140 */
141 Polynomial operator-(const Polynomial& other) const {
142 require_compatible_variables(other, "Polynomial::operator-");
143 const auto& result_var = is_zero() && !other.is_zero()
145 Polynomial res(result_var);
146 size_t n = std::max(coeffs.size(), other.coeffs.size());
147 res.coeffs.resize(n);
148
149 for (size_t i = 0; i < n; ++i) {
150 CoeffType a = (i < coeffs.size()) ? coeffs[i] : CoeffType(0);
151 CoeffType b = (i < other.coeffs.size()) ? other.coeffs[i] : CoeffType(0);
152 res.coeffs[i] = a - b;
153 }
154 res.trim();
155 return res;
156 }
157
158 /**
159 * @brief 多项式乘法
160 * @param other 乘数
161 * @return 积多项式
162 */
163 Polynomial operator*(const Polynomial& other) const {
164 require_compatible_variables(other, "Polynomial::operator*");
165 const auto& result_var = is_zero() && !other.is_zero()
167 Polynomial res(result_var);
168 if (is_zero() || other.is_zero()) { return res; }
169 res.coeffs.resize(coeffs.size() + other.coeffs.size() - 1, CoeffType(0));
170
171 for (size_t i = 0; i < coeffs.size(); ++i) {
172 for (size_t j = 0; j < other.coeffs.size(); ++j) {
173 res.coeffs[i + j] = res.coeffs[i + j] + coeffs[i] * other.coeffs[j];
174 }
175 }
176 res.trim();
177 return res;
178 }
179
180 /**
181 * @brief 多项式判等
182 * @param other 比较对象
183 * @return 同一命名变量环内系数完全相同返回 true;所有零多项式相等
184 */
185 bool operator==(const Polynomial& other) const {
186 if (degree() != other.degree()) {
187 return false;
188 }
189 if (!variables_compatible(other)) {
190 return false;
191 }
192 for (size_t i = 0; i < coeffs.size(); ++i) {
193 if (coeffs[i] != other.coeffs[i]) {
194 return false;
195 }
196 }
197 return true;
198 }
199
200 /**
201 * @brief 多项式带余除法
202 * @param other 除数多项式
203 * @return pair(商, 余数)
204 * @throw std::runtime_error 除数为零多项式时抛出
205 * @throw std::invalid_argument 两个非零操作数的变量名不同时抛出
206 */
207 std::pair<Polynomial, Polynomial> div_mod(const Polynomial& other) const {
208 if (other.is_zero()) throw std::runtime_error("Division by zero polynomial");
209 require_compatible_variables(other, "Polynomial::div_mod");
210 if (is_zero()) {
211 return {Polynomial(other.variable_name), Polynomial(other.variable_name)};
212 }
213
214 Polynomial quotient(variable_name);
215 Polynomial remainder = *this;
216
217 int deg_rem = remainder.degree();
218 int deg_div = other.degree();
219 CoeffType lc_div = other.lead_coeff();
220
221 if (deg_rem < deg_div) {
222 return {quotient, remainder};
223 }
224
225 quotient.coeffs.resize(deg_rem - deg_div + 1, CoeffType(0));
226
227 while (deg_rem >= deg_div && !remainder.is_zero()) {
228
229 CoeffType factor = remainder.lead_coeff() / lc_div;
230 int deg_diff = deg_rem - deg_div;
231
232 quotient.coeffs[deg_diff] = factor;
233
235 term.coeffs.resize(deg_diff + 1, CoeffType(0));
236 term.coeffs[deg_diff] = factor;
237
238 Polynomial subtrahend = other * term;
239 remainder = remainder - subtrahend;
240 deg_rem = remainder.degree();
241 }
242
243 quotient.trim();
244 return {quotient, remainder};
245 }
246
247 /**
248 * @brief 计算两个系数的 GCD(静态方法)
249 * @param a 第一个系数
250 * @param b 第二个系数
251 * @return gcd(a, b)
252 */
253 static CoeffType gcd_coeff(const CoeffType& a, const CoeffType& b) {
254 if constexpr (std::is_same_v<CoeffType, BigInt>) {
255 return BigInt::gcd(a, b);
256 } else if constexpr (std::is_same_v<CoeffType, Rational>) {
257 return CoeffType(1);
258 } else {
259
260 if constexpr (std::is_integral_v<CoeffType>) {
261 return std::gcd(a, b);
262 }
263
264 return CoeffType(1);
265 }
266 }
267
268 /**
269 * @brief 计算多项式的容度(所有系数的 GCD)
270 * @return 容度值
271 */
272 CoeffType content() const;
273
274 /**
275 * @brief 计算多项式的本原部分(除以容度)
276 * @return 本原多项式
277 */
279
280 /**
281 * @brief 通过系数缩放执行伪除法,运算保持在原系数环
282 * @param other 除数多项式
283 * @return pair(伪商, 伪余数)
284 * @throw std::runtime_error 除数为零多项式时抛出
285 * @throw std::invalid_argument 两个非零操作数的变量名不同时抛出
286 */
287 std::pair<Polynomial, Polynomial> pseudo_div_mod(const Polynomial& other) const;
288
289 /**
290 * @brief 对多项式求值(Horner 法)
291 * @param val 自变量的值
292 * @return 多项式在 val 处的值
293 */
294 CoeffType eval(const CoeffType& val) const {
295 if (coeffs.empty()) return CoeffType(0);
296 CoeffType res = coeffs.back();
297 for (int i = (int)coeffs.size() - 2; i >= 0; --i) {
298 res = res * val + coeffs[i];
299 }
300 return res;
301 }
302
303 /**
304 * @brief 求导
305 * @return 导多项式
306 */
308 if (degree() < 1) return Polynomial(variable_name);
310 res.coeffs.resize(coeffs.size() - 1);
311 for (size_t i = 1; i < coeffs.size(); ++i) {
312 CoeffType c = coeffs[i];
313
314 res.coeffs[i-1] = c * CoeffType(i);
315 }
316 res.trim();
317 return res;
318 }
319
320 /**
321 * @brief 首一化(使首项系数为 1)
322 * @return 首一多项式
323 */
325 if (is_zero()) return *this;
326 CoeffType lc = lead_coeff();
327 if (lc == CoeffType(1)) return *this;
328
330 res.coeffs.reserve(coeffs.size());
331 for (const auto& c : coeffs) {
332 res.coeffs.push_back(c / lc);
333 }
334 return res;
335 }
336
337 /**
338 * @brief 伪除法取余数
339 * @param other 除数多项式
340 * @return 伪余数
341 */
343
344 /**
345 * @brief 计算两个多项式的最大公因式
346 * @param a 第一个多项式
347 * @param b 第二个多项式
348 * @return gcd(a, b)
349 * @throw std::invalid_argument 两个非零操作数的变量名不同时抛出
350 */
352
353 /**
354 * @brief 计算无平方因子部分
355 * @return 去除重因子后的多项式
356 */
358
359 /**
360 * @brief 转换为字符串表示
361 * @return 多项式的字符串形式
362 */
363 std::string to_string() const {
364 if (is_zero()) {
365 return "0";
366 }
367 std::string s;
368 for (int i = degree(); i >= 0; --i) {
369 if (coeffs[i] == CoeffType(0)) {
370 continue;
371 }
372 append_string_term(s, coeffs[i], i);
373 }
374 return s.empty() ? "0" : s;
375 }
376
377private:
378 bool variables_compatible(const Polynomial& other) const {
379 return variable_name == other.variable_name || is_zero() || other.is_zero();
380 }
381
382 void require_compatible_variables(const Polynomial& other, const char* operation) const {
383 if (!variables_compatible(other)) {
384 throw std::invalid_argument(
385 std::string(operation) + ": variable name mismatch ('" +
386 variable_name + "' vs '" + other.variable_name + "')");
387 }
388 }
389
390 void append_string_term(std::string& text, CoeffType coefficient, int power) const {
391 const bool positive = !(coefficient < CoeffType(0));
392 if (!text.empty()) {
393 text += positive ? " + " : " - ";
394 } else if (!positive) {
395 text += "-";
396 }
397 if (!positive) {
398 coefficient = coefficient * CoeffType(-1);
399 }
400 if (!(coefficient == CoeffType(1)) || power == 0) {
401 if constexpr (std::is_same_v<CoeffType, BigInt> ||
402 std::is_same_v<CoeffType, Rational>) {
403 text += coefficient.to_string();
404 } else {
405 text += std::to_string(coefficient);
406 }
407 if (power > 0) {
408 text += "*";
409 }
410 }
411 if (power > 0) {
412 text += variable_name;
413 }
414 if (power > 1) {
415 text += "^" + std::to_string(power);
416 }
417 }
418};
419
420/**
421 * @brief 多项式流输出运算符
422 * @tparam T 系数类型
423 * @param os 输出流
424 * @param p 多项式
425 * @return 输出流引用
426 */
427template<typename T>
428std::ostream& operator<<(std::ostream& os, const Polynomial<T>& p) {
429 if (p.is_zero()) {
430 return os << "0";
431 }
432 for (int i = p.degree(); i >= 0; --i) {
433 T c = p.coeffs[i];
434 if (c == T(0)) {
435 continue;
436 }
437
438 if (i < p.degree()) {
439 if (c > T(0)) {
440 os << " + ";
441 } else {
442 os << " - ";
443 }
444 } else if (c < T(0)) {
445 os << "-";
446 }
447
448 T abs_c = (c < T(0)) ? (c * T(-1)) : c;
449 if (abs_c != T(1) || i == 0) {
450 os << abs_c;
451 }
452
453 if (i > 0) {
454 os << p.variable_name;
455 }
456 if (i > 1) {
457 os << "^" << i;
458 }
459 }
460 return os;
461}
462
463}
464
任意精度整数 BigInt,底层调用 LMMP 实现高性能大数运算。
一元多项式模板类
static Polynomial gcd(Polynomial a, Polynomial b)
计算两个多项式的最大公因式
Polynomial(const std::vector< CoeffType > &c, const std::string &var="x")
从系数向量构造多项式
Polynomial pseudo_div_mod_rem(const Polynomial &other) const
伪除法取余数
CoeffType eval(const CoeffType &val) const
对多项式求值(Horner 法)
Polynomial differentiate() const
求导
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
void require_compatible_variables(const Polynomial &other, const char *operation) const
Polynomial(const std::string &var="x")
构造零多项式
Polynomial operator+(const Polynomial &other) const
多项式加法
static CoeffType gcd_coeff(const CoeffType &a, const CoeffType &b)
计算两个系数的 GCD(静态方法)
bool is_zero() const
判断是否为零多项式
std::vector< Rational > coeffs
Polynomial(const CoeffType &c, const std::string &var="x")
从单个常数构造常数多项式
Polynomial primitive_part() const
计算多项式的本原部分(除以容度)
Polynomial square_free_part() const
计算无平方因子部分
std::string to_string() const
转换为字符串表示
std::pair< Polynomial, Polynomial > pseudo_div_mod(const Polynomial &other) const
通过系数缩放执行伪除法,运算保持在原系数环
CoeffType lead_coeff() const
获取首项系数
void append_string_term(std::string &text, Rational coefficient, int power) const
Polynomial operator-(const Polynomial &other) const
多项式减法
int degree() const
获取多项式的次数
CoeffType content() const
计算多项式的容度(所有系数的 GCD)
Polynomial make_monic() const
首一化(使首项系数为 1)
bool variables_compatible(const Polynomial &other) const
bool operator==(const Polynomial &other) const
多项式判等
Polynomial operator*(const Polynomial &other) const
多项式乘法
const VectorField const VectorField & c
const MultiPoly & b
T gcd_coeff_impl(const T &a, const T &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
std::ostream & operator<<(std::ostream &os, const Polynomial< T > &p)
多项式流输出运算符
精确有理数 Rational,基于 BigInt 分子/分母表示,自动约分。