carl  24.04
Computer ARithmetic Library
Division.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "Quotient.h"
5 
6 #include "../MultivariatePolynomial.h"
7 #include "../UnivariatePolynomial.h"
8 
9 namespace carl {
10 
11 /**
12  * A strongly typed pair encoding the result of a division,
13  * being a quotient and a remainder.
14  */
15 template<typename Type>
17  Type quotient;
18  Type remainder;
19 };
20 
21 template<typename Coeff>
22 Term<Coeff> divide(const Term<Coeff>& t, const Coeff& c) {
23  assert(!is_zero(c));
24  return Term<Coeff>(t.coeff() / c, t.monomial());
25 }
26 
27 template<typename Coeff>
28 bool try_divide(const Term<Coeff>& t, const Coeff& c, Term<Coeff>& res) {
29  if (is_zero(c)) return false;
30  res.coeff() = t.coeff() / c;
31  res.monomial() = t.monomial();
32  return true;
33 }
34 
35 template<typename Coeff>
36 bool try_divide(const Term<Coeff>& t, Variable v, Term<Coeff>& res) {
37  if (!t.monomial()) return false;
38  if (t.monomial()->divide(v, res.monomial())) {
39  res.coeff() = t.coeff();
40  return true;
41  }
42  return false;
43 }
44 
45 /**
46  * Divides the polynomial by the given coefficient.
47  * Applies if the coefficients are from a field.
48  * @param divisor
49  * @return
50  */
51 template<typename Coeff, typename Ordering, typename Policies>
53  static_assert(is_field_type<Coeff>::value);
54  std::vector<Term<Coeff>> new_coeffs;
55  for (const auto& t: p) {
56  new_coeffs.emplace_back(divide(t, divisor));
57  }
58  MultivariatePolynomial<Coeff,Ordering,Policies> res(std::move(new_coeffs), false, p.isOrdered());
59  assert(res.is_consistent());
60  return res;
61 }
62 
63 /**
64  * Divides the polynomial by another polynomial.
65  * If the divisor divides this polynomial, quotient contains the result of the division and true is returned.
66  * Otherwise, false is returned and the content of quotient remains unchanged.
67  * Applies if the coefficients are from a field.
68  * Note that the quotient must not be *this.
69  * @param divisor
70  * @param quotient
71  * @return
72  */
73 template<typename Coeff, typename Ordering, typename Policies>
75  static_assert(is_field_type<Coeff>::value, "Division only defined for field coefficients");
76  if (carl::is_one(divisor)) {
77  quotient = dividend;
78  return true;
79  }
80  if (carl::is_zero(dividend)) {
82  return true;
83  }
85  auto id = tam.getId(0);
86  auto thisid = tam.getId(dividend.nr_terms());
87  for (const auto& t: dividend) {
88  tam.template addTerm<false,true>(thisid, t);
89  }
90  while (true) {
91  Term<Coeff> factor = tam.getMaxTerm(thisid);
92  if (carl::is_zero(factor)) break;
93  if (factor.divide(divisor.lterm(), factor)) {
94  for (const auto& t: divisor) {
95  tam.template addTerm<true,true>(thisid, -factor*t);
96  }
97  //res.subtractProduct(factor, divisor);
98  //p -= factor * divisor;
99  tam.template addTerm<true>(id, factor);
100  } else {
101  return false;
102  }
103  }
104  tam.readTerms(id, quotient.terms());
105  tam.dropTerms(thisid);
106  quotient.reset_ordered();
107  quotient.template makeMinimallyOrdered<false, true>();
108  assert(quotient.is_consistent());
109  return true;
110 }
111 
112 /**
113  * Calculating the quotient and the remainder, such that for a given polynomial p we have
114  * p = divisor * quotient + remainder.
115  * @param divisor Another polynomial
116  * @return A divisionresult, holding the quotient and the remainder.
117  * @see
118  * @note Division is only defined on fields
119  */
120 template<typename Coeff, typename Ordering, typename Policies>
122  static_assert(is_field_type<Coeff>::value, "Division only defined for field coefficients");
126  while(!is_zero(p)) {
127  Term<Coeff> factor;
128  if (try_divide(p.lterm(), divisor.lterm(), factor)) {
129  q += factor;
130  p.subtractProduct(factor, divisor);
131  //p -= factor * divisor;
132  } else {
133  r += p.lterm();
134  p.strip_lterm();
135  }
136  }
137  assert(q.is_consistent());
138  assert(r.is_consistent());
139  assert(dividend == q * divisor + r);
141 }
142 
143 template<typename Coeff>
145  static_assert(!is_field_type<Coeff>::value);
146  static_assert(!is_number_type<Coeff>::value);
147  assert(dividend.is_consistent());
148  assert(divisor.is_consistent());
149  Coeff quo;
150  bool res = try_divide(Coeff(dividend), divisor, quo);
151  CARL_LOG_TRACE("carl.core", Coeff(dividend) << " / " << divisor << " = " << quo);
152  assert(quo.is_consistent());
153  if (res) quotient = carl::to_univariate_polynomial(quo, dividend.main_var());
154  return res;
155 }
156 
157 template<typename Coeff>
159  assert(p.is_consistent());
160  assert(divisor.is_consistent());
161  if constexpr(is_field_type<Coeff>::value) {
163  for (auto& c: res.coefficients()) {
164  c = c / divisor;
165  }
167  } else {
168  CARL_LOG_ERROR("carl.core", "Called divide() with non-field number divisor " << divisor);
169  return p;
170  }
171 }
172 
173 template<typename Coeff>
175  assert(p.is_consistent());
176  static_assert(is_field_type<typename UnderlyingNumberType<Coeff>::type>::value);
177 
179  assert(res.is_consistent());
180  for (auto& c: res.coefficients()) {
181  c = divide(c, divisor);
182  }
183  assert(res.is_consistent());
185 }
186 
187 /**
188  * Divides the polynomial by another polynomial.
189  * @param dividend Dividend.
190  * @param divisor Divisor.
191  * @return dividend / divisor.
192  */
193 template<typename Coeff>
195  if constexpr (is_integer_type<Coeff>::value) {
196  assert(!carl::is_zero(divisor));
198  if(carl::is_zero(dividend)) return result;
199  assert(dividend == divisor * result.quotient + result.remainder);
200 
201  std::vector<Coeff> coeffs(1+dividend.coefficients().size()-divisor.coefficients().size(), Coeff(0));
202 
203  uint degdiff = dividend.degree() - divisor.degree();
204  for (std::size_t offset = 0; offset <= degdiff; offset++) {
205  Coeff factor = carl::quotient(result.remainder.coefficients()[dividend.degree()-offset], divisor.lcoeff());
206  result.remainder -= UnivariatePolynomial<Coeff>(dividend.main_var(), factor, degdiff - offset) * divisor;
207  coeffs[degdiff-offset] += factor;
208  }
209  result.quotient = UnivariatePolynomial<Coeff>(dividend.main_var(), std::move(coeffs));
210  assert(dividend == divisor * result.quotient + result.remainder);
211  return result;
212  } else if constexpr (is_field_type<Coeff>::value) {
213  assert(!carl::is_zero(divisor));
214  assert(dividend.main_var() == divisor.main_var());
216  if(carl::is_zero(dividend)) return result;
217  assert(dividend == divisor * result.quotient + result.remainder);
218  if(divisor.degree() > dividend.degree())
219  {
220  return result;
221  }
222  std::vector<Coeff> coeffs(1+dividend.coefficients().size()-divisor.coefficients().size(), Coeff(0));
223 
224  do
225  {
226  Coeff factor = result.remainder.lcoeff()/divisor.lcoeff();
227  uint degdiff = result.remainder.degree() - divisor.degree();
228  result.remainder -= UnivariatePolynomial<Coeff>(dividend.main_var(), factor, degdiff) * divisor;
229  coeffs[degdiff] += factor;
230  }
231  while(!carl::is_zero(result.remainder) && divisor.degree() <= result.remainder.degree());
232  result.quotient = UnivariatePolynomial<Coeff>(dividend.main_var(), std::move(coeffs));
233  assert(dividend == divisor * result.quotient + result.remainder);
234  return result;
235  } else {
236  assert(false);
238  }
239 }
240 
241 template<typename C, typename O, typename P>
244  bool flag = try_divide(lhs, rhs, res);
245  assert(flag);
246  return res;
247 }
248 
249 }
#define CARL_LOG_ERROR(channel, msg)
Definition: carl-logging.h:40
#define CARL_LOG_TRACE(channel, msg)
Definition: carl-logging.h:44
States if a type is a field.
Definition: typetraits.h:132
States if a type is an integer type.
Definition: typetraits.h:203
carl is the main namespace for the library.
UnivariatePolynomial< C > to_univariate_polynomial(const MultivariatePolynomial< C, O, P > &p)
Convert a univariate polynomial that is currently (mis)represented by a 'MultivariatePolynomial' into...
bool try_divide(const Term< Coeff > &t, const Coeff &c, Term< Coeff > &res)
Definition: Division.h:28
std::uint64_t uint
Definition: numbers.h:16
Interval< Number > operator/(const Interval< Number > &lhs, const Number &rhs)
Operator for the division of an interval and a number.
Definition: operators.h:453
Interval< Number > quotient(const Interval< Number > &_lhs, const Interval< Number > &_rhs)
Implements the division with remainder.
Definition: Interval.h:1488
bool is_zero(const Interval< Number > &i)
Check if this interval is a point-interval containing 0.
Definition: Interval.h:1453
void divide(const cln::cl_I &dividend, const cln::cl_I &divisor, cln::cl_I &quotient, cln::cl_I &remainder)
Definition: operations.h:326
typename UnderlyingNumberType< P >::type Coeff
bool is_one(const Interval< Number > &i)
Check if this interval is a point-interval containing 1.
Definition: Interval.h:1462
A Variable represents an algebraic variable that can be used throughout carl.
Definition: Variable.h:85
T type
A type associated with the type.
Definition: typetraits.h:77
This class represents a univariate polynomial with coefficients of an arbitrary type.
const std::vector< Coefficient > & coefficients() const &
Retrieves the coefficients defining this polynomial.
Variable main_var() const
Retrieves the main variable of this polynomial.
const Coefficient & lcoeff() const
Returns the leading coefficient.
bool is_consistent() const
Asserts that this polynomial over numeric coefficients complies with the requirements and assumptions...
uint degree() const
Get the maximal exponent of the main variable.
The general-purpose multivariate polynomial class.
bool is_consistent() const
Asserts that this polynomial complies with the requirements and assumptions for MultivariatePolynomia...
MultivariatePolynomial & strip_lterm()
Drops the leading term.
const Term< Coeff > & lterm() const
The leading term.
void subtractProduct(const Term< Coeff > &factor, const MultivariatePolynomial &p)
Subtract a term times a polynomial from this polynomial.
std::size_t nr_terms() const
Calculate the number of terms.
bool isOrdered() const
Check if the terms are ordered.
States if a type is a number type.
Definition: typetraits.h:237
A strongly typed pair encoding the result of a division, being a quotient and a remainder.
Definition: Division.h:16
Term divide(const Coefficient &c) const
Coefficient & coeff()
Get the coefficient.
Definition: Term.h:80
Monomial::Arg & monomial()
Get the monomial.
Definition: Term.h:91