From 5ebc630e250932cccf386e914d38f2b2a3c4476d Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Sun, 9 Feb 2014 20:20:15 +1100 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 1388 ++++++++++++++++++++++++++++------------------- exprtk_test.cpp | 78 ++- readme.txt | 211 +++++-- 3 files changed, 1065 insertions(+), 612 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index c0bcb1f..28cd5f9 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -815,7 +815,7 @@ namespace exprtk return erfc_impl(static_cast(v),real_type_tag()); } - template inline T abs_impl(const T v, real_type_tag) { return std::abs (v); } + template inline T abs_impl(const T v, real_type_tag) { return ((v >= T(0)) ? v : -v); } template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } @@ -848,7 +848,7 @@ namespace exprtk template inline T frac_impl(const T v, real_type_tag) { return (v - static_cast(v)); } template inline T trunc_impl(const T v, real_type_tag) { return T(static_cast(v)); } - template inline T abs_impl(const T v, int_type_tag) { return std::abs (v); } + template inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } template inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } template inline T log_impl(const T v, int_type_tag) { return std::log (v); } template inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } @@ -1331,8 +1331,8 @@ namespace exprtk } if ( - (exp < numeric::numeric_info::min_exp) || - (numeric::numeric_info::max_exp < exp) + (exp < numeric::numeric_info::min_exp) || + (numeric::numeric_info::max_exp < exp) ) return false; exponent += exp; @@ -2522,7 +2522,17 @@ namespace exprtk bool result() { - return state_ && stack_.empty(); + if (!stack_.empty()) + { + lexer::token t; + t.value = stack_.top().first; + t.position = stack_.top().second; + error_token_ = t; + state_ = false; + return false; + } + else + return state_; } lexer::token error_token() @@ -2533,7 +2543,7 @@ namespace exprtk void reset() { //why? because msvc doesn't support swap properly. - stack_ = std::stack(); + stack_ = std::stack >(); state_ = true; error_token_.clear(); } @@ -2547,9 +2557,9 @@ namespace exprtk ) { char c = t.value[0]; - if (t.type == lexer::token::e_lbracket) stack_.push(')'); - else if (t.type == lexer::token::e_lcrlbracket) stack_.push('}'); - else if (t.type == lexer::token::e_lsqrbracket) stack_.push(']'); + if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position)); + else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); + else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); else if (exprtk::details::is_right_bracket(c)) { if (stack_.empty()) @@ -2558,7 +2568,7 @@ namespace exprtk error_token_ = t; return false; } - else if (c != stack_.top()) + else if (c != stack_.top().first) { state_ = false; error_token_ = t; @@ -2575,7 +2585,7 @@ namespace exprtk private: bool state_; - std::stack stack_; + std::stack > stack_; lexer::token error_token_; }; @@ -3063,7 +3073,8 @@ namespace exprtk e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, - e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043 + e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, + e_sf4ext44 = 2044, e_sf4ext45 = 2045 }; struct base_operation_t @@ -3798,7 +3809,7 @@ namespace exprtk case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) return arg1; else - return ((T(2.0) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); + return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); default : return std::numeric_limits::quiet_NaN(); } } @@ -4640,11 +4651,13 @@ namespace exprtk template struct sfext36_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) / (z - w); } static inline std::string id() { return "(t*t)/(t-t)";} }; template struct sfext37_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) / (z - w); } static inline std::string id() { return "(t/t)/(t-t)";} }; template struct sfext38_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) * (z - w); } static inline std::string id() { return "(t*t)*(t-t)";} }; - template struct sfext39_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) * (z - w); } static inline std::string id() { return "(t/t)*(t-t)";} }; - template struct sfext40_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y * (z / w)); } static inline std::string id() { return "t+(t*(t/t))";} }; - template struct sfext41_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y * (z / w)); } static inline std::string id() { return "t-(t*(t/t))";} }; - template struct sfext42_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y / (z * w)); } static inline std::string id() { return "t+(t/(t*t))";} }; - template struct sfext43_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y / (z * w)); } static inline std::string id() { return "t-(t/(t*t))";} }; + template struct sfext39_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) / (z * w); } static inline std::string id() { return "(t*t)/(t*t)";} }; + template struct sfext40_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x / y) * (z - w); } static inline std::string id() { return "(t/t)*(t-t)";} }; + template struct sfext41_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return (x * y) * (z * w); } static inline std::string id() { return "(t*t)*(t*t)";} }; + template struct sfext42_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y * (z / w)); } static inline std::string id() { return "t+(t*(t/t))";} }; + template struct sfext43_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y * (z / w)); } static inline std::string id() { return "t-(t*(t/t))";} }; + template struct sfext44_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y / (z * w)); } static inline std::string id() { return "t+(t/(t*t))";} }; + template struct sfext45_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y / (z * w)); } static inline std::string id() { return "t-(t/(t*t))";} }; template class sf3_node : public trinary_node @@ -6287,6 +6300,8 @@ namespace exprtk virtual const T c() const = 0; virtual void set_c(const T) = 0; + + virtual expression_node* move_branch(const std::size_t& index) = 0; }; template @@ -6345,8 +6360,6 @@ namespace exprtk public: virtual std::string type_id() const = 0; - - virtual std::string type_id2() const { return ""; } }; template @@ -7140,30 +7153,6 @@ namespace exprtk return id(); } - std::string type_id2() const - { - std::string t[] = { - param_to_str::result>::result(), - param_to_str::result>::result(), - param_to_str::result>::result() - }; - - std::string sf3id = id(); - - for (std::size_t i = 0; i < 3; ++i) - { - std::size_t index = std::string::npos; - if (std::string::npos != (index = sf3id.find("t"))) - { - sf3id[index] = t[i][0]; - } - else - break; - } - - return sf3id; - } - static inline std::string id() { return SF3Operation::id(); @@ -7701,6 +7690,12 @@ namespace exprtk return branch_[0].first; } + inline expression_node* move_branch(const std::size_t&) + { + branch_[0].second = false; + return branch_[0].first; + } + private: cob_node(const cob_node&); @@ -10141,13 +10136,14 @@ namespace exprtk enum precompilation_step { - e_unknown = 0, - e_replacer = 1, - e_joiner = 2, - e_numeric_check = 4, - e_bracket_check = 8, - e_sequence_check = 16, - e_commutative_check = 32 + e_unknown = 0, + e_replacer = 1, + e_joiner = 2, + e_numeric_check = 4, + e_bracket_check = 8, + e_sequence_check = 16, + e_commutative_check = 32, + e_strength_reduction = 64 }; struct unknown_symbol_resolver @@ -10171,16 +10167,17 @@ namespace exprtk } }; - static const std::size_t precompile_all_opts = e_replacer + - e_joiner + - e_numeric_check + - e_bracket_check + - e_sequence_check + - e_commutative_check; + static const std::size_t compile_all_opts = e_replacer + + e_joiner + + e_numeric_check + + e_bracket_check + + e_sequence_check + + e_commutative_check + + e_strength_reduction; - parser(const std::size_t precompile_options = precompile_all_opts) + parser(const std::size_t compile_options = compile_all_opts) : symbol_name_caching_(false), - precompile_options_(precompile_options), + compile_options_(compile_options), resolve_unknown_symbol_(false), unknown_symbol_resolver_(reinterpret_cast(0)), operator_joiner_2_(2), @@ -10199,6 +10196,7 @@ namespace exprtk expression_generator_.set_ibom(inv_binary_op_map_); expression_generator_.set_sf3m(sf3_map_); expression_generator_.set_sf4m(sf4_map_); + expression_generator_.set_strength_reduction_state(strength_reduction_enabled()); } inline void init_precompilation() @@ -10347,32 +10345,37 @@ namespace exprtk inline bool replacer_enabled() const { - return ((precompile_options_ & e_replacer) == e_replacer); + return ((compile_options_ & e_replacer) == e_replacer); } inline bool commutative_check_enabled() const { - return ((precompile_options_ & e_commutative_check) == e_commutative_check); + return ((compile_options_ & e_commutative_check) == e_commutative_check); } inline bool joiner_enabled() const { - return ((precompile_options_ & e_joiner) == e_joiner); + return ((compile_options_ & e_joiner) == e_joiner); } inline bool numeric_check_enabled() const { - return ((precompile_options_ & e_numeric_check) == e_numeric_check); + return ((compile_options_ & e_numeric_check) == e_numeric_check); } inline bool bracket_check_enabled() const { - return ((precompile_options_ & e_bracket_check) == e_bracket_check); + return ((compile_options_ & e_bracket_check) == e_bracket_check); } inline bool sequence_check_enabled() const { - return ((precompile_options_ & e_sequence_check) == e_sequence_check); + return ((compile_options_ & e_sequence_check) == e_sequence_check); + } + + inline bool strength_reduction_enabled() const + { + return ((compile_options_ & e_strength_reduction) == e_strength_reduction); } inline bool run_assemblies() @@ -10411,7 +10414,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, bracket_checker_ptr->error_token(), - "ERR04 - Mismatched brackets: " + bracket_checker_ptr->error_token().value)); + "ERR04 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'")); } else if (0 != (numeric_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) { @@ -10421,7 +10424,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, error_token, - "ERR05 - Invalid numeric token: " + error_token.value)); + "ERR05 - Invalid numeric token: '" + error_token.value + "'")); } } else if (0 != (sequence_validator_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) @@ -11510,7 +11513,7 @@ namespace exprtk { if (expression_list.empty()) return error_node(); - if (1 == expression_list.size()) + else if (1 == expression_list.size()) return expression_list[0]; Sequence tmp_expression_list; @@ -12471,6 +12474,16 @@ namespace exprtk node_allocator_ = &na; } + inline void set_strength_reduction_state(const bool strength_reduction_enabled) + { + strength_reduction_enabled_ = strength_reduction_enabled; + } + + inline bool strength_reduction_enabled() const + { + return strength_reduction_enabled_; + } + inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) { typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); @@ -13737,6 +13750,11 @@ namespace exprtk const unsigned int p = static_cast(std::abs(c)); if (0 == p) return node_allocator_->allocate_c(T(1)); + else if (T(2) == c) + { + return node_allocator_-> + template allocate_rr > >(v,v); + } else { if (not_recipricol) @@ -13879,6 +13897,56 @@ namespace exprtk return cobnode; } } + + if (operation == details::e_mul) + { + details::cob_base_node* cobnode = dynamic_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + switch (cob_opr) + { + case details::e_div : cobnode->set_c(c * cobnode->c()); break; + case details::e_mul : cobnode->set_c(cobnode->c() / c); break; + default : return error_node(); + } + return cobnode; + } + } + else if (operation == details::e_div) + { + details::cob_base_node* cobnode = dynamic_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + details::expression_node* new_cobnode = error_node(); + switch (cob_opr) + { + case details::e_div : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(),cobnode->move_branch(0)); + break; + + case details::e_mul : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(),cobnode->move_branch(0)); + break; + + default : return error_node(); + } + + free_node(*expr_gen.node_allocator_,branch[1]); + return new_cobnode; + } + } } else if (details::is_sf3ext_node(branch[1])) { @@ -13894,7 +13962,7 @@ namespace exprtk { #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ - template allocate_rc > > \ + template allocate_tt > > \ (c,branch[1]); \ basic_opr_switch_statements @@ -13935,6 +14003,25 @@ namespace exprtk return bocnode; } } + else if (operation == details::e_div) + { + details::boc_base_node* bocnode = dynamic_cast*>(branch[0]); + details::operator_type boc_opr = bocnode->operation(); + + if ( + (details::e_div == boc_opr) || + (details::e_mul == boc_opr) + ) + { + switch (boc_opr) + { + case details::e_div : bocnode->set_c(c * bocnode->c()); break; + case details::e_mul : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + return bocnode; + } + } } if (details::is_sf3ext_node(branch[0])) @@ -14037,7 +14124,10 @@ namespace exprtk if (expr_gen.cardinal_pow_optimizable(operation,c)) { - return expr_gen.cardinal_pow_optimization(v,c); + if (T(1) == c) + return branch[0]; + else + return expr_gen.cardinal_pow_optimization(v,c); } switch (operation) @@ -14157,6 +14247,7 @@ namespace exprtk case_stmt(details::e_sf4ext38,details::sfext38_op) case_stmt(details::e_sf4ext39,details::sfext39_op) case_stmt(details::e_sf4ext40,details::sfext40_op) case_stmt(details::e_sf4ext41,details::sfext41_op) case_stmt(details::e_sf4ext42,details::sfext42_op) case_stmt(details::e_sf4ext43,details::sfext43_op) + case_stmt(details::e_sf4ext44,details::sfext44_op) case_stmt(details::e_sf4ext45,details::sfext45_op) #undef case_stmt default : return error_node(); } @@ -14307,15 +14398,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[0]); expression_node_ptr result = error_node(); - // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",v0,v1,v2,result); - return (synthesis_result) ? result : error_node(); + // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",v0,v1,v2,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14352,15 +14447,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",v0,v2,v1,result); - return (synthesis_result) ? result : error_node(); + // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",v0,v2,v1,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14398,15 +14497,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",v0,v1,c,result); - return (synthesis_result) ? result : error_node(); + // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",v0,v1,c,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14443,15 +14546,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",v0,c,v1,result); - return (synthesis_result) ? result : error_node(); + // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",v0,c,v1,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14488,15 +14595,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[0]); expression_node_ptr result = error_node(); - // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",v0,v1,c,result); - return (synthesis_result) ? result : error_node(); + // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",v0,v1,c,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14533,15 +14644,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // v0 / (c / v1) --> (vovoc) (v0 * v1) / c - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",v0,v1,c,result); - return (synthesis_result) ? result : error_node(); + // v0 / (c / v1) --> (vovoc) (v0 * v1) / c + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",v0,v1,c,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14578,15 +14693,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[0]); expression_node_ptr result = error_node(); - // (c / v0) / v1 --> (covov) c / (v0 * v1) - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",c,v0,v1,result); - return (synthesis_result) ? result : error_node(); + // (c / v0) / v1 --> (covov) c / (v0 * v1) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",c,v0,v1,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14624,15 +14743,19 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // c / (v0 / v1) --> (covov) (c * v1) / v0 - if ((details::e_div == o0) && (details::e_div == o1)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",c,v1,v0,result); - return (synthesis_result) ? result : error_node(); + // c / (v0 / v1) --> (covov) (c * v1) / v0 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",c,v1,v0,result); + return (synthesis_result) ? result : error_node(); + } } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14669,55 +14792,59 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (c0 + v) + c1 --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) + if (expr_gen.strength_reduction_enabled()) { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); + // (c0 + v) + c1 --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0 + v) - c1 --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0 - v) + c1 --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0 - v) - c1 --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0 * v) * c1 --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0 * v) / c1 --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0 / v) * c1 --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0 / v) / c1 --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } } - // (c0 + v) - c1 --> (cov) (c0 - c1) + v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0 - v) + c1 --> (cov) (c0 + c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0 - v) - c1 --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0 * v) * c1 --> (cov) (c0 * c1) * v - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0 * v) / c1 --> (cov) (c0 / c1) * v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0 / v) * c1 --> (cov) (c0 * c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0 / v) / c1 --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14755,55 +14882,59 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (c0) + (v + c1) --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) + if (expr_gen.strength_reduction_enabled()) { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); + // (c0) + (v + c1) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) + (v - c1) --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) - (v + c1) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) - (v - c1) --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) * (v * c1) --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0) * (v / c1) --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0) / (v * c1) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0) / (v / c1) --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } } - // (c0) + (v - c1) --> (cov) (c0 - c1) + v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) - (v + c1) --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) - (v - c1) --> (cov) (c0 + c1) - v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0) * (v * c1) --> (voc) v * (c0 * c1) - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0) * (v / c1) --> (cov) (c0 / c1) * v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0) / (v * c1) --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0) / (v / c1) --> (cov) (c0 * c1) / v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14851,55 +14982,59 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (c0) + (c1 + v) --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) + if (expr_gen.strength_reduction_enabled()) { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); + // (c0) + (c1 + v) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) + (c1 - v) --> (cov) (c0 + c1) - v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) - (c1 + v) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) - (c1 - v) --> (cov) (c0 - c1) + v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) * (c1 * v) --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0) * (c1 / v) --> (cov) (c0 * c1) / v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0) / (c1 * v) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0) / (c1 / v) --> (cov) (c0 / c1) * v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } } - // (c0) + (c1 - v) --> (cov) (c0 + c1) - v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0) - (c1 + v) --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) - (c1 - v) --> (cov) (c0 - c1) + v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) * (c1 * v) --> (cov) (c0 * c1) * v - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0) * (c1 / v) --> (cov) (c0 * c1) / v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0) / (c1 * v) --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0) / (c1 / v) --> (cov) (c0 / c1) * v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -14936,55 +15071,59 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (v + c0) + c1 --> (voc) v + (c0 + c1) - if ((details::e_add == o0) && (details::e_add == o1)) + if (expr_gen.strength_reduction_enabled()) { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 + c1); + // (v + c0) + c1 --> (voc) v + (c0 + c1) + if ((details::e_add == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 + c1); + } + // (v + c0) - c1 --> (voc) v + (c0 - c1) + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 - c1); + } + // (v - c0) + c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c1 - c0); + } + // (v - c0) - c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 + c1); + } + // (v * c0) * c1 --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 * c1); + } + // (v * c0) / c1 --> (voc) v * (c0 / c1) + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 / c1); + } + // (v / c0) * c1 --> (voc) v * (c1 / c0) + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c1 / c0); + } + // (v / c0) / c1 --> (voc) v / (c0 * c1) + else if ((details::e_div == o0) && (details::e_div == o1)) + { + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 * c1); + } } - // (v + c0) - c1 --> (voc) v + (c0 - c1) - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 - c1); - } - // (v - c0) + c1 --> (voc) v - (c0 + c1) - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c1 - c0); - } - // (v - c0) - c1 --> (voc) v - (c0 + c1) - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 + c1); - } - // (v * c0) * c1 --> (voc) v * (c0 * c1) - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 * c1); - } - // (v * c0) / c1 --> (voc) v * (c0 / c1) - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 / c1); - } - // (v / c0) * c1 --> (voc) v * (c1 / c0) - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c1 / c0); - } - // (v / c0) / c1 --> (voc) v / (c0 * c1) - else if ((details::e_div == o0) && (details::e_div == o1)) - { - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 * c1); - } - else if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result)) + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -15040,6 +15179,27 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[0]); details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); + + if (expr_gen.strength_reduction_enabled()) + { + // (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v2,v1,v3,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v3,v1,v2,result); + return (synthesis_result) ? result : error_node(); + } + } + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) @@ -15275,71 +15435,94 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); + // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t-t)+t",(c0 - c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t*t)",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && + ((details::e_add == o1) || (details::e_sub == o1)) + ) + { + std::string specfunc; + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + return (synthesis_result) ? result : error_node(); + } } - // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t-t)+t",(c0 - c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t*t)",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - else if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -15387,71 +15570,94 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); + // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c1 - c0),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",Type(1) / (c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t/t)",(c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && + ((details::e_add == o1) || (details::e_sub == o1)) + ) + { + std::string specfunc; + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + return (synthesis_result) ? result : error_node(); + } } - // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c1 - c0),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",Type(1) / (c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t/t)",(c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - else if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -15499,71 +15705,94 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); + // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t-(t+t)",(c0 + c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t/t)",(c0 / c1),v1,v0,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && + ((details::e_add == o1) || (details::e_sub == o1)) + ) + { + std::string specfunc; + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + return (synthesis_result) ? result : error_node(); + } } - // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t-(t+t)",(c0 + c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t/t)",(c0 / c1),v1,v0,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - else if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -15611,71 +15840,94 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[1]); expression_node_ptr result = error_node(); - // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + if (expr_gen.strength_reduction_enabled()) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); + // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",v0,v1,(c1 + c0),result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 / c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result); + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && + ((details::e_add == o1) || (details::e_sub == o1)) + ) + { + std::string specfunc; + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + return (synthesis_result) ? result : error_node(); + } } - // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",v0,v1,(c1 + c0),result); - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 / c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result); - return (synthesis_result) ? result : error_node(); - } - else if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -17710,6 +17962,7 @@ namespace exprtk return expression_point; } + bool strength_reduction_enabled_; details::node_allocator* node_allocator_; synthesize_map_t synthesize_map_; unary_op_map_t* unary_op_map_; @@ -17879,6 +18132,7 @@ namespace exprtk register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) + register_sf4ext(44) register_sf4ext(45) #undef register_sf4ext } @@ -17894,7 +18148,7 @@ namespace exprtk details::node_allocator node_allocator_; symbol_table symbol_table_; bool symbol_name_caching_; - std::size_t precompile_options_; + std::size_t compile_options_; std::deque symbol_name_cache_; std::deque error_list_; bool resolve_unknown_symbol_; diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 3bd22af..6c7ebbe 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -1384,6 +1384,42 @@ inline bool run_test01() test_xy("((x / 2) * (3 / y))",T(7.0),T(9.0),T(((7.0 / 2.0) * (3.0 / 9.0)))), test_xy("((x * 2) / (3 / y))",T(7.0),T(9.0),T(((7.0 * 2.0) / (3.0 / 9.0)))), test_xy("((x / 2) / (3 * y))",T(7.0),T(9.0),T(((7.0 / 2.0) / (3.0 * 9.0)))), + test_xy("([(min(x,8) + y) + 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) - 4.0))), + test_xy("([(min(x,8) + y) + 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) + 4.0))), + test_xy("([(min(x,8) + y) + 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) * 4.0))), + test_xy("([(min(x,8) + y) + 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) + 3.0) / 4.0))), + test_xy("([(min(x,8) + y) - 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) - 4.0))), + test_xy("([(min(x,8) + y) - 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) + 4.0))), + test_xy("([(min(x,8) + y) - 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) * 4.0))), + test_xy("([(min(x,8) + y) - 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) - 3.0) / 4.0))), + test_xy("([(min(x,8) + y) * 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) - 4.0))), + test_xy("([(min(x,8) + y) * 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) + 4.0))), + test_xy("([(min(x,8) + y) * 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) * 4.0))), + test_xy("([(min(x,8) + y) * 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) * 3.0) / 4.0))), + test_xy("([(min(x,8) + y) / 3] - 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) - 4.0))), + test_xy("([(min(x,8) + y) / 3] + 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) + 4.0))), + test_xy("([(min(x,8) + y) / 3] * 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) * 4.0))), + test_xy("([(min(x,8) + y) / 3] / 4)",T(7.0),T(9.0),T((((std::min(7.0,8.0) + 9.0) / 3.0) / 4.0))), + test_xy("(4 - [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 + (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 + [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 + (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 * [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 + (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 / [3 + (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 + (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 - [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 - (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 + [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 - (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 * [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 - (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 / [3 - (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 - (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 - [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 * (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 + [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 * (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 * [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 * (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 / [3 * (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 * (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 - [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 - (3.0 / (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 + [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 + (3.0 / (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 * [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 * (3.0 / (std::min(7.0,8.0) + 9.0))))), + test_xy("(4 / [3 / (min(x,8) + y)])",T(7.0),T(9.0),T((4.0 / (3.0 / (std::min(7.0,8.0) + 9.0))))), + test_xy("((2 * x) + (2 * y))",T(7.0),T(9.0),T(((2.0 * 7.0) + (2.0 * 9.0)))), + test_xy("((2 * x) - (2 * y))",T(7.0),T(9.0),T(((2.0 * 7.0) - (2.0 * 9.0)))), + test_xy("((2 * x) + (y * 2))",T(7.0),T(9.0),T(((2.0 * 7.0) + (9.0 * 2.0)))), + test_xy("((x * 2) - (y * 2))",T(7.0),T(9.0),T(((7.0 * 2.0) - (9.0 * 2.0)))), test_xy("0 * (abs (x) + acos (y) + asin (x) + atan (y))",T(1.0),T(1.0),T(0.0)), test_xy("0 * (ceil (x) + cos (y) + cosh (x) + exp (y))",T(1.0),T(1.0),T(0.0)), test_xy("0 * (floor(x) + log (y) + log10(x) + round(y))",T(1.0),T(1.0),T(0.0)), @@ -1468,7 +1504,39 @@ inline bool run_test01() test_xyz("( x / (y / z))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (9.0 / 3.0)))), test_xyz("( x / (y / 2))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (9.0 / 2.0)))), test_xyz("( x / (2 / y))",T(7.0),T(9.0),T(3.0),T(( 7.0 / (2.0 / 9.0)))), - test_xyz("( 2 / (x / y))",T(7.0),T(9.0),T(3.0),T(( 2.0 / (7.0 / 9.0)))) + test_xyz("( 2 / (x / y))",T(7.0),T(9.0),T(3.0),T(( 2.0 / (7.0 / 9.0)))), + test_xyz("([(min(x,y) + z) + 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) - 4.0))), + test_xyz("([(min(x,y) + z) + 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) + 4.0))), + test_xyz("([(min(x,y) + z) + 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) * 4.0))), + test_xyz("([(min(x,y) + z) + 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) + 3.0) / 4.0))), + test_xyz("([(min(x,y) + z) - 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) - 4.0))), + test_xyz("([(min(x,y) + z) - 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) + 4.0))), + test_xyz("([(min(x,y) + z) - 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) * 4.0))), + test_xyz("([(min(x,y) + z) - 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) - 3.0) / 4.0))), + test_xyz("([(min(x,y) + z) * 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) - 4.0))), + test_xyz("([(min(x,y) + z) * 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) + 4.0))), + test_xyz("([(min(x,y) + z) * 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) * 4.0))), + test_xyz("([(min(x,y) + z) * 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) * 3.0) / 4.0))), + test_xyz("([(min(x,y) + z) / 3] - 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) - 4.0))), + test_xyz("([(min(x,y) + z) / 3] + 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) + 4.0))), + test_xyz("([(min(x,y) + z) / 3] * 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) * 4.0))), + test_xyz("([(min(x,y) + z) / 3] / 4)",T(5.0),T(7.0),T(9.0),T((((std::min(5.0,7.0) + 9.0) / 3.0) / 4.0))), + test_xyz("(4 - [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 + (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 + [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 + (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 * [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 + (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 / [3 + (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 + (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 - [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 - (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 + [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 - (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 * [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 - (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 / [3 - (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 - (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 - [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 * (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 + [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 * (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 * [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 * (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 / [3 * (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 * (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 - [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 - (3.0 / (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 + [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 + (3.0 / (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 * [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 * (3.0 / (std::min(5.0,7.0) + 9.0))))), + test_xyz("(4 / [3 / (min(x,y) + z)])",T(5.0),T(7.0),T(9.0),T((4.0 / (3.0 / (std::min(5.0,7.0) + 9.0))))), }; static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xyz); @@ -3854,6 +3922,12 @@ inline bool run_test19() // gof(x) = g(f(x)) compositor.add("gof","g(f(x))","x"); + // fogof(x) = f(g(f(x))) + compositor.add("fogof","f(g(f(x)))","x"); + + // gofog(x) = g(f(g(x))) + compositor.add("gofog","g(f(g(x)))","x"); + symbol_table_t& symbol_table = compositor.symbol_table(); symbol_table.add_constants(); symbol_table.add_variable("x",x); @@ -3866,6 +3940,8 @@ inline bool run_test19() "equal(gog(x),(x^4 - 6x^2 + 6))", "equal(fog(x),(x^2 - 1))", "equal(gof(x),(x^2 + 4x + 1))", + "equal(fogof(x),(x^2 + 4x + 3))", + "equal(gofog(x),(x^4 - 2x^2 - 2))" }; static const std::size_t expr_str_list_size = sizeof(expr_str_list) / sizeof(std::string); diff --git a/readme.txt b/readme.txt index 77a9fd5..f091246 100644 --- a/readme.txt +++ b/readme.txt @@ -49,26 +49,26 @@ operations, functions and processes: The following is a short listing of the types of mathematical expressions that can be parsed and evaluated using the ExprTk library. -(01) sqrt(1 - (x^2)) -(02) clamp(-1, sin(2 * pi * x) + cos(y / 2 * pi), +1) -(03) sin(2.34e-3 * x) -(04) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) -(05) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) -(06) ({1/1}*[1/2]+(1/3))-{1/4}^[1/5]+(1/6)-({1/7}+[1/8]*(1/9)) -(07) a * exp(2.2 / 3.3 * t) + c -(08) z := x + sin(2.567 * pi / y) -(09) u := 2.123 * (pi * z) / (w := x + cos(y / pi)) -(10) 2x + 3y + 4z + 5w == 2 * x + 3 * y + 4 * z + 5 * w -(11) 3(x + y) / 2.9 + 1.234e+12 == 3 * (x + y) / 2.9 + 1.234e+12 -(12) (x + y)3.3 + 1 / 4.5 == (x + y) * 3.3 + 1 / 4.5 -(13) (x + y)z + 1.1 / 2.7 == (x + y) * z + 1.1 / 2.7 -(14) (sin(x / pi) cos(2y) + 1) == (sin(x / pi) * cos(2 * y) + 1) -(15) 75x^17 + 25.1x^5 - 35x^4 - 15.2x^3 + 40x^2 - 15.3x + 1 -(16) if (avg(x,y) <= x + y, x - y, x * y) + 2.345 * pi / x -(17) fib_i := fib_i + (x := y + 0 * (fib_i := x + (y := fib_i))) -(18) while (x <= 100) { x := x + 1 } -(19) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z) -(20) (x like '*123*') or ('a123b' ilike y) + (01) sqrt(1 - (x^2)) + (02) clamp(-1, sin(2 * pi * x) + cos(y / 2 * pi), +1) + (03) sin(2.34e-3 * x) + (04) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) + (05) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) + (06) ({1/1}*[1/2]+(1/3))-{1/4}^[1/5]+(1/6)-({1/7}+[1/8]*(1/9)) + (07) a * exp(2.2 / 3.3 * t) + c + (08) z := x + sin(2.567 * pi / y) + (09) u := 2.123 * (pi * z) / (w := x + cos(y / pi)) + (10) 2x + 3y + 4z + 5w == 2 * x + 3 * y + 4 * z + 5 * w + (11) 3(x + y) / 2.9 + 1.234e+12 == 3 * (x + y) / 2.9 + 1.234e+12 + (12) (x + y)3.3 + 1 / 4.5 == (x + y) * 3.3 + 1 / 4.5 + (13) (x + y)z + 1.1 / 2.7 == (x + y) * z + 1.1 / 2.7 + (14) (sin(x / pi) cos(2y) + 1) == (sin(x / pi) * cos(2 * y) + 1) + (15) 75x^17 + 25.1x^5 - 35x^4 - 15.2x^3 + 40x^2 - 15.3x + 1 + (16) if (avg(x,y) <= x + y, x - y, x * y) + 2.345 * pi / x + (17) fib_i := fib_i + (x := y + 0 * (fib_i := x + (y := fib_i))) + (18) while (x <= 100) { x := x + 1 } + (19) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z) + (20) (x like '*123*') or ('a123b' ilike y) @@ -86,8 +86,8 @@ The most recent version of the C++ Mathematical Expression Toolkit Library including all updates and tests can be found at the following locations: - (1) http://www.partow.net/programming/exprtk/index.html - (2) svn checkout http://exprtk.googlecode.com/svn/ exprtk + (1) http://www.partow.net/programming/exprtk/index.html + (2) svn checkout http://exprtk.googlecode.com/svn/ exprtk @@ -98,20 +98,21 @@ include path (e.g: /usr/include/). [06 - COMPILATION] -(1) For a complete build: make clean all -(2) For a PGO build: make clean pgo -(3) To strip executables: make strip_bin + (1) For a complete build: make clean all + (2) For a PGO build: make clean pgo + (3) To strip executables: make strip_bin + (5) Execute valgrind check: make valgrind_check [07 - COMPILER COMPATIBILITY] -(*) GNU Compiler Collection (4.1+) -(*) Intel C++ Compiler (9.x+) -(*) Clang/LLVM (1.1+) -(*) PGI C++ (10.x+) -(*) Microsoft Visual Studio C++ Compiler (8.1+) -(*) Comeau C++ Compiler (4.3+) -(*) IBM XL C/C++ (10.x+) + (*) GNU Compiler Collection (4.1+) + (*) Intel C++ Compiler (9.x+) + (*) Clang/LLVM (1.1+) + (*) PGI C++ (10.x+) + (*) Microsoft Visual Studio C++ Compiler (8.1+) + (*) Comeau C++ Compiler (4.3+) + (*) IBM XL C/C++ (10.x+) @@ -424,7 +425,11 @@ follows: (1) Symbol Table A structure that is used to store references to variables, constants -and functions that are to be used within expressions. +and functions that are to be used within expressions. Furthermore in +the context of composited recursive functions the symbol table can +also be thought of as a simple representation of a stack specific for +the expression(s) that reference it. + (2) Expression A structure that holds an AST for a specified expression and is used @@ -459,6 +464,7 @@ Expression: z := (x + y^-2.345) * sin(pi / min(w - 7.3,v)) / \ Variable(w) Constant(7.3) + (3) Parser A structure which takes as input a string representation of an expression and attempts to compile said input with the result being an @@ -470,7 +476,118 @@ interface. -[10 - SPECIAL FUNCTIONS] +[10 - COMPILATION OPTIONS] +The exprtk::parser when being instantiated takes as input a set of +options to be used during the compilation process of expressions. +An example instantiation of exprtk::parser where only the joiner, +commutative and strength reduction options are enabled is as follows: + + const std::size_t compile_options = e_joiner + + e_commutative_check + + e_strength_reduction; + + exprtk::parser parser(compile_options); + + +Currently seven types of options are supported, and enabled by +default. The options and their explanations are as follows: + +(1) Replacer (e_replacer) +Enable replacement of specific tokens with other tokens. For example +the token "true" of type symbol will be replaced with the numeric +token of value one. + + (a) (x < y) == true ---> (x < y) == 1 + (b) false == (x > y) ---> 0 == (x > y) + + +(2) Joiner (e_joiner) +Enable joining of multi-character operators that may have been +incorrectly disjoint in the string representation of the specified +expression. For example the consecutive tokens of ">" "=" will become +">=" representing the "greater than or equal to" operator. If not +properly resolved the original form will cause a compilation error. +The following is a listing of the scenarios that the joiner can +handle: + + (a) ':' '=' ---> ':=' (assignment) + (b) '>' '=' ---> '>=' (gte) + (c) '<' '=' ---> '<=' (lte) + (d) '=' '=' ---> '==' (equal) + (e) '!' '=' ---> '!=' (not-equal) + (f) '<' '>' ---> '<>' (not-equal) + +An example of the transformation that takes place is as follows: + + (a) (x > = y) and (z ! = w) ---> (x >= y) and (z != w) + + +(3) Numeric Check (e_numeric_check) +Enable validation of tokens representing numeric types so as to catch +any errors prior to the costly process of the main compilation step +commencing. + + +(4) Bracket Check (e_bracket_check) +Enable the check for validating the ordering of brackets in the +specified expression. + + +(5) Sequence Check (e_sequence_check) +Enable the check for validating that sequences of either pairs or +triplets of tokens make sense. For example the following sequence of +tokens when encountered will raise an error: + + (a) (x + * 3) ---> sequence error + + +(6) Commutative Check (e_commutative_check) +Enable the check that will transform sequences of pairs of tokens that +imply a multiplication operation. The following are some examples of +such transformations: + + (a) 2x ---> 2 * x + (b) 25x^3 ---> 25 * x^3 + (c) 3(x + 1) ---> 3 * (x + 1) + (d) (x + 1)4 ---> (x + 1) * 4 + (e) 5foo(x,y) ---> 5 * foo(x,y) + (f) foo(x,y)6 + 1 ---> foo(x,y) * 6 + 1 + + +(7) Strength Reduction Check (e_strength_reduction) +Enable the use of strength reduction optimisations during the +compilation process. In ExprTk strength reduction optimisations +predominantly involve transforming sub-expressions into other forms +that are algebraically equivalent yet less costly to compute. The +following are examples of the various transformations that can occur: + + (a) (x / y) / z ---> x / (y * z) + (b) (x / y) / (z / w) ---> (x * w) / (y * z) + (c) (2 * x) - (2 * y) ---> 2 * (x - y) + (d) (2 / x) / (3 / y) ---> (2 / 3) / (x * y) + (e) (2 * x) * (3 * y) ---> (2 * 3) * (x * y) + +Note: +When using strength reduction in conjunction with expressions whose +inputs or sub-expressions may result in values nearing either of the +bounds of the underlying numeric type (eg: double), there may be the +possibility of a decrease in the precision of results. + +In the following example the given expression which represents an +attempt at computing the average between x and y will be transformed +as follows: + + (x * 0.5) + (y * 0.5) ---> 0.5 * (x + y) + +There may be situations where the above transformation will cause +numerical overflows and that the original form of the expression is +desired over the strength reduced form. In these situations it is best +to turn off strength reduction optimisations or to use a type with a +larger numerical bound. + + + +[11 - SPECIAL FUNCTIONS] The purpose of special functions in ExprTk is to provide compiler generated equivalents of common mathematical expressions which can be invoked by using the 'special function' syntax (eg: $f12(x,y,z) or @@ -537,11 +654,11 @@ correctly optimize such expressions for a given architecture. $f96(x,y,z,w) | (x > y) ? z : w $f97(x,y,z,w) | (x >= y) ? z : w $f98(x,y,z,w) | (x == y) ? z : w - $f99(x,y,z,w) | x * sin(y) + z * cos(w) + $f99(x,y,z,w) | x*sin(y)+z*cos(w) -[11 - EXPRTK NOTES] +[12 - EXPRTK NOTES] (00) Precision and performance of expression evaluations are the dominant principles of the ExprTk library. @@ -596,10 +713,9 @@ correctly optimize such expressions for a given architecture. (15) Where appropriate constant folding optimisations may be applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)') - (16) Where applicable strength reduction optimisations may be - applied. The following are example of such optimisations: - (a) '(x / y) / z' --> 'x / (y * z)' - (b) '(x / 3)' --> 'x * (1 / 3)' + (16) If the strength reduction compilation option has been enabled, + then where applicable strength reduction optimisations may be + applied. (17) String processing capabilities are available by default. To turn them off, the following needs to be defined at @@ -614,8 +730,7 @@ correctly optimize such expressions for a given architecture. (20) The entity relationship between symbol_table and an expression is one-to-many. Hence the intended use case is to have a single symbol table manage the variable and function requirements of - multiple expressions. An inappropriate approach would be to have - a unique symbol table for each unique expression. + multiple expressions. (21) The common use-case for an expression is to have it compiled only once and then subsequently have it evaluated multiple @@ -637,7 +752,7 @@ correctly optimize such expressions for a given architecture. -[12 - SIMPLE EXPRTK EXAMPLE] +[13 - SIMPLE EXPRTK EXAMPLE] --- snip --- #include #include @@ -684,12 +799,18 @@ int main() if (!parser.compile(expression_str,expression)) { + // A compilation error has occured. Attempt to + // print all errors to the stdout. + printf("Error: %s\tExpression: %s\n", parser.error().c_str(), expression_str.c_str()); for (std::size_t i = 0; i < parser.error_count(); ++i) { + // Include the specific nature of each error + // and its position in the expression string. + error_t error = parser.get_error(i); printf("Error: %02d Position: %02d " "Type: [%s] " @@ -705,6 +826,8 @@ int main() return 1; } + // Evaluate the expression and obtain its result. + double result = expression.value(); printf("Result: %10.5f\n",result); @@ -715,7 +838,7 @@ int main() -[13 - FILES] +[14 - FILES] (00) Makefile (01) readme.txt (02) exprtk.hpp