carl  24.04
Computer ARithmetic Library
PolynomialParser.h
Go to the documentation of this file.
1 /**
2  * @file PolynomialParser.h
3  * @author Gereon Kremer <gereon.kremer@cs.rwth-aachen.de>
4  */
5 
6 #pragma once
7 
8 #include "Common.h"
9 
10 #include <boost/version.hpp>
12 
13 #if BOOST_VERSION >= 105900
14 #ifdef USE_CLN_NUMBERS
15 namespace boost { namespace spirit { namespace traits {
16  template<> inline bool scale(int exp, cln::cl_RA& r, cln::cl_RA acc) {
17  if (exp >= 0)
18  r = acc * carl::pow(cln::cl_RA(10), unsigned(exp));
19  else
20  r = acc / carl::pow(cln::cl_RA(10), unsigned(-exp));
21  return true;
22  }
23 #if BOOST_VERSION < 107000
24  template<> inline bool is_equal_to_one(const cln::cl_RA& value) {
25  return value == 1;
26  }
27 #endif
28 }}}
29 #endif
30 namespace boost { namespace spirit { namespace traits {
31  template<> inline bool scale(int exp, mpq_class& r, mpq_class acc) {
32  if (exp >= 0)
33  r = acc * carl::pow(mpq_class(10), unsigned(exp));
34  else
35  r = acc / carl::pow(mpq_class(10), unsigned(-exp));
36  return true;
37  }
38 #if BOOST_VERSION < 107000
39  template<> inline bool is_equal_to_one(const mpq_class& value) {
40  return value == 1;
41  }
42 #endif
43  template<> inline mpq_class negate(bool neg, const mpq_class& n) {
44  return neg ? mpq_class(-n) : n;
45  }
46 }}}
47 #else
48 #ifdef USE_CLN_NUMBERS
49 namespace boost { namespace spirit { namespace traits {
50  template<> inline void scale(int exp, cln::cl_RA& n) {
51  if (exp >= 0)
52  n *= carl::pow(cln::cl_RA(10), unsigned(exp));
53  else
54  n /= carl::pow(cln::cl_RA(10), unsigned(-exp));
55  }
56 #if BOOST_VERSION < 107000
57  template<> inline bool is_equal_to_one(const cln::cl_RA& value) {
58  return value == 1;
59  }
60 #endif
61 }}}
62 #endif
63 namespace boost { namespace spirit { namespace traits {
64  template<> inline void scale(int exp, mpq_class& n) {
65  if (exp >= 0)
66  n *= carl::pow(mpq_class(10), unsigned(exp));
67  else
68  n /= carl::pow(mpq_class(10), unsigned(-exp));
69  }
70  template<> inline bool is_equal_to_one(const mpq_class& value) {
71  return value == 1;
72  }
73  template<> inline mpq_class negate(bool neg, const mpq_class& n) {
74  return neg ? mpq_class(-n) : n;
75  }
76 }}}
77 #endif
78 
79 namespace carl::io {
80 namespace parser {
81 
82 template<typename Pol>
83 struct PolynomialParser: public qi::grammar<Iterator, Pol(), Skipper> {
85  PolynomialParser<Pol>::base_type(main, "polynomial"),
86  operation(), varmap(), varname(), number(),
87  variable(), monomial(), term(), polynomial(),
88  expr(), expr_product(), expr_sum(), main()
89  {
90  operation.add("+", ADD)("-", SUB);
91  varname = qi::lexeme[ (qi::alpha | qi::char_("~!@$%^&_=<>.?/")) > *(qi::alnum | qi::char_("~!@$%^&_=<>.?/"))];
92  variable = (varmap[qi::_val = qi::_1]) | (varname[qi::_val = px::bind(&PolynomialParser<Pol>::newVariable, px::ref(*this), qi::_1)]);
93  monomial = ((variable >> ("^" >> number | qi::attr(typename Pol::CoeffType(1)))) % "*")[qi::_val = px::bind(&PolynomialParser<Pol>::newMonomial, px::ref(*this), qi::_1)];
94  term = (-number >> -monomial)[qi::_val = px::bind(&PolynomialParser<Pol>::newTerm, px::ref(*this), qi::_1, qi::_2)];
95  polynomial = (term >> *(operation >> term))[qi::_val = px::bind(&PolynomialParser<Pol>::addTerms, px::ref(*this), qi::_1, qi::_2)];
96  expr = ("(" >> expr_sum >> ")") | polynomial;
97  expr_product = (expr % "*")[qi::_val = px::bind(&PolynomialParser<Pol>::mul, px::ref(*this), qi::_1)];
98  expr_sum = (expr_product >> *(operation >> expr_product))[qi::_val = px::bind(&PolynomialParser<Pol>::addPolynomials, px::ref(*this), qi::_1, qi::_2)];
99  main = expr_sum;
100  }
101 
103  varmap.add(VariablePool::getInstance().get_name(v), v);
104  }
105 
106 private:
107  enum Operation { ADD, SUB };
108 
109  Variable newVariable(const std::string& s) {
111  varmap.add(s, v);
112  return v;
113  }
114  Monomial::Arg newMonomial(const std::vector<boost::fusion::vector2<Variable,typename Pol::CoeffType>>& data) const {
115  Monomial::Arg res;
116  for (const auto& term: data) {
117  res = res * createMonomial(boost::fusion::at_c<0>(term), exponent(carl::to_int<uint>(boost::fusion::at_c<1>(term))));
118  }
119  return res;
120  }
121  Term<typename Pol::CoeffType> newTerm(const boost::optional<typename Pol::CoeffType>& c, const boost::optional<Monomial::Arg>& m) {
122  if (c && m) return Term<typename Pol::CoeffType>(c.get(), m.get());
123  else if (c) return Term<typename Pol::CoeffType>(c.get());
124  else if (m) return Term<typename Pol::CoeffType>(m.get());
125  CARL_LOG_ERROR("carl.parser", "Parsed an empty term.");
127  }
128  Pol addTerms(const Term<typename Pol::CoeffType>& first, const std::vector<boost::fusion::vector2<Operation,Term<typename Pol::CoeffType>>>& ops) {
129  Pol res(first);
130  for (const auto& op: ops) {
131  switch (boost::fusion::at_c<0>(op)) {
132  case ADD: res += boost::fusion::at_c<1>(op); break;
133  case SUB: res -= boost::fusion::at_c<1>(op); break;
134  }
135  }
136  return res;
137  }
138  Pol mul(const std::vector<Pol>& ops) {
139  Pol res(typename Pol::CoeffType(1));
140  for (const auto& op: ops) res *= op;
141  return res;
142  }
143  Pol addPolynomials(const Pol& first, const std::vector<boost::fusion::vector2<Operation,Pol>>& ops) {
144  Pol res = first;
145  for (const auto& op: ops) {
146  switch (boost::fusion::at_c<0>(op)) {
147  case ADD: res += boost::fusion::at_c<1>(op); break;
148  case SUB: res -= boost::fusion::at_c<1>(op); break;
149  }
150  }
151  return res;
152  }
153 
154  qi::symbols<char, Operation> operation;
155  qi::symbols<char, Variable> varmap;
156  qi::rule<Iterator, std::string(), Skipper> varname;
157  qi::real_parser<typename Pol::CoeffType,RationalPolicies<typename Pol::CoeffType>> number;
160  qi::rule<Iterator, Term<typename Pol::CoeffType>(), Skipper> term;
161  qi::rule<Iterator, Pol(), Skipper, qi::locals<Pol>> polynomial;
162  qi::rule<Iterator, Pol(), Skipper> expr;
164  qi::rule<Iterator, Pol(), Skipper, qi::locals<Pol>> expr_sum;
165  qi::rule<Iterator, Pol(), Skipper> main;
166 };
167 
168 
169 }
170 }
#define CARL_LOG_ERROR(channel, msg)
Definition: carl-logging.h:40
MultivariatePolynomial< Rational > Pol
Definition: HornerTest.cpp:17
Monomial::Arg createMonomial(T &&... t)
Definition: MonomialPool.h:168
std::size_t exponent
Type of an exponent.
Definition: Monomial.h:29
Interval< Number > exp(const Interval< Number > &i)
Definition: Exponential.h:10
uint to_int< uint >(const cln::cl_I &n)
Definition: operations.h:137
Variable fresh_real_variable() noexcept
Definition: VariablePool.h:198
Interval< Number > pow(const Interval< Number > &i, Integer exp)
Definition: Power.h:11
boost::spirit::qi::space_type Skipper
Definition: Common.h:34
std::string::const_iterator Iterator
Definition: Common.h:33
A Variable represents an algebraic variable that can be used throughout carl.
Definition: Variable.h:85
std::shared_ptr< const Monomial > Arg
Definition: Monomial.h:62
Represents a single term, that is a numeric coefficient and a monomial.
Definition: Term.h:23
static VariablePool & getInstance()
Returns the single instance of this class by reference.
Definition: Singleton.h:45
qi::rule< Iterator, std::string(), Skipper > varname
Term< typename Pol::CoeffType > newTerm(const boost::optional< typename Pol::CoeffType > &c, const boost::optional< Monomial::Arg > &m)
qi::rule< Iterator, Pol(), Skipper > expr_product
qi::rule< Iterator, Monomial::Arg(), Skipper > monomial
Pol mul(const std::vector< Pol > &ops)
qi::symbols< char, Operation > operation
Monomial::Arg newMonomial(const std::vector< boost::fusion::vector2< Variable, typename Pol::CoeffType >> &data) const
qi::rule< Iterator, Pol(), Skipper, qi::locals< Pol > > expr_sum
Variable newVariable(const std::string &s)
Pol addTerms(const Term< typename Pol::CoeffType > &first, const std::vector< boost::fusion::vector2< Operation, Term< typename Pol::CoeffType >>> &ops)
qi::rule< Iterator, Pol(), Skipper > expr
qi::rule< Iterator, Pol(), Skipper > main
qi::symbols< char, Variable > varmap
qi::rule< Iterator, Term< typename Pol::CoeffType >), Skipper > term
qi::rule< Iterator, Variable(), Skipper > variable
Pol addPolynomials(const Pol &first, const std::vector< boost::fusion::vector2< Operation, Pol >> &ops)
qi::real_parser< typename Pol::CoeffType, RationalPolicies< typename Pol::CoeffType > > number
qi::rule< Iterator, Pol(), Skipper, qi::locals< Pol > > polynomial