carl  25.02
Computer ARithmetic Library
UnivariatePolynomial.tpp
Go to the documentation of this file.
1 /**
2  * @file: UnivariatePolynomial.tpp
3  * @author: Sebastian Junges
4  *
5  * @since August 26, 2013
6  */
7 
8 #pragma once
9 
10 #include <carl-common/debug/debug.h>
11 #include <carl-common/meta/platform.h>
12 #include <carl-common/meta/SFINAE.h>
13 #include <carl-logging/carl-logging.h>
14 #include "MultivariatePolynomial.h"
15 #include <carl-arith/core/Sign.h>
16 
17 #include "functions/Derivative.h"
18 #include "functions/Division.h"
19 
20 #include <algorithm>
21 #include <iomanip>
22 
23 namespace carl
24 {
25 
26 template<typename Coeff>
27 UnivariatePolynomial<Coeff>::UnivariatePolynomial(const UnivariatePolynomial& p):
28  mMainVar(p.mMainVar), mCoefficients(p.mCoefficients)
29 {
30  assert(this->is_consistent());
31 }
32 
33 template<typename Coeff>
34 UnivariatePolynomial<Coeff>::UnivariatePolynomial(UnivariatePolynomial&& p) noexcept:
35  mMainVar(p.mMainVar), mCoefficients()
36 {
37  mCoefficients = std::move(p.mCoefficients);
38  assert(is_consistent());
39 }
40 
41 template<typename Coeff>
42 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator=(const UnivariatePolynomial& p) {
43  mMainVar = p.mMainVar;
44  mCoefficients = p.mCoefficients;
45  assert(is_consistent());
46  return *this;
47 }
48 
49 template<typename Coeff>
50 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator=(UnivariatePolynomial&& p) noexcept {
51  mMainVar = p.mMainVar;
52  mCoefficients = std::move(p.mCoefficients);
53  assert(is_consistent());
54  return *this;
55 }
56 
57 template<typename Coeff>
58 UnivariatePolynomial<Coeff>::UnivariatePolynomial(Variable mainVar)
59 : mMainVar(mainVar), mCoefficients()
60 {
61  assert(this->is_consistent());
62 }
63 template<typename Coeff>
64 UnivariatePolynomial<Coeff>::UnivariatePolynomial(Variable mainVar, const Coeff& coeff, std::size_t degree) :
65 mMainVar(mainVar),
66 mCoefficients(degree+1, Coeff(0)) // We would like to use 0 here, but Coeff(0) is not always constructable (some methods need more parameter)
67 {
68  if(coeff != Coeff(0))
69  {
70  mCoefficients[degree] = coeff;
71  }
72  else
73  {
74  mCoefficients.clear();
75  }
76  strip_leading_zeroes();
77  assert(is_consistent());
78 }
79 
80 template<typename Coeff>
81 UnivariatePolynomial<Coeff>::UnivariatePolynomial(Variable mainVar, std::initializer_list<Coeff> coefficients)
82 : mMainVar(mainVar), mCoefficients(coefficients)
83 {
84  this->strip_leading_zeroes();
85  assert(this->is_consistent());
86 }
87 
88 template<typename Coeff>
89 template<typename C, DisableIf<std::is_same<C, typename UnderlyingNumberType<C>::type>>>
90 UnivariatePolynomial<Coeff>::UnivariatePolynomial(Variable mainVar, std::initializer_list<typename UnderlyingNumberType<C>::type> coefficients)
91 : mMainVar(mainVar), mCoefficients()
92 {
93  for (auto c: coefficients) {
94  this->mCoefficients.push_back(Coeff(c));
95  }
96  this->strip_leading_zeroes();
97  assert(this->is_consistent());
98 }
99 
100 template<typename Coeff>
101 UnivariatePolynomial<Coeff>::UnivariatePolynomial(Variable mainVar, const std::vector<Coeff>& coefficients)
102 : mMainVar(mainVar), mCoefficients(coefficients)
103 {
104  this->strip_leading_zeroes();
105  assert(this->is_consistent());
106 }
107 
108 template<typename Coeff>
109 UnivariatePolynomial<Coeff>::UnivariatePolynomial(Variable mainVar, std::vector<Coeff>&& coefficients)
110 : mMainVar(mainVar), mCoefficients(coefficients)
111 {
112  this->strip_leading_zeroes();
113  assert(this->is_consistent());
114 }
115 
116 template<typename Coeff>
117 UnivariatePolynomial<Coeff>::UnivariatePolynomial(Variable mainVar, const std::map<uint, Coeff>& coefficients)
118 : mMainVar(mainVar)
119 {
120  mCoefficients.reserve(coefficients.rbegin()->first);
121  for (const auto& expAndCoeff : coefficients)
122  {
123  if(expAndCoeff.first != mCoefficients.size())
124  {
125  mCoefficients.resize(expAndCoeff.first, Coeff(0));
126  }
127  mCoefficients.push_back(expAndCoeff.second);
128  }
129  this->strip_leading_zeroes();
130  assert(this->is_consistent());
131 }
132 
133 template<typename Coeff>
134 Coeff UnivariatePolynomial<Coeff>::evaluate(const Coeff& value) const
135 {
136  Coeff result(0);
137  Coeff var(1);
138  for(const Coeff& coeff : mCoefficients)
139  {
140  result += (coeff * var);
141  var *= value;
142  }
143  return result;
144 }
145 
146 template<typename Coeff>
147 bool UnivariatePolynomial<Coeff>::is_normal() const
148 {
149  return unit_part() == Coeff(1);
150 }
151 
152 template<typename Coefficient>
153 UnivariatePolynomial<Coefficient>& UnivariatePolynomial<Coefficient>::mod(const Coefficient& modulus)
154 {
155  for(Coefficient& coeff : mCoefficients)
156  {
157  coeff = carl::mod(coeff, modulus);
158  }
159  return *this;
160 }
161 
162 template<typename Coefficient>
163 UnivariatePolynomial<Coefficient> UnivariatePolynomial<Coefficient>::mod(const Coefficient& modulus) const
164 {
165  UnivariatePolynomial<Coefficient> result;
166  result.mCoefficients.reserve(mCoefficients.size());
167  for(const Coefficient& coeff : mCoefficients)
168  {
169  result.mCoefficients.push_back(mod(coeff, modulus));
170  }
171  result.strip_leading_zeroes();
172  return result;
173 }
174 
175 template<typename Coeff>
176 UnivariatePolynomial<Coeff> UnivariatePolynomial<Coeff>::pow(std::size_t exp) const
177 {
178  if (exp == 0) return UnivariatePolynomial(mMainVar, constant_one<Coeff>::get());
179  if (carl::is_zero(*this)) return UnivariatePolynomial(mMainVar);
180  UnivariatePolynomial<Coeff> res(mMainVar, constant_one<Coeff>::get());
181  UnivariatePolynomial<Coeff> mult(*this);
182  while(exp > 0) {
183  if ((exp & 1) != 0) res *= mult;
184  exp /= 2;
185  if(exp > 0) mult = mult * mult;
186  }
187  return res;
188 }
189 
190 template<typename Coeff>
191 template<typename C, DisableIf<is_number_type<C>>>
192 UnivariatePolynomial<typename UnivariatePolynomial<Coeff>::NumberType> UnivariatePolynomial<Coeff>::toNumberCoefficients() const {
193  std::vector<NumberType> coeffs;
194  coeffs.reserve(this->mCoefficients.size());
195  for (auto c: this->mCoefficients) {
196  assert(c.is_constant());
197  coeffs.push_back(c.constant_part());
198  }
199  return UnivariatePolynomial<NumberType>(this->mMainVar, coeffs);
200 }
201 
202 template<typename Coeff>
203 template<typename NewCoeff>
204 UnivariatePolynomial<NewCoeff> UnivariatePolynomial<Coeff>::convert() const {
205  std::vector<NewCoeff> coeffs;
206  coeffs.resize(this->mCoefficients.size());
207  for (std::size_t i = 0; i < this->mCoefficients.size(); i++) {
208  coeffs[i] = NewCoeff(this->mCoefficients[i]);
209  }
210  return UnivariatePolynomial<NewCoeff>(this->mMainVar, coeffs);
211 }
212 
213 template<typename Coeff>
214 template<typename NewCoeff>
215 UnivariatePolynomial<NewCoeff> UnivariatePolynomial<Coeff>::convert(const std::function<NewCoeff(const Coeff&)>& f) const {
216  std::vector<NewCoeff> coeffs;
217  coeffs.resize(this->mCoefficients.size());
218  for (std::size_t i = 0; i < this->mCoefficients.size(); i++) {
219  coeffs[i] = f(this->mCoefficients[i]);
220  }
221  return UnivariatePolynomial<NewCoeff>(this->mMainVar, coeffs);
222 }
223 
224 template<typename Coeff>
225 UnivariatePolynomial<Coeff> UnivariatePolynomial<Coeff>::normalized() const
226 {
227  if(carl::is_zero(*this))
228  {
229  return *this;
230  }
231  return *this/unit_part();
232 }
233 
234 template<typename Coeff>
235 Coeff UnivariatePolynomial<Coeff>::unit_part() const {
236  if constexpr (is_field_type<Coeff>::value) {
237  // Coeffs from a field
238  return lcoeff();
239  } else if constexpr (is_number_type<Coeff>::value) {
240  // Coeffs from a number ring
241  if (carl::is_zero(*this) || lcoeff() > Coeff(0)) {
242  return Coeff(1);
243  } else {
244  return Coeff(-1);
245  }
246  } else {
247  // Coeffs from a polynomial ring
248  if (carl::is_zero(*this) || carl::is_zero(lcoeff()) || lcoeff().lcoeff() > NumberType(0)) {
249  return Coeff(1);
250  } else {
251  return Coeff(-1);
252  }
253  }
254 }
255 
256 template<typename Coeff>
257 template<typename C, EnableIf<is_subset_of_rationals_type<C>>>
258 Coeff UnivariatePolynomial<Coeff>::coprime_factor() const
259 {
260  assert(!carl::is_zero(*this));
261  auto it = mCoefficients.begin();
262  IntNumberType num = get_num(*it);
263  IntNumberType den = get_denom(*it);
264  for (++it; it != mCoefficients.end(); ++it) {
265  num = carl::gcd(num, get_num(*it));
266  den = carl::lcm(den, get_denom(*it));
267  }
268  return Coeff(den)/Coeff(num);
269 }
270 
271 template<typename Coeff>
272 template<typename C, DisableIf<is_subset_of_rationals_type<C>>>
273 typename UnderlyingNumberType<Coeff>::type UnivariatePolynomial<Coeff>::coprime_factor() const
274 {
275  assert(!carl::is_zero(*this));
276  auto it = mCoefficients.begin();
277  typename UnderlyingNumberType<Coeff>::type factor = it->coprime_factor();
278  for (++it; it != mCoefficients.end(); ++it) {
279  factor = carl::lcm(factor, it->coprime_factor());
280  }
281  return factor;
282 }
283 
284 template<typename Coeff>
285 template<typename C, EnableIf<is_subset_of_rationals_type<C>>>
286 UnivariatePolynomial<typename IntegralType<Coeff>::type> UnivariatePolynomial<Coeff>::coprime_coefficients() const
287 {
288  CARL_LOG_TRACE("carl.core", *this << " .coprime_coefficients()");
289  // Notice that even if factor is 1, we create a new polynomial
290  UnivariatePolynomial<typename IntegralType<Coeff>::type> result(mMainVar);
291  if (carl::is_zero(*this)) {
292  return result;
293  }
294  result.mCoefficients.reserve(mCoefficients.size());
295  Coeff factor = this->coprime_factor();
296  for (const Coeff& coeff: mCoefficients) {
297  assert(get_denom(coeff * factor) == 1);
298  result.mCoefficients.push_back(get_num(coeff * factor));
299  }
300  return result;
301 }
302 
303 template<typename Coeff>
304 template<typename C, DisableIf<is_subset_of_rationals_type<C>>>
305 UnivariatePolynomial<Coeff> UnivariatePolynomial<Coeff>::coprime_coefficients() const {
306  if (carl::is_zero(*this)) return *this;
307  UnivariatePolynomial<Coeff> result(mMainVar);
308  result.mCoefficients.reserve(mCoefficients.size());
309  auto factor = this->coprime_factor();
310  for (const Coeff& c: mCoefficients) {
311  result.mCoefficients.push_back(factor * c);
312  }
313  return result;
314 }
315 
316 template<typename Coeff>
317 template<typename C, EnableIf<is_subset_of_rationals_type<C>>>
318 UnivariatePolynomial<typename IntegralType<Coeff>::type> UnivariatePolynomial<Coeff>::coprime_coefficients_sign_preserving() const
319 {
320  CARL_LOG_TRACE("carl.core", *this << " .coprime_coefficients_sign_preserving()");
321  // Notice that even if factor is 1, we create a new polynomial
322  UnivariatePolynomial<typename IntegralType<Coeff>::type> result(mMainVar);
323  if (carl::is_zero(*this)) {
324  return result;
325  }
326  result.mCoefficients.reserve(mCoefficients.size());
327  Coeff factor = carl::abs(this->coprime_factor());
328  for (const Coeff& coeff: mCoefficients) {
329  assert(get_denom(coeff * factor) == 1);
330  result.mCoefficients.push_back(get_num(coeff * factor));
331  }
332  return result;
333 }
334 
335 template<typename Coeff>
336 template<typename C, DisableIf<is_subset_of_rationals_type<C>>>
337 UnivariatePolynomial<Coeff> UnivariatePolynomial<Coeff>::coprime_coefficients_sign_preserving() const {
338  if (this->is_zero()) return *this;
339  UnivariatePolynomial<Coeff> result(mMainVar);
340  result.mCoefficients.reserve(mCoefficients.size());
341  auto factor = carl::abs(this->coprime_factor());
342  for (const Coeff& c: mCoefficients) {
343  result.mCoefficients.push_back(factor * c);
344  }
345  return result;
346 }
347 
348 template<typename Coeff>
349 bool UnivariatePolynomial<Coeff>::divides(const UnivariatePolynomial& divisor) const
350 {
351  ///@todo Is this correct?
352  //return carl::is_zero(divisor.divideBy(*this).remainder);
353  assert(false); // not implemented
354  return false;
355 }
356 
357 template<typename Coeff>
358 template<typename C, EnableIf<is_instantiation_of<GFNumber, C>>>
359 UnivariatePolynomial<typename IntegralType<Coeff>::type> UnivariatePolynomial<Coeff>::to_integer_domain() const
360 {
361  UnivariatePolynomial<typename IntegralType<Coeff>::type> res(mMainVar);
362  res.mCoefficients.reserve(mCoefficients.size());
363  for(const Coeff& c : mCoefficients)
364  {
365  assert(carl::is_integer(c));
366  res.mCoefficients.push_back(c.representing_integer());
367  }
368  res.strip_leading_zeroes();
369  return res;
370 }
371 
372 template<typename Coeff>
373 template<typename C, DisableIf<is_instantiation_of<GFNumber, C>>>
374 UnivariatePolynomial<typename IntegralType<Coeff>::type> UnivariatePolynomial<Coeff>::to_integer_domain() const
375 {
376  UnivariatePolynomial<typename IntegralType<Coeff>::type> res(mMainVar);
377  res.mCoefficients.reserve(mCoefficients.size());
378  for(const Coeff& c : mCoefficients)
379  {
380  assert(carl::is_integer(c));
381  res.mCoefficients.push_back(get_num(c));
382  }
383  res.strip_leading_zeroes();
384  return res;
385 }
386 
387 template<typename Coeff>
388 //template<typename T = Coeff, EnableIf<!std::is_same<IntegralType<Coeff>, bool>::value>>
389 UnivariatePolynomial<GFNumber<typename IntegralType<Coeff>::type>> UnivariatePolynomial<Coeff>::toFiniteDomain(const GaloisField<typename IntegralType<Coeff>::type>* galoisField) const
390 {
391  UnivariatePolynomial<GFNumber<typename IntegralType<Coeff>::type>> res(mMainVar);
392  res.mCoefficients.reserve(mCoefficients.size());
393  for(const Coeff& c : mCoefficients)
394  {
395  assert(carl::is_integer(c));
396  res.mCoefficients.push_back(GFNumber<typename IntegralType<Coeff>::type>(c,galoisField));
397  }
398  res.strip_leading_zeroes();
399  return res;
400 
401 }
402 
403 template<typename Coeff>
404 template<typename N, EnableIf<is_subset_of_rationals_type<N>>>
405 typename UnivariatePolynomial<Coeff>::NumberType UnivariatePolynomial<Coeff>::numeric_content() const
406 {
407  if (carl::is_zero(*this)) return NumberType(0);
408  // Obtain main denominator for all coefficients.
409  IntNumberType mainDenom = this->main_denom();
410 
411  // now, some coefficient * mainDenom is always integral.
412  // we convert such a product to an integral data type by get_num()
413  UnivariatePolynomial<Coeff>::NumberType c = this->numeric_content(0) * mainDenom;
414  assert(get_denom(c) == 1);
415  IntNumberType res = get_num(c);
416  for (std::size_t i = 1; i < this->mCoefficients.size(); i++) {
417  c = this->numeric_content(i) * mainDenom;
418  assert(get_denom(c) == 1);
419  res = carl::gcd(get_num(c), res);
420  }
421  return NumberType(res) / mainDenom;
422 }
423 
424 template<typename Coeff>
425 template<typename C, EnableIf<is_number_type<C>>>
426 typename UnivariatePolynomial<Coeff>::IntNumberType UnivariatePolynomial<Coeff>::main_denom() const
427 {
428  IntNumberType denom = 1;
429  for (const auto& c: mCoefficients) {
430  denom = carl::lcm(denom, get_denom(c));
431  }
432  CARL_LOG_TRACE("carl.core", "mainDenom of " << *this << " is " << denom);
433  return denom;
434 }
435 template<typename Coeff>
436 template<typename C, DisableIf<is_number_type<C>>>
437 typename UnivariatePolynomial<Coeff>::IntNumberType UnivariatePolynomial<Coeff>::main_denom() const
438 {
439  IntNumberType denom = 1;
440  for (const auto& c: mCoefficients) {
441  denom = carl::lcm(denom, c.main_denom());
442  }
443  return denom;
444 }
445 
446 template<typename Coeff>
447 Coeff UnivariatePolynomial<Coeff>::synthetic_division(const Coeff& zeroOfDivisor)
448 {
449  if(coefficients().empty()) return Coeff(0);
450  if(coefficients().size() == 1) return coefficients().back();
451  std::vector<Coeff> secondRow;
452  secondRow.reserve(coefficients().size());
453  secondRow.push_back(Coeff(0));
454  std::vector<Coeff> thirdRow(coefficients().size(), Coeff(0));
455  size_t posThirdRow = coefficients().size()-1;
456  auto coeff = coefficients().rbegin();
457  thirdRow[posThirdRow] = (*coeff) + secondRow.front();
458  ++coeff;
459  while(coeff != coefficients().rend())
460  {
461  secondRow.push_back(zeroOfDivisor*thirdRow[posThirdRow]);
462  --posThirdRow;
463  thirdRow[posThirdRow] = (*coeff) + secondRow.back();
464  ++coeff;
465  }
466  assert(posThirdRow == 0);
467  CARL_LOG_TRACE("carl.core.upoly", "UnivSynDiv: (" << *this << ")[x -> " << zeroOfDivisor << "] = " << thirdRow.front());
468  if(thirdRow.front() == 0)
469  {
470  thirdRow.erase(thirdRow.begin());
471  this->mCoefficients.swap(thirdRow);
472  CARL_LOG_TRACE("carl.core.upoly", "UnivSynDiv: reduced by ((" << carl::abs(get_denom(thirdRow.front())) << ")*" << main_var() << " + (" << (thirdRow.front()<0 ? "-" : "") << carl::abs(get_num(thirdRow.front())) << ")) -> " << *this);
473  return Coeff(0);
474  }
475  return thirdRow.front();
476 }
477 
478 template<typename Coeff>
479 UnivariatePolynomial<Coeff> UnivariatePolynomial<Coeff>::operator -() const
480 {
481  UnivariatePolynomial result(mMainVar);
482  result.mCoefficients.reserve(mCoefficients.size());
483  for(const auto& c : mCoefficients) {
484  result.mCoefficients.push_back(-c);
485  }
486 
487  return result;
488 }
489 
490 template<typename Coefficient>
491 UnivariatePolynomial<Coefficient>& UnivariatePolynomial<Coefficient>::operator+=(const Coefficient& rhs)
492 {
493  if(rhs == Coefficient(0)) return *this;
494  if(mCoefficients.empty())
495  {
496  // Adding non-zero rhs to zero.
497  mCoefficients.resize(1, rhs);
498  }
499  else
500  {
501  mCoefficients.front() += rhs;
502  if(mCoefficients.size() == 1 && mCoefficients.front() == Coefficient(0))
503  {
504  // Result is zero.
505  mCoefficients.clear();
506  }
507  }
508  return *this;
509 }
510 
511 template<typename Coeff>
512 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator+=(const UnivariatePolynomial& rhs)
513 {
514  assert(mMainVar == rhs.mMainVar);
515 
516  if(carl::is_zero(rhs))
517  {
518  return *this;
519  }
520 
521  if(mCoefficients.size() < rhs.mCoefficients.size())
522  {
523  for(std::size_t i = 0; i < mCoefficients.size(); ++i)
524  {
525  mCoefficients[i] += rhs.mCoefficients[i];
526  }
527  mCoefficients.insert(mCoefficients.end(), rhs.mCoefficients.end() - sint(rhs.mCoefficients.size() - mCoefficients.size()), rhs.mCoefficients.end());
528  }
529  else
530  {
531  for(std::size_t i = 0; i < rhs.mCoefficients.size(); ++i)
532  {
533  mCoefficients[i] += rhs.mCoefficients[i];
534  }
535  }
536  strip_leading_zeroes();
537  return *this;
538 }
539 
540 template<typename C>
541 UnivariatePolynomial<C> operator+(const UnivariatePolynomial<C>& lhs, const UnivariatePolynomial<C>& rhs)
542 {
543  UnivariatePolynomial<C> res(lhs);
544  res += rhs;
545  return res;
546 }
547 
548 template<typename C>
549 UnivariatePolynomial<C> operator+(const UnivariatePolynomial<C>& lhs, const C& rhs)
550 {
551  UnivariatePolynomial<C> res(lhs);
552  res += rhs;
553  return res;
554 }
555 
556 template<typename C>
557 UnivariatePolynomial<C> operator+(const C& lhs, const UnivariatePolynomial<C>& rhs)
558 {
559  return rhs + lhs;
560 }
561 
562 
563 template<typename Coefficient>
564 UnivariatePolynomial<Coefficient>& UnivariatePolynomial<Coefficient>::operator-=(const Coefficient& rhs)
565 {
566 // CARL_LOG_INEFFICIENT();
567  return *this += -rhs;
568 }
569 
570 template<typename Coeff>
571 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator-=(const UnivariatePolynomial& rhs)
572 {
573 // CARL_LOG_INEFFICIENT();
574  return *this += -rhs;
575 }
576 
577 
578 template<typename C>
579 UnivariatePolynomial<C> operator-(const UnivariatePolynomial<C>& lhs, const UnivariatePolynomial<C>& rhs)
580 {
581  UnivariatePolynomial<C> res(lhs);
582  res -= rhs;
583  return res;
584 }
585 
586 template<typename C>
587 UnivariatePolynomial<C> operator-(const UnivariatePolynomial<C>& lhs, const C& rhs)
588 {
589  UnivariatePolynomial<C> res(lhs);
590  res -= rhs;
591  return res;
592 }
593 
594 template<typename C>
595 UnivariatePolynomial<C> operator-(const C& lhs, const UnivariatePolynomial<C>& rhs)
596 {
597  return rhs - lhs;
598 }
599 
600 template<typename Coefficient>
601 template<typename C, EnableIf<is_number_type<C>>>
602 UnivariatePolynomial<Coefficient>& UnivariatePolynomial<Coefficient>::operator*=(Variable rhs) {
603  if (rhs == this->mMainVar) {
604  this->mCoefficients.insert(this->mCoefficients.begin(), Coefficient(0));
605  return *this;
606  }
607  assert(!carl::is_number_type<Coefficient>::value);
608  return *this;
609 }
610 template<typename Coefficient>
611 template<typename C, DisableIf<is_number_type<C>>>
612 UnivariatePolynomial<Coefficient>& UnivariatePolynomial<Coefficient>::operator*=(Variable rhs) {
613  if (rhs == this->mMainVar) {
614  this->mCoefficients.insert(this->mCoefficients.begin(), Coefficient(0));
615  return *this;
616  }
617  assert(!carl::is_number_type<Coefficient>::value);
618  for (auto& c: this->mCoefficients) c *= rhs;
619  return *this;
620 }
621 
622 template<typename Coefficient>
623 UnivariatePolynomial<Coefficient>& UnivariatePolynomial<Coefficient>::operator*=(const Coefficient& rhs)
624 {
625  if(rhs == Coefficient(0))
626  {
627  mCoefficients.clear();
628  return *this;
629  }
630  for(Coefficient& c : mCoefficients)
631  {
632  c *= rhs;
633  }
634 
635  if(is_finite_type<Coefficient>::value)
636  {
637  strip_leading_zeroes();
638  }
639 
640  return *this;
641 }
642 
643 
644 template<typename Coeff>
645 template<typename I, DisableIf<std::is_same<Coeff, I>>...>
646 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator*=(const typename IntegralType<Coeff>::type& rhs)
647 {
648  static_assert(std::is_same<Coeff, I>::value, "Do not provide template parameters");
649  if(rhs == I(0))
650  {
651  mCoefficients.clear();
652  return *this;
653  }
654  for(Coeff& c : mCoefficients)
655  {
656  c *= rhs;
657  }
658  return *this;
659 }
660 
661 template<typename Coeff>
662 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator*=(const UnivariatePolynomial& rhs)
663 {
664  assert(mMainVar == rhs.mMainVar);
665  if(carl::is_zero(rhs))
666  {
667  mCoefficients.clear();
668  return *this;
669  }
670 
671  std::vector<Coeff> newCoeffs;
672  newCoeffs.reserve(mCoefficients.size() + rhs.mCoefficients.size());
673  for(std::size_t e = 0; e < mCoefficients.size() + rhs.degree(); ++e)
674  {
675  newCoeffs.push_back(Coeff(0));
676  for(std::size_t i = 0; i < mCoefficients.size() && i <= e; ++i)
677  {
678  if(e - i < rhs.mCoefficients.size())
679  {
680  newCoeffs.back() += mCoefficients[i] * rhs.mCoefficients[e-i];
681  }
682  }
683  }
684  mCoefficients.swap(newCoeffs);
685  strip_leading_zeroes();
686  return *this;
687 }
688 
689 
690 template<typename C>
691 UnivariatePolynomial<C> operator*(const UnivariatePolynomial<C>& lhs, const UnivariatePolynomial<C>& rhs)
692 {
693  UnivariatePolynomial<C> res(lhs);
694  res *= rhs;
695  return res;
696 }
697 
698 template<typename C>
699 UnivariatePolynomial<C> operator*(const UnivariatePolynomial<C>& lhs, Variable rhs) {
700  return std::move(UnivariatePolynomial<C>(lhs) *= rhs);
701 }
702 template<typename C>
703 UnivariatePolynomial<C> operator*(Variable lhs, const UnivariatePolynomial<C>& rhs) {
704  return std::move(UnivariatePolynomial<C>(rhs) *= lhs);
705 }
706 
707 template<typename C>
708 UnivariatePolynomial<C> operator*(const UnivariatePolynomial<C>& lhs, const C& rhs)
709 {
710  UnivariatePolynomial<C> res(lhs);
711  res *= rhs;
712  return res;
713 }
714 
715 template<typename C>
716 UnivariatePolynomial<C> operator*(const C& lhs, const UnivariatePolynomial<C>& rhs)
717 {
718  return rhs * lhs;
719 }
720 
721 template<typename C>
722 UnivariatePolynomial<C> operator*(const UnivariatePolynomial<C>& lhs, const IntegralTypeIfDifferent<C>& rhs)
723 {
724  UnivariatePolynomial<C> res(lhs);
725  res *= rhs;
726  return res;
727 }
728 
729 template<typename C>
730 UnivariatePolynomial<C> operator*(const IntegralTypeIfDifferent<C>& lhs, const UnivariatePolynomial<C>& rhs)
731 {
732  return rhs * lhs;
733 }
734 
735 
736 
737 template<typename Coeff>
738 template<typename C, EnableIf<is_field_type<C>>>
739 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator/=(const Coeff& rhs)
740 {
741  assert(rhs != Coeff(0));
742  for(Coeff& c : mCoefficients)
743  {
744  c /= rhs;
745  }
746  return *this;
747 }
748 
749 template<typename Coeff>
750 template<typename C, DisableIf<is_field_type<C>>>
751 UnivariatePolynomial<Coeff>& UnivariatePolynomial<Coeff>::operator/=(const Coeff& rhs)
752 {
753  assert(rhs != Coeff(0));
754  for(Coeff& c : mCoefficients)
755  {
756  c = quotient(c, rhs);
757  }
758  /// TODO not fully sure whether this is necessary
759  this->strip_leading_zeroes();
760  return *this;
761 }
762 
763 
764 
765 template<typename C>
766 UnivariatePolynomial<C> operator/(const UnivariatePolynomial<C>& lhs, const C& rhs)
767 {
768  assert(rhs != C(0));
769  if(carl::is_zero(lhs)) return lhs;
770  UnivariatePolynomial<C> res(lhs);
771  return res /= rhs;
772 }
773 
774 template<typename C>
775 bool operator==(const UnivariatePolynomial<C>& lhs, const UnivariatePolynomial<C>& rhs)
776 {
777  assert(lhs.is_consistent());
778  assert(rhs.is_consistent());
779  if(lhs.mMainVar == rhs.mMainVar)
780  {
781  return lhs.mCoefficients == rhs.mCoefficients;
782  }
783  else
784  {
785  // in different variables, polynomials can still be equal if constant.
786  if(carl::is_zero(lhs) && carl::is_zero(rhs)) return true;
787  if ((lhs.mCoefficients.size() == 1) && (rhs.mCoefficients.size() == 1) && (lhs.mCoefficients == rhs.mCoefficients)) return true;
788  // Convert to multivariate and compare that.
789  return MultivariatePolynomial<typename carl::UnderlyingNumberType<C>::type>(lhs) == MultivariatePolynomial<typename carl::UnderlyingNumberType<C>::type>(rhs);
790  }
791 }
792 template<typename C>
793 bool operator==(const UnivariatePolynomialPtr<C>& lhs, const UnivariatePolynomialPtr<C>& rhs)
794 {
795  if (lhs == nullptr && rhs == nullptr) return true;
796  if (lhs == nullptr || rhs == nullptr) return false;
797  return *lhs == *rhs;
798 }
799 
800 template<typename C>
801 bool operator==(const UnivariatePolynomial<C>& lhs, const C& rhs)
802 {
803  if (lhs.coefficients().size() == 0) {
804  return carl::is_zero(rhs);
805  }
806  return (lhs.coefficients().size() == 1) && lhs.lcoeff() == rhs;
807 }
808 
809 template<typename C>
810 bool operator==(const C& lhs, const UnivariatePolynomial<C>& rhs)
811 {
812  return rhs == lhs;
813 }
814 
815 
816 template<typename C>
817 bool operator!=(const UnivariatePolynomial<C>& lhs, const UnivariatePolynomial<C>& rhs)
818 {
819  return !(lhs == rhs);
820 }
821 template<typename C>
822 bool operator!=(const UnivariatePolynomialPtr<C>& lhs, const UnivariatePolynomialPtr<C>& rhs)
823 {
824  if (lhs == nullptr && rhs == nullptr) return false;
825  if (lhs == nullptr || rhs == nullptr) return true;
826  return *lhs != *rhs;
827 }
828 
829 template<typename C>
830 bool UnivariatePolynomial<C>::less(const UnivariatePolynomial<C>& rhs, const PolynomialComparisonOrder& order) const {
831  switch (order) {
832  case PolynomialComparisonOrder::CauchyBound: /*{
833  C a = this->cauchyBound();
834  C b = rhs.cauchyBound();
835  if (a < b) return true;
836  return *this < rhs;
837  }*/
838  case PolynomialComparisonOrder::LowDegree:
839  if (carl::is_zero(rhs)) return false;
840  if (carl::is_zero(*this) || this->degree() < rhs.degree()) return true;
841  return *this < rhs;
842  case PolynomialComparisonOrder::Memory:
843  return this < &rhs;
844  }
845  return false;
846 }
847 
848 template<typename C>
849 bool operator<(const UnivariatePolynomial<C>& lhs, const UnivariatePolynomial<C>& rhs)
850 {
851  if(lhs.mMainVar == rhs.mMainVar)
852  {
853  if(lhs.coefficients().size() == rhs.coefficients().size())
854  {
855  auto iterLhs = lhs.coefficients().rbegin();
856  auto iterRhs = rhs.coefficients().rbegin();
857  while(iterLhs != lhs.coefficients().rend())
858  {
859  assert(iterRhs != rhs.coefficients().rend());
860  if(*iterLhs == *iterRhs)
861  {
862  ++iterLhs;
863  ++iterRhs;
864  }
865  else
866  {
867  return *iterLhs < *iterRhs;
868  }
869  }
870  }
871  return lhs.coefficients().size() < rhs.coefficients().size();
872  }
873  return lhs.mMainVar < rhs.mMainVar;
874 }
875 
876 template<typename C>
877 std::ostream& operator<<(std::ostream& os, const UnivariatePolynomial<C>& rhs)
878 {
879  if(carl::is_zero(rhs)) return os << "0";
880  for(size_t i = 0; i < rhs.mCoefficients.size()-1; ++i )
881  {
882  const C& c = rhs.mCoefficients[rhs.mCoefficients.size()-i-1];
883  if(!(c == 0))
884  {
885  if (!(c == 1)) os << "(" << c << ")*";
886  os << rhs.mMainVar << "^" << rhs.mCoefficients.size()-i-1 << " + ";
887  }
888  }
889  os << rhs.mCoefficients[0];
890  return os;
891 }
892 
893 template<typename Coefficient>
894 template<typename C, EnableIf<is_number_type<C>>>
895 bool UnivariatePolynomial<Coefficient>::is_consistent() const {
896  if (!mCoefficients.empty()) {
897  assert(!carl::is_zero(lcoeff()));
898  }
899  return true;
900 }
901 
902 template<typename Coefficient>
903 template<typename C, DisableIf<is_number_type<C>>>
904 bool UnivariatePolynomial<Coefficient>::is_consistent() const {
905  if (!mCoefficients.empty()) {
906  assert(!carl::is_zero(lcoeff()));
907  }
908  for (const auto& c: mCoefficients) {
909  assert(!c.has(main_var()));
910  assert(c.is_consistent());
911  }
912  return true;
913 }
914 
915 }