LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
multivariate_poly.cpp
浏览该文件的文档.
1/**
2 * @file multivariate_poly.cpp
3 * @brief 多元多项式类 MultiPoly 的实现。
4 *
5 * 本文件实现 MultiPoly 的构造函数和规范化逻辑。
6 * 规范化保证内部表示满足以下不变量:
7 * - 项按 MonomialOrder 严格降序排列
8 * - 无零系数项
9 * - 无重复单项式(同类项已合并)
10 * - 所有单项式长度等于变量数
11 */
12
13#include "multivariate_poly.hpp"
14
15#include <algorithm>
16#include <sstream>
17#include <stdexcept>
18
19namespace LMCAS {
20
21
22/**
23 * @brief 构造零多项式
24 *
25 * 零多项式的项列表为空,变量列表为空,默认使用 GrevLex 序。
26 */
27MultiPoly::MultiPoly()
28 : terms_(), vars_(), order_(MonomialOrderType::GrevLex)
29{
30}
31
32/**
33 * @brief 从项列表和变量名列表构造多元多项式
34 *
35 * 构造后自动执行规范化:合并同类项、去除零系数项、按单项式序排序。
36 * 若项的单项式长度不足变量数,自动补零至正确长度。
37 *
38 * @param[in] terms 项列表,每项为 (单项式, 系数) 对
39 * @param[in] vars 变量名列表,确定各分量对应的变量
40 * @param[in] order 单项式序类型,默认分次逆字典序
41 */
42MultiPoly::MultiPoly(std::vector<Term> terms, std::vector<std::string> vars,
43 MonomialOrderType order)
44 : terms_(std::move(terms)), vars_(std::move(vars)), order_(order)
45{
46 /// 确保所有单项式长度与变量数一致
47 for (auto& term : terms_) {
48 if (term.first.size() < vars_.size()) {
49 term.first.resize(vars_.size(), 0);
50 }
51 }
52 normalize();
53}
54
55/**
56 * @brief 从常数构造多元多项式
57 *
58 * 若常数为零,构造零多项式(空项列表)。
59 * 否则构造含单个全零单项式的常数多项式。
60 *
61 * @param[in] constant 常数值
62 * @param[in] vars 变量名列表
63 */
64MultiPoly::MultiPoly(const Rational& constant, const std::vector<std::string>& vars)
65 : terms_(), vars_(vars), order_(MonomialOrderType::GrevLex)
66{
67 if (!constant.is_zero()) {
68 Monomial zero_mono(vars_.size(), 0);
69 terms_.emplace_back(std::move(zero_mono), constant);
70 }
71}
72
73
74/**
75 * @internal
76 * @brief 规范化多项式内部表示
77 *
78 * 执行三步操作:
79 * 1. 按 MonomialOrder 降序排列所有项
80 * 2. 合并相邻的同类项(单项式相同的项,系数相加)
81 * 3. 移除零系数项
82 *
83 * 排序后同类项必然相邻,因此只需单次线性扫描即可完成合并。
84 */
85void MultiPoly::normalize()
86{
87 if (terms_.empty()) return;
88
89 /// 步骤 1:按单项式序降序排列
90 MonomialOrder cmp(order_);
91 std::sort(terms_.begin(), terms_.end(),
92 [&cmp](const Term& a, const Term& b) {
93 return cmp(a.first, b.first);
94 });
95
96 /// 步骤 2 & 3:合并同类项并移除零系数项
97 std::vector<Term> merged;
98 merged.reserve(terms_.size());
99
100 for (size_t i = 0; i < terms_.size(); ) {
101 Monomial current_mono = terms_[i].first;
102 Rational coeff_sum = terms_[i].second;
103 size_t j = i + 1;
104
105 /// 合并所有具有相同单项式的连续项
106 while (j < terms_.size() && terms_[j].first == current_mono) {
107 coeff_sum = coeff_sum + terms_[j].second;
108 ++j;
109 }
110
111 /// 仅保留非零系数项
112 if (!coeff_sum.is_zero()) {
113 merged.emplace_back(std::move(current_mono), std::move(coeff_sum));
114 }
115
116 i = j;
117 }
118
119 terms_ = std::move(merged);
120}
121
122
123bool MultiPoly::is_zero() const
124{
125 return terms_.empty();
126}
127
128bool MultiPoly::is_constant() const
129{
130 if (terms_.empty()) return true;
131 if (terms_.size() != 1) return false;
132 /// 检查唯一项的单项式是否全零
133 for (int exp : terms_[0].first) {
134 if (exp != 0) return false;
135 }
136 return true;
137}
138
139bool MultiPoly::is_univariate() const
140{
141 if (terms_.empty()) return true;
142 /// 统计哪些变量出现了非零指数
143 int active_count = 0;
144 for (size_t vi = 0; vi < vars_.size(); ++vi) {
145 bool active = false;
146 for (const auto& term : terms_) {
147 if (vi < term.first.size() && term.first[vi] != 0) {
148 active = true;
149 break;
150 }
151 }
152 if (active) ++active_count;
153 if (active_count > 1) return false;
154 }
155 return true;
156}
157
158bool MultiPoly::is_homogeneous() const
159{
160 if (terms_.empty()) return true;
161 int deg = LMCAS::total_degree(terms_[0].first);
162 for (size_t i = 1; i < terms_.size(); ++i) {
163 if (LMCAS::total_degree(terms_[i].first) != deg) return false;
164 }
165 return true;
166}
167
168int MultiPoly::num_terms() const
169{
170 return static_cast<int>(terms_.size());
171}
172
173int MultiPoly::num_vars() const
174{
175 return static_cast<int>(vars_.size());
176}
177
178const std::vector<std::string>& MultiPoly::variables() const
179{
180 return vars_;
181}
182
183const std::vector<MultiPoly::Term>& MultiPoly::terms() const
184{
185 return terms_;
186}
187
188int MultiPoly::total_degree() const
189{
190 if (terms_.empty()) return -1;
191 int max_deg = 0;
192 for (const auto& term : terms_) {
193 int deg = LMCAS::total_degree(term.first);
194 if (deg > max_deg) max_deg = deg;
195 }
196 return max_deg;
197}
198
199int MultiPoly::degree(const std::string& var) const
200{
201 if (terms_.empty()) return -1;
202 /// 找到变量在 vars_ 中的索引
203 int var_idx = -1;
204 for (size_t i = 0; i < vars_.size(); ++i) {
205 if (vars_[i] == var) {
206 var_idx = static_cast<int>(i);
207 break;
208 }
209 }
210 if (var_idx < 0) return 0; // 变量不在列表中,次数为 0
211
212 int max_exp = 0;
213 for (const auto& term : terms_) {
214 if (static_cast<size_t>(var_idx) < term.first.size()) {
215 if (term.first[var_idx] > max_exp) {
216 max_exp = term.first[var_idx];
217 }
218 }
219 }
220 return max_exp;
221}
222
223/**
224 * @brief 获取关于指定变量的首项系数
225 *
226 * 将多项式视为 var 的一元多项式,找到 var 的最高次数,
227 * 收集所有具有该最高次数的项,移除 var 维度后返回辅助变量的多项式。
228 *
229 * @param[in] var 主变量名
230 * @return 首项系数多项式(在剩余变量上)
231 */
232MultiPoly MultiPoly::leading_coeff(const std::string& var) const
233{
234 if (terms_.empty()) {
235 return MultiPoly();
236 }
237
238 /// 找到变量在 vars_ 中的索引
239 int var_idx = -1;
240 for (size_t i = 0; i < vars_.size(); ++i) {
241 if (vars_[i] == var) {
242 var_idx = static_cast<int>(i);
243 break;
244 }
245 }
246
247 /// 变量不在列表中:整个多项式就是"系数"
248 if (var_idx < 0) {
249 return *this;
250 }
251
252 /// 找到 var 的最高指数
253 int max_exp = 0;
254 for (const auto& term : terms_) {
255 if (static_cast<size_t>(var_idx) < term.first.size()) {
256 if (term.first[var_idx] > max_exp) {
257 max_exp = term.first[var_idx];
258 }
259 }
260 }
261
262 /// 构建剩余变量列表(移除 var)
263 std::vector<std::string> remaining_vars;
264 remaining_vars.reserve(vars_.size() - 1);
265 for (size_t i = 0; i < vars_.size(); ++i) {
266 if (static_cast<int>(i) != var_idx) {
267 remaining_vars.push_back(vars_[i]);
268 }
269 }
270
271 /// 收集具有最高指数的项,移除 var 维度
272 std::vector<Term> lc_terms;
273 for (const auto& term : terms_) {
274 int exp_val = (static_cast<size_t>(var_idx) < term.first.size())
275 ? term.first[var_idx] : 0;
276 if (exp_val == max_exp) {
277 Monomial reduced_mono;
278 reduced_mono.reserve(vars_.size() - 1);
279 for (size_t i = 0; i < term.first.size(); ++i) {
280 if (static_cast<int>(i) != var_idx) {
281 reduced_mono.push_back(term.first[i]);
282 }
283 }
284 lc_terms.emplace_back(std::move(reduced_mono), term.second);
285 }
286 }
287
288 return MultiPoly(std::move(lc_terms), std::move(remaining_vars), order_);
289}
290
291/**
292 * @brief 转换为可读字符串表示
293 *
294 * 格式规则:
295 * - 零多项式输出 "0"
296 * - 常数多项式输出数值
297 * - 各项以 " + " 或 " - " 连接
298 * - 系数为 1 时省略(除非为常数项)
299 * - 指数为 0 的变量省略,指数为 1 时省略指数
300 *
301 * @return 多项式的字符串形式
302 */
303std::string MultiPoly::to_string() const
304{
305 if (terms_.empty()) {
306 return "0";
307 }
308
309 std::ostringstream oss;
310
311 for (size_t i = 0; i < terms_.size(); ++i) {
312 const Rational& coeff = terms_[i].second;
313 const Monomial& mono = terms_[i].first;
314
315 /// 判断是否为常数项(所有指数为零)
316 bool is_const_term = true;
317 for (size_t vi = 0; vi < mono.size(); ++vi) {
318 if (mono[vi] != 0) {
319 is_const_term = false;
320 break;
321 }
322 }
323
324 /// 确定系数的符号和绝对值
325 bool negative = coeff < Rational(0);
326 Rational abs_coeff = coeff.abs();
327
328 /// 输出符号
329 if (i == 0) {
330 if (negative) oss << "-";
331 } else {
332 if (negative) {
333 oss << " - ";
334 } else {
335 oss << " + ";
336 }
337 }
338
339 /// 常数项:直接输出绝对值
340 if (is_const_term) {
341 oss << abs_coeff.to_string();
342 continue;
343 }
344
345 /// 非常数项:系数不为 1 时输出系数
346 bool coeff_is_one = (abs_coeff == Rational(1));
347 if (!coeff_is_one) {
348 oss << abs_coeff.to_string() << "*";
349 }
350
351 /// 输出变量部分
352 bool first_var = true;
353 for (size_t vi = 0; vi < mono.size() && vi < vars_.size(); ++vi) {
354 if (mono[vi] == 0) continue;
355
356 if (!first_var) {
357 oss << "*";
358 }
359 first_var = false;
360
361 oss << vars_[vi];
362 if (mono[vi] != 1) {
363 oss << "^" << mono[vi];
364 }
365 }
366 }
367
368 return oss.str();
369}
370
371}
多元多项式类 MultiPoly,稀疏表示,支持任意数量变量上的环运算。
ExpressionResult normalize(const Node &value, ComputationContext &context)
std::vector< int > Monomial
单项式类型,以整数向量表示各变量的指数
__attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorField gradient(const std const std::vector< std::string > & vars
const std::vector< FGLMPoly > const MonomialOrder & order
@ Rational
Rational numbers
int total_degree(const Monomial &m)
计算单项式的全次数
MonomialOrderType
单项式序的类型枚举