OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
matheval.hpp
Go to the documentation of this file.
1//
2// Namespace Matheval
3// Implements a recursive-descent parser for mathematical expressions,
4// building an AST that can be optimized and evaluated at runtime.
5//
6// Copyright (C) 2011-2013, Rhys Ulerich
7// Copyright (C) ???, Martin Bauer
8// Copyright (C) 2017, Henri Menke
9// Copyright (c) 2026, PSI, Villigen, Switzerland
10//
11// All rights reserved
12//
13// This file is part of OPAL.
14//
15// OPAL is free software: you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation, either version 3 of the License, or
18// (at your option) any later version.
19//
20// You should have received a copy of the GNU General Public License
21// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
22//
23#pragma once
24
25#include "Physics/Physics.h"
26#include "Physics/Units.h"
27
28#include <algorithm>
29#include <array>
30#include <cctype>
31#include <cmath>
32#include <functional>
33#include <iterator>
34#include <limits>
35#include <map>
36#include <memory>
37#include <stdexcept>
38#include <string>
39#include <string_view>
40#include <variant>
41
42namespace matheval {
43
44 namespace detail {
45
46 namespace math {
47
65 template < typename T >
66 constexpr T sgn(T x) { return (T{0} < x) - (x < T{0}); }
67
69 template < typename T >
70 T isnan(T x) { return std::isnan(x); }
71
73 template < typename T >
74 T isinf(T x) { return std::isinf(x); }
75
77 template < typename T >
78 inline constexpr T deg(T x) { return x * Units::rad2deg; }
79
81 template < typename T >
82 inline constexpr T rad(T x) { return x * Units::deg2rad; }
83 }
84
85 // Forward declarations
86 template < typename real_t > struct expr_ast;
87 template < typename real_t > struct unary_op;
88 template < typename real_t > struct binary_op;
89
90 struct nil {};
91
92 // Simple recursive wrapper for std::variant using unique_ptr
93 template <typename T>
95 recursive_wrapper() : ptr(std::make_unique<T>()) {}
96 recursive_wrapper(const T& t) : ptr(std::make_unique<T>(t)) {}
97 recursive_wrapper(T&& t) : ptr(std::make_unique<T>(std::move(t))) {}
98 recursive_wrapper(const recursive_wrapper& other) : ptr(std::make_unique<T>(*other.ptr)) {}
99 recursive_wrapper(recursive_wrapper&& other) noexcept = default;
100
102 if (this != &other) {
103 ptr = std::make_unique<T>(*other.ptr);
104 }
105 return *this;
106 }
107
108 recursive_wrapper& operator=(recursive_wrapper&& other) noexcept = default;
109
110 T& get() { return *ptr; }
111 const T& get() const { return *ptr; }
112
113 explicit operator T&() { return *ptr; }
114 explicit operator const T&() const { return *ptr; }
115
116 private:
117 std::unique_ptr<T> ptr;
118 };
119
120 // AST
121
127 template < typename real_t >
128 struct expr_ast
129 {
130 using tree_t = std::variant<
131 nil // can't happen!
132 , real_t
133 , std::string
137 >;
138 public:
147
153 expr_ast() : tree(nil{}) {}
154
159 template <typename Expr>
160 expr_ast(Expr other) : tree(std::move(other)) {} // NOLINT
161
163 expr_ast& operator+=(expr_ast const& rhs);
165 expr_ast& operator-=(expr_ast const& rhs);
167 expr_ast& operator*=(expr_ast const& rhs);
169 expr_ast& operator/=(expr_ast const& rhs);
170 };
171
173 template < typename real_t >
174 struct unary_op
175 {
177 using op_t = std::function<real_t(real_t)>;
178
181 : op(std::move(op)),
182 rhs(std::make_unique<expr_ast<real_t>>(std::move(rhs)))
183 {}
184
185 unary_op(const unary_op& other)
186 : op(other.op),
187 rhs(std::make_unique<expr_ast<real_t>>(*other.rhs))
188 {}
189
190 unary_op(unary_op&&) noexcept = default;
191
192 unary_op& operator=(const unary_op& other) {
193 if (this != &other) {
194 op = other.op;
195 rhs = std::make_unique<expr_ast<real_t>>(*other.rhs);
196 }
197 return *this;
198 }
199
200 unary_op& operator=(unary_op&&) noexcept = default;
201
204
206 std::unique_ptr<expr_ast<real_t>> rhs;
207 };
208
210 template < typename real_t >
212 {
214 using op_t = std::function<real_t(real_t, real_t)>;
215
218 : op(std::move(op)),
219 lhs(std::make_unique<expr_ast<real_t>>(std::move(lhs))),
220 rhs(std::make_unique<expr_ast<real_t>>(std::move(rhs)))
221 {}
222
223 binary_op(const binary_op& other)
224 : op(other.op),
225 lhs(std::make_unique<expr_ast<real_t>>(*other.lhs)),
226 rhs(std::make_unique<expr_ast<real_t>>(*other.rhs))
227 {}
228
229 binary_op(binary_op&&) noexcept = default;
230
231 binary_op& operator=(const binary_op& other) {
232 if (this != &other) {
233 op = other.op;
234 lhs = std::make_unique<expr_ast<real_t>>(*other.lhs);
235 rhs = std::make_unique<expr_ast<real_t>>(*other.rhs);
236 }
237 return *this;
238 }
239
240 binary_op& operator=(binary_op&&) noexcept = default;
241
244
246 std::unique_ptr<expr_ast<real_t>> lhs;
247
249 std::unique_ptr<expr_ast<real_t>> rhs;
250 };
251
252 template < typename real_t >
253 expr_ast<real_t>& expr_ast<real_t>::operator+=(expr_ast<real_t> const& rhs)
254 {
255 tree = binary_op<real_t>(std::plus<real_t>{}, tree, rhs);
256 return *this;
257 }
258 template < typename real_t >
260 {
261 tree = binary_op<real_t>(std::minus<real_t>{}, tree, rhs);
262 return *this;
263 }
264 template < typename real_t >
266 {
267 tree = binary_op<real_t>(std::multiplies<real_t>{}, tree, rhs);
268 return *this;
269 }
270 template < typename real_t >
272 {
273 tree = binary_op<real_t>(std::divides<real_t>{}, tree, rhs);
274 return *this;
275 }
276
282 template < typename real_t >
284 {
285 public:
287 using result_type = real_t;
288
290 using symbol_table_t = std::unordered_map<std::string, result_type>;
291
296 explicit eval_ast(symbol_table_t sym) : st(std::move(sym)) {}
297
299 result_type operator()(nil /*unused*/) const { return 0; }
300
302 result_type operator()(result_type n) const { return n; }
303
305 result_type operator()(std::string const &c) const
306 {
307 auto it = st.find(c);
308 if (it == st.end()) {
309 throw std::invalid_argument("Unknown variable " + c); // NOLINT
310 }
311 return it->second;
312 }
313
316 {
317 return std::visit(*this, ast.tree);
318 }
319
322 {
323 return tree.op(std::visit(*this, tree.lhs->tree),
324 std::visit(*this, tree.rhs->tree));
325 }
326
329 {
330 return tree.op(std::visit(*this, tree.rhs->tree));
331 }
332
335 {
336 return std::visit(*this, w.get().tree);
337 }
338
341 {
342 return (*this)(w.get());
343 }
344
347 {
348 return (*this)(w.get());
349 }
350
351 private:
353 };
354
355 template <typename real_t> struct ConstantFolder {
358
360 result_type operator()(nil /*unused*/) const { return 0; }
361
363 result_type operator()(real_t n) const { return n; }
364
366 result_type operator()(std::string const& c) const { return c; }
367
370 return std::visit(*this, ast.tree);
371 }
372
375 auto lhs = std::visit(*this, tree.lhs->tree);
376 auto rhs = std::visit(*this, tree.rhs->tree);
377
378 /* If both operands are known, we can directly evaluate the function,
379 * else we just update the children with the new expressions. */
380 if (auto l = std::get_if<real_t>(&lhs)) {
381 if (auto r = std::get_if<real_t>(&rhs)) {
382 return tree.op(*l, *r);
383 }
384 }
385 return binary_op<real_t>(tree.op, expr_ast<real_t>(lhs), expr_ast<real_t>(rhs));
386 }
387
390 auto rhs = std::visit(*this, tree.rhs->tree);
391 /* If the operand is known, we can directly evaluate the function. */
392 if (auto r = std::get_if<real_t>(&rhs)) {
393 return tree.op(*r);
394 }
395 return unary_op<real_t>(tree.op, expr_ast<real_t>(rhs));
396 }
397
400 return std::visit(*this, w.get().tree);
401 }
402
405 return (*this)(w.get());
406 }
407
410 return (*this)(w.get());
411 }
412 };
413
414 // Simple recursive descent parser
415 template <typename real_t>
417 public:
418 SimpleMathParser(std::string_view input)
419 : input_(input), pos_(0) {}
420
422 pos_ = 0;
423 skipWhitespace();
424 auto result = parseExpression();
425 skipWhitespace();
426 if (pos_ < input_.length()) {
427 throw std::runtime_error("Unexpected characters at end of expression");
428 }
429 return result;
430 }
431
432 private:
433 std::string_view input_;
434 size_t pos_;
435
437 while (pos_ < input_.length() && std::isspace(static_cast<unsigned char>(input_[pos_]))) {
438 pos_++;
439 }
440 }
441
442 bool match(char c) {
443 skipWhitespace();
444 if (pos_ < input_.length() && input_[pos_] == c) {
445 pos_++;
446 return true;
447 }
448 return false;
449 }
450
451 bool match(const std::string& str) {
452 skipWhitespace();
453 if (input_.compare(pos_, str.length(), str) == 0) {
454 pos_ += str.length();
455 return true;
456 }
457 return false;
458 }
459
460 void expect(char c) {
461 if (!match(c)) {
462 throw std::runtime_error(std::string("Expected '") + c + "'");
463 }
464 }
465
467 auto result = parseTerm();
468 while (true) {
469 if (match('+')) {
470 result += parseTerm();
471 } else if (match('-')) {
472 result -= parseTerm();
473 } else {
474 break;
475 }
476 }
477 return result;
478 }
479
481 auto result = parseFactor();
482 while (true) {
483 if (match('*')) {
484 result *= parseFactor();
485 } else if (match('/')) {
486 result = expr_ast<real_t>(binary_op<real_t>(std::divides<real_t>{}, result, parseFactor()));
487 } else if (match('%')) {
488 auto fmod = static_cast<real_t(*)(real_t,real_t)>(&std::fmod);
489 result = expr_ast<real_t>(binary_op<real_t>(fmod, result, parseFactor()));
490 } else {
491 break;
492 }
493 }
494 return result;
495 }
496
498 auto lhs = parsePrimary();
499 skipWhitespace();
500 if (match("**")) {
501 auto rhs = parseFactor();
502 auto pow = static_cast<real_t(*)(real_t,real_t)>(&std::pow);
503 lhs = expr_ast<real_t>(binary_op<real_t>(pow, lhs, rhs));
504 }
505 return lhs;
506 }
507
509 skipWhitespace();
510
511 // Number
512 if (std::isdigit(static_cast<unsigned char>(input_[pos_])) ||
513 (pos_ < input_.length() && input_[pos_] == '.')) {
514 return parseNumber();
515 }
516
517 // Parentheses
518 if (match('(')) {
519 auto result = parseExpression();
520 expect(')');
521 return result;
522 }
523
524 // Unary operators
525 if (match('-')) {
526 return expr_ast<real_t>(unary_op<real_t>(std::negate<real_t>{}, parsePrimary()));
527 }
528 if (match('+')) {
529 return parsePrimary();
530 }
531
532 // Functions
533 std::string identifier = parseIdentifier();
534 if (identifier.empty()) {
535 throw std::runtime_error("Unexpected character");
536 }
537
538 // Check for constants
539 for (const auto& c : getConstants()) {
540 if (identifier == c.first) {
541 return expr_ast<real_t>(c.second);
542 }
543 }
544
545 // Check for binary functions
546 for (const auto& f : getBinaryFunctions()) {
547 if (identifier == f.first) {
548 expect('(');
549 auto arg1 = parseExpression();
550 expect(',');
551 auto arg2 = parseExpression();
552 expect(')');
553 return expr_ast<real_t>(binary_op<real_t>(f.second, arg1, arg2));
554 }
555 }
556
557 // Check for unary functions
558 for (const auto& f : getUnaryFunctions()) {
559 if (identifier == f.first) {
560 expect('(');
561 auto arg = parseExpression();
562 expect(')');
563 return expr_ast<real_t>(unary_op<real_t>(f.second, arg));
564 }
565 }
566
567 // Variable
568 return expr_ast<real_t>(identifier);
569 }
570
572 skipWhitespace();
573 size_t start = pos_;
574 bool has_dot = false;
575 bool has_exp = false;
576
577 if (pos_ < input_.length() && (input_[pos_] == '+' || input_[pos_] == '-')) {
578 pos_++;
579 }
580
581 while (pos_ < input_.length()) {
582 char c = input_[pos_];
583 if (std::isdigit(static_cast<unsigned char>(c))) {
584 pos_++;
585 } else if (c == '.' && !has_dot) {
586 has_dot = true;
587 pos_++;
588 } else if ((c == 'e' || c == 'E') && !has_exp) {
589 has_exp = true;
590 pos_++;
591 if (pos_ >= input_.length() ||
592 (!std::isdigit(static_cast<unsigned char>(input_[pos_])) &&
593 input_[pos_] != '+' && input_[pos_] != '-')) {
594 throw std::runtime_error("Expected exponent digits at position " + std::to_string(pos_));
595 }
596 if (input_[pos_] == '+' || input_[pos_] == '-') pos_++;
597 if (pos_ >= input_.length() || !std::isdigit(static_cast<unsigned char>(input_[pos_]))) {
598 throw std::runtime_error("Expected exponent digits at position " + std::to_string(pos_));
599 }
600 } else {
601 break;
602 }
603 }
604
605 if (pos_ > start) {
606 try {
607 std::string_view sv(input_.data() + start, pos_ - start);
608 real_t value = static_cast<real_t>(std::stod(std::string(sv)));
609 return expr_ast<real_t>(value);
610 } catch (...) {
611 throw std::runtime_error("Invalid number");
612 }
613 }
614 throw std::runtime_error("Expected number");
615 }
616
617 std::string parseIdentifier() {
618 skipWhitespace();
619 size_t start = pos_;
620 if (pos_ < input_.length() && (std::isalpha(static_cast<unsigned char>(input_[pos_])) || input_[pos_] == '_')) {
621 pos_++;
622 while (pos_ < input_.length() &&
623 (std::isalnum(static_cast<unsigned char>(input_[pos_])) || input_[pos_] == '_')) {
624 pos_++;
625 }
626 return std::string(input_.substr(start, pos_ - start));
627 }
628 return "";
629 }
630
631 static const std::array<std::pair<std::string_view, real_t>, 4>& getConstants() {
632 static const std::array<std::pair<std::string_view, real_t>, 4> constants = {{
633 {"e", Physics::e},
634 {"epsilon", std::numeric_limits<real_t>::epsilon()},
635 {"phi", (1.0 + std::sqrt(5.0)) / 2.0},
636 {"pi", Physics::pi}
637 }};
638 return constants;
639 }
640
641 static const std::array<std::pair<std::string_view, typename unary_op<real_t>::op_t>, 31>& getUnaryFunctions() {
642 static const std::array<std::pair<std::string_view, typename unary_op<real_t>::op_t>, 31> funcs = {{
643 {"abs", static_cast<real_t(*)(real_t)>(&std::abs)},
644 {"acos", static_cast<real_t(*)(real_t)>(&std::acos)},
645 {"acosh", static_cast<real_t(*)(real_t)>(&std::acosh)},
646 {"asin", static_cast<real_t(*)(real_t)>(&std::asin)},
647 {"asinh", static_cast<real_t(*)(real_t)>(&std::asinh)},
648 {"atan", static_cast<real_t(*)(real_t)>(&std::atan)},
649 {"atanh", static_cast<real_t(*)(real_t)>(&std::atanh)},
650 {"cbrt", static_cast<real_t(*)(real_t)>(&std::cbrt)},
651 {"ceil", static_cast<real_t(*)(real_t)>(&std::ceil)},
652 {"cos", static_cast<real_t(*)(real_t)>(&std::cos)},
653 {"cosh", static_cast<real_t(*)(real_t)>(&std::cosh)},
654 {"deg2rad", static_cast<real_t(*)(real_t)>(&math::deg)},
655 {"erf", static_cast<real_t(*)(real_t)>(&std::erf)},
656 {"erfc", static_cast<real_t(*)(real_t)>(&std::erfc)},
657 {"exp", static_cast<real_t(*)(real_t)>(&std::exp)},
658 {"exp2", static_cast<real_t(*)(real_t)>(&std::exp2)},
659 {"floor", static_cast<real_t(*)(real_t)>(&std::floor)},
660 {"isinf", static_cast<real_t(*)(real_t)>(&math::isinf)},
661 {"isnan", static_cast<real_t(*)(real_t)>(&math::isnan)},
662 {"log", static_cast<real_t(*)(real_t)>(&std::log)},
663 {"log2", static_cast<real_t(*)(real_t)>(&std::log2)},
664 {"log10", static_cast<real_t(*)(real_t)>(&std::log10)},
665 {"rad2deg", static_cast<real_t(*)(real_t)>(&math::rad)},
666 {"round", static_cast<real_t(*)(real_t)>(&std::round)},
667 {"sgn", static_cast<real_t(*)(real_t)>(&math::sgn)},
668 {"sin", static_cast<real_t(*)(real_t)>(&std::sin)},
669 {"sinh", static_cast<real_t(*)(real_t)>(&std::sinh)},
670 {"sqrt", static_cast<real_t(*)(real_t)>(&std::sqrt)},
671 {"tan", static_cast<real_t(*)(real_t)>(&std::tan)},
672 {"tanh", static_cast<real_t(*)(real_t)>(&std::tanh)},
673 {"tgamma", static_cast<real_t(*)(real_t)>(&std::tgamma)}
674 }};
675 return funcs;
676 }
677
678 static const std::array<std::pair<std::string_view, typename binary_op<real_t>::op_t>, 4>& getBinaryFunctions() {
679 static const std::array<std::pair<std::string_view, typename binary_op<real_t>::op_t>, 4> funcs = {{
680 {"atan2", static_cast<real_t(*)(real_t,real_t)>(&std::atan2)},
681 {"max", static_cast<real_t(*)(real_t,real_t)>(&std::fmax)},
682 {"min", static_cast<real_t(*)(real_t,real_t)>(&std::fmin)},
683 {"pow", static_cast<real_t(*)(real_t,real_t)>(&std::pow)}
684 }};
685 return funcs;
686 }
687 };
688
697 template <typename real_t, typename Iterator>
698 expr_ast<real_t> parse(Iterator first, Iterator last) {
699 std::string input(first, last);
700 SimpleMathParser<real_t> parser(input);
701 return parser.parse();
702 }
703
704 } // namespace detail
705
706
714 template < typename real_t >
715 class Parser
716 {
718 public:
727 template < typename Iterator >
728 void parse(Iterator first, Iterator last)
729 {
730 ast = detail::parse<real_t>(first, last);
731 }
732
734 void parse(std::string const &str)
735 {
736 parse(str.begin(), str.end());
737 }
738
739 void optimize() {
740 ast.tree = std::visit(detail::ConstantFolder<real_t>{}, ast.tree);
741 }
742
747 real_t evaluate(typename detail::eval_ast<real_t>::symbol_table_t const& st) const
748 {
749 detail::eval_ast<real_t> solver(st);
750 return solver(ast);
751 }
752 };
753
754
764 template < typename real_t, typename Iterator >
765 real_t parse(Iterator first, Iterator last,
767 {
768 Parser<real_t> parser;
769 parser.parse(first, last);
770 return parser.evaluate(st);
771 }
772
774 template < typename real_t >
775 real_t parse(std::string const& str,
777 {
778 return parse<real_t>(str.begin(), str.end(), st);
779 }
780
781} // namespace matheval
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition TpsMath.h:76
PETE_TBTree< FnFmod, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > fmod(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
arg(a))
constexpr double e
The value of.
Definition Physics.h:39
constexpr double pi
The value of.
Definition Physics.h:30
constexpr double rad2deg
Definition Units.h:146
constexpr double deg2rad
Definition Units.h:143
expr_ast< real_t > parse(Iterator first, Iterator last)
Parse an expression.
Definition matheval.hpp:698
constexpr T rad(T x)
Convert degrees to radians.
Definition matheval.hpp:82
T isinf(T x)
isinf function with adjusted return type
Definition matheval.hpp:74
T isnan(T x)
isnan function with adjusted return type
Definition matheval.hpp:70
constexpr T deg(T x)
Convert radians to degrees.
Definition matheval.hpp:78
constexpr T sgn(T x)
Sign function.
Definition matheval.hpp:66
Abstract Syntax Tree.
Definition matheval.hpp:129
expr_ast & operator-=(expr_ast const &rhs)
subtract a tree
Definition matheval.hpp:259
expr_ast()
Default constructor.
Definition matheval.hpp:153
expr_ast & operator/=(expr_ast const &rhs)
Divide by a tree.
Definition matheval.hpp:271
expr_ast & operator*=(expr_ast const &rhs)
Multiply by a tree.
Definition matheval.hpp:265
expr_ast & operator+=(expr_ast const &rhs)
Add a tree.
Definition matheval.hpp:253
expr_ast(Expr other)
Copy constructor.
Definition matheval.hpp:160
tree_t tree
AST storage.
Definition matheval.hpp:146
std::variant< nil, real_t, std::string, recursive_wrapper< expr_ast< real_t > >, recursive_wrapper< binary_op< real_t > >, recursive_wrapper< unary_op< real_t > > > tree_t
Definition matheval.hpp:137
Store a unary operator and its argument tree.
Definition matheval.hpp:175
unary_op(const unary_op &other)
Definition matheval.hpp:185
op_t op
Stored operator.
Definition matheval.hpp:203
unary_op & operator=(unary_op &&) noexcept=default
unary_op(unary_op &&) noexcept=default
unary_op(op_t op, expr_ast< real_t > rhs)
Save the operator and the argument tree.
Definition matheval.hpp:180
std::unique_ptr< expr_ast< real_t > > rhs
Stored argument tree.
Definition matheval.hpp:206
std::function< real_t(real_t)> op_t
Signature of a unary operator: op(x)
Definition matheval.hpp:177
Store a binary operator and its argument trees.
Definition matheval.hpp:212
binary_op & operator=(binary_op &&) noexcept=default
binary_op(op_t op, expr_ast< real_t > lhs, expr_ast< real_t > rhs)
Save the operator and the argument trees.
Definition matheval.hpp:217
binary_op(binary_op &&) noexcept=default
std::function< real_t(real_t, real_t)> op_t
Signature of a binary operator: op(x,y)
Definition matheval.hpp:214
binary_op(const binary_op &other)
Definition matheval.hpp:223
op_t op
Stored operator.
Definition matheval.hpp:243
std::unique_ptr< expr_ast< real_t > > lhs
Stored argument tree of first argument.
Definition matheval.hpp:246
std::unique_ptr< expr_ast< real_t > > rhs
Stored argument tree of second argument.
Definition matheval.hpp:249
recursive_wrapper(recursive_wrapper &&other) noexcept=default
recursive_wrapper & operator=(recursive_wrapper &&other) noexcept=default
recursive_wrapper & operator=(const recursive_wrapper &other)
Definition matheval.hpp:101
recursive_wrapper(const recursive_wrapper &other)
Definition matheval.hpp:98
Evaluate the Abstract Syntax Tree.
Definition matheval.hpp:284
result_type operator()(recursive_wrapper< expr_ast< real_t > > const &w) const
Handle recursive_wrapper for expr_ast.
Definition matheval.hpp:334
real_t result_type
Necessary typedef for visitor.
Definition matheval.hpp:287
result_type operator()(binary_op< real_t > const &tree) const
Evaluate a binary operator and optionally recurse its operands.
Definition matheval.hpp:321
result_type operator()(result_type n) const
Numbers evaluate to themselves.
Definition matheval.hpp:302
result_type operator()(nil) const
Empty nodes in the tree evaluate to 0.
Definition matheval.hpp:299
result_type operator()(expr_ast< real_t > const &ast) const
Recursively evaluate the AST.
Definition matheval.hpp:315
std::unordered_map< std::string, result_type > symbol_table_t
Type of the symbol table.
Definition matheval.hpp:290
result_type operator()(recursive_wrapper< binary_op< real_t > > const &w) const
Handle recursive_wrapper for binary_op.
Definition matheval.hpp:340
result_type operator()(recursive_wrapper< unary_op< real_t > > const &w) const
Handle recursive_wrapper for unary_op.
Definition matheval.hpp:346
result_type operator()(unary_op< real_t > const &tree) const
Evaluate a unary operator and optionally recurse its operand.
Definition matheval.hpp:328
eval_ast(symbol_table_t sym)
Constructor.
Definition matheval.hpp:296
result_type operator()(std::string const &c) const
Variables evaluate to their value in the symbol table.
Definition matheval.hpp:305
result_type operator()(binary_op< real_t > const &tree) const
Evaluate a binary operator and optionally recurse its operands.
Definition matheval.hpp:374
result_type operator()(nil) const
Empty nodes in the tree evaluate to 0.
Definition matheval.hpp:360
result_type operator()(recursive_wrapper< expr_ast< real_t > > const &w) const
Handle recursive_wrapper for expr_ast.
Definition matheval.hpp:399
result_type operator()(unary_op< real_t > const &tree) const
Evaluate a unary operator and optionally recurse its operand.
Definition matheval.hpp:389
result_type operator()(real_t n) const
Numbers evaluate to themselves.
Definition matheval.hpp:363
typename expr_ast< real_t >::tree_t result_type
Necessary typedef for visitor.
Definition matheval.hpp:357
result_type operator()(recursive_wrapper< binary_op< real_t > > const &w) const
Handle recursive_wrapper for binary_op.
Definition matheval.hpp:404
result_type operator()(std::string const &c) const
Variables do not evaluate.
Definition matheval.hpp:366
result_type operator()(expr_ast< real_t > const &ast) const
Recursively evaluate the AST.
Definition matheval.hpp:369
result_type operator()(recursive_wrapper< unary_op< real_t > > const &w) const
Handle recursive_wrapper for unary_op.
Definition matheval.hpp:409
bool match(const std::string &str)
Definition matheval.hpp:451
expr_ast< real_t > parsePrimary()
Definition matheval.hpp:508
static const std::array< std::pair< std::string_view, typename unary_op< real_t >::op_t >, 31 > & getUnaryFunctions()
Definition matheval.hpp:641
static const std::array< std::pair< std::string_view, real_t >, 4 > & getConstants()
Definition matheval.hpp:631
static const std::array< std::pair< std::string_view, typename binary_op< real_t >::op_t >, 4 > & getBinaryFunctions()
Definition matheval.hpp:678
SimpleMathParser(std::string_view input)
Definition matheval.hpp:418
expr_ast< real_t > parseTerm()
Definition matheval.hpp:480
expr_ast< real_t > parseExpression()
Definition matheval.hpp:466
expr_ast< real_t > parseFactor()
Definition matheval.hpp:497
expr_ast< real_t > parseNumber()
Definition matheval.hpp:571
Class interface.
Definition matheval.hpp:716
void parse(Iterator first, Iterator last)
Parse an expression.
Definition matheval.hpp:728
real_t evaluate(typename detail::eval_ast< real_t >::symbol_table_t const &st) const
Evaluate the AST with a given symbol table.
Definition matheval.hpp:747
detail::expr_ast< real_t > ast
Definition matheval.hpp:717
void parse(std::string const &str)
Definition matheval.hpp:734