18 # pragma clang diagnostic push
19 # pragma clang diagnostic ignored "-Wunsequenced"
20 #elif defined __GNUC__
21 # pragma GCC diagnostic push
22 # pragma GCC diagnostic ignored "-Wsequence-point"
35 #define BOOST_RESULT_OF_USE_DECLTYPE
36 #define BOOST_SPIRIT_USE_PHOENIX_V3
37 #include <boost/math/constants/constants.hpp>
38 #include <boost/spirit/include/phoenix.hpp>
39 #include <boost/spirit/include/qi.hpp>
40 #include <boost/variant.hpp>
47 namespace qi = boost::spirit::qi;
48 namespace ascii = boost::spirit::ascii;
69 template <
typename T >
70 T sgn(
T x) {
return (
T{0} < x) - (x <
T{0}); }
73 template <
typename T >
77 template <
typename T >
81 template <
typename T >
82 T deg(
T x) {
return x*boost::math::constants::radian<T>(); }
85 template <
typename T >
86 T rad(
T x) {
return x*boost::math::constants::degree<T>(); }
102 template <
typename real_t >
105 using tree_t = boost::variant<
109 , boost::recursive_wrapper<expr_ast<real_t>>
110 , boost::recursive_wrapper<binary_op<real_t>>
111 , boost::recursive_wrapper<unary_op<real_t>>
134 template <
typename Expr>
148 template <
typename real_t >
152 using op_t = std::function<real_t(real_t)>;
156 : op(std::move(op)), rhs(std::move(rhs))
166 template <
typename real_t >
170 using op_t = std::function<real_t(real_t,real_t)>;
174 : op(std::move(op)), lhs(std::move(lhs)), rhs(std::move(rhs))
185 template <
typename real_t >
191 template <
typename real_t >
197 template <
typename real_t >
203 template <
typename real_t >
215 template <
typename real_t >
240 auto it =
st.find(c);
241 if (it ==
st.end()) {
242 throw std::invalid_argument(
"Unknown variable " + c);
250 return boost::apply_visitor(*
this, ast.
tree);
257 boost::apply_visitor(*
this, tree.
lhs.tree),
258 boost::apply_visitor(*
this, tree.
rhs.tree)
266 boost::apply_visitor(*
this, tree.rhs.tree)
278 return std::is_same<U, T>::value;
282 template <
typename T,
typename... Ts>
302 return boost::apply_visitor(*
this, ast.
tree);
307 auto lhs = boost::apply_visitor(*
this, tree.
lhs.tree);
308 auto rhs = boost::apply_visitor(*
this, tree.
rhs.tree);
312 if (holds_alternative<real_t>(lhs) && holds_alternative<real_t>(rhs)) {
313 return tree.
op(boost::get<real_t>(lhs), boost::get<real_t>(rhs));
320 auto rhs = boost::apply_visitor(*
this, tree.rhs.tree);
322 if (holds_alternative<real_t>(rhs)) {
323 return tree.op(boost::get<real_t>(rhs));
332 template <
typename real_t >
345 template <
typename real_t >
361 template <
typename Iterator >
364 std::stringstream msg;
368 << std::string{first, last}
371 throw std::runtime_error(msg.str());
379 template <
typename real_t,
typename Iterator >
382 Iterator, expr_ast<real_t>(), ascii::space_type
387 qi::rule<Iterator, expr_ast<real_t>(), ascii::space_type>
expression;
388 qi::rule<Iterator, expr_ast<real_t>(), ascii::space_type>
term;
389 qi::rule<Iterator, expr_ast<real_t>(), ascii::space_type>
factor;
390 qi::rule<Iterator, expr_ast<real_t>(), ascii::space_type>
primary;
395 : boost::spirit::qi::symbols<
396 typename std::iterator_traits<Iterator>::value_type,
403 (
"e" , boost::math::constants::e<real_t>() )
404 (
"epsilon", std::numeric_limits<real_t>::epsilon())
405 (
"phi" , boost::math::constants::phi<real_t>() )
406 (
"pi" , boost::math::constants::pi<real_t>() )
413 : boost::spirit::qi::symbols<
414 typename std::iterator_traits<Iterator>::value_type,
415 typename unary_op<real_t>::op_t
421 (
"abs" ,
static_cast<real_t(*)(real_t)
>(&
std::abs ))
422 (
"acos" ,
static_cast<real_t(*)(real_t)
>(&
std::acos ))
423 (
"acosh" ,
static_cast<real_t(*)(real_t)
>(&std::acosh ))
424 (
"asin" ,
static_cast<real_t(*)(real_t)
>(&
std::asin ))
425 (
"asinh" ,
static_cast<real_t(*)(real_t)
>(&std::asinh ))
426 (
"atan" ,
static_cast<real_t(*)(real_t)
>(&
std::atan ))
427 (
"atanh" ,
static_cast<real_t(*)(real_t)
>(&std::atanh ))
428 (
"cbrt" ,
static_cast<real_t(*)(real_t)
>(&std::cbrt ))
429 (
"ceil" ,
static_cast<real_t(*)(real_t)
>(&
std::ceil ))
430 (
"cos" ,
static_cast<real_t(*)(real_t)
>(&
std::cos ))
431 (
"cosh" ,
static_cast<real_t(*)(real_t)
>(&
std::cosh ))
432 (
"deg2rad",
static_cast<real_t(*)(real_t)
>(&
math::deg ))
433 (
"erf" ,
static_cast<real_t(*)(real_t)
>(&
std::erf ))
434 (
"erfc" ,
static_cast<real_t(*)(real_t)
>(&
std::erfc ))
435 (
"exp" ,
static_cast<real_t(*)(real_t)
>(&
std::exp ))
436 (
"exp2" ,
static_cast<real_t(*)(real_t)
>(&std::exp2 ))
437 (
"floor" ,
static_cast<real_t(*)(real_t)
>(&
std::floor ))
438 (
"isinf" ,
static_cast<real_t(*)(real_t)
>(&
math::isinf))
439 (
"isnan" ,
static_cast<real_t(*)(real_t)
>(&
math::isnan))
440 (
"log" ,
static_cast<real_t(*)(real_t)
>(&
std::log ))
441 (
"log2" ,
static_cast<real_t(*)(real_t)
>(&std::log2 ))
442 (
"log10" ,
static_cast<real_t(*)(real_t)
>(&
std::log10 ))
443 (
"rad2deg",
static_cast<real_t(*)(real_t)
>(&
math::rad ))
444 (
"round" ,
static_cast<real_t(*)(real_t)
>(&std::round ))
445 (
"sgn" ,
static_cast<real_t(*)(real_t)
>(&
math::sgn ))
446 (
"sin" ,
static_cast<real_t(*)(real_t)
>(&
std::sin ))
447 (
"sinh" ,
static_cast<real_t(*)(real_t)
>(&
std::sinh ))
448 (
"sqrt" ,
static_cast<real_t(*)(real_t)
>(&
std::sqrt ))
449 (
"tan" ,
static_cast<real_t(*)(real_t)
>(&
std::tan ))
450 (
"tanh" ,
static_cast<real_t(*)(real_t)
>(&
std::tanh ))
451 (
"tgamma" ,
static_cast<real_t(*)(real_t)
>(&std::tgamma))
458 : boost::spirit::qi::symbols<
459 typename std::iterator_traits<Iterator>::value_type,
460 typename binary_op<real_t>::op_t
466 (
"atan2",
static_cast<real_t(*)(real_t,real_t)
>(&
std::atan2))
467 (
"max" ,
static_cast<real_t(*)(real_t,real_t)
>(&std::fmax ))
468 (
"min" ,
static_cast<real_t(*)(real_t,real_t)
>(&std::fmin ))
469 (
"pow" ,
static_cast<real_t(*)(real_t,real_t)
>(&
std::pow ))
477 using boost::spirit::qi::real_parser;
478 using boost::spirit::qi::real_policies;
479 real_parser<real_t,real_policies<real_t>>
real;
481 using boost::spirit::lexeme;
482 using boost::spirit::qi::_1;
483 using boost::spirit::qi::_2;
484 using boost::spirit::qi::_3;
485 using boost::spirit::qi::_4;
486 using boost::spirit::qi::_val;
488 using boost::spirit::qi::alnum;
489 using boost::spirit::qi::raw;
491 boost::phoenix::function<unary_expr_<real_t>> unary_expr;
492 boost::phoenix::function<binary_expr_<real_t>> binary_expr;
494 auto fmod =
static_cast<real_t(*)(real_t,real_t)
>(&
std::fmod);
495 auto pow =
static_cast<real_t(*)(real_t,real_t)
>(&
std::pow);
499 >> *( (
'+' >
term [_val += _1])
500 | (
'-' >
term [_val -= _1])
506 >> *( (
'*' >
factor [_val *= _1])
507 | (
'/' >
factor [_val /= _1])
508 | (
'%' >
factor [_val = binary_expr(
fmod, _val, _1)])
514 >> *( (
"**" >
factor [_val = binary_expr(
pow, _val, _1)])
519 raw[lexeme[
alpha >> *(alnum |
'_')]];
524 | (
'-' > primary [_val = unary_expr(std::negate<real_t>{}, _1)])
525 | (
'+' > primary [_val = _1])
527 [_val = binary_expr(_1, _2, _3)]
529 [_val = unary_expr(_1, _2)]
538 primary.name(
"primary");
540 using boost::spirit::qi::fail;
541 using boost::spirit::qi::on_error;
542 using boost::phoenix::bind;
561 template <
typename real_t,
typename Iterator>
567 bool r = qi::phrase_parse(first, last, g, ascii::space, ast);
569 if (!r || first != last) {
570 std::string rest(first, last);
571 throw std::runtime_error(
"Parsing failed at " + rest);
587 template <
typename real_t >
600 template <
typename Iterator >
601 void parse(Iterator first, Iterator last)
603 ast = detail::parse<real_t>(first, last);
609 parse(str.begin(), str.end());
637 template <
typename real_t,
typename Iterator >
638 real_t
parse(Iterator first, Iterator last,
642 parser.
parse(first, last);
647 template <
typename real_t >
648 real_t
parse(std::string
const &str,
651 return parse<real_t>(str.begin(), str.end(), st);
656 #if defined __clang__
657 # pragma clang diagnostic pop
658 #elif defined __GNUC__
659 # pragma GCC diagnostic pop
bool operator()(U const &) const
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
PETE_TUTree< FnArcCos, typename T::PETE_Expr_t > acos(const PETE_Expr< T > &l)
expr_ast & operator+=(expr_ast const &rhs)
Add a tree.
void parse(Iterator first, Iterator last)
Parse an expression.
std::function< real_t(real_t, real_t)> op_t
Signature of a binary operator: op(x,y)
qi::rule< Iterator, expr_ast< real_t >), ascii::space_type > primary
detail::expr_ast< real_t > ast
qi::rule< Iterator, expr_ast< real_t >), ascii::space_type > factor
eval_ast(symbol_table_t sym)
Constructor.
result_type operator()(expr_ast< real_t > const &ast) const
Recursively evaluate the AST.
FTps< T, N > erf(const FTps< T, N > &x, int trunc=(FTps< T, N >::EXACT))
Error function.
Unary expression functor.
Tps< T > sin(const Tps< T > &x)
Sine.
Make boost::phoenix::function happy.
void operator()(Iterator first, Iterator last, boost::spirit::info const &info) const
Throw an exception saying where and why parsing failed.
PETE_TUTree< FnCeil, typename T::PETE_Expr_t > ceil(const PETE_Expr< T > &l)
Tps< T > exp(const Tps< T > &x)
Exponential.
Binary expression functor.
FTps< T, N > erfc(const FTps< T, N > &x, int trunc=(FTps< T, N >::EXACT))
Complementary error function.
symbol table for binary functions like "pow"
Tps< T > tan(const Tps< T > &x)
Tangent.
std::function< real_t(real_t)> op_t
Signature of a unary operator: op(x)
result_type operator()(expr_ast< real_t > const &ast) const
Recursively evaluate the AST.
expr_ast & operator/=(expr_ast const &rhs)
Divide by a tree.
boost::variant< nil, real_t, std::string, boost::recursive_wrapper< expr_ast< real_t >>, boost::recursive_wrapper< binary_op< real_t >>, boost::recursive_wrapper< unary_op< real_t >> > tree_t
real_t parse(Iterator first, Iterator last, typename detail::eval_ast< real_t >::symbol_table_t const &st)
Convenience function.
qi::rule< Iterator, std::string()> variable
expr_ast< real_t > operator()(typename unary_op< real_t >::op_t op, expr_ast< real_t > const &rhs) const
Create a new AST containing the unary function.
Tps< T > log(const Tps< T > &x)
Natural logarithm.
expr_ast< real_t > operator()(typename binary_op< real_t >::op_t op, expr_ast< real_t > const &lhs, expr_ast< real_t > const &rhs) const
Create a new AST containing the binary function.
FLieGenerator< T, N > real(const FLieGenerator< std::complex< T >, N > &)
Take real part of a complex generator.
expr_ast< real_t > lhs
Stored argument tree of first argument.
T deg(T x)
Convert radians to degrees.
Tps< T > cosh(const Tps< T > &x)
Hyperbolic cosine.
constexpr double alpha
The fine structure constant, no dimension.
expr_ast & operator-=(expr_ast const &rhs)
subtract a tree
result_type operator()(std::string const &c) const
Variables do not evaluate.
result_type operator()(real_t n) const
Numbers evaluate to themselves.
matheval::detail::grammar::bfunc_ bfunc
PETE_TUTree< FnArcTan, typename T::PETE_Expr_t > atan(const PETE_Expr< T > &l)
constexpr double c
The velocity of light in m/s.
detail::expr_ast< real_t > parse(Iterator first, Iterator last)
Parse an expression.
matheval::detail::grammar::constant_ constant
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
real_t result_type
Necessary typedef for boost::apply_visitor
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
expr_ast< real_t > rhs
Stored argument tree.
void parse(std::string const &str)
expr_ast(Expr other)
Copy constructor.
grammar()
Constructor builds the grammar.
PETE_TBTree< FnFmod, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > fmod(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
unary_op(op_t op, expr_ast< real_t > rhs)
Save the operator and the argument tree.
Evaluate the Abstract Syntax Tree.
Tps< T > sqrt(const Tps< T > &x)
Square root.
T rad(T x)
Convert degrees to radians.
real_t evaluate(typename detail::eval_ast< real_t >::symbol_table_t const &st)
Evaluate the AST with a given symbol table.
bool holds_alternative(boost::variant< Ts...> const &v)
matheval::detail::grammar::ufunc_ ufunc
Tps< T > cos(const Tps< T > &x)
Cosine.
Make boost::phoenix::function happy.
expr_ast & operator*=(expr_ast const &rhs)
Multiply by a tree.
T isnan(T x)
isnan function with adjusted return type
Error handler for expectation errors.
std::map< std::string, result_type > symbol_table_t
Type of the symbol table.
result_type operator()(result_type n) const
Numbers evaluate to themselves.
binary_op(op_t op, expr_ast< real_t > lhs, expr_ast< real_t > rhs)
Save the operator and the argument trees.
Store a unary operator and its argument tree.
expr_ast< real_t > rhs
Stored argument tree of second argument.
expectation_handler err_handler
PETE_TUTree< FnArcSin, typename T::PETE_Expr_t > asin(const PETE_Expr< T > &l)
Store a binary operator and its argument trees.
result_type operator()(unary_op< real_t > const &tree) const
Evaluate a unary operator and optionally recurse its operand.
result_type operator()(binary_op< real_t > const &tree) const
Evaluate a binary operator and optionally recurse its operands.
result_type operator()(nil) const
Empty nodes in the tree evaluate to 0.
symbol table for unary functions like "abs"
qi::rule< Iterator, expr_ast< real_t >), ascii::space_type > term
result_type operator()(unary_op< real_t > const &tree) const
Evaluate a unary operator and optionally recurse its operand.
expr_ast()
Default constructor.
Tps< T > tanh(const Tps< T > &x)
Hyperbolic tangent.
result_type operator()(std::string const &c) const
Variables evaluate to their value in the symbol table.
symbol table for constants like "pi"
result_type operator()(nil) const
Empty nodes in the tree evaluate to 0.
qi::rule< Iterator, expr_ast< real_t >), ascii::space_type > expression
result_type operator()(binary_op< real_t > const &tree) const
Evaluate a binary operator and optionally recurse its operands.
typename expr_ast< real_t >::tree_t result_type
Necessary typedef for boost::apply_visitor
Tps< T > sinh(const Tps< T > &x)
Hyperbolic sine.
PETE_TUTree< FnLog10, typename T::PETE_Expr_t > log10(const PETE_Expr< T > &l)
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
T isinf(T x)
isinf function with adjusted return type