carl  24.04
Computer ARithmetic Library
MultivariatePolynomial.tpp
Go to the documentation of this file.
1 /**
2  * @file MultivariatePolynomial.tpp
3  * @ingroup multirp
4  * @author Sebastian Junges
5  */
6 
7 #pragma once
8 
9 #include "MultivariatePolynomial.h"
10 
11 #include "Term.h"
12 #include "UnivariatePolynomial.h"
13 #include <carl-logging/carl-logging.h>
14 #include <carl-arith/numbers/numbers.h>
15 
16 #include <algorithm>
17 #include <memory>
18 #include <mutex>
19 #include <list>
20 #include <type_traits>
21 
22 namespace carl
23 {
24 
25 template<typename Coeff, typename Ordering, typename Policies>
26 TermAdditionManager<MultivariatePolynomial<Coeff,Ordering,Policies>,Ordering> MultivariatePolynomial<Coeff,Ordering,Policies>::mTermAdditionManager;
27 
28 template<typename Coeff, typename Ordering, typename Policies>
29 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial():
30  mTerms(), mOrdered(true)
31 {
32  assert(this->is_consistent());
33 }
34 
35 template<typename Coeff, typename Ordering, typename Policies>
36 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const MultivariatePolynomial<Coeff, Ordering, Policies>& p):
37  Policies(p),
38  mTerms(p.mTerms),
39  mOrdered(p.isOrdered())
40 {
41  assert(this->is_consistent());
42 }
43 
44 template<typename Coeff, typename Ordering, typename Policies>
45 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(MultivariatePolynomial<Coeff, Ordering, Policies>&& p):
46  Policies(p),
47  mTerms(std::move(p.mTerms)),
48  mOrdered(p.isOrdered())
49 {
50  assert(this->is_consistent());
51 }
52 
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);
56  mTerms = p.mTerms;
57  mOrdered = p.mOrdered;
58  assert(this->is_consistent());
59  return *this;
60 }
61 
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());
68  return *this;
69 }
70 
71 template<typename Coeff, typename Ordering, typename Policies>
72 template<typename C>
73 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(EnableIfNotSame<C,sint> c) : MultivariatePolynomial(from_int<Coeff>(c))
74 {
75  mOrdered = true;
76  assert(this->is_consistent());
77 }
78 
79 template<typename Coeff, typename Ordering, typename Policies>
80 template<typename C>
81 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(EnableIfNotSame<C,uint> c) : MultivariatePolynomial(from_int<Coeff>(c))
82 {
83  mOrdered = true;
84  assert(this->is_consistent());
85 }
86 
87 template<typename Coeff, typename Ordering, typename Policies>
88 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const Coeff& c) :
89  Policies(),
90  mTerms(c == Coeff(0) ? 0 : 1, Term<Coeff>(c)),
91  mOrdered(true)
92 {
93  assert(this->is_consistent());
94 }
95 
96 template<typename Coeff, typename Ordering, typename Policies>
97 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(Variable::Arg v) :
98  Policies(),
99  mTerms(1,Term<Coeff>(v)),
100  mOrdered(true)
101 {
102  assert(this->is_consistent());
103 }
104 
105 template<typename Coeff, typename Ordering, typename Policies>
106 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const Monomial::Arg& m) :
107  Policies(),
108  mTerms(1,Term<Coeff>(m)),
109  mOrdered(true)
110 {
111  assert(this->is_consistent());
112 }
113 
114 template<typename Coeff, typename Ordering, typename Policies>
115 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const Term<Coeff>& t) :
116  Policies(),
117  mTerms(1,t),
118  mOrdered(true)
119 {
120  if (carl::is_zero(t)) {
121  this->mTerms.clear();
122  }
123  assert(this->is_consistent());
124 }
125 
126 template<typename Coeff, typename Ordering, typename Policies>
127 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const UnivariatePolynomial<MultivariatePolynomial<Coeff, Ordering, Policies>>& p):
128  Policies(),
129  mTerms(),
130  mOrdered(false)
131 {
132  auto id = mTermAdditionManager.getId();
133  exponent exp = 0;
134  for (const auto& c: p.coefficients()) {
135  if (exp == 0) {
136  for (const auto& term: c) mTermAdditionManager.template addTerm<true>(id, term);
137  } else {
138  for (const auto& term: c * Term<Coeff>(constant_one<Coeff>::get(), p.main_var(), exp)) {
139  mTermAdditionManager.template addTerm<true>(id, term);
140  }
141  }
142  exp++;
143  }
144  mTermAdditionManager.readTerms(id, mTerms);
145  makeMinimallyOrdered<false, true>();
146  assert(this->is_consistent());
147 }
148 
149 template<typename Coeff, typename Ordering, typename Policies>
150 MultivariatePolynomial<Coeff,Ordering,Policies>::MultivariatePolynomial(const UnivariatePolynomial<Coeff>& p) :
151  Policies(),
152  mTerms(),
153  mOrdered(true)
154 {
155  exponent exp = 0;
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);
161  }
162  exp++;
163  }
164  assert(this->is_consistent());
165 }
166 
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) :
170  Policies(),
171  mTerms(pol.begin(), pol.end()),
172  mOrdered(pol.isOrdered())
173 {
174  assert(this->is_consistent());
175 }
176 
177 template<typename Coeff, typename Ordering, typename Policies>
178 #ifdef __VS
179 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(TermsType&& terms, bool duplicates, bool ordered) :
180 #else
181 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(MultivariatePolynomial<Coeff, Ordering, Policies>::TermsType&& terms, bool duplicates, bool ordered):
182 #endif
183  mTerms(std::move(terms)),
184  mOrdered(ordered)
185 {
186  if( duplicates ) {
187  auto id = mTermAdditionManager.getId(mTerms.size());
188  for (const auto& t: mTerms) mTermAdditionManager.template addTerm<false>(id, t);
189  mTermAdditionManager.readTerms(id, mTerms);
190  mOrdered = false;
191  }
192 
193  if (!mOrdered) {
194  makeMinimallyOrdered();
195  }
196 
197  assert(this->is_consistent());
198 }
199 
200 template<typename Coeff, typename Ordering, typename Policies>
201 #ifdef __VS
202 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const TermsType& terms, bool duplicates, bool ordered) :
203 #else
204 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const MultivariatePolynomial<Coeff, Ordering, Policies>::TermsType& terms, bool duplicates, bool ordered) :
205 #endif
206  mTerms(terms),
207  mOrdered(ordered)
208 {
209  if( duplicates ) {
210  auto id = mTermAdditionManager.getId(mTerms.size());
211  for (const auto& t: mTerms) {
212  mTermAdditionManager.template addTerm<false>(id, t);
213  }
214  mTermAdditionManager.readTerms(id, mTerms);
215  }
216  if (!ordered) {
217  makeMinimallyOrdered();
218  }
219  assert(this->is_consistent());
220 }
221 
222 template<typename Coeff, typename Ordering, typename Policies>
223 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const std::initializer_list<Term<Coeff>>& terms):
224  Policies(),
225  mTerms(terms),
226  mOrdered(false)
227 {
228  makeMinimallyOrdered();
229  assert(this->is_consistent());
230 }
231 
232 template<typename Coeff, typename Ordering, typename Policies>
233 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(const std::initializer_list<Variable>& terms):
234  mTerms(),
235  mOrdered(false)
236 {
237  for (const Variable& t: terms) {
238  mTerms.emplace_back(t);
239  }
240  makeMinimallyOrdered();
241  assert(this->is_consistent());
242 }
243 
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)
247 {
248 }
249 
250 template<typename Coeff, typename Ordering, typename Policies>
251 MultivariatePolynomial<Coeff, Ordering, Policies>::MultivariatePolynomial(ConstructorOperation op, const std::vector<MultivariatePolynomial>& operands):
252  mTerms(),
253  mOrdered(false)
254 {
255  assert(!operands.empty());
256  auto it = operands.begin();
257  *this = *it;
258  if ((op == ConstructorOperation::SUB) && (operands.size() == 1)) {
259  // special treatment of unary minus
260  *this *= -1;
261  assert(this->is_consistent());
262  return;
263  }
264  if (op == ConstructorOperation::DIV) {
265  // division shall have at least two arguments
266  assert(operands.size() >= 2);
267  }
268  for (it++; it != operands.end(); it++) {
269  switch (op) {
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();
276  break;
277  }
278  }
279  assert(this->is_consistent());
280 }
281 
282 template<typename Coeff, typename Ordering, typename Policies>
283 std::size_t MultivariatePolynomial<Coeff,Ordering,Policies>::total_degree() const
284 {
285  if (carl::is_zero(*this)) return 0;
286  assert(!mTerms.empty());
287  if (Ordering::degreeOrder) {
288  return this->lterm().tdeg();
289  } else {
290  CARL_LOG_NOTIMPLEMENTED();
291  }
292 }
293 
294 template<typename Coeff, typename Ordering, typename Policies>
295 const Coeff& MultivariatePolynomial<Coeff, Ordering, Policies>::constant_part() const
296 {
297  if(carl::is_zero(*this)) return constant_zero<Coeff>::get();
298  if(trailingTerm().is_constant()) {
299  return trailingTerm().coeff();
300  }
301  return constant_zero<Coeff>::get();
302 }
303 
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();
309  } else {
310  return std::all_of(mTerms.begin(), mTerms.end(),
311  [](const auto& t){ return t.is_linear(); }
312  );
313  }
314 }
315 
316 template<typename Coeff, typename Ordering, typename Policies>
317 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::tail(bool makeFullyOrdered) const
318 {
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());
325  if(isOrdered())
326  {
327  assert(tail.mOrdered);
328  }
329  else
330  {
331  tail.mOrdered = false;
332  if(makeFullyOrdered)
333  {
334  tail.makeOrdered();
335  }
336  else
337  {
338  tail.makeMinimallyOrdered();
339  }
340  }
341  assert(tail.is_consistent());
342  return tail;
343 }
344 
345 template<typename Coeff, typename Ordering, typename Policies>
346 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::strip_lterm()
347 {
348  assert(!carl::is_zero(*this));
349  mTerms.pop_back();
350  if (!isOrdered()) makeMinimallyOrdered<false, true>();
351  assert(this->is_consistent());
352  return *this;
353 }
354 
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;
359 
360  if (this->lterm().num_variables() > 1) {
361  return false;
362  }
363 
364  Variable v = lterm().single_variable();
365  for (const auto& term : mTerms) {
366  if (!term.has_no_other_variable(v)) return false;
367  }
368  return true;
369 }
370 
371 template<typename Coeff, typename Ordering, typename Policies>
372 bool MultivariatePolynomial<Coeff,Ordering,Policies>::is_reducible_identity() const
373 {
374  CARL_LOG_NOTIMPLEMENTED();
375  return false;
376 }
377 
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());
386  }
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);
391  }
392  assert(is_consistent());
393  return;
394  }
395 
396  auto id = mTermAdditionManager.getId(mTerms.size() + p.mTerms.size());
397  for (const auto& term: mTerms) {
398  mTermAdditionManager.template addTerm<false>(id, term);
399  }
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));
404  }
405  mTermAdditionManager.readTerms(id, mTerms);
406  mOrdered = false;
407  makeMinimallyOrdered<false, true>();
408  assert(this->is_consistent());
409 }
410 
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());
419  }
420  } else mTerms.insert(mTerms.begin(), term);
421  return;
422  }
423  if (mOrdered) {
424  auto it = mTerms.begin();
425  for (; it != mTerms.end(); it++) {
426  CompareResult res = Ordering::compare(term, *it);
427  switch (res) {
428  case CompareResult::LESS: break;
429  case CompareResult::EQUAL: {
430  it->coeff() += term.coeff();
431  if (carl::is_zero(it->coeff())) {
432  mTerms.erase(it);
433  }
434  return;
435  }
436  case CompareResult::GREATER: ;
437  }
438  }
439  mTerms.insert(it, term);
440  } else {
441  switch (Ordering::compare(lterm(), term)) {
442  case CompareResult::LESS: {
443  mTerms.push_back(term);
444  break;
445  }
446  case CompareResult::EQUAL: {
447  lterm().coeff() += term.coeff();
448  if (carl::is_zero(lterm().coeff())) {
449  mTerms.pop_back();
450  makeMinimallyOrdered<false,true>();
451  }
452  break;
453  }
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())) {
459  mTerms.erase(it);
460  }
461  return;
462  }
463  }
464  auto lt = mTerms.back();
465  mTerms.push_back(term);
466  std::swap(lt, mTerms.back());
467  }
468  }
469  }
470 }
471 
472 template<typename Coeff, typename Ordering, typename Policies>
473 Coeff MultivariatePolynomial<Coeff,Ordering,Policies>::coprime_factor() const
474 {
475  assert(!carl::is_zero(*this));
476 
477  if constexpr (carl::is_subset_of_rationals_type<Coeff>::value) {
478  auto it = begin();
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())));
484  }
485  if (lcoeff() < 0) {
486  den = -den;
487  }
488  return Coeff(den) / num;
489  } else {
490  return Coeff(1);
491  }
492 }
493 
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
497 {
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)
504  {
505  num = carl::gcd(num, get_num((it)->coeff()));
506  den = carl::lcm(den, get_denom((it)->coeff()));
507  }
508  if( carl::is_negative(lcoeff()) )
509  {
510  return Coeff(den)/(-num);
511  }
512  else
513  {
514  return Coeff(den)/num;
515  }
516 }
517 
518 template<typename Coeff, typename Ordering, typename Policies>
519 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::coprime_coefficients() const
520 {
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)
527  {
528  result.mTerms.push_back(term * factor);
529  }
530  result.mOrdered = mOrdered;
531  assert(result.is_consistent());
532  return result;
533 }
534 
535 template<typename Coeff, typename Ordering, typename Policies>
536 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::coprime_coefficients_sign_preserving() const
537 {
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)
544  {
545  result.mTerms.push_back(term * factor);
546  }
547  result.mOrdered = mOrdered;
548  assert(result.is_consistent());
549  return result;
550 }
551 
552 template<typename Coeff, typename Ordering, typename Policies>
553 MultivariatePolynomial<Coeff,Ordering,Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::normalize() const
554 {
555  MultivariatePolynomial result(*this);
556  if(Policies::has_reasons)
557  {
558  result.setReasons(this->getReasons());
559  }
560  if (carl::is_zero(*this)) return result;
561  auto lc = lcoeff();
562  for (auto& it: result.mTerms)
563  {
564  it.coeff() /= lc;
565  }
566  assert(result.is_consistent());
567  return result;
568 }
569 
570 template<typename Coeff, typename Ordering, typename Policies>
571 bool MultivariatePolynomial<Coeff,Ordering,Policies>::sqrt(MultivariatePolynomial<Coeff,Ordering,Policies>& res) const
572 {
573  if (carl::is_zero(*this)) {
574  res = *this;
575  return true;
576  } else if (mTerms.size() == 1) {
577  Term<Coeff> t;
578  if (mTerms.back().sqrt(t)) {
579  res = MultivariatePolynomial(t);
580  return true;
581  }
582  }
583  return false;
584 }
585 
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
589 {
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());
595  //assert(false);
596  }
597  return res;
598 }
599 
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
603 {
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());
608  }
609  return res;
610 }
611 
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()));
618  }
619  return res;
620 }
621 
622 template<typename Coeff, typename Ordering, typename Policies>
623 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const MultivariatePolynomial& rhs)
624 {
625  assert(this->is_consistent());
626  assert(rhs.is_consistent());
627  if (mTerms.empty()) {
628  *this = rhs;
629  assert(this->is_consistent());
630  return *this;
631  }
632  if (rhs.mTerms.empty()) return *this;
633  if (rhs.is_constant()) {
634  return *this += rhs.constant_part();
635  }
636  if (this->is_constant()) {
637  Coeff c = constant_part();
638  *this = rhs;
639  return *this += c;
640  }
641  TermType newlterm;
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() );
646  mTerms.pop_back();
647  } else if (res == CompareResult::LESS) {
648  newlterm = rhs.lterm();
649  --rhsEnd;
650  } else {
651  mTerms.back().coeff() += rhs.lcoeff();
652  newlterm = std::move( mTerms.back() );
653  mTerms.pop_back();
654  --rhsEnd;
655  }
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);
659  }
660  for (auto termIter = rhs.mTerms.begin(); termIter != rhsEnd; ++termIter) {
661  mTermAdditionManager.template addTerm<false,false>(id, *termIter);
662  }
663  mTermAdditionManager.readTerms(id, mTerms);
664  if (carl::is_zero(newlterm)) {
665  makeMinimallyOrdered<false,true>();
666  } else {
667  mTerms.push_back(newlterm);
668  }
669  mOrdered = false;
670  assert(this->is_consistent());
671  assert(rhs.is_consistent());
672  return *this;
673 }
674 
675 
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);
679 }*/
680 
681 template<typename Coeff, typename Ordering, typename Policies>
682 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const TermType& rhs)
683 {
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);
689  mOrdered = true;
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]);
700  } else {
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));
707  mOrdered = false;
708  }
709  } else if (Term<Coeff>::monomialEqual(lterm(), rhs)) {
710  // Combine with leading term.
711  if (carl::is_zero(Coeff(lcoeff() + rhs.coeff()))) {
712  mTerms.pop_back();
713  makeMinimallyOrdered<false, true>();
714  } else mTerms.back() = Term<Coeff>(lcoeff() + rhs.coeff(), rhs.monomial());
715  } else if (Ordering::less(lterm(), rhs)) {
716  // New leading term.
717  mTerms.push_back(rhs);
718  } else {
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);
723  }
724  mTermAdditionManager.template addTerm<false>(id, rhs);
725  mTermAdditionManager.readTerms(id, mTerms);
726  makeMinimallyOrdered<false, true>();
727  mOrdered = false;
728  }
729  assert(this->is_consistent());
730  return *this;
731 }
732 
733 template<typename Coeff, typename Ordering, typename Policies>
734 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const Monomial::Arg& rhs)
735 {
736  if (mTerms.empty()) {
737  // Empty -> just insert.
738  mTerms.emplace_back(constant_one<Coeff>::get(), rhs);
739  mOrdered = true;
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()) {
745  mTerms.pop_back();
746  makeMinimallyOrdered<false, true>();
747  } else {
748  mTerms.back() = Term<Coeff>(lcoeff() + constant_one<Coeff>::get(), lmon());
749  }
750  } else if (Ordering::less(lmon(),rhs)) {
751  // New leading term.
752  mTerms.emplace_back(rhs);
753  } else {
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()) {
759  mTerms.erase(it);
760  } else {
761  *it = Term<Coeff>((*it).coeff() + constant_one<Coeff>::get(), (*it).monomial());
762  }
763  break;
764  }
765  }
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]);
769  }
770  mOrdered = false;
771  }
772  assert(this->is_consistent());
773  return *this;
774 }
775 
776 template<typename Coeff, typename Ordering, typename Policies>
777 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(Variable rhs)
778 {
779  return *this += createMonomial(rhs, 1);
780 }
781 
782 template<typename Coeff, typename Ordering, typename Policies>
783 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator+=(const Coeff& rhs)
784 {
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);
789  } else {
790  mTerms.emplace(mTerms.begin(), rhs);
791  }
792  assert(this->is_consistent());
793  return *this;
794 }
795 
796 template<typename C, typename O, typename P>
797 MultivariatePolynomial<C,O,P> operator+(const UnivariatePolynomial<C>&, const MultivariatePolynomial<C,O,P>&)
798 {
799  CARL_LOG_NOTIMPLEMENTED();
800 }
801 
802 template<typename C, typename O, typename P>
803 MultivariatePolynomial<C,O,P> operator+(const MultivariatePolynomial<C,O,P>&, const UnivariatePolynomial<C>&)
804 {
805  CARL_LOG_NOTIMPLEMENTED();
806 }
807 
808 template<typename C, typename O, typename P>
809 MultivariatePolynomial<C,O,P> operator+(const UnivariatePolynomial<MultivariatePolynomial<C>>&, const MultivariatePolynomial<C,O,P>&)
810 {
811  CARL_LOG_NOTIMPLEMENTED();
812 }
813 
814 template<typename C, typename O, typename P>
815 MultivariatePolynomial<C,O,P> operator+(const MultivariatePolynomial<C,O,P>&, const UnivariatePolynomial<MultivariatePolynomial<C>>&)
816 {
817  CARL_LOG_NOTIMPLEMENTED();
818 }
819 
820 template<typename Coeff, typename Ordering, typename Policies>
821 MultivariatePolynomial<Coeff, Ordering, Policies> MultivariatePolynomial<Coeff,Ordering,Policies>::operator -() const
822 {
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);
828  }
829  negation.mOrdered = this->mOrdered;
830  assert(negation.is_consistent());
831  return negation;
832 }
833 
834 template<typename Coeff, typename Ordering, typename Policies>
835 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const MultivariatePolynomial& rhs)
836 {
837  assert(this->is_consistent());
838  assert(rhs.is_consistent());
839  if(mTerms.empty())
840  {
841  *this = -rhs;
842  assert(this->is_consistent());
843  return *this;
844  }
845  if(rhs.mTerms.empty()) return *this;
846  if (rhs.is_constant()) {
847  return *this -= rhs.constant_part();
848  }
849  if (this->is_constant()) {
850  Coeff c = constant_part();
851  *this = -rhs;
852  return *this += c;
853  }
854 
855  auto id = mTermAdditionManager.getId(mTerms.size() + rhs.mTerms.size());
856  for (const auto& term: mTerms) {
857  mTermAdditionManager.template addTerm<false>(id, term);
858  }
859  for (const auto& term: rhs.mTerms) {
860  mTermAdditionManager.template addTerm<false>(id, -term);
861  }
862  mTermAdditionManager.readTerms(id, mTerms);
863  mOrdered = false;
864  makeMinimallyOrdered<false, true>();
865  assert(this->is_consistent());
866  return *this;
867 }
868 
869 template<typename Coeff, typename Ordering, typename Policies>
870 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const Term<Coeff>& rhs)
871 {
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)
876  {
877  auto it = mTerms.begin();
878  while(it != mTerms.end())
879  {
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 )
885  {
886  // new coefficient would be zero, simply removing is enough.
887  if((*it).coeff() == rhs.coeff())
888  {
889  it = mTerms.erase(it);
890  if (it == mTerms.end()) {
891  // We removed the leading term.
892  makeMinimallyOrdered<false,true>();
893  }
894  }
895  // we have to create a new term object.
896  else
897  {
898  it->coeff() -= rhs.coeff();
899  }
900  CARL_LOG_TRACE("carl.core", "-> " << *this);
901  assert(this->is_consistent());
902  return *this;
903  }
904  }
905  ++it;
906  }
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());
912  return *this;
913  }
914  else
915  {
916  CARL_LOG_NOTIMPLEMENTED();
917  }
918 }
919 
920 template<typename Coeff, typename Ordering, typename Policies>
921 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const Monomial::Arg& rhs)
922 {
923  ///@todo Check if this works with ordering.
924  if (!rhs)
925  {
926  *this -= constant_one<Coeff>::get();
927  assert(this->is_consistent());
928  return *this;
929  }
930  if (Policies::searchLinear)
931  {
932  auto it = mTerms.begin();
933  while(it != mTerms.end())
934  {
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 )
939  {
940  // new coefficient would be zero, simply removing is enough.
941  if(carl::is_one((*it).coeff()))
942  {
943  it = mTerms.erase(it);
944  if (it == mTerms.end()) {
945  // We removed the leading term.
946  makeMinimallyOrdered<false,true>();
947  }
948  }
949  // we have to create a new term object.
950  else
951  {
952  it->coeff() -= constant_one<Coeff>::get();
953  }
954  assert(this->is_consistent());
955  return *this;
956  }
957  }
958  ++it;
959  }
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());
964  return *this;
965  }
966  else
967  {
968  CARL_LOG_NOTIMPLEMENTED();
969  }
970 }
971 
972 template<typename Coeff, typename Ordering, typename Policies>
973 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(Variable::Arg rhs)
974 {
975  return *this += Term<Coeff>(-carl::constant_one<Coeff>().get(), rhs, 1);
976 }
977 
978 template<typename Coeff, typename Ordering, typename Policies>
979 MultivariatePolynomial<Coeff, Ordering, Policies>& MultivariatePolynomial<Coeff, Ordering, Policies>::operator-=(const Coeff& rhs)
980 {
981  return *this += (-rhs);
982 }
983 
984 template<typename Coeff, typename Ordering, typename Policies>
985 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const MultivariatePolynomial<Coeff,Ordering,Policies>& rhs)
986 {
987  assert(this->is_consistent());
988  assert(rhs.is_consistent());
989  if(mTerms.empty()) return *this;
990  if(rhs.mTerms.empty()) {
991  mTerms.clear();
992  assert(this->is_consistent());
993  return *this;
994  }
995  if (rhs.is_constant()) {
996  return *this *= rhs.constant_part();
997  }
998  if (carl::is_one(*this)) {
999  return *this = rhs;
1000  }
1001  if (this->is_constant()) {
1002  Coeff c = constant_part();
1003  *this = rhs;
1004  return *this *= c;
1005  }
1006  auto id = mTermAdditionManager.getId(mTerms.size() * rhs.mTerms.size());
1007  TermType newlterm;
1008  bool first = true;
1009  for (auto t1 = mTerms.rbegin(); t1 != mTerms.rend(); t1++) {
1010  for (auto t2 = rhs.mTerms.rbegin(); t2 != rhs.mTerms.rend(); t2++) {
1011  if (first) {
1012  newlterm = *t1 * *t2;
1013  first = false;
1014  } else mTermAdditionManager.template addTerm<false>(id, std::move((*t1)*(*t2)));
1015  }
1016  }
1017  mTermAdditionManager.readTerms(id, mTerms);
1018  if (carl::is_zero(newlterm)) makeMinimallyOrdered<false, true>();
1019  else mTerms.push_back(newlterm);
1020  //makeMinimallyOrdered<false, true>();
1021  mOrdered = false;
1022  assert(this->is_consistent());
1023  return *this;
1024 }
1025 template<typename Coeff, typename Ordering, typename Policies>
1026 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const Term<Coeff>& rhs)
1027 {
1028  assert(this->is_consistent());
1029  ///@todo more efficient.
1030  TermsType newTerms;
1031  newTerms.reserve(mTerms.size());
1032  for(const auto& term : mTerms)
1033  {
1034  newTerms.push_back(term * rhs);
1035  }
1036  mTerms = std::move(newTerms);
1037  assert(this->is_consistent());
1038  return *this;
1039 }
1040 template<typename Coeff, typename Ordering, typename Policies>
1041 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const Monomial::Arg& rhs)
1042 {
1043  assert(this->is_consistent());
1044  ///@todo more efficient.
1045  TermsType newTerms;
1046  newTerms.reserve(mTerms.size());
1047  for(const auto& term : mTerms)
1048  {
1049  newTerms.push_back(term * rhs);
1050  }
1051  mTerms = std::move(newTerms);
1052  assert(this->is_consistent());
1053  return *this;
1054 }
1055 template<typename Coeff, typename Ordering, typename Policies>
1056 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(Variable::Arg rhs)
1057 {
1058  ///@todo more efficient.
1059  TermsType newTerms;
1060  newTerms.reserve(mTerms.size());
1061  for(const auto& term : mTerms)
1062  {
1063  newTerms.push_back(term * rhs);
1064  }
1065  mTerms = std::move(newTerms);
1066  assert(this->is_consistent());
1067  return *this;
1068 }
1069 template<typename Coeff, typename Ordering, typename Policies>
1070 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator*=(const Coeff& rhs)
1071 {
1072  ///@todo more efficient.
1073  if (carl::is_one(rhs)) return *this;
1074  if (carl::is_zero(rhs))
1075  {
1076  mTerms.clear();
1077  assert(this->is_consistent());
1078  return *this;
1079  }
1080  TermsType newTerms;
1081  newTerms.reserve(mTerms.size());
1082  for(const auto& term : mTerms)
1083  {
1084  newTerms.push_back(term * rhs);
1085  }
1086  mTerms = std::move(newTerms);
1087  assert(this->is_consistent());
1088  return *this;
1089 }
1090 
1091 template<typename C, typename O, typename P>
1092 const MultivariatePolynomial<C,O,P> operator*(const UnivariatePolynomial<C>&, const MultivariatePolynomial<C,O,P>&)
1093 {
1094  CARL_LOG_NOTIMPLEMENTED();
1095 }
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)
1098 {
1099  return rhs * lhs;
1100 }
1101 template<typename Coeff, typename Ordering, typename Policies>
1102 MultivariatePolynomial<Coeff,Ordering,Policies>& MultivariatePolynomial<Coeff,Ordering,Policies>::operator/=(const Coeff& rhs)
1103 {
1104  assert(!carl::is_zero(rhs));
1105  if (carl::is_one(rhs)) return *this;
1106  for (auto& term : mTerms) {
1107  term.coeff() /= rhs;
1108  }
1109  assert(this->is_consistent());
1110  return *this;
1111 }
1112 
1113 template<typename C, typename O, typename P>
1114 MultivariatePolynomial<C,O,P> operator/(const MultivariatePolynomial<C,O,P>& lhs, unsigned long rhs)
1115 {
1116  MultivariatePolynomial<C,O,P> result;
1117  for (const auto& t: lhs.mTerms) {
1118  result.mTerms.emplace_back(t/rhs);
1119  }
1120  result.mOrdered = lhs.mOrdered;
1121  assert(result.is_consistent());
1122  return result;
1123 }
1124 
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)
1130  {
1131  if (mTerms.size() < 2) return;
1132  auto it = mTerms.begin();
1133  auto lTerm = it;
1134  auto constTerm = mTerms.end();
1135  if ((*it).is_constant()) constTerm = it;
1136 
1137  for (it++; it != mTerms.end();) {
1138  if ((*it).is_constant()) {
1139  assert(constTerm == mTerms.end());
1140  constTerm = it;
1141  } else if (Ordering::less(*lTerm, *it)) {
1142  lTerm = it;
1143  } else {
1144  assert(!Term<Coeff>::monomialEqual(*lTerm, *it));
1145  }
1146  it++;
1147  }
1148  makeMinimallyOrdered(lTerm, constTerm);
1149  }
1150  else
1151  {
1152  if (mTerms.size() < 2) return;
1153  auto it = mTerms.begin();
1154  const auto itToLast = mTerms.end() - 1;
1155  auto lTerm = it;
1156 
1157  for (it++; it != itToLast; ++it) {
1158  if (Ordering::less(*lTerm, *it)) {
1159  lTerm = it;
1160  } else {
1161  assert(!Term<Coeff>::monomialEqual(*lTerm, *it));
1162  }
1163  }
1164 
1165  assert(!Term<Coeff>::monomialEqual(*lTerm, *itToLast));
1166  if (!Ordering::less(*lTerm, *itToLast)) {
1167  std::swap(*lTerm, mTerms.back());
1168  }
1169  }
1170 }
1171 
1172 
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());
1179  }
1180  std::swap(*lterm, mTerms.back());
1181 }
1182 
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]));
1189  if (i > 0) {
1190  assert(this->mTerms[i].tdeg() > 0);
1191  }
1192  auto it = monomials.insert(mTerms[i].monomial());
1193  assert(it.second);
1194  }
1195  if (mOrdered) {
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]);
1199  }
1200  assert(Ordering::less(mTerms[i-1], mTerms[i]));
1201  }
1202  }
1203  else
1204  {
1205  if(nr_terms()> 1)
1206  {
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());
1210  }
1211  assert(Ordering::less(mTerms[i], lterm()));
1212  }
1213  }
1214  }
1215  return true;
1216 }
1217 
1218 }