carl  24.04
Computer ARithmetic Library
RealRoots.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "../common/RealRoots.h"
4 #include "Ran.h"
5 #include "helper/internal.h"
8 #include <carl-arith/core/Sign.h>
10 
12 
13 #include <map>
14 
16 
17 
18 namespace carl {
19 
20 /**
21  * Find all real roots of a univariate 'polynomial' with numeric coefficients within a given 'interval'.
22  * The roots are sorted in ascending order.
23  */
24 template<typename Coeff, typename Number = typename UnderlyingNumberType<Coeff>::type, EnableIf<std::is_same<Coeff, Number>> = dummy>
26  const UnivariatePolynomial<Coeff>& polynomial,
28 ) {
29  if (carl::is_zero(polynomial)) {
30  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::nullified_response();
31  }
32  CARL_LOG_DEBUG("carl.ran.interval", polynomial << " within " << interval);
33  carl::ran::interval::RealRootIsolation rri(polynomial, interval);
34  auto r = rri.get_roots();
35  CARL_LOG_DEBUG("carl.ran.interval", "-> " << r);
36  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::roots_response(std::move(r));
37 }
38 
39 /**
40  * Find all real roots of a univariate 'polynomial' with non-numeric coefficients within a given 'interval'.
41  * However, all coefficients must be types that contain numeric numbers that are retrievable by using .constant_part();
42  * The roots are sorted in ascending order.
43  */
44 template<typename Coeff, typename Number = typename UnderlyingNumberType<Coeff>::type, DisableIf<std::is_same<Coeff, Number>> = dummy>
45 RealRootsResult<IntRepRealAlgebraicNumber<Number>> real_roots(
46  const UnivariatePolynomial<Coeff>& polynomial,
47  const Interval<Number>& interval = Interval<Number>::unbounded_interval()
48 ) {
49  assert(polynomial.is_univariate());
50  return real_roots(polynomial.convert(std::function<Number(const Coeff&)>([](const Coeff& c){ return c.constant_part(); })), interval);
51 }
52 
53 /**
54  * Replace all variables except one of the multivariate polynomial 'p' by
55  * numbers as given in the mapping 'm', which creates a univariate polynomial,
56  * and return all roots of that created polynomial.
57  * Note that 'p' is represented as a univariate polynomial with polynomial coefficients.
58  * Its main variable is not replaced and stays the main variable of the created polynomial.
59  * However, all variables in the polynomial coefficients are replaced, which is why
60  * <ul>
61  * <li>the main variable of 'p' must not be in 'm'</li>
62  * <li>all variables from the coefficients of 'p' must be in 'm'</li>
63  * </ul>
64  * The roots are sorted in ascending order.
65  * Returns a RealRootsResult indicating whether the roots could be isolated or the polynomial
66  * was not univariate or is nullified.
67  */
68 template<typename Coeff, typename Number>
70  const UnivariatePolynomial<Coeff>& poly,
73 ) {
74  CARL_LOG_FUNC("carl.ran.interval", poly << " in " << poly.main_var() << ", " << varToRANMap << ", " << interval);
75  assert(varToRANMap.count(poly.main_var()) == 0);
76 
77  if (carl::is_zero(poly)) {
78  CARL_LOG_TRACE("carl.ran.interval", "poly is 0 -> nullified");
79  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::nullified_response();
80  }
81  if (poly.is_number()) {
82  CARL_LOG_TRACE("carl.ran.interval", "poly is constant but not zero -> no root");
83  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::no_roots_response();
84  }
85 
86  // We want to simplify 'poly', but it's const, so make a copy.
87  UnivariatePolynomial<Coeff> polyCopy(poly);
89 
90  for (Variable v: carl::variables(polyCopy)) {
91  if (v == poly.main_var()) continue;
92  if (varToRANMap.count(v) == 0) {
93  CARL_LOG_TRACE("carl.ran.interval", "poly still contains unassigned variable " << v << " -> non-univariate");
94  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::non_univariate_response();
95  }
96  assert(varToRANMap.count(v) > 0);
97  if (varToRANMap.at(v).is_numeric()) {
98  substitute_inplace(polyCopy, v, Coeff(varToRANMap.at(v).value()));
99  } else {
100  ir_map.emplace(v, varToRANMap.at(v));
101  }
102  }
103  if (carl::is_zero(polyCopy)) {
104  CARL_LOG_TRACE("carl.ran.interval", "poly is 0 after substituting rational assignments -> nullified");
105  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::nullified_response();
106  }
107  if (ir_map.empty()) {
108  assert(polyCopy.is_univariate());
109  CARL_LOG_TRACE("carl.ran.interval", "poly " << polyCopy << " is univariate after substituting rational assignments");
110  return real_roots(polyCopy, interval);
111  } else {
112  CARL_LOG_TRACE("carl.ran.interval", polyCopy << " in " << polyCopy.main_var() << ", " << varToRANMap << ", " << interval);
113  assert(ir_map.find(polyCopy.main_var()) == ir_map.end());
114 
115  // substitute RANs with low degrees first
117  for (const auto& ass : ir_map) ord_ass.emplace_back(ass);
118  std::sort(ord_ass.begin(), ord_ass.end(), [](const auto& a, const auto& b){
119  return a.second.polynomial().degree() > b.second.polynomial().degree();
120  });
121 
122  std::optional<UnivariatePolynomial<Number>> evaledpoly = ran::interval::substitute_rans_into_polynomial(polyCopy, ord_ass);
123  if (!evaledpoly) {
124  CARL_LOG_TRACE("carl.ran.interval", "poly still contains unassigned variable -> non-univariate");
125  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::non_univariate_response();
126  }
127  if (carl::is_zero(*evaledpoly)) {
128  CARL_LOG_TRACE("carl.ran.interval", "got zero polynomial -> nullified");
129  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::nullified_response();
130  }
131 
132  CARL_LOG_TRACE("carl.ran.interval", "Calling on " << *evaledpoly);
134  std::vector<IntRepRealAlgebraicNumber<Number>> roots;
135  auto res = real_roots(*evaledpoly, interval);
136  for (const auto& r: res.roots()) { // TODO can be made more efficient!
137  CARL_LOG_TRACE("carl.ran.interval", "Checking " << polyCopy.main_var() << " = " << r);
138  ir_map[polyCopy.main_var()] = r;
139  CARL_LOG_TRACE("carl.ran.interval", "Evaluating " << cons << " on " << ir_map);
140  if (evaluate(cons, ir_map)) {
141  roots.emplace_back(r);
142  } else {
143  CARL_LOG_TRACE("carl.ran.interval", "Purging spurious root " << r);
144  }
145  }
146  return RealRootsResult<IntRepRealAlgebraicNumber<Number>>::roots_response(std::move(roots));
147  }
148 }
149 
150 template<typename Coeff, typename Ordering, typename Policies>
152  return real_roots(p.content(), a);
153 }
154 
155 }
A small wrapper that configures logging for carl.
#define CARL_LOG_FUNC(channel, args)
Definition: carl-logging.h:46
#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.
std::vector< std::pair< Variable, T > > OrderedAssignment
Definition: Common.h:16
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 is_zero(const Interval< Number > &i)
Check if this interval is a point-interval containing 0.
Definition: Interval.h:1453
const dtl::enabled dummy
Definition: SFINAE.h:53
bool evaluate(const BasicConstraint< Poly > &c, const Assignment< Number > &m)
Definition: Evaluation.h:10
typename UnderlyingNumberType< P >::type Coeff
std::map< Variable, T > Assignment
Definition: Common.h:13
void variables(const BasicConstraint< Pol > &c, carlVariables &vars)
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.
std::optional< UnivariatePolynomial< Number > > substitute_rans_into_polynomial(const UnivariatePolynomial< Coeff > &p, const OrderedAssignment< IntRepRealAlgebraicNumber< Number >> &m, bool use_lazard=false)
Definition: internal.h:8
Represent a polynomial (in)equality against zero.
A Variable represents an algebraic variable that can be used throughout carl.
Definition: Variable.h:85
The class which contains the interval arithmetic including trigonometric functions.
Definition: Interval.h:134
static Interval< Number > unbounded_interval()
Method which returns the unbounded interval rooted at 0.
Definition: Interval.h:804
This class represents a univariate polynomial with coefficients of an arbitrary type.
bool is_number() const
Checks whether the polynomial is only a number.
Variable main_var() const
Retrieves the main variable of this polynomial.
bool is_univariate() const
Checks if the polynomial is univariate, that means if only one variable occurs.
const UnivariatePolynomial< MultivariatePolynomial< Coeff, Ordering, Policies > > & content() const
typename UnivariatePolynomial< NumberType >::RootType RootType
Compact class to isolate real roots from a univariate polynomial using bisection.
std::vector< IntRepRealAlgebraicNumber< Number > > get_roots()
Compute and sort the roots of mPolynomial within mInterval.