OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
matheval.hpp
Go to the documentation of this file.
1// Copyright (C) 2011-2013 Rhys Ulerich
2// Copyright (C) ??? Martin Bauer
3// Copyright (C) 2017 Henri Menke
4//
5// This code borrows heavily from code written by Rhys Ulerich and
6// Martin Bauer. They licensed it under the Mozilla Public License,
7// v. 2.0 and the GNU General Public License (no version info),
8// respectively. I believe that I have made enough contributions and
9// altered this code far enough from the originals that I can
10// relicense it under the Boost Software License.
11//
12// Distributed under the Boost Software License, Version 1.0. (See
13// accompanying file LICENSE_1_0.txt or copy at
14// http://www.boost.org/LICENSE_1_0.txt)
15#pragma once
16
17#include <algorithm>
18#include <cctype>
19#include <cmath>
20#include <functional>
21#include <iterator>
22#include <limits>
23#include <map>
24#include <memory>
25#include <numbers>
26#include <sstream>
27#include <stdexcept>
28#include <string>
29#include <variant>
30
31namespace matheval {
32
33 namespace detail {
34
35 namespace math {
36
54 template <typename T>
55 T sgn(T x) {
56 return (T{0} < x) - (x < T{0});
57 }
58
60 template <typename T>
61 T isnan(T x) {
62 return std::isnan(x);
63 }
64
66 template <typename T>
67 T isinf(T x) {
68 return std::isinf(x);
69 }
70
72 template <typename T>
73 T deg(T x) {
74 return x * (std::numbers::pi_v<T> / 180.0);
75 }
76
78 template <typename T>
79 T rad(T x) {
80 return x * (180.0 / std::numbers::pi_v<T>);
81 }
82
83 } // namespace math
84
85 // Forward declarations
86 template <typename real_t>
87 struct expr_ast;
88 template <typename real_t>
89 struct unary_op;
90 template <typename real_t>
91 struct binary_op;
92
93 struct nil {};
94
95 // Simple recursive wrapper for std::variant using unique_ptr
96 template <typename T>
98 recursive_wrapper() : ptr(std::make_unique<T>()) {}
99 recursive_wrapper(const T& t) : ptr(std::make_unique<T>(t)) {}
100 recursive_wrapper(T&& t) : ptr(std::make_unique<T>(std::move(t))) {}
102 : ptr(std::make_unique<T>(*other.ptr)) {}
103 recursive_wrapper(recursive_wrapper&& other) noexcept = default;
104
106 if (this != &other) {
107 ptr = std::make_unique<T>(*other.ptr);
108 }
109 return *this;
110 }
111
112 recursive_wrapper& operator=(recursive_wrapper&& other) noexcept = default;
113
114 T& get() { return *ptr; }
115 const T& get() const { return *ptr; }
116
117 operator T&() { return *ptr; }
118 operator const T&() const { return *ptr; }
119
120 private:
121 std::unique_ptr<T> ptr;
122 };
123
124 // AST
125
131 template <typename real_t>
132 struct expr_ast {
133 using tree_t = std::variant<
134 nil // can't happen!
135 ,
136 real_t, std::string, recursive_wrapper<expr_ast<real_t>>,
138
139 public:
148
154 expr_ast() : tree(nil{}) {}
155
160 template <typename Expr>
161 expr_ast(Expr other) : tree(std::move(other)) {} // NOLINT
162
164 expr_ast& operator+=(expr_ast const& rhs);
166 expr_ast& operator-=(expr_ast const& rhs);
168 expr_ast& operator*=(expr_ast const& rhs);
170 expr_ast& operator/=(expr_ast const& rhs);
171 };
172
174 template <typename real_t>
175 struct unary_op {
177 using op_t = std::function<real_t(real_t)>;
178
181 : op(std::move(op)), rhs(std::make_unique<expr_ast<real_t>>(std::move(rhs))) {}
182
183 unary_op(const unary_op& other)
184 : op(other.op), rhs(std::make_unique<expr_ast<real_t>>(*other.rhs)) {}
185
186 unary_op(unary_op&&) noexcept = default;
187
188 unary_op& operator=(const unary_op& other) {
189 if (this != &other) {
190 op = other.op;
191 rhs = std::make_unique<expr_ast<real_t>>(*other.rhs);
192 }
193 return *this;
194 }
195
196 unary_op& operator=(unary_op&&) noexcept = default;
197
201 std::unique_ptr<expr_ast<real_t>> rhs;
202 };
203
205 template <typename real_t>
206 struct binary_op {
208 using op_t = std::function<real_t(real_t, real_t)>;
209
212 : op(std::move(op)),
213 lhs(std::make_unique<expr_ast<real_t>>(std::move(lhs))),
214 rhs(std::make_unique<expr_ast<real_t>>(std::move(rhs))) {}
215
216 binary_op(const binary_op& other)
217 : op(other.op),
218 lhs(std::make_unique<expr_ast<real_t>>(*other.lhs)),
219 rhs(std::make_unique<expr_ast<real_t>>(*other.rhs)) {}
220
221 binary_op(binary_op&&) noexcept = default;
222
223 binary_op& operator=(const binary_op& other) {
224 if (this != &other) {
225 op = other.op;
226 lhs = std::make_unique<expr_ast<real_t>>(*other.lhs);
227 rhs = std::make_unique<expr_ast<real_t>>(*other.rhs);
228 }
229 return *this;
230 }
231
232 binary_op& operator=(binary_op&&) noexcept = default;
233
237 std::unique_ptr<expr_ast<real_t>> lhs;
239 std::unique_ptr<expr_ast<real_t>> rhs;
240 };
241
242 template <typename real_t>
243 expr_ast<real_t>& expr_ast<real_t>::operator+=(expr_ast<real_t> const& rhs) {
244 tree = binary_op<real_t>(std::plus<real_t>{}, tree, rhs);
245 return *this;
246 }
247 template <typename real_t>
249 tree = binary_op<real_t>(std::minus<real_t>{}, tree, rhs);
250 return *this;
251 }
252 template <typename real_t>
254 tree = binary_op<real_t>(std::multiplies<real_t>{}, tree, rhs);
255 return *this;
256 }
257 template <typename real_t>
259 tree = binary_op<real_t>(std::divides<real_t>{}, tree, rhs);
260 return *this;
261 }
262
268 template <typename real_t>
269 class eval_ast {
270 public:
272 using result_type = real_t;
273
275 using symbol_table_t = std::map<std::string, result_type>;
276
281 explicit eval_ast(symbol_table_t sym) : st(std::move(sym)) {}
282
284 result_type operator()(nil /*unused*/) const { return 0; }
285
287 result_type operator()(result_type n) const { return n; }
288
290 result_type operator()(std::string const& c) const {
291 auto it = st.find(c);
292 if (it == st.end()) {
293 throw std::invalid_argument("Unknown variable " + c); // NOLINT
294 }
295 return it->second;
296 }
297
300 return std::visit(*this, ast.tree);
301 }
302
305 return tree.op(
306 std::visit(*this, tree.lhs->tree), std::visit(*this, tree.rhs->tree));
307 }
308
311 return tree.op(std::visit(*this, tree.rhs->tree));
312 }
313
316 return std::visit(*this, w.get().tree);
317 }
318
321 return (*this)(w.get());
322 }
323
326 return (*this)(w.get());
327 }
328
329 private:
331 };
332
333 template <typename T>
335 using result_type = bool;
336
337 template <typename U>
338 bool operator()(U const& /*unused*/) const {
339 return std::is_same<U, T>::value;
340 }
341 };
342
343 template <typename T, typename... Ts>
344 bool holds_alternative(std::variant<Ts...> const& v) {
345 return std::visit(holds_alternative_impl<T>(), v);
346 }
347
348 template <typename real_t>
352
354 result_type operator()(nil /*unused*/) const { return 0; }
355
357 result_type operator()(real_t n) const { return n; }
358
360 result_type operator()(std::string const& c) const { return c; }
361
364 return std::visit(*this, ast.tree);
365 }
366
369 auto lhs = std::visit(*this, tree.lhs->tree);
370 auto rhs = std::visit(*this, tree.rhs->tree);
371
372 /* If both operands are known, we can directly evaluate the function,
373 * else we just update the children with the new expressions. */
374 if (holds_alternative<real_t>(lhs) && holds_alternative<real_t>(rhs)) {
375 return tree.op(std::get<real_t>(lhs), std::get<real_t>(rhs));
376 }
377 return binary_op<real_t>(tree.op, expr_ast<real_t>(lhs), expr_ast<real_t>(rhs));
378 }
379
382 auto rhs = std::visit(*this, tree.rhs->tree);
383 /* If the operand is known, we can directly evaluate the function. */
384 if (holds_alternative<real_t>(rhs)) {
385 return tree.op(std::get<real_t>(rhs));
386 }
387 return unary_op<real_t>(tree.op, expr_ast<real_t>(rhs));
388 }
389
392 return std::visit(*this, w.get().tree);
393 }
394
397 return (*this)(w.get());
398 }
399
402 return (*this)(w.get());
403 }
404 };
405
406 // Simple recursive descent parser
407
408 template <typename real_t>
410 public:
411 SimpleMathParser(const std::string& input) : input_(input), pos_(0) {}
412
414 pos_ = 0;
415 skipWhitespace();
416 auto result = parseExpression();
417 skipWhitespace();
418 if (pos_ < input_.length()) {
419 throw std::runtime_error("Unexpected characters at end of expression");
420 }
421 return result;
422 }
423
424 private:
425 std::string input_;
426 size_t pos_;
427
429 while (pos_ < input_.length()
430 && std::isspace(static_cast<unsigned char>(input_[pos_]))) {
431 pos_++;
432 }
433 }
434
435 bool match(char c) {
436 skipWhitespace();
437 if (pos_ < input_.length() && input_[pos_] == c) {
438 pos_++;
439 return true;
440 }
441 return false;
442 }
443
444 bool match(const std::string& str) {
445 skipWhitespace();
446 if (input_.compare(pos_, str.length(), str) == 0) {
447 pos_ += str.length();
448 return true;
449 }
450 return false;
451 }
452
453 void expect(char c) {
454 if (!match(c)) {
455 throw std::runtime_error(std::string("Expected '") + c + "'");
456 }
457 }
458
460 auto result = parseTerm();
461 while (true) {
462 if (match('+')) {
463 result += parseTerm();
464 } else if (match('-')) {
465 result -= parseTerm();
466 } else {
467 break;
468 }
469 }
470 return result;
471 }
472
474 auto result = parseFactor();
475 while (true) {
476 if (match('*')) {
477 result *= parseFactor();
478 } else if (match('/')) {
479 result = expr_ast<real_t>(
480 binary_op<real_t>(std::divides<real_t>{}, result, parseFactor()));
481 } else if (match('%')) {
482 auto fmod = static_cast<real_t (*)(real_t, real_t)>(&std::fmod);
483 result = expr_ast<real_t>(binary_op<real_t>(fmod, result, parseFactor()));
484 } else {
485 break;
486 }
487 }
488 return result;
489 }
490
492 auto result = parsePrimary();
493 while (match("**")) {
494 auto pow = static_cast<real_t (*)(real_t, real_t)>(&std::pow);
495 result = expr_ast<real_t>(binary_op<real_t>(pow, result, parseFactor()));
496 }
497 return result;
498 }
499
501 skipWhitespace();
502
503 // Number
504 if (std::isdigit(static_cast<unsigned char>(input_[pos_]))
505 || (pos_ < input_.length() && input_[pos_] == '.')) {
506 return parseNumber();
507 }
508
509 // Parentheses
510 if (match('(')) {
511 auto result = parseExpression();
512 expect(')');
513 return result;
514 }
515
516 // Unary operators
517 if (match('-')) {
518 return expr_ast<real_t>(
519 unary_op<real_t>(std::negate<real_t>{}, parsePrimary()));
520 }
521 if (match('+')) {
522 return parsePrimary();
523 }
524
525 // Functions
526 std::string identifier = parseIdentifier();
527 if (identifier.empty()) {
528 throw std::runtime_error("Unexpected character");
529 }
530
531 // Check for constants
532 const auto& constants = getConstants();
533 if (constants.find(identifier) != constants.end()) {
534 return expr_ast<real_t>(constants.at(identifier));
535 }
536
537 // Check for unary functions
538 const auto& ufuncs = getUnaryFunctions();
539 if (ufuncs.find(identifier) != ufuncs.end()) {
540 expect('(');
541 auto arg = parseExpression();
542 expect(')');
543 return expr_ast<real_t>(unary_op<real_t>(ufuncs.at(identifier), arg));
544 }
545
546 // Check for binary functions
547 const auto& bfuncs = getBinaryFunctions();
548 if (bfuncs.find(identifier) != bfuncs.end()) {
549 expect('(');
550 auto arg1 = parseExpression();
551 expect(',');
552 auto arg2 = parseExpression();
553 expect(')');
554 return expr_ast<real_t>(binary_op<real_t>(bfuncs.at(identifier), arg1, arg2));
555 }
556
557 // Variable
558 return expr_ast<real_t>(identifier);
559 }
560
562 skipWhitespace();
563 size_t start = pos_;
564 bool has_dot = false;
565 bool has_exp = false;
566
567 if (pos_ < input_.length() && (input_[pos_] == '+' || input_[pos_] == '-')) {
568 pos_++;
569 }
570
571 while (pos_ < input_.length()) {
572 char c = input_[pos_];
573 if (std::isdigit(static_cast<unsigned char>(c))) {
574 pos_++;
575 } else if (c == '.' && !has_dot) {
576 has_dot = true;
577 pos_++;
578 } else if ((c == 'e' || c == 'E') && !has_exp) {
579 has_exp = true;
580 pos_++;
581 if (pos_ < input_.length()
582 && (input_[pos_] == '+' || input_[pos_] == '-')) {
583 pos_++;
584 }
585 } else {
586 break;
587 }
588 }
589
590 if (pos_ > start) {
591 try {
592 real_t value =
593 static_cast<real_t>(std::stod(input_.substr(start, pos_ - start)));
594 return expr_ast<real_t>(value);
595 } catch (...) {
596 throw std::runtime_error("Invalid number");
597 }
598 }
599 throw std::runtime_error("Expected number");
600 }
601
602 std::string parseIdentifier() {
603 skipWhitespace();
604 size_t start = pos_;
605 if (pos_ < input_.length()
606 && (std::isalpha(static_cast<unsigned char>(input_[pos_]))
607 || input_[pos_] == '_')) {
608 pos_++;
609 while (pos_ < input_.length()
610 && (std::isalnum(static_cast<unsigned char>(input_[pos_]))
611 || input_[pos_] == '_')) {
612 pos_++;
613 }
614 return input_.substr(start, pos_ - start);
615 }
616 return "";
617 }
618
619 static const std::map<std::string, real_t>& getConstants() {
620 static const std::map<std::string, real_t> constants = {
621 {"e", std::numbers::e_v<real_t>},
622 {"epsilon", std::numeric_limits<real_t>::epsilon()},
623 {"phi", (1.0 + std::sqrt(5.0)) / 2.0}, // Golden ratio
624 {"pi", std::numbers::pi_v<real_t>}};
625 return constants;
626 }
627
628 static const std::map<std::string, typename unary_op<real_t>::op_t>&
630 static const std::map<std::string, typename unary_op<real_t>::op_t> funcs = {
631 {"abs", static_cast<real_t (*)(real_t)>(&std::abs)},
632 {"acos", static_cast<real_t (*)(real_t)>(&std::acos)},
633 {"acosh", static_cast<real_t (*)(real_t)>(&std::acosh)},
634 {"asin", static_cast<real_t (*)(real_t)>(&std::asin)},
635 {"asinh", static_cast<real_t (*)(real_t)>(&std::asinh)},
636 {"atan", static_cast<real_t (*)(real_t)>(&std::atan)},
637 {"atanh", static_cast<real_t (*)(real_t)>(&std::atanh)},
638 {"cbrt", static_cast<real_t (*)(real_t)>(&std::cbrt)},
639 {"ceil", static_cast<real_t (*)(real_t)>(&std::ceil)},
640 {"cos", static_cast<real_t (*)(real_t)>(&std::cos)},
641 {"cosh", static_cast<real_t (*)(real_t)>(&std::cosh)},
642 {"deg2rad", static_cast<real_t (*)(real_t)>(&math::deg)},
643 {"erf", static_cast<real_t (*)(real_t)>(&std::erf)},
644 {"erfc", static_cast<real_t (*)(real_t)>(&std::erfc)},
645 {"exp", static_cast<real_t (*)(real_t)>(&std::exp)},
646 {"exp2", static_cast<real_t (*)(real_t)>(&std::exp2)},
647 {"floor", static_cast<real_t (*)(real_t)>(&std::floor)},
648 {"isinf", static_cast<real_t (*)(real_t)>(&math::isinf)},
649 {"isnan", static_cast<real_t (*)(real_t)>(&math::isnan)},
650 {"log", static_cast<real_t (*)(real_t)>(&std::log)},
651 {"log2", static_cast<real_t (*)(real_t)>(&std::log2)},
652 {"log10", static_cast<real_t (*)(real_t)>(&std::log10)},
653 {"rad2deg", static_cast<real_t (*)(real_t)>(&math::rad)},
654 {"round", static_cast<real_t (*)(real_t)>(&std::round)},
655 {"sgn", static_cast<real_t (*)(real_t)>(&math::sgn)},
656 {"sin", static_cast<real_t (*)(real_t)>(&std::sin)},
657 {"sinh", static_cast<real_t (*)(real_t)>(&std::sinh)},
658 {"sqrt", static_cast<real_t (*)(real_t)>(&std::sqrt)},
659 {"tan", static_cast<real_t (*)(real_t)>(&std::tan)},
660 {"tanh", static_cast<real_t (*)(real_t)>(&std::tanh)},
661 {"tgamma", static_cast<real_t (*)(real_t)>(&std::tgamma)}};
662 return funcs;
663 }
664
665 static const std::map<std::string, typename binary_op<real_t>::op_t>&
667 static const std::map<std::string, typename binary_op<real_t>::op_t> funcs = {
668 {"atan2", static_cast<real_t (*)(real_t, real_t)>(&std::atan2)},
669 {"max", static_cast<real_t (*)(real_t, real_t)>(&std::fmax)},
670 {"min", static_cast<real_t (*)(real_t, real_t)>(&std::fmin)},
671 {"pow", static_cast<real_t (*)(real_t, real_t)>(&std::pow)}};
672 return funcs;
673 }
674 };
675
684 template <typename real_t, typename Iterator>
685 expr_ast<real_t> parse(Iterator first, Iterator last) {
686 std::string input(first, last);
687 SimpleMathParser<real_t> parser(input);
688 return parser.parse();
689 }
690
691 } // namespace detail
692
700 template <typename real_t>
701 class Parser {
703
704 public:
713 template <typename Iterator>
714 void parse(Iterator first, Iterator last) {
715 ast = detail::parse<real_t>(first, last);
716 }
717
719 void parse(std::string const& str) { parse(str.begin(), str.end()); }
720
721 void optimize() { ast.tree = std::visit(detail::ConstantFolder<real_t>{}, ast.tree); }
722
728 detail::eval_ast<real_t> solver(st);
729 return solver(ast);
730 }
731 };
732
742 template <typename real_t, typename Iterator>
743 real_t parse(
744 Iterator first, Iterator last,
745 typename detail::eval_ast<real_t>::symbol_table_t const& st) {
746 Parser<real_t> parser;
747 parser.parse(first, last);
748 return parser.evaluate(st);
749 }
750
753 template <typename real_t>
754 real_t parse(
755 std::string const& str, typename detail::eval_ast<real_t>::symbol_table_t const& st) {
756 return parse<real_t>(str.begin(), str.end(), st);
757 }
758
759} // namespace matheval
double T
Definition OPALTypes.h:8
Class interface.
Definition matheval.hpp:701
void parse(Iterator first, Iterator last)
Parse an expression.
Definition matheval.hpp:714
detail::expr_ast< real_t > ast
Definition matheval.hpp:702
void parse(std::string const &str)
Definition matheval.hpp:719
real_t evaluate(typename detail::eval_ast< real_t >::symbol_table_t const &st)
Evaluate the AST with a given symbol table.
Definition matheval.hpp:727
bool match(const std::string &str)
Definition matheval.hpp:444
expr_ast< real_t > parsePrimary()
Definition matheval.hpp:500
SimpleMathParser(const std::string &input)
Definition matheval.hpp:411
static const std::map< std::string, typename unary_op< real_t >::op_t > & getUnaryFunctions()
Definition matheval.hpp:629
static const std::map< std::string, real_t > & getConstants()
Definition matheval.hpp:619
expr_ast< real_t > parseTerm()
Definition matheval.hpp:473
expr_ast< real_t > parseExpression()
Definition matheval.hpp:459
expr_ast< real_t > parseFactor()
Definition matheval.hpp:491
expr_ast< real_t > parseNumber()
Definition matheval.hpp:561
static const std::map< std::string, typename binary_op< real_t >::op_t > & getBinaryFunctions()
Definition matheval.hpp:666
Evaluate the Abstract Syntax Tree.
Definition matheval.hpp:269
result_type operator()(recursive_wrapper< expr_ast< real_t > > const &w) const
Handle recursive_wrapper for expr_ast.
Definition matheval.hpp:315
real_t result_type
Necessary typedef for visitor.
Definition matheval.hpp:272
result_type operator()(binary_op< real_t > const &tree) const
Evaluate a binary operator and optionally recurse its operands.
Definition matheval.hpp:304
result_type operator()(result_type n) const
Numbers evaluate to themselves.
Definition matheval.hpp:287
result_type operator()(nil) const
Empty nodes in the tree evaluate to 0.
Definition matheval.hpp:284
result_type operator()(expr_ast< real_t > const &ast) const
Recursively evaluate the AST.
Definition matheval.hpp:299
result_type operator()(recursive_wrapper< binary_op< real_t > > const &w) const
Handle recursive_wrapper for binary_op.
Definition matheval.hpp:320
result_type operator()(recursive_wrapper< unary_op< real_t > > const &w) const
Handle recursive_wrapper for unary_op.
Definition matheval.hpp:325
std::map< std::string, result_type > symbol_table_t
Type of the symbol table.
Definition matheval.hpp:275
result_type operator()(unary_op< real_t > const &tree) const
Evaluate a unary operator and optionally recurse its operand.
Definition matheval.hpp:310
eval_ast(symbol_table_t sym)
Constructor.
Definition matheval.hpp:281
result_type operator()(std::string const &c) const
Variables evaluate to their value in the symbol table.
Definition matheval.hpp:290
T isinf(T x)
isinf function with adjusted return type
Definition matheval.hpp:67
T isnan(T x)
isnan function with adjusted return type
Definition matheval.hpp:61
T rad(T x)
Convert degrees to radians.
Definition matheval.hpp:79
T sgn(T x)
Sign function.
Definition matheval.hpp:55
T deg(T x)
Convert radians to degrees.
Definition matheval.hpp:73
bool holds_alternative(std::variant< Ts... > const &v)
Definition matheval.hpp:344
expr_ast< real_t > parse(Iterator first, Iterator last)
Parse an expression.
Definition matheval.hpp:685
STL namespace.
result_type operator()(binary_op< real_t > const &tree) const
Evaluate a binary operator and optionally recurse its operands.
Definition matheval.hpp:368
result_type operator()(nil) const
Empty nodes in the tree evaluate to 0.
Definition matheval.hpp:354
result_type operator()(recursive_wrapper< expr_ast< real_t > > const &w) const
Handle recursive_wrapper for expr_ast.
Definition matheval.hpp:391
result_type operator()(unary_op< real_t > const &tree) const
Evaluate a unary operator and optionally recurse its operand.
Definition matheval.hpp:381
result_type operator()(real_t n) const
Numbers evaluate to themselves.
Definition matheval.hpp:357
typename expr_ast< real_t >::tree_t result_type
Necessary typedef for visitor.
Definition matheval.hpp:351
result_type operator()(recursive_wrapper< binary_op< real_t > > const &w) const
Handle recursive_wrapper for binary_op.
Definition matheval.hpp:396
result_type operator()(std::string const &c) const
Variables do not evaluate.
Definition matheval.hpp:360
result_type operator()(expr_ast< real_t > const &ast) const
Recursively evaluate the AST.
Definition matheval.hpp:363
result_type operator()(recursive_wrapper< unary_op< real_t > > const &w) const
Handle recursive_wrapper for unary_op.
Definition matheval.hpp:401
Store a binary operator and its argument trees.
Definition matheval.hpp:206
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:211
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:208
binary_op(const binary_op &other)
Definition matheval.hpp:216
op_t op
Stored operator.
Definition matheval.hpp:235
std::unique_ptr< expr_ast< real_t > > lhs
Stored argument tree of first argument.
Definition matheval.hpp:237
std::unique_ptr< expr_ast< real_t > > rhs
Stored argument tree of second argument.
Definition matheval.hpp:239
Abstract Syntax Tree.
Definition matheval.hpp:132
expr_ast & operator-=(expr_ast const &rhs)
subtract a tree
Definition matheval.hpp:248
expr_ast()
Default constructor.
Definition matheval.hpp:154
expr_ast & operator/=(expr_ast const &rhs)
Divide by a tree.
Definition matheval.hpp:258
expr_ast & operator*=(expr_ast const &rhs)
Multiply by a tree.
Definition matheval.hpp:253
expr_ast & operator+=(expr_ast const &rhs)
Add a tree.
Definition matheval.hpp:243
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
expr_ast(Expr other)
Copy constructor.
Definition matheval.hpp:161
tree_t tree
AST storage.
Definition matheval.hpp:147
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:105
recursive_wrapper(const recursive_wrapper &other)
Definition matheval.hpp:101
Store a unary operator and its argument tree.
Definition matheval.hpp:175
unary_op(const unary_op &other)
Definition matheval.hpp:183
op_t op
Stored operator.
Definition matheval.hpp:199
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:201
std::function< real_t(real_t)> op_t
Signature of a unary operator: op(x)
Definition matheval.hpp:177