carl  24.04
Computer ARithmetic Library
LPPolynomial.h
Go to the documentation of this file.
1 /**
2  * @file LPPolynomial.h
3  */
4 
5 #pragma once
6 
7 #include <carl-common/config.h>
8 #ifdef USE_LIBPOLY
9 
10 #include "LPContext.h"
11 #include <poly/polynomial.h>
12 #include "helper.h"
13 
16 
17 #include <functional>
18 #include <list>
19 #include <map>
20 #include <memory>
21 #include <vector>
22 
24 namespace carl {
25 
26 class LPPolynomial {
27 private:
28  /// The libpoly polynomial.
29  lp_polynomial_t* m_internal;
30 
31  LPContext m_context;
32 
33 public:
34 
35  //Defines for real roots
36  using CoeffType = mpq_class ;
37  using RootType = LPRealAlgebraicNumber;
38  using ContextType = LPContext;
39 
40  //For compatibility with MultivariatePolynomial
41  using NumberType = mpq_class;
42 
43  /**
44  * Default constructor shall not exist. Use LPPolynomial(Context) instead.
45  */
46  LPPolynomial() = delete;
47  /**
48  * Copy constructor.
49  */
50  LPPolynomial(const LPPolynomial& p);
51  /**
52  * Move constructor.
53  */
54  LPPolynomial(LPPolynomial&& p);
55  /**
56  * Copy assignment operator.
57  */
58  LPPolynomial& operator=(const LPPolynomial& p);
59  /**
60  * Move assignment operator.
61  */
62  LPPolynomial& operator=(LPPolynomial&& p);
63 
64  /**
65  * Construct a zero polynomial with the given main variable.
66  * @param context Context of libpoly polynomial
67  */
68  explicit LPPolynomial(const LPContext& context);
69 
70  /**
71  * Move constructor.
72  */
73  LPPolynomial(lp_polynomial_t* p, const LPContext& context);
74 
75  /**
76  * Construct a LPPolynomial with only a integer.
77  * @param mainPoly Libpoly Polynomial.
78  */
79  LPPolynomial(const LPContext& context, long val);
80 
81  /**
82  * Construct a LPPolynomial with only a rational.
83  * Attention: Just the numerator is taken!
84  * @param mainPoly Libpoly Polynomial.
85  */
86  LPPolynomial(const LPContext& context, const mpq_class& val);
87 
88  /**
89  * Construct a LPPolynomial with only a integer.
90  * @param mainPoly Libpoly Polynomial.
91  */
92  LPPolynomial(const LPContext& context, const mpz_class& val);
93 
94  /**
95  * Construct from context and variable
96  * @param context Context of libpoly polynomial
97  * @param var The main variable of the polynomial
98  */
99  LPPolynomial(const LPContext& context, const Variable& var);
100 
101  /**
102  * Construct \f$ coeff \cdot mainVar^{degree} \f$.
103  * @param mainVar New main variable.
104  * @param context Context of libpoly polynomial
105  * @param coeff Leading coefficient.
106  * @param degree Degree.
107  */
108  LPPolynomial(const LPContext& context, const Variable& var, const mpz_class& coeff, unsigned int degree = 0);
109 
110  /**
111  * Construct polynomial with the given coefficients.
112  * @param mainVar New main variable.
113  * @param coefficients List of coefficients.
114  * @param context Context of libpoly polynomial
115  */
116  LPPolynomial(const LPContext& context, const Variable& mainVar, const std::initializer_list<mpz_class>& coefficients);
117 
118  /**
119  * Construct polynomial with the given coefficients.
120  * @param mainVar New main variable.
121  * @param coefficients Vector of coefficients.
122  * @param context Context of libpoly polynomial
123  */
124  LPPolynomial(const LPContext& context, const Variable& mainVar, const std::vector<mpz_class>& coefficients);
125  /**
126  * Construct polynomial with the given coefficients, moving the coefficients.
127  * @param mainVar New main variable.
128  * @param coefficients Vector of coefficients.
129  * @param context Context of libpoly polynomial
130  */
131  LPPolynomial(const LPContext& context, const Variable& mainVar, std::vector<mpz_class>&& coefficients);
132  /**
133  * Construct polynomial with the given coefficients.
134  * @param mainVar New main variable.
135  * @param coefficients Assignment of degree to coefficients.
136  * @param context Context of libpoly polynomial
137  */
138  LPPolynomial(const LPContext& context, const Variable& mainVar, const std::map<unsigned int, mpz_class>& coefficients);
139 
140  /**
141  * Destructor.
142  */
143  ~LPPolynomial() = default;
144 
145  // Polynomial interface implementations.
146 
147  /**
148  * Creates a polynomial of value one with the same context
149  * @return One.
150  */
151  LPPolynomial one() const {
152  return LPPolynomial(m_context, 1);
153  }
154 
155  /**
156  * For terms with exactly one variable, get this variable.
157  * @return The only variable occurring in the term.
158  */
159  Variable single_variable() const {
160  assert(lp_polynomial_is_univariate(get_internal()));
161  auto carl_var = context().carl_variable(lp_polynomial_top_variable(get_internal()));
162  assert(carl_var.has_value());
163  return *carl_var;
164  }
165 
166  LPPolynomial coeff(std::size_t k) const {
167  lp_polynomial_t* res = lp_polynomial_alloc();
168  lp_polynomial_construct(res, m_context.lp_context());
169  lp_polynomial_get_coefficient(res, get_internal(), k);
170  return LPPolynomial(res, m_context);
171  }
172 
173  /**
174  * Get the maximal exponent of the main variable.
175  * As the degree of the zero polynomial is \f$-\infty\f$, we assert that this polynomial is not zero. This must be checked by the caller before calling this method.
176  * @see @cite GCL92, page 38
177  * @return Degree.
178  */
179  size_t degree() const {
180  return lp_polynomial_degree(get_internal());
181  }
182 
183  /**
184  * Returns the leading coefficient.
185  * @return The leading coefficient.
186  */
187  LPPolynomial lcoeff() const {
188  return coeff(degree());
189  }
190 
191  /** Obtain all non-zero coefficients of a polynomial. */
192  std::vector<LPPolynomial> coefficients() const {
193  std::vector<LPPolynomial> res;
194  for (std::size_t deg = 0; deg <= degree(); ++deg) {
195  auto cf = coeff(deg);
196  if (lp_polynomial_is_zero(cf.get_internal())) continue;
197  res.emplace_back(std::move(cf));
198  }
199  return res;
200  }
201 
202  /**
203  * Returns the constant part of this polynomial.
204  * @return Constant part.
205  */
206  mpz_class constant_part() const {
207  struct LPPolynomial_constantPart_visitor {
208  mpz_class part = 0;
209  };
210 
211  auto getConstantPart = [](const lp_polynomial_context_t* /*ctx*/,
212  lp_monomial_t* m,
213  void* d) {
214  auto& v = *static_cast<LPPolynomial_constantPart_visitor*>(d);
215  if (m->n == 0) {
216  v.part += *reinterpret_cast<mpz_class*>(&m->a);
217  }
218  };
219 
220  LPPolynomial_constantPart_visitor visitor;
221  lp_polynomial_traverse(get_internal(), getConstantPart, &visitor);
222  return visitor.part;
223  }
224 
225  /**
226  * Removes the leading term from the polynomial.
227  */
228  void truncate() {
229  lp_polynomial_t* lcoeff = lp_polynomial_alloc();
230  lp_polynomial_construct(lcoeff, m_context.lp_context());
231  lp_polynomial_get_coefficient(lcoeff, get_internal(), lp_polynomial_degree(get_internal()));
232  lp_polynomial_sub(get_internal(), get_internal(), lcoeff);
233  lp_polynomial_delete(lcoeff);
234  //*this -= lcoeff();
235  }
236 
237  /**
238  * Retrieves the main variable of this polynomial.
239  * @return Main variable.
240  */
241  Variable main_var() const {
242  if (lp_polynomial_is_constant(get_internal())) return carl::Variable::NO_VARIABLE;
243  else return *(context().carl_variable(lp_polynomial_top_variable(get_internal())));
244  }
245 
246  /**
247  * Retrieves a non-const pointer to the libpoly polynomial.
248  * [Handle with care]
249  * @return Libpoly Polynomial.
250  */
251  lp_polynomial_t* get_internal() {
252  return m_internal;
253  }
254 
255  /**
256  * Retrieves a constant pointer to the libpoly polynomial.
257  * @return Libpoly Polynomial.
258  */
259  const lp_polynomial_t* get_internal() const {
260  return m_internal;
261  }
262 
263  /**
264  * @brief Get the Context object
265  *
266  * @return const LPContext
267  */
268  const LPContext& context() const {
269  return m_context;
270  }
271 
272  /**
273  * @brief Get the Context object
274  *
275  * @return LPContext
276  */
277  LPContext& context() {
278  return m_context;
279  }
280 
281  void set_context(const LPContext& c);
282 
283  /**
284  * Checks if the given variable occurs in the polynomial.
285  * @param v Variable.
286  * @return If v occurs in the polynomial.
287  */
288  bool has(const Variable& v) const;
289 
290  /**
291  * Calculates a factor that would make the coefficients of this polynomial coprime integers.
292  *
293  * We consider a set of integers coprime, if they share no common factor.
294  * As we can only have integer coefficients, we calculate the gcd of the coefficients of the monomial
295  * @return Coprime factor of this polynomial.
296  */
297  mpz_class coprime_factor() const;
298 
299  /**
300  * Constructs a new polynomial that is scaled such that the coefficients are coprime.
301  * It is calculated by multiplying it with the coprime factor.
302  * By definition, this results in a polynomial with integral coefficients.
303  * @return This polynomial multiplied with the coprime factor.
304  */
305 
306  LPPolynomial coprime_coefficients() const;
307 
308  /**
309  * Checks whether the polynomial is unit normal.
310  * A polynomial is unit normal, if the leading coefficient is unit normal, that is if it is either one or minus one.
311  * @see @cite GCL92, page 39
312  * @return If polynomial is normal.
313  */
314  bool is_normal() const;
315  /**
316  * The normal part of a polynomial is the polynomial divided by the unit part.
317  *
318  * HACK: At the moment, this is equal to coprime_coefficients().
319  * @see @cite GCL92, page 42.
320  * @return This polynomial divided by the unit part.
321  */
322  LPPolynomial normalized() const;
323 
324  /**
325  * The unit part of a polynomial over a field is its leading coefficient for nonzero polynomials,
326  * and one for zero polynomials.
327  * The unit part of a polynomial over a ring is the sign of the polynomial for nonzero polynomials,
328  * and one for zero polynomials.
329  * @see @cite GCL92, page 42.
330  * @return The unit part of the polynomial.
331  */
332  mpz_class unit_part() const;
333 
334  /**
335  * Constructs a new polynomial `q` such that \f$ q(x) = p(-x) \f$ where `p` is this polynomial.
336  * @return New polynomial with negated variable.
337  */
338  LPPolynomial negate_variable() const {
340  return LPPolynomial(m_context);
341  }
342 
343  /**
344  * Checks if this polynomial is divisible by the given divisor, that is if the remainder is zero.
345  * @param divisor Polynomial.
346  * @return If divisor divides this polynomial.
347  */
348  bool divides(const LPPolynomial& divisor) const;
349 
350  /**
351  * Replaces every coefficient `c` by `c mod modulus`.
352  * @param modulus Modulus.
353  * @return This.
354  */
355  LPPolynomial& mod(const mpz_class& modulus);
356  /**
357  * Constructs a new polynomial where every coefficient `c` is replaced by `c mod modulus`.
358  * @param modulus Modulus.
359  * @return New polynomial.
360  */
361  LPPolynomial mod(const mpz_class& modulus) const;
362 
363  /**
364  * Compute the main denominator of all numeric coefficients of this polynomial.
365  * This method only applies if the Coefficient type is a number.
366  * @return the main denominator of all coefficients of this polynomial.
367  */
368  mpz_class main_denom() const {
370  return mpz_class(0);
371  }
372 
373  std::size_t total_degree() const ;
374 
375  std::size_t degree(Variable::Arg var) const ;
376 
377  std::vector<std::size_t> monomial_total_degrees() const;
378  std::vector<std::size_t> monomial_degrees(Variable::Arg var) const;
379 
380 
381  /**
382  * Calculates the coefficient of var^exp.
383  * @param var Variable.
384  * @param exp Exponent.
385  * @return Coefficient of var^exp.
386  */
387  LPPolynomial coeff(Variable::Arg var, std::size_t exp) const ;
388 
389  friend std::ostream& operator<<(std::ostream& os, const LPPolynomial& rhs);
390 };
391 
392 bool operator==(const LPPolynomial& lhs, const LPPolynomial& rhs);
393 bool operator==(const LPPolynomial& lhs, const mpz_class& rhs);
394 bool operator==(const mpz_class& lhs, const LPPolynomial& rhs);
395 
396 bool operator!=(const LPPolynomial& lhs, const LPPolynomial& rhs);
397 bool operator!=(const LPPolynomial& lhs, const mpz_class& rhs);
398 bool operator!=(const mpz_class& lhs, const LPPolynomial& rhs);
399 
400 bool operator<(const LPPolynomial& lhs, const LPPolynomial& rhs);
401 bool operator<(const LPPolynomial& lhs, const mpz_class& rhs);
402 bool operator<(const mpz_class& lhs, const LPPolynomial& rhs);
403 
404 bool operator<=(const LPPolynomial& lhs, const LPPolynomial& rhs);
405 bool operator<=(const LPPolynomial& lhs, const mpz_class& rhs);
406 bool operator<=(const mpz_class& lhs, const LPPolynomial& rhs);
407 
408 bool operator>(const LPPolynomial& lhs, const LPPolynomial& rhs);
409 bool operator>(const LPPolynomial& lhs, const mpz_class& rhs);
410 bool operator>(const mpz_class& lhs, const LPPolynomial& rhs);
411 
412 bool operator>=(const LPPolynomial& lhs, const LPPolynomial& rhs);
413 bool operator>=(const LPPolynomial& lhs, const mpz_class& rhs);
414 bool operator>=(const mpz_class& lhs, const LPPolynomial& rhs);
415 
416 LPPolynomial operator+(const LPPolynomial& lhs, const LPPolynomial& rhs);
417 LPPolynomial operator+(const LPPolynomial& lhs, const mpz_class& rhs);
418 LPPolynomial operator+(const mpz_class& lhs, const LPPolynomial& rhs);
419 
420 LPPolynomial operator-(const LPPolynomial& lhs, const LPPolynomial& rhs);
421 LPPolynomial operator-(const LPPolynomial& lhs, const mpz_class& rhs);
422 LPPolynomial operator-(const mpz_class& lhs, const LPPolynomial& rhs);
423 
424 LPPolynomial operator*(const LPPolynomial& lhs, const LPPolynomial& rhs);
425 LPPolynomial operator*(const LPPolynomial& lhs, const mpz_class& rhs);
426 LPPolynomial operator*(const mpz_class& lhs, const LPPolynomial& rhs);
427 
428 LPPolynomial& operator+=(LPPolynomial& lhs, const LPPolynomial& rhs);
429 LPPolynomial& operator+=(LPPolynomial& lhs, const mpz_class& rhs);
430 
431 LPPolynomial& operator-=(LPPolynomial& lhs, const LPPolynomial& rhs);
432 LPPolynomial& operator-=(LPPolynomial& lhs, const mpz_class& rhs);
433 
434 LPPolynomial& operator*=(LPPolynomial& lhs, const LPPolynomial& rhs);
435 LPPolynomial& operator*=(LPPolynomial& lhs, const mpz_class& rhs);
436 
437 /**
438  * Checks if the polynomial is equal to zero.
439  * @return If polynomial is zero.
440  */
441 inline bool is_zero(const LPPolynomial& p) {
442  return lp_polynomial_is_zero(p.get_internal());
443 }
444 
445 /**
446  * Checks if the polynomial is linear or not.
447  * @return If polynomial is linear.
448  */
449 inline bool is_constant(const LPPolynomial& p) {
450  return lp_polynomial_is_constant(p.get_internal());
451 }
452 
453 /**
454  * Checks if the polynomial is equal to one.
455  * @return If polynomial is one.
456  */
457 inline bool is_one(const LPPolynomial& p) {
458  if (!is_constant(p)) {
459  return false;
460  }
461 
462  lp_polynomial_t* one = lp_polynomial_alloc();
463  mpz_class one_int(1);
464  lp_polynomial_construct_simple(one, p.context().lp_context(), one_int.get_mpz_t(), lp_variable_null, 0);
465  bool res = lp_polynomial_eq(p.get_internal(), one);
466  lp_polynomial_delete(one);
467  return res;
468 }
469 
470 /**
471  * Checks whether the polynomial is only a number.
472  * @return If polynomial is a number.
473  */
474 inline bool is_number(const LPPolynomial& p) {
475  return is_constant(p);
476 }
477 
478 /**
479  * @brief Check if the given polynomial is linear.
480  */
481 inline bool is_linear(const LPPolynomial& p) {
482  return lp_polynomial_is_linear(p.get_internal());
483 }
484 
485 /**
486  * @brief Check if the given polynomial is univariate.
487  */
488 inline bool is_univariate(const LPPolynomial& p) {
489  return lp_polynomial_is_univariate(p.get_internal());
490 }
491 
492 inline std::size_t level_of(const LPPolynomial& p) {
493  if (is_number(p)) return 0;
494  auto it = std::find(p.context().variable_ordering().begin(), p.context().variable_ordering().end(), p.main_var());
495  assert(it != p.context().variable_ordering().end());
496  return (std::size_t)std::distance(p.context().variable_ordering().begin(), it)+1;
497 }
498 
499 /// Add the variables of the given polynomial to the variables.
500 inline void variables(const LPPolynomial& p, carlVariables& vars) {
501  struct TraverseData {
502  carlVariables& vars;
503  const LPContext& context;
504  TraverseData(carlVariables& v, const LPContext& c) : vars(v), context(c) {}
505  };
506 
507  auto collectVars = [](const lp_polynomial_context_t* /*ctx*/,
508  lp_monomial_t* m,
509  void* d) {
510  TraverseData* data = static_cast<TraverseData*>(d);
511  for (size_t i = 0; i < m->n; i++) {
512  auto var = data->context.carl_variable(m->p[i].x);
513  assert(var.has_value());
514  data->vars.add(*var);
515  }
516  };
517 
518  TraverseData d(vars, p.context());
519  lp_polynomial_traverse(p.get_internal(), collectVars, &d);
520  return;
521 }
522 
523 template<>
524 struct needs_context_type<LPPolynomial> : std::true_type {};
525 
526 template<>
527 struct is_polynomial_type<LPPolynomial> : std::true_type {};
528 
529 } // namespace carl
530 
531 namespace std {
532 /**
533  * Specialization of `std::hash` for univariate polynomials.
534  */
535 template<>
536 struct hash<carl::LPPolynomial> {
537  /**
538  * Calculates the hash of univariate polynomial.s
539  * @param p LPPolynomial.
540  * @return Hash of p.
541  */
542  std::size_t operator()(const carl::LPPolynomial& p) const {
543  return lp_polynomial_hash(p.get_internal());
544  }
545 };
546 
547 } // namespace std
548 
549 #endif
A small wrapper that configures logging for carl.
#define CARL_LOG_NOTIMPLEMENTED()
Definition: carl-logging.h:48
carl is the main namespace for the library.
bool operator>(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
Interval< Number > operator+(const Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the addition of two intervals.
Definition: operators.h:261
bool operator<(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
bool is_constant(const ContextPolynomial< Coeff, Ordering, Policies > &p)
std::ostream & operator<<(std::ostream &os, const BasicConstraint< Poly > &c)
Prints the given constraint on the given stream.
cln::cl_I mod(const cln::cl_I &a, const cln::cl_I &b)
Calculate the remainder of the integer division.
Definition: operations.h:445
Interval< Number > exp(const Interval< Number > &i)
Definition: Exponential.h:10
bool is_zero(const Interval< Number > &i)
Check if this interval is a point-interval containing 0.
Definition: Interval.h:1453
Interval< Number > operator*(const Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the multiplication of two intervals.
Definition: operators.h:386
Interval< Number > & operator*=(Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the multiplication of an interval and a number with assignment.
Definition: operators.h:425
Interval< Number > & operator+=(Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the addition of an interval and a number with assignment.
Definition: operators.h:295
Interval< Number > operator-(const Interval< Number > &rhs)
Unary minus.
Definition: operators.h:318
bool operator!=(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
bool operator<=(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
bool operator==(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
bool operator>=(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
Interval< Number > & operator-=(Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the subtraction of two intervals with assignment.
Definition: operators.h:362
bool is_number(double d)
Definition: operations.h:54
void variables(const BasicConstraint< Pol > &c, carlVariables &vars)
std::size_t level_of(const ContextPolynomial< Coeff, Ordering, Policies > &p)
bool is_linear(const ContextPolynomial< Coeff, Ordering, Policies > &p)
auto total_degree(const Monomial &m)
Gives the total degree, i.e.
Definition: Degree.h:24
bool is_one(const Interval< Number > &i)
Check if this interval is a point-interval containing 1.
Definition: Interval.h:1462
const Variable & Arg
Argument type for variables being function arguments.
Definition: Variable.h:89
static const Variable NO_VARIABLE
Instance of an invalid variable.
Definition: Variable.h:203