carl  24.04
Computer ARithmetic Library
CoCoAAdaptorLP.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <carl-common/config.h>
4 
5 #if defined(USE_COCOA) && defined(USE_LIBPOLY)
6 
9 
10 #include "LPPolynomial.h"
11 #include "helper.h"
12 
13 #include <algorithm>
14 #include <cstdlib>
15 #include <iterator>
16 #include <map>
17 
18 //#include "CoCoA/library.H"
19 #include <CoCoA/BigInt.H>
20 #include <CoCoA/BigRat.H>
21 #include <CoCoA/RingQQ.H>
22 #include <CoCoA/SparsePolyIter.H>
23 #include <CoCoA/SparsePolyOps-RingElem.H>
24 #include <CoCoA/SparsePolyRing.H>
25 #include <CoCoA/factorization.H>
26 #include <CoCoA/ring.H>
27 
28 namespace carl {
29 /**
30  * This namespace contains wrapper for all heavy CoCoALib methods.
31  * They are implemented in a separate source file, attempting to reduce the
32  * amount of code included from CoCoALib.
33  */
34 namespace cocoawrapper {
35 /// Calls CoCoA::gcd(p,q).
36 CoCoA::RingElem gcd(const CoCoA::RingElem& p, const CoCoA::RingElem& q);
37 /// Calls CoCoA::factor(p).
38 CoCoA::factorization<CoCoA::RingElem> factor(const CoCoA::RingElem& p);
39 /// Calls CoCoA::ReducedGBasis(CoCoA::ideal(p)).
40 std::vector<CoCoA::RingElem> ReducedGBasis(const std::vector<CoCoA::RingElem>& p);
41 /// Calls CoCoA::SqFreeFactor(p).
42 CoCoA::factorization<CoCoA::RingElem> SqFreeFactor(const CoCoA::RingElem& p);
43 } // namespace cocoawrapper
44 
45 class CoCoAAdaptorLP {
46 private:
47  std::map<Variable, CoCoA::RingElem> mSymbolThere;
48  std::vector<Variable> mSymbolBack;
49  CoCoA::ring mQ = CoCoA::RingQQ();
50  CoCoA::SparsePolyRing mRing;
51 
52  const LPContext& mContext ;
53 
54 public:
55  static CoCoA::BigInt convert(const mpz_class& n) {
56  return CoCoA::BigIntFromMPZ(n.get_mpz_t());
57  }
58  static CoCoA::BigInt convert(const mpz_t n) {
59  return CoCoA::BigIntFromMPZ(n);
60  }
61  mpz_class convert(const CoCoA::BigInt& n) const {
62  return mpz_class(CoCoA::mpzref(n));
63  }
64  static CoCoA::BigRat convert(const mpq_class& n) {
65  return CoCoA::BigRatFromMPQ(n.get_mpq_t());
66  }
67  mpq_class convert(const CoCoA::BigRat& n) const {
68  return mpq_class(CoCoA::mpqref(n));
69  }
70 
71  void convert(mpz_class& res, const CoCoA::RingElem& n) const {
72  CoCoA::BigInt i;
73  CoCoA::IsInteger(i, n);
74  res = convert(i);
75  }
76  void convert(mpq_class& res, const CoCoA::RingElem& n) const {
77  CoCoA::BigRat r;
78  CoCoA::IsRational(r, n);
79  res = convert(r);
80  }
81 
82  CoCoA::RingElem convert(const LPPolynomial& p) const {
83  assert(p.context() == mContext);
84 
85  CoCoA::RingElem res(mRing);
86 
87  struct DataLP {
88  CoCoA::RingElem* resPoly;
89  std::map<Variable, CoCoA::RingElem> mSymbolThere;
90  std::vector<Variable> mSymbolBack;
91  CoCoA::ring mQ;
92  CoCoA::SparsePolyRing mRing;
93  const LPContext& context;
94  };
95 
96  auto collectTerms = [](const lp_polynomial_context_t* /*ctx*/, lp_monomial_t* m, void* d) {
97  DataLP* data = static_cast<DataLP*>(d);
98 
99  std::vector<long> exponents(data->mSymbolBack.size());
100 
101  for (size_t i = 0; i < m->n; i++) {
102  auto var = data->context.carl_variable(m->p[i].x);
103  assert(var.has_value());
104  auto it = data->mSymbolThere.find(*var);
105  assert(it != data->mSymbolThere.end());
106  long indetIndex;
107  if (CoCoA::IsIndet(indetIndex, it->second)) {
108  exponents[std::size_t(indetIndex)] = long(m->p[i].d);
109  } else {
110  assert(false && "The symbol is not an inderminant.");
111  }
112  }
113 
114  *data->resPoly += CoCoA::monomial(data->mRing, convert(&(m->a)), exponents);
115  };
116 
117  DataLP data{&res, mSymbolThere, mSymbolBack, mQ, mRing, mContext};
118  lp_polynomial_traverse(p.get_internal(), collectTerms, &data);
119  return res;
120  }
121 
122  LPPolynomial convert(const CoCoA::RingElem& p) const {
123  lp_polynomial_t* res = lp_polynomial_new(mContext.lp_context());
124 
125  for (CoCoA::SparsePolyIter i = CoCoA::BeginIter(p); !CoCoA::IsEnded(i); ++i) {
126  mpq_class coeff;
127  convert(coeff, CoCoA::coeff(i));
128  std::vector<long> exponents;
129  CoCoA::exponents(exponents, CoCoA::PP(i));
130 
131  assert(coeff != 0);
132  assert(carl::get_denom(coeff) == 1);
133 
134  lp_monomial_t t;
135  lp_monomial_construct(mContext.lp_context(), &t);
136  lp_monomial_set_coefficient(mContext.lp_context(), &t, carl::get_num(coeff).get_mpz_t());
137 
138  for (std::size_t i = 0; i < exponents.size(); ++i) {
139  if (exponents[i] == 0) continue;
140  lp_variable_t var = mContext.lp_variable(mSymbolBack[i]);
141  lp_monomial_push(&t, var, (unsigned int)exponents[i]);
142  }
143  lp_polynomial_add_monomial(res, &t);
144  lp_monomial_destruct(&t);
145  }
146 
147  return LPPolynomial(res, mContext);;
148  }
149 
150  std::vector<CoCoA::RingElem> convert(const std::vector<LPPolynomial>& p) const {
151  std::vector<CoCoA::RingElem> res;
152  for (const auto& poly : p)
153  res.emplace_back(convert(poly));
154  return res;
155  }
156  std::vector<LPPolynomial> convert(const std::vector<CoCoA::RingElem>& p) const {
157  std::vector<LPPolynomial> res;
158  for (const CoCoA::RingElem& poly : p)
159  res.emplace_back(convert(poly));
160  return res;
161  }
162 
163  const auto& variables() const {
164  return mSymbolBack;
165  }
166 
167 
168  auto construct_ring(const std::vector<Variable>& vars) const {
169  std::vector<CoCoA::symbol> indets;
170  for (auto s : vars) {
171  indets.emplace_back(s.safe_name());
172  }
173  return CoCoA::NewPolyRing(mQ, indets) ;
174  }
175 
176 public:
177 
178  CoCoAAdaptorLP() = delete ;
179 
180  CoCoAAdaptorLP(const LPContext& ctx) : mSymbolBack(ctx.variable_ordering()), mRing(construct_ring(mSymbolBack)), mContext(ctx) {
181  std::vector<Variable> vars = ctx.variable_ordering() ;
182 
183  auto indets = CoCoA::indets(mRing);
184  for (std::size_t i = 0; i < mSymbolBack.size(); ++i) {
185  mSymbolThere.emplace(mSymbolBack[i], indets[i]);
186  }
187  }
188 
189  // Poly gcd(const Poly& p1, const Poly& p2) const {
190  // auto start = CARL_TIME_START();
191  // auto res = convert(cocoawrapper::gcd(convert(p1), convert(p2)));
192  // CARL_TIME_FINISH(cocoa::statistics().gcd, start);
193  // return res;
194  // }
195 
196  // Poly makeCoprimeWith(const Poly& p1, const Poly& p2) const {
197  // CoCoA::RingElem res = convert(p1);
198  // return convert(res / cocoawrapper::gcd(res, convert(p2)));
199  // }
200 
201  /**
202  * Break down a polynomial into its irreducible factors together with
203  * their exponents/multiplicities.
204  * E.g. "x^3 + 4 x^2 + 5 x + 2" factorizes into "(x+1)^2 * (x+2)^1"
205  * where "(x+1)", "(x+2)" are the irreducible factors and "2" and "1" are
206  * their exponents.
207  *
208  * @param includeConstants One of those factors is a constant-polynomial
209  * (degree 0), which is included by default but can be left out by setting
210  * the flag 'includeConstantFlag' to false, e.g., for root computations.
211  *
212  * @return A map whose keys are the irreducible factors and whose values are
213  * the exponents.
214  */
215  Factors<LPPolynomial> factorize(const LPPolynomial& p, bool includeConstant = true) const {
216  auto finfo = cocoawrapper::factor(convert(p));
217  Factors<LPPolynomial> res;
218  if (includeConstant && !CoCoA::IsOne(finfo.myRemainingFactor())) {
219  res.emplace(convert(finfo.myRemainingFactor()), 1);
220  }
221  for (std::size_t i = 0; i < finfo.myFactors().size(); i++) {
222  res[convert(finfo.myFactors()[i])] = finfo.myMultiplicities()[i];
223  }
224  return res;
225  }
226 
227  /**
228  * Break down a polynomial into its unique, irreducible factors
229  * without their exponents/multiplicities.
230  * E.g. "3*x^3 + 12*x^2 + 15*x + 6" has the unique, non-constant, irreducible
231  * factors "(x+1)", "(x+2)", and a constant factor "3" that is included if includeConstant is true.
232  */
233  std::vector<LPPolynomial> irreducible_factors(const LPPolynomial& p, bool includeConstant = true) const {
234  std::vector<LPPolynomial> res;
235  for (auto& f : factorize(p, includeConstant)) {
236  res.emplace_back(std::move(f.first));
237  }
238  return res;
239  }
240 
241  // Poly squareFreePart(const Poly& p) const {
242  // auto finfo = cocoawrapper::SqFreeFactor(convert(p));
243  // Poly res(1);
244  // for (const auto& f: finfo.myFactors()) {
245  // res *= convert(f);
246  // }
247  // return res;
248  // }
249 
250  auto GBasis(const std::vector<LPPolynomial>& p) const {
251  auto res = convert(cocoawrapper::ReducedGBasis(convert(p)));
252  return res;
253  }
254 };
255 
256 } // namespace carl
257 
258 #endif
carl is the main namespace for the library.
auto irreducible_factors(const ContextPolynomial< Coeff, Ordering, Policies > &p, bool constants=true)
Definition: Functions.h:8
cln::cl_I gcd(const cln::cl_I &a, const cln::cl_I &b)
Calculate the greatest common divisor of two integers.
Definition: operations.h:310
cln::cl_I get_num(const cln::cl_RA &n)
Extract the numerator from a fraction.
Definition: operations.h:60
BasicConstraint< ToPoly > convert(const typename ToPoly::ContextType &context, const BasicConstraint< FromPoly > &c)
Definition: Conversion.h:9
cln::cl_I get_denom(const cln::cl_RA &n)
Extract the denominator from a fraction.
Definition: operations.h:69
void variables(const BasicConstraint< Pol > &c, carlVariables &vars)