8void MultiPoly::require_compatible_variables(
const MultiPoly& other)
const
10 if (vars_ != other.vars_ && !
is_zero() && !other.is_zero()) {
11 throw std::invalid_argument(
"MultiPoly: variable list mismatch");
21MultiPoly MultiPoly::operator+(
const MultiPoly& other)
const
23 if (other.is_zero())
return *
this;
25 require_compatible_variables(other);
27 std::vector<Term> result_terms;
28 result_terms.reserve(terms_.size() + other.terms_.size());
29 result_terms.insert(result_terms.end(), terms_.begin(), terms_.end());
30 result_terms.insert(result_terms.end(), other.terms_.begin(), other.terms_.end());
33 result.terms_ = std::move(result_terms);
35 result.order_ = order_;
45MultiPoly MultiPoly::operator-(
const MultiPoly& other)
const
47 if (other.is_zero())
return *
this;
49 require_compatible_variables(other);
51 std::vector<Term> result_terms;
52 result_terms.reserve(terms_.size() + other.terms_.size());
53 result_terms.insert(result_terms.end(), terms_.begin(), terms_.end());
55 for (
const auto& term : other.terms_) {
56 result_terms.emplace_back(term.first, -term.second);
60 result.terms_ = std::move(result_terms);
62 result.order_ = order_;
72MultiPoly MultiPoly::operator*(
const MultiPoly& other)
const
74 if (terms_.empty() || other.terms_.empty()) {
76 const MultiPoly& ring =
is_zero() && !other.is_zero() ? other : *
this;
77 zero.vars_ = ring.vars_;
78 zero.order_ = ring.order_;
81 require_compatible_variables(other);
83 std::vector<Term> result_terms;
84 result_terms.reserve(terms_.size() * other.terms_.size());
86 size_t n_vars = vars_.size();
88 for (
const auto& term_a : terms_) {
89 for (
const auto& term_b : other.terms_) {
91 for (
size_t i = 0; i < n_vars; ++i) {
92 int exp_a = (i < term_a.first.size()) ? term_a.first[i] : 0;
93 int exp_b = (i < term_b.first.size()) ? term_b.first[i] : 0;
94 product_mono[i] = exp_a + exp_b;
96 Rational product_coeff = term_a.second * term_b.second;
97 result_terms.emplace_back(std::move(product_mono), std::move(product_coeff));
102 result.terms_ = std::move(result_terms);
103 result.vars_ = vars_;
104 result.order_ = order_;
113MultiPoly MultiPoly::operator-()
const
115 std::vector<Term> negated_terms;
116 negated_terms.reserve(terms_.size());
118 for (
const auto& term : terms_) {
119 negated_terms.emplace_back(term.first, -term.second);
123 result.terms_ = std::move(negated_terms);
124 result.vars_ = vars_;
125 result.order_ = order_;
135bool MultiPoly::operator==(
const MultiPoly& other)
const
137 if (terms_.size() != other.terms_.size())
return false;
139 if (vars_ != other.vars_)
return false;
140 if (order_ != other.order_) {
142 for (
const auto& term : terms_) {
143 auto found = std::lower_bound(
144 other.terms_.begin(), other.terms_.end(), term.first,
146 return order(candidate.first, monomial);
148 if (found == other.terms_.end() ||
149 found->first != term.first || found->second != term.second) {
155 for (
size_t i = 0; i < terms_.size(); ++i) {
156 if (terms_[i].first != other.terms_[i].first)
return false;
157 if (terms_[i].second != other.terms_[i].second)
return false;
167bool MultiPoly::operator!=(
const MultiPoly& other)
const
169 return !(*
this == other);
177MultiPoly MultiPoly::operator*(
const Rational& scalar)
const
179 if (scalar.is_zero()) {
182 zero.order_ = order_;
186 std::vector<Term> scaled_terms;
187 scaled_terms.reserve(terms_.size());
189 for (
const auto& term : terms_) {
190 scaled_terms.emplace_back(term.first, term.second * scalar);
194 result.terms_ = std::move(scaled_terms);
195 result.vars_ = vars_;
196 result.order_ = order_;
211MultiPoly MultiPoly::exact_div(
const MultiPoly& divisor)
const
213 if (divisor.is_zero()) {
214 throw std::runtime_error(
"exact division by zero polynomial");
219 zero.vars_ = divisor.vars_;
220 zero.order_ = divisor.order_;
223 require_compatible_variables(divisor);
225 std::optional<MultiPoly> reordered_divisor;
226 if (order_ != divisor.order_) {
227 reordered_divisor.emplace(divisor);
228 reordered_divisor->order_ = order_;
229 reordered_divisor->normalize();
231 const MultiPoly& ordered_divisor = reordered_divisor ? *reordered_divisor : divisor;
232 const Monomial& divisor_lt_mono = ordered_divisor.terms_[0].first;
233 const Rational& divisor_lt_coeff = ordered_divisor.terms_[0].second;
235 size_t n_vars = vars_.size();
237 std::vector<Term> quotient_terms;
238 MultiPoly remainder = *
this;
240 while (!remainder.is_zero()) {
241 const Monomial& rem_lt_mono = remainder.terms_[0].first;
242 const Rational& rem_lt_coeff = remainder.terms_[0].second;
245 throw std::runtime_error(
"exact division failed");
249 for (
size_t i = 0; i < n_vars; ++i) {
250 int rem_exp = (i < rem_lt_mono.size()) ? rem_lt_mono[i] : 0;
251 int div_exp = (i < divisor_lt_mono.size()) ? divisor_lt_mono[i] : 0;
252 q_mono[i] = rem_exp - div_exp;
255 Rational q_coeff = rem_lt_coeff / divisor_lt_coeff;
257 quotient_terms.emplace_back(q_mono, q_coeff);
259 MultiPoly q_term_poly(std::vector<Term>{{q_mono, q_coeff}}, vars_, order_);
260 remainder = remainder - (q_term_poly * ordered_divisor);
263 return MultiPoly(std::move(quotient_terms), vars_, order_);
271Rational MultiPoly::numeric_content()
const
273 if (terms_.empty()) {
277 BigInt num_gcd = terms_[0].second.get_numerator().abs();
278 BigInt den_lcm = terms_[0].second.get_denominator();
280 for (
size_t i = 1; i < terms_.size(); ++i) {
281 BigInt num_i = terms_[i].second.get_numerator().abs();
282 BigInt den_i = terms_[i].second.get_denominator();
284 num_gcd = BigInt::gcd(num_gcd, num_i);
285 BigInt den_gcd = BigInt::gcd(den_lcm, den_i);
286 den_lcm = den_lcm * den_i / den_gcd;
301MultiPoly MultiPoly::make_primitive()
const
303 if (terms_.empty()) {
307 Rational content = numeric_content();
309 if (content.is_zero() || content ==
Rational(1)) {
310 if (!terms_.empty() && terms_[0].second <
Rational(0)) {
316 std::vector<Term> prim_terms;
317 prim_terms.reserve(terms_.size());
319 for (
const auto& term : terms_) {
320 prim_terms.emplace_back(term.first, term.second / content);
323 if (!prim_terms.empty() && prim_terms[0].second <
Rational(0)) {
324 for (
auto& term : prim_terms) {
325 term.second = -term.second;
330 result.terms_ = std::move(prim_terms);
331 result.vars_ = vars_;
332 result.order_ = order_;
单项式序比较器,支持 Lex、GrevLex、DegLex、DegRevLex
多元多项式类 MultiPoly,稀疏表示,支持任意数量变量上的环运算。
bool is_zero(const SymbolicExpr &expression)
std::vector< int > Monomial
单项式类型,以整数向量表示各变量的指数
const std::vector< FGLMPoly > const MonomialOrder & order
@ Rational
Rational numbers
bool divides_monomial(const Monomial &divisor, const Monomial &target)
判断 divisor 是否整除 target