carl  24.04
Computer ARithmetic Library
AlgebraicSubstitution.h
Go to the documentation of this file.
1 #pragma once
2 
3 /**
4  * @file AlgebraicSubstitution.h
5  * This file contains carl::algebraic_substitution which performs what we call an ``algebraic substitution``.
6  * We substitute the ``algebraic part`` of a variable assignment into a multivariate polynomial to obtain a univariate polynomial in the remaining variable.
7  * The algebraic part is a minimal polynomial, in practice the defining polynomial of a real algebraic number.
8  * We implement two strategies: GROEBNER and RESULTANT.
9  *
10  * In both cases you need to make sure that the minimal polynomials are not only reducible over Q, but are actually minimal polynomials within a tower of field extensions characterized by the given polynomials.
11  * If one fails to do this, the resulting polynomial may vanish identically.
12  * In some cases one can exclude that this happens.
13  *
14  * Such minimal polynomials can be computed using FieldExtensions.
15  * If the resultant strategy is used, it is important that the defining polynomials are used from top to bottom.
16  * Thus the first defining polynomials may contain all variables, the last must be univariate.
17  */
18 
21 #ifdef USE_COCOA
23 #endif
24 
28 
30 
31 /**
32  * Implements algebraic substitution by Gröbner basis computation.
33  * Essentially we take all polynomials and compute a Gröbner basis with respect to an elimination order, having the remaining variable at the end.
34  * The result is then the polynomial in the last variable only.
35  */
36 template<typename Number>
37 std::optional<UnivariatePolynomial<Number>> algebraic_substitution_groebner(
38  const std::vector<MultivariatePolynomial<Number>>& polynomials,
39  const std::vector<Variable>& variables
40 ) {
41  #ifdef USE_COCOA
42  Variable target = variables.back();
43  try {
44  CoCoAAdaptor<MultivariatePolynomial<Number>> ca(variables, true);
45  CARL_LOG_DEBUG("carl.ran.interval", "Computing GBasis of " << polynomials << " with order " << variables);
46  auto res = ca.GBasis(polynomials);
47  CARL_LOG_DEBUG("carl.ran.interval", "-> " << res);
48  for (const auto& poly: res) {
49  if (carl::variables(poly) == carlVariables({ target })) {
50  CARL_LOG_DEBUG("carl.ran.interval", "-> " << poly)
51  return carl::to_univariate_polynomial(poly);
52  }
53  }
54  } catch (const CoCoA::ErrorInfo& e) {
55  CARL_LOG_ERROR("carl.ran.interval", "Computation of GBasis failed: " << e << " -> " << CoCoA::context(e));
56  }
57  #else
58  CARL_LOG_ERROR("carl.ran.interval", "CoCoALib is not enabled");
59  assert(false);
60  #endif
61  return std::nullopt;
62  // return UnivariatePolynomial<Number>(target);
63 }
64 
65 /**
66  * Implements algebraic substitution by Gröbner basis computation.
67  * Essentially we take all polynomials and compute a Gröbner basis with respect to an elimination order, having the remaining variable at the end.
68  * The result is then the polynomial in the last variable only.
69  */
70 template<typename Number>
71 std::optional<UnivariatePolynomial<Number>> algebraic_substitution_groebner(
73  const std::vector<UnivariatePolynomial<MultivariatePolynomial<Number>>>& polynomials
74 ) {
75  std::vector<MultivariatePolynomial<Number>> polys;
76  std::vector<Variable> varOrder;
77  for (const auto& poly: polynomials) {
78  polys.emplace_back(poly);
79  varOrder.emplace_back(poly.main_var());
80  }
81  polys.emplace_back(p);
82  varOrder.emplace_back(p.main_var());
83 
84  CARL_LOG_DEBUG("carl.ran.interval", "Converted " << p << " and " << polynomials << " to " << polys << " under " << varOrder);
85  return algebraic_substitution_groebner(polys, varOrder);
86 }
87 
88 /**
89  * Implements algebraic substitution by resultant computation.
90  * We iteratively compute the resultant of the input polynomial with each of the defining polynomials.
91  * Eventually we obtain a polynomial univariate in the remaining variable, our result.
92  *
93  * Note that we assume that the polynomials are in a triangular form where any polynomial may contain variables that are ``defined'' by the previous polynomials.
94  */
95 template<typename Number>
96 std::optional<UnivariatePolynomial<Number>> algebraic_substitution_resultant(
98  const std::vector<UnivariatePolynomial<MultivariatePolynomial<Number>>>& polynomials
99 ) {
100  Variable v = p.main_var();
102  for (auto it = polynomials.rbegin(); it != polynomials.rend(); ++it) {
103  const auto& poly = *it;
104  if (!cur.has(poly.main_var())) {
105  continue;
106  }
107  cur = pseudo_remainder(switch_main_variable(cur, poly.main_var()), poly);
108  CARL_LOG_DEBUG("carl.ran.interval", "Computing resultant of " << cur << " and " << poly);
109  cur = carl::resultant(cur, poly);
110  CARL_LOG_DEBUG("carl.ran.interval", "-> " << cur);
111  }
112  auto swpoly = switch_main_variable(cur, v);
113  if (!swpoly.is_univariate()) {
114  return std::nullopt;
115  }
117  CARL_LOG_DEBUG("carl.ran.interval", "Result: " << result);
118  return result;
119 }
120 
121 /**
122  * Implements algebraic substitution by resultant computation.
123  * We iteratively compute the resultant of the input polynomial with each of the defining polynomials.
124  * Eventually we obtain a polynomial univariate in the remaining variable, our result.
125  *
126  * Note that we assume that the polynomials are in a triangular form where any polynomial may contain variables that are ``defined'' by the previous polynomials.
127  */
128 template<typename Number>
129 std::optional<UnivariatePolynomial<Number>> algebraic_substitution_resultant(
130  const std::vector<MultivariatePolynomial<Number>>& polynomials,
131  const std::vector<Variable>& variables
132 ) {
133  auto p = carl::to_univariate_polynomial(polynomials.back(), variables.back());
134  std::vector<UnivariatePolynomial<MultivariatePolynomial<Number>>> polys;
135 
136  for (std::size_t i = 0; i < polynomials.size() - 1; ++i) {
137  polys.emplace_back(carl::to_univariate_polynomial(polynomials[i], variables[i]));
138  }
139 
140  CARL_LOG_DEBUG("carl.ran.interval", "Converted " << polynomials << " under " << variables << " to " << p << " and " << polys);
141  return algebraic_substitution_resultant(p, polys);
142 }
143 
144 /// Indicates which strategy to use: resultants or Gröbner bases.
147 };
148 
149 /**
150  * Computes the algebraic substitution of the given defining polynomials into a multivariate polynomial p.
151  * The result is a univariate polynomial in the main variable of p.
152  */
153 template<typename Number>
154 std::optional<UnivariatePolynomial<Number>> algebraic_substitution(
156  const std::vector<UnivariatePolynomial<MultivariatePolynomial<Number>>>& polynomials,
158 ) {
159  CARL_LOG_DEBUG("carl.ran.interval", "Substituting " << polynomials << " into " << p);
160  switch (strategy) {
162  return algebraic_substitution_groebner(p, polynomials);
164  default:
165  return algebraic_substitution_resultant(p, polynomials);
166  }
167 }
168 
169 /**
170  * Computes the algebraic substitution of the given defining polynomials into a multivariate polynomial p.
171  * The result is a univariate polynomial in the main variable of p.
172  */
173 template<typename Number>
174 std::optional<UnivariatePolynomial<Number>> algebraic_substitution(
175  const std::vector<MultivariatePolynomial<Number>>& polynomials,
176  const std::vector<Variable>& variables,
178 ) {
179  CARL_LOG_WARN("carl.ran.interval", "Substituting " << polynomials << " into " << polynomials.back());
180  switch (strategy) {
182  return algebraic_substitution_groebner(polynomials, variables);
184  default:
185  return algebraic_substitution_resultant(polynomials, variables);
186  }
187 }
188 
189 }
#define CARL_LOG_WARN(channel, msg)
Definition: carl-logging.h:41
#define CARL_LOG_ERROR(channel, msg)
Definition: carl-logging.h:40
#define CARL_LOG_DEBUG(channel, msg)
Definition: carl-logging.h:43
UnivariatePolynomial< C > to_univariate_polynomial(const MultivariatePolynomial< C, O, P > &p)
Convert a univariate polynomial that is currently (mis)represented by a 'MultivariatePolynomial' into...
void variables(const BasicConstraint< Pol > &c, carlVariables &vars)
UnivariatePolynomial< Coeff > pseudo_remainder(const UnivariatePolynomial< Coeff > &dividend, const UnivariatePolynomial< Coeff > &divisor)
Calculates the pseudo-remainder.
Definition: Remainder.h:105
auto resultant(const ContextPolynomial< Coeff, Ordering, Policies > &p, const ContextPolynomial< Coeff, Ordering, Policies > &q)
Definition: Functions.h:22
UnivariatePolynomial< MultivariatePolynomial< typename UnderlyingNumberType< Coeff >::type > > switch_main_variable(const UnivariatePolynomial< Coeff > &p, Variable newVar)
Switches the main variable using a purely syntactical restructuring.
std::optional< UnivariatePolynomial< Number > > algebraic_substitution_groebner(const std::vector< MultivariatePolynomial< Number >> &polynomials, const std::vector< Variable > &variables)
Implements algebraic substitution by Gröbner basis computation.
std::optional< UnivariatePolynomial< Number > > algebraic_substitution(const UnivariatePolynomial< MultivariatePolynomial< Number >> &p, const std::vector< UnivariatePolynomial< MultivariatePolynomial< Number >>> &polynomials, AlgebraicSubstitutionStrategy strategy=AlgebraicSubstitutionStrategy::RESULTANT)
Computes the algebraic substitution of the given defining polynomials into a multivariate polynomial ...
std::optional< UnivariatePolynomial< Number > > algebraic_substitution_resultant(const UnivariatePolynomial< MultivariatePolynomial< Number >> &p, const std::vector< UnivariatePolynomial< MultivariatePolynomial< Number >>> &polynomials)
Implements algebraic substitution by resultant computation.
AlgebraicSubstitutionStrategy
Indicates which strategy to use: resultants or Gröbner bases.
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.
Variable main_var() const
Retrieves the main variable of this polynomial.
bool has(Variable v) const
Checks if the given variable occurs in the polynomial.
UnivariatePolynomial< NumberType > toNumberCoefficients() const
Asserts that is_univariate() is true.