2 * @file MultivariatePolynomial.tpp
4 * @author Sebastian Junges
9 #include "MultivariatePolynomial.h"
12 #include "UnivariatePolynomial.h"
13 #include <carl-logging/carl-logging.h>
14 #include <carl-arith/numbers/numbers.h>
20 #include <type_traits>
25 template<typename Coeff, typename Ordering, typename Policies>
26 TermAdditionManager<MultivariatePolynomial<Coeff,Ordering,Policies>,Ordering> MultivariatePolynomial<Coeff,Ordering,Policies>::mTermAdditionManager;
28 template<typename Coeff, typename Ordering, typename Policies>
29 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial():
30 mTerms(), mOrdered(true)
32 assert(this->is_consistent());
35 template<typename Coeff, typename Ordering, typename Policies>
36 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const MultivariatePolynomial<Coeff, Ordering, Policies>& p):
39 mOrdered(p.isOrdered())
41 assert(this->is_consistent());
44 template<typename Coeff, typename Ordering, typename Policies>
45 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(MultivariatePolynomial<Coeff, Ordering, Policies>&& p):
47 mTerms(std::move(p.mTerms)),
48 mOrdered(p.isOrdered())
50 assert(this->is_consistent());
53 template<typename Coeff, typename Ordering, typename Policies>
54 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator=(const MultivariatePolynomial<Coeff,Ordering,Policies>& p) {
55 Policies::operator=(p);
57 mOrdered = p.mOrdered;
58 assert(this->is_consistent());
62 template<typename Coeff, typename Ordering, typename Policies>
63 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator=(MultivariatePolynomial<Coeff,Ordering,Policies>&& p) noexcept {
64 Policies::operator=(p);
65 mTerms = std::move(p.mTerms);
66 mOrdered = p.mOrdered;
67 assert(this->is_consistent());
71 template<typename Coeff, typename Ordering, typename Policies>
73 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(EnableIfNotSame<C,sint> c) : MultivariatePolynomial(from_int<Coeff>(c))
76 assert(this->is_consistent());
79 template<typename Coeff, typename Ordering, typename Policies>
81 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(EnableIfNotSame<C,uint> c) : MultivariatePolynomial(from_int<Coeff>(c))
84 assert(this->is_consistent());
87 template<typename Coeff, typename Ordering, typename Policies>
88 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const Coeff& c) :
90 mTerms(c == Coeff(0) ? 0 : 1, Term<Coeff>(c)),
93 assert(this->is_consistent());
96 template<typename Coeff, typename Ordering, typename Policies>
97 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(Variable::Arg v) :
99 mTerms(1,Term<Coeff>(v)),
102 assert(this->is_consistent());
105 template<typename Coeff, typename Ordering, typename Policies>
106 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const Monomial::Arg& m) :
108 mTerms(1,Term<Coeff>(m)),
111 assert(this->is_consistent());
114 template<typename Coeff, typename Ordering, typename Policies>
115 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const Term<Coeff>& t) :
120 if (carl::is_zero(t)) {
121 this->mTerms.clear();
123 assert(this->is_consistent());
126 template<typename Coeff, typename Ordering, typename Policies>
127 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const UnivariatePolynomial<MultivariatePolynomial<Coeff, Ordering, Policies>>& p):
132 auto id = mTermAdditionManager.getId();
134 for (const auto& c: p.coefficients()) {
136 for (const auto& term: c) mTermAdditionManager.template addTerm<true>(id, term);
138 for (const auto& term: c * Term<Coeff>(constant_one<Coeff>::get(), p.main_var(), exp)) {
139 mTermAdditionManager.template addTerm<true>(id, term);
144 mTermAdditionManager.readTerms(id, mTerms);
145 makeMinimallyOrdered<false, true>();
146 assert(this->is_consistent());
149 template<typename Coeff, typename Ordering, typename Policies>
150 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const UnivariatePolynomial<Coeff>& p) :
156 mTerms.reserve(p.degree());
157 for (const auto& c: p.coefficients()) {
158 if (!carl::is_zero(c)) {
159 if (exp == 0) mTerms.emplace_back(c);
160 else mTerms.emplace_back(c, p.main_var(), exp);
164 assert(this->is_consistent());
167 template<typename Coeff, typename Ordering, typename Policies>
168 template<typename OtherPolicies, DisableIf<std::is_same<Policies,OtherPolicies>>>
169 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const MultivariatePolynomial<Coeff, Ordering, OtherPolicies>& pol) :
171 mTerms(pol.begin(), pol.end()),
172 mOrdered(pol.isOrdered())
174 assert(this->is_consistent());
177 template<typename Coeff, typename Ordering, typename Policies>
179 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(TermsType&& terms, bool duplicates, bool ordered) :
181 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(MultivariatePolynomial<Coeff, Ordering, Policies>::TermsType&& terms, bool duplicates, bool ordered):
183 mTerms(std::move(terms)),
187 auto id = mTermAdditionManager.getId(mTerms.size());
188 for (const auto& t: mTerms) mTermAdditionManager.template addTerm<false>(id, t);
189 mTermAdditionManager.readTerms(id, mTerms);
194 makeMinimallyOrdered();
197 assert(this->is_consistent());
200 template<typename Coeff, typename Ordering, typename Policies>
202 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const TermsType& terms, bool duplicates, bool ordered) :
204 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const MultivariatePolynomial<Coeff, Ordering, Policies>::TermsType& terms, bool duplicates, bool ordered) :
210 auto id = mTermAdditionManager.getId(mTerms.size());
211 for (const auto& t: mTerms) {
212 mTermAdditionManager.template addTerm<false>(id, t);
214 mTermAdditionManager.readTerms(id, mTerms);
217 makeMinimallyOrdered();
219 assert(this->is_consistent());
222 template<typename Coeff, typename Ordering, typename Policies>
223 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const std::initializer_list<Term<Coeff>>& terms):
228 makeMinimallyOrdered();
229 assert(this->is_consistent());
232 template<typename Coeff, typename Ordering, typename Policies>
233 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const std::initializer_list<Variable>& terms):
237 for (const Variable& t: terms) {
238 mTerms.emplace_back(t);
240 makeMinimallyOrdered();
241 assert(this->is_consistent());
244 template<typename Coeff, typename Ordering, typename Policies>
245 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const std::pair<ConstructorOperation, std::vector<MultivariatePolynomial>>& p)
246 : MultivariatePolynomial(p.first, p.second)
250 template<typename Coeff, typename Ordering, typename Policies>
251 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(ConstructorOperation op, const std::vector<MultivariatePolynomial>& operands):
255 assert(!operands.empty());
256 auto it = operands.begin();
258 if ((op == ConstructorOperation::SUB) && (operands.size() == 1)) {
259 // special treatment of unary minus
261 assert(this->is_consistent());
264 if (op == ConstructorOperation::DIV) {
265 // division shall have at least two arguments
266 assert(operands.size() >= 2);
268 for (it++; it != operands.end(); it++) {
270 case ConstructorOperation::ADD: *this += *it; break;
271 case ConstructorOperation::SUB: *this -= *it; break;
272 case ConstructorOperation::MUL: *this *= *it; break;
273 case ConstructorOperation::DIV:
274 assert(it->is_constant());
275 *this /= it->constant_part();
279 assert(this->is_consistent());
282 template<typename Coeff, typename Ordering, typename Policies>
283 std::size_t MultivariatePolynomial<Coeff,Ordering,Policies>::total_degree() const
285 if (carl::is_zero(*this)) return 0;
286 assert(!mTerms.empty());
287 if (Ordering::degreeOrder) {
288 return this->lterm().tdeg();
290 CARL_LOG_NOTIMPLEMENTED();
294 template<typename Coeff, typename Ordering, typename Policies>
295 const Coeff& MultivariatePolynomial<Coeff, Ordering, Policies>::constant_part() const
297 if(carl::is_zero(*this)) return constant_zero<Coeff>::get();
298 if(trailingTerm().is_constant()) {
299 return trailingTerm().coeff();
301 return constant_zero<Coeff>::get();
304 template<typename Coeff, typename Ordering, typename Policies>
305 bool MultivariatePolynomial<Coeff,Ordering,Policies>::is_linear() const {
306 if (carl::is_zero(*this)) return true;
307 if (Ordering::degreeOrder) {
308 return lterm().is_linear();
310 return std::all_of(mTerms.begin(), mTerms.end(),
311 [](const auto& t){ return t.is_linear(); }
316 template<typename Coeff, typename Ordering, typename Policies>
317 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::tail(bool makeFullyOrdered) const
319 assert(!mTerms.empty());
320 assert(this->is_consistent());
321 if (mTerms.size() == 1) return MultivariatePolynomial();
322 MultivariatePolynomial tail;
323 tail.mTerms.reserve(mTerms.size()-1);
324 tail.mTerms.insert(tail.mTerms.begin(), mTerms.begin(), --mTerms.end());
327 assert(tail.mOrdered);
331 tail.mOrdered = false;
338 tail.makeMinimallyOrdered();
341 assert(tail.is_consistent());
345 template<typename Coeff, typename Ordering, typename Policies>
346 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::strip_lterm()
348 assert(!carl::is_zero(*this));
350 if (!isOrdered()) makeMinimallyOrdered<false, true>();
351 assert(this->is_consistent());
355 template<typename Coeff, typename Ordering, typename Policies>
356 bool MultivariatePolynomial<Coeff,Ordering,Policies>::is_univariate() const {
357 // A constant polynomial is obviously univariate.
358 if (is_constant()) return true;
360 if (this->lterm().num_variables() > 1) {
364 Variable v = lterm().single_variable();
365 for (const auto& term : mTerms) {
366 if (!term.has_no_other_variable(v)) return false;
371 template<typename Coeff, typename Ordering, typename Policies>
372 bool MultivariatePolynomial<Coeff,Ordering,Policies>::is_reducible_identity() const
374 CARL_LOG_NOTIMPLEMENTED();
378 template<typename Coeff, typename Ordering, typename Policies>
379 void MultivariatePolynomial<Coeff,Ordering,Policies>::subtractProduct(const Term<Coeff>& factor, const MultivariatePolynomial<Coeff,Ordering,Policies> & p) {
380 assert(this->is_consistent());
381 assert(p.is_consistent());
382 if (carl::is_zero(p)) return;
383 if (carl::is_zero(*this)) {
384 *this = - factor * p;
385 assert(this->is_consistent());
387 if (carl::is_zero(factor.coeff())) return;
388 if (p.nr_terms() == 1) {
389 for (const auto& t: p) {
390 this->addTerm(- factor * t);
392 assert(is_consistent());
396 auto id = mTermAdditionManager.getId(mTerms.size() + p.mTerms.size());
397 for (const auto& term: mTerms) {
398 mTermAdditionManager.template addTerm<false>(id, term);
400 for (const auto& term: p.mTerms) {
401 Coeff c = - factor.coeff() * term.coeff();
402 auto m = factor.monomial() * term.monomial();
403 mTermAdditionManager.template addTerm<false>(id, TermType(c, m));
405 mTermAdditionManager.readTerms(id, mTerms);
407 makeMinimallyOrdered<false, true>();
408 assert(this->is_consistent());
411 template<typename Coeff, typename Ordering, typename Policies>
412 void MultivariatePolynomial<Coeff,Ordering,Policies>::addTerm(const Term<Coeff>& term) {
413 //std::cout << *this << " + " << term << std::endl;
414 if (term.is_constant()) {
415 if (has_constant_term()) {
416 trailingTerm().coeff() += term.coeff();
417 if (carl::is_zero(trailingTerm().coeff())) {
418 mTerms.erase(mTerms.begin());
420 } else mTerms.insert(mTerms.begin(), term);
424 auto it = mTerms.begin();
425 for (; it != mTerms.end(); it++) {
426 CompareResult res = Ordering::compare(term, *it);
428 case CompareResult::LESS: break;
429 case CompareResult::EQUAL: {
430 it->coeff() += term.coeff();
431 if (carl::is_zero(it->coeff())) {
436 case CompareResult::GREATER: ;
439 mTerms.insert(it, term);
441 switch (Ordering::compare(lterm(), term)) {
442 case CompareResult::LESS: {
443 mTerms.push_back(term);
446 case CompareResult::EQUAL: {
447 lterm().coeff() += term.coeff();
448 if (carl::is_zero(lterm().coeff())) {
450 makeMinimallyOrdered<false,true>();
454 case CompareResult::GREATER: {
455 for (auto it = mTerms.begin(); it != mTerms.end(); it++) {
456 if (Ordering::equal(*it, term)) {
457 it->coeff() += term.coeff();
458 if (carl::is_zero(it->coeff())) {
464 auto lt = mTerms.back();
465 mTerms.push_back(term);
466 std::swap(lt, mTerms.back());
472 template<typename Coeff, typename Ordering, typename Policies>
473 Coeff MultivariatePolynomial<Coeff,Ordering,Policies>::coprime_factor() const
475 assert(!carl::is_zero(*this));
477 if constexpr (carl::is_subset_of_rationals_type<Coeff>::value) {
479 auto num = carl::abs(carl::get_num(it->coeff()));
480 auto den = carl::abs(carl::get_denom(it->coeff()));
481 for (++it; it != end(); ++it) {
482 num = carl::gcd(num, carl::abs(carl::get_num(it->coeff())));
483 den = carl::lcm(den, carl::abs(carl::get_denom(it->coeff())));
488 return Coeff(den) / num;
494 template<typename Coeff, typename Ordering, typename Policies>
495 template<typename C, EnableIf<is_subset_of_rationals_type<C>>>
496 Coeff MultivariatePolynomial<Coeff,Ordering,Policies>::coprime_factor_without_constant() const
498 assert(!carl::is_zero(*this));
499 typename TermsType::const_iterator it = mTerms.begin();
500 if (it->is_constant()) ++it;
501 typename IntegralType<Coeff>::type num = carl::abs(get_num((it)->coeff()));
502 typename IntegralType<Coeff>::type den = carl::abs(get_denom((it)->coeff()));
503 for(++it; it != mTerms.end(); ++it)
505 num = carl::gcd(num, get_num((it)->coeff()));
506 den = carl::lcm(den, get_denom((it)->coeff()));
508 if( carl::is_negative(lcoeff()) )
510 return Coeff(den)/(-num);
514 return Coeff(den)/num;
518 template<typename Coeff, typename Ordering, typename Policies>
519 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::coprime_coefficients() const
521 if(carl::is_zero(*this)) return *this;
522 Coeff factor = coprime_factor();
523 // Notice that even if factor is 1, we create a new polynomial
524 MultivariatePolynomial<Coeff, Ordering, Policies> result;
525 result.mTerms.reserve(mTerms.size());
526 for (const auto& term: mTerms)
528 result.mTerms.push_back(term * factor);
530 result.mOrdered = mOrdered;
531 assert(result.is_consistent());
535 template<typename Coeff, typename Ordering, typename Policies>
536 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::coprime_coefficients_sign_preserving() const
538 if(nr_terms() == 0) return *this;
539 Coeff factor = carl::abs(coprime_factor());
540 // Notice that even if factor is 1, we create a new polynomial
541 MultivariatePolynomial<Coeff, Ordering, Policies> result;
542 result.mTerms.reserve(mTerms.size());
543 for (const auto& term: mTerms)
545 result.mTerms.push_back(term * factor);
547 result.mOrdered = mOrdered;
548 assert(result.is_consistent());
552 template<typename Coeff, typename Ordering, typename Policies>
553 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::normalize() const
555 MultivariatePolynomial result(*this);
556 if(Policies::has_reasons)
558 result.setReasons(this->getReasons());
560 if (carl::is_zero(*this)) return result;
562 for (auto& it: result.mTerms)
566 assert(result.is_consistent());
570 template<typename Coeff, typename Ordering, typename Policies>
571 bool MultivariatePolynomial<Coeff,Ordering,Policies>::sqrt(MultivariatePolynomial<Coeff,Ordering,Policies>& res) const
573 if (carl::is_zero(*this)) {
576 } else if (mTerms.size() == 1) {
578 if (mTerms.back().sqrt(t)) {
579 res = MultivariatePolynomial(t);
586 template<typename Coeff, typename O, typename P>
587 template<typename C, EnableIf<is_number_type<C>>>
588 Coeff MultivariatePolynomial<Coeff,O,P>::numeric_content() const
590 if (carl::is_zero(*this)) return 0;
591 typename UnderlyingNumberType<C>::type res = this->mTerms.front().coeff();
592 for (unsigned i = 0; i < this->mTerms.size(); i++) {
593 ///@todo gcd needed for fractions
594 res = carl::gcd(res, this->mTerms[i].coeff());
600 template<typename Coeff, typename O, typename P>
601 template<typename C, DisableIf<is_number_type<C>>>
602 typename UnderlyingNumberType<C>::type MultivariatePolynomial<Coeff,O,P>::numeric_content() const
604 if (carl::is_zero(*this)) return 0;
605 typename UnderlyingNumberType<C>::type res = this->mTerms.front()->coeff().numeric_content();
606 for (const auto& t: mTerms) {
607 res = gcd(res, t->coeff().numeric_content());
612 template<typename Coeff, typename O, typename P>
613 template<typename C, EnableIf<is_number_type<C>>>
614 typename MultivariatePolynomial<Coeff,O,P>::IntNumberType MultivariatePolynomial<Coeff,O,P>::main_denom() const {
615 IntNumberType res = 1;
616 for (const auto& t: mTerms) {
617 res = carl::lcm(res, get_denom(t.coeff()));
622 template<typename Coeff, typename Ordering, typename Policies>
623 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const MultivariatePolynomial& rhs)
625 assert(this->is_consistent());
626 assert(rhs.is_consistent());
627 if (mTerms.empty()) {
629 assert(this->is_consistent());
632 if (rhs.mTerms.empty()) return *this;
633 if (rhs.is_constant()) {
634 return *this += rhs.constant_part();
636 if (this->is_constant()) {
637 Coeff c = constant_part();
642 CompareResult res = Ordering::compare(lterm().monomial(), rhs.lterm().monomial());
643 auto rhsEnd = rhs.mTerms.end();
644 if (res == CompareResult::GREATER) {
645 newlterm = std::move( mTerms.back() );
647 } else if (res == CompareResult::LESS) {
648 newlterm = rhs.lterm();
651 mTerms.back().coeff() += rhs.lcoeff();
652 newlterm = std::move( mTerms.back() );
656 auto id = mTermAdditionManager.getId(mTerms.size() + rhs.mTerms.size());
657 for (auto termIter = mTerms.begin(); termIter != mTerms.end(); ++termIter) {
658 mTermAdditionManager.template addTerm<false,false>(id, *termIter);
660 for (auto termIter = rhs.mTerms.begin(); termIter != rhsEnd; ++termIter) {
661 mTermAdditionManager.template addTerm<false,false>(id, *termIter);
663 mTermAdditionManager.readTerms(id, mTerms);
664 if (carl::is_zero(newlterm)) {
665 makeMinimallyOrdered<false,true>();
667 mTerms.push_back(newlterm);
670 assert(this->is_consistent());
671 assert(rhs.is_consistent());
676 /*template<typename Coeff, typename Ordering, typename Policies>
677 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const TermType& rhs) {
678 return *this += std::make_shared<const TermType>(rhs);
681 template<typename Coeff, typename Ordering, typename Policies>
682 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const TermType& rhs)
684 assert(this->is_consistent());
685 if (carl::is_zero(rhs.coeff())) return *this;
686 if (mTerms.empty()) {
687 // Empty -> just insert.
688 mTerms.push_back(rhs);
690 } else if (rhs.is_constant()) {
691 if (this->has_constant_term()) {
692 // Combine with constant term.
693 if (carl::is_zero(Coeff(mTerms.front().coeff() + rhs.coeff()))) {
694 mTerms.erase(mTerms.begin());
695 } else mTerms.front() = Term<Coeff>(mTerms.front().coeff() + rhs.coeff(), nullptr);
696 } else if (mTerms.size() == 1) {
697 // Only a single term, insert and swap.
698 mTerms.push_back(rhs);
699 std::swap(mTerms[0], mTerms[1]);
701 assert(mTerms.size() > 1);
702 // New constant term. Add at the end and swap to correct position.
703 mTerms.push_back(rhs);
704 std::swap(mTerms.front(), mTerms.back());
705 assert(rhs == mTerms.front());
706 std::swap(mTerms.back(), *(mTerms.end()-2));
709 } else if (Term<Coeff>::monomialEqual(lterm(), rhs)) {
710 // Combine with leading term.
711 if (carl::is_zero(Coeff(lcoeff() + rhs.coeff()))) {
713 makeMinimallyOrdered<false, true>();
714 } else mTerms.back() = Term<Coeff>(lcoeff() + rhs.coeff(), rhs.monomial());
715 } else if (Ordering::less(lterm(), rhs)) {
717 mTerms.push_back(rhs);
719 // Full-blown addition.
720 auto id = mTermAdditionManager.getId(mTerms.size()+1);
721 for (const auto& term: mTerms) {
722 mTermAdditionManager.template addTerm<false>(id, term);
724 mTermAdditionManager.template addTerm<false>(id, rhs);
725 mTermAdditionManager.readTerms(id, mTerms);
726 makeMinimallyOrdered<false, true>();
729 assert(this->is_consistent());
733 template<typename Coeff, typename Ordering, typename Policies>
734 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const Monomial::Arg& rhs)
736 if (mTerms.empty()) {
737 // Empty -> just insert.
738 mTerms.emplace_back(constant_one<Coeff>::get(), rhs);
740 } else if (lterm().is_constant()) {
741 mTerms.emplace_back(constant_one<Coeff>::get(), rhs);
742 } else if (lmon() == rhs) {
743 // Combine with leading term.
744 if (lcoeff() == -carl::constant_one<Coeff>().get()) {
746 makeMinimallyOrdered<false, true>();
748 mTerms.back() = Term<Coeff>(lcoeff() + constant_one<Coeff>::get(), lmon());
750 } else if (Ordering::less(lmon(),rhs)) {
752 mTerms.emplace_back(rhs);
754 ///@todo insert at correct position if already ordered
755 auto it = mTerms.begin();
756 for (; it != mTerms.end(); it++) {
757 if ((*it).monomial() == rhs) {
758 if ((*it).coeff() == -carl::constant_one<Coeff>().get()) {
761 *it = Term<Coeff>((*it).coeff() + constant_one<Coeff>::get(), (*it).monomial());
766 if (it == mTerms.end()) {
767 mTerms.emplace_back(constant_one<Coeff>::get(), rhs);
768 std::swap(mTerms[mTerms.size()-2], mTerms[mTerms.size()-1]);
772 assert(this->is_consistent());
776 template<typename Coeff, typename Ordering, typename Policies>
777 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(Variable rhs)
779 return *this += createMonomial(rhs, 1);
782 template<typename Coeff, typename Ordering, typename Policies>
783 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const Coeff& rhs)
785 if (carl::is_zero(rhs)) return *this;
786 if (has_constant_term()) {
787 if (carl::is_zero(Coeff(constant_part() + rhs))) mTerms.erase(mTerms.begin());
788 else mTerms.front() = TermType(constant_part() + rhs);
790 mTerms.emplace(mTerms.begin(), rhs);
792 assert(this->is_consistent());
796 template<typename C, typename O, typename P>
797 MultivariatePolynomial<C,O,P> operator+(const UnivariatePolynomial<C>&, const MultivariatePolynomial<C,O,P>&)
799 CARL_LOG_NOTIMPLEMENTED();
802 template<typename C, typename O, typename P>
803 MultivariatePolynomial<C,O,P> operator+(const MultivariatePolynomial<C,O,P>&, const UnivariatePolynomial<C>&)
805 CARL_LOG_NOTIMPLEMENTED();
808 template<typename C, typename O, typename P>
809 MultivariatePolynomial<C,O,P> operator+(const UnivariatePolynomial<MultivariatePolynomial<C>>&, const MultivariatePolynomial<C,O,P>&)
811 CARL_LOG_NOTIMPLEMENTED();
814 template<typename C, typename O, typename P>
815 MultivariatePolynomial<C,O,P> operator+(const MultivariatePolynomial<C,O,P>&, const UnivariatePolynomial<MultivariatePolynomial<C>>&)
817 CARL_LOG_NOTIMPLEMENTED();
820 template<typename Coeff, typename Ordering, typename Policies>
821 MultivariatePolynomial<Coeff, Ordering, Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::operator -() const
823 assert(this->is_consistent());
824 MultivariatePolynomial<Coeff, Ordering, Policies> negation;
825 negation.mTerms.reserve(mTerms.size());
826 for (const auto& term: mTerms) {
827 negation.mTerms.push_back(-term);
829 negation.mOrdered = this->mOrdered;
830 assert(negation.is_consistent());
834 template<typename Coeff, typename Ordering, typename Policies>
835 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const MultivariatePolynomial& rhs)
837 assert(this->is_consistent());
838 assert(rhs.is_consistent());
842 assert(this->is_consistent());
845 if(rhs.mTerms.empty()) return *this;
846 if (rhs.is_constant()) {
847 return *this -= rhs.constant_part();
849 if (this->is_constant()) {
850 Coeff c = constant_part();
855 auto id = mTermAdditionManager.getId(mTerms.size() + rhs.mTerms.size());
856 for (const auto& term: mTerms) {
857 mTermAdditionManager.template addTerm<false>(id, term);
859 for (const auto& term: rhs.mTerms) {
860 mTermAdditionManager.template addTerm<false>(id, -term);
862 mTermAdditionManager.readTerms(id, mTerms);
864 makeMinimallyOrdered<false, true>();
865 assert(this->is_consistent());
869 template<typename Coeff, typename Ordering, typename Policies>
870 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const Term<Coeff>& rhs)
872 ///@todo Check if this works with ordering.
873 if (carl::is_zero(rhs.coeff())) return *this;
874 CARL_LOG_TRACE("carl.core", *this << " -= " << rhs);
875 if (Policies::searchLinear)
877 auto it = mTerms.begin();
878 while(it != mTerms.end())
880 // TODO consider comparing the shared pointers.
881 if ((*it).monomial() != nullptr) {
882 CompareResult cmpres(Ordering::compare((*it), rhs));
883 if( mOrdered && cmpres == CompareResult::GREATER ) break;
884 if( cmpres == CompareResult::EQUAL )
886 // new coefficient would be zero, simply removing is enough.
887 if((*it).coeff() == rhs.coeff())
889 it = mTerms.erase(it);
890 if (it == mTerms.end()) {
891 // We removed the leading term.
892 makeMinimallyOrdered<false,true>();
895 // we have to create a new term object.
898 it->coeff() -= rhs.coeff();
900 CARL_LOG_TRACE("carl.core", "-> " << *this);
901 assert(this->is_consistent());
907 // no equal monomial does occur. We can simply insert.
908 mTerms.insert(it,-rhs);
909 makeMinimallyOrdered<false,true>();
910 CARL_LOG_TRACE("carl.core", "-> " << *this);
911 assert(this->is_consistent());
916 CARL_LOG_NOTIMPLEMENTED();
920 template<typename Coeff, typename Ordering, typename Policies>
921 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const Monomial::Arg& rhs)
923 ///@todo Check if this works with ordering.
926 *this -= constant_one<Coeff>::get();
927 assert(this->is_consistent());
930 if (Policies::searchLinear)
932 auto it = mTerms.begin();
933 while(it != mTerms.end())
935 if ((*it).monomial() != nullptr) {
936 CompareResult cmpres(Ordering::compare((*it).monomial(), rhs));
937 if( mOrdered && cmpres == CompareResult::GREATER ) break;
938 if( cmpres == CompareResult::EQUAL )
940 // new coefficient would be zero, simply removing is enough.
941 if(carl::is_one((*it).coeff()))
943 it = mTerms.erase(it);
944 if (it == mTerms.end()) {
945 // We removed the leading term.
946 makeMinimallyOrdered<false,true>();
949 // we have to create a new term object.
952 it->coeff() -= constant_one<Coeff>::get();
954 assert(this->is_consistent());
960 // no equal monomial does occur. We can simply insert.
961 mTerms.insert(it,Term<Coeff>(-carl::constant_one<Coeff>().get(), rhs));
962 makeMinimallyOrdered<false,true>();
963 assert(this->is_consistent());
968 CARL_LOG_NOTIMPLEMENTED();
972 template<typename Coeff, typename Ordering, typename Policies>
973 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(Variable::Arg rhs)
975 return *this += Term<Coeff>(-carl::constant_one<Coeff>().get(), rhs, 1);
978 template<typename Coeff, typename Ordering, typename Policies>
979 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const Coeff& rhs)
981 return *this += (-rhs);
984 template<typename Coeff, typename Ordering, typename Policies>
985 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const MultivariatePolynomial<Coeff,Ordering,Policies>& rhs)
987 assert(this->is_consistent());
988 assert(rhs.is_consistent());
989 if(mTerms.empty()) return *this;
990 if(rhs.mTerms.empty()) {
992 assert(this->is_consistent());
995 if (rhs.is_constant()) {
996 return *this *= rhs.constant_part();
998 if (carl::is_one(*this)) {
1001 if (this->is_constant()) {
1002 Coeff c = constant_part();
1006 auto id = mTermAdditionManager.getId(mTerms.size() * rhs.mTerms.size());
1009 for (auto t1 = mTerms.rbegin(); t1 != mTerms.rend(); t1++) {
1010 for (auto t2 = rhs.mTerms.rbegin(); t2 != rhs.mTerms.rend(); t2++) {
1012 newlterm = *t1 * *t2;
1014 } else mTermAdditionManager.template addTerm<false>(id, std::move((*t1)*(*t2)));
1017 mTermAdditionManager.readTerms(id, mTerms);
1018 if (carl::is_zero(newlterm)) makeMinimallyOrdered<false, true>();
1019 else mTerms.push_back(newlterm);
1020 //makeMinimallyOrdered<false, true>();
1022 assert(this->is_consistent());
1025 template<typename Coeff, typename Ordering, typename Policies>
1026 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const Term<Coeff>& rhs)
1028 assert(this->is_consistent());
1029 ///@todo more efficient.
1031 newTerms.reserve(mTerms.size());
1032 for(const auto& term : mTerms)
1034 newTerms.push_back(term * rhs);
1036 mTerms = std::move(newTerms);
1037 assert(this->is_consistent());
1040 template<typename Coeff, typename Ordering, typename Policies>
1041 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const Monomial::Arg& rhs)
1043 assert(this->is_consistent());
1044 ///@todo more efficient.
1046 newTerms.reserve(mTerms.size());
1047 for(const auto& term : mTerms)
1049 newTerms.push_back(term * rhs);
1051 mTerms = std::move(newTerms);
1052 assert(this->is_consistent());
1055 template<typename Coeff, typename Ordering, typename Policies>
1056 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(Variable::Arg rhs)
1058 ///@todo more efficient.
1060 newTerms.reserve(mTerms.size());
1061 for(const auto& term : mTerms)
1063 newTerms.push_back(term * rhs);
1065 mTerms = std::move(newTerms);
1066 assert(this->is_consistent());
1069 template<typename Coeff, typename Ordering, typename Policies>
1070 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const Coeff& rhs)
1072 ///@todo more efficient.
1073 if (carl::is_one(rhs)) return *this;
1074 if (carl::is_zero(rhs))
1077 assert(this->is_consistent());
1081 newTerms.reserve(mTerms.size());
1082 for(const auto& term : mTerms)
1084 newTerms.push_back(term * rhs);
1086 mTerms = std::move(newTerms);
1087 assert(this->is_consistent());
1091 template<typename C, typename O, typename P>
1092 const MultivariatePolynomial<C,O,P> operator*(const UnivariatePolynomial<C>&, const MultivariatePolynomial<C,O,P>&)
1094 CARL_LOG_NOTIMPLEMENTED();
1096 template<typename C, typename O, typename P>
1097 const MultivariatePolynomial<C,O,P> operator*(const MultivariatePolynomial<C,O,P>& lhs, const UnivariatePolynomial<C>& rhs)
1101 template<typename Coeff, typename Ordering, typename Policies>
1102 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator/=(const Coeff& rhs)
1104 assert(!carl::is_zero(rhs));
1105 if (carl::is_one(rhs)) return *this;
1106 for (auto& term : mTerms) {
1107 term.coeff() /= rhs;
1109 assert(this->is_consistent());
1113 template<typename C, typename O, typename P>
1114 MultivariatePolynomial<C,O,P> operator/(const MultivariatePolynomial<C,O,P>& lhs, unsigned long rhs)
1116 MultivariatePolynomial<C,O,P> result;
1117 for (const auto& t: lhs.mTerms) {
1118 result.mTerms.emplace_back(t/rhs);
1120 result.mOrdered = lhs.mOrdered;
1121 assert(result.is_consistent());
1125 template<typename Coeff, typename Ordering, typename Policies>
1126 template<bool findConstantTerm, bool findLeadingTerm>
1127 void MultivariatePolynomial<Coeff, Ordering, Policies>::makeMinimallyOrdered() const {
1128 static_assert(findLeadingTerm, "We do not have implementations of makeMinimallyOrdered() which assume a given leading term position.");
1129 if(findConstantTerm)
1131 if (mTerms.size() < 2) return;
1132 auto it = mTerms.begin();
1134 auto constTerm = mTerms.end();
1135 if ((*it).is_constant()) constTerm = it;
1137 for (it++; it != mTerms.end();) {
1138 if ((*it).is_constant()) {
1139 assert(constTerm == mTerms.end());
1141 } else if (Ordering::less(*lTerm, *it)) {
1144 assert(!Term<Coeff>::monomialEqual(*lTerm, *it));
1148 makeMinimallyOrdered(lTerm, constTerm);
1152 if (mTerms.size() < 2) return;
1153 auto it = mTerms.begin();
1154 const auto itToLast = mTerms.end() - 1;
1157 for (it++; it != itToLast; ++it) {
1158 if (Ordering::less(*lTerm, *it)) {
1161 assert(!Term<Coeff>::monomialEqual(*lTerm, *it));
1165 assert(!Term<Coeff>::monomialEqual(*lTerm, *itToLast));
1166 if (!Ordering::less(*lTerm, *itToLast)) {
1167 std::swap(*lTerm, mTerms.back());
1173 template<typename Coeff, typename Ordering, typename Policies>
1174 void MultivariatePolynomial<Coeff, Ordering, Policies>::makeMinimallyOrdered(typename TermsType::iterator& lterm, typename TermsType::iterator& cterm) const {
1175 if (cterm != mTerms.end()) {
1176 // Prevent that the swaps cancel each other.
1177 if (lterm == mTerms.begin()) lterm = cterm;
1178 std::swap(*cterm, mTerms.front());
1180 std::swap(*lterm, mTerms.back());
1183 template<typename Coeff, typename Ordering, typename Policies>
1184 bool MultivariatePolynomial<Coeff, Ordering, Policies>::is_consistent() const {
1185 std::set<Monomial::Arg> monomials;
1186 for (unsigned i = 0; i < this->mTerms.size(); i++) {
1187 //assert(this->mTerms[i]);
1188 assert(!carl::is_zero(mTerms[i]));
1190 assert(this->mTerms[i].tdeg() > 0);
1192 auto it = monomials.insert(mTerms[i].monomial());
1196 for (unsigned i = 1; i < this->mTerms.size(); i++) {
1197 if (!Ordering::less(mTerms[i-1], mTerms[i])) {
1198 CARL_LOG_ERROR("carl.core", "Ordering error for " << *this << ": " << mTerms[i-1] << " < " << mTerms[i]);
1200 assert(Ordering::less(mTerms[i-1], mTerms[i]));
1207 for (unsigned i = 0; i < this->mTerms.size() - 1; i++) {
1208 if (!Ordering::less(mTerms[i], lterm())) {
1209 CARL_LOG_ERROR("carl.core", "Ordering error for " << *this << ": " << mTerms[i] << " < " << lterm());
1211 assert(Ordering::less(mTerms[i], lterm()));