carl  24.04
Computer ARithmetic Library
Remainder.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "Degree.h"
4 #include "Quotient.h"
6 
7 #include "../MultivariatePolynomial.h"
8 #include "../UnivariatePolynomial.h"
9 
10 namespace carl {
11 
12 /**
13  * Does the heavy lifting for the remainder computation of polynomial division.
14  * @param divisor
15  * @param prefactor
16  * @see @cite GCL92, page 55, Pseudo-Division Property
17  * @return
18  */
19 template<typename Coeff>
21  assert(!carl::is_zero(divisor));
22  if(carl::is_zero(dividend)) {
23  return dividend;
24  }
25  if(dividend.degree() < divisor.degree()) return dividend;
26  assert(dividend.degree() >= divisor.degree());
27  // Remainder in a field is zero by definition.
28  if (is_field_type<Coeff>::value && is_constant(divisor)) {
29  return UnivariatePolynomial<Coeff>(dividend.main_var());
30  }
31 
32  Coeff factor(0); // We have to initialize it to prevent a compiler error.
33  if(prefactor != nullptr)
34  {
35  factor = carl::quotient(Coeff(*prefactor * dividend.lcoeff()), divisor.lcoeff());
36  // There should be no remainder.
37  assert(factor * divisor.lcoeff() == *prefactor * dividend.lcoeff());
38  }
39  else
40  {
41  factor = carl::quotient(dividend.lcoeff(), divisor.lcoeff());
42  // There should be no remainder.
43  assert(factor * divisor.lcoeff() == dividend.lcoeff());
44  }
45 
46  std::vector<Coeff> coeffs;
47  uint degdiff = dividend.degree() - divisor.degree();
48  if(degdiff > 0)
49  {
50  coeffs = std::vector<Coeff>(dividend.coefficients().begin(), dividend.coefficients().begin() + long(degdiff));
51  }
52  if(prefactor != nullptr)
53  {
54  for(Coeff& c : coeffs)
55  {
56  c *= *prefactor;
57  }
58  }
59 
60  // By construction, the leading coefficient will be zero.
61  if(prefactor != nullptr)
62  {
63  for(std::size_t i = 0; i < dividend.coefficients().size() - degdiff -1; ++i)
64  {
65  coeffs.push_back(dividend.coefficients()[i + degdiff] * *prefactor - factor * divisor.coefficients()[i]);
66  }
67  }
68  else
69  {
70  for(std::size_t i = 0; i < dividend.coefficients().size() - degdiff -1; ++i)
71  {
72  coeffs.push_back(dividend.coefficients()[i + degdiff] - factor * divisor.coefficients()[i]);
73  }
74  }
75  auto result = UnivariatePolynomial<Coeff>(dividend.main_var(), std::move(coeffs));
76  // strip zeros from the end as we might have pushed zeros.
77  result.strip_leading_zeroes();
78 
79  if(carl::is_zero(result) || result.degree() < divisor.degree())
80  {
81  return result;
82  }
83  else
84  {
85  return remainder_helper(result, divisor);
86  }
87 }
88 
89 template<typename Coeff>
91  return remainder_helper(dividend, divisor, &prefactor);
92 }
93 
94 template<typename Coeff>
96  static_assert(is_field_type<Coeff>::value, "Reduce must be called with a prefactor if the Coefficients are not from a field.");
97  return remainder_helper(dividend, divisor);
98 }
99 
100 /**
101  * Calculates the pseudo-remainder.
102  * @see @cite GCL92, page 55, Pseudo-Division Property
103  */
104 template<typename Coeff>
106 {
107  assert(dividend.main_var() == divisor.main_var());
108  Variable v = dividend.main_var();
109  if (divisor.degree() == 0) return UnivariatePolynomial<Coeff>(v);
110  if (divisor.degree() > dividend.degree()) return dividend;
111 
112  UnivariatePolynomial<Coeff> reduct = divisor;
113  reduct.truncate();
114  UnivariatePolynomial<Coeff> res = dividend;
115 
116  std::size_t reductions = 0;
117  while (true) {
118  if (carl::is_zero(res)) {
119  return res;
120  }
121  if (divisor.degree() > res.degree()) {
122  std::size_t degdiff = dividend.degree() - divisor.degree() + 1;
123  if (reductions < degdiff) {
124  res *= carl::pow(divisor.lcoeff(), degdiff - reductions);
125  }
126  return res;
127  }
128  std::vector<Coeff> newR(res.degree());
129  Coeff lc = res.lcoeff();
130  for (std::size_t i = 0; i < res.degree(); i++) {
131  newR[i] = res.coefficients()[i] * divisor.lcoeff();
132  assert(!newR[i].has(v));
133  }
134  if (res.degree() == divisor.degree()) {
135  if (!carl::is_zero(reduct)) {
136  for (std::size_t i = 0; i <= reduct.degree(); i++) {
137  newR[i] -= lc * reduct.coefficients()[i];
138  assert(!newR[i].has(v));
139  }
140  }
141  } else {
142  assert(!lc.has(v));
143  if (!carl::is_zero(reduct)) {
144  for (std::size_t i = 0; i <= reduct.degree(); i++) {
145  newR[res.degree() - divisor.degree() + i] -= lc * reduct.coefficients()[i];
146  assert(!newR[res.degree() - divisor.degree() + i].has(v));
147  }
148  }
149  }
150  res = UnivariatePolynomial<Coeff>(v, std::move(newR));
151  reductions++;
152  }
153 }
154 
155 /**
156  * Compute the signed pseudo-remainder.
157  */
158 template<typename Coeff>
160  if(carl::is_zero(dividend) || dividend.degree() < divisor.degree())
161  {
162  // According to definition.
163  return dividend;
164  }
165  Coeff b = divisor.lcoeff();
166  uint d = dividend.degree() - divisor.degree() + 1;
167  if (d % 2 == 1) ++d;
168  Coeff prefactor = pow(b,d);
169  return remainder(dividend, divisor, &prefactor);
170 }
171 
172 template<typename C, typename O, typename P>
174  static_assert(is_field_type<C>::value, "Division only defined for field coefficients");
175  assert(!carl::is_zero(divisor));
176  if(&dividend == &divisor || carl::is_one(divisor) || dividend == divisor)
177  {
179  }
180 
182  MultivariatePolynomial p = dividend;
183  while(!carl::is_zero(p))
184  {
185  if(p.lterm().tdeg() < divisor.lterm().tdeg())
186  {
187  assert(!p.lterm().divisible(divisor.lterm()));
188  if( O::degreeOrder )
189  {
190  remainder += p;
191  assert(remainder.is_consistent());
192  return remainder;
193  }
194  remainder += p.lterm();
195  p.strip_lterm();
196  }
197  else
198  {
199  Term<C> factor;
200  if (p.lterm().divide(divisor.lterm(), factor)) {
201  p.subtractProduct(factor, divisor);
202  //p -= factor * divisor;
203  }
204  else
205  {
206  remainder += p.lterm();
207  p.strip_lterm();
208  }
209  }
210  }
211  assert(remainder.is_consistent());
212  assert(dividend == quotient(dividend, divisor) * divisor + remainder);
213  return remainder;
214 }
215 
216 template<typename C, typename O, typename P>
218  assert(!carl::is_zero(divisor));
220 }
221 
222 }
Implements utility functions concerning the (total) degree of monomials, terms and polynomials.
States if a type is a field.
Definition: typetraits.h:132
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...
std::uint64_t uint
Definition: numbers.h:16
bool is_constant(const ContextPolynomial< Coeff, Ordering, Policies > &p)
Interval< Number > quotient(const Interval< Number > &_lhs, const Interval< Number > &_rhs)
Implements the division with remainder.
Definition: Interval.h:1488
UnivariatePolynomial< Coeff > remainder_helper(const UnivariatePolynomial< Coeff > &dividend, const UnivariatePolynomial< Coeff > &divisor, const Coeff *prefactor=nullptr)
Does the heavy lifting for the remainder computation of polynomial division.
Definition: Remainder.h:20
bool is_zero(const Interval< Number > &i)
Check if this interval is a point-interval containing 0.
Definition: Interval.h:1453
UnivariatePolynomial< Coeff > signed_pseudo_remainder(const UnivariatePolynomial< Coeff > &dividend, const UnivariatePolynomial< Coeff > &divisor)
Compute the signed pseudo-remainder.
Definition: Remainder.h:159
typename UnderlyingNumberType< P >::type Coeff
cln::cl_I remainder(const cln::cl_I &a, const cln::cl_I &b)
Calculate the remainder of the integer division.
Definition: operations.h:526
UnivariatePolynomial< Coeff > pseudo_remainder(const UnivariatePolynomial< Coeff > &dividend, const UnivariatePolynomial< Coeff > &divisor)
Calculates the pseudo-remainder.
Definition: Remainder.h:105
Interval< Number > pow(const Interval< Number > &i, Integer exp)
Definition: Power.h:11
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
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.
void truncate()
Removes the leading term from the polynomial.
uint degree() const
Get the maximal exponent of the main variable.
The general-purpose multivariate polynomial class.
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.
Represents a single term, that is a numeric coefficient and a monomial.
Definition: Term.h:23
Term divide(const Coefficient &c) const
bool divisible(const Term &t) const
uint tdeg() const
Gives the total degree, i.e.
Definition: Term.h:101