carl  24.04
Computer ARithmetic Library
MultivariateRoot.h
Go to the documentation of this file.
1 #pragma once
2 
7 #include <carl-arith/ran/ran.h>
8 
9 
10 #include <optional>
11 #include <algorithm>
12 #include <iostream>
13 #include <tuple>
14 
15 namespace carl {
16 
17 /**
18  * @file
19  * Represent a dynamic root, also known as a "root expression".
20  * It's a generalization of an algebraic real(= univariate poly having roots + root index).
21  * It uses a multivariate poly with distinguished, root-variable "_z"
22  * and an root index. If we want to "evaluate" this root, we need to
23  * plug in a subpoint with algebraic-real values for all variables that are not "_z".
24  * The result is basically an algebraic real.
25  * And since this algebraic real depends on the subpoint,
26  * you can also think of this as a multidimensional scalar function:
27  * A root(p(x1,x2,_z), 1) value represents a function f(x1,x2) of algReal^2 to
28  * an algebraic real. For example, f(a,b)= root(q(_z),1), where the resulting
29  * algebraic real is the 1. root of poly q(_z) := p(a,b,_z) after pluggin a and b into poly p.
30  */
31 template<typename Poly>
33 public:
35  using RAN = typename Poly::RootType;
36 private:
37  /// Polynomial defining this root.
38  Poly m_poly;
39  /// Specifies which root to consider.
40  std::size_t m_k;
41  /// The main variable.
43 public:
44  /**
45  * @param poly Must mention the root-variable "_z" and
46  * should have a at least 'rootIdx'-many roots in "_z" at each subpoint
47  * where it is intended to be evaluated.
48  * @param k The index of the root of the polynomial in "_z".
49  * The first root has index 1, the second has index 2 and so on.
50  */
51  MultivariateRoot(const Poly& poly, std::size_t k, Variable var): m_poly(poly), m_k(k), m_var(var) {
52  assert(m_k > 0);
53  }
54 
56 
57  /**
58  * Return k, the index of the root.
59  */
60  std::size_t k() const noexcept {
61  return m_k;
62  }
63 
64  /**
65  * @return the raw underlying polynomial that still mentions the root-variable "_z".
66  */
67  const Poly& poly() const noexcept {
68  return m_poly;
69  }
70 
71  /**
72  * @return the raw underlying polynomial that still mentions the root-variable "_z".
73  */
74  Poly& poly() noexcept {
75  return m_poly;
76  }
77 
78  /**
79  * @return The globally-unique distinguished root-variable "_z"
80  * to allow you to build a polynomial with this variable yourself.
81  */
82  Variable var() const noexcept {
83  return m_var;
84  }
85 
86  bool is_univariate() const {
87  return m_poly.is_univariate();
88  }
89 
90  template<typename P>
91  friend std::optional<typename MultivariateRoot<P>::RAN> evaluate(const MultivariateRoot<P>& mr, const carl::Assignment<typename MultivariateRoot<P>::RAN>& m);
92 };
93 
94 template<typename Poly>
95 inline bool operator==(const MultivariateRoot<Poly>& lhs, const MultivariateRoot<Poly>& rhs) {
96  return std::forward_as_tuple(lhs.var(), lhs.k(), lhs.poly()) == std::forward_as_tuple(lhs.var(), rhs.k(), rhs.poly());
97 }
98 template<typename Poly>
99 inline bool operator<(const MultivariateRoot<Poly>& lhs, const MultivariateRoot<Poly>& rhs) {
100  return std::forward_as_tuple(lhs.var(), lhs.k(), lhs.poly()) < std::forward_as_tuple(lhs.var(), rhs.k(), rhs.poly());
101 }
102 
103 template<typename P>
104 std::ostream& operator<<(std::ostream& os, const MultivariateRoot<P>& mr) {
105  return os << "rootExpr(" << mr.poly() << ", " << mr.k() << ", " << mr.var() << ")";
106 }
107 
108 /**
109  * Add the variables mentioned in underlying polynomial, excluding
110  * the root-variable "_z". For example, with an underlying poly p(x,y,_z)
111  * we return {x,y}.
112  */
113 template<typename Poly>
115  bool hadVar = vars.has(mr.var());
116  carl::variables(mr.poly(), vars);
117  if (!hadVar) vars.erase(mr.var());
118 }
119 
120 /**
121  * Create a copy of the underlying polynomial with the given variable
122  * replaced by the given polynomial.
123  */
124 template<typename Poly>
125 void substitute_inplace(MultivariateRoot<Poly>& mr, Variable var, const Poly& poly) {
126  carl::substitute_inplace(mr.poly(), var, poly);
127 }
128 
129 template<typename Poly>
131  auto k = [&](){
132  if (ran.is_numeric()) {
133  return (std::size_t)1;
134  } else {
135  auto roots = carl::real_roots(ran.polynomial());
136  auto it = std::find(roots.roots().begin(), roots.roots().end(), ran);
137  assert(it != roots.roots().end());
138  return (std::size_t)std::distance(roots.roots().begin(), it)+1;
139  }
140  }();
141  return MultivariateRoot<Poly>(Poly(switch_main_variable(ran.polynomial(), var)), k, var);
142 }
143 
144 /**
145  * Return the emerging algebraic real after pluggin in a subpoint to replace
146  * all variables with algebraic reals that are not the root-variable "_z".
147  * @param m must contain algebraic real assignments for all variables that are not "_z".
148  * @return std::nullopt if the underlying polynomial has no root with index 'rootIdx' at
149  * the given subpoint.
150  */
151 template<typename Poly>
152 std::optional<typename MultivariateRoot<Poly>::RAN> evaluate(const MultivariateRoot<Poly>& mr, const carl::Assignment<typename MultivariateRoot<Poly>::RAN>& m) {
153  CARL_LOG_DEBUG("carl.rootexpression", "Evaluate: " << mr << " against: " << m);
154 
155  auto result = [&](){
156  if constexpr(needs_context_type<Poly>::value) {
157  return carl::real_roots(mr.poly(), m);
158  } else {
160  }
161  }();
162  if (!result.is_univariate()) {
163  CARL_LOG_TRACE("carl.rootexpression", mr.poly() << " is not univariate (nullified: " << result.is_nullified() << "; non-univariate: " << result.is_non_univariate() << ").");
164  return std::nullopt;
165  }
166  CARL_LOG_DEBUG("carl.rootexpression", "Roots: " << result.roots());
167  if (result.roots().size() < mr.k()) {
168  CARL_LOG_TRACE("carl.rootexpression", mr.k() << "th root does not exist.");
169  return std::nullopt;
170  }
171  CARL_LOG_TRACE("carl.rootexpression", "Take " << mr.k() << "th of isolated roots " << result.roots());
172  assert(result.roots().size() >= mr.k());
173  assert(mr.k() > 0);
174  CARL_LOG_DEBUG("carl.rootexpression", "Result is " << result.roots()[mr.k()-1]);
175  return result.roots()[mr.k()-1];
176 }
177 
178 }
179 
180 namespace std {
181  template<typename Pol>
182  struct hash<carl::MultivariateRoot<Pol>> {
183  std::size_t operator()(const carl::MultivariateRoot<Pol>& mv) const {
184  return carl::hash_all(mv.poly(), mv.k());
185  }
186  };
187 }
Represent a real algebraic number (RAN) in one of several ways:
A small wrapper that configures logging for carl.
#define CARL_LOG_TRACE(channel, msg)
Definition: carl-logging.h:44
#define CARL_LOG_DEBUG(channel, msg)
Definition: carl-logging.h:43
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...
MultivariateRoot< Poly > convert_to_mvroot(const typename MultivariateRoot< Poly >::RAN &ran, Variable var)
bool operator<(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
std::ostream & operator<<(std::ostream &os, const BasicConstraint< Poly > &c)
Prints the given constraint on the given stream.
RealRootsResult< IntRepRealAlgebraicNumber< Number > > real_roots(const UnivariatePolynomial< Coeff > &polynomial, const Interval< Number > &interval=Interval< Number >::unbounded_interval())
Find all real roots of a univariate 'polynomial' with numeric coefficients within a given 'interval'.
Definition: RealRoots.h:25
bool evaluate(const BasicConstraint< Poly > &c, const Assignment< Number > &m)
Definition: Evaluation.h:10
bool operator==(const BasicConstraint< P > &lhs, const BasicConstraint< P > &rhs)
std::map< Variable, T > Assignment
Definition: Common.h:13
std::size_t hash_all(Args &&... args)
Hashes an arbitrary number of values.
Definition: hash.h:71
void variables(const BasicConstraint< Pol > &c, carlVariables &vars)
UnivariatePolynomial< MultivariatePolynomial< typename UnderlyingNumberType< Coeff >::type > > switch_main_variable(const UnivariatePolynomial< Coeff > &p, Variable newVar)
Switches the main variable using a purely syntactical restructuring.
void substitute_inplace(MultivariateRoot< Poly > &mr, Variable var, const Poly &poly)
Create a copy of the underlying polynomial with the given variable replaced by the given polynomial.
A Variable represents an algebraic variable that can be used throughout carl.
Definition: Variable.h:85
void erase(Variable v)
Definition: Variables.h:164
bool has(Variable var) const
Definition: Variables.h:137
Poly & poly() noexcept
Variable m_var
The main variable.
std::size_t k() const noexcept
Return k, the index of the root.
typename Poly::RootType RAN
std::size_t m_k
Specifies which root to consider.
MultivariateRoot(const Poly &poly, std::size_t k, Variable var)
Poly m_poly
Polynomial defining this root.
const Poly & poly() const noexcept
friend std::optional< typename MultivariateRoot< P >::RAN > evaluate(const MultivariateRoot< P > &mr, const carl::Assignment< typename MultivariateRoot< P >::RAN > &m)
Variable var() const noexcept
typename UnderlyingNumberType< Poly >::type Number
std::size_t operator()(const carl::MultivariateRoot< Pol > &mv) const
T type
A type associated with the type.
Definition: typetraits.h:77