diff --git a/CHANGELOG.md b/CHANGELOG.md index d9504338f..dc6cf6827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ Version 1.4.x ------------- ## Version 1.4.2 (under development) +- Added portfolio engine which picks a good engine (among other settings) based on features of the symbolic input +- Setting `--engine dd-to-sparse --bisimulation` now triggers extracting the sparse bisimulation quotiont +- JIT model building is now invoked via `--engine jit` (instead of `--jit`) - DRN: support import of choice labelling - Added option `--build:buildchoiceorig` to build a model (PRISM or JANI) with choice origins (which are exported with, e.g. `--exportscheduler`). - Apply the maximum progress assumption while building a Markov automata with the Dd engine. diff --git a/resources/3rdparty/exprtk/exprtk.hpp b/resources/3rdparty/exprtk/exprtk.hpp old mode 100755 new mode 100644 index e8c156596..68afc0d46 --- a/resources/3rdparty/exprtk/exprtk.hpp +++ b/resources/3rdparty/exprtk/exprtk.hpp @@ -2,7 +2,7 @@ ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2017) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -66,10 +66,31 @@ namespace exprtk #define exprtk_debug(params) (void)0 #endif + #define exprtk_error_location \ + "exprtk.hpp:" + details::to_str(__LINE__) \ + + #if defined(__GNUC__) && (__GNUC__ >= 7) + + #define exprtk_disable_fallthrough_begin \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \ + + #define exprtk_disable_fallthrough_end \ + _Pragma ("GCC diagnostic pop") \ + + #else + #define exprtk_disable_fallthrough_begin (void)0; + #define exprtk_disable_fallthrough_end (void)0; + #endif + namespace details { - typedef unsigned char uchar_t; - typedef char char_t; + typedef unsigned char uchar_t; + typedef char char_t; + typedef uchar_t* uchar_ptr; + typedef char_t* char_ptr; + typedef uchar_t const* uchar_cptr; + typedef char_t const* char_cptr; inline bool is_whitespace(const char_t c) { @@ -143,13 +164,18 @@ namespace exprtk ('\'' != c); } + #ifndef exprtk_disable_caseinsensitivity + inline void case_normalise(std::string& s) + { + for (std::size_t i = 0; i < s.size(); ++i) + { + s[i] = static_cast<std::string::value_type>(std::tolower(s[i])); + } + } + inline bool imatch(const char_t c1, const char_t c2) { - #ifdef MODIFICATION - return c1 == c2; - #else return std::tolower(c1) == std::tolower(c2); - #endif } inline bool imatch(const std::string& s1, const std::string& s2) @@ -158,11 +184,7 @@ namespace exprtk { for (std::size_t i = 0; i < s1.size(); ++i) { - #ifdef MODIFICATION - if (s1[i] != s2[i]) - #else if (std::tolower(s1[i]) != std::tolower(s2[i])) - #endif { return false; } @@ -174,6 +196,50 @@ namespace exprtk return false; } + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + const std::size_t length = std::min(s1.size(),s2.size()); + + for (std::size_t i = 0; i < length; ++i) + { + const char_t c1 = static_cast<char>(std::tolower(s1[i])); + const char_t c2 = static_cast<char>(std::tolower(s2[i])); + + if (c1 > c2) + return false; + else if (c1 < c2) + return true; + } + + return s1.size() < s2.size(); + } + }; + + #else + inline void case_normalise(std::string&) + {} + + inline bool imatch(const char_t c1, const char_t c2) + { + return c1 == c2; + } + + inline bool imatch(const std::string& s1, const std::string& s2) + { + return s1 == s2; + } + + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + return s1 < s2; + } + }; + #endif + inline bool is_valid_sf_symbol(const std::string& symbol) { // Special function: $f12 or $F34 @@ -184,12 +250,12 @@ namespace exprtk is_digit(symbol[3]); } - inline const char& front(const std::string& s) + inline const char_t& front(const std::string& s) { return s[0]; } - inline const char& back(const std::string& s) + inline const char_t& back(const std::string& s) { return s[s.size() - 1]; } @@ -223,6 +289,11 @@ namespace exprtk return result; } + inline std::string to_str(std::size_t i) + { + return to_str(static_cast<int>(i)); + } + inline bool is_hex_digit(const std::string::value_type digit) { return (('0' <= digit) && (digit <= '9')) || @@ -255,7 +326,8 @@ namespace exprtk (is_hex_digit(*(itr + 3))) ) { - result = hex_to_bin(*(itr + 2)) << 4 | hex_to_bin(*(itr + 3)); + result = hex_to_bin(static_cast<uchar_t>(*(itr + 2))) << 4 | + hex_to_bin(static_cast<uchar_t>(*(itr + 3))) ; itr += 3; } else @@ -323,7 +395,7 @@ namespace exprtk return (*this); } - inline build_string& operator << (const char* s) + inline build_string& operator << (char_cptr s) { data_ += std::string(s); return (*this); @@ -344,32 +416,6 @@ namespace exprtk std::string data_; }; - struct ilesscompare - { - inline bool operator()(const std::string& s1, const std::string& s2) const - { - const std::size_t length = std::min(s1.size(),s2.size()); - - for (std::size_t i = 0; i < length; ++i) - { - #ifdef MODIFICATION - const char_t c1 = static_cast<char>(s1[i]); - const char_t c2 = static_cast<char>(s2[i]); - #else - const char_t c1 = static_cast<char>(std::tolower(s1[i])); - const char_t c2 = static_cast<char>(std::tolower(s2[i])); - #endif - - if (c1 > c2) - return false; - else if (c1 < c2) - return true; - } - - return s1.size() < s2.size(); - } - }; - static const std::string reserved_words[] = { "break", "case", "continue", "default", "false", "for", @@ -457,7 +503,7 @@ namespace exprtk { for (std::size_t i = 0; i < reserved_words_size; ++i) { - if (imatch(symbol,reserved_words[i])) + if (imatch(symbol, reserved_words[i])) { return true; } @@ -470,7 +516,7 @@ namespace exprtk { for (std::size_t i = 0; i < reserved_symbols_size; ++i) { - if (imatch(symbol,reserved_symbols[i])) + if (imatch(symbol, reserved_symbols[i])) { return true; } @@ -483,7 +529,7 @@ namespace exprtk { for (std::size_t i = 0; i < base_function_list_size; ++i) { - if (imatch(function_name,base_function_list[i])) + if (imatch(function_name, base_function_list[i])) { return true; } @@ -496,7 +542,7 @@ namespace exprtk { for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) { - if (imatch(cntrl_strct,cntrl_struct_list[i])) + if (imatch(cntrl_strct, cntrl_struct_list[i])) { return true; } @@ -509,7 +555,7 @@ namespace exprtk { for (std::size_t i = 0; i < logic_ops_list_size; ++i) { - if (imatch(lgc_opr,logic_ops_list[i])) + if (imatch(lgc_opr, logic_ops_list[i])) { return true; } @@ -522,11 +568,7 @@ namespace exprtk { static inline bool cmp(const char_t c0, const char_t c1) { - #ifdef MODIFICATION return (c0 == c1); - #else - return (std::tolower(c0) == std::tolower(c1)); - #endif } }; @@ -540,89 +582,92 @@ namespace exprtk template <typename Iterator, typename Compare> inline bool match_impl(const Iterator pattern_begin, - const Iterator pattern_end, - const Iterator data_begin, - const Iterator data_end, + const Iterator pattern_end , + const Iterator data_begin , + const Iterator data_end , const typename std::iterator_traits<Iterator>::value_type& zero_or_more, - const typename std::iterator_traits<Iterator>::value_type& zero_or_one) + const typename std::iterator_traits<Iterator>::value_type& zero_or_one ) { - if (0 == std::distance(data_begin,data_end)) - { - return false; - } + const Iterator null_itr(0); - Iterator d_itr = data_begin; - Iterator p_itr = pattern_begin; - Iterator c_itr = data_begin; - Iterator m_itr = data_begin; + Iterator d_itr = data_begin; + Iterator p_itr = pattern_begin; + Iterator tb_p_itr = null_itr; + Iterator tb_d_itr = null_itr; - while ((data_end != d_itr) && (zero_or_more != (*p_itr))) + while (d_itr != data_end) { - if ((!Compare::cmp((*p_itr),(*d_itr))) && (zero_or_one != (*p_itr))) + if (zero_or_more == *p_itr) { - return false; - } + while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) + { + ++p_itr; + } - ++p_itr; - ++d_itr; - } + if (pattern_end == p_itr) + return true; - while (data_end != d_itr) - { - if (zero_or_more == (*p_itr)) - { - if (pattern_end == (++p_itr)) + const typename std::iterator_traits<Iterator>::value_type c = *(p_itr); + + while ((data_end != d_itr) && !Compare::cmp(c,*d_itr)) { - return true; + ++d_itr; } - m_itr = p_itr; - c_itr = d_itr; - ++c_itr; - } - else if ((Compare::cmp((*p_itr),(*d_itr))) || (zero_or_one == (*p_itr))) - { - ++p_itr; - ++d_itr; + tb_p_itr = p_itr; + tb_d_itr = d_itr; + + continue; } - else + else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr)) { - p_itr = m_itr; - d_itr = c_itr++; + if (null_itr == tb_d_itr) + return false; + + d_itr = tb_d_itr++; + p_itr = tb_p_itr; + + continue; } + + ++p_itr; + ++d_itr; } - while ((p_itr != pattern_end) && (zero_or_more == (*p_itr))) { ++p_itr; } + while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) + { + ++p_itr; + } - return (p_itr == pattern_end); + return (pattern_end == p_itr); } inline bool wc_match(const std::string& wild_card, const std::string& str) { - return match_impl<const char*,cs_match>(wild_card.data(), - wild_card.data() + wild_card.size(), - str.data(), - str.data() + str.size(), - '*', - '?'); + return match_impl<char_cptr,cs_match>(wild_card.data(), + wild_card.data() + wild_card.size(), + str.data(), + str.data() + str.size(), + '*', + '?'); } inline bool wc_imatch(const std::string& wild_card, const std::string& str) { - return match_impl<const char*,cis_match>(wild_card.data(), - wild_card.data() + wild_card.size(), - str.data(), - str.data() + str.size(), - '*', - '?'); + return match_impl<char_cptr,cis_match>(wild_card.data(), + wild_card.data() + wild_card.size(), + str.data(), + str.data() + str.size(), + '*', + '?'); } inline bool sequence_match(const std::string& pattern, const std::string& str, std::size_t& diff_index, - char& diff_value) + char_t& diff_value) { if (str.empty()) { @@ -647,7 +692,7 @@ namespace exprtk if ('*' == target) { - diff_index = std::distance(str.begin(),s_itr); + diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr)); diff_value = static_cast<char>(std::toupper(*p_itr)); return false; @@ -670,7 +715,7 @@ namespace exprtk std::toupper(*p_itr) != std::toupper(*s_itr) ) { - diff_index = std::distance(str.begin(),s_itr); + diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr)); diff_value = static_cast<char>(std::toupper(*p_itr)); return false; @@ -697,7 +742,7 @@ namespace exprtk 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 }; - static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); + static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); namespace numeric { @@ -717,23 +762,29 @@ namespace exprtk namespace details { - struct unknown_type_tag {}; - struct real_type_tag {}; - struct complex_type_tag {}; - struct int_type_tag {}; + struct unknown_type_tag { unknown_type_tag() {} }; + struct real_type_tag { real_type_tag () {} }; + struct complex_type_tag { complex_type_tag() {} }; + struct int_type_tag { int_type_tag () {} }; template <typename T> - struct number_type { typedef unknown_type_tag type; }; + struct number_type + { + typedef unknown_type_tag type; + number_type() {} + }; - #define exprtk_register_real_type_tag(T) \ - template<> struct number_type<T> { typedef real_type_tag type; }; \ + #define exprtk_register_real_type_tag(T) \ + template<> struct number_type<T> \ + { typedef real_type_tag type; number_type() {} }; \ - #define exprtk_register_complex_type_tag(T) \ - template<> struct number_type<std::complex<T> > \ - { typedef complex_type_tag type; }; \ + #define exprtk_register_complex_type_tag(T) \ + template<> struct number_type<std::complex<T> > \ + { typedef complex_type_tag type; number_type() {} }; \ - #define exprtk_register_int_type_tag(T) \ - template<> struct number_type<T> { typedef int_type_tag type; }; \ + #define exprtk_register_int_type_tag(T) \ + template<> struct number_type<T> \ + { typedef int_type_tag type; number_type() {} }; \ exprtk_register_real_type_tag(double ) exprtk_register_real_type_tag(long double) @@ -953,7 +1004,15 @@ namespace exprtk template <typename T> inline T root_impl(const T v0, const T v1, real_type_tag) { - return std::pow(v0,T(1) / v1); + if (v1 < T(0)) + return std::numeric_limits<T>::quiet_NaN(); + + const std::size_t n = static_cast<std::size_t>(v1); + + if ((v0 < T(0)) && (0 == (n % 2))) + return std::numeric_limits<T>::quiet_NaN(); + + return std::pow(v0, T(1) / n); } template <typename T> @@ -1266,6 +1325,9 @@ namespace exprtk template <typename T> inline T frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); } template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v)); } + template <typename T> inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } + template <typename T> inline T const_e_impl (real_type_tag) { return T(numeric::constant::e); } + template <typename T> inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } template <typename T> inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } template <typename T> inline T log_impl(const T v, int_type_tag) { return std::log (v); } @@ -1320,162 +1382,162 @@ namespace exprtk template <typename T> inline int to_int32(const T v) { - typename details::number_type<T>::type num_type; - return to_int32_impl(v,num_type); + const typename details::number_type<T>::type num_type; + return to_int32_impl(v, num_type); } template <typename T> inline long long int to_int64(const T v) { - typename details::number_type<T>::type num_type; - return to_int64_impl(v,num_type); + const typename details::number_type<T>::type num_type; + return to_int64_impl(v, num_type); } template <typename T> inline bool is_nan(const T v) { - typename details::number_type<T>::type num_type; - return is_nan_impl(v,num_type); + const typename details::number_type<T>::type num_type; + return is_nan_impl(v, num_type); } template <typename T> inline T min(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return min_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return min_impl(v0, v1, num_type); } template <typename T> inline T max(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return max_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return max_impl(v0, v1, num_type); } template <typename T> inline T equal(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return equal_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return equal_impl(v0, v1, num_type); } template <typename T> inline T nequal(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return nequal_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return nequal_impl(v0, v1, num_type); } template <typename T> inline T modulus(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return modulus_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return modulus_impl(v0, v1, num_type); } template <typename T> inline T pow(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return pow_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return pow_impl(v0, v1, num_type); } template <typename T> inline T logn(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return logn_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return logn_impl(v0, v1, num_type); } template <typename T> inline T root(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return root_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return root_impl(v0, v1, num_type); } template <typename T> inline T roundn(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return roundn_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return roundn_impl(v0, v1, num_type); } template <typename T> inline T hypot(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return hypot_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return hypot_impl(v0, v1, num_type); } template <typename T> inline T atan2(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return atan2_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return atan2_impl(v0, v1, num_type); } template <typename T> inline T shr(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return shr_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return shr_impl(v0, v1, num_type); } template <typename T> inline T shl(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return shl_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return shl_impl(v0, v1, num_type); } template <typename T> inline T and_opr(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return and_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return and_impl(v0, v1, num_type); } template <typename T> inline T nand_opr(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return nand_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return nand_impl(v0, v1, num_type); } template <typename T> inline T or_opr(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return or_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return or_impl(v0, v1, num_type); } template <typename T> inline T nor_opr(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return nor_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return nor_impl(v0, v1, num_type); } template <typename T> inline T xor_opr(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return xor_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return xor_impl(v0, v1, num_type); } template <typename T> inline T xnor_opr(const T v0, const T v1) { - typename details::number_type<T>::type num_type; - return xnor_impl(v0,v1,num_type); + const typename details::number_type<T>::type num_type; + return xnor_impl(v0, v1, num_type); } template <typename T> inline bool is_integer(const T v) { - typename details::number_type<T>::type num_type; - return is_integer_impl(v,num_type); + const typename details::number_type<T>::type num_type; + return is_integer_impl(v, num_type); } template <typename T, unsigned int N> @@ -1514,13 +1576,13 @@ namespace exprtk template <typename T> struct fast_exp<T, 1> { static inline T result(T v) { return v; } }; template <typename T> struct fast_exp<T, 0> { static inline T result(T ) { return T(1); } }; - #define exprtk_define_unary_function(FunctionName) \ - template <typename T> \ - inline T FunctionName (const T v) \ - { \ - typename details::number_type<T>::type num_type; \ - return FunctionName##_impl(v,num_type); \ - } \ + #define exprtk_define_unary_function(FunctionName) \ + template <typename T> \ + inline T FunctionName (const T v) \ + { \ + const typename details::number_type<T>::type num_type; \ + return FunctionName##_impl(v,num_type); \ + } \ exprtk_define_unary_function(abs ) exprtk_define_unary_function(acos ) @@ -1633,7 +1695,7 @@ namespace exprtk if (itr == end) return false; - bool negative = ('-' == (*itr)); + const bool negative = ('-' == (*itr)); if (negative || ('+' == (*itr))) { @@ -1641,34 +1703,51 @@ namespace exprtk return false; } - while ((end != itr) && ('0' == (*itr))) ++itr; + static const uchar_t zero = static_cast<uchar_t>('0'); + + while ((end != itr) && (zero == (*itr))) ++itr; bool return_result = true; unsigned int digit = 0; - const std::size_t length = std::distance(itr,end); + const std::size_t length = static_cast<std::size_t>(std::distance(itr,end)); if (length <= 4) { + exprtk_disable_fallthrough_begin switch (length) { #ifdef exprtk_use_lut - #define exprtk_process_digit \ - if ((digit = details::digit_table[(int)*itr++]) < 10) result = result * 10 + (digit); else { return_result = false; break; } + #define exprtk_process_digit \ + if ((digit = details::digit_table[(int)*itr++]) < 10) \ + result = result * 10 + (digit); \ + else \ + { \ + return_result = false; \ + break; \ + } \ #else - #define exprtk_process_digit \ - if ((digit = (*itr++ - '0')) < 10) result = result * 10 + (digit); else { return_result = false; break; } + + #define exprtk_process_digit \ + if ((digit = (*itr++ - zero)) < 10) \ + result = result * T(10) + digit; \ + else \ + { \ + return_result = false; \ + break; \ + } \ #endif case 4 : exprtk_process_digit case 3 : exprtk_process_digit case 2 : exprtk_process_digit - case 1 : if ((digit = (*itr - '0'))>= 10) { digit = 0; return_result = false; } + case 1 : if ((digit = (*itr - zero))>= 10) { digit = 0; return_result = false; } #undef exprtk_process_digit } + exprtk_disable_fallthrough_end } else return_result = false; @@ -1723,12 +1802,12 @@ namespace exprtk static const char_t inf_lc[] = "infinity"; static const std::size_t inf_length = 8; - const std::size_t length = std::distance(itr,end); + const std::size_t length = static_cast<std::size_t>(std::distance(itr,end)); if ((3 != length) && (inf_length != length)) return false; - const char* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; while (end != itr) { @@ -1759,7 +1838,7 @@ namespace exprtk T d = T(0); - bool negative = ('-' == (*itr)); + const bool negative = ('-' == (*itr)); if (negative || '+' == (*itr)) { @@ -1769,23 +1848,27 @@ namespace exprtk bool instate = false; - #define parse_digit_1(d) \ - if ((digit = (*itr - '0')) < 10) \ - { d = d * T(10) + digit; } \ - else \ - { break; } \ - if (end == ++itr) break; \ + static const char_t zero = static_cast<uchar_t>('0'); - #define parse_digit_2(d) \ - if ((digit = (*itr - '0')) < 10) \ - { d = d * T(10) + digit; } \ - else { break; } \ - ++itr; \ + #define parse_digit_1(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else \ + { break; } \ + if (end == ++itr) break; \ + + #define parse_digit_2(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else { break; } \ + ++itr; \ if ('.' != (*itr)) { const Iterator curr = itr; - while ((end != itr) && ('0' == (*itr))) ++itr; + + while ((end != itr) && (zero == (*itr))) ++itr; + unsigned int digit; while (end != itr) @@ -1844,7 +1927,7 @@ namespace exprtk { int exp = 0; - if (!details::string_to_type_converter_impl_ref(++itr,end,exp)) + if (!details::string_to_type_converter_impl_ref(++itr, end, exp)) { if (end == itr) return false; @@ -1867,11 +1950,11 @@ namespace exprtk { if (('i' == (*itr)) || ('I' == (*itr))) { - return parse_inf(itr,end,t,negative); + return parse_inf(itr, end, t, negative); } else if (('n' == (*itr)) || ('N' == (*itr))) { - return parse_nan(itr,end,t); + return parse_nan(itr, end, t); } else return false; @@ -1883,11 +1966,11 @@ namespace exprtk { if (('i' == (*itr)) || ('I' == (*itr))) { - return parse_inf(itr,end,t,negative); + return parse_inf(itr, end, t, negative); } else if (('n' == (*itr)) || ('N' == (*itr))) { - return parse_nan(itr,end,t); + return parse_nan(itr, end, t); } else return false; @@ -1910,10 +1993,12 @@ namespace exprtk template <typename T> inline bool string_to_real(const std::string& s, T& t) { - const char* begin = s.data(); - const char* end = s.data() + s.size(); - typename numeric::details::number_type<T>::type num_type; - return string_to_real(begin,end,t,num_type); + const typename numeric::details::number_type<T>::type num_type; + + char_cptr begin = s.data(); + char_cptr end = s.data() + s.size(); + + return string_to_real(begin, end, t, num_type); } template <typename T> @@ -1972,13 +2057,15 @@ namespace exprtk } template <typename Iterator> - inline token& set_operator(const token_type tt, const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) + inline token& set_operator(const token_type tt, + const Iterator begin, const Iterator end, + const Iterator base_begin = Iterator(0)) { type = tt; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast<std::size_t>(std::distance(base_begin,begin)); + return (*this); } template <typename Iterator> @@ -1987,8 +2074,8 @@ namespace exprtk type = e_symbol; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast<std::size_t>(std::distance(base_begin,begin)); + return (*this); } template <typename Iterator> @@ -1997,8 +2084,8 @@ namespace exprtk type = e_number; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast<std::size_t>(std::distance(base_begin,begin)); + return (*this); } template <typename Iterator> @@ -2007,8 +2094,8 @@ namespace exprtk type = e_string; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast<std::size_t>(std::distance(base_begin,begin)); + return (*this); } inline token& set_string(const std::string& s, const std::size_t p) @@ -2016,11 +2103,13 @@ namespace exprtk type = e_string; value = s; position = p; - return *this; + return (*this); } template <typename Iterator> - inline token& set_error(const token_type et, const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) + inline token& set_error(const token_type et, + const Iterator begin, const Iterator end, + const Iterator base_begin = Iterator(0)) { if ( (e_error == et) || @@ -2038,9 +2127,9 @@ namespace exprtk value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); + position = static_cast<std::size_t>(std::distance(base_begin,begin)); - return *this; + return (*this); } static inline std::string to_str(token_type t) @@ -2146,9 +2235,7 @@ namespace exprtk { scan_token(); - if (token_list_.empty()) - return true; - else if (token_list_.back().is_error()) + if (!token_list_.empty() && token_list_.back().is_error()) return false; } @@ -2238,8 +2325,8 @@ namespace exprtk inline std::string substr(const std::size_t& begin, const std::size_t& end) { - const char* begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; - const char* end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; + const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; + const details::char_cptr end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; return std::string(begin_itr,end_itr); } @@ -2256,11 +2343,28 @@ namespace exprtk private: - inline bool is_end(const char* itr) + inline bool is_end(details::char_cptr itr) { return (s_end_ == itr); } + inline bool is_comment_start(details::char_cptr itr) + { + #ifndef exprtk_disable_comments + const char_t c0 = *(itr + 0); + const char_t c1 = *(itr + 1); + + if ('#' == c0) + return true; + else if (!is_end(itr + 1)) + { + if (('/' == c0) && ('/' == c1)) return true; + if (('/' == c0) && ('*' == c1)) return true; + } + #endif + return false; + } + inline void skip_whitespace() { while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) @@ -2290,47 +2394,72 @@ namespace exprtk return (0 != mode); } - static inline bool comment_end(const char_t c0, const char_t c1, const int mode) + static inline bool comment_end(const char_t c0, const char_t c1, int& mode) { - return ( - ((1 == mode) && ('\n' == c0)) || - ((2 == mode) && ( '*' == c0) && ('/' == c1)) - ); + if ( + ((1 == mode) && ('\n' == c0)) || + ((2 == mode) && ( '*' == c0) && ('/' == c1)) + ) + { + mode = 0; + return true; + } + else + return false; } }; int mode = 0; int increment = 0; - if (is_end(s_itr_) || is_end((s_itr_ + 1))) + if (is_end(s_itr_)) return; - else if (!test::comment_start(*s_itr_,*(s_itr_ + 1),mode,increment)) + else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment)) return; + details::char_cptr cmt_start = s_itr_; + s_itr_ += increment; - while (!is_end(s_itr_) && !test::comment_end(*s_itr_,*(s_itr_ + 1),mode)) + while (!is_end(s_itr_)) { - ++s_itr_; + if ((1 == mode) && test::comment_end(*s_itr_, 0, mode)) + { + ++s_itr_; + return; + } + + if ((2 == mode)) + { + if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode)) + { + s_itr_ += 2; + return; + } + } + + ++s_itr_; } - if (!is_end(s_itr_)) + if (2 == mode) { - s_itr_ += mode; - skip_whitespace(); - skip_comments(); + token_t t; + t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_); + token_list_.push_back(t); } #endif } inline void scan_token() { - skip_whitespace(); - - skip_comments(); - - if (is_end(s_itr_)) + if (details::is_whitespace(*s_itr_)) { + skip_whitespace(); + return; + } + else if (is_comment_start(s_itr_)) + { + skip_comments(); return; } else if (details::is_operator_char(*s_itr_)) @@ -2426,11 +2555,11 @@ namespace exprtk } if ('<' == c0) - t.set_operator(token_t::e_lt ,s_itr_, s_itr_ + 1, base_itr_); + t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_); else if ('>' == c0) - t.set_operator(token_t::e_gt ,s_itr_, s_itr_ + 1, base_itr_); + t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_); else if (';' == c0) - t.set_operator(token_t::e_eof,s_itr_, s_itr_ + 1, base_itr_); + t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_); else if ('&' == c0) t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); else if ('|' == c0) @@ -2444,7 +2573,7 @@ namespace exprtk inline void scan_symbol() { - const char* initial_itr = s_itr_; + details::char_cptr initial_itr = s_itr_; while (!is_end(s_itr_)) { @@ -2495,11 +2624,11 @@ namespace exprtk (15) .1234e-3 */ - const char* initial_itr = s_itr_; - bool dot_found = false; - bool e_found = false; - bool post_e_sign_found = false; - bool post_e_digit_found = false; + details::char_cptr initial_itr = s_itr_; + bool dot_found = false; + bool e_found = false; + bool post_e_sign_found = false; + bool post_e_digit_found = false; token_t t; while (!is_end(s_itr_)) @@ -2518,9 +2647,9 @@ namespace exprtk continue; } - else if (details::imatch('e',(*s_itr_))) + else if ('e' == std::tolower(*s_itr_)) { - const char& c = *(s_itr_ + 1); + const char_t& c = *(s_itr_ + 1); if (is_end(s_itr_ + 1)) { @@ -2582,7 +2711,7 @@ namespace exprtk inline void scan_special_function() { - const char* initial_itr = s_itr_; + details::char_cptr initial_itr = s_itr_; token_t t; // $fdd(x,x,x) = at least 11 chars @@ -2618,7 +2747,7 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities inline void scan_string() { - const char* initial_itr = s_itr_ + 1; + details::char_cptr initial_itr = s_itr_ + 1; token_t t; if (std::distance(s_itr_,s_end_) < 2) @@ -2656,7 +2785,7 @@ namespace exprtk Note: The following 'awkward' conditional is due to various broken msvc compilers. */ - #if _MSC_VER == 1600 + #if defined(_MSC_VER) && (_MSC_VER == 1600) const bool within_range = !is_end(s_itr_ + 2) && !is_end(s_itr_ + 3) ; #else @@ -2701,8 +2830,12 @@ namespace exprtk else { std::string parsed_string(initial_itr,s_itr_); + details::cleanup_escapes(parsed_string); - t.set_string(parsed_string, std::distance(base_itr_,initial_itr)); + + t.set_string( + parsed_string, + static_cast<std::size_t>(std::distance(base_itr_,initial_itr))); } token_list_.push_back(t); @@ -2718,9 +2851,9 @@ namespace exprtk token_list_itr_t token_itr_; token_list_itr_t store_token_itr_; token_t eof_token_; - const char* base_itr_; - const char* s_itr_; - const char* s_end_; + details::char_cptr base_itr_; + details::char_cptr s_itr_; + details::char_cptr s_end_; friend class token_scanner; friend class token_modifier; @@ -2781,7 +2914,7 @@ namespace exprtk const token& t0 = g.token_list_[i ]; const token& t1 = g.token_list_[i + 1]; - if (!operator()(t0,t1)) + if (!operator()(t0, t1)) { return i; } @@ -2794,7 +2927,7 @@ namespace exprtk const token& t1 = g.token_list_[i + 1]; const token& t2 = g.token_list_[i + 2]; - if (!operator()(t0,t1,t2)) + if (!operator()(t0, t1, t2)) { return i; } @@ -2808,7 +2941,7 @@ namespace exprtk const token& t2 = g.token_list_[i + 2]; const token& t3 = g.token_list_[i + 3]; - if (!operator()(t0,t1,t2,t3)) + if (!operator()(t0, t1, t2, t3)) { return i; } @@ -2821,29 +2954,29 @@ namespace exprtk return (g.token_list_.size() - stride_ + 1); } - virtual bool operator()(const token&) + virtual bool operator() (const token&) { return false; } - virtual bool operator()(const token&, const token&) + virtual bool operator() (const token&, const token&) { return false; } - virtual bool operator()(const token&, const token&, const token&) + virtual bool operator() (const token&, const token&, const token&) { return false; } - virtual bool operator()(const token&, const token&, const token&, const token&) + virtual bool operator() (const token&, const token&, const token&, const token&) { return false; } private: - std::size_t stride_; + const std::size_t stride_; }; class token_modifier : public helper_interface @@ -2910,9 +3043,13 @@ namespace exprtk break; } + typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t; + if ((insert_index >= 0) && (insert_index <= (static_cast<int>(stride_) + 1))) { - g.token_list_.insert(g.token_list_.begin() + (i + insert_index),t); + g.token_list_.insert( + g.token_list_.begin() + static_cast<diff_t>(i + static_cast<std::size_t>(insert_index)), t); + changes++; } } @@ -2944,14 +3081,14 @@ namespace exprtk private: - std::size_t stride_; + const std::size_t stride_; }; class token_joiner : public helper_interface { public: - token_joiner(const std::size_t& stride) + explicit token_joiner(const std::size_t& stride) : stride_(stride) {} @@ -2968,29 +3105,34 @@ namespace exprtk } } - virtual bool join(const token&, const token&, token&) { return false; } + virtual bool join(const token&, const token&, token&) { return false; } virtual bool join(const token&, const token&, const token&, token&) { return false; } private: inline std::size_t process_stride_2(generator& g) { + typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t; + if (g.token_list_.size() < 2) return 0; std::size_t changes = 0; - for (std::size_t i = 0; i < (g.token_list_.size() - 1); ++i) + for (int i = 0; i < static_cast<int>(g.token_list_.size() - 1); ++i) { token t; - while (join(g[i],g[i + 1],t)) + while (join(g[i], g[i + 1], t)) { g.token_list_[i] = t; - g.token_list_.erase(g.token_list_.begin() + (i + 1)); + g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1)); ++changes; + + if (static_cast<std::size_t>(i + 1) >= g.token_list_.size()) + break; } } @@ -2999,29 +3141,34 @@ namespace exprtk inline std::size_t process_stride_3(generator& g) { + typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t; + if (g.token_list_.size() < 3) return 0; std::size_t changes = 0; - for (std::size_t i = 0; i < (g.token_list_.size() - 2); ++i) + for (int i = 0; i < static_cast<int>(g.token_list_.size() - 2); ++i) { token t; - while (join(g[i],g[i + 1],g[i + 2],t)) + while (join(g[i], g[i + 1], g[i + 2], t)) { g.token_list_[i] = t; - g.token_list_.erase(g.token_list_.begin() + (i + 1), - g.token_list_.begin() + (i + 3)); + g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1), + g.token_list_.begin() + static_cast<diff_t>(i + 3)); ++changes; + + if (static_cast<std::size_t>(i + 2) >= g.token_list_.size()) + break; } } return changes; } - std::size_t stride_; + const std::size_t stride_; }; namespace helper @@ -3092,6 +3239,7 @@ namespace exprtk else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_symbol )) match = true; return (match) ? 1 : -1; } @@ -3105,7 +3253,7 @@ namespace exprtk { public: - operator_joiner(const std::size_t& stride) + explicit operator_joiner(const std::size_t& stride) : token_joiner(stride) {} @@ -3237,7 +3385,7 @@ namespace exprtk return true; } - // '- -' --> '-' + // '- -' --> '+' else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) { /* @@ -3314,7 +3462,7 @@ namespace exprtk error_token_.clear(); } - bool operator()(const lexer::token& t) + bool operator() (const lexer::token& t) { if ( !t.value.empty() && @@ -3325,7 +3473,7 @@ namespace exprtk { details::char_t c = t.value[0]; - if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position)); + 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)) @@ -3381,7 +3529,7 @@ namespace exprtk current_index_ = 0; } - bool operator()(const lexer::token& t) + bool operator() (const lexer::token& t) { if (token::e_number == t.type) { @@ -3432,7 +3580,7 @@ namespace exprtk bool remove(const std::string& target_symbol) { - replace_map_t::iterator itr = replace_map_.find(target_symbol); + const replace_map_t::iterator itr = replace_map_.find(target_symbol); if (replace_map_.end() == itr) return false; @@ -3446,7 +3594,7 @@ namespace exprtk const std::string& replace_symbol, const lexer::token::token_type token_type = lexer::token::e_symbol) { - replace_map_t::iterator itr = replace_map_.find(target_symbol); + const replace_map_t::iterator itr = replace_map_.find(target_symbol); if (replace_map_.end() != itr) { @@ -3472,7 +3620,7 @@ namespace exprtk if (replace_map_.empty()) return false; - replace_map_t::iterator itr = replace_map_.find(t.value); + const replace_map_t::iterator itr = replace_map_.find(t.value); if (replace_map_.end() != itr) { @@ -3503,11 +3651,11 @@ namespace exprtk sequence_validator() : lexer::token_scanner(2) { - add_invalid(lexer::token::e_number ,lexer::token::e_number ); - add_invalid(lexer::token::e_string ,lexer::token::e_string ); - add_invalid(lexer::token::e_number ,lexer::token::e_string ); - add_invalid(lexer::token::e_string ,lexer::token::e_number ); - add_invalid(lexer::token::e_string ,lexer::token::e_ternary); + add_invalid(lexer::token::e_number, lexer::token::e_number); + add_invalid(lexer::token::e_string, lexer::token::e_string); + add_invalid(lexer::token::e_number, lexer::token::e_string); + add_invalid(lexer::token::e_string, lexer::token::e_number); + add_invalid_set1(lexer::token::e_assign ); add_invalid_set1(lexer::token::e_shr ); add_invalid_set1(lexer::token::e_shl ); @@ -3533,9 +3681,9 @@ namespace exprtk return error_list_.empty(); } - bool operator()(const lexer::token& t0, const lexer::token& t1) + bool operator() (const lexer::token& t0, const lexer::token& t1) { - set_t::value_type p = std::make_pair(t0.type,t1.type); + const set_t::value_type p = std::make_pair(t0.type,t1.type); if (invalid_bracket_check(t0.type,t1.type)) { @@ -3549,7 +3697,7 @@ namespace exprtk return true; } - std::size_t error_count() + std::size_t error_count() const { return error_list_.size(); } @@ -3581,21 +3729,21 @@ namespace exprtk void add_invalid_set1(lexer::token::token_type t) { - add_invalid(t,lexer::token::e_assign); - add_invalid(t,lexer::token::e_shr ); - add_invalid(t,lexer::token::e_shl ); - add_invalid(t,lexer::token::e_lte ); - add_invalid(t,lexer::token::e_ne ); - add_invalid(t,lexer::token::e_gte ); - add_invalid(t,lexer::token::e_lt ); - add_invalid(t,lexer::token::e_gt ); - add_invalid(t,lexer::token::e_eq ); - add_invalid(t,lexer::token::e_comma ); - add_invalid(t,lexer::token::e_div ); - add_invalid(t,lexer::token::e_mul ); - add_invalid(t,lexer::token::e_mod ); - add_invalid(t,lexer::token::e_pow ); - add_invalid(t,lexer::token::e_colon ); + add_invalid(t, lexer::token::e_assign); + add_invalid(t, lexer::token::e_shr ); + add_invalid(t, lexer::token::e_shl ); + add_invalid(t, lexer::token::e_lte ); + add_invalid(t, lexer::token::e_ne ); + add_invalid(t, lexer::token::e_gte ); + add_invalid(t, lexer::token::e_lt ); + add_invalid(t, lexer::token::e_gt ); + add_invalid(t, lexer::token::e_eq ); + add_invalid(t, lexer::token::e_comma ); + add_invalid(t, lexer::token::e_div ); + add_invalid(t, lexer::token::e_mul ); + add_invalid(t, lexer::token::e_mod ); + add_invalid(t, lexer::token::e_pow ); + add_invalid(t, lexer::token::e_colon ); } bool invalid_bracket_check(lexer::token::token_type base, lexer::token::token_type t) @@ -3605,7 +3753,7 @@ namespace exprtk switch (t) { case lexer::token::e_assign : return (']' != base); - case lexer::token::e_string : return true; + case lexer::token::e_string : return (')' != base); default : return false; } } @@ -3626,7 +3774,7 @@ namespace exprtk case lexer::token::e_sub : return false; case lexer::token::e_colon : return false; case lexer::token::e_ternary : return false; - default : return true; + default : return true ; } } } @@ -3640,7 +3788,7 @@ namespace exprtk case lexer::token::e_eof : return false; case lexer::token::e_colon : return false; case lexer::token::e_ternary : return false; - default : return true; + default : return true ; } } else if (details::is_left_bracket(static_cast<char>(t))) @@ -3661,12 +3809,97 @@ namespace exprtk std::vector<std::pair<lexer::token,lexer::token> > error_list_; }; + class sequence_validator_3tokens : public lexer::token_scanner + { + private: + + typedef lexer::token::token_type token_t; + typedef std::pair<token_t,std::pair<token_t,token_t> > token_triplet_t; + typedef std::set<token_triplet_t> set_t; + + public: + + using lexer::token_scanner::operator(); + + sequence_validator_3tokens() + : lexer::token_scanner(3) + { + add_invalid(lexer::token::e_number, lexer::token::e_number, lexer::token::e_number); + add_invalid(lexer::token::e_string, lexer::token::e_string, lexer::token::e_string); + add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); + + add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); + + add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); + } + + bool result() + { + return error_list_.empty(); + } + + bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) + { + const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); + + if (invalid_comb_.find(p) != invalid_comb_.end()) + { + error_list_.push_back(std::make_pair(t0,t1)); + } + + return true; + } + + std::size_t error_count() const + { + return error_list_.size(); + } + + std::pair<lexer::token,lexer::token> error(const std::size_t index) + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + else + { + static const lexer::token error_token; + return std::make_pair(error_token,error_token); + } + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + void add_invalid(token_t t0, token_t t1, token_t t2) + { + invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2))); + } + + set_t invalid_comb_; + std::vector<std::pair<lexer::token,lexer::token> > error_list_; + }; + struct helper_assembly { inline bool register_scanner(lexer::token_scanner* scanner) { if (token_scanner_list.end() != std::find(token_scanner_list.begin(), - token_scanner_list.end(), + token_scanner_list.end (), scanner)) { return false; @@ -3680,7 +3913,7 @@ namespace exprtk inline bool register_modifier(lexer::token_modifier* modifier) { if (token_modifier_list.end() != std::find(token_modifier_list.begin(), - token_modifier_list.end(), + token_modifier_list.end (), modifier)) { return false; @@ -3694,7 +3927,7 @@ namespace exprtk inline bool register_joiner(lexer::token_joiner* joiner) { if (token_joiner_list.end() != std::find(token_joiner_list.begin(), - token_joiner_list.end(), + token_joiner_list.end (), joiner)) { return false; @@ -3708,7 +3941,7 @@ namespace exprtk inline bool register_inserter(lexer::token_inserter* inserter) { if (token_inserter_list.end() != std::find(token_inserter_list.begin(), - token_inserter_list.end(), + token_inserter_list.end (), inserter)) { return false; @@ -3915,40 +4148,6 @@ namespace exprtk return true; } - inline bool token_is_then_assign(const token_t::token_type& ttype, - std::string& token, - const token_advance_mode mode = e_advance) - { - if (current_token_.type != ttype) - { - return false; - } - - token = current_token_.value; - - advance_token(mode); - - return true; - } - - template <typename Allocator, - template <typename,typename> class Container> - inline bool token_is_then_assign(const token_t::token_type& ttype, - Container<std::string,Allocator>& token_list, - const token_advance_mode mode = e_advance) - { - if (current_token_.type != ttype) - { - return false; - } - - token_list.push_back(current_token_.value); - - advance_token(mode); - - return true; - } - inline bool peek_token_is(const token_t::token_type& ttype) { return (lexer_.peek_next_token().type == ttype); @@ -4026,7 +4225,7 @@ namespace exprtk private: - std::size_t size_; + const std::size_t size_; data_ptr_t data_; std::vector<data_ptr_t*> data_ref_; }; @@ -4053,19 +4252,24 @@ namespace exprtk enum store_type { e_unknown, - e_scalar, - e_vector, + e_scalar , + e_vector , e_string }; type_store() - : size(0), - data(0), + : data(0), + size(0), type(e_unknown) {} + union + { + void* data; + T* vec_data; + }; + std::size_t size; - void* data; store_type type; class parameter_list @@ -4134,6 +4338,11 @@ namespace exprtk data_(reinterpret_cast<value_t*>(ts_.data)) {} + type_view(const type_store_t& ts) + : ts_(const_cast<type_store_t&>(ts)), + data_(reinterpret_cast<value_t*>(ts_.data)) + {} + inline std::size_t size() const { return ts_.size; @@ -4182,12 +4391,12 @@ namespace exprtk : v_(*reinterpret_cast<value_t*>(const_cast<type_store_t&>(ts).data)) {} - inline value_t& operator()() + inline value_t& operator() () { return v_; } - inline const value_t& operator()() const + inline const value_t& operator() () const { return v_; } @@ -4413,12 +4622,12 @@ namespace exprtk { details(const std::size_t& vsize, const unsigned int loop_batch_size = global_loop_batch_size) - : batch_size(loop_batch_size), + : batch_size(loop_batch_size ), remainder (vsize % batch_size), - upper_bound(static_cast<int>(vsize) - (remainder ? loop_batch_size : 0)) + upper_bound(static_cast<int>(vsize - (remainder ? loop_batch_size : 0))) {} - int batch_size; + unsigned int batch_size; int remainder; int upper_bound; }; @@ -4460,16 +4669,16 @@ namespace exprtk {} control_block(const std::size_t& dsize) - : ref_count(1), + : ref_count(1 ), size (dsize), - data (0), - destruct (true) + data (0 ), + destruct (true ) { create_data(); } control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) - : ref_count(1), - size (dsize), - data (dptr ), + : ref_count(1 ), + size (dsize ), + data (dptr ), destruct (dstrct) {} @@ -4479,7 +4688,7 @@ namespace exprtk { dump_ptr("~control_block() data",data); delete[] data; - data = 0; + data = reinterpret_cast<data_t>(0); } } @@ -4488,12 +4697,12 @@ namespace exprtk if (dsize) { if (0 == data_ptr) - return new control_block(dsize); + return (new control_block(dsize)); else - return new control_block(dsize, data_ptr, dstrct); + return (new control_block(dsize, data_ptr, dstrct)); } else - return new control_block; + return (new control_block); } static inline void destroy(control_block*& cntrl_blck) @@ -4574,7 +4783,7 @@ namespace exprtk } } - return *this; + return (*this); } inline data_t data() @@ -4632,8 +4841,8 @@ namespace exprtk static inline std::size_t min_size(control_block* cb0, control_block* cb1) { - std::size_t size0 = cb0->size; - std::size_t size1 = cb1->size; + const std::size_t size0 = cb0->size; + const std::size_t size1 = cb1->size; if (size0 && size1) return std::min(size0,size1); @@ -4720,19 +4929,19 @@ namespace exprtk case e_ne : return std::not_equal_to<T>()(arg0,arg1) ? T(1) : T(0); case e_gte : return (arg0 >= arg1) ? T(1) : T(0); case e_gt : return (arg0 > arg1) ? T(1) : T(0); - case e_and : return and_opr<T> (arg0,arg1); + case e_and : return and_opr <T>(arg0,arg1); case e_nand : return nand_opr<T>(arg0,arg1); - case e_or : return or_opr<T> (arg0,arg1); - case e_nor : return nor_opr<T> (arg0,arg1); - case e_xor : return xor_opr<T> (arg0,arg1); + case e_or : return or_opr <T>(arg0,arg1); + case e_nor : return nor_opr <T>(arg0,arg1); + case e_xor : return xor_opr <T>(arg0,arg1); case e_xnor : return xnor_opr<T>(arg0,arg1); - case e_root : return root<T> (arg0,arg1); - case e_roundn : return roundn<T> (arg0,arg1); - case e_equal : return equal<T> (arg0,arg1); - case e_nequal : return nequal<T> (arg0,arg1); - case e_hypot : return hypot<T> (arg0,arg1); - case e_shr : return shr<T> (arg0,arg1); - case e_shl : return shl<T> (arg0,arg1); + case e_root : return root <T>(arg0,arg1); + case e_roundn : return roundn <T>(arg0,arg1); + case e_equal : return equal (arg0,arg1); + case e_nequal : return nequal (arg0,arg1); + case e_hypot : return hypot <T>(arg0,arg1); + case e_shr : return shr <T>(arg0,arg1); + case e_shl : return shl <T>(arg0,arg1); default : exprtk_debug(("numeric::details::process_impl<T> - Invalid binary operation.\n")); return std::numeric_limits<T>::quiet_NaN(); @@ -4787,7 +4996,7 @@ namespace exprtk template <typename T> inline T process(const operator_type operation, const T arg0, const T arg1) { - return exprtk::details::numeric::details::process_impl(operation,arg0,arg1); + return exprtk::details::numeric::details::process_impl(operation, arg0, arg1); } } @@ -4798,42 +5007,42 @@ namespace exprtk enum node_type { - e_none , e_null , e_constant , e_unary , - e_binary , e_binary_ext , e_trinary , e_quaternary , - e_vararg , e_conditional , e_while , e_repeat , - e_for , e_switch , e_mswitch , e_return , - e_retenv , e_variable , e_stringvar , e_stringconst , - e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , - e_stringvarsize, e_strswap , e_stringsize , e_stringvararg , - e_function , e_vafunction , e_genfunction , e_strfunction , - e_strcondition , e_strccondition, e_add , e_sub , - e_mul , e_div , e_mod , e_pow , - e_lt , e_lte , e_gt , e_gte , - e_eq , e_ne , e_and , e_nand , - e_or , e_nor , e_xor , e_xnor , - e_in , e_like , e_ilike , e_inranges , - e_ipow , e_ipowinv , e_abs , e_acos , - e_acosh , e_asin , e_asinh , e_atan , - e_atanh , e_ceil , e_cos , e_cosh , - e_exp , e_expm1 , e_floor , e_log , - e_log10 , e_log2 , e_log1p , e_neg , - e_pos , e_round , e_sin , e_sinc , - e_sinh , e_sqrt , e_tan , e_tanh , - e_cot , e_sec , e_csc , e_r2d , - e_d2r , e_d2g , e_g2d , e_notl , - e_sgn , e_erf , e_erfc , e_ncdf , - e_frac , e_trunc , e_uvouv , e_vov , - e_cov , e_voc , e_vob , e_bov , - e_cob , e_boc , e_vovov , e_vovoc , - e_vocov , e_covov , e_covoc , e_vovovov , - e_vovovoc , e_vovocov , e_vocovov , e_covovov , - e_covocov , e_vocovoc , e_covovoc , e_vococov , - e_sf3ext , e_sf4ext , e_nulleq , e_strass , - e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , - e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , - e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , - e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , - e_valvecarith , e_vecunaryop , e_break , e_continue , + e_none , e_null , e_constant , e_unary , + e_binary , e_binary_ext , e_trinary , e_quaternary , + e_vararg , e_conditional , e_while , e_repeat , + e_for , e_switch , e_mswitch , e_return , + e_retenv , e_variable , e_stringvar , e_stringconst , + e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat , + e_stringvarsize , e_strswap , e_stringsize , e_stringvararg , + e_function , e_vafunction , e_genfunction , e_strfunction , + e_strcondition , e_strccondition , e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_lt , e_lte , e_gt , e_gte , + e_eq , e_ne , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_in , e_like , e_ilike , e_inranges , + e_ipow , e_ipowinv , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_neg , + e_pos , e_round , e_sin , e_sinc , + e_sinh , e_sqrt , e_tan , e_tanh , + e_cot , e_sec , e_csc , e_r2d , + e_d2r , e_d2g , e_g2d , e_notl , + e_sgn , e_erf , e_erfc , e_ncdf , + e_frac , e_trunc , e_uvouv , e_vov , + e_cov , e_voc , e_vob , e_bov , + e_cob , e_boc , e_vovov , e_vovoc , + e_vocov , e_covov , e_covoc , e_vovovov , + e_vovovoc , e_vovocov , e_vocovov , e_covovov , + e_covocov , e_vocovoc , e_covovoc , e_vococov , + e_sf3ext , e_sf4ext , e_nulleq , e_strass , + e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , + e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , + e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , + e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , + e_valvecarith , e_vecunaryop , e_break , e_continue , e_swap }; @@ -5054,7 +5263,7 @@ namespace exprtk template <typename T, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline bool all_nodes_valid(const Sequence<expression_node<T>*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) @@ -5081,7 +5290,7 @@ namespace exprtk template <typename T, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline bool all_nodes_variables(Sequence<expression_node<T>*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) @@ -5107,7 +5316,7 @@ namespace exprtk template <typename NodeAllocator, typename T, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline void free_all_nodes(NodeAllocator& node_allocator, Sequence<expression_node<T>*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) @@ -5130,10 +5339,17 @@ namespace exprtk return; node_allocator.free(node); - node = 0; + node = reinterpret_cast<expression_node<T>*>(0); } } + template <typename T> + inline void destroy_node(expression_node<T>*& node) + { + delete node; + node = reinterpret_cast<expression_node<T>*>(0); + } + template <typename Type> class vector_holder { @@ -5147,7 +5363,7 @@ namespace exprtk { public: - virtual ~vector_holder_base(){} + virtual ~vector_holder_base() {} inline value_ptr operator[](const std::size_t& index) const { @@ -5210,7 +5426,7 @@ namespace exprtk }; template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> class sequence_vector_impl : public vector_holder_base { public: @@ -5317,7 +5533,7 @@ namespace exprtk void set_ref(value_ptr* ref) { - return vector_holder_base_->set_ref(ref); + vector_holder_base_->set_ref(ref); } bool rebaseable() const @@ -5364,8 +5580,7 @@ namespace exprtk { if (branch_ && branch_deletable_) { - delete branch_; - branch_ = 0; + destroy_node(branch_); } } @@ -5398,7 +5613,7 @@ namespace exprtk private: expression_ptr branch_; - bool branch_deletable_; + const bool branch_deletable_; bool equality_; }; @@ -5429,7 +5644,7 @@ namespace exprtk private: literal_node(literal_node<T>&) {} - literal_node<T>& operator=(literal_node<T>&) { return *this; } + literal_node<T>& operator=(literal_node<T>&) { return (*this); } const T value_; }; @@ -5468,7 +5683,7 @@ namespace exprtk virtual std::string str () const = 0; - virtual const char* base() const = 0; + virtual char_cptr base() const = 0; virtual std::size_t size() const = 0; }; @@ -5511,7 +5726,7 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { return value_.data(); } @@ -5559,8 +5774,7 @@ namespace exprtk { if (branch_ && branch_deletable_) { - delete branch_; - branch_ = 0; + destroy_node(branch_); } } @@ -5653,23 +5867,21 @@ namespace exprtk { if (branch[i].first && branch[i].second) { - delete branch[i].first; - branch[i].first = 0; + destroy_node(branch[i].first); } } } template <typename T, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline void execute(Sequence<std::pair<expression_node<T>*,bool>,Allocator>& branch) { for (std::size_t i = 0; i < branch.size(); ++i) { if (branch[i].first && branch[i].second) { - delete branch[i].first; - branch[i].first = 0; + destroy_node(branch[i].first); } } } @@ -5688,7 +5900,7 @@ namespace exprtk expression_ptr branch1) : operation_(opr) { - init_branches<2>(branch_,branch0,branch1); + init_branches<2>(branch_, branch0, branch1); } ~binary_node() @@ -5740,7 +5952,7 @@ namespace exprtk binary_ext_node(expression_ptr branch0, expression_ptr branch1) { - init_branches<2>(branch_,branch0,branch1); + init_branches<2>(branch_, branch0, branch1); } ~binary_ext_node() @@ -5795,7 +6007,7 @@ namespace exprtk expression_ptr branch2) : operation_(opr) { - init_branches<3>(branch_,branch0,branch1,branch2); + init_branches<3>(branch_, branch0, branch1, branch2); } ~trinary_node() @@ -5820,10 +6032,8 @@ namespace exprtk else return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); - default : { - exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); - return std::numeric_limits<T>::quiet_NaN(); - } + default : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); + return std::numeric_limits<T>::quiet_NaN(); } } @@ -5853,7 +6063,7 @@ namespace exprtk expression_ptr branch3) : operation_(opr) { - init_branches<4>(branch_,branch0,branch1,branch2,branch3); + init_branches<4>(branch_, branch0, branch1, branch2, branch3); } ~quaternary_node() @@ -5897,9 +6107,20 @@ namespace exprtk ~conditional_node() { - if (test_ && test_deletable_ ) delete test_; - if (consequent_ && consequent_deletable_ ) delete consequent_; - if (alternative_ && alternative_deletable_) delete alternative_; + if (test_ && test_deletable_) + { + destroy_node(test_); + } + + if (consequent_ && consequent_deletable_ ) + { + destroy_node(consequent_); + } + + if (alternative_ && alternative_deletable_) + { + destroy_node(alternative_); + } } inline T value() const @@ -5920,9 +6141,9 @@ namespace exprtk expression_ptr test_; expression_ptr consequent_; expression_ptr alternative_; - bool test_deletable_; - bool consequent_deletable_; - bool alternative_deletable_; + const bool test_deletable_; + const bool consequent_deletable_; + const bool alternative_deletable_; }; template <typename T> @@ -5943,8 +6164,15 @@ namespace exprtk ~cons_conditional_node() { - if (test_ && test_deletable_ ) delete test_; - if (consequent_ && consequent_deletable_) delete consequent_; + if (test_ && test_deletable_) + { + destroy_node(test_); + } + + if (consequent_ && consequent_deletable_) + { + destroy_node(consequent_); + } } inline T value() const @@ -5964,8 +6192,8 @@ namespace exprtk expression_ptr test_; expression_ptr consequent_; - bool test_deletable_; - bool consequent_deletable_; + const bool test_deletable_; + const bool consequent_deletable_; }; #ifndef exprtk_disable_break_continue @@ -6000,7 +6228,7 @@ namespace exprtk { if (return_deletable_) { - delete return_; + destroy_node(return_); } } @@ -6020,7 +6248,7 @@ namespace exprtk private: expression_ptr return_; - bool return_deletable_; + const bool return_deletable_; }; template <typename T> @@ -6061,12 +6289,12 @@ namespace exprtk { if (condition_ && condition_deletable_) { - delete condition_; + destroy_node(condition_); } if (loop_body_ && loop_body_deletable_) { - delete loop_body_; + destroy_node(loop_body_); } } @@ -6091,8 +6319,8 @@ namespace exprtk expression_ptr condition_; expression_ptr loop_body_; - bool condition_deletable_; - bool loop_body_deletable_; + const bool condition_deletable_; + const bool loop_body_deletable_; }; template <typename T> @@ -6113,12 +6341,12 @@ namespace exprtk { if (condition_ && condition_deletable_) { - delete condition_; + destroy_node(condition_); } if (loop_body_ && loop_body_deletable_) { - delete loop_body_; + destroy_node(loop_body_); } } @@ -6144,8 +6372,8 @@ namespace exprtk expression_ptr condition_; expression_ptr loop_body_; - bool condition_deletable_; - bool loop_body_deletable_; + const bool condition_deletable_; + const bool loop_body_deletable_; }; template <typename T> @@ -6160,9 +6388,9 @@ namespace exprtk expression_ptr incrementor, expression_ptr loop_body) : initialiser_(initialiser), - condition_ (condition), + condition_ (condition ), incrementor_(incrementor), - loop_body_ (loop_body), + loop_body_ (loop_body ), initialiser_deletable_(branch_deletable(initialiser_)), condition_deletable_ (branch_deletable(condition_ )), incrementor_deletable_(branch_deletable(incrementor_)), @@ -6173,22 +6401,22 @@ namespace exprtk { if (initialiser_ && initialiser_deletable_) { - delete initialiser_; + destroy_node(initialiser_); } if (condition_ && condition_deletable_) { - delete condition_; + destroy_node(condition_); } if (incrementor_ && incrementor_deletable_) { - delete incrementor_; + destroy_node(incrementor_); } if (loop_body_ && loop_body_deletable_) { - delete loop_body_; + destroy_node(loop_body_); } } @@ -6225,14 +6453,14 @@ namespace exprtk private: - expression_ptr initialiser_; - expression_ptr condition_ ; - expression_ptr incrementor_; - expression_ptr loop_body_ ; - bool initialiser_deletable_; - bool condition_deletable_ ; - bool incrementor_deletable_; - bool loop_body_deletable_ ; + expression_ptr initialiser_ ; + expression_ptr condition_ ; + expression_ptr incrementor_ ; + expression_ptr loop_body_ ; + const bool initialiser_deletable_; + const bool condition_deletable_ ; + const bool incrementor_deletable_; + const bool loop_body_deletable_ ; }; #ifndef exprtk_disable_break_continue @@ -6254,12 +6482,12 @@ namespace exprtk { if (condition_ && condition_deletable_) { - delete condition_; + destroy_node(condition_); } if (loop_body_ && loop_body_deletable_) { - delete loop_body_; + destroy_node(loop_body_); } } @@ -6293,8 +6521,8 @@ namespace exprtk expression_ptr condition_; expression_ptr loop_body_; - bool condition_deletable_; - bool loop_body_deletable_; + const bool condition_deletable_; + const bool loop_body_deletable_; }; template <typename T> @@ -6315,12 +6543,12 @@ namespace exprtk { if (condition_ && condition_deletable_) { - delete condition_; + destroy_node(condition_); } if (loop_body_ && loop_body_deletable_) { - delete loop_body_; + destroy_node(loop_body_); } } @@ -6355,8 +6583,8 @@ namespace exprtk expression_ptr condition_; expression_ptr loop_body_; - bool condition_deletable_; - bool loop_body_deletable_; + const bool condition_deletable_; + const bool loop_body_deletable_; }; template <typename T> @@ -6384,22 +6612,22 @@ namespace exprtk { if (initialiser_ && initialiser_deletable_) { - delete initialiser_; + destroy_node(initialiser_); } if (condition_ && condition_deletable_) { - delete condition_; + destroy_node(condition_); } if (incrementor_ && incrementor_deletable_) { - delete incrementor_; + destroy_node(incrementor_); } if (loop_body_ && loop_body_deletable_) { - delete loop_body_; + destroy_node(loop_body_); } } @@ -6459,10 +6687,10 @@ namespace exprtk expression_ptr condition_ ; expression_ptr incrementor_; expression_ptr loop_body_ ; - bool initialiser_deletable_; - bool condition_deletable_ ; - bool incrementor_deletable_; - bool loop_body_deletable_ ; + const bool initialiser_deletable_; + const bool condition_deletable_ ; + const bool incrementor_deletable_; + const bool loop_body_deletable_ ; }; #endif @@ -6474,8 +6702,8 @@ namespace exprtk typedef expression_node<T>* expression_ptr; template <typename Allocator, - template <typename,typename> class Sequence> - switch_node(const Sequence<expression_ptr,Allocator>& arg_list) + template <typename, typename> class Sequence> + explicit switch_node(const Sequence<expression_ptr,Allocator>& arg_list) { if (1 != (arg_list.size() & 1)) return; @@ -6505,8 +6733,7 @@ namespace exprtk { if (arg_list_[i] && delete_branch_[i]) { - delete arg_list_[i]; - arg_list_[i] = 0; + destroy_node(arg_list_[i]); } } } @@ -6553,8 +6780,8 @@ namespace exprtk typedef expression_node<T>* expression_ptr; template <typename Allocator, - template <typename,typename> class Sequence> - switch_n_node(const Sequence<expression_ptr,Allocator>& arg_list) + template <typename, typename> class Sequence> + explicit switch_n_node(const Sequence<expression_ptr,Allocator>& arg_list) : switch_node<T>(arg_list) {} @@ -6572,8 +6799,8 @@ namespace exprtk typedef expression_node<T>* expression_ptr; template <typename Allocator, - template <typename,typename> class Sequence> - multi_switch_node(const Sequence<expression_ptr,Allocator>& arg_list) + template <typename, typename> class Sequence> + explicit multi_switch_node(const Sequence<expression_ptr,Allocator>& arg_list) { if (0 != (arg_list.size() & 1)) return; @@ -6603,8 +6830,7 @@ namespace exprtk { if (arg_list_[i] && delete_branch_[i]) { - delete arg_list_[i]; - arg_list_[i] = 0; + destroy_node(arg_list_[i]); } } } @@ -6666,23 +6892,13 @@ namespace exprtk static T null_value; explicit variable_node() - : value_(&null_value), - delete_value_(false) + : value_(&null_value) {} - variable_node(T& v) - : value_(&v), - delete_value_(false) + explicit variable_node(T& v) + : value_(&v) {} - ~variable_node() - { - if (delete_value_) - { - delete value_; - } - } - inline bool operator <(const variable_node<T>& v) const { return this < (&v); @@ -6708,15 +6924,9 @@ namespace exprtk return expression_node<T>::e_variable; } - inline bool& delete_value() - { - return delete_value_; - } - private: T* value_; - bool delete_value_; }; template <typename T> @@ -6756,8 +6966,7 @@ namespace exprtk !is_string_node (n0_e.second) ) { - delete n0_e.second; - n0_e.second = expression_node_ptr(0); + destroy_node(n0_e.second); } } @@ -6770,8 +6979,7 @@ namespace exprtk !is_string_node (n1_e.second) ) { - delete n1_e.second; - n1_e.second = expression_node_ptr(0); + destroy_node(n1_e.second); } } } @@ -6788,13 +6996,13 @@ namespace exprtk (!n0_c.first && !n1_c.first); } - bool operator()(std::size_t& r0, std::size_t& r1, const std::size_t& size = std::numeric_limits<std::size_t>::max()) const + bool operator() (std::size_t& r0, std::size_t& r1, const std::size_t& size = std::numeric_limits<std::size_t>::max()) const { if (n0_c.first) r0 = n0_c.second; else if (n0_e.first) { - T r0_value = n0_e.second->value(); + const T r0_value = n0_e.second->value(); if (r0_value < 0) return false; @@ -6808,7 +7016,7 @@ namespace exprtk r1 = n1_c.second; else if (n1_e.first) { - T r1_value = n1_e.second->value(); + const T r1_value = n1_e.second->value(); if (r1_value < 0) return false; @@ -6910,7 +7118,7 @@ namespace exprtk typedef vector_node<T>* vector_node_ptr; typedef vec_data_store<T> vds_t; - vector_node(vector_holder_t* vh) + explicit vector_node(vector_holder_t* vh) : vector_holder_(vh), vds_((*vector_holder_).size(),(*vector_holder_)[0]) { @@ -6989,7 +7197,7 @@ namespace exprtk { if (index_ && index_deletable_) { - delete index_; + destroy_node(index_); } } @@ -7023,7 +7231,7 @@ namespace exprtk expression_ptr index_; vector_holder_ptr vec_holder_; T* vector_base_; - bool index_deletable_; + const bool index_deletable_; }; template <typename T> @@ -7050,7 +7258,7 @@ namespace exprtk { if (index_ && index_deletable_) { - delete index_; + destroy_node(index_); } } @@ -7082,7 +7290,7 @@ namespace exprtk private: expression_ptr index_; - bool index_deletable_; + const bool index_deletable_; vector_holder_ptr vector_holder_; vds_t vds_; }; @@ -7133,7 +7341,7 @@ namespace exprtk private: - std::size_t index_; + const std::size_t index_; vector_holder_ptr vector_holder_; vds_t vds_; }; @@ -7161,7 +7369,7 @@ namespace exprtk { if (branch_deletable(initialiser_list_[i])) { - delete initialiser_list_[i]; + destroy_node(initialiser_list_[i]); } } } @@ -7250,7 +7458,7 @@ namespace exprtk typedef ivariable<T>* ivariable_ptr; swap_generic_node(expression_ptr var0, expression_ptr var1) - : binary_node<T>(details::e_swap,var0,var1), + : binary_node<T>(details::e_swap, var0, var1), var0_(dynamic_cast<ivariable_ptr>(var0)), var1_(dynamic_cast<ivariable_ptr>(var1)) {} @@ -7284,7 +7492,7 @@ namespace exprtk swap_vecvec_node(expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(details::e_swap,branch0,branch1), + : binary_node<T>(details::e_swap, branch0, branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), vec_size_ (0), @@ -7423,7 +7631,7 @@ namespace exprtk return ref(); } - const char* base() const + char_cptr base() const { return &(*value_)[0]; } @@ -7503,7 +7711,7 @@ namespace exprtk return (*value_); } - const char* base() const + char_cptr base() const { return &(*value_)[0]; } @@ -7581,7 +7789,7 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { return value_.data(); } @@ -7669,8 +7877,7 @@ namespace exprtk if (branch_ && branch_deletable_) { - delete branch_; - branch_ = 0; + destroy_node(branch_); } } @@ -7712,7 +7919,7 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { return &value_[0]; } @@ -7739,14 +7946,14 @@ namespace exprtk private: - bool initialised_; - expression_ptr branch_; - bool branch_deletable_; - str_base_ptr str_base_ptr_; - irange_ptr str_range_ptr_; - mutable range_t base_range_; - mutable range_t range_; - mutable std::string value_; + bool initialised_; + expression_ptr branch_; + const bool branch_deletable_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + mutable range_t base_range_; + mutable range_t range_; + mutable std::string value_; }; template <typename T> @@ -7766,7 +7973,7 @@ namespace exprtk string_concat_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), initialised_(false), str0_base_ptr_ (0), str1_base_ptr_ (0), @@ -7828,8 +8035,8 @@ namespace exprtk range_t& range1 = str1_range_ptr_->range_ref(); if ( - range0(str0_r0,str0_r1,str0_base_ptr_->size()) && - range1(str1_r0,str1_r1,str1_base_ptr_->size()) + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) ) { const std::size_t size0 = (str0_r1 - str0_r0) + 1; @@ -7851,7 +8058,7 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { return &value_[0]; } @@ -7903,7 +8110,7 @@ namespace exprtk typedef irange_t* irange_ptr; swap_string_node(expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(details::e_swap,branch0,branch1), + : binary_node<T>(details::e_swap, branch0, branch1), initialised_(false), str0_node_ptr_(0), str1_node_ptr_(0) @@ -7939,7 +8146,7 @@ namespace exprtk return str0_node_ptr_->str(); } - const char* base() const + char_cptr base() const { return str0_node_ptr_->base(); } @@ -7985,7 +8192,7 @@ namespace exprtk swap_genstrings_node(expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(details::e_default,branch0,branch1), + : binary_node<T>(details::e_default, branch0, branch1), str0_base_ptr_ (0), str1_base_ptr_ (0), str0_range_ptr_(0), @@ -7999,12 +8206,12 @@ namespace exprtk if (0 == str0_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); - if (0 == range_ptr) + if (0 == range) return; - str0_range_ptr_ = &(range_ptr->range_ref()); + str0_range_ptr_ = &(range->range_ref()); } if (is_generally_string_node(binary_node<T>::branch_[1].first)) @@ -8014,12 +8221,12 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } initialised_ = str0_base_ptr_ && @@ -8045,19 +8252,19 @@ namespace exprtk range_t& range1 = (*str1_range_ptr_); if ( - range0(str0_r0,str0_r1,str0_base_ptr_->size()) && - range1(str1_r0,str1_r1,str1_base_ptr_->size()) + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) ) { const std::size_t size0 = range0.cache_size(); const std::size_t size1 = range1.cache_size(); const std::size_t max_size = std::min(size0,size1); - char* s0 = const_cast<char*>(str0_base_ptr_->base() + str0_r0); - char* s1 = const_cast<char*>(str1_base_ptr_->base() + str1_r0); + char_ptr s0 = const_cast<char_ptr>(str0_base_ptr_->base() + str0_r0); + char_ptr s1 = const_cast<char_ptr>(str1_base_ptr_->base() + str1_r0); loop_unroll::details lud(max_size); - const char* upper_bound = s0 + lud.upper_bound; + char_cptr upper_bound = s0 + lud.upper_bound; while (s0 < upper_bound) { @@ -8081,6 +8288,7 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ @@ -8097,6 +8305,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -8164,7 +8373,7 @@ namespace exprtk typedef expression_node <T>* expression_ptr; typedef string_base_node<T>* str_base_ptr; - string_size_node(expression_ptr brnch) + explicit string_size_node(expression_ptr brnch) : branch_(brnch), branch_deletable_(branch_deletable(branch_)), str_base_ptr_(0) @@ -8182,8 +8391,7 @@ namespace exprtk { if (branch_ && branch_deletable_) { - delete branch_; - branch_ = 0; + destroy_node(branch_); } } @@ -8207,20 +8415,20 @@ namespace exprtk private: - expression_ptr branch_; - bool branch_deletable_; - str_base_ptr str_base_ptr_; + expression_ptr branch_; + const bool branch_deletable_; + str_base_ptr str_base_ptr_; }; struct asn_assignment { - static inline void execute(std::string& s, const char* data, const std::size_t size) + static inline void execute(std::string& s, char_cptr data, const std::size_t size) { s.assign(data,size); } }; struct asn_addassignment { - static inline void execute(std::string& s, const char* data, const std::size_t size) + static inline void execute(std::string& s, char_cptr data, const std::size_t size) { s.append(data,size); } }; @@ -8242,7 +8450,7 @@ namespace exprtk assignment_string_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), initialised_(false), str0_base_ptr_ (0), str1_base_ptr_ (0), @@ -8263,12 +8471,12 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } initialised_ = str0_base_ptr_ && @@ -8288,7 +8496,7 @@ namespace exprtk range_t& range = (*str1_range_ptr_); - if (range(r0,r1,str1_base_ptr_->size())) + if (range(r0, r1, str1_base_ptr_->size())) { AssignmentProcess::execute(str0_node_ptr_->ref(), str1_base_ptr_->base() + r0, @@ -8306,7 +8514,7 @@ namespace exprtk return str0_node_ptr_->str(); } - const char* base() const + char_cptr base() const { return str0_node_ptr_->base(); } @@ -8358,7 +8566,7 @@ namespace exprtk assignment_string_range_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), initialised_(false), str0_base_ptr_ (0), str1_base_ptr_ (0), @@ -8372,12 +8580,12 @@ namespace exprtk str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first); - irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); - if (0 == range_ptr) + if (0 == range) return; - str0_range_ptr_ = &(range_ptr->range_ref()); + str0_range_ptr_ = &(range->range_ref()); } if (is_generally_string_node(binary_node<T>::branch_[1].first)) @@ -8387,12 +8595,12 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } initialised_ = str0_base_ptr_ && @@ -8419,15 +8627,15 @@ namespace exprtk range_t& range1 = (*str1_range_ptr_); if ( - range0(s0_r0,s0_r1,str0_base_ptr_->size()) && - range1(s1_r0,s1_r1,str1_base_ptr_->size()) + range0(s0_r0, s0_r1, str0_base_ptr_->size()) && + range1(s1_r0, s1_r1, str1_base_ptr_->size()) ) { std::size_t size = std::min((s0_r1 - s0_r0),(s1_r1 - s1_r0)) + 1; std::copy(str1_base_ptr_->base() + s1_r0, str1_base_ptr_->base() + s1_r0 + size, - const_cast<char*>(base() + s0_r0)); + const_cast<char_ptr>(base() + s0_r0)); } } @@ -8439,7 +8647,7 @@ namespace exprtk return str0_node_ptr_->str(); } - const char* base() const + char_cptr base() const { return str0_node_ptr_->base(); } @@ -8553,7 +8761,7 @@ namespace exprtk range_t& range = str0_range_ptr_->range_ref(); - if (range(r0,r1,str0_base_ptr_->size())) + if (range(r0, r1, str0_base_ptr_->size())) { const std::size_t size = (r1 - r0) + 1; @@ -8571,7 +8779,7 @@ namespace exprtk range_t& range = str1_range_ptr_->range_ref(); - if (range(r0,r1,str1_base_ptr_->size())) + if (range(r0, r1, str1_base_ptr_->size())) { const std::size_t size = (r1 - r0) + 1; @@ -8593,7 +8801,7 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { return &value_[0]; } @@ -8649,7 +8857,7 @@ namespace exprtk cons_conditional_str_node(expression_ptr test, expression_ptr consequent) - : binary_node<T>(details::e_default,consequent,test), + : binary_node<T>(details::e_default, consequent, test), initialised_(false), str0_base_ptr_ (0), str0_range_ptr_(0), @@ -8691,7 +8899,7 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - if (range(r0,r1,str0_base_ptr_->size())) + if (range(r0, r1, str0_base_ptr_->size())) { const std::size_t size = (r1 - r0) + 1; @@ -8713,7 +8921,7 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { return &value_[0]; } @@ -8765,8 +8973,8 @@ namespace exprtk typedef irange_t* irange_ptr; template <typename Allocator, - template <typename,typename> class Sequence> - str_vararg_node(const Sequence<expression_ptr,Allocator>& arg_list) + template <typename, typename> class Sequence> + explicit str_vararg_node(const Sequence<expression_ptr,Allocator>& arg_list) : final_node_(arg_list.back()), final_deletable_(branch_deletable(final_node_)), initialised_(false), @@ -8806,7 +9014,7 @@ namespace exprtk } else { - arg_list_.clear(); + arg_list_ .clear(); delete_branch_.clear(); return; } @@ -8818,16 +9026,14 @@ namespace exprtk { if (final_node_ && final_deletable_) { - delete final_node_; - final_node_ = 0; + destroy_node(final_node_); } for (std::size_t i = 0; i < arg_list_.size(); ++i) { if (arg_list_[i] && delete_branch_[i]) { - delete arg_list_[i]; - arg_list_[i] = 0; + destroy_node(arg_list_[i]); } } } @@ -8849,7 +9055,7 @@ namespace exprtk return str_base_ptr_->str(); } - const char* base() const + char_cptr base() const { return str_base_ptr_->base(); } @@ -8915,7 +9121,7 @@ namespace exprtk template <typename T> \ struct sf##NN##_op : public sf_base<T> \ { \ - typedef typename sf_base<T>::Type Type; \ + typedef typename sf_base<T>::Type const Type; \ static inline T process(Type x, Type y, Type z) \ { \ return (OP0); \ @@ -8979,7 +9185,7 @@ namespace exprtk template <typename T> \ struct sf##NN##_op : public sf_base<T> \ { \ - typedef typename sf_base<T>::Type Type; \ + typedef typename sf_base<T>::Type const Type; \ static inline T process(Type x, Type y, Type z, Type w) \ { \ return (OP0); \ @@ -9118,7 +9324,7 @@ namespace exprtk expression_ptr branch0, expression_ptr branch1, expression_ptr branch2) - : trinary_node<T>(opr,branch0,branch1,branch2) + : trinary_node<T>(opr, branch0, branch1, branch2) {} inline T value() const @@ -9127,7 +9333,7 @@ namespace exprtk const T y = trinary_node<T>::branch_[1].first->value(); const T z = trinary_node<T>::branch_[2].first->value(); - return SpecialFunction::process(x,y,z); + return SpecialFunction::process(x, y, z); } }; @@ -9143,7 +9349,7 @@ namespace exprtk expression_ptr branch1, expression_ptr branch2, expression_ptr branch3) - : quaternary_node<T>(opr,branch0,branch1,branch2,branch3) + : quaternary_node<T>(opr, branch0, branch1, branch2, branch3) {} inline T value() const @@ -9153,7 +9359,7 @@ namespace exprtk const T z = quaternary_node<T>::branch_[2].first->value(); const T w = quaternary_node<T>::branch_[3].first->value(); - return SpecialFunction::process(x,y,z,w); + return SpecialFunction::process(x, y, z, w); } }; @@ -9172,7 +9378,7 @@ namespace exprtk inline T value() const { - return SpecialFunction::process(v0_,v1_,v2_); + return SpecialFunction::process(v0_, v1_, v2_); } inline typename expression_node<T>::node_type type() const @@ -9206,7 +9412,7 @@ namespace exprtk inline T value() const { - return SpecialFunction::process(v0_,v1_,v2_,v3_); + return SpecialFunction::process(v0_, v1_, v2_, v3_); } inline typename expression_node<T>::node_type type() const @@ -9233,10 +9439,10 @@ namespace exprtk typedef expression_node<T>* expression_ptr; template <typename Allocator, - template <typename,typename> class Sequence> - vararg_node(const Sequence<expression_ptr,Allocator>& arg_list) + template <typename, typename> class Sequence> + explicit vararg_node(const Sequence<expression_ptr,Allocator>& arg_list) { - arg_list_.resize(arg_list.size()); + arg_list_ .resize(arg_list.size()); delete_branch_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) @@ -9261,18 +9467,14 @@ namespace exprtk { if (arg_list_[i] && delete_branch_[i]) { - delete arg_list_[i]; - arg_list_[i] = 0; + destroy_node(arg_list_[i]); } } } inline T value() const { - if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - return std::numeric_limits<T>::quiet_NaN(); + return VarArgFunction::process(arg_list_); } inline typename expression_node<T>::node_type type() const @@ -9294,8 +9496,8 @@ namespace exprtk typedef expression_node<T>* expression_ptr; template <typename Allocator, - template <typename,typename> class Sequence> - vararg_varnode(const Sequence<expression_ptr,Allocator>& arg_list) + template <typename, typename> class Sequence> + explicit vararg_varnode(const Sequence<expression_ptr,Allocator>& arg_list) { arg_list_.resize(arg_list.size()); @@ -9339,7 +9541,7 @@ namespace exprtk typedef expression_node<T>* expression_ptr; - vectorize_node(const expression_ptr v) + explicit vectorize_node(const expression_ptr v) : ivec_ptr_(0), v_(v), v_deletable_(branch_deletable(v_)) @@ -9356,7 +9558,7 @@ namespace exprtk { if (v_ && v_deletable_) { - delete v_; + destroy_node(v_); } } @@ -9379,8 +9581,8 @@ namespace exprtk private: vector_interface<T>* ivec_ptr_; - expression_ptr v_; - bool v_deletable_; + expression_ptr v_; + const bool v_deletable_; }; template <typename T> @@ -9393,7 +9595,7 @@ namespace exprtk assignment_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), var_node_ptr_(0) { if (is_variable_node(binary_node<T>::branch_[0].first)) @@ -9431,7 +9633,7 @@ namespace exprtk assignment_vec_elem_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec_node_ptr_(0) { if (is_vector_elem_node(binary_node<T>::branch_[0].first)) @@ -9469,7 +9671,7 @@ namespace exprtk assignment_rebasevec_elem_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), rbvec_node_ptr_(0) { if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first)) @@ -9507,7 +9709,7 @@ namespace exprtk assignment_rebasevec_celem_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), rbvec_node_ptr_(0) { if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first)) @@ -9548,7 +9750,7 @@ namespace exprtk assignment_vec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec_node_ptr_(0) { if (is_vector_node(binary_node<T>::branch_[0].first)) @@ -9571,8 +9773,8 @@ namespace exprtk while (vec < upper_bound) { - #define exprtk_loop(N) \ - vec[N] = v; \ + #define exprtk_loop(N) \ + vec[N] = v; \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -9588,6 +9790,7 @@ namespace exprtk vec += lud.batch_size; } + exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ @@ -9604,6 +9807,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -9663,7 +9867,7 @@ namespace exprtk assignment_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), initialised_(false), @@ -9736,6 +9940,7 @@ namespace exprtk vec1 += lud.batch_size; } + exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ @@ -9752,6 +9957,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -9811,7 +10017,7 @@ namespace exprtk assignment_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), var_node_ptr_(0) { if (is_variable_node(binary_node<T>::branch_[0].first)) @@ -9848,7 +10054,7 @@ namespace exprtk assignment_vec_elem_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec_node_ptr_(0) { if (is_vector_elem_node(binary_node<T>::branch_[0].first)) @@ -9885,7 +10091,7 @@ namespace exprtk assignment_rebasevec_elem_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), rbvec_node_ptr_(0) { if (is_rebasevector_elem_node(binary_node<T>::branch_[0].first)) @@ -9922,7 +10128,7 @@ namespace exprtk assignment_rebasevec_celem_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), rbvec_node_ptr_(0) { if (is_rebasevector_celem_node(binary_node<T>::branch_[0].first)) @@ -9962,7 +10168,7 @@ namespace exprtk assignment_vec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec_node_ptr_(0) { if (is_vector_node(binary_node<T>::branch_[0].first)) @@ -10002,6 +10208,7 @@ namespace exprtk vec += lud.batch_size; } + exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ @@ -10018,6 +10225,8 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end + #undef exprtk_loop #undef case_stmt @@ -10082,7 +10291,7 @@ namespace exprtk assignment_vecvec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), initialised_(false) @@ -10121,16 +10330,16 @@ namespace exprtk binary_node<T>::branch_[0].first->value(); binary_node<T>::branch_[1].first->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(vec0[N],vec1[N]); \ + #define exprtk_loop(N) \ + vec0[N] = Operation::process(vec0[N], vec1[N]); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10149,10 +10358,11 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec0[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10165,6 +10375,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -10232,7 +10443,7 @@ namespace exprtk vec_binop_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), temp_ (0), @@ -10304,17 +10515,17 @@ namespace exprtk binary_node<T>::branch_[0].first->value(); binary_node<T>::branch_[1].first->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - T* vec2 = vds().data(); + const T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); + T* vec2 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec2 + lud.upper_bound; while (vec2 < upper_bound) { - #define exprtk_loop(N) \ - vec2[N] = Operation::process(vec0[N],vec1[N]); \ + #define exprtk_loop(N) \ + vec2[N] = Operation::process(vec0[N], vec1[N]); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10334,10 +10545,11 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec2[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ + #define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10350,6 +10562,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -10414,7 +10627,7 @@ namespace exprtk vec_binop_vecval_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec0_node_ptr_(0), temp_ (0), temp_vec_node_(0) @@ -10461,16 +10674,16 @@ namespace exprtk binary_node<T>::branch_[0].first->value(); const T v = binary_node<T>::branch_[1].first->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { - #define exprtk_loop(N) \ - vec1[N] = Operation::process(vec0[N],v); \ + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N], v); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10489,10 +10702,11 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec1[i] = Operation::process(vec0[i],v); ++i; } \ + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10505,6 +10719,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -10567,7 +10782,7 @@ namespace exprtk vec_binop_valvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), vec1_node_ptr_(0), temp_ (0), temp_vec_node_(0) @@ -10614,16 +10829,16 @@ namespace exprtk const T v = binary_node<T>::branch_[0].first->value(); binary_node<T>::branch_[1].first->value(); - T* vec0 = vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + T* vec0 = vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(v,vec1[N]); \ + #define exprtk_loop(N) \ + vec0[N] = Operation::process(v, vec1[N]); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10642,10 +10857,11 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec0[i] = Operation::process(v,vec1[i]); ++i; } \ + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10658,6 +10874,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -10718,7 +10935,7 @@ namespace exprtk typedef vec_data_store<T> vds_t; unary_vector_node(const operator_type& opr, expression_ptr branch0) - : unary_node<T>(opr,branch0), + : unary_node<T>(opr, branch0), vec0_node_ptr_(0), temp_ (0), temp_vec_node_(0) @@ -10764,8 +10981,8 @@ namespace exprtk if (vec0_node_ptr_) { - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; @@ -10792,6 +11009,7 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ @@ -10808,6 +11026,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -10866,7 +11085,7 @@ namespace exprtk scand_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1) + : binary_node<T>(opr, branch0, branch1) {} inline T value() const @@ -10890,7 +11109,7 @@ namespace exprtk scor_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1) + : binary_node<T>(opr, branch0, branch1) {} inline T value() const @@ -10914,7 +11133,7 @@ namespace exprtk typedef std::pair<expression_ptr,bool> branch_t; typedef IFunction ifunction; - function_N_node(ifunction* func) + explicit function_N_node(ifunction* func) : function_((N == func->param_count) ? func : reinterpret_cast<ifunction*>(0)), parameter_count_(func->param_count) {} @@ -11192,9 +11411,9 @@ namespace exprtk private: - ifunction* function_; + ifunction* function_; std::size_t parameter_count_; - branch_t branch_[N]; + branch_t branch_[N]; }; template <typename T, typename IFunction> @@ -11205,7 +11424,7 @@ namespace exprtk typedef expression_node<T>* expression_ptr; typedef IFunction ifunction; - function_N_node(ifunction* func) + explicit function_N_node(ifunction* func) : function_((0 == func->param_count) ? func : reinterpret_cast<ifunction*>(0)) {} @@ -11253,8 +11472,7 @@ namespace exprtk { if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) { - delete arg_list_[i]; - arg_list_[i] = 0; + destroy_node(arg_list_[i]); } } } @@ -11349,6 +11567,7 @@ namespace exprtk ts.size = vi->size(); ts.data = vi->vds().data(); ts.type = type_store_t::e_vector; + vi->vec()->vec_holder().set_ref(&ts.vec_data); } #ifndef exprtk_disable_string_capabilities else if (is_generally_string_node(arg_list_[i])) @@ -11359,7 +11578,7 @@ namespace exprtk return false; ts.size = sbn->size(); - ts.data = reinterpret_cast<void*>(const_cast<char*>(sbn->base())); + ts.data = reinterpret_cast<void*>(const_cast<char_ptr>(sbn->base())); ts.type = type_store_t::e_string; range_list_[i].data = ts.data; @@ -11380,7 +11599,7 @@ namespace exprtk ) { ts.size = rp.const_size(); - ts.data = static_cast<char*>(ts.data) + rp.n0_c.second; + ts.data = static_cast<char_ptr>(ts.data) + rp.n0_c.second; range_list_[i].range = reinterpret_cast<range_t*>(0); } else @@ -11462,10 +11681,10 @@ namespace exprtk ts.size = rp.cache_size(); #ifndef exprtk_disable_string_capabilities if (ts.type == type_store_t::e_string) - ts.data = const_cast<char*>(rdt.str_node->base()) + rp.cache.first; + ts.data = const_cast<char_ptr>(rdt.str_node->base()) + rp.cache.first; else #endif - ts.data = static_cast<char*>(rdt.data) + (rp.cache.first * rdt.type_size); + ts.data = static_cast<char_ptr>(rdt.data) + (rp.cache.first * rdt.type_size); } else return false; @@ -11481,9 +11700,9 @@ namespace exprtk private: std::vector<expression_ptr> arg_list_; - std::vector<branch_t> branch_; - mutable tmp_vs_t expr_as_vec1_store_; - mutable range_list_t range_list_; + std::vector<branch_t> branch_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; }; #ifndef exprtk_disable_string_capabilities @@ -11514,16 +11733,14 @@ namespace exprtk inline T value() const { - T result = std::numeric_limits<T>::quiet_NaN(); - if (gen_function_t::function_) { if (gen_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; - result = (*gen_function_t::function_)(ret_string_, - parameter_list_t(gen_function_t::typestore_list_)); + const T result = (*gen_function_t::function_) + (ret_string_, parameter_list_t(gen_function_t::typestore_list_)); range_.n1_c.second = ret_string_.size() - 1; range_.cache.second = range_.n1_c.second; @@ -11532,7 +11749,7 @@ namespace exprtk } } - return result; + return std::numeric_limits<T>::quiet_NaN(); } inline typename expression_node<T>::node_type type() const @@ -11545,7 +11762,7 @@ namespace exprtk return ret_string_; } - const char* base() const + char_cptr base() const { return &ret_string_[0]; } @@ -11589,8 +11806,6 @@ namespace exprtk inline T value() const { - T result = std::numeric_limits<T>::quiet_NaN(); - if (gen_function_t::function_) { if (gen_function_t::populate_value_list()) @@ -11602,7 +11817,7 @@ namespace exprtk } } - return result; + return std::numeric_limits<T>::quiet_NaN(); } inline typename expression_node<T>::node_type type() const @@ -11633,17 +11848,15 @@ namespace exprtk inline T value() const { - T result = std::numeric_limits<T>::quiet_NaN(); - if (str_function_t::function_) { if (str_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; - result = (*str_function_t::function_)(param_seq_index_, - str_function_t::ret_string_, - parameter_list_t(str_function_t::typestore_list_)); + const T result = (*str_function_t::function_)(param_seq_index_, + str_function_t::ret_string_, + parameter_list_t(str_function_t::typestore_list_)); str_function_t::range_.n1_c.second = str_function_t::ret_string_.size() - 1; str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; @@ -11652,7 +11865,7 @@ namespace exprtk } } - return result; + return std::numeric_limits<T>::quiet_NaN(); } inline typename expression_node<T>::node_type type() const @@ -11662,7 +11875,7 @@ namespace exprtk private: - std::size_t param_seq_index_; + const std::size_t param_seq_index_; }; #endif @@ -11680,7 +11893,7 @@ namespace exprtk typedef type_store<T> generic_type; typedef typename generic_type::parameter_list parameter_list_t; - inline virtual T operator()(parameter_list_t) + inline virtual T operator() (parameter_list_t) { return std::numeric_limits<T>::quiet_NaN(); } @@ -11740,9 +11953,9 @@ namespace exprtk typedef results_context<T> results_context_t; return_envelope_node(expression_ptr body, results_context_t& rc) - : results_context_(&rc), + : results_context_(&rc ), return_invoked_ (false), - body_ (body), + body_ (body ), body_deletable_ (branch_deletable(body_)) {} @@ -11750,7 +11963,7 @@ namespace exprtk { if (body_ && body_deletable_) { - delete body_; + destroy_node(body_); } } @@ -11785,7 +11998,7 @@ namespace exprtk results_context_t* results_context_; mutable bool return_invoked_; expression_ptr body_; - bool body_deletable_; + const bool body_deletable_; }; #endif @@ -11857,20 +12070,21 @@ namespace exprtk template <typename T> struct opr_base { - typedef typename details::functor_t<T>::Type Type; + typedef typename details::functor_t<T>::Type Type; typedef typename details::functor_t<T>::RefType RefType; - typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; + typedef typename details::functor_t<T> functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; }; template <typename T> struct add_op : public opr_base<T> { - typedef typename opr_base<T>::Type Type; + typedef typename opr_base<T>::Type Type; typedef typename opr_base<T>::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 + t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } static inline void assign(RefType t1, Type t2) { t1 += t2; } @@ -11881,8 +12095,9 @@ namespace exprtk template <typename T> struct mul_op : public opr_base<T> { - typedef typename opr_base<T>::Type Type; + typedef typename opr_base<T>::Type Type; typedef typename opr_base<T>::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 * t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } static inline void assign(RefType t1, Type t2) { t1 *= t2; } @@ -11893,8 +12108,9 @@ namespace exprtk template <typename T> struct sub_op : public opr_base<T> { - typedef typename opr_base<T>::Type Type; + typedef typename opr_base<T>::Type Type; typedef typename opr_base<T>::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 - t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } static inline void assign(RefType t1, Type t2) { t1 -= t2; } @@ -11905,8 +12121,9 @@ namespace exprtk template <typename T> struct div_op : public opr_base<T> { - typedef typename opr_base<T>::Type Type; + typedef typename opr_base<T>::Type Type; typedef typename opr_base<T>::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 / t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } static inline void assign(RefType t1, Type t2) { t1 /= t2; } @@ -11917,8 +12134,9 @@ namespace exprtk template <typename T> struct mod_op : public opr_base<T> { - typedef typename opr_base<T>::Type Type; + typedef typename opr_base<T>::Type Type; typedef typename opr_base<T>::RefType RefType; + static inline T process(Type t1, Type t2) { return numeric::modulus<T>(t1,t2); } static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus<T>(t1,t2); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mod; } @@ -11928,8 +12146,9 @@ namespace exprtk template <typename T> struct pow_op : public opr_base<T> { - typedef typename opr_base<T>::Type Type; + typedef typename opr_base<T>::Type Type; typedef typename opr_base<T>::RefType RefType; + static inline T process(Type t1, Type t2) { return numeric::pow<T>(t1,t2); } static inline void assign(RefType t1, Type t2) { t1 = numeric::pow<T>(t1,t2); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_pow; } @@ -11940,6 +12159,7 @@ namespace exprtk struct lt_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_lt; } @@ -11950,6 +12170,7 @@ namespace exprtk struct lte_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_lte; } @@ -11960,6 +12181,7 @@ namespace exprtk struct gt_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_gt; } @@ -11970,6 +12192,7 @@ namespace exprtk struct gte_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_gte; } @@ -11990,7 +12213,8 @@ namespace exprtk struct equal_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; - static inline T process(Type t1, Type t2) { return (numeric::equal<T>(t1,t2) ? T(1) : T(0)); } + + static inline T process(Type t1, Type t2) { return numeric::equal(t1,t2); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_eq; } static inline details::operator_type operation() { return details::e_equal; } @@ -12000,6 +12224,7 @@ namespace exprtk struct ne_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return (std::not_equal_to<T>()(t1,t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_ne; } @@ -12010,6 +12235,7 @@ namespace exprtk struct and_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_and; } static inline details::operator_type operation() { return details::e_and; } @@ -12019,6 +12245,7 @@ namespace exprtk struct nand_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nand; } static inline details::operator_type operation() { return details::e_nand; } @@ -12028,6 +12255,7 @@ namespace exprtk struct or_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_or; } static inline details::operator_type operation() { return details::e_or; } @@ -12037,6 +12265,7 @@ namespace exprtk struct nor_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; } static inline details::operator_type operation() { return details::e_nor; } @@ -12046,6 +12275,7 @@ namespace exprtk struct xor_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return numeric::xor_opr<T>(t1,t2); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; } static inline details::operator_type operation() { return details::e_xor; } @@ -12055,6 +12285,7 @@ namespace exprtk struct xnor_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(Type t1, Type t2) { return numeric::xnor_opr<T>(t1,t2); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; } static inline details::operator_type operation() { return details::e_xnor; } @@ -12064,6 +12295,7 @@ namespace exprtk struct in_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); } static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_in; } @@ -12074,6 +12306,7 @@ namespace exprtk struct like_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); } static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_like; } @@ -12084,6 +12317,7 @@ namespace exprtk struct ilike_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); } static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_ilike; } @@ -12094,6 +12328,7 @@ namespace exprtk struct inrange_op : public opr_base<T> { typedef typename opr_base<T>::Type Type; + static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) { @@ -12122,7 +12357,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12163,14 +12398,14 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]); + value(arg_list[2]) ; } template <typename Sequence> static inline T process_4(const Sequence& arg_list) { return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3]); + value(arg_list[2]) + value(arg_list[3]) ; } template <typename Sequence> @@ -12178,7 +12413,7 @@ namespace exprtk { return value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2]) + value(arg_list[3]) + - value(arg_list[4]); + value(arg_list[4]) ; } }; @@ -12189,7 +12424,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12230,14 +12465,14 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]); + value(arg_list[2]) ; } template <typename Sequence> static inline T process_4(const Sequence& arg_list) { return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]) * value(arg_list[3]); + value(arg_list[2]) * value(arg_list[3]) ; } template <typename Sequence> @@ -12245,7 +12480,7 @@ namespace exprtk { return value(arg_list[0]) * value(arg_list[1]) * value(arg_list[2]) * value(arg_list[3]) * - value(arg_list[4]); + value(arg_list[4]) ; } }; @@ -12256,7 +12491,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12312,7 +12547,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12383,7 +12618,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12454,7 +12689,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12468,7 +12703,7 @@ namespace exprtk { for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (std::equal_to<T>()(T(0),value(arg_list[i]))) + if (std::equal_to<T>()(T(0), value(arg_list[i]))) return T(0); } @@ -12481,15 +12716,15 @@ namespace exprtk static inline T process_1(const Sequence& arg_list) { return std::not_equal_to<T>() - (T(0),value(arg_list[0])) ? T(1) : T(0); + (T(0), value(arg_list[0])) ? T(1) : T(0); } template <typename Sequence> static inline T process_2(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) && - std::not_equal_to<T>()(T(0),value(arg_list[1])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) && + std::not_equal_to<T>()(T(0), value(arg_list[1])) ) ? T(1) : T(0); } @@ -12497,9 +12732,9 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) && - std::not_equal_to<T>()(T(0),value(arg_list[1])) && - std::not_equal_to<T>()(T(0),value(arg_list[2])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) && + std::not_equal_to<T>()(T(0), value(arg_list[1])) && + std::not_equal_to<T>()(T(0), value(arg_list[2])) ) ? T(1) : T(0); } @@ -12507,10 +12742,10 @@ namespace exprtk static inline T process_4(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) && - std::not_equal_to<T>()(T(0),value(arg_list[1])) && - std::not_equal_to<T>()(T(0),value(arg_list[2])) && - std::not_equal_to<T>()(T(0),value(arg_list[3])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) && + std::not_equal_to<T>()(T(0), value(arg_list[1])) && + std::not_equal_to<T>()(T(0), value(arg_list[2])) && + std::not_equal_to<T>()(T(0), value(arg_list[3])) ) ? T(1) : T(0); } @@ -12518,11 +12753,11 @@ namespace exprtk static inline T process_5(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) && - std::not_equal_to<T>()(T(0),value(arg_list[1])) && - std::not_equal_to<T>()(T(0),value(arg_list[2])) && - std::not_equal_to<T>()(T(0),value(arg_list[3])) && - std::not_equal_to<T>()(T(0),value(arg_list[4])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) && + std::not_equal_to<T>()(T(0), value(arg_list[1])) && + std::not_equal_to<T>()(T(0), value(arg_list[2])) && + std::not_equal_to<T>()(T(0), value(arg_list[3])) && + std::not_equal_to<T>()(T(0), value(arg_list[4])) ) ? T(1) : T(0); } }; @@ -12534,7 +12769,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12548,7 +12783,7 @@ namespace exprtk { for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (std::not_equal_to<T>()(T(0),value(arg_list[i]))) + if (std::not_equal_to<T>()(T(0), value(arg_list[i]))) return T(1); } @@ -12561,15 +12796,15 @@ namespace exprtk static inline T process_1(const Sequence& arg_list) { return std::not_equal_to<T>() - (T(0),value(arg_list[0])) ? T(1) : T(0); + (T(0), value(arg_list[0])) ? T(1) : T(0); } template <typename Sequence> static inline T process_2(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) || - std::not_equal_to<T>()(T(0),value(arg_list[1])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) || + std::not_equal_to<T>()(T(0), value(arg_list[1])) ) ? T(1) : T(0); } @@ -12577,9 +12812,9 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) || - std::not_equal_to<T>()(T(0),value(arg_list[1])) || - std::not_equal_to<T>()(T(0),value(arg_list[2])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) || + std::not_equal_to<T>()(T(0), value(arg_list[1])) || + std::not_equal_to<T>()(T(0), value(arg_list[2])) ) ? T(1) : T(0); } @@ -12587,10 +12822,10 @@ namespace exprtk static inline T process_4(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) || - std::not_equal_to<T>()(T(0),value(arg_list[1])) || - std::not_equal_to<T>()(T(0),value(arg_list[2])) || - std::not_equal_to<T>()(T(0),value(arg_list[3])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) || + std::not_equal_to<T>()(T(0), value(arg_list[1])) || + std::not_equal_to<T>()(T(0), value(arg_list[2])) || + std::not_equal_to<T>()(T(0), value(arg_list[3])) ) ? T(1) : T(0); } @@ -12598,11 +12833,11 @@ namespace exprtk static inline T process_5(const Sequence& arg_list) { return ( - std::not_equal_to<T>()(T(0),value(arg_list[0])) || - std::not_equal_to<T>()(T(0),value(arg_list[1])) || - std::not_equal_to<T>()(T(0),value(arg_list[2])) || - std::not_equal_to<T>()(T(0),value(arg_list[3])) || - std::not_equal_to<T>()(T(0),value(arg_list[4])) + std::not_equal_to<T>()(T(0), value(arg_list[0])) || + std::not_equal_to<T>()(T(0), value(arg_list[1])) || + std::not_equal_to<T>()(T(0), value(arg_list[2])) || + std::not_equal_to<T>()(T(0), value(arg_list[3])) || + std::not_equal_to<T>()(T(0), value(arg_list[4])) ) ? T(1) : T(0); } }; @@ -12614,7 +12849,7 @@ namespace exprtk template <typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> static inline T process(const Sequence<Type,Allocator>& arg_list) { switch (arg_list.size()) @@ -12734,6 +12969,7 @@ namespace exprtk T result = T(0); int i = 0; + exprtk_disable_fallthrough_begin switch (vec_size) { #define case_stmt(N) \ @@ -12750,6 +12986,7 @@ namespace exprtk case_stmt( 4) case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef case_stmt @@ -12784,6 +13021,7 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ @@ -12800,6 +13038,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -12831,6 +13070,7 @@ namespace exprtk T result = T(1); int i = 0; + exprtk_disable_fallthrough_begin switch (vec_size) { #define case_stmt(N) \ @@ -12847,6 +13087,7 @@ namespace exprtk case_stmt( 4) case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef case_stmt @@ -12881,6 +13122,7 @@ namespace exprtk int i = 0; + exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ @@ -12897,6 +13139,7 @@ namespace exprtk case_stmt( 3) case_stmt( 2) case_stmt( 1) } + exprtk_disable_fallthrough_end #undef exprtk_loop #undef case_stmt @@ -13210,9 +13453,9 @@ namespace exprtk ufunc_t uf0, ufunc_t uf1, bfunc_t bf) : v0_(var0), v1_(var1), - u0_(uf0), - u1_(uf1), - f_ (bf) + u0_(uf0 ), + u1_(uf1 ), + f_ (bf ) {} inline T value() const @@ -13284,8 +13527,7 @@ namespace exprtk { if (branch_ && branch_deletable_) { - delete branch_; - branch_ = 0; + destroy_node(branch_); } } @@ -13507,15 +13749,15 @@ namespace exprtk template <typename T, typename T0, typename T1> \ const typename expression_node<T>::node_type nodetype_T0oT1<T,T0_,T1_>::result = expression_node<T>:: v_; \ - synthesis_node_type_define(const T0&,const T1&, e_vov) - synthesis_node_type_define(const T0&,const T1 , e_voc) - synthesis_node_type_define(const T0 ,const T1&, e_cov) - synthesis_node_type_define( T0&, T1&,e_none) - synthesis_node_type_define(const T0 ,const T1 ,e_none) - synthesis_node_type_define( T0&,const T1 ,e_none) - synthesis_node_type_define(const T0 , T1&,e_none) - synthesis_node_type_define(const T0&, T1&,e_none) - synthesis_node_type_define( T0&,const T1&,e_none) + synthesis_node_type_define(const T0&, const T1&, e_vov) + synthesis_node_type_define(const T0&, const T1 , e_voc) + synthesis_node_type_define(const T0 , const T1&, e_cov) + synthesis_node_type_define( T0&, T1&, e_none) + synthesis_node_type_define(const T0 , const T1 , e_none) + synthesis_node_type_define( T0&, const T1 , e_none) + synthesis_node_type_define(const T0 , T1&, e_none) + synthesis_node_type_define(const T0&, T1&, e_none) + synthesis_node_type_define( T0&, const T1&, e_none) #undef synthesis_node_type_define template <typename T, typename T0, typename T1, typename T2> @@ -13529,15 +13771,15 @@ namespace exprtk template <typename T, typename T0, typename T1, typename T2> \ const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0_,T1_,T2_>::result = expression_node<T>:: v_; \ - synthesis_node_type_define(const T0&,const T1&,const T2&, e_vovov) - synthesis_node_type_define(const T0&,const T1&,const T2 , e_vovoc) - synthesis_node_type_define(const T0&,const T1 ,const T2&, e_vocov) - synthesis_node_type_define(const T0 ,const T1&,const T2&, e_covov) - synthesis_node_type_define(const T0 ,const T1&,const T2 , e_covoc) - synthesis_node_type_define(const T0 ,const T1 ,const T2 , e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2&, e_none ) - synthesis_node_type_define(const T0&,const T1 ,const T2 , e_none ) - synthesis_node_type_define( T0&, T1&, T2&, e_none ) + synthesis_node_type_define(const T0&, const T1&, const T2&, e_vovov) + synthesis_node_type_define(const T0&, const T1&, const T2 , e_vovoc) + synthesis_node_type_define(const T0&, const T1 , const T2&, e_vocov) + synthesis_node_type_define(const T0 , const T1&, const T2&, e_covov) + synthesis_node_type_define(const T0 , const T1&, const T2 , e_covoc) + synthesis_node_type_define(const T0 , const T1 , const T2 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, e_none ) + synthesis_node_type_define(const T0&, const T1 , const T2 , e_none ) + synthesis_node_type_define( T0&, T1&, T2&, e_none ) #undef synthesis_node_type_define template <typename T, typename T0, typename T1, typename T2, typename T3> @@ -13551,22 +13793,22 @@ namespace exprtk template <typename T, typename T0, typename T1, typename T2, typename T3> \ const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_>::result = expression_node<T>:: v_; \ - synthesis_node_type_define(const T0&,const T1&,const T2&, const T3&,e_vovovov) - synthesis_node_type_define(const T0&,const T1&,const T2&, const T3 ,e_vovovoc) - synthesis_node_type_define(const T0&,const T1&,const T2 , const T3&,e_vovocov) - synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3&,e_vocovov) - synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3&,e_covovov) - synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3&,e_covocov) - synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3 ,e_vocovoc) - synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3 ,e_covovoc) - synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3&,e_vococov) - synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3 ,e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3&,e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3 ,e_none ) - synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3 ,e_none ) - synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3 ,e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3&,e_none ) - synthesis_node_type_define(const T0&,const T1&,const T2 , const T3 ,e_none ) + synthesis_node_type_define(const T0&, const T1&, const T2&, const T3&, e_vovovov) + synthesis_node_type_define(const T0&, const T1&, const T2&, const T3 , e_vovovoc) + synthesis_node_type_define(const T0&, const T1&, const T2 , const T3&, e_vovocov) + synthesis_node_type_define(const T0&, const T1 , const T2&, const T3&, e_vocovov) + synthesis_node_type_define(const T0 , const T1&, const T2&, const T3&, e_covovov) + synthesis_node_type_define(const T0 , const T1&, const T2 , const T3&, e_covocov) + synthesis_node_type_define(const T0&, const T1 , const T2&, const T3 , e_vocovoc) + synthesis_node_type_define(const T0 , const T1&, const T2&, const T3 , e_covovoc) + synthesis_node_type_define(const T0&, const T1 , const T2 , const T3&, e_vococov) + synthesis_node_type_define(const T0 , const T1 , const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2 , const T3&, e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1&, const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0&, const T1 , const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, const T3&, e_none ) + synthesis_node_type_define(const T0&, const T1&, const T2 , const T3 , e_none ) #undef synthesis_node_type_define template <typename T, typename T0, typename T1> @@ -13621,13 +13863,15 @@ namespace exprtk T0 p0, T1 p1, bfunc_t p2) { - return allocator.template allocate_type<node_type,T0,T1,bfunc_t&>(p0,p1,p2); + return allocator + .template allocate_type<node_type, T0, T1, bfunc_t&> + (p0, p1, p2); } private: T0oT1(T0oT1<T,T0,T1>&) {} - T0oT1<T,T0,T1>& operator=(T0oT1<T,T0,T1>&) { return *this; } + T0oT1<T,T0,T1>& operator=(T0oT1<T,T0,T1>&) { return (*this); } T0 t0_; T1 t1_; @@ -13666,7 +13910,7 @@ namespace exprtk inline T value() const { - return ProcessMode::process(t0_,t1_,t2_,f0_,f1_); + return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); } inline T0 t0() const @@ -13707,13 +13951,15 @@ namespace exprtk template <typename Allocator> static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) { - return allocator.template allocate_type<node_type,T0,T1,T2,bfunc_t,bfunc_t>(p0,p1,p2,p3,p4); + return allocator + .template allocate_type<node_type, T0, T1, T2, bfunc_t, bfunc_t> + (p0, p1, p2, p3, p4); } private: T0oT1oT2(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -13749,7 +13995,7 @@ namespace exprtk inline T value() const { - return ProcessMode::process(t0_,t1_,t2_,t3_,f0_,f1_,f2_); + return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); } inline T0 t0() const @@ -13794,7 +14040,7 @@ namespace exprtk static inline std::string id() { - return process_mode_t::template id<T0,T1,T2,T3>(); + return process_mode_t::template id<T0, T1, T2, T3>(); } template <typename Allocator> @@ -13802,13 +14048,15 @@ namespace exprtk T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) { - return allocator.template allocate_type<node_type,T0,T1,T2,T3,bfunc_t,bfunc_t>(p0,p1,p2,p3,p4,p5,p6); + return allocator + .template allocate_type<node_type, T0, T1, T2, T3, bfunc_t, bfunc_t> + (p0, p1, p2, p3, p4, p5, p6); } private: T0oT1oT2oT3(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -13849,7 +14097,7 @@ namespace exprtk inline T value() const { - return f_(t0_,t1_,t2_); + return f_(t0_, t1_, t2_); } inline T0 t0() const @@ -13885,13 +14133,15 @@ namespace exprtk template <typename Allocator> static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) { - return allocator.template allocate_type<node_type,T0,T1,T2,tfunc_t>(p0,p1,p2,p3); + return allocator + .template allocate_type<node_type, T0, T1, T2, tfunc_t> + (p0, p1, p2, p3); } private: T0oT1oT2_sf3(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -13943,7 +14193,7 @@ namespace exprtk inline T value() const { - return SF3Operation::process(t0_,t1_,t2_); + return SF3Operation::process(t0_, t1_, t2_); } T0 t0() const @@ -13974,13 +14224,15 @@ namespace exprtk template <typename Allocator> static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) { - return allocator.template allocate_type<node_type,T0,T1,T2>(p0,p1,p2); + return allocator + .template allocate_type<node_type, T0, T1, T2> + (p0, p1, p2); } private: T0oT1oT2_sf3ext(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -14032,7 +14284,7 @@ namespace exprtk inline T value() const { - return f_(t0_,t1_,t2_,t3_); + return f_(t0_, t1_, t2_, t3_); } inline T0 t0() const @@ -14073,13 +14325,15 @@ namespace exprtk template <typename Allocator> static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) { - return allocator.template allocate_type<node_type,T0,T1,T2,T3,qfunc_t>(p0,p1,p2,p3,p4); + return allocator + .template allocate_type<node_type, T0, T1, T2, T3, qfunc_t> + (p0, p1, p2, p3, p4); } private: T0oT1oT2oT3_sf4(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -14118,7 +14372,7 @@ namespace exprtk inline T value() const { - return SF4Operation::process(t0_,t1_,t2_,t3_); + return SF4Operation::process(t0_, t1_, t2_, t3_); } inline T0 t0() const @@ -14138,7 +14392,7 @@ namespace exprtk inline T3 t3() const { - return t2_; + return t3_; } std::string type_id() const @@ -14154,13 +14408,15 @@ namespace exprtk template <typename Allocator> static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) { - return allocator.template allocate_type<node_type,T0,T1,T2,T3>(p0,p1,p2,p3); + return allocator + .template allocate_type<node_type, T0, T1, T2, T3> + (p0, p1, p2, p3); } private: T0oT1oT2oT3_sf4ext(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -14189,27 +14445,27 @@ namespace exprtk template <typename T, typename T0, typename T1> struct T0oT1_define { - typedef details::T0oT1<T,T0,T1> type0; + typedef details::T0oT1<T, T0, T1> type0; }; template <typename T, typename T0, typename T1, typename T2> struct T0oT1oT2_define { - typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode0> type0; - typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode1> type1; - typedef details::T0oT1oT2_sf3<T,T0,T1,T2> sf3_type; - typedef details::sf3ext_type_node<T,T0,T1,T2> sf3_type_node; + typedef details::T0oT1oT2<T, T0, T1, T2, typename T0oT1oT2process<T>::mode0> type0; + typedef details::T0oT1oT2<T, T0, T1, T2, typename T0oT1oT2process<T>::mode1> type1; + typedef details::T0oT1oT2_sf3<T, T0, T1, T2> sf3_type; + typedef details::sf3ext_type_node<T, T0, T1, T2> sf3_type_node; }; template <typename T, typename T0, typename T1, typename T2, typename T3> struct T0oT1oT2oT3_define { - typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode0> type0; - typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode1> type1; - typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode2> type2; - typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode3> type3; - typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode4> type4; - typedef details::T0oT1oT2oT3_sf4<T,T0,T1,T2,T3> sf4_type; + typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode0> type0; + typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode1> type1; + typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode2> type2; + typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode3> type3; + typedef details::T0oT1oT2oT3<T, T0, T1, T2, T3, typename T0oT1oT20T3process<T>::mode4> type4; + typedef details::T0oT1oT2oT3_sf4<T, T0, T1, T2, T3> sf4_type; }; template <typename T, typename Operation> @@ -14514,7 +14770,7 @@ namespace exprtk cob_node(const cob_node<T,Operation>&); cob_node<T,Operation>& operator=(const cob_node<T,Operation>&); - const T c_; + const T c_; branch_t branch_[1]; }; @@ -14575,7 +14831,7 @@ namespace exprtk boc_node(const boc_node<T,Operation>&); boc_node<T,Operation>& operator=(const boc_node<T,Operation>&); - const T c_; + const T c_; branch_t branch_[1]; }; @@ -14640,8 +14896,8 @@ namespace exprtk // string-range op string node explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) - : s0_(p0), - s1_(p1), + : s0_ (p0 ), + s1_ (p1 ), rp0_(rp0) {} @@ -14655,8 +14911,8 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - if (rp0_(r0,r1,s0_.size())) - return Operation::process(s0_.substr(r0,(r1 - r0) + 1),s1_); + if (rp0_(r0, r1, s0_.size())) + return Operation::process(s0_.substr(r0, (r1 - r0) + 1), s1_); else return T(0); } @@ -14718,8 +14974,8 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - if (rp1_(r0,r1,s1_.size())) - return Operation::process(s0_,s1_.substr(r0,(r1 - r0) + 1)); + if (rp1_(r0, r1, s1_.size())) + return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1)); else return T(0); } @@ -14784,14 +15040,15 @@ namespace exprtk std::size_t r0_1 = 0; std::size_t r1_0 = 0; std::size_t r1_1 = 0; + if ( - rp0_(r0_0,r1_0,s0_.size()) && - rp1_(r0_1,r1_1,s1_.size()) + rp0_(r0_0, r1_0, s0_.size()) && + rp1_(r0_1, r1_1, s1_.size()) ) { return Operation::process( - s0_.substr(r0_0,(r1_0 - r0_0) + 1), - s1_.substr(r0_1,(r1_1 - r0_1) + 1) + s0_.substr(r0_0, (r1_0 - r0_0) + 1), + s1_.substr(r0_1, (r1_1 - r0_1) + 1) ); } else @@ -14846,7 +15103,7 @@ namespace exprtk str_sogens_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node<T>(opr,branch0,branch1), + : binary_node<T>(opr, branch0, branch1), str0_base_ptr_ (0), str1_base_ptr_ (0), str0_range_ptr_(0), @@ -14859,12 +15116,12 @@ namespace exprtk if (0 == str0_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); + irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first); - if (0 == range_ptr) + if (0 == range) return; - str0_range_ptr_ = &(range_ptr->range_ref()); + str0_range_ptr_ = &(range->range_ref()); } if (is_generally_string_node(binary_node<T>::branch_[1].first)) @@ -14874,12 +15131,12 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); + irange_ptr range = dynamic_cast<irange_ptr>(binary_node<T>::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } } @@ -14905,8 +15162,8 @@ namespace exprtk range_t& range1 = (*str1_range_ptr_); if ( - range0(str0_r0,str0_r1,str0_base_ptr_->size()) && - range1(str1_r0,str1_r1,str1_base_ptr_->size()) + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) ) { return Operation::process( @@ -15278,134 +15535,134 @@ namespace exprtk template <typename ResultNode, typename OpType, typename ExprNode> inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[1]) { - return allocate<ResultNode>(operation,branch[0]); + return allocate<ResultNode>(operation, branch[0]); } template <typename ResultNode, typename OpType, typename ExprNode> inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[2]) { - return allocate<ResultNode>(operation,branch[0],branch[1]); + return allocate<ResultNode>(operation, branch[0], branch[1]); } template <typename ResultNode, typename OpType, typename ExprNode> inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[3]) { - return allocate<ResultNode>(operation,branch[0],branch[1],branch[2]); + return allocate<ResultNode>(operation, branch[0], branch[1], branch[2]); } template <typename ResultNode, typename OpType, typename ExprNode> inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[4]) { - return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3]); + return allocate<ResultNode>(operation, branch[0], branch[1], branch[2], branch[3]); } template <typename ResultNode, typename OpType, typename ExprNode> inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[5]) { - return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4]); + return allocate<ResultNode>(operation, branch[0],branch[1], branch[2], branch[3], branch[4]); } template <typename ResultNode, typename OpType, typename ExprNode> inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[6]) { - return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4],branch[5]); + return allocate<ResultNode>(operation, branch[0], branch[1], branch[2], branch[3], branch[4], branch[5]); } template <typename node_type> inline expression_node<typename node_type::value_type>* allocate() const { - return new node_type(); + return (new node_type()); } template <typename node_type, typename Type, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node<typename node_type::value_type>* allocate(const Sequence<Type,Allocator>& seq) const { - return new node_type(seq); + return (new node_type(seq)); } template <typename node_type, typename T1> inline expression_node<typename node_type::value_type>* allocate(T1& t1) const { - return new node_type(t1); + return (new node_type(t1)); } template <typename node_type, typename T1> inline expression_node<typename node_type::value_type>* allocate_c(const T1& t1) const { - return new node_type(t1); + return (new node_type(t1)); } template <typename node_type, typename T1, typename T2> inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2) const { - return new node_type(t1,t2); + return (new node_type(t1, t2)); } template <typename node_type, typename T1, typename T2> inline expression_node<typename node_type::value_type>* allocate_cr(const T1& t1, T2& t2) const { - return new node_type(t1,t2); + return (new node_type(t1, t2)); } template <typename node_type, typename T1, typename T2> inline expression_node<typename node_type::value_type>* allocate_rc(T1& t1, const T2& t2) const { - return new node_type(t1,t2); + return (new node_type(t1, t2)); } template <typename node_type, typename T1, typename T2> inline expression_node<typename node_type::value_type>* allocate_rr(T1& t1, T2& t2) const { - return new node_type(t1,t2); + return (new node_type(t1, t2)); } template <typename node_type, typename T1, typename T2> inline expression_node<typename node_type::value_type>* allocate_tt(T1 t1, T2 t2) const { - return new node_type(t1,t2); + return (new node_type(t1, t2)); } template <typename node_type, typename T1, typename T2, typename T3> inline expression_node<typename node_type::value_type>* allocate_ttt(T1 t1, T2 t2, T3 t3) const { - return new node_type(t1,t2,t3); + return (new node_type(t1, t2, t3)); } template <typename node_type, typename T1, typename T2, typename T3, typename T4> inline expression_node<typename node_type::value_type>* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const { - return new node_type(t1,t2,t3,t4); + return (new node_type(t1, t2, t3, t4)); } template <typename node_type, typename T1, typename T2, typename T3> inline expression_node<typename node_type::value_type>* allocate_rrr(T1& t1, T2& t2, T3& t3) const { - return new node_type(t1,t2,t3); + return (new node_type(t1, t2, t3)); } template <typename node_type, typename T1, typename T2, typename T3, typename T4> inline expression_node<typename node_type::value_type>* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const { - return new node_type(t1,t2,t3,t4); + return (new node_type(t1, t2, t3, t4)); } template <typename node_type, typename T1, typename T2, typename T3, typename T4, typename T5> inline expression_node<typename node_type::value_type>* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const { - return new node_type(t1,t2,t3,t4,t5); + return (new node_type(t1, t2, t3, t4, t5)); } template <typename node_type, @@ -15413,7 +15670,7 @@ namespace exprtk inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, const T3& t3) const { - return new node_type(t1,t2,t3); + return (new node_type(t1, t2, t3)); } template <typename node_type, @@ -15422,7 +15679,7 @@ namespace exprtk inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4) const { - return new node_type(t1,t2,t3,t4); + return (new node_type(t1, t2, t3, t4)); } template <typename node_type, @@ -15432,7 +15689,7 @@ namespace exprtk const T3& t3, const T4& t4, const T5& t5) const { - return new node_type(t1,t2,t3,t4,t5); + return (new node_type(t1, t2, t3, t4, t5)); } template <typename node_type, @@ -15442,7 +15699,7 @@ namespace exprtk const T3& t3, const T4& t4, const T5& t5, const T6& t6) const { - return new node_type(t1,t2,t3,t4,t5,t6); + return (new node_type(t1, t2, t3, t4, t5, t6)); } template <typename node_type, @@ -15454,7 +15711,7 @@ namespace exprtk const T5& t5, const T6& t6, const T7& t7) const { - return new node_type(t1,t2,t3,t4,t5,t6,t7); + return (new node_type(t1, t2, t3, t4, t5, t6, t7)); } template <typename node_type, @@ -15467,7 +15724,7 @@ namespace exprtk const T5& t5, const T6& t6, const T7& t7, const T8& t8) const { - return new node_type(t1,t2,t3,t4,t5,t6,t7,t8); + return (new node_type(t1, t2, t3, t4, t5, t6, t7, t8)); } template <typename node_type, @@ -15481,7 +15738,7 @@ namespace exprtk const T7& t7, const T8& t8, const T9& t9) const { - return new node_type(t1,t2,t3,t4,t5,t6,t7,t8,t9); + return (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9)); } template <typename node_type, @@ -15496,14 +15753,14 @@ namespace exprtk const T7& t7, const T8& t8, const T9& t9, const T10& t10) const { - return new node_type(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10); + return (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); } template <typename node_type, typename T1, typename T2, typename T3> inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, T3 t3) const { - return new node_type(t1,t2,t3); + return (new node_type(t1, t2, t3)); } template <typename node_type, @@ -15512,7 +15769,7 @@ namespace exprtk inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4) const { - return new node_type(t1,t2,t3,t4); + return (new node_type(t1, t2, t3, t4)); } template <typename node_type, @@ -15523,7 +15780,18 @@ namespace exprtk T3 t3, T4 t4, T5 t5) const { - return new node_type(t1,t2,t3,t4,t5); + return (new node_type(t1, t2, t3, t4, t5)); + } + + template <typename node_type, + typename T1, typename T2, + typename T3, typename T4, + typename T5, typename T6> + inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5, T6 t6) const + { + return (new node_type(t1, t2, t3, t4, t5, t6)); } template <typename node_type, @@ -15535,7 +15803,7 @@ namespace exprtk T5 t5, T6 t6, T7 t7) const { - return new node_type(t1,t2,t3,t4,t5,t6,t7); + return (new node_type(t1, t2, t3, t4, t5, t6, t7)); } template <typename T> @@ -15551,58 +15819,58 @@ namespace exprtk #define register_op(Symbol,Type,Args) \ m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ - register_op( "abs",e_abs , 1) - register_op( "acos",e_acos , 1) - register_op( "acosh",e_acosh , 1) - register_op( "asin",e_asin , 1) - register_op( "asinh",e_asinh , 1) - register_op( "atan",e_atan , 1) - register_op( "atanh",e_atanh , 1) - register_op( "ceil",e_ceil , 1) - register_op( "cos",e_cos , 1) - register_op( "cosh",e_cosh , 1) - register_op( "exp",e_exp , 1) - register_op( "expm1",e_expm1 , 1) - register_op( "floor",e_floor , 1) - register_op( "log",e_log , 1) - register_op( "log10",e_log10 , 1) - register_op( "log2",e_log2 , 1) - register_op( "log1p",e_log1p , 1) - register_op( "round",e_round , 1) - register_op( "sin",e_sin , 1) - register_op( "sinc",e_sinc , 1) - register_op( "sinh",e_sinh , 1) - register_op( "sec",e_sec , 1) - register_op( "csc",e_csc , 1) - register_op( "sqrt",e_sqrt , 1) - register_op( "tan",e_tan , 1) - register_op( "tanh",e_tanh , 1) - register_op( "cot",e_cot , 1) - register_op( "rad2deg",e_r2d , 1) - register_op( "deg2rad",e_d2r , 1) - register_op( "deg2grad",e_d2g , 1) - register_op( "grad2deg",e_g2d , 1) - register_op( "sgn",e_sgn , 1) - register_op( "not",e_notl , 1) - register_op( "erf",e_erf , 1) - register_op( "erfc",e_erfc , 1) - register_op( "ncdf",e_ncdf , 1) - register_op( "frac",e_frac , 1) - register_op( "trunc",e_trunc , 1) - register_op( "atan2",e_atan2 , 2) - register_op( "mod",e_mod , 2) - register_op( "logn",e_logn , 2) - register_op( "pow",e_pow , 2) - register_op( "root",e_root , 2) - register_op( "roundn",e_roundn , 2) - register_op( "equal",e_equal , 2) - register_op("not_equal",e_nequal , 2) - register_op( "hypot",e_hypot , 2) - register_op( "shr",e_shr , 2) - register_op( "shl",e_shl , 2) - register_op( "clamp",e_clamp , 3) - register_op( "iclamp",e_iclamp , 3) - register_op( "inrange",e_inrange , 3) + register_op( "abs", e_abs , 1) + register_op( "acos", e_acos , 1) + register_op( "acosh", e_acosh , 1) + register_op( "asin", e_asin , 1) + register_op( "asinh", e_asinh , 1) + register_op( "atan", e_atan , 1) + register_op( "atanh", e_atanh , 1) + register_op( "ceil", e_ceil , 1) + register_op( "cos", e_cos , 1) + register_op( "cosh", e_cosh , 1) + register_op( "exp", e_exp , 1) + register_op( "expm1", e_expm1 , 1) + register_op( "floor", e_floor , 1) + register_op( "log", e_log , 1) + register_op( "log10", e_log10 , 1) + register_op( "log2", e_log2 , 1) + register_op( "log1p", e_log1p , 1) + register_op( "round", e_round , 1) + register_op( "sin", e_sin , 1) + register_op( "sinc", e_sinc , 1) + register_op( "sinh", e_sinh , 1) + register_op( "sec", e_sec , 1) + register_op( "csc", e_csc , 1) + register_op( "sqrt", e_sqrt , 1) + register_op( "tan", e_tan , 1) + register_op( "tanh", e_tanh , 1) + register_op( "cot", e_cot , 1) + register_op( "rad2deg", e_r2d , 1) + register_op( "deg2rad", e_d2r , 1) + register_op( "deg2grad", e_d2g , 1) + register_op( "grad2deg", e_g2d , 1) + register_op( "sgn", e_sgn , 1) + register_op( "not", e_notl , 1) + register_op( "erf", e_erf , 1) + register_op( "erfc", e_erfc , 1) + register_op( "ncdf", e_ncdf , 1) + register_op( "frac", e_frac , 1) + register_op( "trunc", e_trunc , 1) + register_op( "atan2", e_atan2 , 2) + register_op( "mod", e_mod , 2) + register_op( "logn", e_logn , 2) + register_op( "pow", e_pow , 2) + register_op( "root", e_root , 2) + register_op( "roundn", e_roundn , 2) + register_op( "equal", e_equal , 2) + register_op("not_equal", e_nequal , 2) + register_op( "hypot", e_hypot , 2) + register_op( "shr", e_shr , 2) + register_op( "shl", e_shl , 2) + register_op( "clamp", e_clamp , 3) + register_op( "iclamp", e_iclamp , 3) + register_op( "inrange", e_inrange , 3) #undef register_op } @@ -15708,77 +15976,77 @@ namespace exprtk return std::numeric_limits<T>::quiet_NaN(); \ } \ - inline virtual T operator()() + inline virtual T operator() () empty_method_body - inline virtual T operator()(const T&) + inline virtual T operator() (const T&) empty_method_body - inline virtual T operator()(const T&,const T&) + inline virtual T operator() (const T&,const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) empty_method_body #undef empty_method_body @@ -15794,7 +16062,7 @@ namespace exprtk virtual ~ivararg_function() {} - inline virtual T operator()(const std::vector<T>&) + inline virtual T operator() (const std::vector<T>&) { exprtk_debug(("ivararg_function::operator() - Operator has not been overridden.\n")); return std::numeric_limits<T>::quiet_NaN(); @@ -15808,8 +16076,9 @@ namespace exprtk enum return_type { - e_rtrn_scalar = 0, - e_rtrn_string = 1 + e_rtrn_scalar = 0, + e_rtrn_string = 1, + e_rtrn_overload = 2 }; typedef T type; @@ -15831,19 +16100,19 @@ namespace exprtk } \ // f(i_0,i_1,....,i_N) --> Scalar - inline virtual T operator()(parameter_list_t) + inline virtual T operator() (parameter_list_t) igeneric_function_empty_body(1) // f(i_0,i_1,....,i_N) --> String - inline virtual T operator()(std::string&, parameter_list_t) + inline virtual T operator() (std::string&, parameter_list_t) igeneric_function_empty_body(2) // f(psi,i_0,i_1,....,i_N) --> Scalar - inline virtual T operator()(const std::size_t&, parameter_list_t) + inline virtual T operator() (const std::size_t&, parameter_list_t) igeneric_function_empty_body(3) // f(psi,i_0,i_1,....,i_N) --> String - inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) + inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) igeneric_function_empty_body(4) std::string parameter_sequence; @@ -15858,30 +16127,41 @@ namespace exprtk { public: + typedef T (*ff00_functor)(); typedef T (*ff01_functor)(T); - typedef T (*ff02_functor)(T,T); - typedef T (*ff03_functor)(T,T,T); - typedef T (*ff04_functor)(T,T,T,T); - typedef T (*ff05_functor)(T,T,T,T,T); - typedef T (*ff06_functor)(T,T,T,T,T,T); - typedef T (*ff07_functor)(T,T,T,T,T,T,T); - typedef T (*ff08_functor)(T,T,T,T,T,T,T,T); - typedef T (*ff09_functor)(T,T,T,T,T,T,T,T,T); - typedef T (*ff10_functor)(T,T,T,T,T,T,T,T,T,T); - typedef T (*ff11_functor)(T,T,T,T,T,T,T,T,T,T,T); - typedef T (*ff12_functor)(T,T,T,T,T,T,T,T,T,T,T,T); - typedef T (*ff13_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T); - typedef T (*ff14_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T,T); - typedef T (*ff15_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T,T,T); + typedef T (*ff02_functor)(T, T); + typedef T (*ff03_functor)(T, T, T); + typedef T (*ff04_functor)(T, T, T, T); + typedef T (*ff05_functor)(T, T, T, T, T); + typedef T (*ff06_functor)(T, T, T, T, T, T); + typedef T (*ff07_functor)(T, T, T, T, T, T, T); + typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); + typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); + typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); + typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); protected: + struct freefunc00 : public exprtk::ifunction<T> + { + using exprtk::ifunction<T>::operator(); + + explicit freefunc00(ff00_functor ff) : exprtk::ifunction<T>(0), f(ff) {} + inline T operator() () + { return f(); } + ff00_functor f; + }; + struct freefunc01 : public exprtk::ifunction<T> { using exprtk::ifunction<T>::operator(); - freefunc01(ff01_functor ff) : exprtk::ifunction<T>(1), f(ff) {} - inline T operator()(const T& v0) + explicit freefunc01(ff01_functor ff) : exprtk::ifunction<T>(1), f(ff) {} + inline T operator() (const T& v0) { return f(v0); } ff01_functor f; }; @@ -15890,9 +16170,9 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc02(ff02_functor ff) : exprtk::ifunction<T>(2), f(ff) {} - inline T operator()(const T& v0, const T& v1) - { return f(v0,v1); } + explicit freefunc02(ff02_functor ff) : exprtk::ifunction<T>(2), f(ff) {} + inline T operator() (const T& v0, const T& v1) + { return f(v0, v1); } ff02_functor f; }; @@ -15900,9 +16180,9 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc03(ff03_functor ff) : exprtk::ifunction<T>(3), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2) - { return f(v0,v1,v2); } + explicit freefunc03(ff03_functor ff) : exprtk::ifunction<T>(3), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2) + { return f(v0, v1, v2); } ff03_functor f; }; @@ -15910,9 +16190,9 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc04(ff04_functor ff) : exprtk::ifunction<T>(4), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3) - { return f(v0,v1,v2,v3); } + explicit freefunc04(ff04_functor ff) : exprtk::ifunction<T>(4), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) + { return f(v0, v1, v2, v3); } ff04_functor f; }; @@ -15920,9 +16200,9 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc05(ff05_functor ff) : exprtk::ifunction<T>(5), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) - { return f(v0,v1,v2,v3,v4); } + explicit freefunc05(ff05_functor ff) : exprtk::ifunction<T>(5), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + { return f(v0, v1, v2, v3, v4); } ff05_functor f; }; @@ -15930,9 +16210,9 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc06(ff06_functor ff) : exprtk::ifunction<T>(6), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) - { return f(v0,v1,v2,v3,v4,v5); } + explicit freefunc06(ff06_functor ff) : exprtk::ifunction<T>(6), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { return f(v0, v1, v2, v3, v4, v5); } ff06_functor f; }; @@ -15940,10 +16220,10 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc07(ff07_functor ff) : exprtk::ifunction<T>(7), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6) - { return f(v0,v1,v2,v3,v4,v5,v6); } + explicit freefunc07(ff07_functor ff) : exprtk::ifunction<T>(7), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6) + { return f(v0, v1, v2, v3, v4, v5, v6); } ff07_functor f; }; @@ -15951,10 +16231,10 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc08(ff08_functor ff) : exprtk::ifunction<T>(8), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7) - { return f(v0,v1,v2,v3,v4,v5,v6,v7); } + explicit freefunc08(ff08_functor ff) : exprtk::ifunction<T>(8), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7) + { return f(v0, v1, v2, v3, v4, v5, v6, v7); } ff08_functor f; }; @@ -15962,10 +16242,10 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc09(ff09_functor ff) : exprtk::ifunction<T>(9), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8) - { return f(v0,v1,v2,v3,v4,v5,v6,v7,v8); } + explicit freefunc09(ff09_functor ff) : exprtk::ifunction<T>(9), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } ff09_functor f; }; @@ -15973,10 +16253,10 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc10(ff10_functor ff) : exprtk::ifunction<T>(10), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) - { return f(v0,v1,v2,v3,v4,v5,v6,v7,v8,v9); } + explicit freefunc10(ff10_functor ff) : exprtk::ifunction<T>(10), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } ff10_functor f; }; @@ -15984,10 +16264,10 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc11(ff11_functor ff) : exprtk::ifunction<T>(11), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) - { return f(v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10); } + explicit freefunc11(ff11_functor ff) : exprtk::ifunction<T>(11), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } ff11_functor f; }; @@ -15995,11 +16275,11 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc12(ff12_functor ff) : exprtk::ifunction<T>(12), f(ff) {} - inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11) - { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11); } + explicit freefunc12(ff12_functor ff) : exprtk::ifunction<T>(12), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } ff12_functor f; }; @@ -16007,11 +16287,11 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc13(ff13_functor ff) : exprtk::ifunction<T>(13), f(ff) {} - inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12) - { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11,v12); } + explicit freefunc13(ff13_functor ff) : exprtk::ifunction<T>(13), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } ff13_functor f; }; @@ -16019,11 +16299,11 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc14(ff14_functor ff) : exprtk::ifunction<T>(14), f(ff) {} - inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13) - { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11,v12,v13); } + explicit freefunc14(ff14_functor ff) : exprtk::ifunction<T>(14), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } ff14_functor f; }; @@ -16031,11 +16311,11 @@ namespace exprtk { using exprtk::ifunction<T>::operator(); - freefunc15(ff15_functor ff) : exprtk::ifunction<T>(15), f(ff) {} - inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) - { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11,v12,v13,v14); } + explicit freefunc15(ff15_functor ff) : exprtk::ifunction<T>(15), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } ff15_functor f; }; @@ -16105,7 +16385,7 @@ namespace exprtk return false; else { - tm_const_itr_t itr = map.find(symbol_name); + const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return false; @@ -16121,14 +16401,14 @@ namespace exprtk { for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) { - if (details::imatch(symbol_name,details::reserved_symbols[i])) + if (details::imatch(symbol_name, details::reserved_symbols[i])) { return false; } } } - tm_itr_t itr = map.find(symbol_name); + const tm_itr_t itr = map.find(symbol_name); if (map.end() == itr) { @@ -16143,7 +16423,7 @@ namespace exprtk { static inline std::pair<bool,vector_t*> make(std::pair<T*,std::size_t> v, const bool is_const = false) { - return std::make_pair(is_const,new vector_t(v.first,v.second)); + return std::make_pair(is_const, new vector_t(v.first, v.second)); } }; @@ -16152,7 +16432,7 @@ namespace exprtk template <typename Allocator> static inline std::pair<bool,vector_t*> make(std::vector<T,Allocator>& v, const bool is_const = false) { - return std::make_pair(is_const,new vector_t(v)); + return std::make_pair(is_const, new vector_t(v)); } }; @@ -16160,7 +16440,7 @@ namespace exprtk { static inline std::pair<bool,vector_t*> make(exprtk::vector_view<T>& v, const bool is_const = false) { - return std::make_pair(is_const,new vector_t(v)); + return std::make_pair(is_const, new vector_t(v)); } }; @@ -16169,36 +16449,41 @@ namespace exprtk template <typename Allocator> static inline std::pair<bool,vector_t*> make(std::deque<T,Allocator>& v, const bool is_const = false) { - return std::make_pair(is_const,new vector_t(v)); + return std::make_pair(is_const, new vector_t(v)); } }; template <std::size_t v_size> inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) { - return add_impl<tie_array,std::pair<T*,std::size_t> >(symbol_name,std::make_pair(v,v_size),is_const); + return add_impl<tie_array,std::pair<T*,std::size_t> > + (symbol_name, std::make_pair(v,v_size), is_const); } inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) { - return add_impl<tie_array,std::pair<T*,std::size_t> >(symbol_name,std::make_pair(v,v_size),is_const); + return add_impl<tie_array,std::pair<T*,std::size_t> > + (symbol_name, std::make_pair(v,v_size), is_const); } template <typename Allocator> inline bool add(const std::string& symbol_name, std::vector<T,Allocator>& v, const bool is_const = false) { - return add_impl<tie_stdvec,std::vector<T,Allocator>&>(symbol_name,v,is_const); + return add_impl<tie_stdvec,std::vector<T,Allocator>&> + (symbol_name, v, is_const); } inline bool add(const std::string& symbol_name, exprtk::vector_view<T>& v, const bool is_const = false) { - return add_impl<tie_vecview,exprtk::vector_view<T>&>(symbol_name,v,is_const); + return add_impl<tie_vecview,exprtk::vector_view<T>&> + (symbol_name, v, is_const); } template <typename Allocator> inline bool add(const std::string& symbol_name, std::deque<T,Allocator>& v, const bool is_const = false) { - return add_impl<tie_stddeq,std::deque<T,Allocator>&>(symbol_name,v,is_const); + return add_impl<tie_stddeq,std::deque<T,Allocator>&> + (symbol_name, v, is_const); } inline bool add(const std::string& symbol_name, RawType& t, const bool is_const = false) @@ -16207,13 +16492,13 @@ namespace exprtk { static inline std::pair<bool,variable_node_t*> make(T& t,const bool is_const = false) { - return std::make_pair(is_const,new variable_node_t(t)); + return std::make_pair(is_const, new variable_node_t(t)); } #ifndef exprtk_disable_string_capabilities static inline std::pair<bool,stringvar_node_t*> make(std::string& t,const bool is_const = false) { - return std::make_pair(is_const,new stringvar_node_t(t)); + return std::make_pair(is_const, new stringvar_node_t(t)); } #endif @@ -16233,7 +16518,7 @@ namespace exprtk } }; - tm_itr_t itr = map.find(symbol_name); + const tm_itr_t itr = map.find(symbol_name); if (map.end() == itr) { @@ -16246,7 +16531,7 @@ namespace exprtk inline type_ptr get(const std::string& symbol_name) const { - tm_const_itr_t itr = map.find(symbol_name); + const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return reinterpret_cast<type_ptr>(0); @@ -16294,7 +16579,7 @@ namespace exprtk inline bool remove(const std::string& symbol_name, const bool delete_node = true) { - tm_itr_t itr = map.find(symbol_name); + const tm_itr_t itr = map.find(symbol_name); if (map.end() != itr) { @@ -16334,7 +16619,7 @@ namespace exprtk static RawType null_type = init_type::set(RawType()); - tm_const_itr_t itr = map.find(symbol_name); + const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return null_type; @@ -16359,7 +16644,7 @@ namespace exprtk if (delete_node) { tm_itr_t itr = map.begin(); - tm_itr_t end = map.end(); + tm_itr_t end = map.end (); while (end != itr) { @@ -16383,7 +16668,7 @@ namespace exprtk if (!map.empty()) { tm_const_itr_t itr = map.begin(); - tm_const_itr_t end = map.end(); + tm_const_itr_t end = map.end (); while (end != itr) { @@ -16405,7 +16690,7 @@ namespace exprtk if (!map.empty()) { tm_const_itr_t itr = map.begin(); - tm_const_itr_t end = map.end(); + tm_const_itr_t end = map.end (); while (end != itr) { @@ -16445,11 +16730,12 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities type_store<typename details::stringvar_node<T>,std::string> stringvar_store; #endif - type_store<ifunction<T>,ifunction<T> > function_store; + type_store<ifunction<T>,ifunction<T> > function_store; type_store<ivararg_function <T>,ivararg_function <T> > vararg_function_store; type_store<igeneric_function<T>,igeneric_function<T> > generic_function_store; type_store<igeneric_function<T>,igeneric_function<T> > string_function_store; - type_store<vector_holder_t,vector_holder_t> vector_store; + type_store<igeneric_function<T>,igeneric_function<T> > overload_function_store; + type_store<vector_holder_t,vector_holder_t> vector_store; st_data() { @@ -16477,6 +16763,17 @@ namespace exprtk return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); } + static inline st_data* create() + { + return (new st_data); + } + + static inline void destroy(st_data*& sd) + { + delete sd; + sd = reinterpret_cast<st_data*>(0); + } + std::list<T> local_symbol_list_; std::list<std::string> local_stringvar_list_; std::set<std::string> reserved_symbol_table_; @@ -16485,10 +16782,10 @@ namespace exprtk control_block() : ref_count(1), - data_(new st_data) + data_(st_data::create()) {} - control_block(st_data* data) + explicit control_block(st_data* data) : ref_count(1), data_(data) {} @@ -16497,14 +16794,13 @@ namespace exprtk { if (data_ && (0 == ref_count)) { - delete data_; - data_ = 0; + st_data::destroy(data_); } } static inline control_block* create() { - return new control_block; + return (new control_block); } template <typename SymTab> @@ -16560,10 +16856,10 @@ namespace exprtk control_block_->ref_count++; } - return *this; + return (*this); } - inline bool operator==(const symbol_table<T>& st) + inline bool operator==(const symbol_table<T>& st) const { return (this == &st) || (control_block_ == st.control_block_); } @@ -16710,6 +17006,16 @@ namespace exprtk return local_data().string_function_store.get(function_name); } + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast<generic_function_ptr>(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast<generic_function_ptr>(0); + else + return local_data().overload_function_store.get(function_name); + } + typedef vector_holder_t* vector_holder_ptr; inline vector_holder_ptr get_vector(const std::string& vector_name) const @@ -16875,25 +17181,44 @@ namespace exprtk return false; else if (symbol_exists(function_name)) return false; - else if (std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|")) + else if ( + ( + (generic_function_t::e_rtrn_scalar == function.rtrn_type) || + (generic_function_t::e_rtrn_string == function.rtrn_type) + ) && + std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|") + ) return false; - else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) - return local_data().generic_function_store.add(function_name,function); - else if (generic_function_t::e_rtrn_string == function.rtrn_type) - return local_data().string_function_store.add(function_name, function); - else + else if ( + (generic_function_t::e_rtrn_overload == function.rtrn_type) && + std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|:") + ) return false; + + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return local_data().generic_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_string : + return local_data().string_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_overload : + return local_data().overload_function_store.add(function_name,function); + } + + return false; } #define exprtk_define_freefunction(NN) \ inline bool add_function(const std::string& function_name, ff##NN##_functor function) \ { \ if (!valid()) \ - return false; \ - else if (!valid_symbol(function_name)) \ - return false; \ - else if (symbol_exists(function_name)) \ - return false; \ + { return false; } \ + if (!valid_symbol(function_name)) \ + { return false; } \ + if (symbol_exists(function_name)) \ + { return false; } \ \ exprtk::ifunction<T>* ifunc = new freefunc##NN(function); \ \ @@ -16902,14 +17227,14 @@ namespace exprtk return add_function(function_name,(*local_data().free_function_list_.back())); \ } \ - exprtk_define_freefunction(01) exprtk_define_freefunction(02) - exprtk_define_freefunction(03) exprtk_define_freefunction(04) - exprtk_define_freefunction(05) exprtk_define_freefunction(06) - exprtk_define_freefunction(07) exprtk_define_freefunction(08) - exprtk_define_freefunction(09) exprtk_define_freefunction(10) - exprtk_define_freefunction(11) exprtk_define_freefunction(12) - exprtk_define_freefunction(13) exprtk_define_freefunction(14) - exprtk_define_freefunction(15) + exprtk_define_freefunction(00) exprtk_define_freefunction(01) + exprtk_define_freefunction(02) exprtk_define_freefunction(03) + exprtk_define_freefunction(04) exprtk_define_freefunction(05) + exprtk_define_freefunction(06) exprtk_define_freefunction(07) + exprtk_define_freefunction(08) exprtk_define_freefunction(09) + exprtk_define_freefunction(10) exprtk_define_freefunction(11) + exprtk_define_freefunction(12) exprtk_define_freefunction(13) + exprtk_define_freefunction(14) exprtk_define_freefunction(15) #undef exprtk_define_freefunction @@ -16945,14 +17270,33 @@ namespace exprtk return false; else if (symbol_exists(function_name,false)) return false; - else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")) + else if ( + ( + (generic_function_t::e_rtrn_scalar == function.rtrn_type) || + (generic_function_t::e_rtrn_string == function.rtrn_type) + ) && + std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|") + ) return false; - else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) - return local_data().generic_function_store.add(function_name,function); - else if (generic_function_t::e_rtrn_string == function.rtrn_type) - return local_data().string_function_store.add(function_name, function); - else + else if ( + generic_function_t::e_rtrn_overload && + std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|:") + ) return false; + + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return local_data().generic_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_string : + return local_data().string_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_overload : + return local_data().overload_function_store.add(function_name,function); + } + + return false; } template <std::size_t N> @@ -16976,6 +17320,8 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; + else if (0 == v_size) + return false; else return local_data().vector_store.add(vector_name,v,v_size); } @@ -16989,6 +17335,8 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; + else if (0 == v.size()) + return false; else return local_data().vector_store.add(vector_name,v); } @@ -17001,6 +17349,8 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; + else if (0 == v.size()) + return false; else return local_data().vector_store.add(vector_name,v); } @@ -17051,12 +17401,13 @@ namespace exprtk { return add_pi () && add_epsilon () && - add_infinity(); + add_infinity() ; } inline bool add_pi() { - static const T local_pi = T(details::numeric::constant::pi); + const typename details::numeric::details::number_type<T>::type num_type; + static const T local_pi = details::numeric::details::const_pi_impl<T>(num_type); return add_constant("pi",local_pi); } @@ -17134,8 +17485,8 @@ namespace exprtk { /* Function will return true if symbol_name exists as either a - reserved symbol, variable, stringvar or function name in any - of the type stores. + reserved symbol, variable, stringvar, vector or function name + in any of the type stores. */ if (!valid()) return false; @@ -17145,6 +17496,8 @@ namespace exprtk else if (local_data().stringvar_store.symbol_exists(symbol_name)) return true; #endif + else if (local_data().vector_store.symbol_exists(symbol_name)) + return true; else if (local_data().function_store.symbol_exists(symbol_name)) return true; else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) @@ -17299,6 +17652,21 @@ namespace exprtk } } } + + { + std::vector<std::string> name_list; + + st.local_data().overload_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function<T>& ifunc = *st.get_overload_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } } private: @@ -17404,7 +17772,7 @@ namespace exprtk size(0) {} - data_pack(void* ptr, data_type dt, std::size_t sz = 0) + data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) : pointer(ptr), type(dt), size(sz) @@ -17426,7 +17794,7 @@ namespace exprtk return_invoked(&retinv_null) {} - control_block(expression_ptr e) + explicit control_block(expression_ptr e) : ref_count(1), expr (e), results (0), @@ -17438,8 +17806,7 @@ namespace exprtk { if (expr && details::branch_deletable(expr)) { - delete expr; - expr = reinterpret_cast<expression_ptr>(0); + destroy_node(expr); } if (!local_data_list.empty()) @@ -17514,12 +17881,19 @@ namespace exprtk } expression(const expression<T>& e) - : control_block_(e.control_block_), + : control_block_ (e.control_block_ ), symbol_table_list_(e.symbol_table_list_) { control_block_->ref_count++; } + explicit expression(const symbol_table<T>& symbol_table) + : control_block_(0) + { + set_expression(new details::null_node<T>()); + symbol_table_list_.push_back(symbol_table); + } + inline expression<T>& operator=(const expression<T>& e) { if (this != &e) @@ -17545,7 +17919,7 @@ namespace exprtk return *this; } - inline bool operator==(const expression<T>& e) + inline bool operator==(const expression<T>& e) const { return (this == &e); } @@ -17562,7 +17936,7 @@ namespace exprtk { control_block::destroy(control_block_); - return *this; + return (*this); } ~expression() @@ -17575,7 +17949,7 @@ namespace exprtk return control_block_->expr->value(); } - inline T operator()() const + inline T operator() () const { return value(); } @@ -17694,7 +18068,7 @@ namespace exprtk control_block_-> local_data_list.push_back( typename expression<T>::control_block:: - data_pack(reinterpret_cast<void*>(data),dt,size)); + data_pack(reinterpret_cast<void*>(data), dt, size)); } } } @@ -17802,27 +18176,35 @@ namespace exprtk lexer::token token; error_mode mode; std::string diagnostic; + std::string src_location; std::string error_line; std::size_t line_no; std::size_t column_no; }; - inline type make_error(error_mode mode, const std::string& diagnostic = "") + inline type make_error(const error_mode mode, + const std::string& diagnostic = "", + const std::string& src_location = "") { type t; - t.mode = mode; - t.token.type = lexer::token::e_error; - t.diagnostic = diagnostic; + t.mode = mode; + t.token.type = lexer::token::e_error; + t.diagnostic = diagnostic; + t.src_location = src_location; exprtk_debug(("%s\n",diagnostic .c_str())); return t; } - inline type make_error(error_mode mode, const lexer::token& tk, const std::string& diagnostic = "") + inline type make_error(const error_mode mode, + const lexer::token& tk, + const std::string& diagnostic = "", + const std::string& src_location = "") { type t; t.mode = mode; t.token = tk; t.diagnostic = diagnostic; + t.src_location = src_location; exprtk_debug(("%s\n",diagnostic .c_str())); return t; } @@ -17979,15 +18361,16 @@ namespace exprtk typedef details::scor_node<T> scor_node_t; typedef lexer::token token_t; typedef expression_node_t* expression_node_ptr; + typedef expression<T> expression_t; typedef symbol_table<T> symbol_table_t; typedef typename expression<T>::symtab_list_t symbol_table_list_t; typedef details::vector_holder<T>* vector_holder_ptr; - typedef typename details::functor_t<T> functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; + typedef typename details::functor_t<T> functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; typedef details::operator_type operator_t; @@ -18002,28 +18385,28 @@ namespace exprtk typedef std::multimap<std::string,details::base_operation_t,details::ilesscompare> base_ops_map_t; typedef std::set<std::string,details::ilesscompare> disabled_func_set_t; - typedef details::T0oT1_define<T, cref_t, cref_t> vov_t; - typedef details::T0oT1_define<T,const_t, cref_t> cov_t; - typedef details::T0oT1_define<T, cref_t,const_t> voc_t; - - typedef details::T0oT1oT2_define<T, cref_t, cref_t, cref_t> vovov_t; - typedef details::T0oT1oT2_define<T, cref_t, cref_t,const_t> vovoc_t; - typedef details::T0oT1oT2_define<T, cref_t,const_t, cref_t> vocov_t; - typedef details::T0oT1oT2_define<T,const_t, cref_t, cref_t> covov_t; - typedef details::T0oT1oT2_define<T,const_t, cref_t,const_t> covoc_t; - typedef details::T0oT1oT2_define<T,const_t,const_t, cref_t> cocov_t; - typedef details::T0oT1oT2_define<T,cref_t,const_t, const_t> vococ_t; - - typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t, cref_t> vovovov_t; - typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t,const_t> vovovoc_t; - typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t,const_t, cref_t> vovocov_t; - typedef details::T0oT1oT2oT3_define<T, cref_t,const_t, cref_t, cref_t> vocovov_t; - typedef details::T0oT1oT2oT3_define<T,const_t, cref_t, cref_t, cref_t> covovov_t; - - typedef details::T0oT1oT2oT3_define<T,const_t, cref_t,const_t, cref_t> covocov_t; - typedef details::T0oT1oT2oT3_define<T, cref_t,const_t, cref_t,const_t> vocovoc_t; - typedef details::T0oT1oT2oT3_define<T,const_t, cref_t, cref_t,const_t> covovoc_t; - typedef details::T0oT1oT2oT3_define<T, cref_t,const_t,const_t, cref_t> vococov_t; + typedef details::T0oT1_define<T, cref_t, cref_t> vov_t; + typedef details::T0oT1_define<T, const_t, cref_t> cov_t; + typedef details::T0oT1_define<T, cref_t, const_t> voc_t; + + typedef details::T0oT1oT2_define<T, cref_t, cref_t, cref_t> vovov_t; + typedef details::T0oT1oT2_define<T, cref_t, cref_t, const_t> vovoc_t; + typedef details::T0oT1oT2_define<T, cref_t, const_t, cref_t> vocov_t; + typedef details::T0oT1oT2_define<T, const_t, cref_t, cref_t> covov_t; + typedef details::T0oT1oT2_define<T, const_t, cref_t, const_t> covoc_t; + typedef details::T0oT1oT2_define<T, const_t, const_t, cref_t> cocov_t; + typedef details::T0oT1oT2_define<T, cref_t, const_t, const_t> vococ_t; + + typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t, cref_t> vovovov_t; + typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t, const_t> vovovoc_t; + typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, const_t, cref_t> vovocov_t; + typedef details::T0oT1oT2oT3_define<T, cref_t, const_t, cref_t, cref_t> vocovov_t; + typedef details::T0oT1oT2oT3_define<T, const_t, cref_t, cref_t, cref_t> covovov_t; + + typedef details::T0oT1oT2oT3_define<T, const_t, cref_t, const_t, cref_t> covocov_t; + typedef details::T0oT1oT2oT3_define<T, cref_t, const_t, cref_t, const_t> vocovoc_t; + typedef details::T0oT1oT2oT3_define<T, const_t, cref_t, cref_t, const_t> covovoc_t; + typedef details::T0oT1oT2oT3_define<T, cref_t, const_t, const_t, cref_t> vococov_t; typedef results_context<T> results_context_t; @@ -18125,7 +18508,7 @@ namespace exprtk typedef variable_node_t* variable_node_ptr; typedef parser<T> parser_t; - scope_element_manager(parser<T>& p) + explicit scope_element_manager(parser<T>& p) : parser_(p), input_param_cnt_(0) {} @@ -18160,7 +18543,7 @@ namespace exprtk if (se.depth > current_depth) continue; else if ( - (se.name == var_name) && + details::imatch(se.name, var_name) && (se.index == index) ) return se; @@ -18181,8 +18564,8 @@ namespace exprtk if (se.depth > current_depth) continue; else if ( - (se.name == var_name) && - (se.index == index) && + details::imatch(se.name, var_name) && + (se.index == index) && (se.active) ) return se; @@ -18198,11 +18581,11 @@ namespace exprtk scope_element& cse = element_[i]; if ( - (cse.name == se.name ) && - (cse.depth <= se.depth) && - (cse.index == se.index) && - (cse.size == se.size ) && - (cse.type == se.type ) && + details::imatch(cse.name, se.name) && + (cse.depth <= se.depth) && + (cse.index == se.index) && + (cse.size == se.size ) && + (cse.type == se.type ) && (cse.active) ) return false; @@ -18236,6 +18619,10 @@ namespace exprtk inline void free_element(scope_element& se) { + #ifdef exprtk_enable_debugging + exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); + #endif + switch (se.type) { case scope_element::e_variable : if (se.data ) delete (T*) se.data; @@ -18288,7 +18675,7 @@ namespace exprtk se.active && se.var_node && details::is_variable_node(se.var_node) - ) + ) { variable_node_ptr vn = reinterpret_cast<variable_node_ptr>(se.var_node); @@ -18318,12 +18705,12 @@ namespace exprtk typedef parser<T> parser_t; - scope_handler(parser<T>& p) + explicit scope_handler(parser<T>& p) : parser_(p) { parser_.state_.scope_depth++; #ifdef exprtk_enable_debugging - std::string depth(2 * parser_.state_.scope_depth,'-'); + const std::string depth(2 * parser_.state_.scope_depth,'-'); exprtk_debug(("%s> Scope Depth: %02d\n", depth.c_str(), static_cast<int>(parser_.state_.scope_depth))); @@ -18335,7 +18722,7 @@ namespace exprtk parser_.sem_.deactivate(parser_.state_.scope_depth); parser_.state_.scope_depth--; #ifdef exprtk_enable_debugging - std::string depth(2 * parser_.state_.scope_depth,'-'); + const std::string depth(2 * parser_.state_.scope_depth,'-'); exprtk_debug(("<%s Scope Depth: %02d\n", depth.c_str(), static_cast<int>(parser_.state_.scope_depth))); @@ -18549,6 +18936,27 @@ namespace exprtk return result; } + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast<generic_function_ptr>(0); + + generic_function_ptr result = reinterpret_cast<generic_function_ptr>(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).overload_function_store.get(function_name); + + if (result) break; + } + + return result; + } + inline vector_holder_ptr get_vector(const std::string& vector_name) const { if (!valid_symbol(vector_name)) @@ -18807,8 +19215,9 @@ namespace exprtk enum usr_symbol_type { - e_usr_variable_type = 0, - e_usr_constant_type = 1 + e_usr_unknown_type = 0, + e_usr_variable_type = 1, + e_usr_constant_type = 2 }; enum usr_mode @@ -18887,7 +19296,7 @@ namespace exprtk {} template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline std::size_t symbols(Sequence<symbol_t,Allocator>& symbols_list) { if (!collect_variables_ && !collect_functions_) @@ -18897,23 +19306,20 @@ namespace exprtk for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) { - std::string& s = symbol_name_list_[i].first; - #ifndef MODIFICATION - std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(std::tolower)); - #endif + details::case_normalise(symbol_name_list_[i].first); } std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); std::unique_copy(symbol_name_list_.begin(), - symbol_name_list_.end(), + symbol_name_list_.end (), std::back_inserter(symbols_list)); return symbols_list.size(); } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline std::size_t assignment_symbols(Sequence<symbol_t,Allocator>& assignment_list) { if (!collect_assignments_) @@ -18923,16 +19329,13 @@ namespace exprtk for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) { - std::string& s = assignment_name_list_[i].first; - #ifndef MODIFICATION - std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(std::tolower)); - #endif + details::case_normalise(assignment_name_list_[i].first); } std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); std::unique_copy(assignment_name_list_.begin(), - assignment_name_list_.end(), + assignment_name_list_.end (), std::back_inserter(assignment_list)); return assignment_list.size(); @@ -18991,11 +19394,13 @@ namespace exprtk case e_st_local_variable : case e_st_local_vector : case e_st_local_string : if (collect_variables_) - symbol_name_list_.push_back(std::make_pair(symbol,st)); + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); break; case e_st_function : if (collect_functions_) - symbol_name_list_.push_back(std::make_pair(symbol,st)); + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); break; default : return; @@ -19008,10 +19413,10 @@ namespace exprtk { case e_st_variable : case e_st_vector : - case e_st_string : - if (collect_assignments_) - assignment_name_list_.push_back(std::make_pair(symbol,st)); - break; + case e_st_string : if (collect_assignments_) + assignment_name_list_ + .push_back(std::make_pair(symbol, st)); + break; default : return; } @@ -19134,43 +19539,43 @@ namespace exprtk settings_store& enable_all_base_functions() { disabled_func_set_.clear(); - return *this; + return (*this); } settings_store& enable_all_control_structures() { disabled_ctrl_set_.clear(); - return *this; + return (*this); } settings_store& enable_all_logic_ops() { disabled_logic_set_.clear(); - return *this; + return (*this); } settings_store& enable_all_arithmetic_ops() { disabled_arithmetic_set_.clear(); - return *this; + return (*this); } settings_store& enable_all_assignment_ops() { disabled_assignment_set_.clear(); - return *this; + return (*this); } settings_store& enable_all_inequality_ops() { disabled_inequality_set_.clear(); - return *this; + return (*this); } settings_store& enable_local_vardef() { disable_vardef_ = false; - return *this; + return (*this); } settings_store& disable_all_base_functions() @@ -19178,8 +19583,8 @@ namespace exprtk std::copy(details::base_function_list, details::base_function_list + details::base_function_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_func_set_,disabled_func_set_.begin())); - return *this; + (disabled_func_set_, disabled_func_set_.begin())); + return (*this); } settings_store& disable_all_control_structures() @@ -19187,8 +19592,8 @@ namespace exprtk std::copy(details::cntrl_struct_list, details::cntrl_struct_list + details::cntrl_struct_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_ctrl_set_,disabled_ctrl_set_.begin())); - return *this; + (disabled_ctrl_set_, disabled_ctrl_set_.begin())); + return (*this); } settings_store& disable_all_logic_ops() @@ -19196,8 +19601,8 @@ namespace exprtk std::copy(details::logic_ops_list, details::logic_ops_list + details::logic_ops_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_logic_set_,disabled_logic_set_.begin())); - return *this; + (disabled_logic_set_, disabled_logic_set_.begin())); + return (*this); } settings_store& disable_all_arithmetic_ops() @@ -19205,8 +19610,8 @@ namespace exprtk std::copy(details::arithmetic_ops_list, details::arithmetic_ops_list + details::arithmetic_ops_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_arithmetic_set_,disabled_arithmetic_set_.begin())); - return *this; + (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); + return (*this); } settings_store& disable_all_assignment_ops() @@ -19214,8 +19619,8 @@ namespace exprtk std::copy(details::assignment_ops_list, details::assignment_ops_list + details::assignment_ops_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_assignment_set_,disabled_assignment_set_.begin())); - return *this; + (disabled_assignment_set_, disabled_assignment_set_.begin())); + return (*this); } settings_store& disable_all_inequality_ops() @@ -19223,14 +19628,14 @@ namespace exprtk std::copy(details::inequality_ops_list, details::inequality_ops_list + details::inequality_ops_list_size, std::insert_iterator<disabled_entity_set_t> - (disabled_inequality_set_,disabled_inequality_set_.begin())); - return *this; + (disabled_inequality_set_, disabled_inequality_set_.begin())); + return (*this); } settings_store& disable_local_vardef() { disable_vardef_ = true; - return *this; + return (*this); } bool replacer_enabled () const { return enable_replacer_; } @@ -19247,7 +19652,7 @@ namespace exprtk bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } bool zero_return_disabled () const { return disable_zero_return_; } - bool function_enabled(const std::string& function_name) + bool function_enabled(const std::string& function_name) const { if (disabled_func_set_.empty()) return true; @@ -19255,7 +19660,7 @@ namespace exprtk return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); } - bool control_struct_enabled(const std::string& control_struct) + bool control_struct_enabled(const std::string& control_struct) const { if (disabled_ctrl_set_.empty()) return true; @@ -19263,7 +19668,7 @@ namespace exprtk return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); } - bool logic_enabled(const std::string& logic_operation) + bool logic_enabled(const std::string& logic_operation) const { if (disabled_logic_set_.empty()) return true; @@ -19271,31 +19676,34 @@ namespace exprtk return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); } - bool arithmetic_enabled(const details::operator_type& arithmetic_operation) + bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const { if (disabled_logic_set_.empty()) return true; else - return (disabled_arithmetic_set_.end() == disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); + return disabled_arithmetic_set_.end() == disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); } - bool assignment_enabled(const details::operator_type& assignment) + bool assignment_enabled(const details::operator_type& assignment) const { if (disabled_assignment_set_.empty()) return true; else - return (disabled_assignment_set_.end() == disabled_assignment_set_.find(assign_opr_to_string(assignment))); + return disabled_assignment_set_.end() == disabled_assignment_set_ + .find(assign_opr_to_string(assignment)); } - bool inequality_enabled(const details::operator_type& inequality) + bool inequality_enabled(const details::operator_type& inequality) const { if (disabled_inequality_set_.empty()) return true; else - return (disabled_inequality_set_.end() == disabled_inequality_set_.find(inequality_opr_to_string(inequality))); + return disabled_inequality_set_.end() == disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); } - bool function_disabled(const std::string& function_name) + bool function_disabled(const std::string& function_name) const { if (disabled_func_set_.empty()) return false; @@ -19303,7 +19711,7 @@ namespace exprtk return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); } - bool control_struct_disabled(const std::string& control_struct) + bool control_struct_disabled(const std::string& control_struct) const { if (disabled_ctrl_set_.empty()) return false; @@ -19311,7 +19719,7 @@ namespace exprtk return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); } - bool logic_disabled(const std::string& logic_operation) + bool logic_disabled(const std::string& logic_operation) const { if (disabled_logic_set_.empty()) return false; @@ -19319,28 +19727,31 @@ namespace exprtk return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); } - bool assignment_disabled(const details::operator_type assignment_operation) + bool assignment_disabled(const details::operator_type assignment_operation) const { if (disabled_assignment_set_.empty()) return false; else - return (disabled_assignment_set_.end() != disabled_assignment_set_.find(assign_opr_to_string(assignment_operation))); + return disabled_assignment_set_.end() != disabled_assignment_set_ + .find(assign_opr_to_string(assignment_operation)); } - bool arithmetic_disabled(const details::operator_type arithmetic_operation) + bool arithmetic_disabled(const details::operator_type arithmetic_operation) const { if (disabled_arithmetic_set_.empty()) return false; else - return (disabled_arithmetic_set_.end() != disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); + return disabled_arithmetic_set_.end() != disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); } - bool inequality_disabled(const details::operator_type& inequality) + bool inequality_disabled(const details::operator_type& inequality) const { if (disabled_inequality_set_.empty()) return false; else - return (disabled_inequality_set_.end() != disabled_inequality_set_.find(inequality_opr_to_string(inequality))); + return disabled_inequality_set_.end() != disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); } settings_store& disable_base_function(settings_base_funcs bf) @@ -19353,7 +19764,7 @@ namespace exprtk disabled_func_set_.insert(details::base_function_list[bf - 1]); } - return *this; + return (*this); } settings_store& disable_control_structure(settings_control_structs ctrl_struct) @@ -19366,7 +19777,7 @@ namespace exprtk disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); } - return *this; + return (*this); } settings_store& disable_logic_operation(settings_logic_opr logic) @@ -19379,7 +19790,7 @@ namespace exprtk disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); } - return *this; + return (*this); } settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) @@ -19392,7 +19803,7 @@ namespace exprtk disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); } - return *this; + return (*this); } settings_store& disable_assignment_operation(settings_assignment_opr assignment) @@ -19405,7 +19816,7 @@ namespace exprtk disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); } - return *this; + return (*this); } settings_store& disable_inequality_operation(settings_inequality_opr inequality) @@ -19418,7 +19829,7 @@ namespace exprtk disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); } - return *this; + return (*this); } settings_store& enable_base_function(settings_base_funcs bf) @@ -19428,7 +19839,7 @@ namespace exprtk (static_cast<std::size_t>(bf) < (details::base_function_list_size + 1)) ) { - des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); + const des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); if (disabled_func_set_.end() != itr) { @@ -19436,7 +19847,7 @@ namespace exprtk } } - return *this; + return (*this); } settings_store& enable_control_structure(settings_control_structs ctrl_struct) @@ -19446,7 +19857,7 @@ namespace exprtk (static_cast<std::size_t>(ctrl_struct) < (details::cntrl_struct_list_size + 1)) ) { - des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); + const des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); if (disabled_ctrl_set_.end() != itr) { @@ -19454,7 +19865,7 @@ namespace exprtk } } - return *this; + return (*this); } settings_store& enable_logic_operation(settings_logic_opr logic) @@ -19464,7 +19875,7 @@ namespace exprtk (static_cast<std::size_t>(logic) < (details::logic_ops_list_size + 1)) ) { - des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); + const des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); if (disabled_logic_set_.end() != itr) { @@ -19472,7 +19883,7 @@ namespace exprtk } } - return *this; + return (*this); } settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) @@ -19482,7 +19893,7 @@ namespace exprtk (static_cast<std::size_t>(arithmetic) < (details::arithmetic_ops_list_size + 1)) ) { - des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); + const des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); if (disabled_arithmetic_set_.end() != itr) { @@ -19490,7 +19901,7 @@ namespace exprtk } } - return *this; + return (*this); } settings_store& enable_assignment_operation(settings_assignment_opr assignment) @@ -19500,7 +19911,7 @@ namespace exprtk (static_cast<std::size_t>(assignment) < (details::assignment_ops_list_size + 1)) ) { - des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); + const des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); if (disabled_assignment_set_.end() != itr) { @@ -19508,7 +19919,7 @@ namespace exprtk } } - return *this; + return (*this); } settings_store& enable_inequality_operation(settings_inequality_opr inequality) @@ -19518,7 +19929,7 @@ namespace exprtk (static_cast<std::size_t>(inequality) < (details::inequality_ops_list_size + 1)) ) { - des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); + const des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); if (disabled_inequality_set_.end() != itr) { @@ -19526,7 +19937,7 @@ namespace exprtk } } - return *this; + return (*this); } private: @@ -19548,7 +19959,7 @@ namespace exprtk disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; } - std::string assign_opr_to_string(details::operator_type opr) + std::string assign_opr_to_string(details::operator_type opr) const { switch (opr) { @@ -19562,7 +19973,7 @@ namespace exprtk } } - std::string arith_opr_to_string(details::operator_type opr) + std::string arith_opr_to_string(details::operator_type opr) const { switch (opr) { @@ -19575,7 +19986,7 @@ namespace exprtk } } - std::string inequality_opr_to_string(details::operator_type opr) + std::string inequality_opr_to_string(details::operator_type opr) const { switch (opr) { @@ -19713,7 +20124,8 @@ namespace exprtk if (settings_.sequence_check_enabled()) { - helper_assembly_.register_scanner(&sequence_validator_); + helper_assembly_.register_scanner(&sequence_validator_ ); + helper_assembly_.register_scanner(&sequence_validator_3tkns_); } } } @@ -19734,7 +20146,8 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - "ERR000 - Empty expression!")); + "ERR000 - Empty expression!", + exprtk_error_location)); return false; } @@ -19749,7 +20162,8 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - "ERR001 - Empty expression!")); + "ERR001 - Empty expression!", + exprtk_error_location)); return false; } @@ -19777,7 +20191,7 @@ namespace exprtk dec_.return_present_ = true; e = expression_generator_ - .return_envelope(e,results_context_,retinvk_ptr); + .return_envelope(e, results_context_, retinvk_ptr); } expr.set_expression(e); @@ -19795,22 +20209,34 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR002 - Invalid expression encountered")); + "ERR002 - Invalid expression encountered", + exprtk_error_location)); } - dec_.clear (); - sem_.cleanup (); - return_cleanup(); - if ((0 != e) && branch_deletable(e)) { - delete e; + destroy_node(e); } + dec_.clear (); + sem_.cleanup (); + return_cleanup(); + return false; } } + inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) + { + expression_t expr; + + expr.register_symbol_table(symtab); + + compile(expression_string,expr); + + return expr; + } + void process_lexer_errors() { for (std::size_t i = 0; i < lexer().size(); ++i) @@ -19842,7 +20268,8 @@ namespace exprtk set_error( make_error(parser_error::e_lexer, lexer()[i], - diagnostic + ": " + lexer()[i].value)); + diagnostic + ": " + lexer()[i].value, + exprtk_error_location)); } } } @@ -19874,16 +20301,18 @@ namespace exprtk { if (helper_assembly_.error_token_scanner) { - lexer::helper::bracket_checker* bracket_checker_ptr = 0; - lexer::helper::numeric_checker* numeric_checker_ptr = 0; - lexer::helper::sequence_validator* sequence_validator_ptr = 0; + lexer::helper::bracket_checker* bracket_checker_ptr = 0; + lexer::helper::numeric_checker* numeric_checker_ptr = 0; + lexer::helper::sequence_validator* sequence_validator_ptr = 0; + lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0; if (0 != (bracket_checker_ptr = dynamic_cast<lexer::helper::bracket_checker*>(helper_assembly_.error_token_scanner))) { set_error( make_error(parser_error::e_token, bracket_checker_ptr->error_token(), - "ERR004 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'")); + "ERR004 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", + exprtk_error_location)); } else if (0 != (numeric_checker_ptr = dynamic_cast<lexer::helper::numeric_checker*>(helper_assembly_.error_token_scanner))) { @@ -19894,7 +20323,8 @@ namespace exprtk set_error( make_error(parser_error::e_token, error_token, - "ERR005 - Invalid numeric token: '" + error_token.value + "'")); + "ERR005 - Invalid numeric token: '" + error_token.value + "'", + exprtk_error_location)); } if (numeric_checker_ptr->error_count()) @@ -19913,7 +20343,8 @@ namespace exprtk error_token.first, "ERR006 - Invalid token sequence: '" + error_token.first.value + "' and '" + - error_token.second.value + "'")); + error_token.second.value + "'", + exprtk_error_location)); } if (sequence_validator_ptr->error_count()) @@ -19921,6 +20352,26 @@ namespace exprtk sequence_validator_ptr->clear_errors(); } } + else if (0 != (sequence_validator3_ptr = dynamic_cast<lexer::helper::sequence_validator_3tokens*>(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < sequence_validator3_ptr->error_count(); ++i) + { + std::pair<lexer::token,lexer::token> error_token = sequence_validator3_ptr->error(i); + + set_error( + make_error(parser_error::e_token, + error_token.first, + "ERR007 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); + } + + if (sequence_validator3_ptr->error_count()) + { + sequence_validator3_ptr->clear_errors(); + } + } } return false; @@ -19935,7 +20386,7 @@ namespace exprtk return settings_; } - inline parser_error::type get_error(const std::size_t& index) + inline parser_error::type get_error(const std::size_t& index) const { if (index < error_list_.size()) return error_list_[index]; @@ -20006,7 +20457,7 @@ namespace exprtk private: - inline bool valid_base_operation(const std::string& symbol) + inline bool valid_base_operation(const std::string& symbol) const { const std::size_t length = symbol.size(); @@ -20020,7 +20471,7 @@ namespace exprtk (base_ops_map_.end() != base_ops_map_.find(symbol)); } - inline bool valid_vararg_operation(const std::string& symbol) + inline bool valid_vararg_operation(const std::string& symbol) const { static const std::string s_sum = "sum" ; static const std::string s_mul = "mul" ; @@ -20047,17 +20498,17 @@ namespace exprtk settings_.function_enabled(symbol); } - bool is_invalid_arithmetic_operation(const details::operator_type operation) + bool is_invalid_arithmetic_operation(const details::operator_type operation) const { return settings_.arithmetic_disabled(operation); } - bool is_invalid_assignment_operation(const details::operator_type operation) + bool is_invalid_assignment_operation(const details::operator_type operation) const { return settings_.assignment_disabled(operation); } - bool is_invalid_inequality_operation(const details::operator_type operation) + bool is_invalid_inequality_operation(const details::operator_type operation) const { return settings_.inequality_disabled(operation); } @@ -20065,9 +20516,9 @@ namespace exprtk #ifdef exprtk_enable_debugging inline void next_token() { - std::string ct_str = current_token().value; + const std::string ct_str = current_token().value; parser_helper::next_token(); - std::string depth(2 * state_.scope_depth,' '); + const std::string depth(2 * state_.scope_depth,' '); exprtk_debug(("%s" "prev[%s] --> curr[%s]\n", depth.c_str(), @@ -20081,9 +20532,7 @@ namespace exprtk std::vector<expression_node_ptr> arg_list; std::vector<bool> side_effect_list; - expression_node_ptr result = error_node(); - - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); lexer::token begin_token; lexer::token end_token; @@ -20103,7 +20552,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR007 - Invalid expression encountered")); + "ERR008 - Invalid expression encountered", + exprtk_error_location)); } return error_node(); @@ -20116,7 +20566,7 @@ namespace exprtk end_token = current_token(); - std::string sub_expr = construct_subexpr(begin_token,end_token); + const std::string sub_expr = construct_subexpr(begin_token, end_token); exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", static_cast<int>(arg_list.size() - 1), @@ -20148,7 +20598,7 @@ namespace exprtk dec_.final_stmt_return_ = true; } - result = simplify(arg_list,side_effect_list); + const expression_node_ptr result = simplify(arg_list,side_effect_list); sdd.delete_ptr = (0 == result); @@ -20211,25 +20661,25 @@ namespace exprtk switch (current_token().type) { - case token_t::e_assign : current_state.set(e_level00,e_level00,details::e_assign); break; - case token_t::e_addass : current_state.set(e_level00,e_level00,details::e_addass); break; - case token_t::e_subass : current_state.set(e_level00,e_level00,details::e_subass); break; - case token_t::e_mulass : current_state.set(e_level00,e_level00,details::e_mulass); break; - case token_t::e_divass : current_state.set(e_level00,e_level00,details::e_divass); break; - case token_t::e_modass : current_state.set(e_level00,e_level00,details::e_modass); break; - case token_t::e_swap : current_state.set(e_level00,e_level00,details::e_swap ); break; - case token_t::e_lt : current_state.set(e_level05,e_level06,details:: e_lt); break; - case token_t::e_lte : current_state.set(e_level05,e_level06,details:: e_lte); break; - case token_t::e_eq : current_state.set(e_level05,e_level06,details:: e_eq); break; - case token_t::e_ne : current_state.set(e_level05,e_level06,details:: e_ne); break; - case token_t::e_gte : current_state.set(e_level05,e_level06,details:: e_gte); break; - case token_t::e_gt : current_state.set(e_level05,e_level06,details:: e_gt); break; - case token_t::e_add : current_state.set(e_level07,e_level08,details:: e_add); break; - case token_t::e_sub : current_state.set(e_level07,e_level08,details:: e_sub); break; - case token_t::e_div : current_state.set(e_level10,e_level11,details:: e_div); break; - case token_t::e_mul : current_state.set(e_level10,e_level11,details:: e_mul); break; - case token_t::e_mod : current_state.set(e_level10,e_level11,details:: e_mod); break; - case token_t::e_pow : current_state.set(e_level12,e_level12,details:: e_pow); break; + case token_t::e_assign : current_state.set(e_level00,e_level00, details::e_assign); break; + case token_t::e_addass : current_state.set(e_level00,e_level00, details::e_addass); break; + case token_t::e_subass : current_state.set(e_level00,e_level00, details::e_subass); break; + case token_t::e_mulass : current_state.set(e_level00,e_level00, details::e_mulass); break; + case token_t::e_divass : current_state.set(e_level00,e_level00, details::e_divass); break; + case token_t::e_modass : current_state.set(e_level00,e_level00, details::e_modass); break; + case token_t::e_swap : current_state.set(e_level00,e_level00, details::e_swap ); break; + case token_t::e_lt : current_state.set(e_level05,e_level06, details:: e_lt); break; + case token_t::e_lte : current_state.set(e_level05,e_level06, details:: e_lte); break; + case token_t::e_eq : current_state.set(e_level05,e_level06, details:: e_eq); break; + case token_t::e_ne : current_state.set(e_level05,e_level06, details:: e_ne); break; + case token_t::e_gte : current_state.set(e_level05,e_level06, details:: e_gte); break; + case token_t::e_gt : current_state.set(e_level05,e_level06, details:: e_gt); break; + case token_t::e_add : current_state.set(e_level07,e_level08, details:: e_add); break; + case token_t::e_sub : current_state.set(e_level07,e_level08, details:: e_sub); break; + case token_t::e_div : current_state.set(e_level10,e_level11, details:: e_div); break; + case token_t::e_mul : current_state.set(e_level10,e_level11, details:: e_mul); break; + case token_t::e_mod : current_state.set(e_level10,e_level11, details:: e_mod); break; + case token_t::e_pow : current_state.set(e_level12,e_level12, details:: e_pow); break; default : if (token_t::e_symbol == current_token().type) { static const std::string s_and = "and"; @@ -20243,68 +20693,73 @@ namespace exprtk static const std::string s_ilike = "ilike"; static const std::string s_and1 = "&"; static const std::string s_or1 = "|"; + static const std::string s_not = "not"; if (details::imatch(current_token().value,s_and)) { - current_state.set(e_level03,e_level04,details::e_and); + current_state.set(e_level03, e_level04, details::e_and); break; } else if (details::imatch(current_token().value,s_and1)) { #ifndef exprtk_disable_sc_andor - current_state.set(e_level03,e_level04,details::e_scand); + current_state.set(e_level03, e_level04, details::e_scand); #else - current_state.set(e_level03,e_level04,details::e_and); + current_state.set(e_level03, e_level04, details::e_and); #endif break; } else if (details::imatch(current_token().value,s_nand)) { - current_state.set(e_level03,e_level04,details::e_nand); + current_state.set(e_level03, e_level04, details::e_nand); break; } else if (details::imatch(current_token().value,s_or)) { - current_state.set(e_level01,e_level02,details::e_or); + current_state.set(e_level01, e_level02, details::e_or); break; } else if (details::imatch(current_token().value,s_or1)) { #ifndef exprtk_disable_sc_andor - current_state.set(e_level01,e_level02,details::e_scor); + current_state.set(e_level01, e_level02, details::e_scor); #else - current_state.set(e_level01,e_level02,details::e_or); + current_state.set(e_level01, e_level02, details::e_or); #endif break; } else if (details::imatch(current_token().value,s_nor)) { - current_state.set(e_level01,e_level02,details::e_nor); + current_state.set(e_level01, e_level02, details::e_nor); break; } else if (details::imatch(current_token().value,s_xor)) { - current_state.set(e_level01,e_level02,details::e_xor); + current_state.set(e_level01, e_level02, details::e_xor); break; } else if (details::imatch(current_token().value,s_xnor)) { - current_state.set(e_level01,e_level02,details::e_xnor); + current_state.set(e_level01, e_level02, details::e_xnor); break; } else if (details::imatch(current_token().value,s_in)) { - current_state.set(e_level04,e_level04,details::e_in); + current_state.set(e_level04, e_level04, details::e_in); break; } else if (details::imatch(current_token().value,s_like)) { - current_state.set(e_level04,e_level04,details::e_like); + current_state.set(e_level04, e_level04, details::e_like); break; } else if (details::imatch(current_token().value,s_ilike)) { - current_state.set(e_level04,e_level04,details::e_ilike); + current_state.set(e_level04, e_level04, details::e_ilike); + break; + } + else if (details::imatch(current_token().value,s_not)) + { break; } } @@ -20320,7 +20775,7 @@ namespace exprtk else if (current_state.left < precedence) break; - lexer::token prev_token = current_token(); + const lexer::token prev_token = current_token(); next_token(); @@ -20334,7 +20789,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR008 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'")); + "ERR009 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } @@ -20345,7 +20801,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR009 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'")); + "ERR010 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } @@ -20356,7 +20813,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR010 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'")); + "ERR011 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } @@ -20368,13 +20826,14 @@ namespace exprtk details::is_return_node(right_branch) ) { - free_node(node_allocator_, expression); - free_node(node_allocator_,right_branch); + free_node(node_allocator_, expression); + free_node(node_allocator_, right_branch); set_error( make_error(parser_error::e_syntax, prev_token, - "ERR011 - Return statements cannot be part of sub-expressions")); + "ERR012 - Return statements cannot be part of sub-expressions", + exprtk_error_location)); return error_node(); } @@ -20396,10 +20855,12 @@ namespace exprtk prev_token, !synthesis_error_.empty() ? synthesis_error_ : - "ERR012 - General parsing error at token: '" + prev_token.value + "'")); + "ERR013 - General parsing error at token: '" + prev_token.value + "'", + exprtk_error_location)); } - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); + free_node(node_allocator_, right_branch); return error_node(); } @@ -20464,7 +20925,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR013 - Failed to find variable node in symbol table")); + "ERR014 - Failed to find variable node in symbol table", + exprtk_error_location)); free_node(node_allocator_,node); @@ -20586,7 +21048,7 @@ namespace exprtk struct scoped_bool_negator { - scoped_bool_negator(bool& bb) + explicit scoped_bool_negator(bool& bb) : b(bb) { b = !b; } @@ -20598,7 +21060,7 @@ namespace exprtk struct scoped_bool_or_restorer { - scoped_bool_or_restorer(bool& bb) + explicit scoped_bool_or_restorer(bool& bb) : b(bb), original_value_(bb) {} @@ -20643,7 +21105,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR014 - Invalid number of parameters for function: '" + function_name + "'")); + "ERR015 - Invalid number of parameters for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -20656,7 +21119,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR015 - Failed to generate call to function: '" + function_name + "'")); + "ERR016 - Failed to generate call to function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -20674,7 +21138,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR016 - Expecting ifunction '" + function_name + "' to have non-zero parameter count")); + "ERR017 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + exprtk_error_location)); return error_node(); } @@ -20685,8 +21150,9 @@ namespace exprtk expression_node_ptr branch[NumberofParameters]; expression_node_ptr result = error_node(); - std::fill_n(branch,NumberofParameters,reinterpret_cast<expression_node_ptr>(0)); - scoped_delete<expression_node_t,NumberofParameters> sd(*this,branch); + std::fill_n(branch, NumberofParameters, reinterpret_cast<expression_node_ptr>(0)); + + scoped_delete<expression_node_t,NumberofParameters> sd((*this),branch); next_token(); @@ -20695,7 +21161,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR017 - Expecting argument list for function: '" + function_name + "'")); + "ERR018 - Expecting argument list for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -20709,7 +21176,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR018 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); + "ERR019 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -20720,7 +21188,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR019 - Invalid number of arguments for function: '" + function_name + "'")); + "ERR020 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -20732,7 +21201,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR020 - Invalid number of arguments for function: '" + function_name + "'")); + "ERR021 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } @@ -20760,7 +21230,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR021 - Expecting '()' to proceed call to function: '" + function_name + "'")); + "ERR022 - Expecting '()' to proceed call to function: '" + function_name + "'", + exprtk_error_location)); free_node(node_allocator_,result); @@ -20771,11 +21242,11 @@ namespace exprtk } template <std::size_t MaxNumberofParameters> - inline int parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters]) + inline std::size_t parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters], const std::string& function_name = "") { - std::fill_n(param_list,MaxNumberofParameters,reinterpret_cast<expression_node_ptr>(0)); + std::fill_n(param_list, MaxNumberofParameters, reinterpret_cast<expression_node_ptr>(0)); - scoped_delete<expression_node_t,MaxNumberofParameters> sd(*this,param_list); + scoped_delete<expression_node_t,MaxNumberofParameters> sd((*this),param_list); next_token(); @@ -20784,21 +21255,37 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR022 - Expected a '(' at start of function call, instead got: '" + current_token().value + "'")); + "ERR023 - Expected a '(' at start of function call to '" + function_name + + "', instead got: '" + current_token().value + "'", + exprtk_error_location)); return 0; } - int param_index = 0; + if (token_is(token_t::e_rbracket, e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR024 - Expected at least one input parameter for function call '" + function_name + "'", + exprtk_error_location)); - for (; param_index < static_cast<int>(MaxNumberofParameters); ++param_index) + return 0; + } + + std::size_t param_index = 0; + + for (; param_index < MaxNumberofParameters; ++param_index) { param_list[param_index] = parse_expression(); if (0 == param_list[param_index]) return 0; else if (token_is(token_t::e_rbracket)) + { + sd.delete_ptr = false; break; + } else if (token_is(token_t::e_comma)) continue; else @@ -20806,13 +21293,23 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR023 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'")); + "ERR025 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + exprtk_error_location)); return 0; } } - sd.delete_ptr = false; + if (sd.delete_ptr) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR026 - Invalid number of input parameters passed to function '" + function_name + "'", + exprtk_error_location)); + + return 0; + } return (param_index + 1); } @@ -20821,15 +21318,18 @@ namespace exprtk { typedef std::pair<base_ops_map_t::iterator,base_ops_map_t::iterator> map_range_t; - const std::string operation_name = current_token().value; + const std::string operation_name = current_token().value; + const token_t diagnostic_token = current_token(); + map_range_t itr_range = base_ops_map_.equal_range(operation_name); if (0 == std::distance(itr_range.first,itr_range.second)) { set_error( make_error(parser_error::e_syntax, - current_token(), - "ERR024 - No entry found for base operation: " + operation_name)); + diagnostic_token, + "ERR027 - No entry found for base operation: " + operation_name, + exprtk_error_location)); return error_node(); } @@ -20837,29 +21337,25 @@ namespace exprtk static const std::size_t MaxNumberofParameters = 4; expression_node_ptr param_list[MaxNumberofParameters] = {0}; - std::size_t parameter_count = parse_base_function_call(param_list); + const std::size_t parameter_count = parse_base_function_call(param_list, operation_name); - if (0 == parameter_count) - { - return error_node(); - } - else if (parameter_count <= MaxNumberofParameters) + if ((parameter_count > 0) && (parameter_count <= MaxNumberofParameters)) { for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) { - details::base_operation_t& operation = itr->second; + const details::base_operation_t& operation = itr->second; if (operation.num_params == parameter_count) { switch (parameter_count) { - #define base_opr_case(N) \ - case N : { \ - expression_node_ptr pl##N[N] = {0}; \ - std::copy(param_list,param_list + N,pl##N); \ - lodge_symbol(operation_name,e_st_function); \ - return expression_generator_(operation.type,pl##N); \ - } \ + #define base_opr_case(N) \ + case N : { \ + expression_node_ptr pl##N[N] = {0}; \ + std::copy(param_list, param_list + N, pl##N); \ + lodge_symbol(operation_name, e_st_function); \ + return expression_generator_(operation.type, pl##N); \ + } \ base_opr_case(1) base_opr_case(2) @@ -20873,13 +21369,14 @@ namespace exprtk for (std::size_t i = 0; i < MaxNumberofParameters; ++i) { - free_node(node_allocator_,param_list[i]); + free_node(node_allocator_, param_list[i]); } set_error( make_error(parser_error::e_syntax, - current_token(), - "ERR025 - Invalid number of parameters for call to function: '" + operation_name + "'")); + diagnostic_token, + "ERR028 - Invalid number of input parameters for call to function: '" + operation_name + "'", + exprtk_error_location)); return error_node(); } @@ -20898,7 +21395,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR026 - Expected ',' between if-statement condition and consequent")); + "ERR029 - Expected ',' between if-statement condition and consequent", + exprtk_error_location)); result = false; } else if (0 == (consequent = parse_expression())) @@ -20906,7 +21404,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR027 - Failed to parse consequent for if-statement")); + "ERR030 - Failed to parse consequent for if-statement", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_comma)) @@ -20914,7 +21413,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR028 - Expected ',' between if-statement consequent and alternative")); + "ERR031 - Expected ',' between if-statement consequent and alternative", + exprtk_error_location)); result = false; } else if (0 == (alternative = parse_expression())) @@ -20922,7 +21422,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR029 - Failed to parse alternative for if-statement")); + "ERR032 - Failed to parse alternative for if-statement", + exprtk_error_location)); result = false; } else if (!token_is(token_t::e_rbracket)) @@ -20930,7 +21431,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR030 - Expected ')' at the end of if-statement")); + "ERR033 - Expected ')' at the end of if-statement", + exprtk_error_location)); result = false; } @@ -20951,7 +21453,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR031 - Return types of ternary if-statement differ")); + "ERR034 - Return types of ternary if-statement differ", + exprtk_error_location)); result = false; } @@ -20985,7 +21488,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR032 - Failed to parse body of consequent for if-statement")); + "ERR035 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + result = false; } } @@ -21006,7 +21511,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR033 - Expected ';' at the end of the consequent for if-statement")); + "ERR036 - Expected ';' at the end of the consequent for if-statement", + exprtk_error_location)); + result = false; } } @@ -21015,7 +21522,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR034 - Failed to parse body of consequent for if-statement")); + "ERR037 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + result = false; } } @@ -21033,7 +21542,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR035 - Failed to parse body of the 'else' for if-statement")); + "ERR038 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); + result = false; } } @@ -21044,7 +21555,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR036 - Failed to parse body of if-else statement")); + "ERR039 - Failed to parse body of if-else statement", + exprtk_error_location)); + result = false; } } @@ -21055,7 +21568,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR037 - Expected ';' at the end of the 'else-if' for the if-statement")); + "ERR040 - Expected ';' at the end of the 'else-if' for the if-statement", + exprtk_error_location)); + result = false; } } @@ -21064,7 +21579,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR038 - Failed to parse body of the 'else' for if-statement")); + "ERR041 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); + result = false; } } @@ -21081,13 +21598,14 @@ namespace exprtk if (consq_is_str && alter_is_str) { return expression_generator_ - .conditional_string(condition,consequent,alternative); + .conditional_string(condition, consequent, alternative); } set_error( make_error(parser_error::e_syntax, current_token(), - "ERR039 - Return types of ternary if-statement differ")); + "ERR042 - Return types of ternary if-statement differ", + exprtk_error_location)); result = false; } @@ -21096,15 +21614,15 @@ namespace exprtk if (!result) { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + free_node(node_allocator_, alternative); return error_node(); } else return expression_generator_ - .conditional(condition,consequent,alternative); + .conditional(condition, consequent, alternative); } inline expression_node_ptr parse_conditional_statement() @@ -21118,7 +21636,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR040 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'")); + "ERR043 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", + exprtk_error_location)); return error_node(); } @@ -21127,7 +21646,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR041 - Failed to parse condition for if-statement")); + "ERR044 - Failed to parse condition for if-statement", + exprtk_error_location)); return error_node(); } @@ -21158,7 +21678,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR042 - Invalid if-statement")); + "ERR045 - Invalid if-statement", + exprtk_error_location)); free_node(node_allocator_,condition); @@ -21178,7 +21699,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR043 - Encountered invalid condition branch for ternary if-statement")); + "ERR046 - Encountered invalid condition branch for ternary if-statement", + exprtk_error_location)); return error_node(); } @@ -21187,7 +21709,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR044 - Expected '?' after condition of ternary if-statement")); + "ERR047 - Expected '?' after condition of ternary if-statement", + exprtk_error_location)); result = false; } @@ -21196,7 +21719,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR045 - Failed to parse consequent for ternary if-statement")); + "ERR048 - Failed to parse consequent for ternary if-statement", + exprtk_error_location)); result = false; } @@ -21205,7 +21729,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR046 - Expected ':' between ternary if-statement consequent and alternative")); + "ERR049 - Expected ':' between ternary if-statement consequent and alternative", + exprtk_error_location)); result = false; } @@ -21214,7 +21739,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR047 - Failed to parse alternative for ternary if-statement")); + "ERR050 - Failed to parse alternative for ternary if-statement", + exprtk_error_location)); result = false; } @@ -21230,13 +21756,14 @@ namespace exprtk if (consq_is_str && alter_is_str) { return expression_generator_ - .conditional_string(condition,consequent,alternative); + .conditional_string(condition, consequent, alternative); } set_error( make_error(parser_error::e_syntax, current_token(), - "ERR048 - Return types of ternary if-statement differ")); + "ERR051 - Return types of ternary if-statement differ", + exprtk_error_location)); result = false; } @@ -21245,15 +21772,15 @@ namespace exprtk if (!result) { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + free_node(node_allocator_, alternative); return error_node(); } else return expression_generator_ - .conditional(condition,consequent,alternative); + .conditional(condition, consequent, alternative); } inline expression_node_ptr parse_while_loop() @@ -21272,7 +21799,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR049 - Expected '(' at start of while-loop condition statement")); + "ERR052 - Expected '(' at start of while-loop condition statement", + exprtk_error_location)); return error_node(); } @@ -21281,7 +21809,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR050 - Failed to parse condition for while-loop")); + "ERR053 - Failed to parse condition for while-loop", + exprtk_error_location)); return error_node(); } @@ -21290,7 +21819,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR051 - Expected ')' at end of while-loop condition statement")); + "ERR054 - Expected ')' at end of while-loop condition statement", + exprtk_error_location)); + result = false; } @@ -21303,7 +21834,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR052 - Failed to parse body of while-loop")); + "ERR055 - Failed to parse body of while-loop")); result = false; } else if (0 == (result_node = expression_generator_.while_loop(condition, @@ -21313,16 +21844,18 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR053 - Failed to synthesize while-loop")); + "ERR056 - Failed to synthesize while-loop", + exprtk_error_location)); + result = false; } } if (!result) { - free_node(node_allocator_, branch); - free_node(node_allocator_, condition); - free_node(node_allocator_,result_node); + free_node(node_allocator_, branch); + free_node(node_allocator_, condition); + free_node(node_allocator_, result_node); brkcnt_list_.pop_front(); @@ -21342,7 +21875,7 @@ namespace exprtk std::vector<expression_node_ptr> arg_list; std::vector<bool> side_effect_list; - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); brkcnt_list_.push_front(false); @@ -21353,7 +21886,7 @@ namespace exprtk } else { - token_t::token_type seperator = token_t::e_eof; + const token_t::token_type seperator = token_t::e_eof; scope_handler sh(*this); @@ -21379,15 +21912,16 @@ namespace exprtk break; } - bool is_next_until = peek_token_is(token_t::e_symbol) && - peek_token_is("until"); + const bool is_next_until = peek_token_is(token_t::e_symbol) && + peek_token_is("until"); if (!token_is(seperator) && is_next_until) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR054 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop")); + "ERR057 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -21410,7 +21944,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR055 - Failed to parse body of repeat until loop")); + "ERR058 - Failed to parse body of repeat until loop", + exprtk_error_location)); return error_node(); } @@ -21423,7 +21958,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR056 - Expected '(' before condition statement of repeat until loop")); + "ERR059 - Expected '(' before condition statement of repeat until loop", + exprtk_error_location)); free_node(node_allocator_,branch); @@ -21436,7 +21972,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR057 - Failed to parse condition for repeat until loop")); + "ERR060 - Failed to parse condition for repeat until loop", + exprtk_error_location)); free_node(node_allocator_,branch); @@ -21447,7 +21984,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR058 - Expected ')' after condition of repeat until loop")); + "ERR061 - Expected ')' after condition of repeat until loop", + exprtk_error_location)); free_node(node_allocator_, branch); free_node(node_allocator_, condition); @@ -21460,16 +21998,18 @@ namespace exprtk expression_node_ptr result; result = expression_generator_ - .repeat_until_loop(condition,branch,brkcnt_list_.front()); + .repeat_until_loop(condition, branch, brkcnt_list_.front()); if (0 == result) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR059 - Failed to synthesize repeat until loop")); + "ERR062 - Failed to synthesize repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,condition); - free_node(node_allocator_, condition); brkcnt_list_.pop_front(); return error_node(); @@ -21490,7 +22030,6 @@ namespace exprtk scope_element* se = 0; bool result = true; - std::string loop_counter_symbol; next_token(); @@ -21501,7 +22040,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR060 - Expected '(' at start of for-loop")); + "ERR063 - Expected '(' at start of for-loop", + exprtk_error_location)); return error_node(); } @@ -21520,7 +22060,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR061 - Expected a variable at the start of initialiser section of for-loop")); + "ERR064 - Expected a variable at the start of initialiser section of for-loop", + exprtk_error_location)); return error_node(); } @@ -21529,12 +22070,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR062 - Expected variable assignment of initialiser section of for-loop")); + "ERR065 - Expected variable assignment of initialiser section of for-loop", + exprtk_error_location)); return error_node(); } - loop_counter_symbol = current_token().value; + const std::string loop_counter_symbol = current_token().value; se = &sem_.get_element(loop_counter_symbol); @@ -21543,7 +22085,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR063 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration")); + "ERR066 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + exprtk_error_location)); return error_node(); } @@ -21574,7 +22117,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR064 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); + "ERR067 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -21595,7 +22139,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR065 - Failed to parse initialiser of for-loop")); + "ERR068 - Failed to parse initialiser of for-loop", + exprtk_error_location)); + result = false; } else if (!token_is(token_t::e_eof)) @@ -21603,7 +22149,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR066 - Expected ';' after initialiser of for-loop")); + "ERR069 - Expected ';' after initialiser of for-loop", + exprtk_error_location)); + result = false; } } @@ -21615,7 +22163,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR067 - Failed to parse condition of for-loop")); + "ERR070 - Failed to parse condition of for-loop", + exprtk_error_location)); + result = false; } else if (!token_is(token_t::e_eof)) @@ -21623,7 +22173,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR068 - Expected ';' after condition section of for-loop")); + "ERR071 - Expected ';' after condition section of for-loop", + exprtk_error_location)); + result = false; } } @@ -21635,7 +22187,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR069 - Failed to parse incrementor of for-loop")); + "ERR072 - Failed to parse incrementor of for-loop", + exprtk_error_location)); + result = false; } else if (!token_is(token_t::e_rbracket)) @@ -21643,7 +22197,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR070 - Expected ')' after incrementor section of for-loop")); + "ERR073 - Expected ')' after incrementor section of for-loop", + exprtk_error_location)); + result = false; } } @@ -21657,7 +22213,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR071 - Failed to parse body of for-loop")); + "ERR074 - Failed to parse body of for-loop", + exprtk_error_location)); + result = false; } } @@ -21669,12 +22227,10 @@ namespace exprtk se->ref_count--; } - sem_.cleanup(); - - free_node(node_allocator_,initialiser); - free_node(node_allocator_, condition); - free_node(node_allocator_,incrementor); - free_node(node_allocator_, loop_body); + free_node(node_allocator_, initialiser); + free_node(node_allocator_, condition); + free_node(node_allocator_, incrementor); + free_node(node_allocator_, loop_body); if (!brkcnt_list_.empty()) { @@ -21707,12 +22263,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR072 - Expected keyword 'switch'")); + "ERR075 - Expected keyword 'switch'", + exprtk_error_location)); return error_node(); } - scoped_vec_delete<expression_node_t> svd(*this,arg_list); + scoped_vec_delete<expression_node_t> svd((*this),arg_list); next_token(); @@ -21721,7 +22278,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR073 - Expected '{' for call to switch statement")); + "ERR076 - Expected '{' for call to switch statement", + exprtk_error_location)); return error_node(); } @@ -21733,7 +22291,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR074 - Expected either a 'case' or 'default' statement")); + "ERR077 - Expected either a 'case' or 'default' statement", + exprtk_error_location)); return error_node(); } @@ -21749,7 +22308,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR075 - Expected ':' for case of switch statement")); + "ERR078 - Expected ':' for case of switch statement", + exprtk_error_location)); return error_node(); } @@ -21763,7 +22323,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR076 - Expected ';' at end of case for switch statement")); + "ERR079 - Expected ';' at end of case for switch statement", + exprtk_error_location)); return error_node(); } @@ -21771,11 +22332,8 @@ namespace exprtk // Can we optimise away the case statement? if (is_constant_node(condition) && is_false(condition)) { - free_node(node_allocator_, condition); - free_node(node_allocator_,consequent); - - condition = 0; - consequent = 0; + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); } else { @@ -21791,7 +22349,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR077 - Expected ':' for default of switch statement")); + "ERR080 - Expected ':' for default of switch statement", + exprtk_error_location)); return error_node(); } @@ -21812,7 +22371,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR078 - Expected ';' at end of default for switch statement")); + "ERR081 - Expected ';' at end of default for switch statement", + exprtk_error_location)); return error_node(); } @@ -21827,7 +22387,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR079 - Expected '}' at end of switch statement")); + "ERR082 - Expected '}' at end of switch statement", + exprtk_error_location)); return error_node(); } @@ -21842,19 +22403,19 @@ namespace exprtk inline expression_node_ptr parse_multi_switch_statement() { std::vector<expression_node_ptr> arg_list; - expression_node_ptr result = error_node(); if (!details::imatch(current_token().value,"[*]")) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR080 - Expected token '[*]'")); + "ERR083 - Expected token '[*]'", + exprtk_error_location)); return error_node(); } - scoped_vec_delete<expression_node_t> svd(*this,arg_list); + scoped_vec_delete<expression_node_t> svd((*this),arg_list); next_token(); @@ -21863,7 +22424,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR081 - Expected '{' for call to [*] statement")); + "ERR084 - Expected '{' for call to [*] statement", + exprtk_error_location)); return error_node(); } @@ -21875,7 +22437,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR082 - Expected a 'case' statement for multi-switch")); + "ERR085 - Expected a 'case' statement for multi-switch", + exprtk_error_location)); return error_node(); } @@ -21892,7 +22455,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR083 - Expected ':' for case of [*] statement")); + "ERR086 - Expected ':' for case of [*] statement", + exprtk_error_location)); return error_node(); } @@ -21907,7 +22471,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR084 - Expected ';' at end of case for [*] statement")); + "ERR087 - Expected ';' at end of case for [*] statement", + exprtk_error_location)); return error_node(); } @@ -21915,15 +22480,12 @@ namespace exprtk // Can we optimise away the case statement? if (is_constant_node(condition) && is_false(condition)) { - free_node(node_allocator_, condition); - free_node(node_allocator_,consequent); - - condition = 0; - consequent = 0; + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); } else { - arg_list.push_back(condition); + arg_list.push_back( condition); arg_list.push_back(consequent); } @@ -21938,12 +22500,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR085 - Expected '}' at end of [*] statement")); + "ERR088 - Expected '}' at end of [*] statement", + exprtk_error_location)); return error_node(); } - result = expression_generator_.multi_switch_statement(arg_list); + const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); svd.delete_ptr = (0 == result); @@ -21953,7 +22516,6 @@ namespace exprtk inline expression_node_ptr parse_vararg_function() { std::vector<expression_node_ptr> arg_list; - expression_node_ptr result = error_node(); details::operator_type opt_type = details::e_default; const std::string symbol = current_token().value; @@ -21967,26 +22529,27 @@ namespace exprtk { return parse_multi_switch_statement(); } - else if (details::imatch(symbol,"avg" )) opt_type = details::e_avg; - else if (details::imatch(symbol,"mand")) opt_type = details::e_mand; - else if (details::imatch(symbol,"max" )) opt_type = details::e_max; - else if (details::imatch(symbol,"min" )) opt_type = details::e_min; - else if (details::imatch(symbol,"mor" )) opt_type = details::e_mor; - else if (details::imatch(symbol,"mul" )) opt_type = details::e_prod; - else if (details::imatch(symbol,"sum" )) opt_type = details::e_sum; + else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; + else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; + else if (details::imatch(symbol, "max" )) opt_type = details::e_max ; + else if (details::imatch(symbol, "min" )) opt_type = details::e_min ; + else if (details::imatch(symbol, "mor" )) opt_type = details::e_mor ; + else if (details::imatch(symbol, "mul" )) opt_type = details::e_prod; + else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; else { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR086 - Unsupported vararg function: " + symbol)); + "ERR089 - Unsupported vararg function: " + symbol, + exprtk_error_location)); return error_node(); } - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); next_token(); @@ -21995,7 +22558,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR087 - Expected '(' for call to vararg function: " + symbol)); + "ERR090 - Expected '(' for call to vararg function: " + symbol, + exprtk_error_location)); return error_node(); } @@ -22016,13 +22580,14 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR088 - Expected ',' for call to vararg function: " + symbol)); + "ERR091 - Expected ',' for call to vararg function: " + symbol, + exprtk_error_location)); return error_node(); } } - result = expression_generator_.vararg_function(opt_type,arg_list); + const expression_node_ptr result = expression_generator_.vararg_function(opt_type,arg_list); sdd.delete_ptr = (0 == result); return result; @@ -22036,7 +22601,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR089 - Expected '[' as start of string range definition")); + "ERR092 - Expected '[' as start of string range definition", + exprtk_error_location)); free_node(node_allocator_,expression); @@ -22063,7 +22629,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR090 - Failed to generate string range node")); + "ERR093 - Failed to generate string range node", + exprtk_error_location)); free_node(node_allocator_,expression); } @@ -22101,7 +22668,7 @@ namespace exprtk template <typename Allocator1, typename Allocator2, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr simplify(Sequence<expression_node_ptr,Allocator1>& expression_list, Sequence<bool,Allocator2>& side_effect_list, const bool specialise_on_final_type = false) @@ -22198,8 +22765,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR091 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + - ((!source.empty()) ? std::string(" section of " + source): ""))); + "ERR094 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + + ((!source.empty()) ? std::string(" section of " + source): ""), + exprtk_error_location)); return error_node(); } @@ -22214,7 +22782,7 @@ namespace exprtk expression_node_ptr result = error_node(); - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); scope_handler sh(*this); @@ -22237,14 +22805,15 @@ namespace exprtk if (token_is(close_bracket)) break; - bool is_next_close = peek_token_is(close_bracket); + const bool is_next_close = peek_token_is(close_bracket); if (!token_is(seperator) && is_next_close) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR092 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source)); + "ERR095 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, + exprtk_error_location)); return error_node(); } @@ -22277,7 +22846,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR093 - Expected '[' for start of range")); + "ERR096 - Expected '[' for start of range", + exprtk_error_location)); return false; } @@ -22297,14 +22867,14 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR094 - Failed parse begin section of range")); + "ERR097 - Failed parse begin section of range", + exprtk_error_location)); return false; - } else if (is_constant_node(r0)) { - T r0_value = r0->value(); + const T r0_value = r0->value(); if (r0_value >= T(0)) { @@ -22320,7 +22890,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR095 - Range lower bound less than zero! Constraint: r0 >= 0")); + "ERR098 - Range lower bound less than zero! Constraint: r0 >= 0", + exprtk_error_location)); return false; } @@ -22336,9 +22907,11 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR096 - Expected ':' for break in range")); + "ERR099 - Expected ':' for break in range", + exprtk_error_location)); rp.free(); + return false; } } @@ -22357,15 +22930,16 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR097 - Failed parse end section of range")); + "ERR100 - Failed parse end section of range", + exprtk_error_location)); rp.free(); - return false; + return false; } else if (is_constant_node(r1)) { - T r1_value = r1->value(); + const T r1_value = r1->value(); if (r1_value >= T(0)) { @@ -22381,7 +22955,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR098 - Range upper bound less than zero! Constraint: r1 >= 0")); + "ERR101 - Range upper bound less than zero! Constraint: r1 >= 0", + exprtk_error_location)); return false; } @@ -22397,9 +22972,11 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR099 - Expected ']' for start of range")); + "ERR102 - Expected ']' for start of range", + exprtk_error_location)); rp.free(); + return false; } } @@ -22409,14 +22986,15 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - bool rp_result = rp(r0,r1); + const bool rp_result = rp(r0,r1); if (!rp_result || (r0 > r1)) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR100 - Invalid range, Constraint: r0 <= r1")); + "ERR103 - Invalid range, Constraint: r0 <= r1", + exprtk_error_location)); return false; } @@ -22440,7 +23018,6 @@ namespace exprtk expression_node_ptr result = error_node(); strvar_node_t const_str_node = static_cast<strvar_node_t>(0); - bool is_const_string = false; scope_element& se = sem_.get_active_element(symbol); @@ -22448,7 +23025,7 @@ namespace exprtk { se.active = true; result = se.str_node; - lodge_symbol(symbol,e_st_local_string); + lodge_symbol(symbol, e_st_local_string); } else { @@ -22457,22 +23034,21 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR101 - Unknown string symbol")); + "ERR104 - Unknown string symbol", + exprtk_error_location)); return error_node(); } result = symtab_store_.get_stringvar(symbol); - is_const_string = symtab_store_.is_constant_string(symbol); - - if (is_const_string) + if (symtab_store_.is_constant_string(symbol)) { const_str_node = static_cast<strvar_node_t>(result); result = expression_generator_(const_str_node->str()); } - lodge_symbol(symbol,e_st_string); + lodge_symbol(symbol, e_st_string); } if (peek_token_is(token_t::e_lsqrbracket)) @@ -22509,7 +23085,8 @@ namespace exprtk result = expression_generator_(const_str_node->ref(),rp); } else - result = expression_generator_(static_cast<details::stringvar_node<T>*>(result)->ref(),rp); + result = expression_generator_(static_cast<details::stringvar_node<T>*> + (result)->ref(), rp); if (result) rp.clear(); @@ -22529,8 +23106,8 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities inline expression_node_ptr parse_const_string() { - const std::string const_str = current_token().value; - expression_node_ptr result = expression_generator_(const_str); + const std::string const_str = current_token().value; + expression_node_ptr result = expression_generator_(const_str); if (peek_token_is(token_t::e_lsqrbracket)) { @@ -22571,9 +23148,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR102 - Overflow in range for string: '" + const_str + "'[" + + "ERR105 - Overflow in range for string: '" + const_str + "'[" + (rp.n0_c.first ? details::to_str(static_cast<int>(rp.n0_c.second)) : "?") + ":" + - (rp.n1_c.first ? details::to_str(static_cast<int>(rp.n1_c.second)) : "?") + "]")); + (rp.n1_c.first ? details::to_str(static_cast<int>(rp.n1_c.second)) : "?") + "]", + exprtk_error_location)); return error_node(); } @@ -22604,8 +23182,8 @@ namespace exprtk const scope_element& se = sem_.get_active_element(symbol); if ( - (se.name != symbol) || - (se.depth > state_.scope_depth) || + !details::imatch(se.name, symbol) || + (se.depth > state_.scope_depth) || (scope_element::e_vector != se.type) ) { @@ -22614,7 +23192,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR103 - Symbol '" + symbol+ " not a vector")); + "ERR106 - Symbol '" + symbol+ " not a vector", + exprtk_error_location)); return error_node(); } @@ -22639,7 +23218,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR104 - Failed to parse index for vector: '" + symbol + "'")); + "ERR107 - Failed to parse index for vector: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -22648,7 +23228,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR105 - Expected ']' for index of vector: '" + symbol + "'")); + "ERR108 - Expected ']' for index of vector: '" + symbol + "'", + exprtk_error_location)); free_node(node_allocator_,index_expr); @@ -22658,7 +23239,7 @@ namespace exprtk // Perform compile-time range check if (details::is_constant_node(index_expr)) { - const std::size_t index = std::size_t(index_expr->value()); + const std::size_t index = static_cast<std::size_t>(details::numeric::to_int32(index_expr->value())); const std::size_t vec_size = vec->size(); if (index >= vec_size) @@ -22666,8 +23247,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR106 - Index of " + details::to_str(index) + " out of range for " - "vector '" + symbol + "' of size " + details::to_str(vec_size))); + "ERR109 - Index of " + details::to_str(index) + " out of range for " + "vector '" + symbol + "' of size " + details::to_str(vec_size), + exprtk_error_location)); free_node(node_allocator_,index_expr); @@ -22681,9 +23263,10 @@ namespace exprtk inline expression_node_ptr parse_vararg_function_call(ivararg_function<T>* vararg_function, const std::string& vararg_function_name) { std::vector<expression_node_ptr> arg_list; + expression_node_ptr result = error_node(); - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); next_token(); @@ -22696,8 +23279,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR107 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed")); + "ERR110 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -22720,8 +23304,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR108 - Expected ',' for call to vararg function: " - + vararg_function_name)); + "ERR111 - Expected ',' for call to vararg function: " + + vararg_function_name, + exprtk_error_location)); return error_node(); } @@ -22733,8 +23318,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR109 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed")); + "ERR112 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -22744,9 +23330,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR110 - Invalid number of parameters to call to vararg function: " + "ERR113 - Invalid number of parameters to call to vararg function: " + vararg_function_name + ", require at least " - + details::to_str(static_cast<int>(vararg_function->min_num_args())) + " parameters")); + + details::to_str(static_cast<int>(vararg_function->min_num_args())) + " parameters", + exprtk_error_location)); return error_node(); } @@ -22755,9 +23342,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR111 - Invalid number of parameters to call to vararg function: " + "ERR114 - Invalid number of parameters to call to vararg function: " + vararg_function_name + ", require no more than " - + details::to_str(static_cast<int>(vararg_function->max_num_args())) + " parameters")); + + details::to_str(static_cast<int>(vararg_function->max_num_args())) + " parameters", + exprtk_error_location)); return error_node(); } @@ -22773,34 +23361,54 @@ namespace exprtk { public: + enum return_type_t + { + e_overload = ' ', + e_numeric = 'T', + e_string = 'S' + }; + + struct function_prototype_t + { + return_type_t return_type; + std::string param_seq; + }; + typedef parser<T> parser_t; - typedef std::vector<std::string> param_seq_list_t; + typedef std::vector<function_prototype_t> function_definition_list_t; type_checker(parser_t& p, const std::string& func_name, - const std::string& param_seq) + const std::string& func_prototypes, + const return_type_t default_return_type) : invalid_state_(true), parser_(p), - function_name_(func_name) + function_name_(func_name), + default_return_type_(default_return_type) { - split(param_seq); + parse_function_prototypes(func_prototypes); + } + + void set_default_return_type(const std::string& return_type) + { + default_return_type_ = return_type; } bool verify(const std::string& param_seq, std::size_t& pseq_index) { - if (param_seq_list_.empty()) + if (function_definition_list_.empty()) return true; std::vector<std::pair<std::size_t,char> > error_list; - for (std::size_t i = 0; i < param_seq_list_.size(); ++i) + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) { details::char_t diff_value = 0; std::size_t diff_index = 0; - bool result = details::sequence_match(param_seq_list_[i], - param_seq, - diff_index,diff_value); + const bool result = details::sequence_match(function_definition_list_[i].param_seq, + param_seq, + diff_index, diff_value); if (result) { @@ -22808,7 +23416,7 @@ namespace exprtk return true; } else - error_list.push_back(std::make_pair(diff_index,diff_value)); + error_list.push_back(std::make_pair(diff_index, diff_value)); } if (1 == error_list.size()) @@ -22817,8 +23425,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR112 - Failed parameter type check for function '" + function_name_ + "', " - "Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'")); + "ERR115 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } else { @@ -22837,8 +23447,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR113 - Failed parameter type check for function '" + function_name_ + "', " - "Best match: '" + param_seq_list_[max_diff_index] + "' call set: '" + param_seq +"'")); + "ERR116 - Failed parameter type check for function '" + function_name_ + "', " + "Best match: '" + function_definition_list_[max_diff_index].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } return false; @@ -22846,12 +23458,17 @@ namespace exprtk std::size_t paramseq_count() const { - return param_seq_list_.size(); + return function_definition_list_.size(); } std::string paramseq(const std::size_t& index) const { - return param_seq_list_[index]; + return function_definition_list_[index].param_seq; + } + + return_type_t return_type(const std::size_t& index) const + { + return function_definition_list_[index].return_type; } bool invalid() const @@ -22861,91 +23478,142 @@ namespace exprtk bool allow_zero_parameters() const { - return - param_seq_list_.end() != std::find(param_seq_list_.begin(), - param_seq_list_.end(), - "Z"); + + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) + { + if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) + { + return true; + } + } + + return false; } private: - void split(const std::string& s) + std::vector<std::string> split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const { - if (s.empty()) - return; + std::string::const_iterator current_begin = param_seq.begin(); + std::string::const_iterator iter = param_seq.begin(); + + std::vector<std::string> result; + + while (iter != param_seq.end()) + { + if (*iter == delimiter) + { + result.push_back(std::string(current_begin, iter)); + current_begin = ++iter; + } + else + ++iter; + } + + if (current_begin != iter) + { + result.push_back(std::string(current_begin, iter)); + } - std::size_t start = 0; - std::size_t end = 0; + return result; + } - param_seq_list_t param_seq_list; + inline bool is_valid_token(std::string param_seq, + function_prototype_t& funcproto) const + { + // Determine return type + funcproto.return_type = default_return_type_; - struct token_validator + if (param_seq.size() > 2) { - static inline bool process(const std::string& str, - std::size_t s, std::size_t e, - param_seq_list_t& psl) + if (':' == param_seq[1]) { - if ( - (e - s) && - (std::string::npos == str.find("?*")) && - (std::string::npos == str.find("**")) - ) + // Note: Only overloaded igeneric functions can have return + // type definitions. + if (type_checker::e_overload != default_return_type_) + return false; + + switch (param_seq[0]) { - const std::string curr_str = str.substr(s,e - s); + case 'T' : funcproto.return_type = type_checker::e_numeric; + break; - if ("Z" == curr_str) - { - psl.push_back(curr_str); - return true; - } - else if (std::string::npos == curr_str.find_first_not_of("STV*?|")) - { - psl.push_back(curr_str); - return true; - } + case 'S' : funcproto.return_type = type_checker::e_string; + break; + + default : return false; } - return false; + param_seq.erase(0,2); } - }; + } - while (std::string::npos != (end = s.find('|',start))) + if ( + (std::string::npos != param_seq.find("?*")) || + (std::string::npos != param_seq.find("**")) + ) { - if (!token_validator::process(s,start,end,param_seq_list)) + return false; + } + else if ( + (std::string::npos == param_seq.find_first_not_of("STV*?|")) || + ("Z" == param_seq) + ) + { + funcproto.param_seq = param_seq; + return true; + } + + return false; + } + + void parse_function_prototypes(const std::string& func_prototypes) + { + if (func_prototypes.empty()) + return; + + std::vector<std::string> param_seq_list = split_param_seq(func_prototypes); + + typedef std::map<std::string,std::size_t> param_seq_map_t; + param_seq_map_t param_seq_map; + + for (std::size_t i = 0; i < param_seq_list.size(); ++i) + { + function_prototype_t func_proto; + + if (!is_valid_token(param_seq_list[i], func_proto)) { invalid_state_ = false; - const std::string err_param_seq = s.substr(start,end - start); - parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR114 - Invalid parameter sequence of '" + err_param_seq + - "' for function: " + function_name_)); - + "ERR117 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, + exprtk_error_location)); return; } - else - start = end + 1; - } - if (start < s.size()) - { - if (token_validator::process(s,start,s.size(),param_seq_list)) - param_seq_list_ = param_seq_list; - else + param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); + + if (param_seq_map.end() != seq_itr) { - const std::string err_param_seq = s.substr(start,s.size() - start); + invalid_state_ = false; parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR115 - Invalid parameter sequence of '" + err_param_seq + - "' for function: " + function_name_)); + "ERR118 - Function '" + function_name_ + "' has a parameter sequence conflict between " + + "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + + "pseq_idx[" + details::to_str(i) + "] " + + "param seq: " + param_seq_list[i], + exprtk_error_location)); return; } + + function_definition_list_.push_back(func_proto); } } @@ -22955,42 +23623,29 @@ namespace exprtk bool invalid_state_; parser_t& parser_; std::string function_name_; - param_seq_list_t param_seq_list_; + const return_type_t default_return_type_; + function_definition_list_t function_definition_list_; }; inline expression_node_ptr parse_generic_function_call(igeneric_function<T>* function, const std::string& function_name) { std::vector<expression_node_ptr> arg_list; - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); next_token(); std::string param_type_list; - type_checker tc(*this,function_name,function->parameter_sequence); + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); if (tc.invalid()) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR116 - Type checker instantiation failure for generic function: " + function_name)); - - return error_node(); - } - - if ( - !function->parameter_sequence.empty() && - function->allow_zero_parameters () && - !tc .allow_zero_parameters () - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR117 - Mismatch in zero parameter condition for generic function: " - + function_name)); + "ERR119 - Type checker instantiation failure for generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -23007,8 +23662,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR118 - Zero parameter call to generic function: " - + function_name + " not allowed")); + "ERR120 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -23038,7 +23694,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR119 - Expected ',' for call to generic function: " + function_name)); + "ERR121 - Expected ',' for call to generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -23054,8 +23711,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR120 - Zero parameter call to generic function: " - + function_name + " not allowed")); + "ERR122 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); return error_node(); } @@ -23070,7 +23728,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR121 - Expected ',' for call to generic function: " + function_name)); + "ERR123 - Invalid input parameter sequence for call to generic function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -23079,47 +23738,49 @@ namespace exprtk if (tc.paramseq_count() <= 1) result = expression_generator_ - .generic_function_call(function,arg_list); + .generic_function_call(function, arg_list); else result = expression_generator_ - .generic_function_call(function,arg_list,param_seq_index); + .generic_function_call(function, arg_list, param_seq_index); sdd.delete_ptr = (0 == result); return result; } - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name) + inline bool parse_igeneric_function_params(std::string& param_type_list, + std::vector<expression_node_ptr>& arg_list, + const std::string function_name, + igeneric_function<T>* function, + const type_checker& tc) { - std::vector<expression_node_ptr> arg_list; - - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); - - next_token(); - - std::string param_type_list; - - type_checker tc(*this,function_name,function->parameter_sequence); - - if ( - (!function->parameter_sequence.empty()) && - (0 == tc.paramseq_count()) - ) - { - return error_node(); - } - if (token_is(token_t::e_lbracket)) { - if (!token_is(token_t::e_rbracket)) + if (token_is(token_t::e_rbracket)) + { + if ( + !function->allow_zero_parameters() && + !tc .allow_zero_parameters() + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR124 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return false; + } + } + else { for ( ; ; ) { expression_node_ptr arg = parse_expression(); if (0 == arg) - return error_node(); + return false; if (is_ivector_node(arg)) param_type_list += 'V'; @@ -23137,12 +23798,44 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR122 - Expected ',' for call to string function: " + function_name)); + "ERR125 - Expected ',' for call to string function: " + function_name, + exprtk_error_location)); - return error_node(); + return false; } } } + + return true; + } + else + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector<expression_node_ptr> arg_list; + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); } std::size_t param_seq_index = 0; @@ -23152,7 +23845,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR123 - Expected ',' for call to string function: " + function_name)); + "ERR126 - Invalid input parameter sequence for call to string function: " + function_name, + exprtk_error_location)); return error_node(); } @@ -23161,25 +23855,98 @@ namespace exprtk if (tc.paramseq_count() <= 1) result = expression_generator_ - .string_function_call(function,arg_list); + .string_function_call(function, arg_list); else result = expression_generator_ - .string_function_call(function,arg_list,param_seq_index); + .string_function_call(function, arg_list, param_seq_index); sdd.delete_ptr = (0 == result); return result; } + + inline expression_node_ptr parse_overload_function_call(igeneric_function<T>* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector<expression_node_ptr> arg_list; + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); + } + + std::size_t param_seq_index = 0; + + if (!tc.verify(param_type_list, param_seq_index)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR127 - Invalid input parameter sequence for call to overloaded function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (type_checker::e_numeric == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .generic_function_call(function, arg_list); + else + result = expression_generator_ + .generic_function_call(function, arg_list, param_seq_index); + } + else if (type_checker::e_string == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .string_function_call(function, arg_list); + else + result = expression_generator_ + .string_function_call(function, arg_list, param_seq_index); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR128 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); + } + + sdd.delete_ptr = (0 == result); + return result; + } #endif template <typename Type, std::size_t NumberOfParameters> struct parse_special_function_impl { - static inline expression_node_ptr process(parser<Type>& p,const details::operator_type opt_type) + static inline expression_node_ptr process(parser<Type>& p,const details::operator_type opt_type, const std::string& sf_name) { expression_node_ptr branch[NumberOfParameters]; expression_node_ptr result = error_node(); + std::fill_n(branch,NumberOfParameters,reinterpret_cast<expression_node_ptr>(0)); + scoped_delete<expression_node_t,NumberOfParameters> sd(p,branch); p.next_token(); @@ -23189,7 +23956,8 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR124 - Expected '(' for special function")); + "ERR129 - Expected '(' for special function '" + sf_name + "'", + exprtk_error_location)); return error_node(); } @@ -23209,7 +23977,8 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR125 - Expected ',' before next parameter of special function")); + "ERR130 - Expected ',' before next parameter of special function '" + sf_name + "'", + exprtk_error_location)); return p.error_node(); } @@ -23217,7 +23986,15 @@ namespace exprtk } if (!p.token_is(token_t::e_rbracket)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR131 - Invalid number of parameters for special function '" + sf_name + "'", + exprtk_error_location)); + return p.error_node(); + } else result = p.expression_generator_.special_function(opt_type,branch); @@ -23229,40 +24006,45 @@ namespace exprtk inline expression_node_ptr parse_special_function() { + const std::string sf_name = current_token().value; + // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) if ( - !details::is_digit(current_token().value[2]) || - !details::is_digit(current_token().value[3]) + !details::is_digit(sf_name[2]) || + !details::is_digit(sf_name[3]) ) { set_error( make_error(parser_error::e_token, current_token(), - "ERR126 - Invalid special function[1]: " + current_token().value)); + "ERR132 - Invalid special function[1]: " + sf_name, + exprtk_error_location)); return error_node(); } - const unsigned int id = (current_token().value[2] - '0') * 10 + (current_token().value[3] - '0'); + const int id = (sf_name[2] - '0') * 10 + + (sf_name[3] - '0'); if (id >= details::e_sffinal) { set_error( make_error(parser_error::e_token, current_token(), - "ERR127 - Invalid special function[2]: " + current_token().value)); + "ERR133 - Invalid special function[2]: " + sf_name, + exprtk_error_location)); return error_node(); } - const std::size_t sf_3_to_4 = details::e_sf48; + const int sf_3_to_4 = details::e_sf48; const details::operator_type opt_type = details::operator_type(id + 1000); - const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3 : 4; + const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3U : 4U; switch (NumberOfParameters) { - case 3 : return parse_special_function_impl<T,3>::process(*this,opt_type); - case 4 : return parse_special_function_impl<T,4>::process(*this,opt_type); + case 3 : return parse_special_function_impl<T,3>::process((*this), opt_type, sf_name); + case 4 : return parse_special_function_impl<T,4>::process((*this), opt_type, sf_name); default : return error_node(); } } @@ -23281,7 +24063,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR128 - Break call within a break call is not allowed")); + "ERR134 - Break call within a break call is not allowed", + exprtk_error_location)); return error_node(); } @@ -23303,7 +24086,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR129 - Failed to parse return expression for 'break' statement")); + "ERR135 - Failed to parse return expression for 'break' statement", + exprtk_error_location)); return error_node(); } @@ -23312,7 +24096,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR130 - Expected ']' at the completion of break's return expression")); + "ERR136 - Expected ']' at the completion of break's return expression", + exprtk_error_location)); free_node(node_allocator_,return_expr); @@ -23329,7 +24114,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR131 - Invalid use of 'break', allowed only in the scope of a loop")); + "ERR137 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); } return error_node(); @@ -23351,7 +24137,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR132 - Invalid use of 'continue', allowed only in the scope of a loop")); + "ERR138 - Invalid use of 'continue', allowed only in the scope of a loop", + exprtk_error_location)); return error_node(); } @@ -23367,7 +24154,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR133 - Expected '[' as part of vector size definition")); + "ERR139 - Expected '[' as part of vector size definition", + exprtk_error_location)); return error_node(); } @@ -23376,7 +24164,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR134 - Failed to determine size of vector '" + vec_name + "'")); + "ERR140 - Failed to determine size of vector '" + vec_name + "'", + exprtk_error_location)); return error_node(); } @@ -23387,33 +24176,38 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR135 - Expected a literal number as size of vector '" + vec_name + "'")); + "ERR141 - Expected a literal number as size of vector '" + vec_name + "'", + exprtk_error_location)); return error_node(); } - T vector_size = size_expr->value(); + const T vector_size = size_expr->value(); free_node(node_allocator_,size_expr); + const T max_vector_size = T(2000000000.0); + if ( (vector_size <= T(0)) || std::not_equal_to<T>() - (T(0),vector_size - details::numeric::trunc(vector_size)) + (T(0),vector_size - details::numeric::trunc(vector_size)) || + (vector_size > max_vector_size) ) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR136 - Invalid vector size. Must be an integer greater than zero, size: " + - details::to_str(details::numeric::to_int32(vector_size)))); + "ERR142 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + + details::to_str(details::numeric::to_int32(vector_size)), + exprtk_error_location)); return error_node(); } std::vector<expression_node_ptr> vec_initilizer_list; - scoped_vec_delete<expression_node_t> svd(*this,vec_initilizer_list); + scoped_vec_delete<expression_node_t> svd((*this),vec_initilizer_list); bool single_value_initialiser = false; bool vec_to_vec_initialiser = false; @@ -23424,7 +24218,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR137 - Expected ']' as part of vector size definition")); + "ERR143 - Expected ']' as part of vector size definition", + exprtk_error_location)); return error_node(); } @@ -23435,7 +24230,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR138 - Expected ':=' as part of vector definition")); + "ERR144 - Expected ':=' as part of vector definition", + exprtk_error_location)); return error_node(); } @@ -23448,7 +24244,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR139 - Failed to parse single vector initialiser")); + "ERR145 - Failed to parse single vector initialiser", + exprtk_error_location)); return error_node(); } @@ -23460,7 +24257,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR140 - Expected ']' to close single value vector initialiser")); + "ERR146 - Expected ']' to close single value vector initialiser", + exprtk_error_location)); return error_node(); } @@ -23487,7 +24285,7 @@ namespace exprtk // Are we dealing with a user defined vector? else if (symtab_store_.is_vector(current_token().value)) { - lodge_symbol(current_token().value,e_st_vector); + lodge_symbol(current_token().value, e_st_vector); if (0 != (initialiser = parse_expression())) vec_initilizer_list.push_back(initialiser); @@ -23506,7 +24304,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR141 - Expected '{' as part of vector initialiser list")); + "ERR147 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -23525,7 +24324,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR142 - Expected '{' as part of vector initialiser list")); + "ERR148 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); return error_node(); } @@ -23535,14 +24335,15 @@ namespace exprtk if (token_is(token_t::e_rcrlbracket)) break; - bool is_next_close = peek_token_is(token_t::e_rcrlbracket); + const bool is_next_close = peek_token_is(token_t::e_rcrlbracket); if (!token_is(token_t::e_comma) && is_next_close) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR143 - Expected ',' between vector initialisers")); + "ERR149 - Expected ',' between vector initialisers", + exprtk_error_location)); return error_node(); } @@ -23553,9 +24354,9 @@ namespace exprtk } if ( - !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) ) { if (!token_is(token_t::e_eof)) @@ -23563,7 +24364,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR144 - Expected ';' at end of vector definition")); + "ERR150 - Expected ';' at end of vector definition", + exprtk_error_location)); return error_node(); } @@ -23574,7 +24376,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR145 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'")); + "ERR151 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + exprtk_error_location)); return error_node(); } @@ -23582,7 +24385,7 @@ namespace exprtk typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); - std::size_t vec_size = static_cast<std::size_t>(details::numeric::to_int32(vector_size)); + const std::size_t vec_size = static_cast<std::size_t>(details::numeric::to_int32(vector_size)); scope_element& se = sem_.get_element(vec_name); @@ -23593,7 +24396,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR146 - Illegal redefinition of local vector: '" + vec_name + "'")); + "ERR152 - Illegal redefinition of local vector: '" + vec_name + "'", + exprtk_error_location)); return error_node(); } @@ -23626,7 +24430,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR147 - Failed to add new local vector '" + vec_name + "' to SEM")); + "ERR153 - Failed to add new local vector '" + vec_name + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -23642,17 +24447,21 @@ namespace exprtk state_.activate_side_effect("parse_define_vector_statement()"); - lodge_symbol(vec_name,e_st_local_vector); + lodge_symbol(vec_name, e_st_local_vector); expression_node_ptr result = error_node(); if (null_initialisation) result = expression_generator_(T(0.0)); else if (vec_to_vec_initialiser) + { + expression_node_ptr vec_node = node_allocator_.allocate<vector_node_t>(vec_holder); + result = expression_generator_( details::e_assign, - node_allocator_.allocate<vector_node_t>(vec_holder), + vec_node, vec_initilizer_list[0]); + } else result = node_allocator_ .allocate<details::vector_assignment_node<T> >( @@ -23680,7 +24489,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR148 - Illegal redefinition of local variable: '" + str_name + "'")); + "ERR154 - Illegal redefinition of local variable: '" + str_name + "'", + exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -23711,7 +24521,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR149 - Failed to add new local string variable '" + str_name + "' to SEM")); + "ERR155 - Failed to add new local string variable '" + str_name + "' to SEM", + exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -23725,7 +24536,7 @@ namespace exprtk exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); } - lodge_symbol(str_name,e_st_local_string); + lodge_symbol(str_name, e_st_local_string); state_.activate_side_effect("parse_define_string_statement()"); @@ -23756,7 +24567,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR150 - Illegal variable definition")); + "ERR156 - Illegal variable definition", + exprtk_error_location)); return error_node(); } @@ -23776,7 +24588,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR151 - Expected a symbol for variable definition")); + "ERR157 - Expected a symbol for variable definition", + exprtk_error_location)); return error_node(); } @@ -23785,7 +24598,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR152 - Illegal redefinition of reserved keyword: '" + var_name + "'")); + "ERR158 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -23794,7 +24608,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR153 - Illegal redefinition of variable '" + var_name + "'")); + "ERR159 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -23803,7 +24618,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR154 - Illegal redefinition of local variable: '" + var_name + "'")); + "ERR160 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -23822,16 +24638,17 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR155 - Failed to parse initialisation expression")); + "ERR161 - Failed to parse initialisation expression", + exprtk_error_location)); return error_node(); } } if ( - !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) ) { if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) @@ -23839,7 +24656,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR156 - Expected ';' after variable definition")); + "ERR162 - Expected ';' after variable definition", + exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -23866,9 +24684,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR157 - Illegal redefinition of local variable: '" + var_name + "'")); + "ERR163 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); return error_node(); } @@ -23897,9 +24716,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR158 - Failed to add new local variable '" + var_name + "' to SEM")); + "ERR164 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); - free_node(node_allocator_,initialisation_expression); + free_node(node_allocator_, initialisation_expression); sem_.free_element(nse); @@ -23913,7 +24733,7 @@ namespace exprtk state_.activate_side_effect("parse_define_var_statement()"); - lodge_symbol(var_name,e_st_local_variable); + lodge_symbol(var_name, e_st_local_variable); expression_node_ptr branch[2] = {0}; @@ -23933,7 +24753,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR159 - Expected a '{}' for uninitialised var definition")); + "ERR165 - Expected a '{}' for uninitialised var definition", + exprtk_error_location)); return error_node(); } @@ -23942,7 +24763,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR160 - Expected ';' after uninitialised variable definition")); + "ERR166 - Expected ';' after uninitialised variable definition", + exprtk_error_location)); return error_node(); } @@ -23958,7 +24780,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR161 - Illegal redefinition of local variable: '" + var_name + "'")); + "ERR167 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } @@ -23987,7 +24810,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR162 - Failed to add new local variable '" + var_name + "' to SEM")); + "ERR168 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); sem_.free_element(nse); @@ -23998,7 +24822,7 @@ namespace exprtk nse.name.c_str())); } - lodge_symbol(var_name,e_st_local_variable); + lodge_symbol(var_name, e_st_local_variable); state_.activate_side_effect("parse_uninitialised_var_statement()"); @@ -24019,7 +24843,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR163 - Expected '(' at start of swap statement")); + "ERR169 - Expected '(' at start of swap statement", + exprtk_error_location)); return error_node(); } @@ -24037,7 +24862,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR164 - Expected a symbol for variable or vector element definition")); + "ERR170 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); return error_node(); } @@ -24048,7 +24874,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR165 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); + "ERR171 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -24073,14 +24900,15 @@ namespace exprtk variable0 = se.var_node; } - lodge_symbol(var0_name,e_st_variable); + lodge_symbol(var0_name, e_st_variable); if (0 == variable0) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR166 - First parameter to swap is an invalid variable: '" + var0_name + "'")); + "ERR172 - First parameter to swap is an invalid variable: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } @@ -24093,7 +24921,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR167 - Expected ',' between parameters to swap")); + "ERR173 - Expected ',' between parameters to swap", + exprtk_error_location)); if (variable0_generated) { @@ -24110,7 +24939,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR168 - Expected a symbol for variable or vector element definition")); + "ERR174 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); if (variable0_generated) { @@ -24126,7 +24956,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR169 - Second parameter to swap is an invalid vector element: '" + var1_name + "'")); + "ERR175 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + exprtk_error_location)); if (variable0_generated) { @@ -24156,14 +24987,15 @@ namespace exprtk variable1 = se.var_node; } - lodge_symbol(var1_name,e_st_variable); + lodge_symbol(var1_name, e_st_variable); if (0 == variable1) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR170 - Second parameter to swap is an invalid variable: '" + var1_name + "'")); + "ERR176 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + exprtk_error_location)); if (variable0_generated) { @@ -24181,7 +25013,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR171 - Expected ')' at end of swap statement")); + "ERR177 - Expected ')' at end of swap statement", + exprtk_error_location)); if (variable0_generated) { @@ -24197,6 +25030,7 @@ namespace exprtk } typedef details::variable_node<T>* variable_node_ptr; + variable_node_ptr v0 = variable_node_ptr(0); variable_node_ptr v1 = variable_node_ptr(0); @@ -24207,7 +25041,7 @@ namespace exprtk (0 != (v1 = dynamic_cast<variable_node_ptr>(variable1))) ) { - result = node_allocator_.allocate<details::swap_node<T> >(v0,v1); + result = node_allocator_.allocate<details::swap_node<T> >(v0, v1); if (variable0_generated) { @@ -24220,7 +25054,8 @@ namespace exprtk } } else - result = node_allocator_.allocate<details::swap_generic_node<T> >(variable0,variable1); + result = node_allocator_.allocate<details::swap_generic_node<T> > + (variable0, variable1); state_.activate_side_effect("parse_swap_statement()"); @@ -24235,7 +25070,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR172 - Return call within a return call is not allowed")); + "ERR178 - Return call within a return call is not allowed", + exprtk_error_location)); return error_node(); } @@ -24244,7 +25080,7 @@ namespace exprtk std::vector<expression_node_ptr> arg_list; - scoped_vec_delete<expression_node_t> sdd(*this,arg_list); + scoped_vec_delete<expression_node_t> sdd((*this),arg_list); if (!details::imatch(current_token().value,"return")) { @@ -24258,7 +25094,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR173 - Expected '[' at start of return statement")); + "ERR179 - Expected '[' at start of return statement", + exprtk_error_location)); return error_node(); } @@ -24280,7 +25117,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR174 - Expected ',' between values during call to return")); + "ERR180 - Expected ',' between values during call to return", + exprtk_error_location)); return error_node(); } @@ -24291,12 +25129,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR175 - Zero parameter return statement not allowed")); + "ERR181 - Zero parameter return statement not allowed", + exprtk_error_location)); return error_node(); } - lexer::token prev_token = current_token(); + const lexer::token prev_token = current_token(); if (token_is(token_t::e_rsqrbracket)) { @@ -24305,7 +25144,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR176 - Invalid ']' found during return call")); + "ERR182 - Invalid ']' found during return call", + exprtk_error_location)); return error_node(); } @@ -24357,7 +25197,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR177 - Invalid sequence of variable '"+ symbol + "' and bracket")); + "ERR183 - Invalid sequence of variable '"+ symbol + "' and bracket", + exprtk_error_location)); return false; } @@ -24404,7 +25245,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR178 - Invalid sequence of brackets")); + "ERR184 - Invalid sequence of brackets", + exprtk_error_location)); return false; } @@ -24436,7 +25278,7 @@ namespace exprtk if (!post_variable_process(symbol)) return error_node(); - lodge_symbol(symbol,e_st_variable); + lodge_symbol(symbol, e_st_variable); next_token(); return variable; @@ -24447,12 +25289,12 @@ namespace exprtk { scope_element& se = sem_.get_active_element(symbol); - if (se.active && (se.name == symbol)) + if (se.active && details::imatch(se.name, symbol)) { if (scope_element::e_variable == se.type) { se.active = true; - lodge_symbol(symbol,e_st_local_variable); + lodge_symbol(symbol, e_st_local_variable); if (!post_variable_process(symbol)) return error_node(); @@ -24488,7 +25330,7 @@ namespace exprtk if (function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr func_node = parse_function_invocation(function,symbol); @@ -24500,7 +25342,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR179 - Failed to generate node for function: '" + symbol + "'")); + "ERR185 - Failed to generate node for function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -24513,10 +25356,10 @@ namespace exprtk if (vararg_function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr vararg_func_node = - parse_vararg_function_call(vararg_function,symbol); + parse_vararg_function_call(vararg_function, symbol); if (vararg_func_node) return vararg_func_node; @@ -24525,7 +25368,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR180 - Failed to generate node for vararg function: '" + symbol + "'")); + "ERR186 - Failed to generate node for vararg function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -24538,10 +25382,10 @@ namespace exprtk if (generic_function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr genericfunc_node = - parse_generic_function_call(generic_function,symbol); + parse_generic_function_call(generic_function, symbol); if (genericfunc_node) return genericfunc_node; @@ -24550,7 +25394,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR181 - Failed to generate node for generic function: '" + symbol + "'")); + "ERR187 - Failed to generate node for generic function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -24564,10 +25409,10 @@ namespace exprtk if (string_function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr stringfunc_node = - parse_string_function_call(string_function,symbol); + parse_string_function_call(string_function, symbol); if (stringfunc_node) return stringfunc_node; @@ -24576,7 +25421,34 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR182 - Failed to generate node for string function: '" + symbol + "'")); + "ERR188 - Failed to generate node for string function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg overloaded scalar/string returning function? + igeneric_function<T>* overload_function = symtab_store_.get_overload_function(symbol); + + if (overload_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr overloadfunc_node = + parse_overload_function_call(overload_function, symbol); + + if (overloadfunc_node) + return overloadfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR189 - Failed to generate node for overload function: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -24587,18 +25459,22 @@ namespace exprtk // Are we dealing with a vector? if (symtab_store_.is_vector(symbol)) { - lodge_symbol(symbol,e_st_vector); + lodge_symbol(symbol, e_st_vector); return parse_vector(); } if (details::is_reserved_symbol(symbol)) { - if (settings_.function_enabled(symbol) || !details::is_base_function(symbol)) + if ( + settings_.function_enabled(symbol) || + !details::is_base_function(symbol) + ) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR183 - Invalid use of reserved symbol '" + symbol + "'")); + "ERR190 - Invalid use of reserved symbol '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -24610,12 +25486,14 @@ namespace exprtk if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) { symbol_table_t& symtab = symtab_store_.get_symbol_table(); + std::string error_message; if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) { T default_value = T(0); - typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type; + + typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type; if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) { @@ -24643,7 +25521,7 @@ namespace exprtk var = expression_generator_(var->value()); } - lodge_symbol(symbol,e_st_variable); + lodge_symbol(symbol, e_st_variable); if (!post_variable_process(symbol)) return error_node(); @@ -24658,34 +25536,29 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR184 - Failed to create variable: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message))); + "ERR191 - Failed to create variable: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); } else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) { if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) { - static bool usr_extmode_active = false; + expression_node_ptr result = parse_symtab_symbol(); - if (!usr_extmode_active) + if (result) { - usr_extmode_active = true; - expression_node_ptr result = parse_symtab_symbol(); - usr_extmode_active = false; - - if (result) - { - return result; - } + return result; } } set_error( make_error(parser_error::e_symtab, current_token(), - "ERR185 - Failed to resolve symbol: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message))); + "ERR192 - Failed to resolve symbol: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); } return error_node(); @@ -24695,7 +25568,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR186 - Undefined symbol: '" + symbol + "'")); + "ERR193 - Undefined symbol: '" + symbol + "'", + exprtk_error_location)); return error_node(); } @@ -24723,35 +25597,35 @@ namespace exprtk return parse_base_operation(); } else if ( - details::imatch(current_token().value,symbol_if) && + details::imatch(current_token().value, symbol_if) && settings_.control_struct_enabled(current_token().value) ) { return parse_conditional_statement(); } else if ( - details::imatch(current_token().value,symbol_while) && + details::imatch(current_token().value, symbol_while) && settings_.control_struct_enabled(current_token().value) ) { return parse_while_loop(); } else if ( - details::imatch(current_token().value,symbol_repeat) && + details::imatch(current_token().value, symbol_repeat) && settings_.control_struct_enabled(current_token().value) ) { return parse_repeat_until_loop(); } else if ( - details::imatch(current_token().value,symbol_for) && + details::imatch(current_token().value, symbol_for) && settings_.control_struct_enabled(current_token().value) ) { return parse_for_loop(); } else if ( - details::imatch(current_token().value,symbol_switch) && + details::imatch(current_token().value, symbol_switch) && settings_.control_struct_enabled(current_token().value) ) { @@ -24761,31 +25635,31 @@ namespace exprtk { return parse_special_function(); } - else if (details::imatch(current_token().value,symbol_null)) + else if (details::imatch(current_token().value, symbol_null)) { return parse_null_statement(); } #ifndef exprtk_disable_break_continue - else if (details::imatch(current_token().value,symbol_break)) + else if (details::imatch(current_token().value, symbol_break)) { return parse_break_statement(); } - else if (details::imatch(current_token().value,symbol_continue)) + else if (details::imatch(current_token().value, symbol_continue)) { return parse_continue_statement(); } #endif - else if (details::imatch(current_token().value,symbol_var)) + else if (details::imatch(current_token().value, symbol_var)) { return parse_define_var_statement(); } - else if (details::imatch(current_token().value,symbol_swap)) + else if (details::imatch(current_token().value, symbol_swap)) { return parse_swap_statement(); } #ifndef exprtk_disable_return_statement else if ( - details::imatch(current_token().value,symbol_return) && + details::imatch(current_token().value, symbol_return) && settings_.control_struct_enabled(current_token().value) ) { @@ -24801,7 +25675,8 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR187 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value)); + "ERR194 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value, + exprtk_error_location)); return error_node(); } @@ -24815,9 +25690,21 @@ namespace exprtk { T numeric_value = T(0); - if (details::string_to_real(current_token().value,numeric_value)) + if (details::string_to_real(current_token().value, numeric_value)) { expression_node_ptr literal_exp = expression_generator_(numeric_value); + + if (0 == literal_exp) + { + set_error( + make_error(parser_error::e_numeric, + current_token(), + "ERR195 - Failed generate node for scalar: '" + current_token().value + "'", + exprtk_error_location)); + + return error_node(); + } + next_token(); branch = literal_exp; } @@ -24826,7 +25713,8 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token(), - "ERR188 - Failed to convert '" + current_token().value + "' to a number")); + "ERR196 - Failed to convert '" + current_token().value + "' to a number", + exprtk_error_location)); return error_node(); } @@ -24852,7 +25740,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR189 - Expected ')' instead of: '" + current_token().value + "'")); + "ERR197 - Expected ')' instead of: '" + current_token().value + "'", + exprtk_error_location)); free_node(node_allocator_,branch); @@ -24876,7 +25765,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR190 - Expected ']' instead of: '" + current_token().value + "'")); + "ERR198 - Expected ']' instead of: '" + current_token().value + "'", + exprtk_error_location)); free_node(node_allocator_,branch); @@ -24900,7 +25790,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR191 - Expected '}' instead of: '" + current_token().value + "'")); + "ERR199 - Expected '}' instead of: '" + current_token().value + "'", + exprtk_error_location)); free_node(node_allocator_,branch); @@ -24939,7 +25830,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR192 - Premature end of expression[1]")); + "ERR200 - Premature end of expression[1]", + exprtk_error_location)); return error_node(); } @@ -24948,7 +25840,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR193 - Premature end of expression[2]")); + "ERR201 - Premature end of expression[2]", + exprtk_error_location)); return error_node(); } @@ -25121,33 +26014,33 @@ namespace exprtk return true; } - inline details::operator_type get_operator(const binary_functor_t& bop) + inline details::operator_type get_operator(const binary_functor_t& bop) const { return (*inv_binary_op_map_).find(bop)->second; } - inline expression_node_ptr operator()(const Type& v) const + inline expression_node_ptr operator() (const Type& v) const { return node_allocator_->allocate<literal_node_t>(v); } #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr operator()(const std::string& s) const + inline expression_node_ptr operator() (const std::string& s) const { return node_allocator_->allocate<string_literal_node_t>(s); } - inline expression_node_ptr operator()(std::string& s, range_t& rp) const + inline expression_node_ptr operator() (std::string& s, range_t& rp) const { return node_allocator_->allocate_rr<string_range_node_t>(s,rp); } - inline expression_node_ptr operator()(const std::string& s, range_t& rp) const + inline expression_node_ptr operator() (const std::string& s, range_t& rp) const { return node_allocator_->allocate_tt<const_string_range_node_t>(s,rp); } - inline expression_node_ptr operator()(expression_node_ptr branch, range_t& rp) const + inline expression_node_ptr operator() (expression_node_ptr branch, range_t& rp) const { if (is_generally_string_node(branch)) return node_allocator_->allocate_tt<generic_string_range_node_t>(branch,rp); @@ -25180,9 +26073,9 @@ namespace exprtk (details::e_frac == operation) || (details::e_trunc == operation) ; } - inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) + inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const { - typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; @@ -25192,9 +26085,9 @@ namespace exprtk return true; } - inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) + inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const { - typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); if (sf4_map_->end() == itr) return false; @@ -25204,9 +26097,9 @@ namespace exprtk return true; } - inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) + inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const { - typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; @@ -25216,9 +26109,9 @@ namespace exprtk return true; } - inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) + inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const { - typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); if (sf4_map_->end() == itr) return false; @@ -25228,22 +26121,36 @@ namespace exprtk return true; } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[1]) + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[1]) { if (0 == branch[0]) + { return error_node(); + } else if (details::is_null_node(branch[0])) + { return branch[0]; + } else if (details::is_break_node(branch[0])) + { return error_node(); + } else if (details::is_continue_node(branch[0])) + { return error_node(); + } else if (details::is_constant_node(branch[0])) + { return synthesize_expression<unary_node_t,1>(operation,branch); + } else if (unary_optimisable(operation) && details::is_variable_node(branch[0])) + { return synthesize_uv_expression(operation,branch); + } else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) + { return synthesize_uvec_expression(operation,branch); + } else return synthesize_unary_expression(operation,branch); } @@ -25251,11 +26158,11 @@ namespace exprtk inline bool is_assignment_operation(const details::operator_type& operation) const { return ( - (details::e_addass == operation) || - (details::e_subass == operation) || - (details::e_mulass == operation) || - (details::e_divass == operation) || - (details::e_modass == operation) + (details::e_addass == operation) || + (details::e_subass == operation) || + (details::e_mulass == operation) || + (details::e_divass == operation) || + (details::e_modass == operation) ) && parser_->settings_.assignment_enabled(operation); } @@ -25288,24 +26195,24 @@ namespace exprtk { switch (operation) { - case details::e_add : return "+"; - case details::e_sub : return "-"; - case details::e_mul : return "*"; - case details::e_div : return "/"; - case details::e_mod : return "%"; - case details::e_pow : return "^"; - case details::e_lt : return "<"; - case details::e_lte : return "<="; - case details::e_gt : return ">"; - case details::e_gte : return ">="; - case details::e_eq : return "=="; - case details::e_ne : return "!="; - case details::e_and : return "and"; - case details::e_nand : return "nand"; - case details::e_or : return "or"; - case details::e_nor : return "nor"; - case details::e_xor : return "xor"; - case details::e_xnor : return "xnor"; + case details::e_add : return "+" ; + case details::e_sub : return "-" ; + case details::e_mul : return "*" ; + case details::e_div : return "/" ; + case details::e_mod : return "%" ; + case details::e_pow : return "^" ; + case details::e_lt : return "<" ; + case details::e_lte : return "<=" ; + case details::e_gt : return ">" ; + case details::e_gte : return ">=" ; + case details::e_eq : return "==" ; + case details::e_ne : return "!=" ; + case details::e_and : return "and" ; + case details::e_nand : return "nand" ; + case details::e_or : return "or" ; + case details::e_nor : return "nor" ; + case details::e_xor : return "xor" ; + case details::e_xnor : return "xnor" ; default : return "UNKNOWN"; } } @@ -25332,7 +26239,7 @@ namespace exprtk (details::e_xnor == operation) ; } - inline std::string branch_to_id(expression_node_ptr branch) + inline std::string branch_to_id(expression_node_ptr branch) const { static const std::string null_str ("(null)" ); static const std::string const_str ("(c)" ); @@ -25373,7 +26280,7 @@ namespace exprtk return "ERROR"; } - inline std::string branch_to_id(expression_node_ptr (&branch)[2]) + inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const { return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); } @@ -25383,7 +26290,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); + return details::is_constant_node(branch[0]) && + details::is_variable_node(branch[1]) ; } inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25391,7 +26299,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); + return details::is_variable_node(branch[0]) && + details::is_constant_node(branch[1]) ; } inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25399,7 +26308,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); + return details::is_variable_node(branch[0]) && + details::is_variable_node(branch[1]) ; } inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25407,7 +26317,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); + return details::is_constant_node(branch[0]) && + !details::is_constant_node(branch[1]) ; } inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25415,7 +26326,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); + return !details::is_constant_node(branch[0]) && + details::is_constant_node(branch[1]) ; } inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25428,7 +26340,7 @@ namespace exprtk ) { return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])); + (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])) ; } else return false; @@ -25444,7 +26356,7 @@ namespace exprtk ) { return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])); + (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])) ; } else return false; @@ -25455,7 +26367,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); + return details::is_uv_node(branch[0]) && + details::is_uv_node(branch[1]) ; } inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25463,7 +26376,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); + return details::is_variable_node(branch[0]) && + !details::is_variable_node(branch[1]) ; } inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25471,7 +26385,8 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); + return !details::is_variable_node(branch[0]) && + details::is_variable_node(branch[1]) ; } inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const @@ -25479,10 +26394,11 @@ namespace exprtk if (!operation_optimisable(operation)) return false; else - return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1])); + return !details::is_constant_node(branch[0]) || + !details::is_constant_node(branch[1]) ; } - inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (is_assignment_operation(operation)) { @@ -25504,14 +26420,14 @@ namespace exprtk return false; } - inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) + inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const { if ( - !is_constant_node(branch[1]) || - is_constant_node(branch[0]) || - is_variable_node(branch[0]) || - is_vector_node (branch[0]) || - is_generally_string_node(branch[0]) + !details::is_constant_node(branch[1]) || + details::is_constant_node(branch[0]) || + details::is_variable_node(branch[0]) || + details::is_vector_node (branch[0]) || + details::is_generally_string_node(branch[0]) ) return false; @@ -25520,7 +26436,7 @@ namespace exprtk return cardinal_pow_optimisable(operation, c); } - inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) + inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const { return ( details::is_break_node (branch[0]) || @@ -25530,7 +26446,7 @@ namespace exprtk ); } - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -25550,7 +26466,7 @@ namespace exprtk return result; } - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -25571,7 +26487,7 @@ namespace exprtk return result; } - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -25579,7 +26495,7 @@ namespace exprtk return (b0_string && b1_string && valid_string_operation(operation)); } - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -25589,7 +26505,7 @@ namespace exprtk } #ifndef exprtk_disable_sc_andor - inline bool is_shortcircuit_expression(const details::operator_type& operation) + inline bool is_shortcircuit_expression(const details::operator_type& operation) const { return ( (details::e_scand == operation) || @@ -25597,13 +26513,13 @@ namespace exprtk ); } #else - inline bool is_shortcircuit_expression(const details::operator_type&) + inline bool is_shortcircuit_expression(const details::operator_type&) const { return false; } #endif - inline bool is_null_present(expression_node_ptr (&branch)[2]) + inline bool is_null_present(expression_node_ptr (&branch)[2]) const { return ( details::is_null_node(branch[0]) || @@ -25611,29 +26527,29 @@ namespace exprtk ); } - inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; else return ( - (details::e_lt == operation) || - (details::e_lte == operation) || - (details::e_gt == operation) || - (details::e_gte == operation) || - (details::e_eq == operation) || - (details::e_ne == operation) || - (details::e_equal == operation) || - (details::e_and == operation) || - (details::e_nand == operation) || - (details:: e_or == operation) || - (details:: e_nor == operation) || - (details:: e_xor == operation) || - (details::e_xnor == operation) + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_equal == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details:: e_or == operation) || + (details:: e_nor == operation) || + (details:: e_xor == operation) || + (details::e_xnor == operation) ); } - inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; @@ -25647,42 +26563,70 @@ namespace exprtk ); } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[2]) { if ((0 == branch[0]) || (0 == branch[1])) + { return error_node(); + } else if (is_invalid_string_op(operation,branch)) + { return error_node(); + } else if (is_invalid_assignment_op(operation,branch)) + { return error_node(); + } else if (is_invalid_break_continue_op(branch)) + { return error_node(); + } else if (details::e_assign == operation) - return synthesize_assignment_expression(operation,branch); + { + return synthesize_assignment_expression(operation, branch); + } else if (details::e_swap == operation) + { return synthesize_swap_expression(branch); + } else if (is_assignment_operation(operation)) - return synthesize_assignment_operation_expression(operation,branch); - else if (is_vector_eqineq_logic_operation(operation,branch)) - return synthesize_veceqineqlogic_operation_expression(operation,branch); - else if (is_vector_arithmetic_operation(operation,branch)) - return synthesize_vecarithmetic_operation_expression(operation,branch); + { + return synthesize_assignment_operation_expression(operation, branch); + } + else if (is_vector_eqineq_logic_operation(operation, branch)) + { + return synthesize_veceqineqlogic_operation_expression(operation, branch); + } + else if (is_vector_arithmetic_operation(operation, branch)) + { + return synthesize_vecarithmetic_operation_expression(operation, branch); + } else if (is_shortcircuit_expression(operation)) - return synthesize_shortcircuit_expression(operation,branch); - else if (is_string_operation(operation,branch)) - return synthesize_string_expression(operation,branch); + { + return synthesize_shortcircuit_expression(operation, branch); + } + else if (is_string_operation(operation, branch)) + { + return synthesize_string_expression(operation, branch); + } else if (is_null_present(branch)) + { return synthesize_null_expression(operation, branch); + } #ifndef exprtk_disable_cardinal_pow_optimisation else if (is_constpow_operation(operation, branch)) + { return cardinal_pow_optimisation(branch); + } #endif expression_node_ptr result = error_node(); #ifndef exprtk_disable_enhanced_features - if (synthesize_expression(operation,branch,result)) + if (synthesize_expression(operation, branch, result)) + { return result; + } else #endif @@ -25696,36 +26640,54 @@ namespace exprtk */ result = error_node(); - if (cocob_optimisable(operation,branch)) - result = synthesize_cocob_expression::process(*this,operation,branch); - else if (coboc_optimisable(operation,branch) && (0 == result)) - result = synthesize_coboc_expression::process(*this,operation,branch); + if (cocob_optimisable(operation, branch)) + { + result = synthesize_cocob_expression::process((*this), operation, branch); + } + else if (coboc_optimisable(operation, branch) && (0 == result)) + { + result = synthesize_coboc_expression::process((*this), operation, branch); + } if (result) return result; } - if (uvouv_optimisable(operation,branch)) - return synthesize_uvouv_expression(operation,branch); - else if (vob_optimisable(operation,branch)) - return synthesize_vob_expression::process(*this,operation,branch); - else if (bov_optimisable(operation,branch)) - return synthesize_bov_expression::process(*this,operation,branch); - else if (cob_optimisable(operation,branch)) - return synthesize_cob_expression::process(*this,operation,branch); - else if (boc_optimisable(operation,branch)) - return synthesize_boc_expression::process(*this,operation,branch); + if (uvouv_optimisable(operation, branch)) + { + return synthesize_uvouv_expression(operation, branch); + } + else if (vob_optimisable(operation, branch)) + { + return synthesize_vob_expression::process((*this), operation, branch); + } + else if (bov_optimisable(operation, branch)) + { + return synthesize_bov_expression::process((*this), operation, branch); + } + else if (cob_optimisable(operation, branch)) + { + return synthesize_cob_expression::process((*this), operation, branch); + } + else if (boc_optimisable(operation, branch)) + { + return synthesize_boc_expression::process((*this), operation, branch); + } #ifndef exprtk_disable_enhanced_features - else if (cov_optimisable(operation,branch)) - return synthesize_cov_expression::process(*this,operation,branch); + else if (cov_optimisable(operation, branch)) + { + return synthesize_cov_expression::process((*this), operation, branch); + } #endif - else if (binext_optimisable(operation,branch)) - return synthesize_binary_ext_expression::process(*this,operation,branch); + else if (binext_optimisable(operation, branch)) + { + return synthesize_binary_ext_expression::process((*this), operation, branch); + } else - return synthesize_expression<binary_node_t,2>(operation,branch); + return synthesize_expression<binary_node_t,2>(operation, branch); } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[3]) { if ( (0 == branch[0]) || @@ -25737,34 +26699,42 @@ namespace exprtk return error_node(); } - else if (is_invalid_string_op(operation,branch)) + else if (is_invalid_string_op(operation, branch)) + { return error_node(); - else if (is_string_operation(operation,branch)) - return synthesize_string_expression(operation,branch); + } + else if (is_string_operation(operation, branch)) + { + return synthesize_string_expression(operation, branch); + } else - return synthesize_expression<trinary_node_t,3>(operation,branch); + return synthesize_expression<trinary_node_t,3>(operation, branch); } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[4]) { return synthesize_expression<quaternary_node_t,4>(operation,branch); } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0) + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0) { expression_node_ptr branch[1] = { b0 }; return (*this)(operation,branch); } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0, expression_node_ptr b1) + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1) { - if ((0 == b0) || (0 == b1)) - return error_node(); - else + expression_node_ptr result = error_node(); + + if ((0 != b0) && (0 != b1)) { expression_node_ptr branch[2] = { b0, b1 }; - return expression_generator<Type>::operator()(operation,branch); + result = expression_generator<Type>::operator()(operation, branch); + b0 = branch[0]; + b1 = branch[1]; } + + return result; } inline expression_node_ptr conditional(expression_node_ptr condition, @@ -25773,9 +26743,9 @@ namespace exprtk { if ((0 == condition) || (0 == consequent)) { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,consequent ); - free_node(*node_allocator_,alternative); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, consequent); + free_node(*node_allocator_, alternative); return error_node(); } @@ -25785,16 +26755,16 @@ namespace exprtk // True branch if (details::is_true(condition)) { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,alternative); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, alternative); return consequent; } // False branch else { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,consequent); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, consequent); if (alternative) return alternative; @@ -25805,11 +26775,11 @@ namespace exprtk else if ((0 != consequent) && (0 != alternative)) { return node_allocator_-> - allocate<conditional_node_t>(condition,consequent,alternative); + allocate<conditional_node_t>(condition, consequent, alternative); } else return node_allocator_-> - allocate<cons_conditional_node_t>(condition,consequent); + allocate<cons_conditional_node_t>(condition, consequent); } #ifndef exprtk_disable_string_capabilities @@ -25819,9 +26789,9 @@ namespace exprtk { if ((0 == condition) || (0 == consequent)) { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,consequent ); - free_node(*node_allocator_,alternative); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, consequent); + free_node(*node_allocator_, alternative); return error_node(); } @@ -25831,16 +26801,16 @@ namespace exprtk // True branch if (details::is_true(condition)) { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,alternative); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, alternative); return consequent; } // False branch else { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,consequent); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, consequent); if (alternative) return alternative; @@ -25851,7 +26821,7 @@ namespace exprtk } else if ((0 != consequent) && (0 != alternative)) return node_allocator_-> - allocate<conditional_string_node_t>(condition,consequent,alternative); + allocate<conditional_string_node_t>(condition, consequent, alternative); else return error_node(); } @@ -25878,7 +26848,7 @@ namespace exprtk result = node_allocator_->allocate<details::null_node<Type> >(); free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch ); + free_node(*node_allocator_, branch); return result; } @@ -25904,7 +26874,10 @@ namespace exprtk { if (!brkcont && details::is_constant_node(condition)) { - if (details::is_true(condition) && details::is_constant_node(branch)) + if ( + details::is_true(condition) && + details::is_constant_node(branch) + ) { free_node(*node_allocator_,condition); @@ -25912,7 +26885,7 @@ namespace exprtk } free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch ); + free_node(*node_allocator_, branch); return error_node(); } @@ -25948,39 +26921,46 @@ namespace exprtk else result = node_allocator_->allocate<details::null_node<Type> >(); - free_node(*node_allocator_,initialiser); - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,incrementor); - free_node(*node_allocator_,loop_body ); + free_node(*node_allocator_, initialiser); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, incrementor); + free_node(*node_allocator_, loop_body); return result; } - else if (details::is_null_node(condition)) + else if (details::is_null_node(condition) || (0 == condition)) { - free_node(*node_allocator_,initialiser); - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,incrementor); + free_node(*node_allocator_, initialiser); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, incrementor); return loop_body; } else if (!brkcont) - return node_allocator_->allocate<for_loop_node_t>(initialiser, - condition, - incrementor, - loop_body); + return node_allocator_->allocate<for_loop_node_t> + ( + initialiser, + condition, + incrementor, + loop_body + ); + #ifndef exprtk_disable_break_continue else - return node_allocator_->allocate<for_loop_bc_node_t>(initialiser, - condition, - incrementor, - loop_body); + return node_allocator_->allocate<for_loop_bc_node_t> + ( + initialiser, + condition, + incrementor, + loop_body + ); #else return error_node(); #endif } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr const_optimise_switch(Sequence<expression_node_ptr,Allocator>& arg_list) { expression_node_ptr result = error_node(); @@ -26016,7 +26996,7 @@ namespace exprtk } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr const_optimise_mswitch(Sequence<expression_node_ptr,Allocator>& arg_list) { expression_node_ptr result = error_node(); @@ -26063,6 +27043,7 @@ namespace exprtk static inline T process(const arg_list_t& arg) { case_stmt(0) + return arg.back()->value(); } }; @@ -26072,6 +27053,7 @@ namespace exprtk static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) + return arg.back()->value(); } }; @@ -26082,6 +27064,7 @@ namespace exprtk { case_stmt(0) case_stmt(1) case_stmt(2) + return arg.back()->value(); } }; @@ -26092,6 +27075,7 @@ namespace exprtk { case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) + return arg.back()->value(); } }; @@ -26103,6 +27087,7 @@ namespace exprtk case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) case_stmt(4) + return arg.back()->value(); } }; @@ -26114,6 +27099,7 @@ namespace exprtk case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) case_stmt(4) case_stmt(5) + return arg.back()->value(); } }; @@ -26126,6 +27112,7 @@ namespace exprtk case_stmt(2) case_stmt(3) case_stmt(4) case_stmt(5) case_stmt(6) + return arg.back()->value(); } }; @@ -26134,7 +27121,7 @@ namespace exprtk }; template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list) { if (arg_list.empty()) @@ -26174,7 +27161,7 @@ namespace exprtk } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr multi_switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list) { if (!all_nodes_valid(arg_list)) @@ -26189,47 +27176,47 @@ namespace exprtk return node_allocator_->allocate<details::multi_switch_node<Type> >(arg_list); } - #define unary_opr_switch_statements \ - case_stmt(details:: e_abs,details:: abs_op) \ - case_stmt(details:: e_acos,details:: acos_op) \ - case_stmt(details::e_acosh,details::acosh_op) \ - case_stmt(details:: e_asin,details:: asin_op) \ - case_stmt(details::e_asinh,details::asinh_op) \ - case_stmt(details:: e_atan,details:: atan_op) \ - case_stmt(details::e_atanh,details::atanh_op) \ - case_stmt(details:: e_ceil,details:: ceil_op) \ - case_stmt(details:: e_cos,details:: cos_op) \ - case_stmt(details:: e_cosh,details:: cosh_op) \ - case_stmt(details:: e_exp,details:: exp_op) \ - case_stmt(details::e_expm1,details::expm1_op) \ - case_stmt(details::e_floor,details::floor_op) \ - case_stmt(details:: e_log,details:: log_op) \ - case_stmt(details::e_log10,details::log10_op) \ - case_stmt(details:: e_log2,details:: log2_op) \ - case_stmt(details::e_log1p,details::log1p_op) \ - case_stmt(details:: e_neg,details:: neg_op) \ - case_stmt(details:: e_pos,details:: pos_op) \ - case_stmt(details::e_round,details::round_op) \ - case_stmt(details:: e_sin,details:: sin_op) \ - case_stmt(details:: e_sinc,details:: sinc_op) \ - case_stmt(details:: e_sinh,details:: sinh_op) \ - case_stmt(details:: e_sqrt,details:: sqrt_op) \ - case_stmt(details:: e_tan,details:: tan_op) \ - case_stmt(details:: e_tanh,details:: tanh_op) \ - case_stmt(details:: e_cot,details:: cot_op) \ - case_stmt(details:: e_sec,details:: sec_op) \ - case_stmt(details:: e_csc,details:: csc_op) \ - case_stmt(details:: e_r2d,details:: r2d_op) \ - case_stmt(details:: e_d2r,details:: d2r_op) \ - case_stmt(details:: e_d2g,details:: d2g_op) \ - case_stmt(details:: e_g2d,details:: g2d_op) \ - case_stmt(details:: e_notl,details:: notl_op) \ - case_stmt(details:: e_sgn,details:: sgn_op) \ - case_stmt(details:: e_erf,details:: erf_op) \ - case_stmt(details:: e_erfc,details:: erfc_op) \ - case_stmt(details:: e_ncdf,details:: ncdf_op) \ - case_stmt(details:: e_frac,details:: frac_op) \ - case_stmt(details::e_trunc,details::trunc_op) \ + #define unary_opr_switch_statements \ + case_stmt(details:: e_abs, details:: abs_op) \ + case_stmt(details:: e_acos, details:: acos_op) \ + case_stmt(details::e_acosh, details::acosh_op) \ + case_stmt(details:: e_asin, details:: asin_op) \ + case_stmt(details::e_asinh, details::asinh_op) \ + case_stmt(details:: e_atan, details:: atan_op) \ + case_stmt(details::e_atanh, details::atanh_op) \ + case_stmt(details:: e_ceil, details:: ceil_op) \ + case_stmt(details:: e_cos, details:: cos_op) \ + case_stmt(details:: e_cosh, details:: cosh_op) \ + case_stmt(details:: e_exp, details:: exp_op) \ + case_stmt(details::e_expm1, details::expm1_op) \ + case_stmt(details::e_floor, details::floor_op) \ + case_stmt(details:: e_log, details:: log_op) \ + case_stmt(details::e_log10, details::log10_op) \ + case_stmt(details:: e_log2, details:: log2_op) \ + case_stmt(details::e_log1p, details::log1p_op) \ + case_stmt(details:: e_neg, details:: neg_op) \ + case_stmt(details:: e_pos, details:: pos_op) \ + case_stmt(details::e_round, details::round_op) \ + case_stmt(details:: e_sin, details:: sin_op) \ + case_stmt(details:: e_sinc, details:: sinc_op) \ + case_stmt(details:: e_sinh, details:: sinh_op) \ + case_stmt(details:: e_sqrt, details:: sqrt_op) \ + case_stmt(details:: e_tan, details:: tan_op) \ + case_stmt(details:: e_tanh, details:: tanh_op) \ + case_stmt(details:: e_cot, details:: cot_op) \ + case_stmt(details:: e_sec, details:: sec_op) \ + case_stmt(details:: e_csc, details:: csc_op) \ + case_stmt(details:: e_r2d, details:: r2d_op) \ + case_stmt(details:: e_d2r, details:: d2r_op) \ + case_stmt(details:: e_d2g, details:: d2g_op) \ + case_stmt(details:: e_g2d, details:: g2d_op) \ + case_stmt(details:: e_notl, details:: notl_op) \ + case_stmt(details:: e_sgn, details:: sgn_op) \ + case_stmt(details:: e_erf, details:: erf_op) \ + case_stmt(details:: e_erfc, details:: erfc_op) \ + case_stmt(details:: e_ncdf, details:: ncdf_op) \ + case_stmt(details:: e_frac, details:: frac_op) \ + case_stmt(details::e_trunc, details::trunc_op) \ inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[1]) @@ -26256,7 +27243,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ allocate<typename details::unary_vector_node<Type,op1<Type> > > \ - (operation,branch[0]); \ + (operation, branch[0]); \ unary_opr_switch_statements #undef case_stmt @@ -26289,8 +27276,8 @@ namespace exprtk #define case_stmt(op) \ case details::e_sf##op : temp_node = node_allocator_-> \ allocate<details::sf3_node<Type,details::sf##op##_op<Type> > > \ - (operation,branch); \ - break; \ + (operation, branch); \ + break; \ case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) @@ -26308,7 +27295,7 @@ namespace exprtk default : return error_node(); } - T v = temp_node->value(); + const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); @@ -26328,7 +27315,7 @@ namespace exprtk #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate_rrr<details::sf3_var_node<Type,details::sf##op##_op<Type> > > \ - (v0,v1,v2); \ + (v0, v1, v2); \ case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) @@ -26362,7 +27349,7 @@ namespace exprtk #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate<details::sf3_node<Type,details::sf##op##_op<Type> > > \ - (operation,branch); \ + (operation, branch); \ case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) @@ -26391,8 +27378,8 @@ namespace exprtk #define case_stmt(op) \ case details::e_sf##op : temp_node = node_allocator_-> \ allocate<details::sf4_node<Type,details::sf##op##_op<Type> > > \ - (operation,branch); \ - break; \ + (operation, branch); \ + break; \ case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) @@ -26411,7 +27398,8 @@ namespace exprtk default : return error_node(); } - T v = temp_node->value(); + const T v = temp_node->value(); + details::free_node(*node_allocator_,temp_node); return node_allocator_->allocate<literal_node_t>(v); @@ -26431,7 +27419,7 @@ namespace exprtk #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate_rrrr<details::sf4_var_node<Type,details::sf##op##_op<Type> > > \ - (v0,v1,v2,v3); \ + (v0, v1, v2, v3); \ case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) @@ -26464,7 +27452,7 @@ namespace exprtk #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate<details::sf4_node<Type,details::sf##op##_op<Type> > > \ - (operation,branch); \ + (operation, branch); \ case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) @@ -26485,7 +27473,7 @@ namespace exprtk } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) { expression_node_ptr temp_node = error_node(); @@ -26498,25 +27486,26 @@ namespace exprtk (arg_list); \ break; \ - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) #undef case_stmt default : return error_node(); } - T v = temp_node->value(); + const T v = temp_node->value(); + details::free_node(*node_allocator_,temp_node); return node_allocator_->allocate<literal_node_t>(v); } - inline bool special_one_parameter_vararg(const details::operator_type& operation) + inline bool special_one_parameter_vararg(const details::operator_type& operation) const { return ( (details::e_sum == operation) || @@ -26528,7 +27517,7 @@ namespace exprtk } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) { switch (operation) @@ -26537,21 +27526,21 @@ namespace exprtk case op0 : return node_allocator_-> \ allocate<details::vararg_varnode<Type,op1<Type> > >(arg_list); \ - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) #undef case_stmt default : return error_node(); } } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) { if (1 == arg_list.size()) @@ -26562,11 +27551,11 @@ namespace exprtk case op0 : return node_allocator_-> \ allocate<details::vectorize_node<Type,op1<Type> > >(arg_list[0]); \ - case_stmt(details::e_sum, details::vec_add_op) - case_stmt(details::e_prod, details::vec_mul_op) - case_stmt(details::e_avg, details::vec_avg_op) - case_stmt(details::e_min, details::vec_min_op) - case_stmt(details::e_max, details::vec_max_op) + case_stmt(details::e_sum , details::vec_add_op) + case_stmt(details::e_prod , details::vec_mul_op) + case_stmt(details::e_avg , details::vec_avg_op) + case_stmt(details::e_min , details::vec_min_op) + case_stmt(details::e_max , details::vec_max_op) #undef case_stmt default : return error_node(); } @@ -26576,7 +27565,7 @@ namespace exprtk } template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list) { if (!all_nodes_valid(arg_list)) @@ -26609,14 +27598,14 @@ namespace exprtk case op0 : return node_allocator_-> \ allocate<details::vararg_node<Type,op1<Type> > >(arg_list); \ - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) #undef case_stmt default : return error_node(); } @@ -26684,7 +27673,7 @@ namespace exprtk is_constant_foldable(arg_list) ) { - Type v = result->value(); + const Type v = result->value(); details::free_node(*node_allocator_,result); result = node_allocator_->allocate<literal_node_t>(v); } @@ -26714,7 +27703,7 @@ namespace exprtk if (no_psi == param_seq_index) result = node_allocator_->allocate<alloc_type1>(arg_list,gf); else - result = node_allocator_->allocate<alloc_type2>(gf,param_seq_index,arg_list); + result = node_allocator_->allocate<alloc_type2>(gf, param_seq_index, arg_list); alloc_type1* genfunc_node_ptr = static_cast<alloc_type1*>(result); @@ -26726,19 +27715,24 @@ namespace exprtk ) { genfunc_node_ptr->init_branches(); - Type v = result->value(); + + const Type v = result->value(); + details::free_node(*node_allocator_,result); + return node_allocator_->allocate<literal_node_t>(v); } else if (genfunc_node_ptr->init_branches()) { parser_->state_.activate_side_effect("generic_function_call()"); + return result; } else { - details::free_node(*node_allocator_,result); - details::free_all_nodes(*node_allocator_,arg_list); + details::free_node(*node_allocator_, result); + details::free_all_nodes(*node_allocator_, arg_list); + return error_node(); } } @@ -26764,7 +27758,7 @@ namespace exprtk if (no_psi == param_seq_index) result = node_allocator_->allocate<alloc_type1>(gf,arg_list); else - result = node_allocator_->allocate<alloc_type2>(gf,param_seq_index,arg_list); + result = node_allocator_->allocate<alloc_type2>(gf, param_seq_index, arg_list); alloc_type1* strfunc_node_ptr = static_cast<alloc_type1*>(result); @@ -26776,7 +27770,7 @@ namespace exprtk { strfunc_node_ptr->init_branches(); - Type v = result->value(); + const Type v = result->value(); details::free_node(*node_allocator_,result); @@ -26790,7 +27784,7 @@ namespace exprtk } else { - details::free_node(*node_allocator_,result); + details::free_node (*node_allocator_,result ); details::free_all_nodes(*node_allocator_,arg_list); return error_node(); @@ -26822,7 +27816,7 @@ namespace exprtk } else { - details::free_node(*node_allocator_,result); + details::free_node (*node_allocator_,result ); details::free_all_nodes(*node_allocator_,arg_list); return error_node(); @@ -26933,7 +27927,7 @@ namespace exprtk template <typename NodePtr, typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline bool is_constant_foldable(const Sequence<NodePtr,Allocator>& b) const { for (std::size_t i = 0; i < b.size(); ++i) @@ -27028,13 +28022,13 @@ namespace exprtk { lodge_assignment(e_st_string,branch[0]); - return synthesize_expression<assignment_string_node_t,2>(operation,branch); + return synthesize_expression<assignment_string_node_t,2>(operation, branch); } else if (details::is_string_range_node(branch[0])) { lodge_assignment(e_st_string,branch[0]); - return synthesize_expression<assignment_string_range_node_t,2>(operation,branch); + return synthesize_expression<assignment_string_range_node_t,2>(operation, branch); } #endif else if (details::is_vector_node(branch[0])) @@ -27042,9 +28036,9 @@ namespace exprtk lodge_assignment(e_st_vector,branch[0]); if (details::is_ivector_node(branch[1])) - return synthesize_expression<assignment_vecvec_node_t,2>(operation,branch); + return synthesize_expression<assignment_vecvec_node_t,2>(operation, branch); else - return synthesize_expression<assignment_vec_node_t,2>(operation,branch); + return synthesize_expression<assignment_vec_node_t,2>(operation, branch); } else { @@ -27066,7 +28060,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::assignment_op_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ case_stmt(details::e_addass,details::add_op) case_stmt(details::e_subass,details::sub_op) @@ -27079,12 +28073,14 @@ namespace exprtk } else if (details::is_vector_elem_node(branch[0])) { + lodge_assignment(e_st_vecelem,branch[0]); + switch (operation) { #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::assignment_vec_elem_op_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ case_stmt(details::e_addass,details::add_op) case_stmt(details::e_subass,details::sub_op) @@ -27097,12 +28093,14 @@ namespace exprtk } else if (details::is_rebasevector_elem_node(branch[0])) { + lodge_assignment(e_st_vecelem,branch[0]); + switch (operation) { #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::assignment_rebasevec_elem_op_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ case_stmt(details::e_addass,details::add_op) case_stmt(details::e_subass,details::sub_op) @@ -27115,12 +28113,14 @@ namespace exprtk } else if (details::is_rebasevector_celem_node(branch[0])) { + lodge_assignment(e_st_vecelem,branch[0]); + switch (operation) { #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::assignment_rebasevec_celem_op_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ case_stmt(details::e_addass,details::add_op) case_stmt(details::e_subass,details::sub_op) @@ -27142,7 +28142,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::assignment_vecvec_op_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ case_stmt(details::e_addass,details::add_op) case_stmt(details::e_subass,details::sub_op) @@ -27160,7 +28160,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::assignment_vec_op_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ case_stmt(details::e_addass,details::add_op) case_stmt(details::e_subass,details::sub_op) @@ -27199,20 +28199,20 @@ namespace exprtk const bool is_b0_ivec = details::is_ivector_node(branch[0]); const bool is_b1_ivec = details::is_ivector_node(branch[1]); - #define batch_eqineq_logic_case \ - case_stmt(details:: e_lt,details:: lt_op) \ - case_stmt(details:: e_lte,details:: lte_op) \ - case_stmt(details:: e_gt,details:: gt_op) \ - case_stmt(details:: e_gte,details:: gte_op) \ - case_stmt(details:: e_eq,details:: eq_op) \ - case_stmt(details:: e_ne,details:: ne_op) \ - case_stmt(details::e_equal,details::equal_op) \ - case_stmt(details:: e_and, details::and_op) \ - case_stmt(details:: e_nand, details::nand_op) \ - case_stmt(details:: e_or, details:: or_op) \ - case_stmt(details:: e_nor, details:: nor_op) \ - case_stmt(details:: e_xor, details:: xor_op) \ - case_stmt(details:: e_xnor, details::xnor_op) \ + #define batch_eqineq_logic_case \ + case_stmt(details:: e_lt, details:: lt_op) \ + case_stmt(details:: e_lte, details:: lte_op) \ + case_stmt(details:: e_gt, details:: gt_op) \ + case_stmt(details:: e_gte, details:: gte_op) \ + case_stmt(details:: e_eq, details:: eq_op) \ + case_stmt(details:: e_ne, details:: ne_op) \ + case_stmt(details::e_equal, details::equal_op) \ + case_stmt(details:: e_and, details:: and_op) \ + case_stmt(details:: e_nand, details:: nand_op) \ + case_stmt(details:: e_or, details:: or_op) \ + case_stmt(details:: e_nor, details:: nor_op) \ + case_stmt(details:: e_xor, details:: xor_op) \ + case_stmt(details:: e_xnor, details:: xnor_op) \ if (is_b0_ivec && is_b1_ivec) { @@ -27221,7 +28221,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecvec_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ batch_eqineq_logic_case #undef case_stmt @@ -27235,7 +28235,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecval_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ batch_eqineq_logic_case #undef case_stmt @@ -27249,7 +28249,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::vec_binop_valvec_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ batch_eqineq_logic_case #undef case_stmt @@ -27282,7 +28282,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecvec_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -27297,7 +28297,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::vec_binop_vecval_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ vector_ops case_stmt(details::e_pow,details:: pow_op) @@ -27312,7 +28312,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ template allocate_rrr<typename details::vec_binop_valvec_node<Type,op1<Type> > > \ - (operation,branch[0],branch[1]); \ + (operation, branch[0], branch[1]); \ vector_ops #undef case_stmt @@ -27330,8 +28330,8 @@ namespace exprtk const bool v0_is_ivar = details::is_ivariable_node(branch[0]); const bool v1_is_ivar = details::is_ivariable_node(branch[1]); - const bool v0_is_ivec = details::is_ivector_node(branch[0]); - const bool v1_is_ivec = details::is_ivector_node(branch[1]); + const bool v0_is_ivec = details::is_ivector_node (branch[0]); + const bool v1_is_ivec = details::is_ivector_node (branch[1]); #ifndef exprtk_disable_string_capabilities const bool v0_is_str = details::is_generally_string_node(branch[0]); @@ -27365,9 +28365,11 @@ namespace exprtk else if (v0_is_str && v1_is_str) { if (is_string_node(branch[0]) && is_string_node(branch[1])) - result = node_allocator_->allocate<details::swap_string_node<T> >(branch[0],branch[1]); + result = node_allocator_->allocate<details::swap_string_node<T> > + (branch[0], branch[1]); else - result = node_allocator_->allocate<details::swap_genstrings_node<T> >(branch[0],branch[1]); + result = node_allocator_->allocate<details::swap_genstrings_node<T> > + (branch[0], branch[1]); } #endif else @@ -27417,15 +28419,19 @@ namespace exprtk if (result) { - free_node(*node_allocator_,branch[0]); - free_node(*node_allocator_,branch[1]); + free_node(*node_allocator_, branch[0]); + free_node(*node_allocator_, branch[1]); return result; } else if (details::e_scand == operation) - return synthesize_expression<scand_node_t,2>(operation,branch); + { + return synthesize_expression<scand_node_t,2>(operation, branch); + } else if (details::e_scor == operation) - return synthesize_expression<scor_node_t,2>(operation,branch); + { + return synthesize_expression<scor_node_t,2>(operation, branch); + } else return error_node(); } @@ -27436,30 +28442,30 @@ namespace exprtk } #endif - #define basic_opr_switch_statements \ - case_stmt(details::e_add,details::add_op) \ - case_stmt(details::e_sub,details::sub_op) \ - case_stmt(details::e_mul,details::mul_op) \ - case_stmt(details::e_div,details::div_op) \ - case_stmt(details::e_mod,details::mod_op) \ - case_stmt(details::e_pow,details::pow_op) \ - - #define extended_opr_switch_statements \ - case_stmt(details:: e_lt,details:: lt_op) \ - case_stmt(details:: e_lte,details:: lte_op) \ - case_stmt(details:: e_gt,details:: gt_op) \ - case_stmt(details:: e_gte,details:: gte_op) \ - case_stmt(details:: e_eq,details:: eq_op) \ - case_stmt(details:: e_ne,details:: ne_op) \ - case_stmt(details:: e_and,details:: and_op) \ - case_stmt(details::e_nand,details::nand_op) \ - case_stmt(details:: e_or,details:: or_op) \ - case_stmt(details:: e_nor,details:: nor_op) \ - case_stmt(details:: e_xor,details:: xor_op) \ - case_stmt(details::e_xnor,details::xnor_op) \ + #define basic_opr_switch_statements \ + case_stmt(details::e_add, details::add_op) \ + case_stmt(details::e_sub, details::sub_op) \ + case_stmt(details::e_mul, details::mul_op) \ + case_stmt(details::e_div, details::div_op) \ + case_stmt(details::e_mod, details::mod_op) \ + case_stmt(details::e_pow, details::pow_op) \ + + #define extended_opr_switch_statements \ + case_stmt(details:: e_lt, details:: lt_op) \ + case_stmt(details:: e_lte, details:: lte_op) \ + case_stmt(details:: e_gt, details:: gt_op) \ + case_stmt(details:: e_gte, details:: gte_op) \ + case_stmt(details:: e_eq, details:: eq_op) \ + case_stmt(details:: e_ne, details:: ne_op) \ + case_stmt(details:: e_and, details:: and_op) \ + case_stmt(details::e_nand, details::nand_op) \ + case_stmt(details:: e_or, details:: or_op) \ + case_stmt(details:: e_nor, details:: nor_op) \ + case_stmt(details:: e_xor, details:: xor_op) \ + case_stmt(details::e_xnor, details::xnor_op) \ #ifndef exprtk_disable_cardinal_pow_optimisation - template <typename TType, template <typename,typename> class IPowNode> + template <typename TType, template <typename, typename> class IPowNode> inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) { switch (p) @@ -27491,7 +28497,7 @@ namespace exprtk inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) { const bool not_recipricol = (c >= T(0)); - const int p = details::numeric::to_int32(details::numeric::abs(c)); + const unsigned int p = static_cast<unsigned int>(details::numeric::to_int32(details::numeric::abs(c))); if (0 == p) return node_allocator_->allocate_c<literal_node_t>(T(1)); @@ -27509,7 +28515,7 @@ namespace exprtk } } - inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) + inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const { return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); } @@ -27518,13 +28524,14 @@ namespace exprtk { const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); const bool not_recipricol = (c >= T(0)); - const int p = details::numeric::to_int32(details::numeric::abs(c)); + const unsigned int p = static_cast<unsigned int>(details::numeric::to_int32(details::numeric::abs(c))); node_allocator_->free(branch[1]); if (0 == p) { details::free_all_nodes(*node_allocator_, branch); + return node_allocator_->allocate_c<literal_node_t>(T(1)); } else if (not_recipricol) @@ -27615,25 +28622,25 @@ namespace exprtk // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) case details::e_add : return expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::sub_op<Type> > > - (branch[1],branch[0]); + (branch[1], branch[0]); // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) case details::e_sub : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::add_op<Type> > > - (branch[0],branch[1])); + (branch[0], branch[1])); // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) case details::e_mul : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::mul_op<Type> > > - (branch[0],branch[1])); + (branch[0], branch[1])); // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) case details::e_div : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::div_op<Type> > > - (branch[0],branch[1])); + (branch[0], branch[1])); default : return error_node(); } @@ -27660,24 +28667,24 @@ namespace exprtk // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) case details::e_add : return expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::sub_op<Type> > > - (branch[0],branch[1]); + (branch[0], branch[1]); // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) case details::e_sub : return expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::add_op<Type> > > - (branch[0],branch[1]); + (branch[0], branch[1]); // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) case details::e_mul : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::mul_op<Type> > > - (branch[0],branch[1])); + (branch[0], branch[1])); // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) case details::e_div : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate<typename details::binary_ext_node<Type,details::div_op<Type> > > - (branch[0],branch[1])); + (branch[0], branch[1])); default : return error_node(); } @@ -27689,7 +28696,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate<typename details::binary_ext_node<Type,op1<Type> > > \ - (branch[0],branch[1]); \ + (branch[0], branch[1]); \ basic_opr_switch_statements extended_opr_switch_statements @@ -27712,7 +28719,10 @@ namespace exprtk { expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile_right<vtype>(expr_gen,v,operation,branch[1],result)) + const bool synthesis_result = synthesize_sf4ext_expression::template compile_right<vtype> + (expr_gen, v, operation, branch[1], result); + + if (synthesis_result) { free_node(*expr_gen.node_allocator_,branch[1]); return result; @@ -27760,7 +28770,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_rc<typename details::vob_node<Type,op1<Type> > > \ - (v,branch[1]); \ + (v, branch[1]); \ basic_opr_switch_statements extended_opr_switch_statements @@ -27783,9 +28793,12 @@ namespace exprtk { expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile_left<vtype>(expr_gen,v,operation,branch[0],result)) + const bool synthesis_result = synthesize_sf4ext_expression::template compile_left<vtype> + (expr_gen, v, operation, branch[0], result); + + if (synthesis_result) { - free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_, branch[0]); return result; } @@ -27842,7 +28855,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_cr<typename details::bov_node<Type,op1<Type> > > \ - (branch[0],v); \ + (branch[0], v); \ basic_opr_switch_statements extended_opr_switch_statements @@ -27862,21 +28875,21 @@ namespace exprtk free_node(*expr_gen.node_allocator_,branch[0]); - if ((T(0) == c) && (details::e_mul == operation)) + if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { free_node(*expr_gen.node_allocator_,branch[1]); return expr_gen(T(0)); } - else if ((T(0) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } - else if ((T(0) == c) && (details::e_add == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) return branch[1]; - else if ((T(1) == c) && (details::e_mul == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) return branch[1]; if (details::is_cob_node(branch[1])) @@ -27940,12 +28953,12 @@ namespace exprtk { case details::e_div : new_cobnode = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::mul_op<Type> > > - (c / cobnode->c(),cobnode->move_branch(0)); + (c / cobnode->c(), cobnode->move_branch(0)); break; case details::e_mul : new_cobnode = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > - (c / cobnode->c(),cobnode->move_branch(0)); + (c / cobnode->c(), cobnode->move_branch(0)); break; default : return error_node(); @@ -27976,7 +28989,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_tt<typename details::cob_node<Type,op1<Type> > > \ - (c,branch[1]); \ + (c, branch[1]); \ basic_opr_switch_statements extended_opr_switch_statements @@ -27994,23 +29007,23 @@ namespace exprtk { const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); - details::free_node(*(expr_gen.node_allocator_),branch[1]); + details::free_node(*(expr_gen.node_allocator_), branch[1]); - if ((T(0) == c) && (details::e_mul == operation)) + if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_, branch[0]); return expr_gen(T(0)); } - else if ((T(0) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { free_node(*expr_gen.node_allocator_, branch[0]); return expr_gen(std::numeric_limits<T>::quiet_NaN()); } - else if ((T(0) == c) && (details::e_add == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) return branch[0]; - else if ((T(1) == c) && (details::e_mul == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) return branch[0]; if (details::is_boc_node(branch[0])) @@ -28040,7 +29053,7 @@ namespace exprtk else if (operation == details::e_div) { details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); - details::operator_type boc_opr = bocnode->operation(); + details::operator_type boc_opr = bocnode->operation(); if ( (details::e_div == boc_opr) || @@ -28061,7 +29074,7 @@ namespace exprtk { // (v ^ c0) ^ c1 --> v ^(c0 * c1) details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); - details::operator_type boc_opr = bocnode->operation(); + details::operator_type boc_opr = bocnode->operation(); if (details::e_pow == boc_opr) { @@ -28077,9 +29090,12 @@ namespace exprtk { expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile_left<ctype>(expr_gen,c,operation,branch[0],result)) + const bool synthesis_result = synthesize_sf4ext_expression::template compile_left<ctype> + (expr_gen, c, operation, branch[0], result); + + if (synthesis_result) { - free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_, branch[0]); return result; } @@ -28091,7 +29107,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_cr<typename details::boc_node<Type,op1<Type> > > \ - (branch[0],c); \ + (branch[0], c); \ basic_opr_switch_statements extended_opr_switch_statements @@ -28113,40 +29129,44 @@ namespace exprtk if (details::is_cob_node(branch[0])) { details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[0]); + const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); - if ((T(0) == c) && (details::e_mul == operation)) + if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } - else if ((T(0) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(std::numeric_limits<T>::quiet_NaN())); } - else if ((T(0) == c) && (details::e_add == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) { free_node(*expr_gen.node_allocator_, branch[1]); + return branch[0]; } - else if ((T(1) == c) && (details::e_mul == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) { free_node(*expr_gen.node_allocator_, branch[1]); + return branch[0]; } - else if ((T(1) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_div == operation)) { free_node(*expr_gen.node_allocator_, branch[1]); + return branch[0]; } - bool op_addsub = (details::e_add == cobnode->operation()) || - (details::e_sub == cobnode->operation()); + const bool op_addsub = (details::e_add == cobnode->operation()) || + (details::e_sub == cobnode->operation()) ; if (op_addsub) { @@ -28181,9 +29201,9 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > - (cobnode->c() / c,cobnode->move_branch(0)); + (cobnode->c() / c, cobnode->move_branch(0)); - free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_, branch[0]); } } @@ -28197,30 +29217,33 @@ namespace exprtk else if (details::is_cob_node(branch[1])) { details::cob_base_node<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]); + const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); - if ((T(0) == c) && (details::e_mul == operation)) + if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } - else if ((T(0) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } - else if ((T(0) == c) && (details::e_add == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) { free_node(*expr_gen.node_allocator_, branch[0]); + return branch[1]; } - else if ((T(1) == c) && (details::e_mul == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) { free_node(*expr_gen.node_allocator_, branch[0]); + return branch[1]; } @@ -28235,7 +29258,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > - (c - cobnode->c(),cobnode->move_branch(0)); + (c - cobnode->c(), cobnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28251,7 +29274,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::add_op<Type> > > - (c - cobnode->c(),cobnode->move_branch(0)); + (c - cobnode->c(), cobnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28267,7 +29290,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > - (c / cobnode->c(),cobnode->move_branch(0)); + (c / cobnode->c(), cobnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28283,7 +29306,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::mul_op<Type> > > - (c / cobnode->c(),cobnode->move_branch(0)); + (c / cobnode->c(), cobnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28311,6 +29334,7 @@ namespace exprtk if (details::is_boc_node(branch[0])) { details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]); + const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value(); if (details::e_add == bocnode->operation()) @@ -28341,7 +29365,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::boc_node<Type,details::add_op<Type> > > - (bocnode->move_branch(0),c - bocnode->c()); + (bocnode->move_branch(0), c - bocnode->c()); free_node(*expr_gen.node_allocator_,branch[0]); } @@ -28365,7 +29389,7 @@ namespace exprtk if (result) { - free_node(*expr_gen.node_allocator_,branch[1]); + free_node(*expr_gen.node_allocator_, branch[1]); } } @@ -28373,6 +29397,7 @@ namespace exprtk else if (details::is_boc_node(branch[1])) { details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[1]); + const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value(); if (details::e_add == bocnode->operation()) @@ -28386,7 +29411,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > - (c - bocnode->c(),bocnode->move_branch(0)); + (c - bocnode->c(), bocnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28397,7 +29422,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::boc_node<Type,details::add_op<Type> > > - (bocnode->move_branch(0),c - bocnode->c()); + (bocnode->move_branch(0), c - bocnode->c()); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28405,7 +29430,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::sub_op<Type> > > - (c + bocnode->c(),bocnode->move_branch(0)); + (c + bocnode->c(), bocnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28421,7 +29446,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > - (c / bocnode->c(),bocnode->move_branch(0)); + (c / bocnode->c(), bocnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28437,7 +29462,7 @@ namespace exprtk { result = expr_gen.node_allocator_-> template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > > - (c * bocnode->c(),bocnode->move_branch(0)); + (c * bocnode->c(), bocnode->move_branch(0)); free_node(*expr_gen.node_allocator_,branch[1]); } @@ -28465,11 +29490,11 @@ namespace exprtk const std::string node_id = branch_to_id(branch); - typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); + const typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); if (synthesize_map_.end() != itr) { - result = itr->second(*this,operation,branch); + result = itr->second((*this), operation, branch); return true; } @@ -28491,7 +29516,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_rr<typename details::vov_node<Type,op1<Type> > > \ - (v1,v2); \ + (v1, v2); \ basic_opr_switch_statements extended_opr_switch_statements @@ -28508,17 +29533,17 @@ namespace exprtk expression_node_ptr (&branch)[2]) { const Type c = static_cast<details::literal_node<Type>*> (branch[0])->value(); - const Type& v = static_cast<details::variable_node<Type>*>(branch[1])->ref(); + const Type& v = static_cast<details::variable_node<Type>*>(branch[1])->ref (); details::free_node(*(expr_gen.node_allocator_),branch[0]); - if ((T(0) == c) && (details::e_mul == operation)) + if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) return expr_gen(T(0)); - else if ((T(0) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) return expr_gen(T(0)); - else if ((T(0) == c) && (details::e_add == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) return static_cast<details::variable_node<Type>*>(branch[1]); - else if ((T(1) == c) && (details::e_mul == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) return static_cast<details::variable_node<Type>*>(branch[1]); switch (operation) @@ -28526,7 +29551,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_cr<typename details::cov_node<Type,op1<Type> > > \ - (c,v); \ + (c, v); \ basic_opr_switch_statements extended_opr_switch_statements @@ -28542,10 +29567,10 @@ namespace exprtk const details::operator_type& operation, expression_node_ptr (&branch)[2]) { - const Type& v = static_cast<details::variable_node<Type>*>(branch[0])->ref(); + const Type& v = static_cast<details::variable_node<Type>*>(branch[0])->ref (); const Type c = static_cast<details::literal_node<Type>*> (branch[1])->value(); - details::free_node(*(expr_gen.node_allocator_),branch[1]); + details::free_node(*(expr_gen.node_allocator_), branch[1]); if (expr_gen.cardinal_pow_optimisable(operation,c)) { @@ -28554,15 +29579,15 @@ namespace exprtk else return expr_gen.cardinal_pow_optimisation(v,c); } - else if ((T(0) == c) && (details::e_mul == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_mul == operation)) return expr_gen(T(0)); - else if ((T(0) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_div == operation)) return expr_gen(std::numeric_limits<T>::quiet_NaN()); - else if ((T(0) == c) && (details::e_add == operation)) + else if (std::equal_to<T>()(T(0),c) && (details::e_add == operation)) return static_cast<details::variable_node<Type>*>(branch[0]); - else if ((T(1) == c) && (details::e_mul == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_mul == operation)) return static_cast<details::variable_node<Type>*>(branch[0]); - else if ((T(1) == c) && (details::e_div == operation)) + else if (std::equal_to<T>()(T(1),c) && (details::e_div == operation)) return static_cast<details::variable_node<Type>*>(branch[0]); switch (operation) @@ -28570,7 +29595,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_rc<typename details::voc_node<Type,op1<Type> > > \ - (v,c); \ + (v, c); \ basic_opr_switch_statements extended_opr_switch_statements @@ -28591,7 +29616,7 @@ namespace exprtk { #define case_stmt(op) \ case details::e_sf##op : return details::T0oT1oT2_sf3ext<T,T0,T1,T2,details::sf##op##_op<Type> >:: \ - allocate(*(expr_gen.node_allocator_),t0,t1,t2); \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2); \ case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) @@ -28616,7 +29641,8 @@ namespace exprtk if (!expr_gen.sf3_optimisable(id,sf3opr)) return false; else - result = synthesize_sf3ext_expression::template process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2); + result = synthesize_sf3ext_expression::template process<T0, T1, T2> + (expr_gen, sf3opr, t0, t1, t2); return true; } @@ -28633,12 +29659,12 @@ namespace exprtk { #define case_stmt0(op) \ case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,details::sf##op##_op<Type> >:: \ - allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ #define case_stmt1(op) \ case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,details::sfext##op##_op<Type> >:: \ - allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) @@ -28683,7 +29709,8 @@ namespace exprtk if (!expr_gen.sf4_optimisable(id,sf4opr)) return false; else - result = synthesize_sf4ext_expression::template process<T0,T1,T2,T3>(expr_gen,sf4opr,t0,t1,t2,t3); + result = synthesize_sf4ext_expression::template process<T0, T1, T2, T3> + (expr_gen, sf4opr, t0, t1, t2, t3); return true; } @@ -28702,29 +29729,29 @@ namespace exprtk typedef details::T0oT1oT2_base_node<Type>* sf3ext_base_ptr; sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node); - std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; + const std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; switch (n->type()) { case details::expression_node<Type>::e_covoc : return compile_right_impl - <typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype> - (expr_gen,id,t,sf3node,result); + <typename covoc_t::sf3_type_node,ExternalType, ctype, vtype, ctype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_covov : return compile_right_impl - <typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype> - (expr_gen,id,t,sf3node,result); + <typename covov_t::sf3_type_node,ExternalType, ctype, vtype, vtype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_vocov : return compile_right_impl - <typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype> - (expr_gen,id,t,sf3node,result); + <typename vocov_t::sf3_type_node,ExternalType, vtype, ctype, vtype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_vovoc : return compile_right_impl - <typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype> - (expr_gen,id,t,sf3node,result); + <typename vovoc_t::sf3_type_node,ExternalType, vtype, vtype, ctype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_vovov : return compile_right_impl - <typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype> - (expr_gen,id,t,sf3node,result); + <typename vovov_t::sf3_type_node,ExternalType, vtype, vtype, vtype> + (expr_gen, id, t, sf3node, result); default : return false; } @@ -28745,29 +29772,29 @@ namespace exprtk sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node); - std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; + const std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; switch (n->type()) { case details::expression_node<Type>::e_covoc : return compile_left_impl - <typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype> - (expr_gen,id,t,sf3node,result); + <typename covoc_t::sf3_type_node,ExternalType, ctype, vtype, ctype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_covov : return compile_left_impl - <typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype> - (expr_gen,id,t,sf3node,result); + <typename covov_t::sf3_type_node,ExternalType, ctype, vtype, vtype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_vocov : return compile_left_impl - <typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype> - (expr_gen,id,t,sf3node,result); + <typename vocov_t::sf3_type_node,ExternalType, vtype, ctype, vtype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_vovoc : return compile_left_impl - <typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype> - (expr_gen,id,t,sf3node,result); + <typename vovoc_t::sf3_type_node,ExternalType, vtype, vtype, ctype> + (expr_gen, id, t, sf3node, result); case details::expression_node<Type>::e_vovov : return compile_left_impl - <typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype> - (expr_gen,id,t,sf3node,result); + <typename vovov_t::sf3_type_node,ExternalType, vtype, vtype, vtype> + (expr_gen, id, t, sf3node, result); default : return false; } @@ -28788,8 +29815,8 @@ namespace exprtk T1 t1 = n->t1(); T2 t2 = n->t2(); - return synthesize_sf4ext_expression:: - template compile<ExternalType,T0,T1,T2>(expr_gen,id,t,t0,t1,t2,result); + return synthesize_sf4ext_expression::template compile<ExternalType, T0, T1, T2> + (expr_gen, id, t, t0, t1, t2, result); } else return false; @@ -28810,8 +29837,8 @@ namespace exprtk T1 t1 = n->t1(); T2 t2 = n->t2(); - return synthesize_sf4ext_expression:: - template compile<T0,T1,T2,ExternalType>(expr_gen,id,t0,t1,t2,t,result); + return synthesize_sf4ext_expression::template compile<T0, T1, T2, ExternalType> + (expr_gen, id, t0, t1, t2, t, result); } else return false; @@ -28849,7 +29876,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,vtype>(expr_gen,"t/(t*t)",v0,v1,v2,result); + template compile<vtype,vtype,vtype>(expr_gen, "t/(t*t)", v0, v1, v2, result); exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); @@ -28857,20 +29884,27 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<vtype, vtype, vtype> + (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -28905,7 +29939,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,vtype>(expr_gen,"(t*t)/t",v0,v2,v1,result); + template compile<vtype,vtype,vtype>(expr_gen, "(t*t)/t", v0, v2, v1, result); exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); @@ -28913,20 +29947,27 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<vtype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<vtype, vtype, vtype> + (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -28962,7 +30003,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result); + template compile<vtype,vtype,ctype>(expr_gen, "t/(t*t)", v0, v1, c, result); exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); @@ -28970,20 +30011,27 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<vtype, vtype, ctype> + (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29018,7 +30066,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,ctype,vtype>(expr_gen,"(t*t)/t",v0,c,v1,result); + template compile<vtype,ctype,vtype>(expr_gen, "(t*t)/t", v0, c, v1, result); exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); @@ -29026,20 +30074,27 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<vtype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<vtype, vtype, ctype> + (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29074,7 +30129,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen,"t/(t*t)",v0,v1,c,result); + template compile<vtype,vtype,ctype>(expr_gen, "t/(t*t)", v0, v1, c, result); exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); @@ -29082,20 +30137,27 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<vtype, ctype, vtype> + (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29130,7 +30192,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen,"(t*t)/t",v0,v1,c,result); + template compile<vtype, vtype, ctype>(expr_gen, "(t*t)/t", v0, v1, c, result); exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); @@ -29138,20 +30200,27 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<vtype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<vtype, ctype, vtype> + (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29186,7 +30255,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",c,v0,v1,result); + template compile<ctype, vtype, vtype>(expr_gen, "t/(t*t)", c, v0, v1, result); exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); @@ -29194,20 +30263,27 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<ctype, vtype, vtype> + (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29243,7 +30319,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",c,v1,v0,result); + template compile<ctype, vtype, vtype>(expr_gen, "(t*t)/t", c, v1, v0, result); exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); @@ -29251,19 +30327,26 @@ namespace exprtk } } - if (synthesize_sf3ext_expression::template compile<ctype,vtype,vtype>(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<ctype, vtype, vtype> + (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29300,7 +30383,7 @@ namespace exprtk exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1,v); + template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1, v); } // (c0 + v) - c1 --> (cov) (c0 - c1) + v else if ((details::e_add == o0) && (details::e_sub == o1)) @@ -29308,7 +30391,7 @@ namespace exprtk exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1,v); + template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1, v); } // (c0 - v) + c1 --> (cov) (c0 + c1) - v else if ((details::e_sub == o0) && (details::e_add == o1)) @@ -29316,7 +30399,7 @@ namespace exprtk exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1,v); + template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1, v); } // (c0 - v) - c1 --> (cov) (c0 - c1) - v else if ((details::e_sub == o0) && (details::e_sub == o1)) @@ -29324,7 +30407,7 @@ namespace exprtk exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1,v); + template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1, v); } // (c0 * v) * c1 --> (cov) (c0 * c1) * v else if ((details::e_mul == o0) && (details::e_mul == o1)) @@ -29332,7 +30415,7 @@ namespace exprtk exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1,v); + template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1, v); } // (c0 * v) / c1 --> (cov) (c0 / c1) * v else if ((details::e_mul == o0) && (details::e_div == o1)) @@ -29340,7 +30423,7 @@ namespace exprtk exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v); + template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1, v); } // (c0 / v) * c1 --> (cov) (c0 * c1) / v else if ((details::e_div == o0) && (details::e_mul == o1)) @@ -29348,7 +30431,7 @@ namespace exprtk exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v); + template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1, v); } // (c0 / v) / c1 --> (cov) (c0 / c1) / v else if ((details::e_div == o0) && (details::e_div == o1)) @@ -29356,24 +30439,31 @@ namespace exprtk exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v); + template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1, v); } } - if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<ctype, vtype, ctype> + (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29410,7 +30500,7 @@ namespace exprtk exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1,v); + template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1, v); } // (c0) + (v - c1) --> (cov) (c0 - c1) + v else if ((details::e_add == o0) && (details::e_sub == o1)) @@ -29418,7 +30508,7 @@ namespace exprtk exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1,v); + template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1, v); } // (c0) - (v + c1) --> (cov) (c0 - c1) - v else if ((details::e_sub == o0) && (details::e_add == o1)) @@ -29426,7 +30516,7 @@ namespace exprtk exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1,v); + template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1, v); } // (c0) - (v - c1) --> (cov) (c0 + c1) - v else if ((details::e_sub == o0) && (details::e_sub == o1)) @@ -29434,7 +30524,7 @@ namespace exprtk exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1,v); + template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1, v); } // (c0) * (v * c1) --> (voc) v * (c0 * c1) else if ((details::e_mul == o0) && (details::e_mul == o1)) @@ -29442,7 +30532,7 @@ namespace exprtk exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1,v); + template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1, v); } // (c0) * (v / c1) --> (cov) (c0 / c1) * v else if ((details::e_mul == o0) && (details::e_div == o1)) @@ -29450,7 +30540,7 @@ namespace exprtk exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v); + template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1, v); } // (c0) / (v * c1) --> (cov) (c0 / c1) / v else if ((details::e_div == o0) && (details::e_mul == o1)) @@ -29458,7 +30548,7 @@ namespace exprtk exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v); + template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1, v); } // (c0) / (v / c1) --> (cov) (c0 * c1) / v else if ((details::e_div == o0) && (details::e_div == o1)) @@ -29466,24 +30556,31 @@ namespace exprtk exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v); + template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1, v); } } - if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<ctype, vtype, ctype> + (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29530,7 +30627,7 @@ namespace exprtk exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1,v); + template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 + c1, v); } // (c0) + (c1 - v) --> (cov) (c0 + c1) - v else if ((details::e_add == o0) && (details::e_sub == o1)) @@ -29538,7 +30635,7 @@ namespace exprtk exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1,v); + template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 + c1, v); } // (c0) - (c1 + v) --> (cov) (c0 - c1) - v else if ((details::e_sub == o0) && (details::e_add == o1)) @@ -29546,7 +30643,7 @@ namespace exprtk exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1,v); + template allocate_cr<typename details::cov_node<Type,details::sub_op<Type> > >(c0 - c1, v); } // (c0) - (c1 - v) --> (cov) (c0 - c1) + v else if ((details::e_sub == o0) && (details::e_sub == o1)) @@ -29554,7 +30651,7 @@ namespace exprtk exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1,v); + template allocate_cr<typename details::cov_node<Type,details::add_op<Type> > >(c0 - c1, v); } // (c0) * (c1 * v) --> (cov) (c0 * c1) * v else if ((details::e_mul == o0) && (details::e_mul == o1)) @@ -29562,7 +30659,7 @@ namespace exprtk exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1,v); + template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 * c1, v); } // (c0) * (c1 / v) --> (cov) (c0 * c1) / v else if ((details::e_mul == o0) && (details::e_div == o1)) @@ -29570,7 +30667,7 @@ namespace exprtk exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v); + template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1, v); } // (c0) / (c1 * v) --> (cov) (c0 / c1) / v else if ((details::e_div == o0) && (details::e_mul == o1)) @@ -29578,7 +30675,7 @@ namespace exprtk exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v); + template allocate_cr<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1, v); } // (c0) / (c1 / v) --> (cov) (c0 / c1) * v else if ((details::e_div == o0) && (details::e_div == o1)) @@ -29586,23 +30683,30 @@ namespace exprtk exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); return expr_gen.node_allocator_-> - template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v); + template allocate_cr<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1, v); } } - if (synthesize_sf3ext_expression::template compile<ctype,ctype,vtype>(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<ctype, ctype, vtype> + (expr_gen, id(expr_gen, o0, o1), c0, c1, v, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c0,c1,v,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), c0, c1, v, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29639,7 +30743,7 @@ namespace exprtk exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v,c0 + c1); + template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v, c0 + c1); } // (v + c0) - c1 --> (voc) v + (c0 - c1) else if ((details::e_add == o0) && (details::e_sub == o1)) @@ -29647,7 +30751,7 @@ namespace exprtk exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v,c0 - c1); + template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v, c0 - c1); } // (v - c0) + c1 --> (voc) v - (c0 + c1) else if ((details::e_sub == o0) && (details::e_add == o1)) @@ -29655,7 +30759,7 @@ namespace exprtk exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v,c1 - c0); + template allocate_rc<typename details::voc_node<Type,details::add_op<Type> > >(v, c1 - c0); } // (v - c0) - c1 --> (voc) v - (c0 + c1) else if ((details::e_sub == o0) && (details::e_sub == o1)) @@ -29663,7 +30767,7 @@ namespace exprtk exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::sub_op<Type> > >(v,c0 + c1); + template allocate_rc<typename details::voc_node<Type,details::sub_op<Type> > >(v, c0 + c1); } // (v * c0) * c1 --> (voc) v * (c0 * c1) else if ((details::e_mul == o0) && (details::e_mul == o1)) @@ -29671,7 +30775,7 @@ namespace exprtk exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v,c0 * c1); + template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v, c0 * c1); } // (v * c0) / c1 --> (voc) v * (c0 / c1) else if ((details::e_mul == o0) && (details::e_div == o1)) @@ -29679,7 +30783,7 @@ namespace exprtk exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v,c0 / c1); + template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v, c0 / c1); } // (v / c0) * c1 --> (voc) v * (c1 / c0) else if ((details::e_div == o0) && (details::e_mul == o1)) @@ -29687,7 +30791,7 @@ namespace exprtk exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v,c1 / c0); + template allocate_rc<typename details::voc_node<Type,details::mul_op<Type> > >(v, c1 / c0); } // (v / c0) / c1 --> (voc) v / (c0 * c1) else if ((details::e_div == o0) && (details::e_div == o1)) @@ -29695,7 +30799,7 @@ namespace exprtk exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::div_op<Type> > >(v,c0 * c1); + template allocate_rc<typename details::voc_node<Type,details::div_op<Type> > >(v, c0 * c1); } // (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) else if ((details::e_pow == o0) && (details::e_pow == o1)) @@ -29703,24 +30807,31 @@ namespace exprtk exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); return expr_gen.node_allocator_-> - template allocate_rc<typename details::voc_node<Type,details::pow_op<Type> > >(v,c0 * c1); + template allocate_rc<typename details::voc_node<Type,details::pow_op<Type> > >(v, c0 * c1); } } - if (synthesize_sf3ext_expression::template compile<vtype,ctype,ctype>(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result)) + const bool synthesis_result = + synthesize_sf3ext_expression::template compile<vtype, ctype, ctype> + (expr_gen, id(expr_gen, o0, o1), v, c0, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); else if (!expr_gen.valid_operator(o1,f1)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v,c0,c1,f0,f1); + return node_type::allocate(*(expr_gen.node_allocator_), v, c0, c1, f0, f1); } static inline std::string id(expression_generator<Type>& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29776,7 +30887,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v2,v1,v3,result); + template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, v3, result); exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); @@ -29787,7 +30898,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v3,v1,v2,result); + template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v3, v1, v2, result); exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); @@ -29798,7 +30909,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t+t)*(t/t)",v0,v1,v3,v2,result); + template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t+t)*(t/t)", v0, v1, v3, v2, result); exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); @@ -29809,7 +30920,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen,"(t-t)*(t/t)",v0,v1,v3,v2,result); + template compile<vtype,vtype,vtype,vtype>(expr_gen, "(t-t)*(t/t)", v0, v1, v3, v2, result); exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); @@ -29820,7 +30931,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,vtype>(expr_gen,"((t*t)*t)/t",v0,v1,v3,v2,result); + template compile<vtype,vtype,vtype,vtype>(expr_gen, "((t*t)*t)/t", v0, v1, v3, v2, result); exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); @@ -29828,7 +30939,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -29837,7 +30952,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -29845,7 +30960,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -29889,7 +31008,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,ctype>(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); + template compile<vtype,vtype,vtype,ctype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); @@ -29900,7 +31019,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); + template compile<vtype,ctype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); @@ -29908,7 +31027,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -29917,7 +31040,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -29925,7 +31048,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -29969,7 +31096,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); + template compile<vtype,ctype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); @@ -29980,7 +31107,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,vtype,ctype>(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); + template compile<vtype,vtype,vtype,ctype>(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); @@ -29988,7 +31115,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -29997,7 +31128,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -30005,7 +31136,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30049,7 +31184,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,ctype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v1,c,v2,result); + template compile<vtype,vtype,ctype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v1, c, v2, result); exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); @@ -30060,7 +31195,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,vtype,ctype,vtype>(expr_gen,"(t*t)/(t*t)",v0,v2,c,v1,result); + template compile<vtype,vtype,ctype,vtype>(expr_gen, "(t*t)/(t*t)", v0, v2, c, v1, result); exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); @@ -30068,7 +31203,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -30077,7 +31216,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -30085,7 +31224,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30129,7 +31272,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<ctype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",c,v1,v0,v2,result); + template compile<ctype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", c, v1, v0, v2, result); exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); @@ -30140,7 +31283,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<ctype,vtype,vtype,vtype>(expr_gen,"(t*t)/(t*t)",c,v2,v0,v1,result); + template compile<ctype,vtype,vtype,vtype>(expr_gen, "(t*t)/(t*t)", c, v2, v0, v1, result); exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); @@ -30148,7 +31291,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -30157,7 +31304,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -30165,7 +31312,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30209,7 +31360,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -30220,7 +31371,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -30231,7 +31382,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t-t)+t",(c0 - c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t-t)+t", (c0 - c1), v0, v1, result); exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); @@ -30242,7 +31393,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -30253,7 +31404,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); @@ -30264,7 +31415,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); @@ -30275,7 +31426,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v1,v0,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v1, v0, result); exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); @@ -30286,7 +31437,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t*(t*t)",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t*(t*t)", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); @@ -30297,7 +31448,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); @@ -30325,7 +31476,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); + template compile<ctype, vtype, vtype>(expr_gen, specfunc, c0, v0, v1, result); exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); @@ -30333,7 +31484,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -30342,7 +31497,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -30350,7 +31505,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30394,7 +31553,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -30405,7 +31564,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -30416,7 +31575,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c1 - c0),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c1 - c0), v0, v1, result); exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); @@ -30427,7 +31586,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -30438,7 +31597,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); @@ -30449,7 +31608,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",Type(1) / (c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", Type(1) / (c0 * c1), v0, v1, result); exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); @@ -30460,7 +31619,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); @@ -30471,7 +31630,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t*(t/t)", (c0 * c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); @@ -30482,7 +31641,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t*(t/t)", Type(1) / (c0 * c1), v0, v1, result); exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); @@ -30493,7 +31652,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,ctype>(expr_gen,"(t*t)*(t+t)",v0,T(1) / c0,v1,c1,result); + template compile<vtype,ctype,vtype,ctype>(expr_gen, "(t*t)*(t+t)", v0, T(1) / c0, v1, c1, result); exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); @@ -30504,7 +31663,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf4ext_expression:: - template compile<vtype,ctype,vtype,ctype>(expr_gen,"(t*t)*(t-t)",v0,T(1) / c0,v1,c1,result); + template compile<vtype,ctype,vtype,ctype>(expr_gen, "(t*t)*(t-t)", v0, T(1) / c0, v1, c1, result); exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); @@ -30532,7 +31691,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, specfunc, c0, v0, v1, result); exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); @@ -30560,7 +31719,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen,specfunc,v0,v1,c0,result); + template compile<vtype,vtype,ctype>(expr_gen, specfunc, v0, v1, c0, result); exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); @@ -30568,7 +31727,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -30577,7 +31740,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -30585,7 +31748,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30629,7 +31796,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -30640,7 +31807,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -30651,7 +31818,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t-(t+t)",(c0 + c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t-(t+t)", (c0 + c1), v0, v1, result); exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); @@ -30662,7 +31829,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -30673,7 +31840,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); @@ -30684,7 +31851,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t*(t/t)",(c0 / c1),v1,v0,result); + template compile<ctype,vtype,vtype>(expr_gen, "t*(t/t)", (c0 / c1), v1, v0, result); exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); @@ -30695,7 +31862,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); @@ -30706,7 +31873,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 * c1), v0, v1, result); exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); @@ -30717,7 +31884,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); @@ -30745,7 +31912,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen,specfunc, c0, v0, v1, result); exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); @@ -30753,7 +31920,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -30762,7 +31933,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -30770,7 +31941,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30814,7 +31989,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); @@ -30825,7 +32000,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); @@ -30836,7 +32011,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen,"(t+t)-t",v0,v1,(c1 + c0),result); + template compile<vtype,vtype,ctype>(expr_gen, "(t+t)-t", v0, v1, (c1 + c0), result); exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); @@ -30847,7 +32022,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); @@ -30858,7 +32033,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); @@ -30869,7 +32044,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); @@ -30880,7 +32055,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)*t",(c0 / c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)*t", (c0 / c1), v0, v1, result); exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); @@ -30891,7 +32066,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, "(t*t)/t", Type(1) / (c0 * c1), v0, v1, result); exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); @@ -30902,7 +32077,7 @@ namespace exprtk { const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<vtype,vtype,ctype>(expr_gen,"(t*t)*t",v0,v1,Type(1) / (c0 * c1),result); + template compile<vtype,vtype,ctype>(expr_gen, "(t*t)*t", v0, v1, Type(1) / (c0 * c1), result); exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); @@ -30929,7 +32104,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression:: - template compile<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result); + template compile<ctype,vtype,vtype>(expr_gen, specfunc, c0, v0, v1, result); exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); @@ -30937,7 +32112,11 @@ namespace exprtk } } - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); @@ -30946,7 +32125,7 @@ namespace exprtk else if (!expr_gen.valid_operator(o2,f2)) return error_node(); else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -30954,7 +32133,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31006,7 +32189,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31043,14 +32230,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31058,7 +32249,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31095,14 +32290,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) return result; if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31110,7 +32309,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31147,14 +32350,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31162,7 +32369,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31200,14 +32411,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) return result; if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31215,7 +32430,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31253,14 +32472,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31268,7 +32491,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31305,14 +32532,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31320,7 +32551,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31357,14 +32592,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31372,7 +32611,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31409,14 +32652,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31424,7 +32671,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31461,14 +32712,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31476,7 +32731,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31513,14 +32772,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31528,7 +32791,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31565,14 +32832,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31580,7 +32851,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31617,14 +32892,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31632,7 +32911,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31670,14 +32953,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31685,7 +32972,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31723,14 +33014,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31738,7 +33033,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31775,14 +33074,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31790,7 +33093,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31828,14 +33135,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o0,f0)) return error_node(); exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31843,7 +33154,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31897,14 +33212,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31912,7 +33231,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -31950,14 +33273,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -31965,7 +33292,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32002,14 +33333,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32017,7 +33352,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32054,14 +33393,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32069,7 +33412,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32106,14 +33453,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32121,7 +33472,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32158,14 +33513,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32173,7 +33532,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32211,14 +33574,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32226,7 +33593,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32264,14 +33635,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32279,7 +33654,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32316,14 +33695,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32331,7 +33714,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32368,14 +33755,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32383,7 +33774,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32421,14 +33816,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32436,7 +33835,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32473,14 +33876,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32488,7 +33895,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32524,14 +33935,18 @@ namespace exprtk details::free_node(*(expr_gen.node_allocator_),branch[0]); expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32539,7 +33954,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32576,14 +33995,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32591,7 +34014,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32628,14 +34055,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32643,7 +34074,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32681,14 +34116,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32696,7 +34135,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32734,14 +34177,18 @@ namespace exprtk expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile<T0, T1, T2, T3> + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) return result; else if (!expr_gen.valid_operator(o2,f2)) return error_node(); exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); } static inline std::string id(expression_generator<Type>& expr_gen, @@ -32749,7 +34196,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32802,28 +34253,28 @@ namespace exprtk case details::e_add : result = (*this)(details::e_neg, node_allocator_-> allocate_rr<typename details:: - vov_node<Type,details::add_op<Type> > >(v0,v1)); + vov_node<Type,details::add_op<Type> > >(v0, v1)); exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); break; // (-v0 - -v1) --> (v1 - v0) case details::e_sub : result = node_allocator_-> allocate_rr<typename details:: - vov_node<Type,details::sub_op<Type> > >(v1,v0); + vov_node<Type,details::sub_op<Type> > >(v1, v0); exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); break; // (-v0 * -v1) --> (v0 * v1) case details::e_mul : result = node_allocator_-> allocate_rr<typename details:: - vov_node<Type,details::mul_op<Type> > >(v0,v1); + vov_node<Type,details::mul_op<Type> > >(v0, v1); exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); break; // (-v0 / -v1) --> (v0 / v1) case details::e_div : result = node_allocator_-> allocate_rr<typename details:: - vov_node<Type,details::div_op<Type> > >(v0,v1); + vov_node<Type,details::div_op<Type> > >(v0, v1); exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); break; @@ -32834,7 +34285,7 @@ namespace exprtk if (0 == result) { result = node_allocator_-> - allocate_rrrrr<typename details::uvouv_node<Type> >(v0,v1,u0,u1,f); + allocate_rrrrr<typename details::uvouv_node<Type> >(v0, v1, u0, u1, f); } details::free_all_nodes(*node_allocator_,branch); @@ -32868,7 +34319,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ allocate_ttt<typename details::str_xrox_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ - (s0,s1,rp0); \ + (s0, s1, rp0); \ string_opr_switch_statements #undef case_stmt @@ -32886,7 +34337,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ allocate_ttt<typename details::str_xoxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ - (s0,s1,rp1); \ + (s0, s1, rp1); \ string_opr_switch_statements #undef case_stmt @@ -32904,7 +34355,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ allocate_tttt<typename details::str_xroxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \ - (s0,s1,rp0,rp1); \ + (s0, s1, rp0, rp1); \ string_opr_switch_statements #undef case_stmt @@ -32917,9 +34368,9 @@ namespace exprtk { switch (opr) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate_tt<typename details::sos_node<Type,T0,T1,op1<Type> >,T0,T1>(s0,s1); \ + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_tt<typename details::sos_node<Type,T0,T1,op1<Type> >,T0,T1>(s0, s1); \ string_opr_switch_statements #undef case_stmt @@ -32932,7 +34383,7 @@ namespace exprtk std::string& s0 = static_cast<details::stringvar_node<Type>*>(branch[0])->ref(); std::string& s1 = static_cast<details::stringvar_node<Type>*>(branch[1])->ref(); - return synthesize_sos_expression_impl<std::string&,std::string&>(opr,s0,s1); + return synthesize_sos_expression_impl<std::string&,std::string&>(opr, s0, s1); } inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -32945,7 +34396,7 @@ namespace exprtk free_node(*node_allocator_,branch[0]); - return synthesize_str_xrox_expression_impl<std::string&,std::string&>(opr,s0,s1,rp0); + return synthesize_str_xrox_expression_impl<std::string&,std::string&>(opr, s0, s1, rp0); } inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -32958,7 +34409,7 @@ namespace exprtk free_node(*node_allocator_,branch[1]); - return synthesize_str_xoxr_expression_impl<std::string&,std::string&>(opr,s0,s1,rp1); + return synthesize_str_xoxr_expression_impl<std::string&,std::string&>(opr, s0, s1, rp1); } inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -32971,7 +34422,7 @@ namespace exprtk free_node(*node_allocator_,branch[1]); - return synthesize_str_xoxr_expression_impl<std::string&, const std::string>(opr,s0,s1,rp1); + return synthesize_str_xoxr_expression_impl<std::string&, const std::string>(opr, s0, s1, rp1); } inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -32987,7 +34438,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[0]); details::free_node(*node_allocator_,branch[1]); - return synthesize_str_xroxr_expression_impl<std::string&,std::string&>(opr,s0,s1,rp0,rp1); + return synthesize_str_xroxr_expression_impl<std::string&,std::string&>(opr, s0, s1, rp0, rp1); } inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -32997,7 +34448,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[1]); - return synthesize_sos_expression_impl<std::string&, const std::string>(opr,s0,s1); + return synthesize_sos_expression_impl<std::string&, const std::string>(opr, s0, s1); } inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -33007,7 +34458,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[0]); - return synthesize_sos_expression_impl<const std::string,std::string&>(opr,s0,s1); + return synthesize_sos_expression_impl<const std::string,std::string&>(opr, s0, s1); } inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -33021,7 +34472,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[0]); details::free_node(*node_allocator_,branch[1]); - return synthesize_str_xoxr_expression_impl<const std::string,std::string&>(opr,s0,s1,rp1); + return synthesize_str_xoxr_expression_impl<const std::string,std::string&>(opr, s0, s1, rp1); } inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -33035,7 +34486,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[0]); details::free_node(*node_allocator_,branch[1]); - return synthesize_str_xrox_expression_impl<std::string&, const std::string>(opr,s0,s1,rp0); + return synthesize_str_xrox_expression_impl<std::string&, const std::string>(opr, s0, s1, rp0); } inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -33051,7 +34502,7 @@ namespace exprtk details::free_node(*node_allocator_,branch[0]); details::free_node(*node_allocator_,branch[1]); - return synthesize_str_xroxr_expression_impl<std::string&, const std::string>(opr,s0,s1,rp0,rp1); + return synthesize_str_xroxr_expression_impl<std::string&, const std::string>(opr, s0, s1, rp0, rp1); } inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -33064,16 +34515,19 @@ namespace exprtk if (details::e_add == opr) result = node_allocator_->allocate_c<details::string_literal_node<Type> >(s0 + s1); else if (details::e_in == opr) - result = node_allocator_->allocate_c<details::literal_node<Type> >(details::in_op<Type>::process(s0,s1)); + result = node_allocator_->allocate_c<details::literal_node<Type> >(details::in_op <Type>::process(s0,s1)); else if (details::e_like == opr) - result = node_allocator_->allocate_c<details::literal_node<Type> >(details::like_op<Type>::process(s0,s1)); + result = node_allocator_->allocate_c<details::literal_node<Type> >(details::like_op <Type>::process(s0,s1)); else if (details::e_ilike == opr) result = node_allocator_->allocate_c<details::literal_node<Type> >(details::ilike_op<Type>::process(s0,s1)); else { - expression_node_ptr temp = synthesize_sos_expression_impl<const std::string, const std::string>(opr,s0,s1); - Type v = temp->value(); + expression_node_ptr temp = synthesize_sos_expression_impl<const std::string, const std::string>(opr, s0, s1); + + const Type v = temp->value(); + details::free_node(*node_allocator_,temp); + result = node_allocator_->allocate<literal_node_t>(v); } @@ -33093,7 +34547,7 @@ namespace exprtk free_node(*node_allocator_,branch[0]); free_node(*node_allocator_,branch[1]); - return synthesize_str_xoxr_expression_impl<const std::string, const std::string>(opr,s0,s1,rp1); + return synthesize_str_xoxr_expression_impl<const std::string, const std::string>(opr, s0, s1, rp1); } inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -33106,15 +34560,15 @@ namespace exprtk free_node(*node_allocator_,branch[0]); - return synthesize_str_xrox_expression_impl<const std::string,std::string&>(opr,s0,s1,rp0); + return synthesize_str_xrox_expression_impl<const std::string,std::string&>(opr, s0, s1, rp0); } inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { const std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); std::string& s1 = static_cast<details::string_range_node<Type>*> (branch[1])->ref (); - range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); - range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range(); + const range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); + const range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range(); static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); static_cast<details::string_range_node<Type>*> (branch[1])->range_ref().clear(); @@ -33122,35 +34576,35 @@ namespace exprtk free_node(*node_allocator_,branch[0]); free_node(*node_allocator_,branch[1]); - return synthesize_str_xroxr_expression_impl<const std::string,std::string&>(opr,s0,s1,rp0,rp1); + return synthesize_str_xroxr_expression_impl<const std::string,std::string&>(opr, s0, s1, rp0, rp1); } inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); + const std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); const std::string s1 = static_cast<details::string_literal_node<Type>*> (branch[1])->str (); - range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); + const range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); details::free_all_nodes(*node_allocator_,branch); - return synthesize_str_xrox_expression_impl<const std::string,std::string>(opr,s0,s1,rp0); + return synthesize_str_xrox_expression_impl<const std::string,std::string>(opr, s0, s1, rp0); } inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); - std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); - range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); - range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); + const std::string s0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->str (); + const std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str (); + const range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range(); + const range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range(); static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear(); static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear(); details::free_all_nodes(*node_allocator_,branch); - return synthesize_str_xroxr_expression_impl<const std::string, const std::string>(opr,s0,s1,rp0,rp1); + return synthesize_str_xroxr_expression_impl<const std::string, const std::string>(opr, s0, s1, rp0, rp1); } inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) @@ -33160,7 +34614,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ allocate_ttt<typename details::str_sogens_node<Type,op1<Type> > > \ - (opr,branch[0],branch[1]); \ + (opr, branch[0], branch[1]); \ string_opr_switch_statements #undef case_stmt @@ -33277,7 +34731,8 @@ namespace exprtk const std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str(); const std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); - Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); + const Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); + details::free_all_nodes(*node_allocator_,branch); return node_allocator_->allocate_c<details::literal_node<Type> >(v); @@ -33292,9 +34747,9 @@ namespace exprtk std::string& s1 = static_cast<details::stringvar_node<Type>*>(branch[1])->ref(); std::string& s2 = static_cast<details::stringvar_node<Type>*>(branch[2])->ref(); - typedef typename details::sosos_node<Type,std::string&,std::string&,std::string&,details::inrange_op<Type> > inrange_t; + typedef typename details::sosos_node<Type, std::string&, std::string&, std::string&, details::inrange_op<Type> > inrange_t; - return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string&>(s0,s1,s2); + return node_allocator_->allocate_type<inrange_t, std::string&, std::string&, std::string&>(s0, s1, s2); } else if ( details::is_const_string_node(branch[0]) && @@ -33306,12 +34761,12 @@ namespace exprtk std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); - typedef typename details::sosos_node<Type,std::string,std::string&,std::string,details::inrange_op<Type> > inrange_t; + typedef typename details::sosos_node<Type, std::string, std::string&, std::string, details::inrange_op<Type> > inrange_t; details::free_node(*node_allocator_,branch[0]); details::free_node(*node_allocator_,branch[2]); - return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string>(s0,s1,s2); + return node_allocator_->allocate_type<inrange_t, std::string, std::string&, std::string>(s0, s1, s2); } else if ( details::is_string_node(branch[0]) && @@ -33323,11 +34778,11 @@ namespace exprtk std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str(); std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref(); - typedef typename details::sosos_node<Type,std::string&,std::string,std::string&,details::inrange_op<Type> > inrange_t; + typedef typename details::sosos_node<Type, std::string&, std::string, std::string&, details::inrange_op<Type> > inrange_t; details::free_node(*node_allocator_,branch[1]); - return node_allocator_->allocate_type<inrange_t,std::string&,std::string,std::string&>(s0,s1,s2); + return node_allocator_->allocate_type<inrange_t, std::string&, std::string, std::string&>(s0, s1, s2); } else if ( details::is_string_node(branch[0]) && @@ -33339,11 +34794,11 @@ namespace exprtk std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str(); - typedef typename details::sosos_node<Type,std::string&,std::string&,std::string,details::inrange_op<Type> > inrange_t; + typedef typename details::sosos_node<Type, std::string&, std::string&, std::string, details::inrange_op<Type> > inrange_t; details::free_node(*node_allocator_,branch[2]); - return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string>(s0,s1,s2); + return node_allocator_->allocate_type<inrange_t, std::string&, std::string&, std::string>(s0, s1, s2); } else if ( details::is_const_string_node(branch[0]) && @@ -33355,11 +34810,11 @@ namespace exprtk std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref(); std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref(); - typedef typename details::sosos_node<Type,std::string,std::string&,std::string&,details::inrange_op<Type> > inrange_t; + typedef typename details::sosos_node<Type, std::string, std::string&, std::string&, details::inrange_op<Type> > inrange_t; details::free_node(*node_allocator_,branch[0]); - return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string&>(s0,s1,s2); + return node_allocator_->allocate_type<inrange_t, std::string, std::string&, std::string&>(s0, s1, s2); } else return error_node(); @@ -33387,8 +34842,8 @@ namespace exprtk typedef typename details::null_eq_node<T> nulleq_node_t; - bool b0_null = details::is_null_node(branch[0]); - bool b1_null = details::is_null_node(branch[1]); + const bool b0_null = details::is_null_node(branch[0]); + const bool b1_null = details::is_null_node(branch[1]); if (b0_null && b1_null) { @@ -33475,7 +34930,11 @@ namespace exprtk (details::e_like == operation) || (details::e_ilike == operation) ) + { + free_all_nodes(*node_allocator_,branch); + return error_node(); + } else if (!details::all_nodes_valid<N>(branch)) { free_all_nodes(*node_allocator_,branch); @@ -33489,7 +34948,7 @@ namespace exprtk if (is_constant_foldable<N>(branch)) { - Type v = expression_point->value(); + const Type v = expression_point->value(); details::free_node(*node_allocator_,expression_point); return node_allocator_->allocate<literal_node_t>(v); @@ -33540,15 +34999,15 @@ namespace exprtk return expression_point; } - bool strength_reduction_enabled_; + bool strength_reduction_enabled_; details::node_allocator* node_allocator_; - synthesize_map_t synthesize_map_; - unary_op_map_t* unary_op_map_; - binary_op_map_t* binary_op_map_; - inv_binary_op_map_t* inv_binary_op_map_; - sf3_map_t* sf3_map_; - sf4_map_t* sf4_map_; - parser_t* parser_; + synthesize_map_t synthesize_map_; + unary_op_map_t* unary_op_map_; + binary_op_map_t* binary_op_map_; + inv_binary_op_map_t* inv_binary_op_map_; + sf3_map_t* sf3_map_; + sf4_map_t* sf4_map_; + parser_t* parser_; }; inline void set_error(const parser_error::type& error_type) @@ -33590,7 +35049,7 @@ namespace exprtk if (se.data) { - e.register_local_data(se.data,1,0); + e.register_local_data(se.data, 1, 0); } } else if (scope_element::e_vector == se.type) @@ -33602,7 +35061,7 @@ namespace exprtk if (se.data) { - e.register_local_data(se.data,se.size,1); + e.register_local_data(se.data, se.size, 1); } } #ifndef exprtk_disable_string_capabilities @@ -33615,7 +35074,7 @@ namespace exprtk if (se.data) { - e.register_local_data(se.data,se.size,2); + e.register_local_data(se.data, se.size, 2); } } #endif @@ -33642,45 +35101,45 @@ namespace exprtk #define register_unary_op(Op,UnaryFunctor) \ m.insert(std::make_pair(Op,UnaryFunctor<T>::process)); \ - register_unary_op(details:: e_abs,details:: abs_op) - register_unary_op(details:: e_acos,details:: acos_op) - register_unary_op(details::e_acosh,details::acosh_op) - register_unary_op(details:: e_asin,details:: asin_op) - register_unary_op(details::e_asinh,details::asinh_op) - register_unary_op(details::e_atanh,details::atanh_op) - register_unary_op(details:: e_ceil,details:: ceil_op) - register_unary_op(details:: e_cos,details:: cos_op) - register_unary_op(details:: e_cosh,details:: cosh_op) - register_unary_op(details:: e_exp,details:: exp_op) - register_unary_op(details::e_expm1,details::expm1_op) - register_unary_op(details::e_floor,details::floor_op) - register_unary_op(details:: e_log,details:: log_op) - register_unary_op(details::e_log10,details::log10_op) - register_unary_op(details:: e_log2,details:: log2_op) - register_unary_op(details::e_log1p,details::log1p_op) - register_unary_op(details:: e_neg,details:: neg_op) - register_unary_op(details:: e_pos,details:: pos_op) - register_unary_op(details::e_round,details::round_op) - register_unary_op(details:: e_sin,details:: sin_op) - register_unary_op(details:: e_sinc,details:: sinc_op) - register_unary_op(details:: e_sinh,details:: sinh_op) - register_unary_op(details:: e_sqrt,details:: sqrt_op) - register_unary_op(details:: e_tan,details:: tan_op) - register_unary_op(details:: e_tanh,details:: tanh_op) - register_unary_op(details:: e_cot,details:: cot_op) - register_unary_op(details:: e_sec,details:: sec_op) - register_unary_op(details:: e_csc,details:: csc_op) - register_unary_op(details:: e_r2d,details:: r2d_op) - register_unary_op(details:: e_d2r,details:: d2r_op) - register_unary_op(details:: e_d2g,details:: d2g_op) - register_unary_op(details:: e_g2d,details:: g2d_op) - register_unary_op(details:: e_notl,details:: notl_op) - register_unary_op(details:: e_sgn,details:: sgn_op) - register_unary_op(details:: e_erf,details:: erf_op) - register_unary_op(details:: e_erfc,details:: erfc_op) - register_unary_op(details:: e_ncdf,details:: ncdf_op) - register_unary_op(details:: e_frac,details:: frac_op) - register_unary_op(details::e_trunc,details::trunc_op) + register_unary_op(details:: e_abs, details:: abs_op) + register_unary_op(details:: e_acos, details:: acos_op) + register_unary_op(details::e_acosh, details::acosh_op) + register_unary_op(details:: e_asin, details:: asin_op) + register_unary_op(details::e_asinh, details::asinh_op) + register_unary_op(details::e_atanh, details::atanh_op) + register_unary_op(details:: e_ceil, details:: ceil_op) + register_unary_op(details:: e_cos, details:: cos_op) + register_unary_op(details:: e_cosh, details:: cosh_op) + register_unary_op(details:: e_exp, details:: exp_op) + register_unary_op(details::e_expm1, details::expm1_op) + register_unary_op(details::e_floor, details::floor_op) + register_unary_op(details:: e_log, details:: log_op) + register_unary_op(details::e_log10, details::log10_op) + register_unary_op(details:: e_log2, details:: log2_op) + register_unary_op(details::e_log1p, details::log1p_op) + register_unary_op(details:: e_neg, details:: neg_op) + register_unary_op(details:: e_pos, details:: pos_op) + register_unary_op(details::e_round, details::round_op) + register_unary_op(details:: e_sin, details:: sin_op) + register_unary_op(details:: e_sinc, details:: sinc_op) + register_unary_op(details:: e_sinh, details:: sinh_op) + register_unary_op(details:: e_sqrt, details:: sqrt_op) + register_unary_op(details:: e_tan, details:: tan_op) + register_unary_op(details:: e_tanh, details:: tanh_op) + register_unary_op(details:: e_cot, details:: cot_op) + register_unary_op(details:: e_sec, details:: sec_op) + register_unary_op(details:: e_csc, details:: csc_op) + register_unary_op(details:: e_r2d, details:: r2d_op) + register_unary_op(details:: e_d2r, details:: d2r_op) + register_unary_op(details:: e_d2g, details:: d2g_op) + register_unary_op(details:: e_g2d, details:: g2d_op) + register_unary_op(details:: e_notl, details:: notl_op) + register_unary_op(details:: e_sgn, details:: sgn_op) + register_unary_op(details:: e_erf, details:: erf_op) + register_unary_op(details:: e_erfc, details:: erfc_op) + register_unary_op(details:: e_ncdf, details:: ncdf_op) + register_unary_op(details:: e_frac, details:: frac_op) + register_unary_op(details::e_trunc, details::trunc_op) #undef register_unary_op } @@ -33691,24 +35150,24 @@ namespace exprtk #define register_binary_op(Op,BinaryFunctor) \ m.insert(value_type(Op,BinaryFunctor<T>::process)); \ - register_binary_op(details:: e_add,details:: add_op) - register_binary_op(details:: e_sub,details:: sub_op) - register_binary_op(details:: e_mul,details:: mul_op) - register_binary_op(details:: e_div,details:: div_op) - register_binary_op(details:: e_mod,details:: mod_op) - register_binary_op(details:: e_pow,details:: pow_op) - register_binary_op(details:: e_lt,details:: lt_op) - register_binary_op(details:: e_lte,details:: lte_op) - register_binary_op(details:: e_gt,details:: gt_op) - register_binary_op(details:: e_gte,details:: gte_op) - register_binary_op(details:: e_eq,details:: eq_op) - register_binary_op(details:: e_ne,details:: ne_op) - register_binary_op(details:: e_and,details:: and_op) - register_binary_op(details::e_nand,details::nand_op) - register_binary_op(details:: e_or,details:: or_op) - register_binary_op(details:: e_nor,details:: nor_op) - register_binary_op(details:: e_xor,details:: xor_op) - register_binary_op(details::e_xnor,details::xnor_op) + register_binary_op(details:: e_add, details:: add_op) + register_binary_op(details:: e_sub, details:: sub_op) + register_binary_op(details:: e_mul, details:: mul_op) + register_binary_op(details:: e_div, details:: div_op) + register_binary_op(details:: e_mod, details:: mod_op) + register_binary_op(details:: e_pow, details:: pow_op) + register_binary_op(details:: e_lt, details:: lt_op) + register_binary_op(details:: e_lte, details:: lte_op) + register_binary_op(details:: e_gt, details:: gt_op) + register_binary_op(details:: e_gte, details:: gte_op) + register_binary_op(details:: e_eq, details:: eq_op) + register_binary_op(details:: e_ne, details:: ne_op) + register_binary_op(details:: e_and, details:: and_op) + register_binary_op(details::e_nand, details::nand_op) + register_binary_op(details:: e_or, details:: or_op) + register_binary_op(details:: e_nor, details:: nor_op) + register_binary_op(details:: e_xor, details:: xor_op) + register_binary_op(details::e_xnor, details::xnor_op) #undef register_binary_op } @@ -33719,24 +35178,24 @@ namespace exprtk #define register_binary_op(Op,BinaryFunctor) \ m.insert(value_type(BinaryFunctor<T>::process,Op)); \ - register_binary_op(details:: e_add,details:: add_op) - register_binary_op(details:: e_sub,details:: sub_op) - register_binary_op(details:: e_mul,details:: mul_op) - register_binary_op(details:: e_div,details:: div_op) - register_binary_op(details:: e_mod,details:: mod_op) - register_binary_op(details:: e_pow,details:: pow_op) - register_binary_op(details:: e_lt,details:: lt_op) - register_binary_op(details:: e_lte,details:: lte_op) - register_binary_op(details:: e_gt,details:: gt_op) - register_binary_op(details:: e_gte,details:: gte_op) - register_binary_op(details:: e_eq,details:: eq_op) - register_binary_op(details:: e_ne,details:: ne_op) - register_binary_op(details:: e_and,details:: and_op) - register_binary_op(details::e_nand,details::nand_op) - register_binary_op(details:: e_or,details:: or_op) - register_binary_op(details:: e_nor,details:: nor_op) - register_binary_op(details:: e_xor,details:: xor_op) - register_binary_op(details::e_xnor,details::xnor_op) + register_binary_op(details:: e_add, details:: add_op) + register_binary_op(details:: e_sub, details:: sub_op) + register_binary_op(details:: e_mul, details:: mul_op) + register_binary_op(details:: e_div, details:: div_op) + register_binary_op(details:: e_mod, details:: mod_op) + register_binary_op(details:: e_pow, details:: pow_op) + register_binary_op(details:: e_lt, details:: lt_op) + register_binary_op(details:: e_lte, details:: lte_op) + register_binary_op(details:: e_gt, details:: gt_op) + register_binary_op(details:: e_gte, details:: gte_op) + register_binary_op(details:: e_eq, details:: eq_op) + register_binary_op(details:: e_ne, details:: ne_op) + register_binary_op(details:: e_and, details:: and_op) + register_binary_op(details::e_nand, details::nand_op) + register_binary_op(details:: e_or, details:: or_op) + register_binary_op(details:: e_nor, details:: nor_op) + register_binary_op(details:: e_xor, details:: xor_op) + register_binary_op(details::e_xnor, details::xnor_op) #undef register_binary_op } @@ -33756,6 +35215,12 @@ namespace exprtk register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) register_sf3(28) register_sf3(29) register_sf3(30) #undef register_sf3 + + #define register_sf3_extid(Id, Op) \ + sf3_map[Id] = pair_t(details::sf##Op##_op<T>::process,details::e_sf##Op); \ + + register_sf3_extid("(t-t)-t",23) // (t-t)-t --> t-(t+t) + #undef register_sf3_extid } inline void load_sf4_map(sf4_map_t& sf4_map) @@ -33849,48 +35314,123 @@ namespace exprtk lexer::helper::helper_assembly helper_assembly_; - lexer::helper::commutative_inserter commutative_inserter_; - lexer::helper::operator_joiner operator_joiner_2_; - lexer::helper::operator_joiner operator_joiner_3_; - lexer::helper::symbol_replacer symbol_replacer_; - lexer::helper::bracket_checker bracket_checker_; - lexer::helper::numeric_checker numeric_checker_; - lexer::helper::sequence_validator sequence_validator_; + lexer::helper::commutative_inserter commutative_inserter_; + lexer::helper::operator_joiner operator_joiner_2_; + lexer::helper::operator_joiner operator_joiner_3_; + lexer::helper::symbol_replacer symbol_replacer_; + lexer::helper::bracket_checker bracket_checker_; + lexer::helper::numeric_checker numeric_checker_; + lexer::helper::sequence_validator sequence_validator_; + lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; template <typename ParserType> friend void details::disable_type_checking(ParserType& p); }; + namespace details + { + template <typename T> + struct collector_helper + { + typedef exprtk::symbol_table<T> symbol_table_t; + typedef exprtk::expression<T> expression_t; + typedef exprtk::parser<T> parser_t; + typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef typename parser_t::unknown_symbol_resolver usr_t; + + struct resolve_as_vector : public parser_t::unknown_symbol_resolver + { + typedef exprtk::parser<T> parser_t; + + resolve_as_vector() + : usr_t(usr_t::e_usrmode_extended) + {} + + virtual bool process(const std::string& unknown_symbol, + symbol_table_t& symbol_table, + std::string&) + { + static T v[1]; + symbol_table.add_vector(unknown_symbol,v); + return true; + } + }; + + static inline bool collection_pass(const std::string& expression_string, + std::set<std::string>& symbol_set, + const bool collect_variables, + const bool collect_functions, + const bool vector_pass, + symbol_table_t& ext_symbol_table) + { + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + resolve_as_vector vect_resolver; + + expression.register_symbol_table(symbol_table ); + expression.register_symbol_table(ext_symbol_table); + + if (vector_pass) + parser.enable_unknown_symbol_resolver(&vect_resolver); + else + parser.enable_unknown_symbol_resolver(); + + if (collect_variables) + parser.dec().collect_variables() = true; + + if (collect_functions) + parser.dec().collect_functions() = true; + + bool pass_result = false; + + details::disable_type_checking(parser); + + if (parser.compile(expression_string, expression)) + { + pass_result = true; + + std::deque<symbol_t> symb_list; + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_set.insert(symb_list[i].first); + } + } + + return pass_result; + } + }; + } + template <typename Allocator, template <typename, typename> class Sequence> - inline bool collect_variables(const std::string& expr_str, + inline bool collect_variables(const std::string& expression, Sequence<std::string, Allocator>& symbol_list) { typedef double T; - typedef exprtk::symbol_table<T> symbol_table_t; - typedef exprtk::expression<T> expression_t; - typedef exprtk::parser<T> parser_t; - typedef parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef details::collector_helper<T> collect_t; - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; + collect_t::symbol_table_t null_symbol_table; - expression.register_symbol_table(symbol_table); + std::set<std::string> symbol_set; - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_variables() = true; + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, null_symbol_table); - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque<symbol_t> symb_list; - - parser.dec().symbols(symb_list); + std::set<std::string>::iterator itr = symbol_set.begin(); - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -33899,37 +35439,28 @@ namespace exprtk template <typename T, typename Allocator, template <typename, typename> class Sequence> - inline bool collect_variables(const std::string& expr_str, + inline bool collect_variables(const std::string& expression, exprtk::symbol_table<T>& extrnl_symbol_table, Sequence<std::string, Allocator>& symbol_list) { - typedef exprtk::symbol_table<T> symbol_table_t; - typedef exprtk::expression<T> expression_t; - typedef exprtk::parser<T> parser_t; - typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef details::collector_helper<T> collect_t; - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; + std::set<std::string> symbol_set; - expression.register_symbol_table(symbol_table); - expression.register_symbol_table(extrnl_symbol_table); - - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_variables() = true; + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, extrnl_symbol_table); - details::disable_type_checking(parser); - - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque<symbol_t> symb_list; - - parser.dec().symbols(symb_list); + std::set<std::string>::iterator itr = symbol_set.begin(); - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -33937,34 +35468,30 @@ namespace exprtk template <typename Allocator, template <typename, typename> class Sequence> - inline bool collect_functions(const std::string& expr_str, + inline bool collect_functions(const std::string& expression, Sequence<std::string, Allocator>& symbol_list) { typedef double T; - typedef exprtk::symbol_table<T> symbol_table_t; - typedef exprtk::expression<T> expression_t; - typedef exprtk::parser<T> parser_t; - typedef parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef details::collector_helper<T> collect_t; - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; + collect_t::symbol_table_t null_symbol_table; - expression.register_symbol_table(symbol_table); + std::set<std::string> symbol_set; - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_functions() = true; + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, null_symbol_table); - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque<symbol_t> symb_list; - - parser.dec().symbols(symb_list); + std::set<std::string>::iterator itr = symbol_set.begin(); - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -33973,37 +35500,28 @@ namespace exprtk template <typename T, typename Allocator, template <typename, typename> class Sequence> - inline bool collect_functions(const std::string& expr_str, + inline bool collect_functions(const std::string& expression, exprtk::symbol_table<T>& extrnl_symbol_table, Sequence<std::string, Allocator>& symbol_list) { - typedef exprtk::symbol_table<T> symbol_table_t; - typedef exprtk::expression<T> expression_t; - typedef exprtk::parser<T> parser_t; - typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; - - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; - - expression.register_symbol_table(symbol_table); - expression.register_symbol_table(extrnl_symbol_table); + typedef details::collector_helper<T> collect_t; - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_functions() = true; + std::set<std::string> symbol_set; - details::disable_type_checking(parser); + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, extrnl_symbol_table); - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque<symbol_t> symb_list; - - parser.dec().symbols(symb_list); + std::set<std::string>::iterator itr = symbol_set.begin(); - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -34018,15 +35536,15 @@ namespace exprtk if (r0 > r1) return T(0); - T h = (r1 - r0) / (T(2) * number_of_intervals); + const T h = (r1 - r0) / (T(2) * number_of_intervals); T total_area = T(0); for (std::size_t i = 0; i < number_of_intervals; ++i) { x = r0 + T(2) * i * h; - T y0 = e.value(); x += h; - T y1 = e.value(); x += h; - T y2 = e.value(); x += h; + const T y0 = e.value(); x += h; + const T y1 = e.value(); x += h; + const T y2 = e.value(); x += h; total_area += h * (y0 + T(4) * y1 + y2) / T(3); } @@ -34050,7 +35568,7 @@ namespace exprtk { T& x = var->ref(); T x_original = x; - T result = integrate(e,x,r0,r1,number_of_intervals); + T result = integrate(e, x, r0, r1, number_of_intervals); x = x_original; return result; @@ -34068,13 +35586,13 @@ namespace exprtk const T _2h = T(2) * h; x = x_init + _2h; - T y0 = e.value(); + const T y0 = e.value(); x = x_init + h; - T y1 = e.value(); + const T y1 = e.value(); x = x_init - h; - T y2 = e.value(); + const T y2 = e.value(); x = x_init - _2h; - T y3 = e.value(); + const T y3 = e.value(); x = x_init; return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); @@ -34088,15 +35606,15 @@ namespace exprtk const T x_init = x; const T _2h = T(2) * h; - T y = e.value(); + const T y = e.value(); x = x_init + _2h; - T y0 = e.value(); + const T y0 = e.value(); x = x_init + h; - T y1 = e.value(); + const T y1 = e.value(); x = x_init - h; - T y2 = e.value(); + const T y2 = e.value(); x = x_init - _2h; - T y3 = e.value(); + const T y3 = e.value(); x = x_init; return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); @@ -34111,13 +35629,13 @@ namespace exprtk const T _2h = T(2) * h; x = x_init + _2h; - T y0 = e.value(); + const T y0 = e.value(); x = x_init + h; - T y1 = e.value(); + const T y1 = e.value(); x = x_init - h; - T y2 = e.value(); + const T y2 = e.value(); x = x_init - _2h; - T y3 = e.value(); + const T y3 = e.value(); x = x_init; return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); @@ -34141,7 +35659,7 @@ namespace exprtk { T& x = var->ref(); T x_original = x; - T result = derivative(e,x,h); + T result = derivative(e, x, h); x = x_original; return result; @@ -34167,8 +35685,8 @@ namespace exprtk if (var) { T& x = var->ref(); - T x_original = x; - T result = second_derivative(e,x,h); + const T x_original = x; + const T result = second_derivative(e, x, h); x = x_original; return result; @@ -34194,8 +35712,8 @@ namespace exprtk if (var) { T& x = var->ref(); - T x_original = x; - T result = third_derivative(e,x,h); + const T x_original = x; + const T result = third_derivative(e, x, h); x = x_original; return result; @@ -34486,79 +36004,79 @@ namespace exprtk #define poly_rtrn(NN) \ return (NN != N) ? std::numeric_limits<T>::quiet_NaN() : - inline virtual T operator()(const T& x, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c1, const T& c0) { poly_rtrn(1) poly_impl<T,1>::evaluate(x,c1,c0); } - inline virtual T operator()(const T& x, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) { poly_rtrn(2) poly_impl<T,2>::evaluate(x,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(3) poly_impl<T,3>::evaluate(x,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(4) poly_impl<T,4>::evaluate(x,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(5) poly_impl<T,5>::evaluate(x,c5,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(6) poly_impl<T,6>::evaluate(x,c6,c5,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(7) poly_impl<T,7>::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(8) poly_impl<T,8>::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(9) poly_impl<T,9>::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(10) poly_impl<T,10>::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(11) poly_impl<T,11>::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } - inline virtual T operator()(const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { poly_rtrn(12) poly_impl<T,12>::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } #undef poly_rtrn - inline virtual T operator()() + inline virtual T operator() () { return std::numeric_limits<T>::quiet_NaN(); } - inline virtual T operator()(const T&) + inline virtual T operator() (const T&) { return std::numeric_limits<T>::quiet_NaN(); } - inline virtual T operator()(const T&, const T&) + inline virtual T operator() (const T&, const T&) { return std::numeric_limits<T>::quiet_NaN(); } @@ -34824,6 +36342,7 @@ namespace exprtk void copy(const lvr_vec_t& src_v, var_t& dest_v) { typename var_t::iterator itr = dest_v.begin(); + typedef typename std::iterator_traits<typename var_t::iterator>::difference_type diff_t; for (std::size_t i = 0; i < src_v.size(); ++i) { @@ -34833,8 +36352,8 @@ namespace exprtk *itr++ = (*vr.first); else { - std::copy(vr.first,vr.first + vr.second,itr); - itr += vr.second; + std::copy(vr.first, vr.first + vr.second, itr); + itr += static_cast<diff_t>(vr.second); } } } @@ -34842,6 +36361,7 @@ namespace exprtk void copy(const var_t& src_v, lvr_vec_t& dest_v) { typename var_t::const_iterator itr = src_v.begin(); + typedef typename std::iterator_traits<typename var_t::iterator>::difference_type diff_t; for (std::size_t i = 0; i < src_v.size(); ++i) { @@ -34851,8 +36371,8 @@ namespace exprtk (*vr.first) = *itr++; else { - std::copy(itr,itr + vr.second,vr.first); - itr += vr.second; + std::copy(itr, itr + static_cast<diff_t>(vr.second), vr.first); + itr += static_cast<diff_t>(vr.second); } } } @@ -34887,7 +36407,7 @@ namespace exprtk func_0param() : base_func(0) {} - inline T operator()() + inline T operator() () { return this->value(base_func::expression); } @@ -34915,13 +36435,11 @@ namespace exprtk func_1param() : base_func(1) {} - inline T operator()(type v0) + inline T operator() (type v0) { scoped_bft<func_1param> sb(*this); base_func::update(v0); - T result = this->value(base_func::expression); - - return result; + return this->value(base_func::expression); } }; @@ -34931,13 +36449,11 @@ namespace exprtk func_2param() : base_func(2) {} - inline T operator()(type v0, type v1) + inline T operator() (type v0, type v1) { scoped_bft<func_2param> sb(*this); - base_func::update(v0,v1); - T result = this->value(base_func::expression); - - return result; + base_func::update(v0, v1); + return this->value(base_func::expression); } }; @@ -34947,13 +36463,11 @@ namespace exprtk func_3param() : base_func(3) {} - inline T operator()(type v0, type v1, type v2) + inline T operator() (type v0, type v1, type v2) { scoped_bft<func_3param> sb(*this); - base_func::update(v0,v1,v2); - T result = this->value(base_func::expression); - - return result; + base_func::update(v0, v1, v2); + return this->value(base_func::expression); } }; @@ -34963,13 +36477,11 @@ namespace exprtk func_4param() : base_func(4) {} - inline T operator()(type v0, type v1, type v2, type v3) + inline T operator() (type v0, type v1, type v2, type v3) { scoped_bft<func_4param> sb(*this); - base_func::update(v0,v1,v2,v3); - T result = this->value(base_func::expression); - - return result; + base_func::update(v0, v1, v2, v3); + return this->value(base_func::expression); } }; @@ -34979,13 +36491,11 @@ namespace exprtk func_5param() : base_func(5) {} - inline T operator()(type v0, type v1, type v2, type v3, type v4) + inline T operator() (type v0, type v1, type v2, type v3, type v4) { scoped_bft<func_5param> sb(*this); - base_func::update(v0,v1,v2,v3,v4); - T result = this->value(base_func::expression); - - return result; + base_func::update(v0, v1, v2, v3, v4); + return this->value(base_func::expression); } }; @@ -34995,13 +36505,11 @@ namespace exprtk func_6param() : base_func(6) {} - inline T operator()(type v0, type v1, type v2, type v3, type v4, type v5) + inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) { scoped_bft<func_6param> sb(*this); - base_func::update(v0,v1,v2,v3,v4,v5); - T result = this->value(base_func::expression); - - return result; + base_func::update(v0, v1, v2, v3, v4, v5); + return this->value(base_func::expression); } }; @@ -35042,15 +36550,13 @@ namespace exprtk def_fp_retval(6) template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> inline bool add(const std::string& name, const std::string& expression, const Sequence<std::string,Allocator>& var_list, const bool override = false) { - const std::size_t n = var_list.size(); - - typename std::map<std::string,expression_t>::iterator itr = expr_map_.find(name); + const typename std::map<std::string,expression_t>::iterator itr = expr_map_.find(name); if (expr_map_.end() != itr) { @@ -35067,6 +36573,8 @@ namespace exprtk if (compile_expression(name,expression,var_list)) { + const std::size_t n = var_list.size(); + fp_map_[n][name]->setup(expr_map_[name]); return true; @@ -35132,13 +36640,13 @@ namespace exprtk inline bool add(const function& f, const bool override = false) { - return add(f.name_,f.expression_,f.v_,override); + return add(f.name_, f.expression_, f.v_,override); } private: template <typename Allocator, - template <typename,typename> class Sequence> + template <typename, typename> class Sequence> bool compile_expression(const std::string& name, const std::string& expression, const Sequence<std::string,Allocator>& input_var_list, @@ -35195,7 +36703,7 @@ namespace exprtk { remove(name,input_var_list.size()); - return compile_expression(name,expression,input_var_list,true); + return compile_expression(name, expression, input_var_list, true); } // Make sure every return point has a scalar as its first parameter @@ -35290,14 +36798,14 @@ namespace exprtk if (arg_count > 6) return; - typename std::map<std::string,expression_t>::iterator em_itr = expr_map_.find(name); + const typename std::map<std::string,expression_t>::iterator em_itr = expr_map_.find(name); if (expr_map_.end() != em_itr) { expr_map_.erase(em_itr); } - typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); + const typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); if (fp_map_[arg_count].end() != fp_itr) { @@ -35320,89 +36828,90 @@ namespace exprtk template <typename T> inline bool pgo_primer() { - static const std::string expression_list[] - = { - "(y + x)", - "2 * (y + x)", - "(2 * y + 2 * x)", - "(y + x / y) * (x - y / x)", - "x / ((x + y) * (x - y)) / y", - "1 - ((x * y) + (y / x)) - 3", - "sin(2 * x) + cos(pi / y)", - "1 - sin(2 * x) + cos(pi / y)", - "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", - "(x^2 / sin(2 * pi / y)) -x / 2", - "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", - "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", - "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", - "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", - "(yy + xx)", - "2 * (yy + xx)", - "(2 * yy + 2 * xx)", - "(yy + xx / yy) * (xx - yy / xx)", - "xx / ((xx + yy) * (xx - yy)) / yy", - "1 - ((xx * yy) + (yy / xx)) - 3", - "sin(2 * xx) + cos(pi / yy)", - "1 - sin(2 * xx) + cos(pi / yy)", - "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", - "(xx^2 / sin(2 * pi / yy)) -xx / 2", - "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", - "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", - "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", - "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", - "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", - "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", - "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", - "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", - "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", - "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", - "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", - "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", - "2 + (x * (y / 3))", "x + (2 * (3 / y))", - "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", - "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", - "x + ((2 * 3) / y)", "(((x + y) * z) / w)", - "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", - "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", - "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", - "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", - "((x + (2 * 3)) / y)", - "(xx + yy) * zz", "xx + (yy * zz)", - "(xx + yy) * 7", "xx + (yy * 7)", - "(xx + 7) * yy", "xx + (7 * yy)", - "(7 + xx) * yy", "7 + (xx * yy)", - "(2 + x) * 3", "2 + (x * 3)", - "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", - "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", - "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", - "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", - "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", - "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", - "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", - "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", - "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", - "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", - "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", - "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", - "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", - "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", - "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", - "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", - "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", - "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", - "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", - "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", - "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", - "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", - "((xx + (2 * 3)) / yy)" - }; + static const std::string expression_list[] = + { + "(y + x)", + "2 * (y + x)", + "(2 * y + 2 * x)", + "(y + x / y) * (x - y / x)", + "x / ((x + y) * (x - y)) / y", + "1 - ((x * y) + (y / x)) - 3", + "sin(2 * x) + cos(pi / y)", + "1 - sin(2 * x) + cos(pi / y)", + "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", + "(x^2 / sin(2 * pi / y)) -x / 2", + "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", + "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", + "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", + "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", + "(yy + xx)", + "2 * (yy + xx)", + "(2 * yy + 2 * xx)", + "(yy + xx / yy) * (xx - yy / xx)", + "xx / ((xx + yy) * (xx - yy)) / yy", + "1 - ((xx * yy) + (yy / xx)) - 3", + "sin(2 * xx) + cos(pi / yy)", + "1 - sin(2 * xx) + cos(pi / yy)", + "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", + "(xx^2 / sin(2 * pi / yy)) -xx / 2", + "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", + "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", + "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", + "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", + "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", + "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", + "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", + "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", + "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", + "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", + "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", + "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", + "2 + (x * (y / 3))", "x + (2 * (3 / y))", + "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", + "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", + "x + ((2 * 3) / y)", "(((x + y) * z) / w)", + "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", + "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", + "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", + "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", + "((x + (2 * 3)) / y)", + "(xx + yy) * zz", "xx + (yy * zz)", + "(xx + yy) * 7", "xx + (yy * 7)", + "(xx + 7) * yy", "xx + (7 * yy)", + "(7 + xx) * yy", "7 + (xx * yy)", + "(2 + x) * 3", "2 + (x * 3)", + "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", + "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", + "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", + "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", + "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", + "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", + "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", + "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", + "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", + "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", + "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", + "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", + "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", + "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", + "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", + "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", + "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", + "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", + "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", + "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", + "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", + "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", + "((xx + (2 * 3)) / yy)" + }; + static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); T x = T(0); @@ -35457,8 +36966,8 @@ namespace exprtk { static const T lower_bound = T(-20); static const T upper_bound = T(+20); + static const T delta = T(0.1); - T delta = T(0.1); T total = T(0); for (x = lower_bound; x <= upper_bound; x += delta) @@ -35482,7 +36991,7 @@ namespace exprtk { for (std::size_t i = 0; i < 10000; ++i) { - T v = T(123.456 + i); + const T v = T(123.456 + i); if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 1>::result(v),details::numeric::pow(v,T( 1))))) return false; @@ -35587,8 +37096,8 @@ namespace exprtk { if (stop_time_.tv_sec >= start_time_.tv_sec) { - return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) + - (stop_time_.tv_usec - start_time_.tv_usec); + return 1000000LLU * static_cast<unsigned long long int>(stop_time_.tv_sec - start_time_.tv_sec ) + + static_cast<unsigned long long int>(stop_time_.tv_usec - start_time_.tv_usec) ; } else return std::numeric_limits<unsigned long long int>::max(); @@ -35707,7 +37216,7 @@ namespace exprtk exprtk::enable_zero_parameters(*this); } - inline T operator()(parameter_list_t parameters) + inline T operator() (parameter_list_t parameters) { details::print_impl<T>::process(scalar_format_,parameters); return T(0); @@ -35729,7 +37238,7 @@ namespace exprtk exprtk::enable_zero_parameters(*this); } - inline T operator()(parameter_list_t parameters) + inline T operator() (parameter_list_t parameters) { details::print_impl<T>::process(scalar_format_,parameters); printf("\n"); @@ -35756,8 +37265,8 @@ namespace exprtk return false; \ } \ - exprtk_register_function("print" , p) - exprtk_register_function("println" ,pl) + exprtk_register_function("print" , p) + exprtk_register_function("println", pl) #undef exprtk_register_function return true; @@ -35925,7 +37434,7 @@ namespace exprtk } } - bool eof() + bool eof() const { switch (mode) { @@ -35936,7 +37445,7 @@ namespace exprtk } } - file_mode get_file_mode(const std::string& access) + file_mode get_file_mode(const std::string& access) const { if (access.empty() || access.size() > 2) return e_error; @@ -35946,11 +37455,7 @@ namespace exprtk for (std::size_t i = 0; i < access.size(); ++i) { - #ifdef MODIFICATION - switch (access[i]) - #else switch (std::tolower(access[i])) - #endif { case 'r' : r_cnt++; break; case 'w' : w_cnt++; break; @@ -35997,6 +37502,7 @@ namespace exprtk #pragma warning(pop) #endif } + } // namespace exprtk::rtl::io::file::details template <typename T> @@ -36015,13 +37521,11 @@ namespace exprtk : exprtk::igeneric_function<T>("S|SS") { details::perform_check<T>(); } - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - std::string file_name; + std::string file_name = to_str(string_t(parameters[0])); std::string access; - file_name = to_str(string_t(parameters[0])); - if (file_name.empty()) return T(0); @@ -36038,7 +37542,7 @@ namespace exprtk { T t = T(0); - std::memcpy(reinterpret_cast<char*>(&t), + std::memcpy(reinterpret_cast<char*>(&t ), reinterpret_cast<char*>(&fd), sizeof(fd)); return t; @@ -36060,7 +37564,7 @@ namespace exprtk : exprtk::ifunction<T>(1) { details::perform_check<T>(); } - inline T operator()(const T& v) + inline T operator() (const T& v) { details::file_descriptor* fd = details::make_handle(v); @@ -36091,7 +37595,7 @@ namespace exprtk : igfun_t("TS|TST|TV|TVT") { details::perform_check<T>(); } - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); @@ -36100,29 +37604,29 @@ namespace exprtk switch (ps_index) { case 0 : { - string_t buffer(parameters[1]); + const string_t buffer(parameters[1]); amount = buffer.size(); - return T(fd->write(buffer,amount) ? 1 : 0); + return T(fd->write(buffer, amount) ? 1 : 0); } case 1 : { - string_t buffer(parameters[1]); + const string_t buffer(parameters[1]); amount = std::min(buffer.size(), static_cast<std::size_t>(scalar_t(parameters[2])())); - return T(fd->write(buffer,amount) ? 1 : 0); + return T(fd->write(buffer, amount) ? 1 : 0); } case 2 : { - vector_t vec(parameters[1]); + const vector_t vec(parameters[1]); amount = vec.size(); - return T(fd->write(vec,amount) ? 1 : 0); + return T(fd->write(vec, amount) ? 1 : 0); } case 3 : { - vector_t vec(parameters[1]); + const vector_t vec(parameters[1]); amount = std::min(vec.size(), static_cast<std::size_t>(scalar_t(parameters[2])())); - return T(fd->write(vec,amount) ? 1 : 0); + return T(fd->write(vec, amount) ? 1 : 0); } } @@ -36148,7 +37652,7 @@ namespace exprtk : igfun_t("TS|TST|TV|TVT") { details::perform_check<T>(); } - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); @@ -36204,8 +37708,8 @@ namespace exprtk : igfun_t("T",igfun_t::e_rtrn_string) { details::perform_check<T>(); } - inline T operator()(std::string& result, - parameter_list_t parameters) + inline T operator() (std::string& result, + parameter_list_t parameters) { details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); return T(fd->getline(result) ? 1 : 0); @@ -36221,7 +37725,7 @@ namespace exprtk : exprtk::ifunction<T>(1) { details::perform_check<T>(); } - inline T operator()(const T& v) + inline T operator() (const T& v) { details::file_descriptor* fd = details::make_handle(v); @@ -36315,7 +37819,7 @@ namespace exprtk if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) return false; - return !invalid_range(vector_t(parameters[vec_idx]),r0,r1); + return !invalid_range(vector_t(parameters[vec_idx]), r0, r1); } }; } @@ -36323,10 +37827,10 @@ namespace exprtk namespace details { template <typename T> - inline void kahan_sum(T& sum, T& error, T v) + inline void kahan_sum(T& sum, T& error, const T v) { - T x = v - error; - T y = sum + x; + const T x = v - error; + const T y = sum + x; error = (y - sum) - x; sum = y; } @@ -36354,14 +37858,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - const vector_t& vec(parameters[0]); + const vector_t vec(parameters[0]); std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) return std::numeric_limits<T>::quiet_NaN(); for (std::size_t i = r0; i <= r1; ++i) @@ -36397,14 +37904,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - const vector_t& vec(parameters[0]); + const vector_t vec(parameters[0]); std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) return std::numeric_limits<T>::quiet_NaN(); for (std::size_t i = r0; i <= r1; ++i) @@ -36440,14 +37950,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - const vector_t& vec(parameters[0]); + const vector_t vec(parameters[0]); std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) return std::numeric_limits<T>::quiet_NaN(); for (std::size_t i = r0; i <= r1; ++i) @@ -36483,14 +37996,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - const vector_t& vec(parameters[0]); + const vector_t vec(parameters[0]); std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) return std::numeric_limits<T>::quiet_NaN(); for (std::size_t i = r0; i <= r1; ++i) @@ -36526,14 +38042,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - const vector_t& vec(parameters[0]); + const vector_t vec(parameters[0]); std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0) + ) return std::numeric_limits<T>::quiet_NaN(); std::size_t cnt = 0; @@ -36569,10 +38088,10 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[0]); - vector_t y(parameters[(0 == ps_index) ? 1 : 3]); + const vector_t x(parameters[0]); + vector_t y(parameters[(0 == ps_index) ? 1 : 3]); std::size_t xr0 = 0; std::size_t xr1 = x.size() - 1; @@ -36580,10 +38099,14 @@ namespace exprtk std::size_t yr0 = 0; std::size_t yr1 = y.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,xr0,xr1,1,2,0)) - return T(0); - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,yr0,yr1,4,5,3)) - return T(0); + if (1 == ps_index) + { + if ( + !helper::load_vector_range<T>::process(parameters, xr0, xr1, 1, 2, 0) || + !helper::load_vector_range<T>::process(parameters, yr0, yr1, 4, 5, 3) + ) + return T(0); + } const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); @@ -36615,7 +38138,7 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { vector_t vec(parameters[0]); @@ -36626,7 +38149,10 @@ namespace exprtk if (!scalar_t(parameters[1]).to_uint(n)) return T(0); - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0) + ) return T(0); std::size_t dist = r1 - r0 + 1; @@ -36660,7 +38186,7 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { vector_t vec(parameters[0]); @@ -36671,7 +38197,10 @@ namespace exprtk if (!scalar_t(parameters[1]).to_uint(n)) return T(0); - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0) + ) return T(0); std::size_t dist = r1 - r0 + 1; @@ -36705,7 +38234,7 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { vector_t vec(parameters[0]); @@ -36716,7 +38245,10 @@ namespace exprtk if (!scalar_t(parameters[1]).to_uint(n)) return T(0); - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0) + ) return T(0); std::size_t dist = r1 - r0 + 1; @@ -36757,7 +38289,7 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { vector_t vec(parameters[0]); @@ -36768,7 +38300,10 @@ namespace exprtk if (!scalar_t(parameters[1]).to_uint(n)) return T(0); - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ( + (1 == ps_index) && + !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0) + ) return T(0); std::size_t dist = r1 - r0 + 1; @@ -36813,16 +38348,16 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { vector_t vec(parameters[0]); std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0)) return T(0); - if ((3 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ((3 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0)) return T(0); bool ascending = true; @@ -36868,7 +38403,7 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { vector_t vec(parameters[0]); @@ -36879,7 +38414,7 @@ namespace exprtk if (!scalar_t(parameters[1]).to_uint(n)) return T(0); - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0)) return std::numeric_limits<T>::quiet_NaN(); std::nth_element(vec.begin() + r0, vec.begin() + r0 + n , vec.begin() + r1 + 1); @@ -36912,7 +38447,7 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { vector_t vec(parameters[0]); @@ -36922,9 +38457,9 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((2 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ((2 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0)) return std::numeric_limits<T>::quiet_NaN(); - else if ((3 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,3,4,0)) + else if ((3 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 3, 4, 0)) return std::numeric_limits<T>::quiet_NaN(); else { @@ -36961,14 +38496,14 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t vec(parameters[0]); + const vector_t vec(parameters[0]); std::size_t r0 = 0; std::size_t r1 = vec.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,1,2,0)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 1, 2, 0)) return std::numeric_limits<T>::quiet_NaN(); T result = T(0); @@ -36976,7 +38511,7 @@ namespace exprtk for (std::size_t i = r0; i <= r1; ++i) { - details::kahan_sum(result,error,vec[i]); + details::kahan_sum(result, error, vec[i]); } return result; @@ -37006,24 +38541,24 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[1]); - vector_t y(parameters[2]); + const vector_t x(parameters[1]); + vector_t y(parameters[2]); std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,3,4,1)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 3, 4, 1)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); - T a = scalar_t(parameters[0])(); + const T a = scalar_t(parameters[0])(); for (std::size_t i = r0; i <= r1; ++i) { - y[i] = a * x[i] + y[i]; + y[i] = (a * x[i]) + y[i]; } return T(1); @@ -37053,17 +38588,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[1]); - vector_t y(parameters[3]); + const vector_t x(parameters[1]); + vector_t y(parameters[3]); std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,4,5,1)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); const T a = scalar_t(parameters[0])(); @@ -37101,27 +38636,27 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[1]); - vector_t y(parameters[2]); - vector_t z(parameters[3]); + const vector_t x(parameters[1]); + const vector_t y(parameters[2]); + vector_t z(parameters[3]); std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,3,4,1)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 3, 4, 1)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) + else if (helper::invalid_range(z, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); - T a = scalar_t(parameters[0])(); + const T a = scalar_t(parameters[0])(); for (std::size_t i = r0; i <= r1; ++i) { - z[i] = a * x[i] + y[i]; + z[i] = (a * x[i]) + y[i]; } return T(1); @@ -37151,20 +38686,20 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[1]); - vector_t y(parameters[3]); - vector_t z(parameters[4]); + const vector_t x(parameters[1]); + const vector_t y(parameters[3]); + vector_t z(parameters[4]); std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,4,5,1)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) + else if (helper::invalid_range(z, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); const T a = scalar_t(parameters[0])(); @@ -37202,17 +38737,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[1]); - vector_t z(parameters[3]); + const vector_t x(parameters[1]); + vector_t z(parameters[3]); std::size_t r0 = 0; std::size_t r1 = x.size() - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,4,5,1)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) + else if (helper::invalid_range(z, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); const T a = scalar_t(parameters[0])(); @@ -37220,7 +38755,7 @@ namespace exprtk for (std::size_t i = r0; i <= r1; ++i) { - z[i] = a * x[i] + b; + z[i] = (a * x[i]) + b; } return T(1); @@ -37249,17 +38784,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[0]); - vector_t y(parameters[1]); + const vector_t x(parameters[0]); + const vector_t y(parameters[1]); std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); T result = T(0); @@ -37295,17 +38830,17 @@ namespace exprtk */ {} - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - vector_t x(parameters[0]); - vector_t y(parameters[1]); + const vector_t x(parameters[0]); + const vector_t y(parameters[1]); std::size_t r0 = 0; std::size_t r1 = std::min(x.size(),y.size()) - 1; - if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters,r0,r1,2,3,0)) + if ((1 == ps_index) && !helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0)) return std::numeric_limits<T>::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits<T>::quiet_NaN(); T result = T(0); @@ -37313,7 +38848,7 @@ namespace exprtk for (std::size_t i = r0; i <= r1; ++i) { - details::kahan_sum(result,error,(x[i] * y[i])); + details::kahan_sum(result, error, (x[i] * y[i])); } return result; @@ -37361,7 +38896,7 @@ namespace exprtk exprtk_register_function("any_true" ,nt) exprtk_register_function("any_false" ,nf) exprtk_register_function("count" , c) - exprtk_register_function("copy" , cp) + exprtk_register_function("copy" ,cp) exprtk_register_function("rotate_left" ,rl) exprtk_register_function("rol" ,rl) exprtk_register_function("rotate_right" ,rr) @@ -37395,9 +38930,9 @@ namespace exprtk namespace information { static const char* library = "Mathematical Expression Toolkit"; - static const char* version = "2.71828182845904523536028747135266249775724709" - "3699959574966967627724076630353547594571382178"; - static const char* date = "20170404"; + static const char* version = "2.7182818284590452353602874713526624977572470936999595749" + "669676277240766303535475945713821785251664274274663919320"; + static const char* date = "20200101"; static inline std::string data() { @@ -37409,6 +38944,22 @@ namespace exprtk } // namespace information + #ifdef exprtk_debug + #undef exprtk_debug + #endif + + #ifdef exprtk_error_location + #undef exprtk_error_location + #endif + + #ifdef exprtk_disable_fallthrough_begin + #undef exprtk_disable_fallthrough_begin + #endif + + #ifdef exprtk_disable_fallthrough_end + #undef exprtk_disable_fallthrough_end + #endif + } // namespace exprtk #endif diff --git a/src/storm-cli-utilities/cli.cpp b/src/storm-cli-utilities/cli.cpp index c7b18fb7a..df10dcbf1 100644 --- a/src/storm-cli-utilities/cli.cpp +++ b/src/storm-cli-utilities/cli.cpp @@ -242,25 +242,34 @@ namespace storm { // Start by setting some urgent options (log levels, resources, etc.) setUrgentOptions(); - // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.) - SymbolicInput symbolicInput = parseAndPreprocessSymbolicInput(); + // Parse symbolic input (PRISM, JANI, properties, etc.) + SymbolicInput symbolicInput = parseSymbolicInput(); - auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); - if (generalSettings.isParametricSet()) { -#ifdef STORM_HAVE_CARL - processInputWithValueType<storm::RationalFunction>(symbolicInput); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No parameters are supported in this build."); -#endif - } else if (generalSettings.isExactSet()) { + // Obtain settings for model processing + ModelProcessingInformation mpi = getModelProcessingInformation(symbolicInput); + + // Preprocess the symbolic input + symbolicInput = preprocessSymbolicInput(symbolicInput, mpi.engine); + + // Export symbolic input (if requested) + exportSymbolicInput(symbolicInput); + #ifdef STORM_HAVE_CARL - processInputWithValueType<storm::RationalNumber>(symbolicInput); + switch (mpi.verificationValueType) { + case ModelProcessingInformation::ValueType::Parametric: + processInputWithValueType<storm::RationalFunction>(symbolicInput, mpi); + break; + case ModelProcessingInformation::ValueType::Exact: + processInputWithValueType<storm::RationalNumber>(symbolicInput, mpi); + break; + case ModelProcessingInformation::ValueType::FinitePrecision: + processInputWithValueType<double>(symbolicInput, mpi); + break; + } #else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No exact numbers are supported in this build."); + STORM_LOG_THROW(mpi.verificationValueType == ModelProcessingInformation::ValueType::FinitePrecision, storm::exceptions::NotSupportedException, "No exact numbers or parameters are supported in this build."); + processInputWithValueType<double>(symbolicInput, mpi); #endif - } else { - processInputWithValueType<double>(symbolicInput); - } } void printTimeAndMemoryStatistics(uint64_t wallclockMilliseconds) { diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index b35b9f0d3..cd57360ef 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -10,6 +10,8 @@ #include "storm/utility/storm-version.h" #include "storm/utility/macros.h" #include "storm/utility/NumberTraits.h" +#include "storm/utility/Engine.h" +#include "storm/utility/Portfolio.h" #include "storm/utility/initialize.h" #include "storm/utility/Stopwatch.h" @@ -24,6 +26,8 @@ #include "storm/models/ModelBase.h" +#include "storm/environment/Environment.h" + #include "storm/exceptions/OptionParserException.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" @@ -43,6 +47,7 @@ #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/TransformationSettings.h" +#include "storm/settings/modules/HintSettings.h" #include "storm/storage/Qvbs.h" #include "storm/utility/Stopwatch.h" @@ -62,13 +67,12 @@ namespace storm { boost::optional<std::vector<storm::jani::Property>> preprocessedProperties; }; - void parseSymbolicModelDescription(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input, storm::builder::BuilderType const& builderType) { + void parseSymbolicModelDescription(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input) { if (ioSettings.isPrismOrJaniInputSet()) { storm::utility::Stopwatch modelParsingWatch(true); if (ioSettings.isPrismInputSet()) { input.model = storm::api::parseProgram(ioSettings.getPrismInputFilename(), storm::settings::getModule<storm::settings::modules::BuildSettings>().isPrismCompatibilityEnabled()); } else { - storm::jani::ModelFeatures supportedFeatures = storm::api::getSupportedJaniFeatures(builderType); boost::optional<std::vector<std::string>> propertyFilter; if (ioSettings.isJaniPropertiesSet()) { if (ioSettings.areJaniPropertiesSelected()) { @@ -79,7 +83,7 @@ namespace storm { } else { propertyFilter = std::vector<std::string>(); } - auto janiInput = storm::api::parseJaniModel(ioSettings.getJaniInputFilename(), supportedFeatures, propertyFilter); + auto janiInput = storm::api::parseJaniModel(ioSettings.getJaniInputFilename(), propertyFilter); input.model = std::move(janiInput.first); if (ioSettings.isJaniPropertiesSet()) { input.properties = std::move(janiInput.second); @@ -102,20 +106,175 @@ namespace storm { input.properties.insert(input.properties.end(), newProperties.begin(), newProperties.end()); } } - - SymbolicInput parseSymbolicInput(storm::builder::BuilderType const& builderType) { - auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); + + SymbolicInput parseSymbolicInputQvbs(storm::settings::modules::IOSettings const& ioSettings) { + // Parse the model input + SymbolicInput input; + storm::storage::QvbsBenchmark benchmark(ioSettings.getQvbsModelName()); + STORM_PRINT_AND_LOG(benchmark.getInfo(ioSettings.getQvbsInstanceIndex(), ioSettings.getQvbsPropertyFilter())); + storm::utility::Stopwatch modelParsingWatch(true); + auto janiInput = storm::api::parseJaniModel(benchmark.getJaniFile(ioSettings.getQvbsInstanceIndex()), ioSettings.getQvbsPropertyFilter()); + input.model = std::move(janiInput.first); + input.properties = std::move(janiInput.second); + modelParsingWatch.stop(); + STORM_PRINT("Time for model input parsing: " << modelParsingWatch << "." << std::endl << std::endl); - // Parse the property filter, if any is given. + // Parse additional properties boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter()); - - SymbolicInput input; - parseSymbolicModelDescription(ioSettings, input, builderType); parseProperties(ioSettings, input, propertyFilter); + // Substitute constant definitions + auto constantDefinitions = input.model.get().parseConstantDefinitions(benchmark.getConstantDefinition(ioSettings.getQvbsInstanceIndex())); + input.model = input.model.get().preprocess(constantDefinitions); + if (!input.properties.empty()) { + input.properties = storm::api::substituteConstantsInProperties(input.properties, constantDefinitions); + } + return input; } + SymbolicInput parseSymbolicInput() { + auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); + if (ioSettings.isQvbsInputSet()) { + return parseSymbolicInputQvbs(ioSettings); + } else { + // Parse the property filter, if any is given. + boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter()); + + SymbolicInput input; + parseSymbolicModelDescription(ioSettings, input); + parseProperties(ioSettings, input, propertyFilter); + return input; + } + } + + struct ModelProcessingInformation { + + // The engine to use + storm::utility::Engine engine; + + // If set, bisimulation will be applied. + bool applyBisimulation; + + // Which data type is to be used for numbers ... + enum class ValueType { + FinitePrecision, + Exact, + Parametric + }; + ValueType buildValueType; // ... during model building + ValueType verificationValueType; // ... during model verification + + // The Dd library to be used + storm::dd::DdType ddType; + + // The environment used during model checking + storm::Environment env; + }; + + void getModelProcessingInformationPortfolio(SymbolicInput const& input, ModelProcessingInformation& mpi) { + auto hints = storm::settings::getModule<storm::settings::modules::HintSettings>(); + + STORM_LOG_THROW(input.model.is_initialized(), storm::exceptions::InvalidArgumentException, "Portfolio engine requires a symbolic model (PRISM or JANI."); + std::vector<storm::jani::Property> const& properties = input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties; + STORM_LOG_THROW(!properties.empty(), storm::exceptions::InvalidArgumentException, "Portfolio engine requires a property."); + STORM_LOG_WARN_COND(properties.size() == 1, "Portfolio engine does not support decisions based on multiple properties. Only the first property will be considered."); + + storm::utility::Portfolio pf; + if (hints.isNumberStatesSet()) { + pf.predict(input.model.get(), properties.front(), hints.getNumberStates()); + } else { + pf.predict(input.model.get(), properties.front()); + } + + mpi.engine = pf.getEngine(); + if (pf.enableBisimulation()) { + mpi.applyBisimulation = true; + } + if (pf.enableExact() && mpi.verificationValueType == ModelProcessingInformation::ValueType::FinitePrecision) { + mpi.verificationValueType = ModelProcessingInformation::ValueType::Exact; + } + STORM_PRINT_AND_LOG( "Portfolio engine picked the following settings: " << std::endl << "\tengine=" << mpi.engine << "\t bisimulation=" << mpi.applyBisimulation << "\t exact=" << (mpi.verificationValueType != ModelProcessingInformation::ValueType::FinitePrecision) << std::endl) + } + + ModelProcessingInformation getModelProcessingInformation(SymbolicInput const& input) { + ModelProcessingInformation mpi; + auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); + auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); + auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); + + // Set the engine. + mpi.engine = coreSettings.getEngine(); + + // Set whether bisimulation is to be used. + mpi.applyBisimulation = generalSettings.isBisimulationSet(); + + // Set the value type used for numeric values + if (generalSettings.isParametricSet()) { + mpi.verificationValueType = ModelProcessingInformation::ValueType::Parametric; + } else if (generalSettings.isExactSet()) { + mpi.verificationValueType = ModelProcessingInformation::ValueType::Exact; + } else { + mpi.verificationValueType = ModelProcessingInformation::ValueType::FinitePrecision; + } + + // Since the remaining settings could depend on the ones above, we need apply the portfolio engine now. + bool usePortfolio = mpi.engine == storm::utility::Engine::Portfolio; + if (usePortfolio) { + // This can potentially overwrite the settings above, but will not overwrite settings that were explicitly set by the user (e.g. we will not disable bisimulation or disable exact arithmetic) + getModelProcessingInformationPortfolio(input, mpi); + } + + // Check whether these settings are compatible with the provided input. + bool incompatibleSettings = false; + if (input.model) { + switch (mpi.verificationValueType) { + case ModelProcessingInformation::ValueType::Parametric: + incompatibleSettings = !storm::utility::canHandle<storm::RationalFunction>(mpi.engine, input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties, input.model.get()); + break; + case ModelProcessingInformation::ValueType::Exact: + incompatibleSettings = !storm::utility::canHandle<storm::RationalNumber>(mpi.engine, input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties, input.model.get()); + break; + case ModelProcessingInformation::ValueType::FinitePrecision: + incompatibleSettings = !storm::utility::canHandle<double>(mpi.engine, input.preprocessedProperties.is_initialized() ? input.preprocessedProperties.get() : input.properties, input.model.get()); + break; + } + } + if (incompatibleSettings) { + if (usePortfolio) { + STORM_LOG_WARN("The settings picked by the portfolio engine (engine=" << mpi.engine << ", bisim=" << mpi.applyBisimulation << ", exact=" << (mpi.verificationValueType != ModelProcessingInformation::ValueType::FinitePrecision) << ") are incompatible with this model. Falling back to sparse engine without bisimulation and floating point arithmetic."); + mpi.engine = storm::utility::Engine::Sparse; + mpi.applyBisimulation = false; + mpi.verificationValueType = ModelProcessingInformation::ValueType::FinitePrecision; + } else { + STORM_LOG_WARN("The model checking query does not seem to be supported for the selected engine. Storm will try to solve the query, but you will most likely get an error for at least one of the provided properties."); + } + } + + + // Set the Valuetype used during model building + mpi.buildValueType = mpi.verificationValueType; + if (bisimulationSettings.useExactArithmeticInDdBisimulation()) { + if (storm::utility::getBuilderType(mpi.engine) == storm::builder::BuilderType::Dd && mpi.applyBisimulation) { + if (mpi.buildValueType == ModelProcessingInformation::ValueType::FinitePrecision) { + mpi.buildValueType = ModelProcessingInformation::ValueType::Exact; + } + } else { + STORM_LOG_WARN("Requested using exact arithmetic in Dd bisimulation but no dd bisimulation is applied."); + } + } + + // Set the Dd library + mpi.ddType = coreSettings.getDdLibraryType(); + if (mpi.ddType == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue()) { + if (!(mpi.buildValueType == ModelProcessingInformation::ValueType::FinitePrecision && mpi.verificationValueType == ModelProcessingInformation::ValueType::FinitePrecision)) { + STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); + mpi.ddType = storm::dd::DdType::Sylvan; + } + } + return mpi; + } + void ensureNoUndefinedPropertyConstants(std::vector<storm::jani::Property> const& properties) { // Make sure there are no undefined constants remaining in any property. for (auto const& property : properties) { @@ -130,11 +289,17 @@ namespace storm { } } - SymbolicInput preprocessSymbolicInput(SymbolicInput const& input, storm::builder::BuilderType const& builderType) { + SymbolicInput preprocessSymbolicInput(SymbolicInput const& input, storm::utility::Engine const& engine) { auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); + auto builderType = storm::utility::getBuilderType(engine); SymbolicInput output = input; + if (output.model && output.model.get().isJaniModel()) { + storm::jani::ModelFeatures supportedFeatures = storm::api::getSupportedJaniFeatures(builderType); + storm::api::simplifyJaniModel(output.model.get().asJaniModel(), output.properties, supportedFeatures); + } + // Substitute constant definitions in symbolic input. std::string constantDefinitionString = ioSettings.getConstantDefinitionString(); std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions; @@ -185,63 +350,12 @@ namespace storm { } } - storm::builder::BuilderType getBuilderType(storm::settings::modules::CoreSettings::Engine const& engine, bool useJit) { - if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::DdSparse || engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) { - return storm::builder::BuilderType::Dd; - } else if (engine == storm::settings::modules::CoreSettings::Engine::Sparse) { - if (useJit) { - return storm::builder::BuilderType::Jit; - } else { - return storm::builder::BuilderType::Explicit; - } - } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { - return storm::builder::BuilderType::Explicit; - } - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to determine the model builder type."); - } - - SymbolicInput parseAndPreprocessSymbolicInputQvbs(storm::settings::modules::IOSettings const& ioSettings, storm::builder::BuilderType const& builderType) { - // Parse the model input - SymbolicInput input; - storm::storage::QvbsBenchmark benchmark(ioSettings.getQvbsModelName()); - STORM_PRINT_AND_LOG(benchmark.getInfo(ioSettings.getQvbsInstanceIndex(), ioSettings.getQvbsPropertyFilter())); - storm::utility::Stopwatch modelParsingWatch(true); - storm::jani::ModelFeatures supportedFeatures = storm::api::getSupportedJaniFeatures(builderType); - auto janiInput = storm::api::parseJaniModel(benchmark.getJaniFile(ioSettings.getQvbsInstanceIndex()), supportedFeatures, ioSettings.getQvbsPropertyFilter()); - input.model = std::move(janiInput.first); - input.properties = std::move(janiInput.second); - modelParsingWatch.stop(); - STORM_PRINT("Time for model input parsing: " << modelParsingWatch << "." << std::endl << std::endl); - - // Parse additional properties - boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter()); - parseProperties(ioSettings, input, propertyFilter); - - // Substitute constant definitions - auto constantDefinitions = input.model.get().parseConstantDefinitions(benchmark.getConstantDefinition(ioSettings.getQvbsInstanceIndex())); - input.model = input.model.get().preprocess(constantDefinitions); - if (!input.properties.empty()) { - input.properties = storm::api::substituteConstantsInProperties(input.properties, constantDefinitions); - } - - ensureNoUndefinedPropertyConstants(input.properties); - return input; - } - - SymbolicInput parseAndPreprocessSymbolicInput() { + SymbolicInput parseAndPreprocessSymbolicInput(storm::utility::Engine const& engine) { // Get the used builder type to handle cases where preprocessing depends on it auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>(); - auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); - auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); - auto builderType = getBuilderType(coreSettings.getEngine(), buildSettings.isJitSet()); - SymbolicInput input; - if (ioSettings.isQvbsInputSet()) { - input = parseAndPreprocessSymbolicInputQvbs(ioSettings, builderType); - } else { - input = parseSymbolicInput(builderType); - input = preprocessSymbolicInput(input, builderType); - } + SymbolicInput input = parseSymbolicInput(); + input = preprocessSymbolicInput(input, engine); exportSymbolicInput(input); return input; } @@ -265,7 +379,7 @@ namespace storm { } template <typename ValueType> - std::shared_ptr<storm::models::ModelBase> buildModelSparse(SymbolicInput const& input, storm::settings::modules::BuildSettings const& buildSettings) { + std::shared_ptr<storm::models::ModelBase> buildModelSparse(SymbolicInput const& input, storm::settings::modules::BuildSettings const& buildSettings, bool useJit) { storm::builder::BuilderOptions options(createFormulasToRespect(input.properties), input.model.get()); options.setBuildChoiceLabels(buildSettings.isBuildChoiceLabelsSet()); options.setBuildStateValuations(buildSettings.isBuildStateValuationsSet()); @@ -293,7 +407,7 @@ namespace storm { options.setBuildAllLabels(true); options.setBuildAllRewardModels(true); } - return storm::api::buildSparseModel<ValueType>(input.model.get(), options, buildSettings.isJitSet(), storm::settings::getModule<storm::settings::modules::JitBuilderSettings>().isDoctorSet()); + return storm::api::buildSparseModel<ValueType>(input.model.get(), options, useJit, storm::settings::getModule<storm::settings::modules::JitBuilderSettings>().isDoctorSet()); } template <typename ValueType> @@ -313,20 +427,20 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType> - std::shared_ptr<storm::models::ModelBase> buildModel(storm::settings::modules::CoreSettings::Engine const& engine, SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings) { + std::shared_ptr<storm::models::ModelBase> buildModel(SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings, ModelProcessingInformation const& mpi) { storm::utility::Stopwatch modelBuildingWatch(true); auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>(); std::shared_ptr<storm::models::ModelBase> result; if (input.model) { - auto builderType = getBuilderType(engine, buildSettings.isJitSet()); + auto builderType = storm::utility::getBuilderType(mpi.engine); if (builderType == storm::builder::BuilderType::Dd) { result = buildModelDd<DdType, ValueType>(input); } else if (builderType == storm::builder::BuilderType::Explicit || builderType == storm::builder::BuilderType::Jit) { - result = buildModelSparse<ValueType>(input, buildSettings); + result = buildModelSparse<ValueType>(input, buildSettings, builderType == storm::builder::BuilderType::Jit); } } else if (ioSettings.isExplicitSet() || ioSettings.isExplicitDRNSet() || ioSettings.isExplicitIMCASet()) { - STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Can only use sparse engine with explicit input."); + STORM_LOG_THROW(mpi.engine == storm::utility::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Can only use sparse engine with explicit input."); result = buildModelExplicit<ValueType>(ioSettings, buildSettings); } @@ -341,11 +455,12 @@ namespace storm { template <typename ValueType> std::shared_ptr<storm::models::sparse::Model<ValueType>> preprocessSparseMarkovAutomaton(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& model) { auto transformationSettings = storm::settings::getModule<storm::settings::modules::TransformationSettings>(); - + auto debugSettings = storm::settings::getModule<storm::settings::modules::DebugSettings>(); + std::shared_ptr<storm::models::sparse::Model<ValueType>> result = model; model->close(); - STORM_LOG_WARN_COND(!model->containsZenoCycle(), "MA contains a Zeno cycle. Model checking results cannot be trusted."); - + STORM_LOG_WARN_COND(!debugSettings.isAdditionalChecksSet() || !model->containsZenoCycle(), "MA contains a Zeno cycle. Model checking results cannot be trusted."); + if (model->isConvertibleToCtmc()) { STORM_LOG_WARN_COND(false, "MA is convertible to a CTMC, consider using a CTMC instead."); result = model->convertToCtmc(); @@ -371,8 +486,7 @@ namespace storm { } template <typename ValueType> - std::pair<std::shared_ptr<storm::models::sparse::Model<ValueType>>, bool> preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) { - auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); + std::pair<std::shared_ptr<storm::models::sparse::Model<ValueType>>, bool> preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto transformationSettings = storm::settings::getModule<storm::settings::modules::TransformationSettings>(); @@ -384,7 +498,7 @@ namespace storm { result.second = true; } - if (generalSettings.isBisimulationSet()) { + if (mpi.applyBisimulation) { result.first = preprocessSparseModelBisimulation(result.first, input, bisimulationSettings); result.second = true; } @@ -457,17 +571,21 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType> - std::shared_ptr<storm::models::Model<ExportValueType>> preprocessDdModelBisimulation(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) { + std::shared_ptr<storm::models::Model<ExportValueType>> preprocessDdModelBisimulation(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings, ModelProcessingInformation const& mpi) { STORM_LOG_WARN_COND(!bisimulationSettings.isWeakBisimulationSet(), "Weak bisimulation is currently not supported on DDs. Falling back to strong bisimulation."); + auto quotientFormat = bisimulationSettings.getQuotientFormat(); + if (mpi.engine == storm::utility::Engine::DdSparse && quotientFormat != storm::dd::bisimulation::QuotientFormat::Sparse && bisimulationSettings.isQuotientFormatSetFromDefaultValue()) { + STORM_LOG_INFO("Setting bisimulation quotient format to 'sparse'."); + quotientFormat = storm::dd::bisimulation::QuotientFormat::Sparse; + } STORM_LOG_INFO("Performing bisimulation minimization..."); - return storm::api::performBisimulationMinimization<DdType, ValueType, ExportValueType>(model, createFormulasToRespect(input.properties), storm::storage::BisimulationType::Strong, bisimulationSettings.getSignatureMode()); + return storm::api::performBisimulationMinimization<DdType, ValueType, ExportValueType>(model, createFormulasToRespect(input.properties), storm::storage::BisimulationType::Strong, bisimulationSettings.getSignatureMode(), quotientFormat); } template <storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType> - std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input) { + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); - auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); std::pair<std::shared_ptr<storm::models::Model<ValueType>>, bool> intermediateResult = std::make_pair(model, false); if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) { @@ -477,14 +595,14 @@ namespace storm { std::unique_ptr<std::pair<std::shared_ptr<storm::models::Model<ExportValueType>>, bool>> result; auto symbolicModel = intermediateResult.first->template as<storm::models::symbolic::Model<DdType, ValueType>>(); - if (generalSettings.isBisimulationSet()) { - std::shared_ptr<storm::models::Model<ExportValueType>> newModel = preprocessDdModelBisimulation<DdType, ValueType, ExportValueType>(symbolicModel, input, bisimulationSettings); + if (mpi.applyBisimulation) { + std::shared_ptr<storm::models::Model<ExportValueType>> newModel = preprocessDdModelBisimulation<DdType, ValueType, ExportValueType>(symbolicModel, input, bisimulationSettings, mpi); result = std::make_unique<std::pair<std::shared_ptr<storm::models::Model<ExportValueType>>, bool>>(newModel, true); } else { result = std::make_unique<std::pair<std::shared_ptr<storm::models::Model<ExportValueType>>, bool>>(symbolicModel->template toValueType<ExportValueType>(), !std::is_same<ValueType, ExportValueType>::value); } - if (result && result->first->isSymbolicModel() && storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::DdSparse) { + if (result && result->first->isSymbolicModel() && mpi.engine == storm::utility::Engine::DdSparse) { // Mark as changed. result->second = true; @@ -501,15 +619,15 @@ namespace storm { } template <storm::dd::DdType DdType, typename BuildValueType, typename ExportValueType = BuildValueType> - std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { storm::utility::Stopwatch preprocessingWatch(true); std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false); if (model->isSparseModel()) { - result = preprocessSparseModel<BuildValueType>(result.first->as<storm::models::sparse::Model<BuildValueType>>(), input); + result = preprocessSparseModel<BuildValueType>(result.first->as<storm::models::sparse::Model<BuildValueType>>(), input, mpi); } else { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); - result = preprocessDdModel<DdType, BuildValueType, ExportValueType>(result.first->as<storm::models::symbolic::Model<DdType, BuildValueType>>(), input); + result = preprocessDdModel<DdType, BuildValueType, ExportValueType>(result.first->as<storm::models::symbolic::Model<DdType, BuildValueType>>(), input, mpi); } preprocessingWatch.stop(); @@ -791,45 +909,45 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType> - void verifyWithAbstractionRefinementEngine(SymbolicInput const& input) { + void verifyWithAbstractionRefinementEngine(SymbolicInput const& input, ModelProcessingInformation const& mpi) { STORM_LOG_ASSERT(input.model, "Expected symbolic model description."); storm::settings::modules::AbstractionSettings const& abstractionSettings = storm::settings::getModule<storm::settings::modules::AbstractionSettings>(); storm::api::AbstractionRefinementOptions options(parseConstraints(input.model->getManager(), abstractionSettings.getConstraintString()), parseInjectedRefinementPredicates(input.model->getManager(), abstractionSettings.getInjectedRefinementPredicates())); - verifyProperties<ValueType>(input, [&input,&options] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { + verifyProperties<ValueType>(input, [&input,&options,&mpi] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states."); - return storm::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(input.model.get(), storm::api::createTask<ValueType>(formula, true), options); + return storm::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(mpi.env, input.model.get(), storm::api::createTask<ValueType>(formula, true), options); }); } template <typename ValueType> - void verifyWithExplorationEngine(SymbolicInput const& input) { + void verifyWithExplorationEngine(SymbolicInput const& input, ModelProcessingInformation const& mpi) { STORM_LOG_ASSERT(input.model, "Expected symbolic model description."); STORM_LOG_THROW((std::is_same<ValueType, double>::value), storm::exceptions::NotSupportedException, "Exploration does not support other data-types than floating points."); - verifyProperties<ValueType>(input, [&input] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { + verifyProperties<ValueType>(input, [&input,&mpi] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Exploration can only filter initial states."); - return storm::api::verifyWithExplorationEngine<ValueType>(input.model.get(), storm::api::createTask<ValueType>(formula, true)); + return storm::api::verifyWithExplorationEngine<ValueType>(mpi.env, input.model.get(), storm::api::createTask<ValueType>(formula, true)); }); } template <typename ValueType> - void verifyWithSparseEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { + void verifyWithSparseEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { auto sparseModel = model->as<storm::models::sparse::Model<ValueType>>(); auto const& ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); verifyProperties<ValueType>(input, - [&sparseModel,&ioSettings] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { + [&sparseModel,&ioSettings,&mpi] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { bool filterForInitialStates = states->isInitialFormula(); auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates); if (ioSettings.isExportSchedulerSet()) { task.setProduceSchedulers(true); } - std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(sparseModel, task); + std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(mpi.env, sparseModel, task); std::unique_ptr<storm::modelchecker::CheckResult> filter; if (filterForInitialStates) { filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult>(sparseModel->getInitialStates()); } else { - filter = storm::api::verifyWithSparseEngine<ValueType>(sparseModel, storm::api::createTask<ValueType>(states, false)); + filter = storm::api::verifyWithSparseEngine<ValueType>(mpi.env, sparseModel, storm::api::createTask<ValueType>(states, false)); } if (result && filter) { result->filter(filter->asQualitativeCheckResult()); @@ -854,19 +972,19 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType> - void verifyWithHybridEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { - verifyProperties<ValueType>(input, [&model] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { + void verifyWithHybridEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { + verifyProperties<ValueType>(input, [&model,&mpi] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { bool filterForInitialStates = states->isInitialFormula(); auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates); auto symbolicModel = model->as<storm::models::symbolic::Model<DdType, ValueType>>(); - std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithHybridEngine<DdType, ValueType>(symbolicModel, task); + std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithHybridEngine<DdType, ValueType>(mpi.env, symbolicModel, task); std::unique_ptr<storm::modelchecker::CheckResult> filter; if (filterForInitialStates) { filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(), symbolicModel->getInitialStates()); } else { - filter = storm::api::verifyWithHybridEngine<DdType, ValueType>(symbolicModel, storm::api::createTask<ValueType>(states, false)); + filter = storm::api::verifyWithHybridEngine<DdType, ValueType>(mpi.env, symbolicModel, storm::api::createTask<ValueType>(states, false)); } if (result && filter) { result->filter(filter->asQualitativeCheckResult()); @@ -876,19 +994,19 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType> - void verifyWithDdEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { - verifyProperties<ValueType>(input, [&model] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { + void verifyWithDdEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { + verifyProperties<ValueType>(input, [&model,&mpi] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { bool filterForInitialStates = states->isInitialFormula(); auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates); auto symbolicModel = model->as<storm::models::symbolic::Model<DdType, ValueType>>(); - std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithDdEngine<DdType, ValueType>(symbolicModel, storm::api::createTask<ValueType>(formula, true)); + std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithDdEngine<DdType, ValueType>(mpi.env, symbolicModel, storm::api::createTask<ValueType>(formula, true)); std::unique_ptr<storm::modelchecker::CheckResult> filter; if (filterForInitialStates) { filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(), symbolicModel->getInitialStates()); } else { - filter = storm::api::verifyWithDdEngine<DdType, ValueType>(symbolicModel, storm::api::createTask<ValueType>(states, false)); + filter = storm::api::verifyWithDdEngine<DdType, ValueType>(mpi.env, symbolicModel, storm::api::createTask<ValueType>(states, false)); } if (result && filter) { result->filter(filter->asQualitativeCheckResult()); @@ -898,48 +1016,47 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType> - void verifyWithAbstractionRefinementEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { - verifyProperties<ValueType>(input, [&model] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { + void verifyWithAbstractionRefinementEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { + verifyProperties<ValueType>(input, [&model,&mpi] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states."); auto symbolicModel = model->as<storm::models::symbolic::Model<DdType, ValueType>>(); - return storm::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(symbolicModel, storm::api::createTask<ValueType>(formula, true)); + return storm::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(mpi.env, symbolicModel, storm::api::createTask<ValueType>(formula, true)); }); } template <storm::dd::DdType DdType, typename ValueType> - typename std::enable_if<DdType != storm::dd::DdType::CUDD || std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) { - storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine();; - if (engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { - verifyWithHybridEngine<DdType, ValueType>(model, input); - } else if (engine == storm::settings::modules::CoreSettings::Engine::Dd) { - verifyWithDdEngine<DdType, ValueType>(model, input); + typename std::enable_if<DdType != storm::dd::DdType::CUDD || std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { + if (mpi.engine == storm::utility::Engine::Hybrid) { + verifyWithHybridEngine<DdType, ValueType>(model, input, mpi); + } else if (mpi.engine == storm::utility::Engine::Dd) { + verifyWithDdEngine<DdType, ValueType>(model, input, mpi); } else { - verifyWithAbstractionRefinementEngine<DdType, ValueType>(model, input); + verifyWithAbstractionRefinementEngine<DdType, ValueType>(model, input, mpi); } } template <storm::dd::DdType DdType, typename ValueType> - typename std::enable_if<DdType == storm::dd::DdType::CUDD && !std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) { + typename std::enable_if<DdType == storm::dd::DdType::CUDD && !std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const&, SymbolicInput const&, ModelProcessingInformation const&) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support the selected data-type."); } template <storm::dd::DdType DdType, typename ValueType> - void verifyModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) { + void verifyModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, ModelProcessingInformation const& mpi) { if (model->isSparseModel()) { - verifyWithSparseEngine<ValueType>(model, input); + verifyWithSparseEngine<ValueType>(model, input, mpi); } else { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); - verifySymbolicModel<DdType, ValueType>(model, input, coreSettings); + verifySymbolicModel<DdType, ValueType>(model, input, mpi); } } template <storm::dd::DdType DdType, typename BuildValueType, typename VerificationValueType = BuildValueType> - std::shared_ptr<storm::models::ModelBase> buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, storm::settings::modules::CoreSettings::Engine engine) { + std::shared_ptr<storm::models::ModelBase> buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, ModelProcessingInformation const& mpi) { auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>(); std::shared_ptr<storm::models::ModelBase> model; if (!buildSettings.isNoBuildModelSet()) { - model = buildModel<DdType, BuildValueType>(engine, input, ioSettings); + model = buildModel<DdType, BuildValueType>(input, ioSettings, mpi); } if (model) { @@ -949,7 +1066,7 @@ namespace storm { STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); if (model) { - auto preprocessingResult = preprocessModel<DdType, BuildValueType, VerificationValueType>(model, input); + auto preprocessingResult = preprocessModel<DdType, BuildValueType, VerificationValueType>(model, input, mpi); if (preprocessingResult.second) { model = preprocessingResult.first; model->printModelInformationToStream(std::cout); @@ -960,50 +1077,48 @@ namespace storm { } template <storm::dd::DdType DdType, typename BuildValueType, typename VerificationValueType = BuildValueType> - void processInputWithValueTypeAndDdlib(SymbolicInput const& input) { - auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); + void processInputWithValueTypeAndDdlib(SymbolicInput const& input, ModelProcessingInformation const& mpi) { auto abstractionSettings = storm::settings::getModule<storm::settings::modules::AbstractionSettings>(); auto counterexampleSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>(); // For several engines, no model building step is performed, but the verification is started right away. - storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine(); - - if (engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement && abstractionSettings.getAbstractionRefinementMethod() == storm::settings::modules::AbstractionSettings::Method::Games) { - verifyWithAbstractionRefinementEngine<DdType, VerificationValueType>(input); - } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { - verifyWithExplorationEngine<VerificationValueType>(input); + if (mpi.engine == storm::utility::Engine::AbstractionRefinement && abstractionSettings.getAbstractionRefinementMethod() == storm::settings::modules::AbstractionSettings::Method::Games) { + verifyWithAbstractionRefinementEngine<DdType, VerificationValueType>(input, mpi); + } else if (mpi.engine == storm::utility::Engine::Exploration) { + verifyWithExplorationEngine<VerificationValueType>(input, mpi); } else { - std::shared_ptr<storm::models::ModelBase> model = buildPreprocessExportModelWithValueTypeAndDdlib<DdType, BuildValueType, VerificationValueType>(input, engine); - + std::shared_ptr<storm::models::ModelBase> model = buildPreprocessExportModelWithValueTypeAndDdlib<DdType, BuildValueType, VerificationValueType>(input, mpi); if (model) { if (counterexampleSettings.isCounterexampleSet()) { generateCounterexamples<VerificationValueType>(model, input); } else { - verifyModel<DdType, VerificationValueType>(model, input, coreSettings); + verifyModel<DdType, VerificationValueType>(model, input, mpi); } } } } template <typename ValueType> - void processInputWithValueType(SymbolicInput const& input) { - auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); - auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); - auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); + void processInputWithValueType(SymbolicInput const& input, ModelProcessingInformation const& mpi) { - if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && generalSettings.isExactSet()) { - STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); - processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalNumber>(input); - } else if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && std::is_same<ValueType, double>::value && generalSettings.isBisimulationSet() && bisimulationSettings.useExactArithmeticInDdBisimulation()) { - STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); - processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalNumber, double>(input); - } else if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD) { - processInputWithValueTypeAndDdlib<storm::dd::DdType::CUDD, double>(input); + if (mpi.ddType == storm::dd::DdType::CUDD) { + STORM_LOG_ASSERT(mpi.verificationValueType == ModelProcessingInformation::ValueType::FinitePrecision && mpi.buildValueType == ModelProcessingInformation::ValueType::FinitePrecision && (std::is_same<ValueType, double>::value), "Unexpected value type for Dd library cudd."); + processInputWithValueTypeAndDdlib<storm::dd::DdType::CUDD, double>(input, mpi); } else { - STORM_LOG_ASSERT(coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "Unknown DD library."); - processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, ValueType>(input); + STORM_LOG_ASSERT(mpi.ddType == storm::dd::DdType::Sylvan, "Unknown DD library."); + if (mpi.buildValueType == mpi.verificationValueType) { + processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, ValueType>(input, mpi); + } else { + // Right now, we only require (buildType == Exact and verificationType == FinitePrecision). + // We exclude all other combinations to safe a few template instantiations. + STORM_LOG_THROW((std::is_same<ValueType, double>::value) && mpi.buildValueType == ModelProcessingInformation::ValueType::Exact, storm::exceptions::InvalidArgumentException, "Unexpected combination of buildValueType and verificationValueType"); +#ifdef STORM_HAVE_CARL + processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalNumber, double>(input, mpi); +#else + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unexpected buildValueType."); +#endif + } } } - } } diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp index 95ca5c4ee..14c140770 100644 --- a/src/storm-conv/api/storm-conv.cpp +++ b/src/storm-conv/api/storm-conv.cpp @@ -53,6 +53,10 @@ namespace storm { } } + if (options.simplifyComposition) { + janiModel.simplifyComposition(); + } + if (options.flatten) { std::shared_ptr<storm::utility::solver::SmtSolverFactory> smtSolverFactory; if (storm::settings::hasModule<storm::settings::modules::CoreSettings>()) { diff --git a/src/storm-conv/converter/options/JaniConversionOptions.cpp b/src/storm-conv/converter/options/JaniConversionOptions.cpp index c8a4ab8a3..4d0937c3a 100644 --- a/src/storm-conv/converter/options/JaniConversionOptions.cpp +++ b/src/storm-conv/converter/options/JaniConversionOptions.cpp @@ -3,11 +3,11 @@ namespace storm { namespace converter { - JaniConversionOptions::JaniConversionOptions() : edgeAssignments(false), flatten(false), substituteConstants(true), localVars(false), globalVars(false), allowedModelFeatures(storm::jani::getAllKnownModelFeatures()), addPropertyConstants(true), replaceUnassignedVariablesWithConstants(false) { + JaniConversionOptions::JaniConversionOptions() : edgeAssignments(false), flatten(false), substituteConstants(true), localVars(false), globalVars(false), allowedModelFeatures(storm::jani::getAllKnownModelFeatures()), addPropertyConstants(true), replaceUnassignedVariablesWithConstants(false), simplifyComposition(false) { // Intentionally left empty } - JaniConversionOptions::JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings) : locationVariables(settings.getLocationVariables()), edgeAssignments(settings.isAllowEdgeAssignmentsSet()), flatten(settings.isExportFlattenedSet()), substituteConstants(true), localVars(settings.isLocalVarsSet()), globalVars(settings.isGlobalVarsSet()), allowedModelFeatures(storm::jani::getAllKnownModelFeatures()), addPropertyConstants(true), replaceUnassignedVariablesWithConstants(settings.isReplaceUnassignedVariablesWithConstantsSet()) { + JaniConversionOptions::JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings) : locationVariables(settings.getLocationVariables()), edgeAssignments(settings.isAllowEdgeAssignmentsSet()), flatten(settings.isExportFlattenedSet()), substituteConstants(true), localVars(settings.isLocalVarsSet()), globalVars(settings.isGlobalVarsSet()), allowedModelFeatures(storm::jani::getAllKnownModelFeatures()), addPropertyConstants(true), replaceUnassignedVariablesWithConstants(settings.isReplaceUnassignedVariablesWithConstantsSet()), simplifyComposition(settings.isSimplifyCompositionSet()) { if (settings.isEliminateFunctionsSet()) { allowedModelFeatures.remove(storm::jani::ModelFeature::Functions); } diff --git a/src/storm-conv/converter/options/JaniConversionOptions.h b/src/storm-conv/converter/options/JaniConversionOptions.h index 65f6f7ce5..301d94b08 100644 --- a/src/storm-conv/converter/options/JaniConversionOptions.h +++ b/src/storm-conv/converter/options/JaniConversionOptions.h @@ -44,6 +44,10 @@ namespace storm { /// If set, local and global variables that are (a) not assigned to some value and (b) have a known initial value are replaced by constants. bool replaceUnassignedVariablesWithConstants; + + /// If set, attempts to simplify the system composition + bool simplifyComposition; + }; } } diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index cc6aeef29..90d02e8aa 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -23,6 +23,7 @@ namespace storm { const std::string JaniExportSettings::eliminateArraysOptionName = "remove-arrays"; const std::string JaniExportSettings::eliminateFunctionsOptionName = "remove-functions"; const std::string JaniExportSettings::replaceUnassignedVariablesWithConstantsOptionName = "replace-unassigned-vars"; + const std::string JaniExportSettings::simplifyCompositionOptionName = "simplify-composition"; JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list of automaton and local variable names seperated by a dot, e.g. A.x,B.y.").setDefaultValueString("").build()).build()); @@ -34,6 +35,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, eliminateArraysOptionName, false, "If set, transforms the model such that array variables/expressions are eliminated.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, eliminateFunctionsOptionName, false, "If set, transforms the model such that functions are eliminated.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, replaceUnassignedVariablesWithConstantsOptionName, false, "If set, local and global variables that are (a) not assigned to some value and (b) have a known initial value are replaced by constants.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, simplifyCompositionOptionName, false, "If set, attempts to simplify the system composition.").build()); } bool JaniExportSettings::isAllowEdgeAssignmentsSet() const { @@ -88,6 +90,10 @@ namespace storm { return this->getOption(replaceUnassignedVariablesWithConstantsOptionName).getHasOptionBeenSet(); } + bool JaniExportSettings::isSimplifyCompositionSet() const { + return this->getOption(simplifyCompositionOptionName).getHasOptionBeenSet(); + } + void JaniExportSettings::finalize() { } diff --git a/src/storm-conv/settings/modules/JaniExportSettings.h b/src/storm-conv/settings/modules/JaniExportSettings.h index c91097b5f..cf492af78 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.h +++ b/src/storm-conv/settings/modules/JaniExportSettings.h @@ -31,6 +31,8 @@ namespace storm { bool isEliminateFunctionsSet() const; bool isReplaceUnassignedVariablesWithConstantsSet() const; + + bool isSimplifyCompositionSet() const; std::vector<std::pair<std::string, std::string>> getLocationVariables() const; @@ -49,6 +51,7 @@ namespace storm { static const std::string eliminateArraysOptionName; static const std::string eliminateFunctionsOptionName; static const std::string replaceUnassignedVariablesWithConstantsOptionName; + static const std::string simplifyCompositionOptionName; }; } diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index d290dd47c..0b7ff3bbd 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -23,7 +23,6 @@ #include "storm/exceptions/BaseException.h" #include "storm/exceptions/InvalidSettingsException.h" -#include "storm/exceptions/InvalidSettingsException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/models/ModelBase.h" @@ -39,6 +38,7 @@ #include "storm/utility/initialize.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/macros.h" +#include "storm/utility/Engine.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" @@ -158,8 +158,7 @@ namespace storm { } template <typename ValueType> - PreprocessResult preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) { - auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); + PreprocessResult preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, storm::cli::ModelProcessingInformation const& mpi) { auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>(); auto transformationSettings = storm::settings::getModule<storm::settings::modules::TransformationSettings>(); @@ -171,7 +170,7 @@ namespace storm { result.changed = true; } - if (generalSettings.isBisimulationSet()) { + if (mpi.applyBisimulation) { result.model = storm::cli::preprocessSparseModelBisimulation(result.model->template as<storm::models::sparse::Model<ValueType>>(), input, bisimulationSettings); result.changed = true; } @@ -200,28 +199,26 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType> - PreprocessResult preprocessDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input) { - auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); - auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); + PreprocessResult preprocessDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, storm::cli::ModelProcessingInformation const& mpi) { auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); - + PreprocessResult result(model, false); - if (coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Hybrid) { + if (mpi.engine == storm::utility::Engine::Hybrid) { // Currently, hybrid engine for parametric models just refers to building the model symbolically. STORM_LOG_INFO("Translating symbolic model to sparse model..."); result.model = storm::api::transformSymbolicToSparseModel(model); result.changed = true; // Invoke preprocessing on the sparse model - PreprocessResult sparsePreprocessingResult = storm::pars::preprocessSparseModel<ValueType>(result.model->as<storm::models::sparse::Model<ValueType>>(), input); + PreprocessResult sparsePreprocessingResult = storm::pars::preprocessSparseModel<ValueType>(result.model->as<storm::models::sparse::Model<ValueType>>(), input, mpi); if (sparsePreprocessingResult.changed) { result.model = sparsePreprocessingResult.model; result.formulas = sparsePreprocessingResult.formulas; } } else { - STORM_LOG_ASSERT(coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Dd, "Expected Dd engine."); - if (generalSettings.isBisimulationSet()) { - result.model = storm::cli::preprocessDdModelBisimulation(result.model->template as<storm::models::symbolic::Model<DdType, ValueType>>(), input, bisimulationSettings); + STORM_LOG_ASSERT(mpi.engine == storm::utility::Engine::Dd, "Expected Dd engine."); + if (mpi.applyBisimulation) { + result.model = storm::cli::preprocessDdModelBisimulation(result.model->template as<storm::models::symbolic::Model<DdType, ValueType>>(), input, bisimulationSettings, mpi); result.changed = true; } } @@ -229,15 +226,15 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType> - PreprocessResult preprocessModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { + PreprocessResult preprocessModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::cli::ModelProcessingInformation const& mpi) { storm::utility::Stopwatch preprocessingWatch(true); PreprocessResult result(model, false); if (model->isSparseModel()) { - result = storm::pars::preprocessSparseModel<ValueType>(result.model->as<storm::models::sparse::Model<ValueType>>(), input); + result = storm::pars::preprocessSparseModel<ValueType>(result.model->as<storm::models::sparse::Model<ValueType>>(), input, mpi); } else { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); - result = storm::pars::preprocessDdModel<DdType, ValueType>(result.model->as<storm::models::symbolic::Model<DdType, ValueType>>(), input); + result = storm::pars::preprocessDdModel<DdType, ValueType>(result.model->as<storm::models::symbolic::Model<DdType, ValueType>>(), input, mpi); } if (result.changed) { @@ -565,22 +562,18 @@ namespace storm { } } - template <storm::dd::DdType DdType, typename ValueType> - void processInputWithValueTypeAndDdlib(SymbolicInput& input) { - auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); + void processInputWithValueTypeAndDdlib(SymbolicInput& input, storm::cli::ModelProcessingInformation const& mpi) { auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); - auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>(); auto parSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>(); auto monSettings = storm::settings::getModule<storm::settings::modules::MonotonicitySettings>(); - auto engine = coreSettings.getEngine(); - STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models."); + STORM_LOG_THROW(mpi.engine == storm::utility::Engine::Sparse || mpi.engine == storm::utility::Engine::Hybrid || mpi.engine == storm::utility::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models."); std::shared_ptr<storm::models::ModelBase> model; if (!buildSettings.isNoBuildModelSet()) { - model = storm::cli::buildModel<DdType, ValueType>(engine, input, ioSettings); + model = storm::cli::buildModel<DdType, ValueType>(input, ioSettings, mpi); } if (model) { @@ -592,7 +585,7 @@ namespace storm { if (model) { - auto preprocessingResult = storm::pars::preprocessModel<DdType, ValueType>(model, input); + auto preprocessingResult = storm::pars::preprocessModel<DdType, ValueType>(model, input, mpi); if (preprocessingResult.changed) { model = preprocessingResult.model; @@ -646,7 +639,7 @@ namespace storm { } if (model) { - auto preprocessingResult = storm::pars::preprocessModel<DdType, ValueType>(model, input); + auto preprocessingResult = storm::pars::preprocessModel<DdType, ValueType>(model, input, mpi); if (preprocessingResult.changed) { model = preprocessingResult.model; @@ -783,15 +776,16 @@ namespace storm { void processOptions() { // Start by setting some urgent options (log levels, resources, etc.) storm::cli::setUrgentOptions(); - - // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.) - SymbolicInput symbolicInput = storm::cli::parseAndPreprocessSymbolicInput(); - + auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); auto engine = coreSettings.getEngine(); - STORM_LOG_WARN_COND(engine != storm::settings::modules::CoreSettings::Engine::Dd || engine != storm::settings::modules::CoreSettings::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan..."); - - processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalFunction>(symbolicInput); + STORM_LOG_WARN_COND(engine != storm::utility::Engine::Dd || engine != storm::utility::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan..."); + + // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.) + auto symbolicInput = storm::cli::parseSymbolicInput(); + auto mpi = storm::cli::getModelProcessingInformation(symbolicInput); + symbolicInput = storm::cli::preprocessSymbolicInput(symbolicInput, mpi.engine); + processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalFunction>(symbolicInput, mpi); } } diff --git a/src/storm-parsers/api/model_descriptions.cpp b/src/storm-parsers/api/model_descriptions.cpp index 983156279..b66855a25 100644 --- a/src/storm-parsers/api/model_descriptions.cpp +++ b/src/storm-parsers/api/model_descriptions.cpp @@ -22,21 +22,7 @@ namespace storm { return program; } - std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> parseJaniModel(std::string const& filename) { - storm::jani::ModelFeatures features; - // Add derived-operators and state-exit-rewards as these can be handled by all model builders - features.add(storm::jani::ModelFeature::DerivedOperators); - features.add(storm::jani::ModelFeature::StateExitRewards); - auto parsedResult = parseJaniModel(filename, features); - std::map<std::string, storm::jani::Property> propertyMap; - for (auto const& property : parsedResult.second) { - propertyMap.emplace(property.getName(), property); - } - return std::make_pair(std::move(parsedResult.first), std::move(propertyMap)); - } - - std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& filename, storm::jani::ModelFeatures const& allowedFeatures, boost::optional<std::vector<std::string>> const& propertyFilter) { - + std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& filename, boost::optional<std::vector<std::string>> const& propertyFilter) { bool parseProperties = !propertyFilter.is_initialized() || !propertyFilter.get().empty(); std::pair<storm::jani::Model, std::vector<storm::jani::Property>> modelAndFormulae = storm::parser::JaniParser::parse(filename, parseProperties); @@ -57,13 +43,20 @@ namespace storm { } modelAndFormulae.second = std::move(newProperties); } - modelAndFormulae.first.checkValid(); - auto nonEliminatedFeatures = modelAndFormulae.first.restrictToFeatures(allowedFeatures, modelAndFormulae.second); - STORM_LOG_THROW(nonEliminatedFeatures.empty(), storm::exceptions::NotSupportedException, "The used model feature(s) " << nonEliminatedFeatures.toString() << " is/are not in the list of allowed features."); return modelAndFormulae; } + std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& filename, storm::jani::ModelFeatures const& supportedFeatures, boost::optional<std::vector<std::string>> const& propertyFilter) { + auto modelAndFormulae = parseJaniModel(filename, propertyFilter); + simplifyJaniModel(modelAndFormulae.first, modelAndFormulae.second, supportedFeatures); + return modelAndFormulae; + } + + void simplifyJaniModel(storm::jani::Model& model, std::vector<storm::jani::Property>& properties , storm::jani::ModelFeatures const& supportedFeatures) { + auto nonEliminatedFeatures = model.restrictToFeatures(supportedFeatures, properties); + STORM_LOG_THROW(nonEliminatedFeatures.empty(), storm::exceptions::NotSupportedException, "The used model feature(s) " << nonEliminatedFeatures.toString() << " is/are not in the list of supported features."); + } } } diff --git a/src/storm-parsers/api/model_descriptions.h b/src/storm-parsers/api/model_descriptions.h index 8e45304c3..de098ee80 100644 --- a/src/storm-parsers/api/model_descriptions.h +++ b/src/storm-parsers/api/model_descriptions.h @@ -19,7 +19,9 @@ namespace storm { storm::prism::Program parseProgram(std::string const& filename, bool prismCompatibility = false, bool simplify = true); - std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> parseJaniModel(std::string const& filename); + std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& filename, boost::optional<std::vector<std::string>> const& propertyFilter = boost::none); std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& filename, storm::jani::ModelFeatures const& allowedFeatures, boost::optional<std::vector<std::string>> const& propertyFilter = boost::none); + void simplifyJaniModel(storm::jani::Model& model, std::vector<storm::jani::Property>& properties , storm::jani::ModelFeatures const& supportedFeatures); + } } diff --git a/src/storm-pomdp-cli/storm-pomdp.cpp b/src/storm-pomdp-cli/storm-pomdp.cpp index 9fc95f904..3da5f6662 100644 --- a/src/storm-pomdp-cli/storm-pomdp.cpp +++ b/src/storm-pomdp-cli/storm-pomdp.cpp @@ -98,12 +98,12 @@ int main(const int argc, const char** argv) { auto const& coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); auto const& pomdpSettings = storm::settings::getModule<storm::settings::modules::POMDPSettings>(); - // For several engines, no model building step is performed, but the verification is started right away. - storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine(); - - storm::cli::SymbolicInput symbolicInput = storm::cli::parseAndPreprocessSymbolicInput(); + auto symbolicInput = storm::cli::parseSymbolicInput(); + auto mpi = storm::cli::getModelProcessingInformation(symbolicInput); + symbolicInput = storm::cli::preprocessSymbolicInput(symbolicInput, mpi.engine); + // We should not export here if we are going to do some processing first. - auto model = storm::cli::buildPreprocessExportModelWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalNumber>(symbolicInput, engine); + auto model = storm::cli::buildPreprocessExportModelWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalNumber>(symbolicInput, mpi); STORM_LOG_THROW(model && model->getType() == storm::models::ModelType::Pomdp, storm::exceptions::WrongFormatException, "Expected a POMDP."); std::shared_ptr<storm::models::sparse::Pomdp<storm::RationalNumber>> pomdp = model->template as<storm::models::sparse::Pomdp<storm::RationalNumber>>(); storm::transformer::MakePOMDPCanonic<storm::RationalNumber> makeCanonic(*pomdp); diff --git a/src/storm/utility/exprtk.h b/src/storm/adapters/ExprttkAdapter.h similarity index 69% rename from src/storm/utility/exprtk.h rename to src/storm/adapters/ExprttkAdapter.h index 3aba1b8db..ddf013b48 100644 --- a/src/storm/utility/exprtk.h +++ b/src/storm/adapters/ExprttkAdapter.h @@ -5,6 +5,9 @@ #pragma GCC diagnostic push +// exprtk should be case sensitive in our case. +#define exprtk_disable_caseinsensitivity + #include "exprtk.hpp" #pragma GCC diagnostic pop diff --git a/src/storm/api/bisimulation.h b/src/storm/api/bisimulation.h index 40391be2b..d5ae374c5 100644 --- a/src/storm/api/bisimulation.h +++ b/src/storm/api/bisimulation.h @@ -56,7 +56,7 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType> - typename std::enable_if<DdType == storm::dd::DdType::Sylvan || std::is_same<ValueType, double>::value, std::shared_ptr<storm::models::Model<ExportValueType>>>::type performBisimulationMinimization(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { + typename std::enable_if<DdType == storm::dd::DdType::Sylvan || std::is_same<ValueType, double>::value, std::shared_ptr<storm::models::Model<ExportValueType>>>::type performBisimulationMinimization(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager, storm::dd::bisimulation::QuotientFormat const& quotientFormat = storm::dd::bisimulation::QuotientFormat::Dd) { STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::Mdp) || model->isOfType(storm::models::ModelType::MarkovAutomaton), storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is currently only available for DTMCs, CTMCs, MDPs and MAs."); STORM_LOG_THROW(bisimulationType == storm::storage::BisimulationType::Strong, storm::exceptions::NotSupportedException, "Currently only strong bisimulation is supported."); @@ -66,11 +66,11 @@ namespace storm { storm::dd::BisimulationDecomposition<DdType, ValueType, ExportValueType> decomposition(*model, formulas, bisimulationType); decomposition.compute(mode); - return decomposition.getQuotient(); + return decomposition.getQuotient(quotientFormat); } template <storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType> - typename std::enable_if<DdType != storm::dd::DdType::Sylvan && !std::is_same<ValueType, double>::value, std::shared_ptr<storm::models::Model<ExportValueType>>>::type performBisimulationMinimization(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { + typename std::enable_if<DdType != storm::dd::DdType::Sylvan && !std::is_same<ValueType, double>::value, std::shared_ptr<storm::models::Model<ExportValueType>>>::type performBisimulationMinimization(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager, storm::dd::bisimulation::QuotientFormat const& quotientFormat = storm::dd::bisimulation::QuotientFormat::Dd) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is not supported for this combination of DD library and value type."); return nullptr; } diff --git a/src/storm/api/builder.h b/src/storm/api/builder.h index 4e22d6662..0760ae9f1 100644 --- a/src/storm/api/builder.h +++ b/src/storm/api/builder.h @@ -33,13 +33,7 @@ namespace storm { namespace api { inline storm::jani::ModelFeatures getSupportedJaniFeatures(storm::builder::BuilderType const& builderType) { - storm::jani::ModelFeatures features; - features.add(storm::jani::ModelFeature::DerivedOperators); - features.add(storm::jani::ModelFeature::StateExitRewards); - if (builderType == storm::builder::BuilderType::Explicit) { - features.add(storm::jani::ModelFeature::Arrays); - } - return features; + return storm::builder::getSupportedJaniFeatures(builderType); } template<storm::dd::DdType LibraryType, typename ValueType> diff --git a/src/storm/api/transformation.h b/src/storm/api/transformation.h index 9aa99aa01..1ab8f696e 100644 --- a/src/storm/api/transformation.h +++ b/src/storm/api/transformation.h @@ -105,6 +105,8 @@ namespace storm { return storm::transformer::SymbolicMdpToSparseMdpTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Mdp<Type, ValueType>>(), formulas); case storm::models::ModelType::Ctmc: return storm::transformer::SymbolicCtmcToSparseCtmcTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Ctmc<Type, ValueType>>(), formulas); + case storm::models::ModelType::MarkovAutomaton: + return storm::transformer::SymbolicMaToSparseMaTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::MarkovAutomaton<Type, ValueType>>(), formulas); default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of symbolic " << symbolicModel->getType() << " to sparse model is not supported."); } diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h index 3f5b9653c..f5033568c 100644 --- a/src/storm/api/verification.h +++ b/src/storm/api/verification.h @@ -13,6 +13,7 @@ #include "storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h" #include "storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h" #include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" +#include "storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.h" #include "storm/modelchecker/abstraction/GameBasedMdpModelChecker.h" #include "storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h" #include "storm/modelchecker/exploration/SparseExplorationModelChecker.h" @@ -20,6 +21,7 @@ #include "storm/models/symbolic/Dtmc.h" #include "storm/models/symbolic/Mdp.h" +#include "storm/models/symbolic/MarkovAutomaton.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" @@ -327,6 +329,27 @@ namespace storm { return verifyWithHybridEngine(env, mdp, task); } + template<storm::dd::DdType DdType, typename ValueType> + typename std::enable_if<!std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithHybridEngine(storm::Environment const& env, std::shared_ptr<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>> const& ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { + std::unique_ptr<storm::modelchecker::CheckResult> result; + storm::modelchecker::HybridMarkovAutomatonCslModelChecker<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>> modelchecker(*ma); + if (modelchecker.canHandle(task)) { + result = modelchecker.check(env, task); + } + return result; + } + + template<storm::dd::DdType DdType, typename ValueType> + typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithHybridEngine(storm::Environment const& , std::shared_ptr<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>> const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Hybrid engine cannot verify MDPs with this data type."); + } + + template<storm::dd::DdType DdType, typename ValueType> + std::unique_ptr<storm::modelchecker::CheckResult> verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>> const& ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { + Environment env; + return verifyWithHybridEngine(env, ma, task); + } + template<storm::dd::DdType DdType, typename ValueType> std::unique_ptr<storm::modelchecker::CheckResult> verifyWithHybridEngine(storm::Environment const& env, std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { std::unique_ptr<storm::modelchecker::CheckResult> result; @@ -336,6 +359,8 @@ namespace storm { result = verifyWithHybridEngine(env, model->template as<storm::models::symbolic::Ctmc<DdType, ValueType>>(), task); } else if (model->getType() == storm::models::ModelType::Mdp) { result = verifyWithHybridEngine(env, model->template as<storm::models::symbolic::Mdp<DdType, ValueType>>(), task); + } else if (model->getType() == storm::models::ModelType::MarkovAutomaton) { + result = verifyWithHybridEngine(env, model->template as<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>(), task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The model type " << model->getType() << " is not supported by the hybrid engine."); } diff --git a/src/storm/builder/BuilderType.cpp b/src/storm/builder/BuilderType.cpp new file mode 100644 index 000000000..d8c701d9b --- /dev/null +++ b/src/storm/builder/BuilderType.cpp @@ -0,0 +1,69 @@ +#include "storm/builder/BuilderType.h" + +#include "storm/storage/dd/DdType.h" + +#include "storm/storage/jani/ModelFeatures.h" +#include "storm/generator/JaniNextStateGenerator.h" +#include "storm/generator/PrismNextStateGenerator.h" +#include "storm/builder/DdJaniModelBuilder.h" +#include "storm/builder/DdPrismModelBuilder.h" +#include "storm/builder/jit/ExplicitJitJaniModelBuilder.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace builder { + + storm::jani::ModelFeatures getSupportedJaniFeatures(BuilderType const& builderType) { + // The supported jani features should be independent of the ValueType and Dd type. We just take sylvan and double for all. + storm::dd::DdType const ddType = storm::dd::DdType::Sylvan; + typedef double ValueType; + switch (builderType) { + case BuilderType::Explicit: + return storm::generator::JaniNextStateGenerator<ValueType>::getSupportedJaniFeatures(); + case BuilderType::Dd: + return storm::builder::DdJaniModelBuilder<ddType, ValueType>::getSupportedJaniFeatures(); + case BuilderType::Jit: + return storm::builder::jit::ExplicitJitJaniModelBuilder<ValueType>::getSupportedJaniFeatures(); + + } + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unexpected builder type."); + } + + template <typename ValueType> + bool canHandle(BuilderType const& builderType, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional<std::vector<storm::jani::Property>> const& properties) { + storm::dd::DdType const ddType = storm::dd::DdType::Sylvan; + if (!modelDescription.hasModel()) { + // If there is no model to be build, we assume that the task of obtaining a model is either not required or can be accomplished somehow. + return true; + } + STORM_LOG_THROW(modelDescription.isPrismProgram() || modelDescription.isJaniModel(), storm::exceptions::UnexpectedException, "The model is neither PRISM nor Jani which is not expected."); + switch (builderType) { + case BuilderType::Explicit: + if (modelDescription.isPrismProgram()) { + return storm::generator::PrismNextStateGenerator<ValueType>::canHandle(modelDescription.asPrismProgram()); + } else { + return storm::generator::JaniNextStateGenerator<ValueType>::canHandle(modelDescription.asJaniModel()); + } + case BuilderType::Dd: + if (modelDescription.isPrismProgram()) { + return storm::builder::DdPrismModelBuilder<ddType, ValueType>::canHandle(modelDescription.asPrismProgram()); + } else { + return storm::builder::DdJaniModelBuilder<ddType, ValueType>::canHandle(modelDescription.asJaniModel(), properties); + } + case BuilderType::Jit: + return storm::builder::jit::ExplicitJitJaniModelBuilder<ValueType>::canHandle(modelDescription.asJaniModel()); + } + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled builderType."); + return false; + } + + + + template bool canHandle<double>(BuilderType const& builderType, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional<std::vector<storm::jani::Property>> const& properties); + template bool canHandle<storm::RationalNumber>(BuilderType const& builderType, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional<std::vector<storm::jani::Property>> const& properties); + template bool canHandle<storm::RationalFunction>(BuilderType const& builderType, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional<std::vector<storm::jani::Property>> const& properties); + + } +} \ No newline at end of file diff --git a/src/storm/builder/BuilderType.h b/src/storm/builder/BuilderType.h index 8e5e86ad0..22b08158c 100644 --- a/src/storm/builder/BuilderType.h +++ b/src/storm/builder/BuilderType.h @@ -1,11 +1,26 @@ #pragma once +#include <vector> +#include <boost/optional.hpp> + +#include "storm/storage/jani/Property.h" +#include "storm/storage/SymbolicModelDescription.h" + namespace storm { + namespace jani { + class ModelFeatures; + } + namespace builder { enum class BuilderType { Explicit, Dd, Jit }; + + storm::jani::ModelFeatures getSupportedJaniFeatures(BuilderType const& builderType); + + template <typename ValueType> + bool canHandle(BuilderType const& builderType, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional<std::vector<storm::jani::Property>> const& properties = boost::none); } } \ No newline at end of file diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index 2175dd2e1..259ad60d9 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -14,6 +14,7 @@ #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/CompositionInformationVisitor.h" +#include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/dd/Add.h" #include "storm/storage/dd/Bdd.h" @@ -45,6 +46,57 @@ namespace storm { namespace builder { + template <storm::dd::DdType Type, typename ValueType> + storm::jani::ModelFeatures DdJaniModelBuilder<Type, ValueType>::getSupportedJaniFeatures() { + storm::jani::ModelFeatures features; + features.add(storm::jani::ModelFeature::DerivedOperators); + features.add(storm::jani::ModelFeature::StateExitRewards); + // We do not add Functions and arrays as these should ideally be substituted before creating this generator. + // This is because functions or arrays may also occur in properties and the user of this builder should take care of that. + return features; + } + + template <storm::dd::DdType Type, typename ValueType> + bool DdJaniModelBuilder<Type, ValueType>::canHandle(storm::jani::Model const& model, boost::optional<std::vector<storm::jani::Property>> const& properties) { + // Check jani features + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::Arrays); // can be substituted + features.remove(storm::jani::ModelFeature::DerivedOperators); + features.remove(storm::jani::ModelFeature::Functions); // can be substituted + features.remove(storm::jani::ModelFeature::StateExitRewards); + if (!features.empty()) { + STORM_LOG_INFO("Symbolic engine can not build Jani model due to unsupported jani features."); + return false; + } + // Check assignment levels + if (model.usesAssignmentLevels()) { + STORM_LOG_INFO("Symbolic engine can not build Jani model due to assignment levels."); + return false; + } + // Check nonTrivial reward expressions + if (properties) { + std::set<std::string> rewardModels; + for (auto const& p : properties.get()) { + p.gatherReferencedRewardModels(rewardModels); + } + for (auto const& r : rewardModels) { + if (model.isNonTrivialRewardModelExpression(r)) { + STORM_LOG_INFO("Symbolic engine can not build Jani model due to non-trivial reward expressions."); + return false; + } + } + } else { + if (model.hasNonTrivialRewardExpression()) { + STORM_LOG_INFO("Symbolic engine can not build Jani model due to non-trivial reward expressions."); + return false; + } + } + + // There probably are more cases where the model is unsupported. However, checking these is often more involved. + // As this method is supposed to be a quick check, we just return true at this point. + return true; + } + template <storm::dd::DdType Type, typename ValueType> DdJaniModelBuilder<Type, ValueType>::Options::Options(bool buildAllLabels, bool buildAllRewardModels, bool applyMaximumProgressAssumption) : buildAllLabels(buildAllLabels), buildAllRewardModels(buildAllRewardModels), applyMaximumProgressAssumption(applyMaximumProgressAssumption), rewardModelsToBuild(), constantDefinitions() { // Intentionally left empty. @@ -887,7 +939,7 @@ namespace storm { inputEnabledActionIndices.insert(actionInformation.getActionIndex(actionName)); } - return buildAutomatonDd(composition.getAutomatonName(), data.empty() ? actionInstantiations : boost::any_cast<ActionInstantiations const&>(data), inputEnabledActionIndices); + return buildAutomatonDd(composition.getAutomatonName(), data.empty() ? actionInstantiations : boost::any_cast<ActionInstantiations const&>(data), inputEnabledActionIndices, data.empty()); } boost::any visit(storm::jani::ParallelComposition const& composition, boost::any const& data) override { @@ -1707,10 +1759,13 @@ namespace storm { } } - AutomatonDd buildAutomatonDd(std::string const& automatonName, ActionInstantiations const& actionInstantiations, std::set<uint64_t> const& inputEnabledActionIndices) { + AutomatonDd buildAutomatonDd(std::string const& automatonName, ActionInstantiations const& actionInstantiations, std::set<uint64_t> const& inputEnabledActionIndices, bool isTopLevelAutomaton) { STORM_LOG_TRACE("Building DD for automaton '" << automatonName << "'."); AutomatonDd result(this->variables.automatonToIdentityMap.at(automatonName)); + // Disjunction of all guards of non-markovian actions (only required for maximum progress assumption). + storm::dd::Bdd<Type> nonMarkovianActionGuards = this->variables.manager->getBddZero(); + storm::jani::Automaton const& automaton = this->model.getAutomaton(automatonName); for (auto const& actionInstantiation : actionInstantiations) { uint64_t actionIndex = actionInstantiation.first; @@ -1727,12 +1782,20 @@ namespace storm { if (inputEnabled) { actionDd.setIsInputEnabled(); } + if (applyMaximumProgress && isTopLevelAutomaton && !instantiation.isMarkovian()) { + nonMarkovianActionGuards |= actionDd.guard; + } STORM_LOG_TRACE("Used local nondeterminism variables are " << actionDd.getLowestLocalNondeterminismVariable() << " to " << actionDd.getHighestLocalNondeterminismVariable() << "."); result.actions[ActionIdentification(actionIndex, instantiation.synchronizationVectorIndex, instantiation.isMarkovian())] = actionDd; result.extendLocalNondeterminismVariables(actionDd.getLocalNondeterminismVariables()); } } + if (applyMaximumProgress && isTopLevelAutomaton) { + ActionIdentification silentMarkovianActionIdentification(storm::jani::Model::SILENT_ACTION_INDEX, true); + result.actions[silentMarkovianActionIdentification].conjunctGuardWith(!nonMarkovianActionGuards); + } + for (uint64_t locationIndex = 0; locationIndex < automaton.getNumberOfLocations(); ++locationIndex) { auto const& location = automaton.getLocation(locationIndex); performTransientAssignments(location.getAssignments().getTransientAssignments(), [this,&automatonName,locationIndex,&result] (storm::jani::Assignment const& assignment) { @@ -2076,10 +2139,20 @@ namespace storm { auto features = model.getModelFeatures(); features.remove(storm::jani::ModelFeature::DerivedOperators); features.remove(storm::jani::ModelFeature::StateExitRewards); - STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The dd jani model builder does not support the following model feature(s): " << features.toString() << "."); storm::jani::Model preparedModel = model; - preparedModel.substituteFunctions(); + preparedModel.simplifyComposition(); + if (features.hasArrays()) { + STORM_LOG_ERROR("The jani model still considers arrays. These should have been eliminated before calling the dd builder. The arrays are eliminated now, but occurrences in properties will not be handled properly."); + preparedModel.eliminateArrays(); + features.remove(storm::jani::ModelFeature::Arrays); + } + if (features.hasFunctions()) { + STORM_LOG_ERROR("The jani model still considers functions. These should have been substituted before calling the dd builder. The functions are substituted now, but occurrences in properties will not be handled properly."); + preparedModel.substituteFunctions(); + features.remove(storm::jani::ModelFeature::Functions); + } + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The dd jani model builder does not support the following model feature(s): " << features.toString() << "."); // Lift the transient edge destinations. We can do so, as we know that there are no assignment levels (because that's not supported anyway). if (preparedModel.hasTransientEdgeDestinationAssignments()) { diff --git a/src/storm/builder/DdJaniModelBuilder.h b/src/storm/builder/DdJaniModelBuilder.h index 23684f4f9..b1fe91f83 100644 --- a/src/storm/builder/DdJaniModelBuilder.h +++ b/src/storm/builder/DdJaniModelBuilder.h @@ -3,6 +3,7 @@ #include <boost/optional.hpp> #include "storm/storage/dd/DdType.h" +#include "storm/storage/jani/Property.h" #include "storm/logic/Formula.h" #include "storm/builder/TerminalStatesGetter.h" @@ -17,13 +18,27 @@ namespace storm { } namespace jani { class Model; + class ModelFeatures; } namespace builder { template <storm::dd::DdType Type, typename ValueType = double> class DdJaniModelBuilder { - public: + public: + + /*! + * Returns the jani features with which this builder can deal natively. + */ + static storm::jani::ModelFeatures getSupportedJaniFeatures(); + + /*! + * A quick check to detect whether the given model is not supported. + * This method only over-approximates the set of models that can be handled, i.e., if this + * returns true, the model might still be unsupported. + */ + static bool canHandle(storm::jani::Model const& model, boost::optional<std::vector<storm::jani::Property>> const& properties = boost::none); + struct Options { /*! * Creates an object representing the default building options. diff --git a/src/storm/builder/DdPrismModelBuilder.cpp b/src/storm/builder/DdPrismModelBuilder.cpp index 4633ebdbc..32de16b91 100644 --- a/src/storm/builder/DdPrismModelBuilder.cpp +++ b/src/storm/builder/DdPrismModelBuilder.cpp @@ -540,7 +540,12 @@ namespace storm { }; template <storm::dd::DdType Type, typename ValueType> - DdPrismModelBuilder<Type, ValueType>::Options::Options() : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild() { + bool DdPrismModelBuilder<Type, ValueType>::canHandle(storm::prism::Program const& program) { + return program.getModelType() != storm::prism::Program::ModelType::PTA; + } + + template <storm::dd::DdType Type, typename ValueType> + DdPrismModelBuilder<Type, ValueType>::Options::Options() : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates() { // Intentionally left empty. } diff --git a/src/storm/builder/DdPrismModelBuilder.h b/src/storm/builder/DdPrismModelBuilder.h index a529f0656..a7f8d56b2 100644 --- a/src/storm/builder/DdPrismModelBuilder.h +++ b/src/storm/builder/DdPrismModelBuilder.h @@ -33,6 +33,13 @@ namespace storm { template <storm::dd::DdType Type, typename ValueType = double> class DdPrismModelBuilder { public: + /*! + * A quick check to detect whether the given model is not supported. + * This method only over-approximates the set of models that can be handled, i.e., if this + * returns true, the model might still be unsupported. + */ + static bool canHandle(storm::prism::Program const& program); + struct Options { /*! * Creates an object representing the default building options. diff --git a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp index eb1b397dc..374f86f73 100644 --- a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp +++ b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp @@ -53,6 +53,33 @@ namespace storm { #ifdef WINDOWS static const std::string DYLIB_EXTENSION = ".dll"; #endif + + template <typename ValueType, typename RewardModelType> + storm::jani::ModelFeatures ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::getSupportedJaniFeatures() { + storm::jani::ModelFeatures features; + features.add(storm::jani::ModelFeature::DerivedOperators); + features.add(storm::jani::ModelFeature::StateExitRewards); + // We do not add Functions and arrays as these should ideally be substituted before creating this generator. + // This is because functions or arrays may also occur in properties and the user of this builder should take care of that. + return features; + } + + template <typename ValueType, typename RewardModelType> + bool ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::canHandle(storm::jani::Model const& model) { + // Check jani features + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::Arrays); // can be substituted + features.remove(storm::jani::ModelFeature::DerivedOperators); + features.remove(storm::jani::ModelFeature::Functions); // can be substituted + features.remove(storm::jani::ModelFeature::StateExitRewards); + if (!features.empty()) { + STORM_LOG_INFO("Jit engine can not build Jani model due to unsupported jani features."); + return false; + } + // There probably are more cases where the model is unsupported. However, checking these is often more involved. + // As this method is supposed to be a quick check, we just return true at this point. + return true; + } template <typename ValueType, typename RewardModelType> ExplicitJitJaniModelBuilder<ValueType, RewardModelType>::ExplicitJitJaniModelBuilder(storm::jani::Model const& model, storm::builder::BuilderOptions const& options) : options(options), model(model.substituteConstantsFunctions()), modelComponentsBuilder(model.getModelType()) { diff --git a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.h b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.h index cb2247d35..5ccf4eec6 100644 --- a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.h +++ b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.h @@ -48,6 +48,18 @@ namespace storm { typedef JitModelBuilderInterface<IndexType, ValueType>* (CreateFunctionType)(ModelComponentsBuilder<IndexType, ValueType>& modelComponentsBuilder); typedef boost::function<CreateFunctionType> ImportCreateFunctionType; + /*! + * Returns the jani features with which this builder can deal natively. + */ + static storm::jani::ModelFeatures getSupportedJaniFeatures(); + + /*! + * A quick check to detect whether the given model is not supported. + * This method only over-approximates the set of models that can be handled, i.e., if this + * returns true, the model might still be unsupported. + */ + static bool canHandle(storm::jani::Model const& model); + /*! * Creates a model builder for the given model. The provided options are used to determine which part of * the model is built. diff --git a/src/storm/environment/SubEnvironment.cpp b/src/storm/environment/SubEnvironment.cpp index feabd5e46..91b4f66dc 100644 --- a/src/storm/environment/SubEnvironment.cpp +++ b/src/storm/environment/SubEnvironment.cpp @@ -10,6 +10,7 @@ #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/LongRunAverageSolverEnvironment.h" +#include "storm/environment/solver/TimeBoundedSolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/environment/solver/OviSolverEnvironment.h" @@ -66,6 +67,7 @@ namespace storm { template class SubEnvironment<GmmxxSolverEnvironment>; template class SubEnvironment<NativeSolverEnvironment>; template class SubEnvironment<LongRunAverageSolverEnvironment>; + template class SubEnvironment<TimeBoundedSolverEnvironment>; template class SubEnvironment<MinMaxSolverEnvironment>; template class SubEnvironment<MultiplierEnvironment>; template class SubEnvironment<OviSolverEnvironment>; diff --git a/src/storm/environment/solver/SolverEnvironment.cpp b/src/storm/environment/solver/SolverEnvironment.cpp index c4402903f..6870d1632 100644 --- a/src/storm/environment/solver/SolverEnvironment.cpp +++ b/src/storm/environment/solver/SolverEnvironment.cpp @@ -1,6 +1,7 @@ #include "storm/environment/solver/SolverEnvironment.h" #include "storm/environment/solver/LongRunAverageSolverEnvironment.h" +#include "storm/environment/solver/TimeBoundedSolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" @@ -23,6 +24,7 @@ namespace storm { SolverEnvironment::SolverEnvironment() { forceSoundness = storm::settings::getModule<storm::settings::modules::GeneralSettings>().isSoundSet(); + forceExact = storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet(); linearEquationSolverType = storm::settings::getModule<storm::settings::modules::CoreSettings>().getEquationSolver(); linearEquationSolverTypeSetFromDefault = storm::settings::getModule<storm::settings::modules::CoreSettings>().isEquationSolverSetFromDefaultValue(); } @@ -39,6 +41,14 @@ namespace storm { return longRunAverageSolverEnvironment.get(); } + TimeBoundedSolverEnvironment& SolverEnvironment::timeBounded() { + return timeBoundedSolverEnvironment.get(); + } + + TimeBoundedSolverEnvironment const& SolverEnvironment::timeBounded() const { + return timeBoundedSolverEnvironment.get(); + } + MinMaxSolverEnvironment& SolverEnvironment::minMax() { return minMaxSolverEnvironment.get(); } @@ -111,6 +121,14 @@ namespace storm { SolverEnvironment::forceSoundness = value; } + bool SolverEnvironment::isForceExact() const { + return forceExact; + } + + void SolverEnvironment::setForceExact(bool value) { + SolverEnvironment::forceExact = value; + } + storm::solver::EquationSolverType const& SolverEnvironment::getLinearEquationSolverType() const { return linearEquationSolverType; } diff --git a/src/storm/environment/solver/SolverEnvironment.h b/src/storm/environment/solver/SolverEnvironment.h index 303a0cc79..b57262423 100644 --- a/src/storm/environment/solver/SolverEnvironment.h +++ b/src/storm/environment/solver/SolverEnvironment.h @@ -15,6 +15,7 @@ namespace storm { class GmmxxSolverEnvironment; class NativeSolverEnvironment; class LongRunAverageSolverEnvironment; + class TimeBoundedSolverEnvironment; class MinMaxSolverEnvironment; class MultiplierEnvironment; class GameSolverEnvironment; @@ -35,6 +36,8 @@ namespace storm { NativeSolverEnvironment const& native() const; LongRunAverageSolverEnvironment& lra(); LongRunAverageSolverEnvironment const& lra() const; + TimeBoundedSolverEnvironment& timeBounded(); + TimeBoundedSolverEnvironment const& timeBounded() const; MinMaxSolverEnvironment& minMax(); MinMaxSolverEnvironment const& minMax() const; MultiplierEnvironment& multiplier(); @@ -48,6 +51,8 @@ namespace storm { bool isForceSoundness() const; void setForceSoundness(bool value); + bool isForceExact() const; + void setForceExact(bool value); storm::solver::EquationSolverType const& getLinearEquationSolverType() const; void setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool isSetFromDefault = false); @@ -63,6 +68,7 @@ namespace storm { SubEnvironment<GameSolverEnvironment> gameSolverEnvironment; SubEnvironment<TopologicalSolverEnvironment> topologicalSolverEnvironment; SubEnvironment<LongRunAverageSolverEnvironment> longRunAverageSolverEnvironment; + SubEnvironment<TimeBoundedSolverEnvironment> timeBoundedSolverEnvironment; SubEnvironment<MinMaxSolverEnvironment> minMaxSolverEnvironment; SubEnvironment<MultiplierEnvironment> multiplierEnvironment; SubEnvironment<OviSolverEnvironment> oviSolverEnvironment; @@ -70,6 +76,7 @@ namespace storm { storm::solver::EquationSolverType linearEquationSolverType; bool linearEquationSolverTypeSetFromDefault; bool forceSoundness; + bool forceExact; }; } diff --git a/src/storm/environment/solver/TimeBoundedSolverEnvironment.cpp b/src/storm/environment/solver/TimeBoundedSolverEnvironment.cpp new file mode 100644 index 000000000..743474e4b --- /dev/null +++ b/src/storm/environment/solver/TimeBoundedSolverEnvironment.cpp @@ -0,0 +1,60 @@ +#include "storm/environment/solver/TimeBoundedSolverEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/TimeBoundedSolverSettings.h" +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + +namespace storm { + + TimeBoundedSolverEnvironment::TimeBoundedSolverEnvironment() { + auto const& tbSettings = storm::settings::getModule<storm::settings::modules::TimeBoundedSolverSettings>(); + maMethod = tbSettings.getMaMethod(); + maMethodSetFromDefault = tbSettings.isMaMethodSetFromDefaultValue(); + precision = storm::utility::convertNumber<storm::RationalNumber>(tbSettings.getPrecision()); + relative = tbSettings.isRelativePrecision(); + unifPlusKappa = tbSettings.getUnifPlusKappa(); + } + + TimeBoundedSolverEnvironment::~TimeBoundedSolverEnvironment() { + // Intentionally left empty + } + + storm::solver::MaBoundedReachabilityMethod const& TimeBoundedSolverEnvironment::getMaMethod() const { + return maMethod; + } + + bool const& TimeBoundedSolverEnvironment::isMaMethodSetFromDefault() const { + return maMethodSetFromDefault; + } + + void TimeBoundedSolverEnvironment::setMaMethod(storm::solver::MaBoundedReachabilityMethod value, bool isSetFromDefault) { + maMethod = value; + maMethodSetFromDefault = isSetFromDefault; + } + + storm::RationalNumber const& TimeBoundedSolverEnvironment::getPrecision() const { + return precision; + } + + void TimeBoundedSolverEnvironment::setPrecision(storm::RationalNumber value) { + precision = value; + } + + bool const& TimeBoundedSolverEnvironment::getRelativeTerminationCriterion() const { + return relative; + } + + void TimeBoundedSolverEnvironment::setRelativeTerminationCriterion(bool value) { + relative = value; + } + + storm::RationalNumber const& TimeBoundedSolverEnvironment::getUnifPlusKappa() const { + return unifPlusKappa; + } + + void TimeBoundedSolverEnvironment::setUnifPlusKappa(storm::RationalNumber value) { + unifPlusKappa = value; + } + +} diff --git a/src/storm/environment/solver/TimeBoundedSolverEnvironment.h b/src/storm/environment/solver/TimeBoundedSolverEnvironment.h new file mode 100644 index 000000000..ddf1d8321 --- /dev/null +++ b/src/storm/environment/solver/TimeBoundedSolverEnvironment.h @@ -0,0 +1,36 @@ +#pragma once + +#include "storm/environment/solver/SolverEnvironment.h" +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + + class TimeBoundedSolverEnvironment { + public: + + TimeBoundedSolverEnvironment(); + ~TimeBoundedSolverEnvironment(); + + storm::solver::MaBoundedReachabilityMethod const& getMaMethod() const; + bool const& isMaMethodSetFromDefault() const; + void setMaMethod(storm::solver::MaBoundedReachabilityMethod value, bool isSetFromDefault = false); + + storm::RationalNumber const& getPrecision() const; + void setPrecision(storm::RationalNumber value); + bool const& getRelativeTerminationCriterion() const; + void setRelativeTerminationCriterion(bool value); + + storm::RationalNumber const& getUnifPlusKappa() const; + void setUnifPlusKappa(storm::RationalNumber value); + + private: + storm::solver::MaBoundedReachabilityMethod maMethod; + bool maMethodSetFromDefault; + + storm::RationalNumber precision; + bool relative; + + storm::RationalNumber unifPlusKappa; + }; +} + diff --git a/src/storm/generator/Choice.cpp b/src/storm/generator/Choice.cpp index 43189e623..5d69c98ab 100644 --- a/src/storm/generator/Choice.cpp +++ b/src/storm/generator/Choice.cpp @@ -163,6 +163,11 @@ namespace storm { return distribution.size(); } + template<typename ValueType, typename StateType> + void Choice<ValueType, StateType>::reserve(std::size_t const& size) { + distribution.reserve(size); + } + template<typename ValueType, typename StateType> std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice) { out << "<"; diff --git a/src/storm/generator/Choice.h b/src/storm/generator/Choice.h index 04e0fd311..1dbc41760 100644 --- a/src/storm/generator/Choice.h +++ b/src/storm/generator/Choice.h @@ -150,6 +150,11 @@ namespace storm { */ std::size_t size() const; + /*! + * If the size is already known, reserves space in the underlying distribution. + */ + void reserve(std::size_t const& size); + private: // A flag indicating whether this choice is Markovian or not. bool markovian; diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index f2b05f74d..6c260746b 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -115,6 +115,34 @@ namespace storm { } } } + + template<typename ValueType, typename StateType> + storm::jani::ModelFeatures JaniNextStateGenerator<ValueType, StateType>::getSupportedJaniFeatures() { + storm::jani::ModelFeatures features; + features.add(storm::jani::ModelFeature::DerivedOperators); + features.add(storm::jani::ModelFeature::StateExitRewards); + features.add(storm::jani::ModelFeature::Arrays); + // We do not add Functions as these should ideally be substituted before creating this generator. + // This is because functions may also occur in properties and the user of this class should take care of that. + return features; + } + + template<typename ValueType, typename StateType> + bool JaniNextStateGenerator<ValueType, StateType>::canHandle(storm::jani::Model const& model) { + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::Arrays); + features.remove(storm::jani::ModelFeature::DerivedOperators); + features.remove(storm::jani::ModelFeature::Functions); // can be substituted + features.remove(storm::jani::ModelFeature::StateExitRewards); + if (!features.empty()) { + STORM_LOG_INFO("The model can not be build as it contains these unsupported features: " << features.toString()); + return false; + } + // There probably are more cases where the model is unsupported. However, checking these is more involved. + // As this method is supposed to be a quick check, we just return true at this point. + return true; + } + template<typename ValueType, typename StateType> ModelType JaniNextStateGenerator<ValueType, StateType>::getModelType() const { @@ -747,8 +775,7 @@ namespace storm { } template<typename ValueType, typename StateType> - std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback) { - std::vector<Choice<ValueType>> result; + void JaniNextStateGenerator<ValueType, StateType>::expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback, std::vector<Choice<ValueType>>& newChoices) { if (this->options.isExplorationChecksSet()) { // Check whether a global variable is written multiple times in any combination. @@ -778,10 +805,10 @@ namespace storm { // At this point, we applied all commands of the current command combination and newTargetStates // contains all target states and their respective probabilities. That means we are now ready to // add the choice to the list of transitions. - result.emplace_back(outputActionIndex); + newChoices.emplace_back(outputActionIndex); // Now create the actual distribution. - Choice<ValueType>& choice = result.back(); + Choice<ValueType>& choice = newChoices.back(); // Add the edge indices if requested. if (this->getOptions().isBuildChoiceOriginsSet()) { @@ -793,6 +820,7 @@ namespace storm { // Add the probabilities/rates to the newly created choice. ValueType probabilitySum = storm::utility::zero<ValueType>(); + choice.reserve(std::distance(distribution.begin(), distribution.end())); for (auto const& stateProbability : distribution) { choice.addProbability(stateProbability.getState(), stateProbability.getValue()); @@ -820,15 +848,19 @@ namespace storm { done = !movedIterator; } - - return result; } template<typename ValueType, typename StateType> std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::getActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback, EdgeFilter const& edgeFilter) { std::vector<Choice<ValueType>> result; - for (auto const& outputAndEdges : edges) { + // To avoid reallocations, we declare some memory here here. + // This vector will store for each automaton the set of edges with the current output and the current source location + std::vector<EdgeSetWithIndices const*> edgeSetsMemory; + // This vector will store the 'first' combination of edges that is productive. + std::vector<typename EdgeSetWithIndices::const_iterator> edgeIteratorMemory; + + for (OutputAndEdges const& outputAndEdges : edges) { auto const& edges = outputAndEdges.second; if (edges.size() == 1) { // If the synch consists of just one element, it's non-synchronizing. @@ -848,61 +880,106 @@ namespace storm { continue; } - Choice<ValueType> choice = expandNonSynchronizingEdge(*indexAndEdge.second, outputAndEdges.first ? outputAndEdges.first.get() : indexAndEdge.second->getActionIndex(), automatonIndex, state, stateToIdCallback); + result.push_back(expandNonSynchronizingEdge(*indexAndEdge.second, outputAndEdges.first ? outputAndEdges.first.get() : indexAndEdge.second->getActionIndex(), automatonIndex, state, stateToIdCallback)); if (this->getOptions().isBuildChoiceOriginsSet()) { EdgeIndexSet edgeIndex { model.encodeAutomatonAndEdgeIndices(automatonIndex, indexAndEdge.first) }; - choice.addOriginData(boost::any(std::move(edgeIndex))); + result.back().addOriginData(boost::any(std::move(edgeIndex))); } - result.emplace_back(std::move(choice)); } } } else { // If the element has more than one set of edges, we need to perform a synchronization. STORM_LOG_ASSERT(outputAndEdges.first, "Need output action index for synchronization."); - AutomataEdgeSets automataEdgeSets; uint64_t outputActionIndex = outputAndEdges.first.get(); + // Find out whether this combination is productive bool productiveCombination = true; + // First check, whether each automaton has at least one edge with the current output and the current source location + // We will also store the edges of each automaton with the current outputAction + edgeSetsMemory.clear(); for (auto const& automatonAndEdges : outputAndEdges.second) { uint64_t automatonIndex = automatonAndEdges.first; - EdgeSetWithIndices enabledEdgesOfAutomaton; - - bool atLeastOneEdge = false; - auto edgesIt = automatonAndEdges.second.find(locations[automatonIndex]); - if (edgesIt != automatonAndEdges.second.end()) { - for (auto const& indexAndEdge : edgesIt->second) { + LocationsAndEdges const& locationsAndEdges = automatonAndEdges.second; + auto edgesIt = locationsAndEdges.find(locations[automatonIndex]); + if (edgesIt == locationsAndEdges.end()) { + productiveCombination = false; + break; + } + edgeSetsMemory.push_back(&edgesIt->second); + } + + if (productiveCombination) { + // second, check whether each automaton has at least one enabled action + edgeIteratorMemory.clear(); // Store the first enabled edge in each automaton. + for (auto const& edgesIt : edgeSetsMemory) { + bool atLeastOneEdge = false; + EdgeSetWithIndices const& edgeSetWithIndices = *edgesIt; + for (auto indexAndEdgeIt = edgeSetWithIndices.begin(), indexAndEdgeIte = edgeSetWithIndices.end(); indexAndEdgeIt != indexAndEdgeIte; ++indexAndEdgeIt) { + // check whether we do not consider this edge if (edgeFilter != EdgeFilter::All) { STORM_LOG_ASSERT(edgeFilter == EdgeFilter::WithRate || edgeFilter == EdgeFilter::WithoutRate, "Unexpected edge filter."); - if ((edgeFilter == EdgeFilter::WithRate) != indexAndEdge.second->hasRate()) { + if ((edgeFilter == EdgeFilter::WithRate) != indexAndEdgeIt->second->hasRate()) { continue; } } - if (!this->evaluator->asBool(indexAndEdge.second->getGuard())) { + + if (!this->evaluator->asBool(indexAndEdgeIt->second->getGuard())) { continue; } + // If we reach this point, the edge is considered enabled. atLeastOneEdge = true; - enabledEdgesOfAutomaton.emplace_back(indexAndEdge); + edgeIteratorMemory.push_back(indexAndEdgeIt); + break; + } + + // If there is no enabled edge of this automaton, the whole combination is not productive. + if (!atLeastOneEdge) { + productiveCombination = false; + break; } } - - // If there is no enabled edge of this automaton, the whole combination is not productive. - if (!atLeastOneEdge) { - productiveCombination = false; - break; - } - - automataEdgeSets.emplace_back(std::make_pair(automatonIndex, std::move(enabledEdgesOfAutomaton))); } + // produce the combination if (productiveCombination) { - std::vector<Choice<ValueType>> choices = expandSynchronizingEdgeCombination(automataEdgeSets, outputActionIndex, state, stateToIdCallback); - - for (auto const& choice : choices) { - result.emplace_back(std::move(choice)); + AutomataEdgeSets automataEdgeSets; + automataEdgeSets.reserve(outputAndEdges.second.size()); + STORM_LOG_ASSERT(edgeSetsMemory.size() == outputAndEdges.second.size(), "Unexpected number of edge sets stored."); + STORM_LOG_ASSERT(edgeIteratorMemory.size() == outputAndEdges.second.size(), "Unexpected number of edge iterators stored."); + auto edgeSetIt = edgeSetsMemory.begin(); + auto edgeIteratorIt = edgeIteratorMemory.begin(); + for (auto const& automatonAndEdges : outputAndEdges.second) { + EdgeSetWithIndices enabledEdgesOfAutomaton; + uint64_t automatonIndex = automatonAndEdges.first; + EdgeSetWithIndices const& edgeSetWithIndices = **edgeSetIt; + auto indexAndEdgeIt = *edgeIteratorIt; + // The first edge where the edgeIterator points to is always enabled. + enabledEdgesOfAutomaton.emplace_back(*indexAndEdgeIt); + auto indexAndEdgeIte = edgeSetWithIndices.end(); + for (++indexAndEdgeIt; indexAndEdgeIt != indexAndEdgeIte; ++indexAndEdgeIt) { + // check whether we do not consider this edge + if (edgeFilter != EdgeFilter::All) { + STORM_LOG_ASSERT(edgeFilter == EdgeFilter::WithRate || edgeFilter == EdgeFilter::WithoutRate, "Unexpected edge filter."); + if ((edgeFilter == EdgeFilter::WithRate) != indexAndEdgeIt->second->hasRate()) { + continue; + } + } + + if (!this->evaluator->asBool(indexAndEdgeIt->second->getGuard())) { + continue; + } + // If we reach this point, the edge is considered enabled. + enabledEdgesOfAutomaton.emplace_back(*indexAndEdgeIt); + } + automataEdgeSets.emplace_back(std::move(automatonIndex), std::move(enabledEdgesOfAutomaton)); + ++edgeSetIt; + ++edgeIteratorIt; } + // insert choices in the result vector. + expandSynchronizingEdgeCombination(automataEdgeSets, outputActionIndex, state, stateToIdCallback, result); } } } diff --git a/src/storm/generator/JaniNextStateGenerator.h b/src/storm/generator/JaniNextStateGenerator.h index 790395faf..74ead73e6 100644 --- a/src/storm/generator/JaniNextStateGenerator.h +++ b/src/storm/generator/JaniNextStateGenerator.h @@ -32,6 +32,18 @@ namespace storm { JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options = NextStateGeneratorOptions()); + /*! + * Returns the jani features with which this builder can deal natively. + */ + static storm::jani::ModelFeatures getSupportedJaniFeatures(); + + /*! + * A quick check to detect whether the given model is not supported. + * This method only over-approximates the set of models that can be handled, i.e., if this + * returns true, the model might still be unsupported. + */ + static bool canHandle(storm::jani::Model const& model); + virtual ModelType getModelType() const override; virtual bool isDeterministicModel() const override; virtual bool isDiscreteTimeModel() const override; @@ -124,7 +136,7 @@ namespace storm { typedef std::pair<uint64_t, EdgeSetWithIndices> AutomatonAndEdgeSet; typedef std::vector<AutomatonAndEdgeSet> AutomataEdgeSets; - std::vector<Choice<ValueType>> expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback); + void expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback, std::vector<Choice<ValueType>>& newChoices); void generateSynchronizedDistribution(storm::storage::BitVector const& state, AutomataEdgeSets const& edgeCombination, std::vector<EdgeSetWithIndices::const_iterator> const& iteratorList, storm::builder::jit::Distribution<StateType, ValueType>& distribution, std::vector<ValueType>& stateActionRewards, EdgeIndexSet& edgeIndices, StateToIdCallback stateToIdCallback); /*! diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp index 68fda0abd..30e55f5bd 100644 --- a/src/storm/generator/PrismNextStateGenerator.cpp +++ b/src/storm/generator/PrismNextStateGenerator.cpp @@ -82,6 +82,12 @@ namespace storm { } } + template<typename ValueType, typename StateType> + bool PrismNextStateGenerator<ValueType, StateType>::canHandle(storm::prism::Program const& program) { + // We can handle all valid prism programs (except for PTAs) + return program.getModelType() != storm::prism::Program::ModelType::PTA; + } + template<typename ValueType, typename StateType> void PrismNextStateGenerator<ValueType, StateType>::checkValid() const { // If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message. diff --git a/src/storm/generator/PrismNextStateGenerator.h b/src/storm/generator/PrismNextStateGenerator.h index 2b9fdc678..b2eb1b555 100644 --- a/src/storm/generator/PrismNextStateGenerator.h +++ b/src/storm/generator/PrismNextStateGenerator.h @@ -24,7 +24,14 @@ namespace storm { enum class CommandFilter {All, Markovian, Probabilistic}; PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options = NextStateGeneratorOptions()); - + + /*! + * A quick check to detect whether the given model is not supported. + * This method only over-approximates the set of models that can be handled, i.e., if this + * returns true, the model might still be unsupported. + */ + static bool canHandle(storm::prism::Program const& program); + virtual ModelType getModelType() const override; virtual bool isDeterministicModel() const override; virtual bool isDiscreteTimeModel() const override; diff --git a/src/storm/logic/FormulaInformation.cpp b/src/storm/logic/FormulaInformation.cpp index a6f471922..50ddf2e76 100644 --- a/src/storm/logic/FormulaInformation.cpp +++ b/src/storm/logic/FormulaInformation.cpp @@ -26,6 +26,10 @@ namespace storm { return this->mContainsRewardBoundedFormula; } + bool FormulaInformation::containsLongRunFormula() const { + return this->mContainsLongRunFormula; + } + FormulaInformation FormulaInformation::join(FormulaInformation const& other) { FormulaInformation result; result.mContainsRewardOperator = this->containsRewardOperator() || other.containsRewardOperator(); @@ -33,6 +37,7 @@ namespace storm { result.mContainsBoundedUntilFormula = this->containsBoundedUntilFormula() || other.containsBoundedUntilFormula(); result.mContainsCumulativeRewardFormula = this->containsCumulativeRewardFormula() || other.containsCumulativeRewardFormula(); result.mContainsRewardBoundedFormula = this->containsRewardBoundedFormula() || other.containsRewardBoundedFormula(); + result.mContainsLongRunFormula = this->containsLongRunFormula() || other.containsLongRunFormula(); return result; } @@ -60,5 +65,10 @@ namespace storm { this->mContainsRewardBoundedFormula = newValue; return *this; } + + FormulaInformation& FormulaInformation::setContainsLongRunFormula(bool newValue) { + this->mContainsLongRunFormula = newValue; + return *this; + } } } diff --git a/src/storm/logic/FormulaInformation.h b/src/storm/logic/FormulaInformation.h index 06e1ff4ea..6c2c320b2 100644 --- a/src/storm/logic/FormulaInformation.h +++ b/src/storm/logic/FormulaInformation.h @@ -17,6 +17,7 @@ namespace storm { bool containsBoundedUntilFormula() const; bool containsCumulativeRewardFormula() const; bool containsRewardBoundedFormula() const; + bool containsLongRunFormula() const; FormulaInformation join(FormulaInformation const& other); @@ -25,6 +26,7 @@ namespace storm { FormulaInformation& setContainsBoundedUntilFormula(bool newValue = true); FormulaInformation& setContainsCumulativeRewardFormula(bool newValue = true); FormulaInformation& setContainsRewardBoundedFormula(bool newValue = true); + FormulaInformation& setContainsLongRunFormula(bool newValue = true); private: bool mContainsRewardOperator; @@ -32,6 +34,7 @@ namespace storm { bool mContainsBoundedUntilFormula; bool mContainsCumulativeRewardFormula; bool mContainsRewardBoundedFormula; + bool mContainsLongRunFormula; }; } diff --git a/src/storm/logic/FormulaInformationVisitor.cpp b/src/storm/logic/FormulaInformationVisitor.cpp index b3ad356db..e4e9a15ed 100644 --- a/src/storm/logic/FormulaInformationVisitor.cpp +++ b/src/storm/logic/FormulaInformationVisitor.cpp @@ -78,11 +78,16 @@ namespace storm { } boost::any FormulaInformationVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { - return f.getSubformula().accept(*this, data); + FormulaInformation result; + result.setContainsLongRunFormula(true); + result.join(boost::any_cast<FormulaInformation>(f.getSubformula().accept(*this, data))); + return result; } boost::any FormulaInformationVisitor::visit(LongRunAverageRewardFormula const&, boost::any const&) const { - return FormulaInformation(); + FormulaInformation result; + result.setContainsLongRunFormula(true); + return result; } boost::any FormulaInformationVisitor::visit(MultiObjectiveFormula const& f, boost::any const& data) const { diff --git a/src/storm/modelchecker/AbstractModelChecker.cpp b/src/storm/modelchecker/AbstractModelChecker.cpp index 2c12639c3..233aa1733 100644 --- a/src/storm/modelchecker/AbstractModelChecker.cpp +++ b/src/storm/modelchecker/AbstractModelChecker.cpp @@ -17,6 +17,7 @@ #include "storm/models/symbolic/Dtmc.h" #include "storm/models/symbolic/Ctmc.h" #include "storm/models/symbolic/Mdp.h" +#include "storm/models/symbolic/MarkovAutomaton.h" #include "storm/models/symbolic/StochasticTwoPlayerGame.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -25,6 +26,7 @@ #include "storm/storage/dd/Bdd.h" #include <boost/core/typeinfo.hpp> +#include <storm/models/symbolic/MarkovAutomaton.h> namespace storm { namespace modelchecker { @@ -360,6 +362,10 @@ namespace storm { template class AbstractModelChecker<storm::models::symbolic::Ctmc<storm::dd::DdType::Sylvan, double>>; template class AbstractModelChecker<storm::models::symbolic::Ctmc<storm::dd::DdType::Sylvan, storm::RationalNumber>>; template class AbstractModelChecker<storm::models::symbolic::Ctmc<storm::dd::DdType::Sylvan, storm::RationalFunction>>; + template class AbstractModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::CUDD, double>>; + template class AbstractModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, double>>; + template class AbstractModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalNumber>>; + template class AbstractModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalFunction>>; template class AbstractModelChecker<storm::models::symbolic::StochasticTwoPlayerGame<storm::dd::DdType::CUDD, double>>; template class AbstractModelChecker<storm::models::symbolic::StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, double>>; template class AbstractModelChecker<storm::models::symbolic::StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, storm::RationalNumber>>; diff --git a/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.cpp b/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.cpp index b41ddaca5..d574de24d 100644 --- a/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.cpp @@ -60,7 +60,7 @@ namespace storm { template<typename ModelType> std::shared_ptr<storm::models::Model<typename BisimulationAbstractionRefinementModelChecker<ModelType>::ValueType>> BisimulationAbstractionRefinementModelChecker<ModelType>::getAbstractModel() { - lastAbstractModel = this->bisimulation->getQuotient(); + lastAbstractModel = this->bisimulation->getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); return lastAbstractModel; } diff --git a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp index b6d65edf0..88f380bd4 100644 --- a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp @@ -24,22 +24,17 @@ namespace storm { } template <typename ModelType> - bool HybridCtmcCslModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { - return HybridCtmcCslModelChecker<ModelType>::canHandleImplementation<ValueType>(checkTask); - } - - template <typename ModelType> - template<typename CValueType, typename std::enable_if<storm::NumberTraits<CValueType>::SupportsExponential, int>::type> - bool HybridCtmcCslModelChecker<ModelType>::canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const { - storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTimeOperatorsAllowed(true).setRewardAccumulationAllowed(true)); + bool HybridCtmcCslModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask) { + auto fragment = storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTimeOperatorsAllowed(true).setRewardAccumulationAllowed(true); + if (!storm::NumberTraits<ValueType>::SupportsExponential) { + fragment.setBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false).setInstantaneousFormulasAllowed(false); + } + return checkTask.getFormula().isInFragment(fragment); } template <typename ModelType> - template<typename CValueType, typename std::enable_if<!storm::NumberTraits<CValueType>::SupportsExponential, int>::type> - bool HybridCtmcCslModelChecker<ModelType>::canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const { - storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTimeOperatorsAllowed(true).setBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false).setInstantaneousFormulasAllowed(false)); + bool HybridCtmcCslModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + return canHandleStatic(checkTask); } template<typename ModelType> diff --git a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h index eaa55d42e..f266e9fe4 100644 --- a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h +++ b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h @@ -20,6 +20,9 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit HybridCtmcCslModelChecker(ModelType const& model); + + // Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; @@ -33,14 +36,7 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override; - - private: - template<typename CValueType = ValueType, typename std::enable_if<storm::NumberTraits<CValueType>::SupportsExponential, int>::type = 0> - bool canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const; - - template<typename CValueType = ValueType, typename std::enable_if<!storm::NumberTraits<CValueType>::SupportsExponential, int>::type = 0> - bool canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const; - + }; } // namespace modelchecker diff --git a/src/storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.cpp b/src/storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.cpp new file mode 100644 index 000000000..8cec970c6 --- /dev/null +++ b/src/storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.cpp @@ -0,0 +1,126 @@ +#include "storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.h" + +#include "storm/models/symbolic/StandardRewardModel.h" + +#include "storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h" +#include "storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.h" +#include "storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h" + +#include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" + +#include "storm/storage/dd/DdManager.h" +#include "storm/storage/dd/Add.h" +#include "storm/storage/dd/Bdd.h" +#include "storm/utility/FilteredRewardModel.h" + +#include "storm/logic/FragmentSpecification.h" + +#include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/InvalidPropertyException.h" + +namespace storm { + namespace modelchecker { + template<typename ModelType> + HybridMarkovAutomatonCslModelChecker<ModelType>::HybridMarkovAutomatonCslModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker<ModelType>(model) { + // Intentionally left empty. + } + + template <typename ModelType> + bool HybridMarkovAutomatonCslModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask) { + auto singleObjectiveFragment = storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(false).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true).setRewardAccumulationAllowed(true).setInstantaneousFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false); + if (!storm::NumberTraits<ValueType>::SupportsExponential) { + singleObjectiveFragment.setBoundedUntilFormulasAllowed(false); + } + return checkTask.getFormula().isInFragment(singleObjectiveFragment); + } + + template <typename ModelType> + bool HybridMarkovAutomatonCslModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + return canHandleStatic(checkTask); + } + + template<typename ModelType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslModelChecker<ModelType>::computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); + std::unique_ptr<CheckResult> leftResultPointer = this->check(env, pathFormula.getLeftSubformula()); + std::unique_ptr<CheckResult> rightResultPointer = this->check(env, pathFormula.getRightSubformula()); + SymbolicQualitativeCheckResult<DdType> const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult<DdType>(); + SymbolicQualitativeCheckResult<DdType> const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult<DdType>(); + + return storm::modelchecker::helper::HybridMdpPrctlHelper<DdType, ValueType>::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + } + + template<typename ModelType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslModelChecker<ModelType>::computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr<CheckResult> subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>(); + auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); + return storm::modelchecker::helper::HybridMarkovAutomatonCslHelper::computeReachabilityRewards<DdType, ValueType>(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getMarkovianStates(), this->getModel().getExitRateVector(), rewardModel.get(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + } + + template<typename ModelType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslModelChecker<ModelType>::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr<CheckResult> subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>(); + + storm::models::symbolic::StandardRewardModel<DdType, ValueType> timeRewardModel(this->getModel().getManager().getConstant(storm::utility::one<ValueType>()), boost::none, boost::none); + return storm::modelchecker::helper::HybridMarkovAutomatonCslHelper::computeReachabilityRewards<DdType, ValueType>(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getMarkovianStates(), this->getModel().getExitRateVector(), timeRewardModel, subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + } + + template<typename ModelType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslModelChecker<ModelType>::computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) { + storm::logic::BoundedUntilFormula const& pathFormula = checkTask.getFormula(); + std::unique_ptr<CheckResult> leftResultPointer = this->check(env, pathFormula.getLeftSubformula()); + SymbolicQualitativeCheckResult<DdType> const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult<DdType>(); + + std::unique_ptr<CheckResult> rightResultPointer = this->check(env, pathFormula.getRightSubformula()); + SymbolicQualitativeCheckResult<DdType> const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult<DdType>(); + + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + STORM_LOG_THROW(pathFormula.getTimeBoundReference().isTimeBound(), storm::exceptions::NotImplementedException, "Currently step-bounded and reward-bounded properties on MarkovAutomatons are not supported."); + double lowerBound = 0; + double upperBound = 0; + if (pathFormula.hasLowerBound()) { + lowerBound = pathFormula.getLowerBound<double>(); + } + if (pathFormula.hasUpperBound()) { + upperBound = pathFormula.getNonStrictUpperBound<double>(); + } else { + upperBound = storm::utility::infinity<double>(); + } + + return storm::modelchecker::helper::HybridMarkovAutomatonCslHelper::computeBoundedUntilProbabilities<DdType, ValueType>(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getMarkovianStates(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), lowerBound, upperBound); + } + + template<typename ModelType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslModelChecker<ModelType>::computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) { + storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); + std::unique_ptr<CheckResult> subResultPointer = this->check(env, stateFormula); + SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + + return storm::modelchecker::helper::HybridMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getMarkovianStates(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector()); + + } + + template<typename ModelType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslModelChecker<ModelType>::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula, ValueType> const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); + return storm::modelchecker::helper::HybridMarkovAutomatonCslHelper::computeLongRunAverageRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getMarkovianStates(), this->getModel().getExitRateVector(), rewardModel.get()); + } + + // Explicitly instantiate the model checker. + template class HybridMarkovAutomatonCslModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::CUDD, double>>; + template class HybridMarkovAutomatonCslModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, double>>; + + template class HybridMarkovAutomatonCslModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalNumber>>; + + } // namespace modelchecker +} // namespace storm diff --git a/src/storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.h b/src/storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.h new file mode 100644 index 000000000..da765ddd8 --- /dev/null +++ b/src/storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.h @@ -0,0 +1,36 @@ +#pragma once + +#include "storm/modelchecker/propositional/SymbolicPropositionalModelChecker.h" + +#include "storm/models/symbolic/MarkovAutomaton.h" + +#include "storm/solver/LinearEquationSolver.h" + +#include "storm/utility/NumberTraits.h" + +namespace storm { + + namespace modelchecker { + + template<typename ModelType> + class HybridMarkovAutomatonCslModelChecker : public SymbolicPropositionalModelChecker<ModelType> { + public: + typedef typename ModelType::ValueType ValueType; + static const storm::dd::DdType DdType = ModelType::DdType; + + explicit HybridMarkovAutomatonCslModelChecker(ModelType const& model); + + // The implemented methods of the AbstractModelChecker interface. + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask); + virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; + virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) override; + virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula, ValueType> const& checkTask) override; + + }; + + } // namespace modelchecker +} // namespace storm diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp index 05555b125..10f1600bc 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp @@ -29,23 +29,18 @@ namespace storm { // Intentionally left empty. } - template <typename SparseCtmcModelType> - bool SparseCtmcCslModelChecker<SparseCtmcModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { - return SparseCtmcCslModelChecker<SparseCtmcModelType>::canHandleImplementation<ValueType>(checkTask); - } - - template <typename SparseCtmcModelType> - template<typename CValueType, typename std::enable_if<storm::NumberTraits<CValueType>::SupportsExponential, int>::type> - bool SparseCtmcCslModelChecker<SparseCtmcModelType>::canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const { - storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTotalRewardFormulasAllowed(true).setRewardAccumulationAllowed(true)); + template <typename ModelType> + bool SparseCtmcCslModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask) { + auto fragment = storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTimeOperatorsAllowed(true).setTotalRewardFormulasAllowed(true).setRewardAccumulationAllowed(true); + if (!storm::NumberTraits<ValueType>::SupportsExponential) { + fragment.setBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false).setInstantaneousFormulasAllowed(false); + } + return checkTask.getFormula().isInFragment(fragment); } template <typename SparseCtmcModelType> - template<typename CValueType, typename std::enable_if<!storm::NumberTraits<CValueType>::SupportsExponential, int>::type> - bool SparseCtmcCslModelChecker<SparseCtmcModelType>::canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const { - storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTotalRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false).setInstantaneousFormulasAllowed(false)); + bool SparseCtmcCslModelChecker<SparseCtmcModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + return canHandleStatic(checkTask); } template <typename SparseCtmcModelType> diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h index d7f432f53..bdb896a7b 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h @@ -21,6 +21,9 @@ namespace storm { explicit SparseCtmcCslModelChecker(SparseCtmcModelType const& model); + // Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; @@ -40,13 +43,6 @@ namespace storm { */ std::vector<ValueType> computeAllTransientProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask); - private: - template<typename CValueType = ValueType, typename std::enable_if<storm::NumberTraits<CValueType>::SupportsExponential, int>::type = 0> - bool canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const; - - template<typename CValueType = ValueType, typename std::enable_if<!storm::NumberTraits<CValueType>::SupportsExponential, int>::type = 0> - bool canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const; - }; } // namespace modelchecker diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index 28e2444d5..10e3355f9 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -11,6 +11,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" +#include "storm/solver/SolveGoal.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" @@ -27,38 +28,31 @@ namespace storm { // Intentionally left empty. } - template<typename SparseMarkovAutomatonModelType> - bool SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { - return SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::canHandleImplementation<ValueType>(checkTask); - } - - template <typename SparseMarkovAutomatonModelType> - template<typename CValueType, typename std::enable_if<storm::NumberTraits<CValueType>::SupportsExponential, int>::type> - bool SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const { - storm::logic::Formula const& formula = checkTask.getFormula(); - if(formula.isInFragment(storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true).setRewardAccumulationAllowed(true))) { + template <typename ModelType> + bool SparseMarkovAutomatonCslModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState) { + auto singleObjectiveFragment = storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true).setRewardAccumulationAllowed(true).setInstantaneousFormulasAllowed(false); + auto multiObjectiveFragment = storm::logic::multiObjective().setTimeAllowed(true).setTimeBoundedUntilFormulasAllowed(true); + if (!storm::NumberTraits<ValueType>::SupportsExponential) { + singleObjectiveFragment.setBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false); + multiObjectiveFragment.setTimeBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false); + } + if (checkTask.getFormula().isInFragment(singleObjectiveFragment)) { return true; - } else { - // Check whether we consider a multi-objective formula - // For multi-objective model checking, each initial state requires an individual scheduler (in contrast to single objective model checking). Let's exclude multiple initial states. - if (this->getModel().getInitialStates().getNumberOfSetBits() > 1) return false; - if (!checkTask.isOnlyInitialStatesRelevantSet()) return false; - return formula.isInFragment(storm::logic::multiObjective().setTimeAllowed(true).setTimeBoundedUntilFormulasAllowed(true)); + } else if (checkTask.isOnlyInitialStatesRelevantSet() && checkTask.getFormula().isInFragment(multiObjectiveFragment)) { + if (requiresSingleInitialState) { + *requiresSingleInitialState = true; + } } + return false; } - template <typename SparseMarkovAutomatonModelType> - template<typename CValueType, typename std::enable_if<!storm::NumberTraits<CValueType>::SupportsExponential, int>::type> - bool SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const { - storm::logic::Formula const& formula = checkTask.getFormula(); - if(formula.isInFragment(storm::logic::prctl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false).setInstantaneousFormulasAllowed(false))) { - return true; + template<typename SparseMarkovAutomatonModelType> + bool SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool requiresSingleInitialState = false; + if (canHandleStatic(checkTask, &requiresSingleInitialState)) { + return !requiresSingleInitialState || this->getModel().getInitialStates().getNumberOfSetBits() == 1; } else { - // Check whether we consider a multi-objective formula - // For multi-objective model checking, each initial state requires an individual scheduler (in contrast to single objective model checking). Let's exclude multiple initial states. - if (this->getModel().getInitialStates().getNumberOfSetBits() > 1) return false; - if (!checkTask.isOnlyInitialStatesRelevantSet()) return false; - return formula.isInFragment(storm::logic::multiObjective().setTimeAllowed(true).setTimeBoundedUntilFormulasAllowed(false).setCumulativeRewardFormulasAllowed(false).setInstantaneousFormulasAllowed(false)); + return false; } } @@ -66,11 +60,13 @@ namespace storm { std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) { storm::logic::BoundedUntilFormula const& pathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); - STORM_LOG_THROW(pathFormula.getLeftSubformula().isTrueFormula(), storm::exceptions::NotImplementedException, "Only bounded properties of the form 'true U[t1, t2] phi' are currently supported."); STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute time-bounded reachability probabilities in non-closed Markov automaton."); std::unique_ptr<CheckResult> rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); + std::unique_ptr<CheckResult> leftResultPointer = this->check(env, pathFormula.getLeftSubformula()); + ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); + STORM_LOG_THROW(pathFormula.getTimeBoundReference().isTimeBound(), storm::exceptions::NotImplementedException, "Currently step-bounded and reward-bounded properties on MAs are not supported."); double lowerBound = 0; double upperBound = 0; @@ -83,7 +79,7 @@ namespace storm { upperBound = storm::utility::infinity<double>(); } - std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound)); + std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound)); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result))); } diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h index 3bd220449..f18f4a374 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h @@ -19,6 +19,12 @@ namespace storm { explicit SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model); + /*! + * Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + * @param requiresSingleInitialState if not nullptr, this flag is set to true iff checking this formula requires a model with a single initial state + */ + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState = nullptr); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; @@ -29,13 +35,6 @@ namespace storm { virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> checkMultiObjectiveFormula(Environment const& env, CheckTask<storm::logic::MultiObjectiveFormula, ValueType> const& checkTask) override; - - private: - template<typename CValueType = ValueType, typename std::enable_if<storm::NumberTraits<CValueType>::SupportsExponential, int>::type = 0> - bool canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const; - - template<typename CValueType = ValueType, typename std::enable_if<!storm::NumberTraits<CValueType>::SupportsExponential, int>::type = 0> - bool canHandleImplementation(CheckTask<storm::logic::Formula, CValueType> const& checkTask) const; }; } } diff --git a/src/storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.cpp new file mode 100644 index 000000000..d09a0e58a --- /dev/null +++ b/src/storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.cpp @@ -0,0 +1,150 @@ +#include "storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.h" + +#include "storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h" +#include "storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h" + +#include "storm/storage/dd/DdManager.h" +#include "storm/storage/dd/Add.h" +#include "storm/storage/dd/Bdd.h" + +#include "storm/utility/macros.h" +#include "storm/utility/graph.h" +#include "storm/utility/constants.h" +#include "storm/solver/SolveGoal.h" + +#include "storm/models/symbolic/StandardRewardModel.h" + +#include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" +#include "storm/modelchecker/results/SymbolicQuantitativeCheckResult.h" +#include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" + +#include "storm/utility/Stopwatch.h" + +#include "storm/exceptions/InvalidOperationException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace modelchecker { + namespace helper { + + template<storm::dd::DdType DdType, class ValueType> + void discretizeRewardModel(typename storm::models::symbolic::Model<DdType, ValueType>::RewardModelType& rewardModel, storm::dd::Add<DdType, ValueType> const& exitRateVector, storm::dd::Bdd<DdType> const& markovianStates) { + if (rewardModel.hasStateRewards()) { + rewardModel.getStateRewardVector() *= markovianStates.ite(exitRateVector.getDdManager().template getAddOne<ValueType>() / exitRateVector, exitRateVector.getDdManager().template getAddZero<ValueType>()); + } + } + + + template<storm::dd::DdType DdType, class ValueType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, typename storm::models::symbolic::Model<DdType, ValueType>::RewardModelType const& rewardModel, storm::dd::Bdd<DdType> const& targetStates, bool qualitative) { + + auto discretizedRewardModel = rewardModel; + discretizeRewardModel(discretizedRewardModel, exitRateVector, markovianStates); + return HybridMdpPrctlHelper<DdType, ValueType>::computeReachabilityRewards(env, dir, model, transitionMatrix, discretizedRewardModel, targetStates, qualitative); + } + + + + template<storm::dd::DdType DdType, typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, storm::dd::Bdd<DdType> const& phiStates, storm::dd::Bdd<DdType> const& psiStates, bool qualitative, double lowerBound, double upperBound) { + // If the time bounds are [0, inf], we rather call untimed reachability. + if (storm::utility::isZero(lowerBound) && upperBound == storm::utility::infinity<ValueType>()) { + return storm::modelchecker::helper::HybridMdpPrctlHelper<DdType, ValueType>::computeUntilProbabilities(env, dir, model, transitionMatrix, phiStates, psiStates, qualitative); + } + // If the interval is of the form [0,0], we can return the result directly + if (storm::utility::isZero(upperBound)) { + // In this case, the interval is of the form [0, 0]. + return std::unique_ptr<CheckResult>(new SymbolicQuantitativeCheckResult<DdType, ValueType>(model.getReachableStates(), psiStates.template toAdd<ValueType>())); + } + + // If we reach this point, we convert this query to an instance for the sparse engine. + storm::utility::Stopwatch conversionWatch(true); + // Create ODD for the translation. + storm::dd::Odd odd = model.getReachableStates().createOdd(); + storm::storage::SparseMatrix<ValueType> explicitTransitionMatrix = transitionMatrix.toMatrix(model.getNondeterminismVariables(), odd, odd); + std::vector<ValueType> explicitExitRateVector = exitRateVector.toVector(odd); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + auto explicitResult = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal<ValueType>(dir), explicitTransitionMatrix, explicitExitRateVector, markovianStates.toVector(odd), phiStates.toVector(odd), psiStates.toVector(odd), {lowerBound, upperBound}); + return std::unique_ptr<CheckResult>(new HybridQuantitativeCheckResult<DdType, ValueType>(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero<ValueType>(), model.getReachableStates(), std::move(odd), std::move(explicitResult))); + } + + template<storm::dd::DdType DdType, typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const&, OptimizationDirection, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const&, storm::dd::Add<DdType, ValueType> const&, storm::dd::Bdd<DdType> const&, storm::dd::Add<DdType, ValueType> const&, storm::dd::Bdd<DdType> const&, storm::dd::Bdd<DdType> const&, bool, double, double) { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); + + } + + template<storm::dd::DdType DdType, class ValueType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, storm::dd::Bdd<DdType> const& psiStates) { + + // Convert this query to an instance for the sparse engine. + storm::utility::Stopwatch conversionWatch(true); + // Create ODD for the translation. + storm::dd::Odd odd = model.getReachableStates().createOdd(); + storm::storage::SparseMatrix<ValueType> explicitTransitionMatrix = transitionMatrix.toMatrix(model.getNondeterminismVariables(), odd, odd); + std::vector<ValueType> explicitExitRateVector = exitRateVector.toVector(odd); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + auto explicitResult = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(env, dir, explicitTransitionMatrix, explicitTransitionMatrix.transpose(true), explicitExitRateVector, markovianStates.toVector(odd), psiStates.toVector(odd)); + return std::unique_ptr<CheckResult>(new HybridQuantitativeCheckResult<DdType, ValueType>(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero<ValueType>(), model.getReachableStates(), std::move(odd), std::move(explicitResult))); + + } + + template<storm::dd::DdType DdType, class ValueType> + std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, typename storm::models::symbolic::Model<DdType, ValueType>::RewardModelType const& rewardModel) { + + // Convert this query to an instance for the sparse engine. + storm::utility::Stopwatch conversionWatch(true); + // Create ODD for the translation. + storm::dd::Odd odd = model.getReachableStates().createOdd(); + std::vector<ValueType> explicitExitRateVector = exitRateVector.toVector(odd); + storm::storage::SparseMatrix<ValueType> explicitTransitionMatrix; + boost::optional<std::vector<ValueType>> optionalStateRewards, optionalStateActionRewards; + if (rewardModel.hasStateRewards()) { + optionalStateRewards = rewardModel.getStateRewardVector().toVector(odd); + } + if (rewardModel.hasStateActionRewards()) { + auto matrixRewards = transitionMatrix.toMatrixVector(rewardModel.getStateActionRewardVector(), model.getNondeterminismVariables(), odd, odd); + explicitTransitionMatrix = std::move(matrixRewards.first); + optionalStateActionRewards = std::move(matrixRewards.second); + } else { + explicitTransitionMatrix = transitionMatrix.toMatrix(model.getNondeterminismVariables(), odd, odd); + } + STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotSupportedException, "Transition rewards are not supported in this engine."); + storm::models::sparse::StandardRewardModel<ValueType> explicitRewardModel(optionalStateRewards, optionalStateActionRewards); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + auto explicitResult = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(env, dir, explicitTransitionMatrix, explicitTransitionMatrix.transpose(true), explicitExitRateVector, markovianStates.toVector(odd), explicitRewardModel); + return std::unique_ptr<CheckResult>(new HybridQuantitativeCheckResult<DdType, ValueType>(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero<ValueType>(), model.getReachableStates(), std::move(odd), std::move(explicitResult))); + + } + + // Explicit instantiations. + + // Cudd, double. + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::CUDD, double> const& model, storm::dd::Add<storm::dd::DdType::CUDD, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::CUDD> const& markovianStates, storm::dd::Add<storm::dd::DdType::CUDD, double> const& exitRateVector, typename storm::models::symbolic::Model<storm::dd::DdType::CUDD, double>::RewardModelType const& rewardModel, storm::dd::Bdd<storm::dd::DdType::CUDD> const& targetStates, bool qualitative); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::CUDD, double> const& model, storm::dd::Add<storm::dd::DdType::CUDD, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::CUDD> const& markovianStates, storm::dd::Add<storm::dd::DdType::CUDD, double> const& exitRateVector, storm::dd::Bdd<storm::dd::DdType::CUDD> const& phiStates, storm::dd::Bdd<storm::dd::DdType::CUDD> const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::CUDD, double> const& model, storm::dd::Add<storm::dd::DdType::CUDD, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::CUDD> const& markovianStates, storm::dd::Add<storm::dd::DdType::CUDD, double> const& exitRateVector, storm::dd::Bdd<storm::dd::DdType::CUDD> const& psiStates); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::CUDD, double> const& model, storm::dd::Add<storm::dd::DdType::CUDD, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::CUDD> const& markovianStates, storm::dd::Add<storm::dd::DdType::CUDD, double> const& exitRateVector, typename storm::models::symbolic::Model<storm::dd::DdType::CUDD, double>::RewardModelType const& rewardModel); + + // Sylvan, double. + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, double> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& exitRateVector, typename storm::models::symbolic::Model<storm::dd::DdType::Sylvan, double>::RewardModelType const& rewardModel, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& targetStates, bool qualitative); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, double> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& exitRateVector, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& phiStates, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, double> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& exitRateVector, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& psiStates); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, double> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, double> const& exitRateVector, typename storm::models::symbolic::Model<storm::dd::DdType::Sylvan, double>::RewardModelType const& rewardModel); + + // Sylvan, rational number. + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalNumber> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& exitRateVector, typename storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalNumber>::RewardModelType const& rewardModel, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& targetStates, bool qualitative); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalNumber> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& exitRateVector, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& phiStates, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalNumber> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& exitRateVector, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& psiStates); + template std::unique_ptr<CheckResult> HybridMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalNumber> const& model, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& transitionMatrix, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& markovianStates, storm::dd::Add<storm::dd::DdType::Sylvan, storm::RationalNumber> const& exitRateVector, typename storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalNumber>::RewardModelType const& rewardModel); + + + } + } +} diff --git a/src/storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.h new file mode 100644 index 000000000..45a82c0ff --- /dev/null +++ b/src/storm/modelchecker/csl/helper/HybridMarkovAutomatonCslHelper.h @@ -0,0 +1,42 @@ +#pragma once + +#include <memory> + +#include "storm/models/symbolic/MarkovAutomaton.h" + +#include "storm/modelchecker/results/CheckResult.h" + +#include "storm/utility/NumberTraits.h" +#include "storm/solver/OptimizationDirection.h" + +namespace storm { + + class Environment; + + namespace modelchecker { + namespace helper { + + class HybridMarkovAutomatonCslHelper { + public: + template<storm::dd::DdType DdType, typename ValueType> + static std::unique_ptr<CheckResult> computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, typename storm::models::symbolic::Model<DdType, ValueType>::RewardModelType const& rewardModel, storm::dd::Bdd<DdType> const& targetStates, bool qualitative); + + template<storm::dd::DdType DdType, typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0> + static std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, storm::dd::Bdd<DdType> const& phiStates, storm::dd::Bdd<DdType> const& psiStates, bool qualitative, double lowerBound, double upperBound); + + template<storm::dd::DdType DdType, typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0> + static std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, storm::dd::Bdd<DdType> const& phiStates, storm::dd::Bdd<DdType> const& psiStates, bool qualitative, double lowerBound, double upperBound); + + template<storm::dd::DdType DdType, typename ValueType> + static std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, storm::dd::Bdd<DdType> const& psiStates); + + template<storm::dd::DdType DdType, typename ValueType> + static std::unique_ptr<CheckResult> computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& markovianStates, storm::dd::Add<DdType, ValueType> const& exitRateVector, typename storm::models::symbolic::Model<DdType, ValueType>::RewardModelType const& rewardModel); + + + }; + + } + } +} + diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 6d82a6d79..5911b4044 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -576,7 +576,7 @@ namespace storm { } storm::solver::LraMethod method = env.solver().lra().getDetLraMethod(); - if (storm::NumberTraits<ValueType>::IsExact && env.solver().lra().isDetLraMethodSetFromDefault() && method == storm::solver::LraMethod::ValueIteration) { + if ((storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()) && env.solver().lra().isDetLraMethodSetFromDefault() && method == storm::solver::LraMethod::ValueIteration) { method = storm::solver::LraMethod::GainBiasEquations; STORM_LOG_INFO("Selecting " << storm::solver::toString(method) << " as the solution technique for long-run properties to guarantee exact results. If you want to override this, please explicitly specify a different LRA method."); } else if (env.solver().isForceSoundness() && env.solver().lra().isDetLraMethodSetFromDefault() && method != storm::solver::LraMethod::ValueIteration) { diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 2a39daf3c..df9c20682 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -16,6 +16,7 @@ #include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/environment/solver/LongRunAverageSolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" +#include "storm/environment/solver/TimeBoundedSolverEnvironment.h" #include "storm/utility/macros.h" #include "storm/utility/vector.h" @@ -26,6 +27,7 @@ #include "storm/storage/expressions/Expression.h" #include "storm/storage/expressions/ExpressionManager.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/MinMaxLinearEquationSolver.h" #include "storm/solver/LpSolver.h" @@ -37,391 +39,386 @@ namespace storm { namespace modelchecker { namespace helper { - - /** - * Data structure holding result vectors (vLower, vUpper, wUpper) for Unif+. - */ - template<typename ValueType> - struct UnifPlusVectors { - UnifPlusVectors() { - // Intentionally empty - } - - /** - * Initialize results vectors. vLowerOld, vUpperOld and wUpper[k=N] are initialized with zeros. - */ - UnifPlusVectors(uint64_t steps, uint64_t noStates) : numberOfStates(noStates), steps(steps), resLowerOld(numberOfStates, storm::utility::zero<ValueType>()), resLowerNew(numberOfStates, -1), resUpper(numberOfStates, storm::utility::zero<ValueType>()), wUpperOld(numberOfStates, storm::utility::zero<ValueType>()), wUpperNew(numberOfStates, -1) { - // Intentionally left empty - } - - /** - * Prepare new iteration by setting the new result vectors as old result vectors, and initializing the new result vectors with -1 again. - */ - void prepareNewIteration() { - resLowerOld.swap(resLowerNew); - std::fill(resLowerNew.begin(), resLowerNew.end(), -1); - wUpperOld.swap(wUpperNew); - std::fill(wUpperNew.begin(), wUpperNew.end(), -1); - } - - uint64_t numberOfStates; - uint64_t steps; - std::vector<ValueType> resLowerOld; - std::vector<ValueType> resLowerNew; - std::vector<ValueType> resUpper; - std::vector<ValueType> wUpperOld; - std::vector<ValueType> wUpperNew; - }; template<typename ValueType> - void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t state, bool calcLower, ValueType lambda, uint64_t numberOfProbabilisticChoices, std::vector<std::vector<ValueType>> const & relativeReachability, OptimizationDirection dir, UnifPlusVectors<ValueType>& unifVectors, storm::storage::SparseMatrix<ValueType> const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> const& solver, storm::utility::numerical::FoxGlynnResult<ValueType> const& poisson, bool cycleFree) { - // Set reference to acutal vector - std::vector<ValueType>& resVectorOld = calcLower ? unifVectors.resLowerOld : unifVectors.wUpperOld; - std::vector<ValueType>& resVectorNew = calcLower ? unifVectors.resLowerNew : unifVectors.wUpperNew; - - if (resVectorNew[state] != -1) { - // Result already calculated. - return; - } - - auto numberOfStates = fullTransitionMatrix.getRowGroupCount(); - uint64_t N = unifVectors.steps; - auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - ValueType res; - - // First case, k==N, independent from kind of state. - if (k == N) { - STORM_LOG_ASSERT(false, "Result for k=N was already calculated."); - resVectorNew[state] = storm::utility::zero<ValueType>(); - return; + class UnifPlusHelper { + public: + UnifPlusHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates) : transitionMatrix(transitionMatrix), exitRateVector(exitRateVector), markovianStates(markovianStates) { + // Intentionally left empty } - // Goal state, independent from kind of state. - if (psiStates[state]) { - if (calcLower) { - // v lower - res = storm::utility::zero<ValueType>(); - for (uint64_t i = k; i < N; ++i){ - if (i >= poisson.left && i <= poisson.right) { - res += poisson.weights[i - poisson.left]; - } - } - resVectorNew[state] = res; - } else { - // w upper - resVectorNew[state] = storm::utility::one<ValueType>(); + std::vector<ValueType> computeBoundedUntilProbabilities(storm::Environment const& env, OptimizationDirection dir, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, ValueType const& upperTimeBound, boost::optional<storm::storage::BitVector> const& relevantStates = boost::none) { + // Since there is no lower time bound, we can treat the psiStates as if they are absorbing. + + // Compute some important subsets of states + storm::storage::BitVector maybeStates = ~(getProb0States(dir, phiStates, psiStates) | psiStates); + storm::storage::BitVector markovianMaybeStates = markovianStates & maybeStates; + storm::storage::BitVector probabilisticMaybeStates = ~markovianStates & maybeStates; + storm::storage::BitVector markovianStatesModMaybeStates = markovianMaybeStates % maybeStates; + storm::storage::BitVector probabilisticStatesModMaybeStates = probabilisticMaybeStates % maybeStates; + boost::optional<storm::storage::BitVector> relevantMaybeStates; + if (relevantStates) { + relevantMaybeStates = relevantStates.get() % maybeStates; } - return; - } - + // Catch the case where this is query can be solved by solving the untimed variant instead. + // This is the case if there is no Markovian maybe state (e.g. if the initial state is already a psi state) of if the time bound is infinity. + if (markovianMaybeStates.empty() || storm::utility::isInfinity(upperTimeBound)) { + return SparseMarkovAutomatonCslHelper::computeUntilProbabilities<ValueType>(env, dir, transitionMatrix, transitionMatrix.transpose(true), phiStates, psiStates, false, false).values; + } + + // Get the exit rates restricted to only markovian maybe states. + std::vector<ValueType> markovianExitRates = storm::utility::vector::filterVector(exitRateVector, markovianMaybeStates); + + // Obtain parameters of the algorithm + // Truncation error + ValueType kappa = storm::utility::convertNumber<ValueType>(env.solver().timeBounded().getUnifPlusKappa()); + // Precision to be achieved + ValueType epsilon = storm::utility::convertNumber<ValueType>(2.0) * storm::utility::convertNumber<ValueType>(env.solver().timeBounded().getPrecision()); + bool relativePrecision = env.solver().timeBounded().getRelativeTerminationCriterion(); + // Uniformization rate + ValueType lambda = *std::max_element(markovianExitRates.begin(), markovianExitRates.end()); + STORM_LOG_DEBUG("Initial lambda is " << lambda << "."); - // Markovian non-goal state. - if (markovianStates[state]) { - res = storm::utility::zero<ValueType>(); - for (auto const& element : fullTransitionMatrix.getRow(rowGroupIndices[state])) { - uint64_t successor = element.getColumn(); - if (resVectorOld[successor] == -1) { - STORM_LOG_ASSERT(false, "Need to calculate previous result."); - calculateUnifPlusVector(env, k+1, successor, calcLower, lambda, numberOfProbabilisticChoices, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); - } - res += element.getValue() * resVectorOld[successor]; + // Split the transitions into various part + // The (uniformized) probabilities to go from a Markovian state to a psi state in one step + std::vector<std::pair<uint64_t, ValueType>> markovianToPsiProbabilities = getSparseOneStepProbabilities(markovianMaybeStates, psiStates); + for (auto& entry : markovianToPsiProbabilities) { + entry.second *= markovianExitRates[entry.first] / lambda; } - resVectorNew[state]=res; - return; - } - - // Probabilistic non-goal state. - if (cycleFree) { - // If the model is cycle free, do "slight value iteration". (What is that?) - res = -1; - for (uint64_t i = rowGroupIndices[state]; i < rowGroupIndices[state + 1]; ++i) { - auto row = fullTransitionMatrix.getRow(i); - ValueType between = storm::utility::zero<ValueType>(); - for (auto const& element : row) { - uint64_t successor = element.getColumn(); - - // This should never happen, right? The model has no cycles, and therefore also no self-loops. - if (successor == state) { - continue; - } - - if (resVectorNew[successor] == -1) { - calculateUnifPlusVector(env, k, successor, calcLower, lambda, numberOfProbabilisticChoices, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + // Uniformized transitions from Markovian maybe states to all other maybe states. Inserts selfloop entries. + storm::storage::SparseMatrix<ValueType> markovianToMaybeTransitions = getUniformizedMarkovianTransitions(markovianExitRates, lambda, maybeStates, markovianMaybeStates); + // Transitions from probabilistic maybe states to probabilistic maybe states. + storm::storage::SparseMatrix<ValueType> probabilisticToProbabilisticTransitions = transitionMatrix.getSubmatrix(true, probabilisticMaybeStates, probabilisticMaybeStates, false); + // Transitions from probabilistic maybe states to Markovian maybe states. + storm::storage::SparseMatrix<ValueType> probabilisticToMarkovianTransitions = transitionMatrix.getSubmatrix(true, probabilisticMaybeStates, markovianMaybeStates, false); + // The probabilities to go from a probabilistic state to a psi state in one step + std::vector<std::pair<uint64_t, ValueType>> probabilisticToPsiProbabilities = getSparseOneStepProbabilities(probabilisticMaybeStates, psiStates); + + // Set up a solver for the transitions between probabilistic states (if there are some) + Environment solverEnv = env; + solverEnv.solver().setForceExact(true); // Errors within the inner iterations can propagate significantly + auto solver = setUpProbabilisticStatesSolver(solverEnv, dir, probabilisticToProbabilisticTransitions); + + // Allocate auxiliary memory that can be used during the iterations + std::vector<ValueType> maybeStatesValuesLower(maybeStates.getNumberOfSetBits(), storm::utility::zero<ValueType>()); // should be zero initially + std::vector<ValueType> maybeStatesValuesWeightedUpper(maybeStates.getNumberOfSetBits(), storm::utility::zero<ValueType>()); // should be zero initially + std::vector<ValueType> maybeStatesValuesUpper(maybeStates.getNumberOfSetBits(), storm::utility::zero<ValueType>()); // should be zero initially + std::vector<ValueType> nextMarkovianStateValues = std::move(markovianExitRates); // At this point, the markovianExitRates are no longer needed, so we 'move' them away instead of allocating new memory + std::vector<ValueType> nextProbabilisticStateValues(probabilisticToProbabilisticTransitions.getRowGroupCount()); + std::vector<ValueType> eqSysRhs(probabilisticToProbabilisticTransitions.getRowCount()); + + // Start the outer iterations which increase the uniformization rate until lower and upper bound on the result vector is sufficiently small + storm::utility::ProgressMeasurement progressIterations("iterations"); + uint64_t iteration = 0; + progressIterations.startNewMeasurement(iteration); + bool converged = false; + + while (!converged) { + // Maximal step size + uint64_t N = storm::utility::ceil(lambda * upperTimeBound * std::exp(2) - storm::utility::log(kappa * epsilon)); + // Compute poisson distribution. + // The division by 8 is similar to what is done for CTMCs (probably to reduce numerical impacts?) + auto foxGlynnResult = storm::utility::numerical::foxGlynn(lambda * upperTimeBound, epsilon * kappa / storm::utility::convertNumber<ValueType>(8.0)); + // Scale the weights so they sum to one. + //storm::utility::vector::scaleVectorInPlace(foxGlynnResult.weights, storm::utility::one<ValueType>() / foxGlynnResult.totalWeight); + + // Set up multiplier + auto markovianToMaybeMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, markovianToMaybeTransitions); + auto probabilisticToMarkovianMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, probabilisticToMarkovianTransitions); + + //Perform inner iterations first for upper, then for lower bound + STORM_LOG_ASSERT(!storm::utility::vector::hasNonZeroEntry(maybeStatesValuesUpper), "Current values need to be initialized with zero."); + for (bool computeLowerBound : {false, true}) { + auto& maybeStatesValues = computeLowerBound ? maybeStatesValuesLower : maybeStatesValuesWeightedUpper; + ValueType targetValue = computeLowerBound ? storm::utility::zero<ValueType>() : storm::utility::one<ValueType>(); + storm::utility::ProgressMeasurement progressSteps("steps in iteration " + std::to_string(iteration) + " for " + std::string(computeLowerBound ? "lower" : "upper") + " bounds."); + progressSteps.setMaxCount(N); + progressSteps.startNewMeasurement(0); + bool firstIteration = true; // The first iterations can be irrelevant, because they will only produce zeroes anyway. + // Iteration k = N is always non-relevant + for (int64_t k = N - 1; k >= 0; --k) { + + // Check whether the iteration is relevant, that is, whether it will contribute non-zero values to the overall result + if (computeLowerBound) { + // Check whether the value for visiting a target state will be zero. + if (static_cast<uint64_t>(k) > foxGlynnResult.right) { + // Reaching this point means that we are in one of the earlier iterations where fox glynn told us to cut off + continue; + } + } else { + uint64_t i = N-1-k; + if (i > foxGlynnResult.right) { + // Reaching this point means that we are in a later iteration which will not contribute to the upper bound + // Since i will only get larger in subsequent iterations, we can directly break here. + break; + } + } + + // Compute the values at Markovian maybe states. + if (firstIteration) { + firstIteration = false; + // Reaching this point means that this is the very first relevant iteration. + // If we are in the very first relevant iteration, we know that all states from the previous iteration have value zero. + // It is therefore valid (and necessary) to just set the values of Markovian states to zero. + std::fill(nextMarkovianStateValues.begin(), nextMarkovianStateValues.end(), storm::utility::zero<ValueType>()); + } else { + // Compute the values at Markovian maybe states. + markovianToMaybeMultiplier->multiply(env, maybeStatesValues, nullptr, nextMarkovianStateValues); + for (auto const& oneStepProb : markovianToPsiProbabilities) { + nextMarkovianStateValues[oneStepProb.first] += oneStepProb.second * targetValue; + } + } + + // Update the value when reaching a psi state. + // This has to be done after updating the Markovian state values since we needed the 'old' target value above. + if (computeLowerBound && static_cast<uint64_t>(k) >= foxGlynnResult.left) { + assert(static_cast<uint64_t>(k) <= foxGlynnResult.right); // has to hold since this iteration is relevant + targetValue += foxGlynnResult.weights[k - foxGlynnResult.left]; + } + + // Compute the values at probabilistic states. + probabilisticToMarkovianMultiplier->multiply(env, nextMarkovianStateValues, nullptr, eqSysRhs); + for (auto const& oneStepProb : probabilisticToPsiProbabilities) { + eqSysRhs[oneStepProb.first] += oneStepProb.second * targetValue; + } + if (solver) { + solver->solveEquations(solverEnv, dir, nextProbabilisticStateValues, eqSysRhs); + } else { + storm::utility::vector::reduceVectorMinOrMax(dir, eqSysRhs, nextProbabilisticStateValues, probabilisticToProbabilisticTransitions.getRowGroupIndices()); + } + + // Create the new values for the maybestates + // Fuse the results together + storm::utility::vector::setVectorValues(maybeStatesValues, markovianStatesModMaybeStates, nextMarkovianStateValues); + storm::utility::vector::setVectorValues(maybeStatesValues, probabilisticStatesModMaybeStates, nextProbabilisticStateValues); + if (!computeLowerBound) { + // Add the scaled values to the actual result vector + uint64_t i = N-1-k; + if (i >= foxGlynnResult.left) { + assert(i <= foxGlynnResult.right); // has to hold since this iteration is considered relevant. + ValueType const& weight = foxGlynnResult.weights[i - foxGlynnResult.left]; + storm::utility::vector::addScaledVector(maybeStatesValuesUpper, maybeStatesValuesWeightedUpper, weight); + } + } + + progressSteps.updateProgress(N-k); } - between += element.getValue() * resVectorNew[successor]; - } - if (maximize(dir)) { - res = storm::utility::max(res, between); - } else { - if (res != -1) { - res = storm::utility::min(res, between); + if (computeLowerBound) { + storm::utility::vector::scaleVectorInPlace(maybeStatesValuesLower, storm::utility::one<ValueType>() / foxGlynnResult.totalWeight); } else { - res = between; + storm::utility::vector::scaleVectorInPlace(maybeStatesValuesUpper, storm::utility::one<ValueType>() / foxGlynnResult.totalWeight); } - } - } - resVectorNew[state] = res; - return; - } - - // If we arrived at this point, the model is not cycle free. Use the solver to solve the underlying equation system. - uint64_t numberOfProbabilisticStates = numberOfStates - markovianStates.getNumberOfSetBits(); - std::vector<ValueType> b(numberOfProbabilisticChoices, storm::utility::zero<ValueType>()); - std::vector<ValueType> x(numberOfProbabilisticStates, storm::utility::zero<ValueType>()); - - // Compute right-hand side vector b. - uint64_t row = 0; - for (uint64_t i = 0; i < numberOfStates; ++i) { - if (markovianStates[i]) { - continue; - } - for (auto j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; j++) { - uint64_t stateCount = 0; - res = storm::utility::zero<ValueType>(); - for (auto const& element : fullTransitionMatrix.getRow(j)) { - auto successor = element.getColumn(); - if (!markovianStates[successor]) { - continue; + // Check if the lower and upper bound are sufficiently close to each other + converged = checkConvergence(maybeStatesValuesLower, maybeStatesValuesUpper, relevantMaybeStates, epsilon, relativePrecision, kappa); + if (converged) { + break; } + } + + if (!converged) { + // Increase the uniformization rate and prepare the next run + + // Double lambda. + ValueType oldLambda = lambda; + lambda *= storm::utility::convertNumber<ValueType>(2.0); + STORM_LOG_DEBUG("Increased lambda to " << lambda << "."); - if (resVectorNew[successor] == -1) { - calculateUnifPlusVector(env, k, successor, calcLower, lambda, numberOfProbabilisticStates, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + if (relativePrecision) { + // Reduce kappa a bit + ValueType minValue = *std::min_element(maybeStatesValuesUpper.begin(), maybeStatesValuesUpper.end()); + minValue *= storm::utility::convertNumber<ValueType>(env.solver().timeBounded().getUnifPlusKappa()); + kappa = std::min(kappa, minValue); + STORM_LOG_DEBUG("Decreased kappa to " << kappa << "."); } - res += relativeReachability[j][stateCount] * resVectorNew[successor]; - ++stateCount; + + // Apply uniformization with new rate + uniformize(markovianToMaybeTransitions, markovianToPsiProbabilities, oldLambda, lambda, markovianStatesModMaybeStates); + + // Reset the values of the maybe states to zero. + std::fill(maybeStatesValuesUpper.begin(), maybeStatesValuesUpper.end(), storm::utility::zero<ValueType>()); } - - b[row] = res; - ++row; + progressIterations.updateProgress(++iteration); } + + // We take the average of the lower and upper bounds + auto two = storm::utility::convertNumber<ValueType>(2.0); + storm::utility::vector::applyPointwise<ValueType, ValueType, ValueType>(maybeStatesValuesLower, maybeStatesValuesUpper, maybeStatesValuesLower, [&two] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / two; }); + + std::vector<ValueType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>()); + storm::utility::vector::setVectorValues(result, psiStates, storm::utility::one<ValueType>()); + storm::utility::vector::setVectorValues(result, maybeStates, maybeStatesValuesLower); + return result; } - - // Solve the equation system. - solver->solveEquations(env, dir, x, b); - // Expand the solution for the probabilistic states to all states. - storm::utility::vector::setVectorValues(resVectorNew, ~markovianStates, x); - } - - template <typename ValueType> - void eliminateProbabilisticSelfLoops(storm::storage::SparseMatrix<ValueType>& transitionMatrix, storm::storage::BitVector const& markovianStates) { - auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); - - for (uint64_t i = 0; i < transitionMatrix.getRowGroupCount(); ++i) { - if (markovianStates[i]) { - continue; + private: + + bool checkConvergence(std::vector<ValueType> const& lower, std::vector<ValueType> const& upper, boost::optional<storm::storage::BitVector> const& relevantValues, ValueType const& epsilon, bool relative, ValueType& kappa) { + STORM_LOG_ASSERT(!relevantValues.is_initialized() || relevantValues->size() == lower.size(), "Relevant values size mismatch."); + if (!relative) { + if (relevantValues) { + return storm::utility::vector::equalModuloPrecision(lower, upper, relevantValues.get(), epsilon * (storm::utility::one<ValueType>() - kappa), false); + } else { + return storm::utility::vector::equalModuloPrecision(lower, upper, epsilon * (storm::utility::one<ValueType>() - kappa), false); + } } - - for (uint64_t j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; j++) { - ValueType selfLoop = storm::utility::zero<ValueType>(); - for (auto const& element: transitionMatrix.getRow(j)){ - if (element.getColumn() == i) { - selfLoop += element.getValue(); + ValueType truncationError = epsilon * kappa; + for (uint64_t i = 0; i < lower.size(); ++i) { + if (relevantValues) { + i = relevantValues->getNextSetIndex(i); + if (i == lower.size()) { + break; } } - - if (storm::utility::isZero(selfLoop)) { + if (lower[i] == upper[i]) { continue; } - - for (auto& element : transitionMatrix.getRow(j)) { - if (element.getColumn() != i) { - if (!storm::utility::isOne(selfLoop)) { - element.setValue(element.getValue() / (storm::utility::one<ValueType>() - selfLoop)); - } - } else { - element.setValue(storm::utility::zero<ValueType>()); - } + if (lower[i] <= truncationError) { + return false; } + ValueType absDiff = upper[i] - lower[i] + truncationError; + ValueType relDiff = absDiff / lower[i]; + if (relDiff > epsilon) { + return false; + } + STORM_LOG_ASSERT(absDiff > storm::utility::zero<ValueType>(), "Upper bound " << upper[i] << " is smaller than lower bound " << lower[i] << "."); } + return true; } - } - - template<typename ValueType> - std::vector<ValueType> computeBoundedUntilProbabilitiesUnifPlus(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair) { - STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - - // Obtain bit vectors to identify different kind of states. - storm::storage::BitVector allStates(markovianStates.size(), true); - storm::storage::BitVector probabilisticStates = ~markovianStates; - - // Searching for SCCs in probabilistic fragment to decide which algorithm is applied. - bool cycleFree = !storm::utility::graph::hasCycle(transitionMatrix, probabilisticStates); - - // Vectors to store computed vectors. - UnifPlusVectors<ValueType> unifVectors; - - // Transitions from goal states will be ignored. However, we mark them as non-probabilistic to make sure - // we do not apply the MDP algorithm to them. - storm::storage::BitVector markovianAndGoalStates = markovianStates | psiStates; - probabilisticStates &= ~psiStates; - - std::vector<ValueType> mutableExitRates = exitRateVector; - // Extend the transition matrix with diagonal entries so we can change them easily during the uniformization step. - typename storm::storage::SparseMatrix<ValueType> fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates, allStates, true); - - // Eliminate self-loops of probabilistic states. Is this really needed for the "slight value iteration" process? - eliminateProbabilisticSelfLoops(fullTransitionMatrix, markovianAndGoalStates); - typename storm::storage::SparseMatrix<ValueType> probMatrix; - uint64_t numberOfProbabilisticChoices = 0; - if (!probabilisticStates.empty()) { - probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates, probabilisticStates, true); - numberOfProbabilisticChoices = probMatrix.getRowCount(); - } - - // Get row grouping of transition matrix. - auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - - // (1) define/declare horizon, epsilon, kappa, N, lambda, maxNorm - uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); - // 'Unpack' the bounds to make them more easily accessible. - double lowerBound = boundsPair.first; - double upperBound = boundsPair.second; - // Lower bound > 0 is not implemented! - STORM_LOG_THROW(lowerBound == 0, storm::exceptions::NotImplementedException, "Support for lower bound > 0 not implemented in Unif+."); - // Truncation error - // TODO: make kappa a parameter. - ValueType kappa = storm::utility::one<ValueType>() / 10; - // Approximation error - ValueType epsilon = storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision(); - // Lambda is largest exit rate - ValueType lambda = exitRateVector[0]; - for (ValueType const& rate : exitRateVector) { - lambda = std::max(rate, lambda); - } - STORM_LOG_DEBUG("Initial lambda is " << lambda << "."); - - // Compute the relative reachability vectors and create solver for models with SCCs. - std::vector<std::vector<ValueType>> relativeReachabilities(transitionMatrix.getRowCount()); - std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver; - if (!cycleFree) { - for (uint64_t i = 0; i < numberOfStates; i++) { - if (markovianAndGoalStates[i]) { - continue; - } + storm::storage::SparseMatrix<ValueType> getUniformizedMarkovianTransitions(std::vector<ValueType> const& oldRates, ValueType uniformizationRate, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& markovianMaybeStates) { + // We need a submatrix whose rows correspond to the markovian states and columns correpsond to the maybestates. + // In addition, we need 'selfloop' entries for the markovian maybe states. + + // First build a submatrix without selfloop entries + auto submatrix = transitionMatrix.getSubmatrix(true, markovianMaybeStates, maybeStates); + assert(submatrix.getRowCount() == submatrix.getRowGroupCount()); - for (auto j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; ++j) { - for (auto const& element : fullTransitionMatrix.getRow(j)) { - if (markovianAndGoalStates[element.getColumn()]) { - relativeReachabilities[j].push_back(element.getValue()); - } + // Now add selfloop entries at the correct positions and apply uniformization + storm::storage::SparseMatrixBuilder<ValueType> builder(submatrix.getRowCount(), submatrix.getColumnCount()); + auto markovianStateColumns = markovianMaybeStates % maybeStates; + uint64_t row = 0; + for (auto const& selfloopColumn : markovianStateColumns) { + ValueType const& oldExitRate = oldRates[row]; + bool foundSelfoop = false; + for (auto const& entry : submatrix.getRow(row)) { + if (entry.getColumn() == selfloopColumn) { + foundSelfoop = true; + ValueType newSelfLoop = uniformizationRate - oldExitRate + entry.getValue() * oldExitRate; + builder.addNextValue(row, entry.getColumn(), newSelfLoop / uniformizationRate); + } else { + builder.addNextValue(row, entry.getColumn(), entry.getValue() * oldExitRate / uniformizationRate); } } + if (!foundSelfoop) { + ValueType newSelfLoop = uniformizationRate - oldExitRate; + builder.addNextValue(row, selfloopColumn, newSelfLoop / uniformizationRate); + } + ++row; } - - // Create solver. - storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory; - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, true, dir); - requirements.clearBounds(); - STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); - - if (numberOfProbabilisticChoices > 0) { - solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); - solver->setHasUniqueSolution(); - solver->setHasNoEndComponents(); - solver->setBounds(storm::utility::zero<ValueType>(), storm::utility::one<ValueType>()); - solver->setRequirementsChecked(); - solver->setCachingEnabled(true); - } + assert(row == submatrix.getRowCount()); + + return builder.build(); } - ValueType maxNorm = storm::utility::zero<ValueType>(); - // Maximal step size - uint64_t N; - storm::utility::ProgressMeasurement progressIterations("iterations"); - size_t iteration = 0; - progressIterations.startNewMeasurement(iteration); - // Loop until result is within precision bound. - do { - // (2) update parameter - N = storm::utility::ceil(lambda * upperBound * std::exp(2) - storm::utility::log(kappa * epsilon)); - - // (3) uniform - just applied to Markovian states. - for (uint64_t i = 0; i < numberOfStates; i++) { - if (!markovianAndGoalStates[i] || psiStates[i]) { - continue; - } - - // As the current state is Markovian, its branching probabilities are stored within one row. - uint64_t markovianRowIndex = rowGroupIndices[i]; - - if (mutableExitRates[i] == lambda) { + void uniformize(storm::storage::SparseMatrix<ValueType>& matrix, std::vector<std::pair<uint64_t, ValueType>>& oneSteps, std::vector<ValueType> const& oldRates, ValueType uniformizationRate, storm::storage::BitVector const& selfloopColumns) { + uint64_t row = 0; + for (auto const& selfloopColumn : selfloopColumns) { + ValueType const& oldExitRate = oldRates[row]; + if (oldExitRate == uniformizationRate) { // Already uniformized. + ++row; continue; } - - auto markovianRow = fullTransitionMatrix.getRow(markovianRowIndex); - ValueType oldExitRate = mutableExitRates[i]; - ValueType newExitRate = lambda; - for (auto& v : markovianRow) { - if (v.getColumn() == i) { - ValueType newSelfLoop = newExitRate - oldExitRate + v.getValue() * oldExitRate; - ValueType newRate = newSelfLoop / newExitRate; - v.setValue(newRate); + for (auto& v : matrix.getRow(row)) { + if (v.getColumn() == selfloopColumn) { + ValueType newSelfLoop = uniformizationRate - oldExitRate + v.getValue() * oldExitRate; + v.setValue(newSelfLoop / uniformizationRate); } else { - ValueType oldProbability = v.getValue(); - ValueType newProbability = oldProbability * oldExitRate / newExitRate; - v.setValue(newProbability); + v.setValue(v.getValue() * oldExitRate / uniformizationRate); } } - mutableExitRates[i] = newExitRate; + ++row; } - - // Compute poisson distribution. - storm::utility::numerical::FoxGlynnResult<ValueType> foxGlynnResult = storm::utility::numerical::foxGlynn(lambda * upperBound, epsilon * kappa / 100); - - // Scale the weights so they sum to one. - for (auto& element : foxGlynnResult.weights) { - element /= foxGlynnResult.totalWeight; + assert(row == matrix.getRowCount()); + for (auto& oneStep : oneSteps) { + oneStep.second *= oldRates[oneStep.first] / uniformizationRate; } - - // (4) Define vectors/matrices. - // Initialize result vectors and already insert zeros for iteration N - unifVectors = UnifPlusVectors<ValueType>(N, numberOfStates); - - // (5) Compute vectors and maxNorm. - // Iteration k = N was already performed by initializing with zeros. - - // Iterations k < N - storm::utility::ProgressMeasurement progressSteps("steps in iteration " + std::to_string(iteration)); - progressSteps.setMaxCount(N); - progressSteps.startNewMeasurement(0); - for (int64_t k = N-1; k >= 0; --k) { - if (k < (int64_t)(N-1)) { - unifVectors.prepareNewIteration(); - } - for (uint64_t state = 0; state < numberOfStates; ++state) { - // Calculate results for lower bound and wUpper - calculateUnifPlusVector(env, k, state, true, lambda, numberOfProbabilisticChoices, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); - calculateUnifPlusVector(env, k, state, false, lambda, numberOfProbabilisticChoices, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); - // Calculate result for upper bound - uint64_t index = N-1-k; - if (index >= foxGlynnResult.left && index <= foxGlynnResult.right) { - STORM_LOG_ASSERT(unifVectors.wUpperNew[state] != -1, "wUpper was not computed before."); - unifVectors.resUpper[state] += foxGlynnResult.weights[index - foxGlynnResult.left] * unifVectors.wUpperNew[state]; + } + + /// Uniformizes the given matrix assuming that it is already uniform. The selfloopColumns indicate for each row, the column indices that correspond to the 'selfloops' for that row + void uniformize(storm::storage::SparseMatrix<ValueType>& matrix, std::vector<std::pair<uint64_t, ValueType>>& oneSteps, ValueType oldUniformizationRate, ValueType newUniformizationRate, storm::storage::BitVector const& selfloopColumns) { + if (oldUniformizationRate != newUniformizationRate) { + assert(oldUniformizationRate < newUniformizationRate); + ValueType rateDiff = newUniformizationRate - oldUniformizationRate; + ValueType rateFraction = oldUniformizationRate / newUniformizationRate; + uint64_t row = 0; + for (auto const& selfloopColumn : selfloopColumns) { + for (auto& v : matrix.getRow(row)) { + if (v.getColumn() == selfloopColumn) { + ValueType newSelfLoop = rateDiff + v.getValue() * oldUniformizationRate; + v.setValue(newSelfLoop / newUniformizationRate); + } else { + v.setValue(v.getValue() * rateFraction); + } } + ++row; + } + assert(row == matrix.getRowCount()); + for (auto& oneStep : oneSteps) { + oneStep.second *= rateFraction; } - progressSteps.updateProgress(N-k); } - - // Only iterate over result vector, as the results can only get more precise. - maxNorm = storm::utility::zero<ValueType>(); - for (uint64_t i = 0; i < numberOfStates; i++){ - ValueType diff = storm::utility::abs(unifVectors.resUpper[i] - unifVectors.resLowerNew[i]); - maxNorm = std::max(maxNorm, diff); + } + + std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> setUpProbabilisticStatesSolver(storm::Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitions) const { + std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver; + if (transitions.getNonzeroEntryCount() > 0) { + storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> factory; + solver = factory.create(env, transitions); + solver->setHasUniqueSolution(true); // Assume non-zeno MA + solver->setHasNoEndComponents(true); // assume non-zeno MA + solver->setLowerBound(storm::utility::zero<ValueType>()); + solver->setUpperBound(storm::utility::one<ValueType>()); + solver->setCachingEnabled(true); + solver->setRequirementsChecked(true); + auto req = solver->getRequirements(env, dir); + req.clearBounds(); + req.clearUniqueSolution(); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "The solver requirement " << req.getEnabledRequirementsAsString() << " has not been checked."); } - - // (6) Double lambda. - lambda *= 2; - STORM_LOG_DEBUG("Increased lambda to " << lambda << ", max diff is " << maxNorm << "."); - progressIterations.updateProgress(++iteration); - } while (maxNorm > epsilon * (1 - kappa)); - - return unifVectors.resLowerNew; - } - + return solver; + } + + storm::storage::BitVector getProb0States(OptimizationDirection dir, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) const { + if (dir == storm::solver::OptimizationDirection::Maximize) { + return storm::utility::graph::performProb0A(transitionMatrix.transpose(true), phiStates, psiStates); + } else { + return storm::utility::graph::performProb0E(transitionMatrix, transitionMatrix.getRowGroupIndices(), transitionMatrix.transpose(true), phiStates, psiStates); + } + } + + /*! + * Returns a vector with pairs of state indices and non-zero probabilities to move from the corresponding state to a target state. + * The state indices are with respect to the number of states satisfying the sourceStateConstraint, i.e. the indices are in the range [0, sourceStateConstraint.getNumberOfSetBits()) + */ + std::vector<std::pair<uint64_t, ValueType>> getSparseOneStepProbabilities(storm::storage::BitVector const& sourceStateConstraint, storm::storage::BitVector const& targetStateConstraint) const { + auto denseResult = transitionMatrix.getConstrainedRowGroupSumVector(sourceStateConstraint, targetStateConstraint); + std::vector<std::pair<uint64_t, ValueType>> sparseResult; + for (uint64 i = 0; i < denseResult.size(); ++i) { + auto const& val = denseResult[i]; + if (!storm::utility::isZero(val)) { + sparseResult.emplace_back(i, val); + } + } + return sparseResult; + } + + storm::storage::SparseMatrix<ValueType> const& transitionMatrix; + std::vector<ValueType> const& exitRateVector; + storm::storage::BitVector const& markovianStates; + }; + template <typename ValueType> void computeBoundedReachabilityProbabilitiesImca(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps) { @@ -556,7 +553,7 @@ namespace storm { for (auto value : exitRateVector) { maxExitRate = std::max(maxExitRate, value); } - ValueType delta = (2 * storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision()) / (upperBound * maxExitRate * maxExitRate); + ValueType delta = (2.0 * storm::utility::convertNumber<ValueType>(env.solver().timeBounded().getPrecision())) / (upperBound * maxExitRate * maxExitRate); // (2) Compute the number of steps we need to make for the interval. uint64_t numberOfSteps = static_cast<uint64_t>(std::ceil((upperBound - lowerBound) / delta)); @@ -607,23 +604,36 @@ namespace storm { } template <typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type> - std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair) { - auto const& settings = storm::settings::getModule<storm::settings::modules::MinMaxEquationSolverSettings>(); - if (settings.getMarkovAutomatonBoundedReachabilityMethod() == storm::settings::modules::MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::Imca) { - return computeBoundedUntilProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair); + std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal<ValueType>&& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair) { + // Choose the applicable method + auto method = env.solver().timeBounded().getMaMethod(); + if (method == storm::solver::MaBoundedReachabilityMethod::Imca) { + if (!phiStates.full()) { + STORM_LOG_WARN("Using Unif+ method because IMCA method does not support (phi Until psi) for non-trivial phi"); + method = storm::solver::MaBoundedReachabilityMethod::UnifPlus; + } } else { - STORM_LOG_ASSERT(settings.getMarkovAutomatonBoundedReachabilityMethod() == storm::settings::modules::MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::UnifPlus, "Unknown solution method."); + STORM_LOG_ASSERT(method == storm::solver::MaBoundedReachabilityMethod::UnifPlus, "Unknown solution method."); if (!storm::utility::isZero(boundsPair.first)) { STORM_LOG_WARN("Using IMCA method because Unif+ does not support a lower bound > 0."); - return computeBoundedUntilProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair); - } else { - return computeBoundedUntilProbabilitiesUnifPlus(env, dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair); + method = storm::solver::MaBoundedReachabilityMethod::Imca; } } + + if (method == storm::solver::MaBoundedReachabilityMethod::Imca) { + return computeBoundedUntilProbabilitiesImca(env, goal.direction(), transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair); + } else { + UnifPlusHelper<ValueType> helper(transitionMatrix, exitRateVector, markovianStates); + boost::optional<storm::storage::BitVector> relevantValues; + if (goal.hasRelevantValues()) { + relevantValues = std::move(goal.relevantValues()); + } + return helper.computeBoundedUntilProbabilities(env, goal.direction(), phiStates, psiStates, boundsPair.second, relevantValues); + } } template <typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type> - std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair) { + std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal<ValueType>&& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); } @@ -883,7 +893,7 @@ namespace storm { // Solve MEC with the method specified in the settings storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod(); - if (storm::NumberTraits<ValueType>::IsExact && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::LinearProgramming) { + if ((storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()) && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::LinearProgramming) { STORM_LOG_INFO("Selecting 'LP' as the solution technique for long-run properties to guarantee exact results. If you want to override this, please explicitly specify a different LRA method."); method = storm::solver::LraMethod::LinearProgramming; } else if (env.solver().isForceSoundness() && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::ValueIteration) { @@ -1136,7 +1146,7 @@ namespace storm { return v.front() * uniformizationRate; } - template std::vector<double> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); + template std::vector<double> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal<double>&& goal, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); template MDPSparseModelCheckingHelperReturnType<double> SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler); @@ -1156,7 +1166,7 @@ namespace storm { template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel<double> const& rewardModel, storm::storage::MaximalEndComponent const& mec); - template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); + template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal<storm::RationalNumber>&& goal, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); template MDPSparseModelCheckingHelperReturnType<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index d56747e5c..ed0dfddef 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -6,6 +6,7 @@ #include "storm/storage/MaximalEndComponent.h" #include "storm/solver/OptimizationDirection.h" #include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/SolveGoal.h" #include "storm/utility/NumberTraits.h" namespace storm { @@ -19,10 +20,10 @@ namespace storm { public: template <typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0> - static std::vector<ValueType> computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); + static std::vector<ValueType> computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal<ValueType>&& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); template <typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0> - static std::vector<ValueType> computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); + static std::vector<ValueType> computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal<ValueType>&& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair); template <typename ValueType> static MDPSparseModelCheckingHelperReturnType<ValueType> computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler); diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp index ecd57182f..266363662 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp @@ -32,11 +32,16 @@ namespace storm { } template<typename ModelType> - bool HybridDtmcPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool HybridDtmcPrctlModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask) { storm::logic::Formula const& formula = checkTask.getFormula(); return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true).setRewardAccumulationAllowed(true)); } - + + template<typename ModelType> + bool HybridDtmcPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + return canHandleStatic(checkTask); + } + template<typename ModelType> std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<ModelType>::computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) { storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h index 854fae195..f779e1920 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h @@ -19,6 +19,11 @@ namespace storm { explicit HybridDtmcPrctlModelChecker(ModelType const& model); + /*! + * Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + */ + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp index 270e99c47..c4099bb5b 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp @@ -38,20 +38,28 @@ namespace storm { } template<typename ModelType> - bool HybridMdpPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool HybridMdpPrctlModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState) { storm::logic::Formula const& formula = checkTask.getFormula(); if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true).setRewardAccumulationAllowed(true))) { return true; + } else if (checkTask.isOnlyInitialStatesRelevantSet() && formula.isInFragment(storm::logic::multiObjective().setCumulativeRewardFormulasAllowed(true))) { + if (requiresSingleInitialState) { + *requiresSingleInitialState = true; + } + } + return false; + } + + template<typename ModelType> + bool HybridMdpPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool requiresSingleInitialState = false; + if (canHandleStatic(checkTask, &requiresSingleInitialState)) { + return !requiresSingleInitialState || this->getModel().getInitialStates().getNonZeroCount() == 1; } else { - // Check whether we consider a multi-objective formula - // For multi-objective model checking, each state requires an individual scheduler (in contrast to single-objective model checking). Let's exclude that multiple states are relevant - if(this->getModel().getInitialStates().getNonZeroCount() > 1) return false; - if(!checkTask.isOnlyInitialStatesRelevantSet()) return false; - return formula.isInFragment(storm::logic::multiObjective().setCumulativeRewardFormulasAllowed(true)); + return false; } - } - + template<typename ModelType> std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<ModelType>::computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) { storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h index 68eb12baa..cc253e753 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h @@ -26,6 +26,12 @@ namespace storm { explicit HybridMdpPrctlModelChecker(ModelType const& model); + /*! + * Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + * @param requiresSingleInitialState if not nullptr, this flag is set to true iff checking this formula requires a model with a single initial state + */ + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState = nullptr); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index 9896f8ce4..541c51502 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -32,17 +32,29 @@ namespace storm { } template<typename SparseDtmcModelType> - bool SparseDtmcPrctlModelChecker<SparseDtmcModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool SparseDtmcPrctlModelChecker<SparseDtmcModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState) { storm::logic::Formula const& formula = checkTask.getFormula(); if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setConditionalRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true).setRewardAccumulationAllowed(true))) { return true; - } else if (formula.isInFragment(storm::logic::quantiles())) { - if (this->getModel().getInitialStates().getNumberOfSetBits() > 1) return false; + } else if (checkTask.isOnlyInitialStatesRelevantSet() && formula.isInFragment(storm::logic::quantiles())) { + if (requiresSingleInitialState) { + *requiresSingleInitialState = true; + } return true; } return false; } + template<typename SparseDtmcModelType> + bool SparseDtmcPrctlModelChecker<SparseDtmcModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool requiresSingleInitialState = false; + if (canHandleStatic(checkTask, &requiresSingleInitialState)) { + return !requiresSingleInitialState || this->getModel().getInitialStates().getNumberOfSetBits() == 1; + } else { + return false; + } + } + template<typename SparseDtmcModelType> std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) { storm::logic::BoundedUntilFormula const& pathFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h index 1001b5572..8e72833d6 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h @@ -18,6 +18,12 @@ namespace storm { explicit SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model); + /*! + * Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + * @param requiresSingleInitialState if not nullptr, this flag is set to true iff checking this formula requires a model with a single initial state + */ + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState = nullptr); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index 11821a518..f62035f73 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -39,23 +39,32 @@ namespace storm { } template<typename SparseMdpModelType> - bool SparseMdpPrctlModelChecker<SparseMdpModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool SparseMdpPrctlModelChecker<SparseMdpModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState) { storm::logic::Formula const& formula = checkTask.getFormula(); if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true).setRewardAccumulationAllowed(true))) { return true; - } else if (formula.isInFragment(storm::logic::multiObjective().setCumulativeRewardFormulasAllowed(true).setTimeBoundedCumulativeRewardFormulasAllowed(true).setStepBoundedCumulativeRewardFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true))) { - // Check whether we consider a multi-objective formula - // For multi-objective model checking, each initial state requires an individual scheduler (in contrast to single-objective model checking). Let's exclude multiple initial states. - if (this->getModel().getInitialStates().getNumberOfSetBits() > 1) return false; - if (!checkTask.isOnlyInitialStatesRelevantSet()) return false; - return true; - } else if (formula.isInFragment(storm::logic::quantiles())) { - if (this->getModel().getInitialStates().getNumberOfSetBits() > 1) return false; - return true; + } else if (checkTask.isOnlyInitialStatesRelevantSet()) { + auto multiObjectiveFragment = storm::logic::multiObjective().setCumulativeRewardFormulasAllowed(true).setTimeBoundedCumulativeRewardFormulasAllowed(true).setStepBoundedCumulativeRewardFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true); + if (formula.isInFragment(multiObjectiveFragment) || formula.isInFragment(storm::logic::quantiles())) { + if (requiresSingleInitialState) { + *requiresSingleInitialState = true; + } + return true; + } } return false; } + template<typename SparseMdpModelType> + bool SparseMdpPrctlModelChecker<SparseMdpModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool requiresSingleInitialState = false; + if (canHandleStatic(checkTask, &requiresSingleInitialState)) { + return !requiresSingleInitialState || this->getModel().getInitialStates().getNumberOfSetBits() == 1; + } else { + return false; + } + } + template<typename SparseMdpModelType> std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) { storm::logic::BoundedUntilFormula const& pathFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h index 38a0a090c..44916728b 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h @@ -18,6 +18,12 @@ namespace storm { explicit SparseMdpPrctlModelChecker(SparseMdpModelType const& model); + /*! + * Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + * @param requiresSingleInitialState if not nullptr, this flag is set to true iff checking this formula requires a model with a single initial state + */ + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState = nullptr); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp index 8b0040b2f..f10639dd4 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp @@ -29,11 +29,16 @@ namespace storm { } template<typename ModelType> - bool SymbolicDtmcPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool SymbolicDtmcPrctlModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask) { storm::logic::Formula const& formula = checkTask.getFormula(); return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true).setRewardAccumulationAllowed(true)); } + template<typename ModelType> + bool SymbolicDtmcPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + return canHandleStatic(checkTask); + } + template<typename ModelType> std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<ModelType>::computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) { storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h index 1186c0271..1a115468f 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h @@ -17,6 +17,9 @@ namespace storm { explicit SymbolicDtmcPrctlModelChecker(ModelType const& model); + // Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp index a08546669..d4dcf3a04 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp @@ -29,11 +29,16 @@ namespace storm { } template<typename ModelType> - bool SymbolicMdpPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + bool SymbolicMdpPrctlModelChecker<ModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask) { storm::logic::Formula const& formula = checkTask.getFormula(); return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true).setRewardAccumulationAllowed(true)); } + template<typename ModelType> + bool SymbolicMdpPrctlModelChecker<ModelType>::canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const { + return canHandleStatic(checkTask); + } + template<typename ModelType> std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<ModelType>::computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) { storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h index bf259e8b7..4fda40be3 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h @@ -18,6 +18,9 @@ namespace storm { explicit SymbolicMdpPrctlModelChecker(ModelType const& model); + // Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + static bool canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask); + // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask<storm::logic::Formula, ValueType> const& checkTask) const override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 0bcc31726..122814633 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -1477,7 +1477,7 @@ namespace storm { // Solve MEC with the method specified in the settings storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod(); - if (storm::NumberTraits<ValueType>::IsExact && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::LinearProgramming) { + if ((storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()) && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::LinearProgramming) { STORM_LOG_INFO("Selecting 'LP' as the solution technique for long-run properties to guarantee exact results. If you want to override this, please explicitly specify a different LRA method."); method = storm::solver::LraMethod::LinearProgramming; } else if (env.solver().isForceSoundness() && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::ValueIteration) { diff --git a/src/storm/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp b/src/storm/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp index c66f5fbea..1185002f7 100644 --- a/src/storm/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp +++ b/src/storm/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp @@ -1,3 +1,4 @@ +#include <storm/models/symbolic/MarkovAutomaton.h> #include "storm/modelchecker/propositional/SymbolicPropositionalModelChecker.h" #include "storm/storage/dd/Add.h" @@ -6,6 +7,7 @@ #include "storm/models/symbolic/Dtmc.h" #include "storm/models/symbolic/Ctmc.h" #include "storm/models/symbolic/Mdp.h" +#include "storm/models/symbolic/MarkovAutomaton.h" #include "storm/models/symbolic/StochasticTwoPlayerGame.h" #include "storm/models/symbolic/StandardRewardModel.h" @@ -62,21 +64,25 @@ namespace storm { template class SymbolicPropositionalModelChecker<storm::models::symbolic::Dtmc<storm::dd::DdType::CUDD, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Ctmc<storm::dd::DdType::CUDD, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD, double>>; + template class SymbolicPropositionalModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::CUDD, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::StochasticTwoPlayerGame<storm::dd::DdType::CUDD, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Ctmc<storm::dd::DdType::Sylvan, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, double>>; + template class SymbolicPropositionalModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, double>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalNumber>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, storm::RationalNumber>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Ctmc<storm::dd::DdType::Sylvan, storm::RationalNumber>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, storm::RationalNumber>>; + template class SymbolicPropositionalModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalNumber>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, storm::RationalNumber>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalFunction>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, storm::RationalFunction>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Ctmc<storm::dd::DdType::Sylvan, storm::RationalFunction>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, storm::RationalFunction>>; + template class SymbolicPropositionalModelChecker<storm::models::symbolic::MarkovAutomaton<storm::dd::DdType::Sylvan, storm::RationalFunction>>; template class SymbolicPropositionalModelChecker<storm::models::symbolic::StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, storm::RationalFunction>>; } diff --git a/src/storm/models/sparse/MarkovAutomaton.cpp b/src/storm/models/sparse/MarkovAutomaton.cpp index 6e7070546..bea9278c5 100644 --- a/src/storm/models/sparse/MarkovAutomaton.cpp +++ b/src/storm/models/sparse/MarkovAutomaton.cpp @@ -282,9 +282,8 @@ namespace storm { if (isClosed() && markovianStates.empty()) { return true; } - - storm::storage::MaximalEndComponentDecomposition<ValueType> maxEnd(this->getTransitionMatrix(), this->getBackwardTransitions(),~markovianStates); - return !maxEnd.empty(); + storm::storage::BitVector statesWithZenoCycle = storm::utility::graph::performProb0E(*this, this->getBackwardTransitions(), ~markovianStates, markovianStates); + return !statesWithZenoCycle.empty(); } diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index fcd378fe6..d3e63d96b 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -32,6 +32,7 @@ #include "storm/settings/modules/GurobiSettings.h" #include "storm/settings/modules/Smt2SmtSolverSettings.h" #include "storm/settings/modules/TopologicalEquationSolverSettings.h" +#include "storm/settings/modules/TimeBoundedSolverSettings.h" #include "storm/settings/modules/ExplorationSettings.h" #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/AbstractionSettings.h" @@ -658,6 +659,7 @@ namespace storm { storm::settings::addModule<storm::settings::modules::NativeEquationSolverSettings>(); storm::settings::addModule<storm::settings::modules::EliminationSettings>(); storm::settings::addModule<storm::settings::modules::LongRunAverageSolverSettings>(); + storm::settings::addModule<storm::settings::modules::TimeBoundedSolverSettings>(); storm::settings::addModule<storm::settings::modules::MinMaxEquationSolverSettings>(); storm::settings::addModule<storm::settings::modules::GameSolverSettings>(); storm::settings::addModule<storm::settings::modules::BisimulationSettings>(); diff --git a/src/storm/settings/modules/BisimulationSettings.cpp b/src/storm/settings/modules/BisimulationSettings.cpp index 8f797a40f..1b5606bf5 100644 --- a/src/storm/settings/modules/BisimulationSettings.cpp +++ b/src/storm/settings/modules/BisimulationSettings.cpp @@ -70,12 +70,17 @@ namespace storm { return false; } - BisimulationSettings::QuotientFormat BisimulationSettings::getQuotientFormat() const { + bool BisimulationSettings::isQuotientFormatSetFromDefaultValue() const { + return !this->getOption(quotientFormatOptionName).getHasOptionBeenSet() || this->getOption(quotientFormatOptionName).getArgumentByName("format").wasSetFromDefaultValue(); + } + + storm::dd::bisimulation::QuotientFormat BisimulationSettings::getQuotientFormat() const { std::string quotientFormatAsString = this->getOption(quotientFormatOptionName).getArgumentByName("format").getValueAsString(); if (quotientFormatAsString == "sparse") { - return BisimulationSettings::QuotientFormat::Sparse; + return storm::dd::bisimulation::QuotientFormat::Sparse; } - return BisimulationSettings::QuotientFormat::Dd; + STORM_LOG_ASSERT(quotientFormatAsString == "dd", "Invalid bisimulation quotient format: " << quotientFormatAsString << "."); + return storm::dd::bisimulation::QuotientFormat::Dd; } bool BisimulationSettings::isUseRepresentativesSet() const { diff --git a/src/storm/settings/modules/BisimulationSettings.h b/src/storm/settings/modules/BisimulationSettings.h index c06713a8a..acf6ac424 100644 --- a/src/storm/settings/modules/BisimulationSettings.h +++ b/src/storm/settings/modules/BisimulationSettings.h @@ -4,6 +4,7 @@ #include "storm/settings/modules/ModuleSettings.h" #include "storm/storage/dd/bisimulation/SignatureMode.h" +#include "storm/storage/dd/bisimulation/QuotientFormat.h" namespace storm { namespace settings { @@ -17,8 +18,6 @@ namespace storm { // An enumeration of all available bisimulation types. enum class BisimulationType { Strong, Weak }; - enum class QuotientFormat { Sparse, Dd }; - enum class ReuseMode { None, BlockNumbers }; enum class InitialPartitionMode { Regular, Finer }; @@ -44,11 +43,18 @@ namespace storm { */ bool isWeakBisimulationSet() const; + /*! + * Retrieves whether the format in which the quotient is to be extracted has been set from its default value. + * + * @return True iff it has been set from its default value. + */ + bool isQuotientFormatSetFromDefaultValue() const; + /*! * Retrieves the format in which the quotient is to be extracted. * NOTE: only applies to DD-based bisimulation. */ - QuotientFormat getQuotientFormat() const; + storm::dd::bisimulation::QuotientFormat getQuotientFormat() const; /*! * Retrieves whether representatives for blocks are to be used instead of the block numbers. diff --git a/src/storm/settings/modules/BuildSettings.cpp b/src/storm/settings/modules/BuildSettings.cpp index b460d7ba6..3d1852ba5 100644 --- a/src/storm/settings/modules/BuildSettings.cpp +++ b/src/storm/settings/modules/BuildSettings.cpp @@ -18,7 +18,6 @@ namespace storm { const std::string BuildSettings::moduleName = "build"; - const std::string jitOptionName = "jit"; const std::string explorationOrderOptionName = "explorder"; const std::string explorationOrderOptionShortName = "eo"; const std::string explorationChecksOptionName = "explchecks"; @@ -40,7 +39,6 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, prismCompatibilityOptionName, false, "Enables PRISM compatibility. This may be necessary to process some PRISM models.").setShortName(prismCompatibilityOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, dontFixDeadlockOptionName, false, "If the model contains deadlock states, they need to be fixed by setting this option.").setShortName(dontFixDeadlockOptionShortName).setIsAdvanced().build()); - this->addOption(storm::settings::OptionBuilder(moduleName, jitOptionName, false, "If set, the model is built using the JIT model builder.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, fullModelBuildOptionName, false, "If set, include all rewards and labels.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, applyNoMaxProgAssumptionOptionName, false, "If set, the maximum progress assumption is not applied while building the model (relevant for MAs)").setIsAdvanced().build()); this->addOption(storm::settings::OptionBuilder(moduleName, buildChoiceLabelOptionName, false, "If set, also build the choice labels").setIsAdvanced().build()); @@ -57,10 +55,6 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("number", "The number of bits.").addValidatorUnsignedInteger(ArgumentValidatorFactory::createUnsignedRangeValidatorExcluding(0,63)).setDefaultValueUnsignedInteger(32).build()).build()); } - bool BuildSettings::isJitSet() const { - return this->getOption(jitOptionName).getHasOptionBeenSet(); - } - bool BuildSettings::isExplorationOrderSet() const { return this->getOption(explorationOrderOptionName).getHasOptionBeenSet(); } diff --git a/src/storm/settings/modules/BuildSettings.h b/src/storm/settings/modules/BuildSettings.h index 274f42da1..3cce0a705 100644 --- a/src/storm/settings/modules/BuildSettings.h +++ b/src/storm/settings/modules/BuildSettings.h @@ -16,12 +16,6 @@ namespace storm { * Creates a new set of core settings. */ BuildSettings(); - /*! - * Retrieves whether the option to use the JIT builder is set. - * - * @return True iff the JIT builder is to be used. - */ - bool isJitSet() const; /*! * Retrieves whether the model exploration order was set. diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp index bc9ea87fb..19df21f3e 100644 --- a/src/storm/settings/modules/CoreSettings.cpp +++ b/src/storm/settings/modules/CoreSettings.cpp @@ -32,8 +32,11 @@ namespace storm { const std::string CoreSettings::intelTbbOptionName = "enable-tbb"; const std::string CoreSettings::intelTbbOptionShortName = "tbb"; - CoreSettings::CoreSettings() : ModuleSettings(moduleName), engine(CoreSettings::Engine::Sparse) { - std::vector<std::string> engines = {"sparse", "hybrid", "dd", "dd-to-sparse", "expl", "abs"}; + CoreSettings::CoreSettings() : ModuleSettings(moduleName), engine(storm::utility::Engine::Sparse) { + std::vector<std::string> engines; + for (auto e : storm::utility::getEngines()) { + engines.push_back(storm::utility::toString(e)); + } this->addOption(storm::settings::OptionBuilder(moduleName, engineOptionName, false, "Sets which engine is used for model building and model checking.").setShortName(engineOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the engine to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(engines)).setDefaultValueString("sparse").build()).build()); @@ -133,32 +136,19 @@ namespace storm { return this->getOption(cudaOptionName).getHasOptionBeenSet(); } - CoreSettings::Engine CoreSettings::getEngine() const { + storm::utility::Engine CoreSettings::getEngine() const { return engine; } - void CoreSettings::setEngine(Engine newEngine) { + void CoreSettings::setEngine(storm::utility::Engine const& newEngine) { this->engine = newEngine; } void CoreSettings::finalize() { // Finalize engine. std::string engineStr = this->getOption(engineOptionName).getArgumentByName("name").getValueAsString(); - if (engineStr == "sparse") { - engine = CoreSettings::Engine::Sparse; - } else if (engineStr == "hybrid") { - engine = CoreSettings::Engine::Hybrid; - } else if (engineStr == "dd") { - engine = CoreSettings::Engine::Dd; - } else if (engineStr == "dd-to-sparse") { - engine = CoreSettings::Engine::DdSparse; - } else if (engineStr == "expl") { - engine = CoreSettings::Engine::Exploration; - } else if (engineStr == "abs") { - engine = CoreSettings::Engine::AbstractionRefinement; - } else { - STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown engine '" << engineStr << "'."); - } + engine = storm::utility::engineFromString(engineStr); + STORM_LOG_THROW(engine != storm::utility::Engine::Unknown, storm::exceptions::IllegalArgumentValueException, "Unknown engine '" << engineStr << "'."); } bool CoreSettings::check() const { diff --git a/src/storm/settings/modules/CoreSettings.h b/src/storm/settings/modules/CoreSettings.h index 405fad91f..c7a2e6f4d 100644 --- a/src/storm/settings/modules/CoreSettings.h +++ b/src/storm/settings/modules/CoreSettings.h @@ -5,6 +5,7 @@ #include "storm/settings/modules/ModuleSettings.h" #include "storm/builder/ExplorationOrder.h" +#include "storm/utility/Engine.h" namespace storm { namespace solver { @@ -26,10 +27,6 @@ namespace storm { */ class CoreSettings : public ModuleSettings { public: - // An enumeration of all engines. - enum class Engine { - Sparse, Hybrid, Dd, DdSparse, Exploration, AbstractionRefinement - }; /*! * Creates a new set of core settings. @@ -118,12 +115,12 @@ namespace storm { * * @return The selected engine. */ - Engine getEngine() const; + storm::utility::Engine getEngine() const; /*! * Sets the engine for further usage. */ - void setEngine(Engine); + void setEngine(storm::utility::Engine const& engine); bool check() const override; void finalize() override; @@ -132,7 +129,7 @@ namespace storm { static const std::string moduleName; private: - Engine engine; + storm::utility::Engine engine; // Define the string names of the options as constants. static const std::string eqSolverOptionName; diff --git a/src/storm/settings/modules/DebugSettings.cpp b/src/storm/settings/modules/DebugSettings.cpp index 38eb4fe7c..d117958ca 100644 --- a/src/storm/settings/modules/DebugSettings.cpp +++ b/src/storm/settings/modules/DebugSettings.cpp @@ -13,6 +13,7 @@ namespace storm { const std::string DebugSettings::moduleName = "debug"; const std::string DebugSettings::debugOptionName = "debug"; const std::string DebugSettings::traceOptionName = "trace"; + const std::string DebugSettings::additionalChecksOptionName = "additional-checks"; const std::string DebugSettings::logfileOptionName = "logfile"; const std::string DebugSettings::logfileOptionShortName = "l"; const std::string DebugSettings::testOptionName = "test"; @@ -20,6 +21,7 @@ namespace storm { DebugSettings::DebugSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, debugOptionName, false, "Print debug output.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, traceOptionName, false, "Print even more debug output.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, additionalChecksOptionName, false, "If set, additional sanity checks are performed during execution.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, logfileOptionName, false, "If specified, the log output will also be written to this file.").setShortName(logfileOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file to write the log.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, testOptionName, false, "Activate a test setting.").setIsAdvanced().build()); @@ -33,6 +35,10 @@ namespace storm { return this->getOption(traceOptionName).getHasOptionBeenSet(); } + bool DebugSettings::isAdditionalChecksSet() const { + return this->getOption(additionalChecksOptionName).getHasOptionBeenSet(); + } + bool DebugSettings::isLogfileSet() const { return this->getOption(logfileOptionName).getHasOptionBeenSet(); } diff --git a/src/storm/settings/modules/DebugSettings.h b/src/storm/settings/modules/DebugSettings.h index 4364b7bc7..8330e8c95 100644 --- a/src/storm/settings/modules/DebugSettings.h +++ b/src/storm/settings/modules/DebugSettings.h @@ -31,6 +31,13 @@ namespace storm { */ bool isTraceSet() const; + /*! + * Retrieves whether additional checks on the input should be performed. + * + * @return True iff additoinal checks on the input should be performed. + */ + bool isAdditionalChecksSet() const; + /*! * Retrieves whether the logfile option was set. * @@ -60,6 +67,7 @@ namespace storm { // Define the string names of the options as constants. static const std::string debugOptionName; static const std::string traceOptionName; + static const std::string additionalChecksOptionName; static const std::string logfileOptionName; static const std::string logfileOptionShortName; static const std::string testOptionName; diff --git a/src/storm/settings/modules/ExplorationSettings.cpp b/src/storm/settings/modules/ExplorationSettings.cpp index 6be2d8c3f..ef86740d2 100644 --- a/src/storm/settings/modules/ExplorationSettings.cpp +++ b/src/storm/settings/modules/ExplorationSettings.cpp @@ -7,6 +7,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/utility/macros.h" +#include "storm/utility/Engine.h" #include "storm/exceptions/IllegalArgumentValueException.h" namespace storm { @@ -91,7 +92,7 @@ namespace storm { this->getOption(numberOfExplorationStepsUntilPrecomputationOptionName).getHasOptionBeenSet() || this->getOption(numberOfSampledPathsUntilPrecomputationOptionName).getHasOptionBeenSet() || this->getOption(nextStateHeuristicOptionName).getHasOptionBeenSet(); - STORM_LOG_WARN_COND(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Exploration || !optionsSet, "Exploration engine is not selected, so setting options for it has no effect."); + STORM_LOG_WARN_COND(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::utility::Engine::Exploration || !optionsSet, "Exploration engine is not selected, so setting options for it has no effect."); return true; } } // namespace modules diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 66c1bf2e8..0014edb2d 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -17,7 +17,6 @@ namespace storm { const std::string MinMaxEquationSolverSettings::maximalIterationsOptionShortName = "i"; const std::string MinMaxEquationSolverSettings::precisionOptionName = "precision"; const std::string MinMaxEquationSolverSettings::absoluteOptionName = "absolute"; - const std::string MinMaxEquationSolverSettings::markovAutomatonBoundedReachabilityMethodOptionName = "mamethod"; const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; const std::string MinMaxEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; @@ -32,9 +31,6 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, absoluteOptionName, false, "Sets whether the relative or the absolute error is considered for detecting convergence.").setIsAdvanced().build()); - std::vector<std::string> maMethods = {"imca", "unifplus"}; - this->addOption(storm::settings::OptionBuilder(moduleName, markovAutomatonBoundedReachabilityMethodOptionName, false, "The method to use to solve bounded reachability queries on MAs.").setIsAdvanced().addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(maMethods)).setDefaultValueString("unifplus").build()).build()); - std::vector<std::string> multiplicationStyles = {"gaussseidel", "regular", "gs", "r"}; this->addOption(storm::settings::OptionBuilder(moduleName, valueIterationMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for value iteration.").setIsAdvanced() .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); @@ -100,14 +96,6 @@ namespace storm { return this->getOption(absoluteOptionName).getHasOptionBeenSet() ? MinMaxEquationSolverSettings::ConvergenceCriterion::Absolute : MinMaxEquationSolverSettings::ConvergenceCriterion::Relative; } - MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod MinMaxEquationSolverSettings::getMarkovAutomatonBoundedReachabilityMethod() const { - std::string techniqueAsString = this->getOption(markovAutomatonBoundedReachabilityMethodOptionName).getArgumentByName("name").getValueAsString(); - if (techniqueAsString == "imca") { - return MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::Imca; - } - return MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::UnifPlus; - } - storm::solver::MultiplicationStyle MinMaxEquationSolverSettings::getValueIterationMultiplicationStyle() const { std::string multiplicationStyleString = this->getOption(valueIterationMultiplicationStyleOptionName).getArgumentByName("name").getValueAsString(); if (multiplicationStyleString == "gaussseidel" || multiplicationStyleString == "gs") { diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index 5e7bf9b98..87b21252d 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -18,9 +18,6 @@ namespace storm { // An enumeration of all available convergence criteria. enum class ConvergenceCriterion { Absolute, Relative }; - // An enumeration of all available bounded reachability methods for MAs. - enum class MarkovAutomatonBoundedReachabilityMethod { Imca, UnifPlus }; - MinMaxEquationSolverSettings(); /*! @@ -86,13 +83,6 @@ namespace storm { */ ConvergenceCriterion getConvergenceCriterion() const; - /*! - * Retrieves the method to be used for bounded reachability on MAs. - * - * @return The selected method. - */ - MarkovAutomatonBoundedReachabilityMethod getMarkovAutomatonBoundedReachabilityMethod() const; - /*! * Retrieves the multiplication style to use in the min-max methods. * @@ -114,7 +104,6 @@ namespace storm { static const std::string maximalIterationsOptionShortName; static const std::string precisionOptionName; static const std::string absoluteOptionName; - static const std::string markovAutomatonBoundedReachabilityMethodOptionName; static const std::string valueIterationMultiplicationStyleOptionName; static const std::string intervalIterationSymmetricUpdatesOptionName; static const std::string forceBoundsOptionName; diff --git a/src/storm/settings/modules/TimeBoundedSolverSettings.cpp b/src/storm/settings/modules/TimeBoundedSolverSettings.cpp new file mode 100644 index 000000000..88b323c8f --- /dev/null +++ b/src/storm/settings/modules/TimeBoundedSolverSettings.cpp @@ -0,0 +1,62 @@ +#include "storm/settings/modules/TimeBoundedSolverSettings.h" + +#include "storm/settings/Option.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/OptionBuilder.h" + +#include "storm/utility/macros.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string TimeBoundedSolverSettings::moduleName = "timebounded"; + + const std::string TimeBoundedSolverSettings::maMethodOptionName = "mamethod"; + const std::string TimeBoundedSolverSettings::precisionOptionName = "precision"; + const std::string TimeBoundedSolverSettings::absoluteOptionName = "absolute"; + const std::string TimeBoundedSolverSettings::unifPlusKappaOptionName = "kappa"; + + TimeBoundedSolverSettings::TimeBoundedSolverSettings() : ModuleSettings(moduleName) { + std::vector<std::string> maMethods = {"imca", "unifplus"}; + this->addOption(storm::settings::OptionBuilder(moduleName, maMethodOptionName, false, "The method to use to solve bounded reachability queries on MAs.").setIsAdvanced().addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(maMethods)).setDefaultValueString("unifplus").build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").setIsAdvanced().addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, absoluteOptionName, false, "Sets whether the relative or the absolute error is considered for detecting convergence.").setIsAdvanced().build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, unifPlusKappaOptionName, false, "The truncation factor used in unifPlus.").setIsAdvanced().addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("kappa", "The factor").setDefaultValueDouble(0.1).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); + + } + + bool TimeBoundedSolverSettings::isPrecisionSet() const { + return this->getOption(precisionOptionName).getHasOptionBeenSet(); + } + + double TimeBoundedSolverSettings::getPrecision() const { + return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); + } + + bool TimeBoundedSolverSettings::isRelativePrecision() const { + return !this->getOption(absoluteOptionName).getHasOptionBeenSet(); + } + + storm::solver::MaBoundedReachabilityMethod TimeBoundedSolverSettings::getMaMethod() const { + std::string techniqueAsString = this->getOption(maMethodOptionName).getArgumentByName("name").getValueAsString(); + if (techniqueAsString == "imca") { + return storm::solver::MaBoundedReachabilityMethod::Imca; + } + return storm::solver::MaBoundedReachabilityMethod::UnifPlus; + } + + bool TimeBoundedSolverSettings::isMaMethodSetFromDefaultValue() const { + return !this->getOption(maMethodOptionName).getArgumentByName("name").getHasBeenSet() || this->getOption(maMethodOptionName).getArgumentByName("name").wasSetFromDefaultValue(); + } + + double TimeBoundedSolverSettings::getUnifPlusKappa() const { + return this->getOption(unifPlusKappaOptionName).getArgumentByName("kappa").getValueAsDouble(); + } + + } + } +} diff --git a/src/storm/settings/modules/TimeBoundedSolverSettings.h b/src/storm/settings/modules/TimeBoundedSolverSettings.h new file mode 100644 index 000000000..8140da9ce --- /dev/null +++ b/src/storm/settings/modules/TimeBoundedSolverSettings.h @@ -0,0 +1,66 @@ +#pragma once + +#include "storm-config.h" +#include "storm/settings/modules/ModuleSettings.h" + +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the min/max solver settings. + */ + class TimeBoundedSolverSettings : public ModuleSettings { + public: + + TimeBoundedSolverSettings(); + + /*! + * Retrieves whether solving technique for time bounded reachability on Markov Automata has been set from its default value. + */ + bool isMaMethodSetFromDefaultValue() const; + + /*! + * Retrieves the selected solving technique for time bounded reachability on Markov Automata. + */ + storm::solver::MaBoundedReachabilityMethod getMaMethod() const; + + /*! + * Retrieves whether the precision has been set. + * + * @return True iff the precision has been set. + */ + bool isPrecisionSet() const; + + /*! + * Retrieves the precision that is used for detecting convergence. + * + * @return The precision to use for detecting convergence. + */ + double getPrecision() const; + + /*! + * Retrieves whether the convergence criterion has been set to relative or absolute. + */ + bool isRelativePrecision() const; + + /*! + * Retrieves the truncation factor used for unifPlus + */ + double getUnifPlusKappa() const; + + // The name of the module. + static const std::string moduleName; + + private: + static const std::string maMethodOptionName; + static const std::string precisionOptionName; + static const std::string absoluteOptionName; + static const std::string unifPlusKappaOptionName; + }; + + } + } +} diff --git a/src/storm/solver/EigenLinearEquationSolver.cpp b/src/storm/solver/EigenLinearEquationSolver.cpp index 6c96715cf..0ca9a4554 100644 --- a/src/storm/solver/EigenLinearEquationSolver.cpp +++ b/src/storm/solver/EigenLinearEquationSolver.cpp @@ -107,7 +107,7 @@ namespace storm { auto eigenX = StormEigen::Matrix<ValueType, StormEigen::Dynamic, 1>::Map(x.data(), x.size()); auto eigenB = StormEigen::Matrix<ValueType, StormEigen::Dynamic, 1>::Map(b.data(), b.size()); - auto solutionMethod = getMethod(env, false); + auto solutionMethod = getMethod(env, env.solver().isForceExact()); if (solutionMethod == EigenLinearEquationSolverMethod::SparseLU) { STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with sparse LU factorization (Eigen library)."); StormEigen::SparseLU<StormEigen::SparseMatrix<ValueType>, StormEigen::COLAMDOrdering<int>> solver; diff --git a/src/storm/solver/GmmxxLinearEquationSolver.cpp b/src/storm/solver/GmmxxLinearEquationSolver.cpp index 9ce51fa72..a42386c0e 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.cpp +++ b/src/storm/solver/GmmxxLinearEquationSolver.cpp @@ -46,6 +46,7 @@ namespace storm { template<typename ValueType> GmmxxLinearEquationSolverMethod GmmxxLinearEquationSolver<ValueType>::getMethod(Environment const& env) const { STORM_LOG_ERROR_COND(!env.solver().isForceSoundness(), "This linear equation solver does not support sound computations. Using unsound methods now..."); + STORM_LOG_ERROR_COND(!env.solver().isForceExact(), "This linear equation solver does not support exact computations. Using unsound methods now..."); return env.solver().gmmxx().getMethod(); } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 1925390f2..68f8da1b4 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -65,7 +65,7 @@ namespace storm { template<typename ValueType> bool IterativeMinMaxLinearEquationSolver<ValueType>::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const { bool result = false; - switch (getMethod(env, storm::NumberTraits<ValueType>::IsExact)) { + switch (getMethod(env, storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact())) { case MinMaxMethod::ValueIteration: result = solveEquationsValueIteration(env, dir, x, b); break; @@ -232,7 +232,7 @@ namespace storm { template<typename ValueType> MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver<ValueType>::getRequirements(Environment const& env, boost::optional<storm::solver::OptimizationDirection> const& direction, bool const& hasInitialScheduler) const { - auto method = getMethod(env, storm::NumberTraits<ValueType>::IsExact); + auto method = getMethod(env, storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()); // Check whether a linear equation solver is needed and potentially start with its requirements bool needsLinEqSolver = false; diff --git a/src/storm/solver/LinearEquationSolver.cpp b/src/storm/solver/LinearEquationSolver.cpp index 8207efcff..5d2884d86 100644 --- a/src/storm/solver/LinearEquationSolver.cpp +++ b/src/storm/solver/LinearEquationSolver.cpp @@ -128,8 +128,15 @@ namespace storm { std::unique_ptr<LinearEquationSolver<ValueType>> GeneralLinearEquationSolverFactory<ValueType>::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); - // Adjust the solver type if none was specified and we want sound computations - if (env.solver().isForceSoundness() && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological) { + // Adjust the solver type if none was specified and we want sound/exact computations + if (env.solver().isForceExact() && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological) { + if (env.solver().isLinearEquationSolverTypeSetFromDefaultValue()) { + type = EquationSolverType::Eigen; + STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver to guarantee exact results. If you want to override this, please explicitly specify a different solver."); + } else { + STORM_LOG_WARN("The selected solver does not yield exact results."); + } + } else if (env.solver().isForceSoundness() && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological) { if (env.solver().isLinearEquationSolverTypeSetFromDefaultValue()) { type = EquationSolverType::Native; STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver to guarantee sound results. If you want to override this, please explicitly specify a different solver."); diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index ca0142249..a79bc6b3e 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -922,7 +922,7 @@ namespace storm { template<typename ValueType> bool NativeLinearEquationSolver<ValueType>::internalSolveEquations(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> const& b) const { - switch(getMethod(env, storm::NumberTraits<ValueType>::IsExact)) { + switch(getMethod(env, storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact())) { case NativeLinearEquationSolverMethod::SOR: return this->solveEquationsSOR(env, x, b, storm::utility::convertNumber<ValueType>(env.solver().native().getSorOmega())); case NativeLinearEquationSolverMethod::GaussSeidel: @@ -946,7 +946,7 @@ namespace storm { template<typename ValueType> LinearEquationSolverProblemFormat NativeLinearEquationSolver<ValueType>::getEquationProblemFormat(Environment const& env) const { - auto method = getMethod(env, storm::NumberTraits<ValueType>::IsExact); + auto method = getMethod(env, storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()); if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::SoundValueIteration || method == NativeLinearEquationSolverMethod::RationalSearch || method == NativeLinearEquationSolverMethod::IntervalIteration) { return LinearEquationSolverProblemFormat::FixedPointSystem; } else { @@ -957,7 +957,7 @@ namespace storm { template<typename ValueType> LinearEquationSolverRequirements NativeLinearEquationSolver<ValueType>::getRequirements(Environment const& env) const { LinearEquationSolverRequirements requirements; - auto method = getMethod(env, storm::NumberTraits<ValueType>::IsExact); + auto method = getMethod(env, storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()); if (method == NativeLinearEquationSolverMethod::IntervalIteration) { requirements.requireBounds(); } else if (method == NativeLinearEquationSolverMethod::RationalSearch) { diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 0b6836b8a..9e69c09a4 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -62,6 +62,16 @@ namespace storm { return "invalid"; } + std::string toString(MaBoundedReachabilityMethod m) { + switch(m) { + case MaBoundedReachabilityMethod::Imca: + return "imca"; + case MaBoundedReachabilityMethod::UnifPlus: + return "unifplus"; + } + return "invalid"; + } + std::string toString(LpSolverType t) { switch(t) { case LpSolverType::Gurobi: diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index bad126df8..6bb1300fb 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -10,6 +10,7 @@ namespace storm { ExtendEnumsWithSelectionField(MultiplierType, Native, Gmmxx) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration, GainBiasEquations, LraDistributionEquations) + ExtendEnumsWithSelectionField(MaBoundedReachabilityMethod, Imca, UnifPlus) ExtendEnumsWithSelectionField(LpSolverType, Gurobi, Glpk, Z3) ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination, Topological) diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index a818f2706..8fcc46a80 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -72,7 +72,7 @@ namespace storm { template<typename ValueType> bool StandardGameSolver<ValueType>::solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector<ValueType>& x, std::vector<ValueType> const& b, std::vector<uint64_t>* player1Choices, std::vector<uint64_t>* player2Choices) const { - auto method = getMethod(env, std::is_same<ValueType, storm::RationalNumber>::value); + auto method = getMethod(env, std::is_same<ValueType, storm::RationalNumber>::value || env.solver().isForceExact()); STORM_LOG_INFO("Solving stochastic two player game over " << x.size() << " states using " << toString(method) << "."); switch (method) { case GameMethod::ValueIteration: diff --git a/src/storm/storage/Distribution.cpp b/src/storm/storage/Distribution.cpp index 9d0d89d19..f40afb402 100644 --- a/src/storm/storage/Distribution.cpp +++ b/src/storm/storage/Distribution.cpp @@ -19,6 +19,11 @@ namespace storm { // Intentionally left empty. } + template<typename ValueType, typename StateType> + void Distribution<ValueType, StateType>::reserve(uint64_t size) { + this->distribution.reserve(size); + } + template<typename ValueType, typename StateType> void Distribution<ValueType, StateType>::add(Distribution const& other) { container_type newDistribution; @@ -51,12 +56,7 @@ namespace storm { template<typename ValueType, typename StateType> void Distribution<ValueType, StateType>::addProbability(StateType const& state, ValueType const& probability) { - auto it = this->distribution.find(state); - if (it == this->distribution.end()) { - this->distribution.emplace_hint(it, state, probability); - } else { - it->second += probability; - } + this->distribution[state] += probability; } template<typename ValueType, typename StateType> diff --git a/src/storm/storage/Distribution.h b/src/storm/storage/Distribution.h index 1d0fbbd5f..d7e0bd2fb 100644 --- a/src/storm/storage/Distribution.h +++ b/src/storm/storage/Distribution.h @@ -32,6 +32,11 @@ namespace storm { Distribution(Distribution&& other) = default; Distribution& operator=(Distribution&& other) = default; + /* + * If the size of this distribution is known before adding probabilities,, this method can be used to reserve enough space. + */ + void reserve(uint64_t size); + /*! * Adds the given distribution to the current one. */ diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index ecf29de4a..59d158d96 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -586,6 +586,25 @@ namespace storm { return res; } + template<typename ValueType> + typename SparseMatrix<ValueType>::index_type SparseMatrix<ValueType>::getNumRowsInRowGroups(storm::storage::BitVector const& groupConstraint) const { + if (this->hasTrivialRowGrouping()) { + return groupConstraint.getNumberOfSetBits(); + } + index_type numRows = 0; + index_type rowGroupIndex = groupConstraint.getNextSetIndex(0); + while (rowGroupIndex < this->getRowGroupCount()) { + index_type start = this->getRowGroupIndices()[rowGroupIndex]; + rowGroupIndex = groupConstraint.getNextUnsetIndex(rowGroupIndex + 1); + index_type end = this->getRowGroupIndices()[rowGroupIndex]; + // All rows with index in [start,end) are selected. + numRows += end - start; + rowGroupIndex = groupConstraint.getNextSetIndex(rowGroupIndex + 1); + } + return numRows; + } + + template<typename ValueType> std::vector<typename SparseMatrix<ValueType>::index_type> const& SparseMatrix<ValueType>::getRowGroupIndices() const { // If there is no current row grouping, we need to create it. @@ -874,7 +893,7 @@ namespace storm { template<typename ValueType> std::vector<ValueType> SparseMatrix<ValueType>::getConstrainedRowGroupSumVector(storm::storage::BitVector const& rowGroupConstraint, storm::storage::BitVector const& columnConstraint) const { std::vector<ValueType> result; - result.reserve(rowGroupConstraint.getNumberOfSetBits()); + result.reserve(this->getNumRowsInRowGroups(rowGroupConstraint)); if (!this->hasTrivialRowGrouping()) { for (auto rowGroup : rowGroupConstraint) { for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) { diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index d3bbb5930..ad9c00ecd 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -573,6 +573,11 @@ namespace storm { */ index_type getSizeOfLargestRowGroup() const; + /*! + * Returns the total number of rows that are in one of the specified row groups. + */ + index_type getNumRowsInRowGroups(storm::storage::BitVector const& groupConstraint) const; + /*! * Returns the grouping of rows of this matrix. * diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp index 16d4fbfb6..2acbe742d 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp @@ -4,6 +4,7 @@ #include "storm/models/sparse/StandardRewardModel.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" +#include "storm/utility/Stopwatch.h" #include "storm/exceptions/UnexpectedException.h" @@ -54,6 +55,7 @@ namespace storm { * @param currentIndex The next free index that can be assigned to states. * @param hasPreorderNumber A bit that is used to keep track of the states that already have a preorder number. * @param preorderNumbers A vector storing the preorder number for each state. + * @param recursionStateStack memory used for the recursion stack. * @param s The stack S used by the algorithm. * @param p The stack S used by the algorithm. * @param stateHasScc A bit vector containing all states that have already been assigned to an SCC. @@ -63,12 +65,11 @@ namespace storm { * is increased. */ template <typename ValueType> - void performSccDecompositionGCM(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& nonTrivialStates, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector<uint_fast64_t>& preorderNumbers, std::vector<uint_fast64_t>& s, std::vector<uint_fast64_t>& p, storm::storage::BitVector& stateHasScc, std::vector<uint_fast64_t>& stateToSccMapping, uint_fast64_t& sccCount, bool /*forceTopologicalSort*/, std::vector<uint_fast64_t>* sccDepths) { + void performSccDecompositionGCM(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& nonTrivialStates, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector<uint_fast64_t>& preorderNumbers, std::vector<uint_fast64_t>& recursionStateStack, std::vector<uint_fast64_t>& s, std::vector<uint_fast64_t>& p, storm::storage::BitVector& stateHasScc, std::vector<uint_fast64_t>& stateToSccMapping, uint_fast64_t& sccCount, bool /*forceTopologicalSort*/, std::vector<uint_fast64_t>* sccDepths) { // The forceTopologicalSort flag can be ignored as this method always generates a topological sort. // Prepare the stack used for turning the recursive procedure into an iterative one. - std::vector<uint_fast64_t> recursionStateStack; - recursionStateStack.reserve(transitionMatrix.getRowGroupCount()); + STORM_LOG_ASSERT(recursionStateStack.empty(), "Expected an empty recursion stack."); recursionStateStack.push_back(startState); while (!recursionStateStack.empty()) { @@ -157,48 +158,55 @@ namespace storm { STORM_LOG_ASSERT(!options.choicesPtr || options.subsystemPtr, "Expecting subsystem if choices are given."); uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); - - // Set up the environment of the algorithm. - // Start with the two stacks it maintains. - std::vector<uint_fast64_t> s; - s.reserve(numberOfStates); - std::vector<uint_fast64_t> p; - p.reserve(numberOfStates); - - // We also need to store the preorder numbers of states and which states have been assigned to which SCC. - std::vector<uint_fast64_t> preorderNumbers(numberOfStates); - storm::storage::BitVector hasPreorderNumber(numberOfStates); - storm::storage::BitVector stateHasScc(numberOfStates); - std::vector<uint_fast64_t> stateToSccMapping(numberOfStates); uint_fast64_t sccCount = 0; - - // Store scc depths if requested - std::vector<uint_fast64_t>* sccDepthsPtr = nullptr; - sccDepths = boost::none; - if (options.isComputeSccDepthsSet || options.areOnlyBottomSccsConsidered) { - sccDepths = std::vector<uint_fast64_t>(); - sccDepthsPtr = &sccDepths.get(); - } - - // Finally, we need to keep of trivial states (singleton SCCs without selfloop). + + // We need to keep of trivial states (singleton SCCs without selfloop). storm::storage::BitVector nonTrivialStates(numberOfStates, false); - // Start the search for SCCs from every state in the block. - uint_fast64_t currentIndex = 0; - if (options.subsystemPtr) { - for (auto state : *options.subsystemPtr) { - if (!hasPreorderNumber.get(state)) { - performSccDecompositionGCM(transitionMatrix, state, nonTrivialStates, options.subsystemPtr, options.choicesPtr, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount, options.isTopologicalSortForced, sccDepthsPtr); - } + // Obtain a mapping from states to the SCC it belongs to + std::vector<uint_fast64_t> stateToSccMapping(numberOfStates); + { + + // Set up the environment of the algorithm. + // Start with the two stacks it maintains. + // This is to reduce memory (re-)allocations + std::vector<uint_fast64_t> s; + s.reserve(numberOfStates); + std::vector<uint_fast64_t> p; + p.reserve(numberOfStates); + std::vector<uint_fast64_t> recursionStateStack; + recursionStateStack.reserve(numberOfStates); + + // We also need to store the preorder numbers of states and which states have been assigned to which SCC. + std::vector<uint_fast64_t> preorderNumbers(numberOfStates); + storm::storage::BitVector hasPreorderNumber(numberOfStates); + storm::storage::BitVector stateHasScc(numberOfStates); + + // Store scc depths if requested + std::vector<uint_fast64_t>* sccDepthsPtr = nullptr; + sccDepths = boost::none; + if (options.isComputeSccDepthsSet || options.areOnlyBottomSccsConsidered) { + sccDepths = std::vector<uint_fast64_t>(); + sccDepthsPtr = &sccDepths.get(); } - } else { - for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { - if (!hasPreorderNumber.get(state)) { - performSccDecompositionGCM(transitionMatrix, state, nonTrivialStates, options.subsystemPtr, options.choicesPtr, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount, options.isTopologicalSortForced, sccDepthsPtr); + + + // Start the search for SCCs from every state in the block. + uint_fast64_t currentIndex = 0; + if (options.subsystemPtr) { + for (auto state : *options.subsystemPtr) { + if (!hasPreorderNumber.get(state)) { + performSccDecompositionGCM(transitionMatrix, state, nonTrivialStates, options.subsystemPtr, options.choicesPtr, currentIndex, hasPreorderNumber, preorderNumbers, recursionStateStack, s, p, stateHasScc, stateToSccMapping, sccCount, options.isTopologicalSortForced, sccDepthsPtr); + } + } + } else { + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + if (!hasPreorderNumber.get(state)) { + performSccDecompositionGCM(transitionMatrix, state, nonTrivialStates, options.subsystemPtr, options.choicesPtr, currentIndex, hasPreorderNumber, preorderNumbers, recursionStateStack, s, p, stateHasScc, stateToSccMapping, sccCount, options.isTopologicalSortForced, sccDepthsPtr); + } } } } - // After we obtained the state-to-SCC mapping, we build the actual blocks. this->blocks.resize(sccCount); for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { diff --git a/src/storm/storage/dd/Add.cpp b/src/storm/storage/dd/Add.cpp index 5f1b05586..a9cfbafdf 100644 --- a/src/storm/storage/dd/Add.cpp +++ b/src/storm/storage/dd/Add.cpp @@ -533,7 +533,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - std::vector<ValueType> Add<LibraryType, ValueType>::toVector(storm::dd::Add<LibraryType, ValueType> const& matrix, std::vector<uint_fast64_t> const& rowGroupIndices, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { + std::vector<ValueType> Add<LibraryType, ValueType>::toVector(storm::dd::Add<LibraryType, ValueType> const& matrix, std::vector<uint_fast64_t> const& rowGroupIndices, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd) const { std::vector<uint_fast64_t> ddRowVariableIndices; std::vector<uint_fast64_t> ddColumnVariableIndices; std::vector<uint_fast64_t> ddGroupVariableIndices; @@ -894,6 +894,38 @@ namespace storm { template<DdType LibraryType, typename ValueType> std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> Add<LibraryType, ValueType>::toMatrixVector(std::vector<uint_fast64_t>&& rowGroupIndices, storm::dd::Add<LibraryType, ValueType> const& vector, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { + auto resultAsVector = toMatrixVectors(std::move(rowGroupIndices), {vector}, rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd); + return std::make_pair(resultAsVector.first, resultAsVector.second.front()); + } + + template<DdType LibraryType, typename ValueType> + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<std::vector<ValueType>>> Add<LibraryType, ValueType>::toMatrixVectors(std::vector<storm::dd::Add<LibraryType, ValueType>> const& vectors, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { + std::set<storm::expressions::Variable> rowMetaVariables; + std::set<storm::expressions::Variable> columnMetaVariables; + + for (auto const& variable : this->getContainedMetaVariables()) { + // If the meta variable is a group meta variable, we do not insert it into the set of row/column meta variables. + if (groupMetaVariables.find(variable) != groupMetaVariables.end()) { + continue; + } + + if (variable.getName().size() > 0 && variable.getName().back() == '\'') { + columnMetaVariables.insert(variable); + } else { + rowMetaVariables.insert(variable); + } + } + // Count how many choices each row group has. + Bdd<LibraryType> vectorsNotZero = this->getDdManager().getBddZero(); + for (auto const& v : vectors) { + vectorsNotZero |= v.notZero(); + } + std::vector<uint_fast64_t> rowGroupIndices = (this->notZero().existsAbstract(columnMetaVariables) || vectorsNotZero).template toAdd<uint_fast64_t>().sumAbstract(groupMetaVariables).toVector(rowOdd); + return toMatrixVectors(std::move(rowGroupIndices), vectors, rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd); + } + + template<DdType LibraryType, typename ValueType> + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<std::vector<ValueType>>> Add<LibraryType, ValueType>::toMatrixVectors(std::vector<uint_fast64_t>&& rowGroupIndices, std::vector<storm::dd::Add<LibraryType, ValueType>> const& vectors, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::vector<uint_fast64_t> ddRowVariableIndices; std::vector<uint_fast64_t> ddColumnVariableIndices; std::vector<uint_fast64_t> ddGroupVariableIndices; @@ -936,14 +968,36 @@ namespace storm { } rowGroupIndices[0] = 0; - // Create the explicit vector we need to fill later. - std::vector<ValueType> explicitVector(rowGroupIndices.back()); + // Create the explicit vectors we need to fill later. + std::vector<std::vector<ValueType>> explicitVectors(vectors.size()); + for (auto& v : explicitVectors) { + v.resize(rowGroupIndices.back()); + } // Next, we split the matrix into one for each group. Note that this only works if the group variables are at the very top. - std::vector<std::pair<InternalAdd<LibraryType, ValueType>, InternalAdd<LibraryType, ValueType>>> internalAddGroups = internalAdd.splitIntoGroups(vector, ddGroupVariableIndices); - std::vector<std::pair<Add<LibraryType, ValueType>, Add<LibraryType, ValueType>>> groups; - for (auto const& internalAdd : internalAddGroups) { - groups.push_back(std::make_pair(Add<LibraryType, ValueType>(this->getDdManager(), internalAdd.first, rowAndColumnMetaVariables), Add<LibraryType, ValueType>(this->getDdManager(), internalAdd.second, rowMetaVariables))); + std::vector<std::vector<Add<LibraryType, ValueType>>> groups; + if (vectors.size() == 1) { + // This version potentially has slightly reduced overhead + std::vector<std::pair<InternalAdd<LibraryType, ValueType>, InternalAdd<LibraryType, ValueType>>> internalAddGroups = internalAdd.splitIntoGroups(vectors.front(), ddGroupVariableIndices); + for (auto const& internalAdd : internalAddGroups) { + groups.push_back({Add<LibraryType, ValueType>(this->getDdManager(), internalAdd.second, rowMetaVariables), Add<LibraryType, ValueType>(this->getDdManager(), internalAdd.first, rowAndColumnMetaVariables)}); + } + } else { + std::vector<InternalAdd<LibraryType, ValueType>> internalVectors; + for (Add<LibraryType, ValueType> const& v : vectors) { + internalVectors.push_back(v.getInternalAdd()); + } + std::vector<std::vector<InternalAdd<LibraryType, ValueType>>> internalAddGroups = internalAdd.splitIntoGroups(internalVectors, ddGroupVariableIndices); + for (auto const& internalAddGroup : internalAddGroups) { + STORM_LOG_ASSERT(internalAddGroup.size() == vectors.size() + 1, "Unexpected group size."); + std::vector<Add<LibraryType, ValueType>> group; + for (uint64_t vectorIndex = 0; vectorIndex < vectors.size(); ++vectorIndex) { + group.push_back(Add<LibraryType, ValueType>(this->getDdManager(), internalAddGroup[vectorIndex], rowMetaVariables)); + } + // The last group member corresponds to the matrix. + group.push_back(Add<LibraryType, ValueType>(this->getDdManager(), internalAddGroup.back(), rowAndColumnMetaVariables)); + groups.push_back(std::move(group)); + } } // Create the actual storage for the non-zero entries. @@ -955,16 +1009,19 @@ namespace storm { std::vector<InternalAdd<LibraryType, uint_fast64_t>> statesWithGroupEnabled(groups.size()); InternalAdd<LibraryType, uint_fast64_t> stateToRowGroupCount = this->getDdManager().template getAddZero<uint_fast64_t>(); for (uint_fast64_t i = 0; i < groups.size(); ++i) { - std::pair<Add<LibraryType, ValueType>, Add<LibraryType, ValueType>> const& ddPair = groups[i]; - Bdd<LibraryType> matrixDdNotZero = ddPair.first.notZero(); - Bdd<LibraryType> vectorDdNotZero = ddPair.second.notZero(); + std::vector<Add<LibraryType, ValueType>> const& group = groups[i]; + Bdd<LibraryType> matrixDdNotZero = group.back().notZero(); std::vector<uint64_t> tmpRowIndications = matrixDdNotZero.template toAdd<uint_fast64_t>().sumAbstract(columnMetaVariables).toVector(rowOdd); for (uint64_t offset = 0; offset < tmpRowIndications.size(); ++offset) { rowIndications[rowGroupIndices[offset]] += tmpRowIndications[offset]; } - ddPair.second.internalAdd.composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, explicitVector, std::plus<ValueType>()); + Bdd<LibraryType> vectorDdNotZero = this->getDdManager().getBddZero(); + for (uint64_t vectorIndex = 0; vectorIndex < vectors.size(); ++vectorIndex) { + vectorDdNotZero |= group[vectorIndex].notZero(); + group[vectorIndex].internalAdd.composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, explicitVectors[vectorIndex], std::plus<ValueType>()); + } statesWithGroupEnabled[i] = (matrixDdNotZero.existsAbstract(columnMetaVariables) || vectorDdNotZero).template toAdd<uint_fast64_t>(); stateToRowGroupCount += statesWithGroupEnabled[i]; @@ -986,7 +1043,7 @@ namespace storm { // Now actually fill the entry vector. for (uint_fast64_t i = 0; i < groups.size(); ++i) { - auto const& dd = groups[i].first; + auto const& dd = groups[i].back(); dd.internalAdd.toMatrixComponents(rowGroupIndices, rowIndications, columnsAndValues, rowOdd, columnOdd, ddRowVariableIndices, ddColumnVariableIndices, true); statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, std::plus<uint_fast64_t>()); @@ -1001,9 +1058,10 @@ namespace storm { } rowIndications[0] = 0; - return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)), std::move(explicitVector)); + return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)), std::move(explicitVectors)); } + template<DdType LibraryType, typename ValueType> void Add<LibraryType, ValueType>::exportToDot(std::string const& filename, bool showVariablesIfPossible) const { diff --git a/src/storm/storage/dd/Add.h b/src/storm/storage/dd/Add.h index 2d94b07fc..f74b75dd2 100644 --- a/src/storm/storage/dd/Add.h +++ b/src/storm/storage/dd/Add.h @@ -581,21 +581,22 @@ namespace storm { /*! * Converts the ADD to a row-grouped vector while respecting the row group sizes of the provided matrix. * That is, if the vector has a zero entry for some row in a row group for which the matrix has a non-zero - * row, the value at the vector will be correctly set to zero. Note: this function assumes that the meta - * variables used to distinguish different row groups are at the very top of the ADD. + * row, the value at the vector will be correctly set to zero. + * @note: This function assumes that the meta variables used to distinguish different row groups + * are at the very top of the ADD. + * @note: The order of the rows within the groups could be inconsistent with the order obtained by other toMatrix/toVector methods. * * @param matrix The symbolic matrix whose row group sizes to respect. - * @param rowGroupSizes A vector specifying the sizes of the row groups. + * @param rowGroupIndices A vector specifying the sizes of the row groups. * @param rowMetaVariables The meta variables that encode the rows of the matrix. * @param columnMetaVariables The meta variables that encode the columns of the matrix. * @param groupMetaVariables The meta variables that are used to distinguish different row groups. * @param rowOdd The ODD used for determining the correct row. - * @param columnOdd The ODD used for determining the correct column. * @return The matrix that is represented by this ADD and and a vector corresponding to the symbolic vector * (if it was given). * @return The vector that is represented by this ADD. */ - std::vector<ValueType> toVector(storm::dd::Add<LibraryType, ValueType> const& matrix, std::vector<uint_fast64_t> const& rowGroupSizes, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; + std::vector<ValueType> toVector(storm::dd::Add<LibraryType, ValueType> const& matrix, std::vector<uint_fast64_t> const& rowGroupIndices, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd) const; /*! * Converts the ADD to a (sparse) matrix. All contained non-primed variables are assumed to encode the @@ -632,6 +633,7 @@ namespace storm { * Converts the ADD to a row-grouped (sparse) matrix. The given offset-labeled DDs are used to * determine the correct row and column, respectively, for each entry. Note: this function assumes that * the meta variables used to distinguish different row groups are at the very top of the ADD. + * @note: The order of the rows within the groups could be inconsistent with the order obtained by other toMatrix/toVector methods. * * @param groupMetaVariables The meta variables that are used to distinguish different row groups. * @param rowOdd The ODD used for determining the correct row. @@ -645,6 +647,7 @@ namespace storm { * correct row and column, respectively, for each entry. If requested, it builds a labeling of the rows * that is derived from the group variable encodings. Note: this function assumes that the meta variables * used to distinguish different row groups are at the very top of the ADD. + * @note: The order of the rows within the groups could be inconsistent with the order obtained by other toMatrix/toVector methods. * * @param rowMetaVariables The meta variables that encode the rows of the matrix. * @param columnMetaVariables The meta variables that encode the columns of the matrix. @@ -677,6 +680,7 @@ namespace storm { * The given offset-labeled DDs are used to determine the correct row and column, respectively, for each * entry. Note: this function assumes that the meta variables used to distinguish different row groups are * at the very top of the ADD. + * @note: The order of the rows within the groups could be inconsistent with the order obtained by other toMatrix/toVector methods. * * @param vector The symbolic vector to convert. * @param groupMetaVariables The meta variables that are used to distinguish different row groups. @@ -686,6 +690,22 @@ namespace storm { */ std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> toMatrixVector(std::vector<uint_fast64_t>&& rowGroupSizes, storm::dd::Add<LibraryType, ValueType> const& vector, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; + + /*! + * Converts the ADD to a row-grouped (sparse) matrix and the given vectors to row-grouped vectors. + * The given offset-labeled DDs are used to determine the correct row and column, respectively, for each + * entry. Note: this function assumes that the meta variables used to distinguish different row groups are + * at the very top of the ADD. + * @note: The order of the rows within the groups could be inconsistent with the order obtained by other toMatrix/toVector methods. + * + * @param vectors The symbolic vectors to convert. + * @param groupMetaVariables The meta variables that are used to distinguish different row groups. + * @param rowOdd The ODD used for determining the correct row. + * @param columnOdd The ODD used for determining the correct column. + * @return The matrix that is represented by this ADD. + */ + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<std::vector<ValueType>>> toMatrixVectors(std::vector<storm::dd::Add<LibraryType, ValueType>> const& vectors, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<std::vector<ValueType>>> toMatrixVectors(std::vector<uint_fast64_t>&& rowGroupSizes, std::vector<storm::dd::Add<LibraryType, ValueType>> const& vectors, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; /*! * Exports the DD to the given file in the dot format. diff --git a/src/storm/storage/dd/BisimulationDecomposition.cpp b/src/storm/storage/dd/BisimulationDecomposition.cpp index d43dd9c65..a0eeae5e4 100644 --- a/src/storm/storage/dd/BisimulationDecomposition.cpp +++ b/src/storm/storage/dd/BisimulationDecomposition.cpp @@ -129,18 +129,18 @@ namespace storm { } template <storm::dd::DdType DdType, typename ValueType, typename ExportValueType> - std::shared_ptr<storm::models::Model<ExportValueType>> BisimulationDecomposition<DdType, ValueType, ExportValueType>::getQuotient() const { + std::shared_ptr<storm::models::Model<ExportValueType>> BisimulationDecomposition<DdType, ValueType, ExportValueType>::getQuotient(storm::dd::bisimulation::QuotientFormat const& quotientFormat) const { std::shared_ptr<storm::models::Model<ExportValueType>> quotient; if (this->refiner->getStatus() == Status::FixedPoint) { STORM_LOG_INFO("Starting full quotient extraction."); - QuotientExtractor<DdType, ValueType, ExportValueType> extractor; + QuotientExtractor<DdType, ValueType, ExportValueType> extractor(quotientFormat); quotient = extractor.extract(model, refiner->getStatePartition(), preservationInformation); } else { STORM_LOG_THROW(model.getType() == storm::models::ModelType::Dtmc || model.getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidOperationException, "Can only extract partial quotient for discrete-time models."); STORM_LOG_INFO("Starting partial quotient extraction."); if (!partialQuotientExtractor) { - partialQuotientExtractor = std::make_unique<bisimulation::PartialQuotientExtractor<DdType, ValueType, ExportValueType>>(model); + partialQuotientExtractor = std::make_unique<bisimulation::PartialQuotientExtractor<DdType, ValueType, ExportValueType>>(model, quotientFormat); } quotient = partialQuotientExtractor->extract(refiner->getStatePartition(), preservationInformation); diff --git a/src/storm/storage/dd/BisimulationDecomposition.h b/src/storm/storage/dd/BisimulationDecomposition.h index 1a552c497..36cee976b 100644 --- a/src/storm/storage/dd/BisimulationDecomposition.h +++ b/src/storm/storage/dd/BisimulationDecomposition.h @@ -7,6 +7,7 @@ #include "storm/storage/bisimulation/BisimulationType.h" #include "storm/storage/dd/bisimulation/SignatureMode.h" #include "storm/storage/dd/bisimulation/PreservationInformation.h" +#include "storm/storage/dd/bisimulation/QuotientFormat.h" #include "storm/logic/Formula.h" @@ -64,7 +65,7 @@ namespace storm { /*! * Retrieves the quotient model after the bisimulation decomposition was computed. */ - std::shared_ptr<storm::models::Model<ExportValueType>> getQuotient() const; + std::shared_ptr<storm::models::Model<ExportValueType>> getQuotient(storm::dd::bisimulation::QuotientFormat const& quotientFormat) const; private: void initialize(); diff --git a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp index fea92c755..06c387781 100644 --- a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp @@ -16,11 +16,11 @@ namespace storm { namespace bisimulation { template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType> - PartialQuotientExtractor<DdType, ValueType, ExportValueType>::PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model) : model(model) { - auto const& settings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); - this->quotientFormat = settings.getQuotientFormat(); - - STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); + PartialQuotientExtractor<DdType, ValueType, ExportValueType>::PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::dd::bisimulation::QuotientFormat const& quotientFormat) : model(model), quotientFormat(quotientFormat) { + if (this->quotientFormat != storm::dd::bisimulation::QuotientFormat::Dd) { + STORM_LOG_ERROR("Only DD-based partial quotient extraction is currently supported. Switching to DD-based extraction."); + this->quotientFormat = storm::dd::bisimulation::QuotientFormat::Dd; + } } template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType> @@ -28,7 +28,7 @@ namespace storm { auto start = std::chrono::high_resolution_clock::now(); std::shared_ptr<storm::models::Model<ExportValueType>> result; - STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); + STORM_LOG_THROW(this->quotientFormat == storm::dd::bisimulation::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); result = extractDdQuotient(partition, preservationInformation); auto end = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Quotient extraction completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms."); diff --git a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h index d5c638c2a..df38bf696 100644 --- a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h +++ b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h @@ -19,7 +19,7 @@ namespace storm { template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType> class PartialQuotientExtractor { public: - PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model); + PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::dd::bisimulation::QuotientFormat const& quotientFormat); std::shared_ptr<storm::models::Model<ExportValueType>> extract(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation); @@ -29,7 +29,7 @@ namespace storm { // The model for which to compute the partial quotient. storm::models::symbolic::Model<DdType, ValueType> const& model; - storm::settings::modules::BisimulationSettings::QuotientFormat quotientFormat; + storm::dd::bisimulation::QuotientFormat quotientFormat; }; } diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp index 36f7f1fe3..ed94fbff8 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp @@ -818,18 +818,17 @@ namespace storm { }; template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType> - QuotientExtractor<DdType, ValueType, ExportValueType>::QuotientExtractor() : useRepresentatives(false) { + QuotientExtractor<DdType, ValueType, ExportValueType>::QuotientExtractor(storm::dd::bisimulation::QuotientFormat const& quotientFormat) : useRepresentatives(false), quotientFormat(quotientFormat) { auto const& settings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); this->useRepresentatives = settings.isUseRepresentativesSet(); this->useOriginalVariables = settings.isUseOriginalVariablesSet(); - this->quotientFormat = settings.getQuotientFormat(); } template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType> std::shared_ptr<storm::models::Model<ExportValueType>> QuotientExtractor<DdType, ValueType, ExportValueType>::extract(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) { auto start = std::chrono::high_resolution_clock::now(); std::shared_ptr<storm::models::Model<ExportValueType>> result; - if (quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Sparse) { + if (quotientFormat == storm::dd::bisimulation::QuotientFormat::Sparse) { result = extractSparseQuotient(model, partition, preservationInformation); } else { result = extractDdQuotient(model, partition, preservationInformation); diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.h b/src/storm/storage/dd/bisimulation/QuotientExtractor.h index 422453bf7..2ecfe41a3 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.h +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.h @@ -19,7 +19,7 @@ namespace storm { template <storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType> class QuotientExtractor { public: - QuotientExtractor(); + QuotientExtractor(storm::dd::bisimulation::QuotientFormat const& quotientFormat); std::shared_ptr<storm::models::Model<ExportValueType>> extract(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation); @@ -32,7 +32,7 @@ namespace storm { bool useRepresentatives; bool useOriginalVariables; - storm::settings::modules::BisimulationSettings::QuotientFormat quotientFormat; + storm::dd::bisimulation::QuotientFormat quotientFormat; }; } diff --git a/src/storm/storage/dd/bisimulation/QuotientFormat.h b/src/storm/storage/dd/bisimulation/QuotientFormat.h new file mode 100644 index 000000000..5ce91bd07 --- /dev/null +++ b/src/storm/storage/dd/bisimulation/QuotientFormat.h @@ -0,0 +1,9 @@ +#pragma once + +namespace storm { + namespace dd { + namespace bisimulation { + enum class QuotientFormat { Sparse, Dd }; + } + } +} diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp index d94e6cadc..0f982488d 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp @@ -596,6 +596,8 @@ namespace storm { splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } else { + // FIXME: We first traverse the else successor (unlike other variants of this method). + // Otherwise, the GameBasedMdpModelCheckerTest would not terminate. See github issue #64 splitIntoGroupsRec(Cudd_E(dd), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(Cudd_T(dd), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } @@ -634,6 +636,58 @@ namespace storm { } } + template<typename ValueType> + std::vector<std::vector<InternalAdd<DdType::CUDD, ValueType>>> InternalAdd<DdType::CUDD, ValueType>::splitIntoGroups(std::vector<InternalAdd<DdType::CUDD, ValueType>> const& vectors, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const { + std::vector<std::vector<InternalAdd<DdType::CUDD, ValueType>>> result; + std::vector<DdNode*> dds; + for (auto const& vector : vectors) { + dds.push_back(vector.getCuddDdNode()); + } + dds.push_back(this->getCuddDdNode()); + + splitIntoGroupsRec(dds, result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); + return result; + } + + template<typename ValueType> + void InternalAdd<DdType::CUDD, ValueType>::splitIntoGroupsRec(std::vector<DdNode*> const& dds, std::vector<std::vector<InternalAdd<DdType::CUDD, ValueType>>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { + // For the empty DD, we do not need to create a group. + { + bool emptyDd = true; + for (auto const& dd : dds) { + if (dd != Cudd_ReadZero(ddManager->getCuddManager().getManager())) { + emptyDd = false; + break; + } + } + if (emptyDd) { + return; + } + } + + if (currentLevel == maxLevel) { + std::vector<InternalAdd<DdType::CUDD, ValueType>> newGroup; + for (auto dd : dds) { + newGroup.emplace_back(ddManager, cudd::ADD(ddManager->getCuddManager(), dd)); + } + groups.push_back(std::move(newGroup)); + } else { + std::vector<DdNode*> thenSubDds(dds), elseSubDds(dds); + for (uint64_t ddIndex = 0; ddIndex < dds.size(); ++ddIndex) { + auto const& dd = dds[ddIndex]; + if (ddGroupVariableIndices[currentLevel] == Cudd_NodeReadIndex(dd)) { + thenSubDds[ddIndex] = Cudd_T(dd); + elseSubDds[ddIndex] = Cudd_E(dd); + } + } + splitIntoGroupsRec(thenSubDds, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(elseSubDds, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } + } + + + + template<typename ValueType> void InternalAdd<DdType::CUDD, ValueType>::toMatrixComponents(std::vector<uint_fast64_t> const& rowGroupIndices, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd const& rowOdd, Odd const& columnOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const { return toMatrixComponentsRec(this->getCuddDdNode(), rowGroupIndices, rowIndications, columnsAndValues, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, writeValues); diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.h b/src/storm/storage/dd/cudd/InternalCuddAdd.h index 21788a7a7..dd80cb18c 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.h +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.h @@ -609,6 +609,17 @@ namespace storm { */ std::vector<std::pair<InternalAdd<DdType::CUDD, ValueType>, InternalAdd<DdType::CUDD, ValueType>>> splitIntoGroups(InternalAdd<DdType::CUDD, ValueType> vector, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const; + /*! + * Simultaneously splits the ADD and the given vector ADDs into several ADDs that differ in the encoding of + * the given group variables (given via indices). + * + * @param vectors The vectors to split (in addition to the current ADD). + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of vectors of ADDs such that result.size() is the number of groups and result[i] refers to all ADDs within the same group i (wrt. to the encoding of the given variables). + * result[i].back() always refers to this ADD. + */ + std::vector<std::vector<InternalAdd<DdType::CUDD, ValueType>>> splitIntoGroups(std::vector<InternalAdd<DdType::CUDD, ValueType>> const& vectors, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const; + /*! * Translates the ADD into the components needed for constructing a matrix. * @@ -716,6 +727,18 @@ namespace storm { */ void splitIntoGroupsRec(DdNode* dd1, DdNode* dd2, std::vector<std::pair<InternalAdd<DdType::CUDD, ValueType>, InternalAdd<DdType::CUDD, ValueType>>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + /*! + * Splits the given DDs into the groups using the given group variables. + * + * @param dds The DDs to split. + * @param negatedDds indicates which of the DDs need to be interpreted as negated. + * @param groups A vector that is to be filled with the DDs for the individual groups. + * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + */ + void splitIntoGroupsRec(std::vector<DdNode*> const& dds, std::vector<std::vector<InternalAdd<DdType::CUDD, ValueType>>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + /*! * Helper function to convert the DD into a (sparse) matrix. * diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp index 8ede93854..1d02cadb3 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp @@ -986,6 +986,22 @@ namespace storm { return result; } + template<typename ValueType> + std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>> InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroups(std::vector<InternalAdd<DdType::Sylvan, ValueType>> const& vectors, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const { + std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>> result; + std::vector<MTBDD> dds; + storm::storage::BitVector negatedDds(vectors.size() + 1); + for (auto const& vector : vectors) { + negatedDds.set(dds.size(), mtbdd_hascomp(vector.getSylvanMtbdd().GetMTBDD())); + dds.push_back(mtbdd_regular(vector.getSylvanMtbdd().GetMTBDD())); + } + dds.push_back(this->getSylvanMtbdd().GetMTBDD()); + negatedDds.set(vectors.size(), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD())); + + splitIntoGroupsRec(dds, negatedDds, result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); + return result; + } + template<typename ValueType> void InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroupsRec(MTBDD dd, bool negated, std::vector<InternalAdd<DdType::Sylvan, ValueType>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { // For the empty DD, we do not need to create a group. @@ -1007,6 +1023,8 @@ namespace storm { bool elseComplemented = mtbdd_hascomp(elseDdNode) ^ negated; bool thenComplemented = mtbdd_hascomp(thenDdNode) ^ negated; + // FIXME: We first traverse the else successor (unlike other variants of this method). + // Otherwise, the GameBasedMdpModelCheckerTest would not terminate. See github issue #64 splitIntoGroupsRec(mtbdd_regular(elseDdNode), elseComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(mtbdd_regular(thenDdNode), thenComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } @@ -1063,6 +1081,48 @@ namespace storm { } } + template<typename ValueType> + void InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroupsRec(std::vector<MTBDD> const& dds, storm::storage::BitVector const& negatedDds, std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { + // For the empty DD, we do not need to create a group. + { + bool emptyDd = true; + for (auto const& dd : dds) { + if (!(mtbdd_isleaf(dd) && mtbdd_iszero(dd))) { + emptyDd = false; + break; + } + } + if (emptyDd) { + return; + } + } + + if (currentLevel == maxLevel) { + std::vector<InternalAdd<DdType::Sylvan, ValueType>> newGroup; + for (uint64_t ddIndex = 0; ddIndex < dds.size(); ++ddIndex) { + newGroup.emplace_back(ddManager, negatedDds.get(ddIndex) ? sylvan::Mtbdd(dds[ddIndex]).Negate() : sylvan::Mtbdd(dds[ddIndex])); + } + groups.push_back(std::move(newGroup)); + } else { + std::vector<MTBDD> thenSubDds(dds), elseSubDds(dds); + storm::storage::BitVector thenNegatedSubDds(negatedDds), elseNegatedSubDds(negatedDds); + for (uint64_t ddIndex = 0; ddIndex < dds.size(); ++ddIndex) { + auto const& dd = dds[ddIndex]; + if (!mtbdd_isleaf(dd) && ddGroupVariableIndices[currentLevel] == mtbdd_getvar(dd)) { + MTBDD ddThenNode = mtbdd_gethigh(dd); + MTBDD ddElseNode = mtbdd_getlow(dd); + thenSubDds[ddIndex] = mtbdd_regular(ddThenNode); + elseSubDds[ddIndex] = mtbdd_regular(ddElseNode); + // Determine whether we have to evaluate the successors as if they were complemented. + thenNegatedSubDds.set(ddIndex, mtbdd_hascomp(ddThenNode) ^ negatedDds.get(ddIndex)); + elseNegatedSubDds.set(ddIndex, mtbdd_hascomp(ddElseNode) ^ negatedDds.get(ddIndex)); + } + } + splitIntoGroupsRec(thenSubDds, thenNegatedSubDds, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(elseSubDds, elseNegatedSubDds, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } + } + template<typename ValueType> void InternalAdd<DdType::Sylvan, ValueType>::toMatrixComponents(std::vector<uint_fast64_t> const& rowGroupIndices, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd const& rowOdd, Odd const& columnOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const { return toMatrixComponentsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), rowGroupIndices, rowIndications, columnsAndValues, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, writeValues); diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h index 6e9238481..19a4c3882 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h @@ -601,6 +601,17 @@ namespace storm { */ std::vector<std::pair<InternalAdd<DdType::Sylvan, ValueType>, InternalAdd<DdType::Sylvan, ValueType>>> splitIntoGroups(InternalAdd<DdType::Sylvan, ValueType> vector, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const; + /*! + * Simultaneously splits the ADD and the given vector ADDs into several ADDs that differ in the encoding of + * the given group variables (given via indices). + * + * @param vectors The vectors to split (in addition to the current ADD). + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of vectors of ADDs such that result.size() is the number of groups and result[i] refers to all ADDs within the same group i (wrt. to the encoding of the given variables). + * result[i].back() always refers to this ADD. + */ + std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>> splitIntoGroups(std::vector<InternalAdd<DdType::Sylvan, ValueType>> const& vectors, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const; + /*! * Translates the ADD into the components needed for constructing a matrix. * @@ -702,7 +713,6 @@ namespace storm { * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. - * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. */ void splitIntoGroupsRec(MTBDD dd, bool negated, std::vector<InternalAdd<DdType::Sylvan, ValueType>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; @@ -717,10 +727,21 @@ namespace storm { * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. - * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. */ void splitIntoGroupsRec(MTBDD dd1, bool negated1, MTBDD dd2, bool negated2, std::vector<std::pair<InternalAdd<DdType::Sylvan, ValueType>, InternalAdd<DdType::Sylvan, ValueType>>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + /*! + * Splits the given DDs into the groups using the given group variables. + * + * @param dds The DDs to split. + * @param negatedDds indicates which of the DDs need to be interpreted as negated. + * @param groups A vector that is to be filled with the DDs for the individual groups. + * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + */ + void splitIntoGroupsRec(std::vector<MTBDD> const& dds, storm::storage::BitVector const& negatedDds, std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + /*! * Builds an ADD representing the given vector. * diff --git a/src/storm/storage/expressions/ExprtkCompiledExpression.h b/src/storm/storage/expressions/ExprtkCompiledExpression.h index b2c98fc2b..1e88424b3 100644 --- a/src/storm/storage/expressions/ExprtkCompiledExpression.h +++ b/src/storm/storage/expressions/ExprtkCompiledExpression.h @@ -2,7 +2,7 @@ #include "storm/storage/expressions/CompiledExpression.h" -#include "storm/utility/exprtk.h" +#include "storm/adapters/ExprttkAdapter.h" namespace storm { namespace expressions { diff --git a/src/storm/storage/expressions/ExprtkExpressionEvaluator.h b/src/storm/storage/expressions/ExprtkExpressionEvaluator.h index e6a7c6fb4..874a35af8 100755 --- a/src/storm/storage/expressions/ExprtkExpressionEvaluator.h +++ b/src/storm/storage/expressions/ExprtkExpressionEvaluator.h @@ -6,7 +6,7 @@ #include "storm/storage/expressions/ExpressionEvaluatorBase.h" -#include "storm/utility/exprtk.h" +#include "storm/adapters/ExprttkAdapter.h" #include "storm/storage/expressions/ToExprtkStringVisitor.h" diff --git a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp index b3b0df9c3..2f1b2c947 100644 --- a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp @@ -29,14 +29,14 @@ namespace storm { case BinaryBooleanFunctionExpression::OperatorType::And: stream << "("; expression.getFirstOperand()->accept(*this, data); - stream << " and "; + stream << " & "; expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryBooleanFunctionExpression::OperatorType::Or: stream << "("; expression.getFirstOperand()->accept(*this, data); - stream << " or "; + stream << " | "; expression.getSecondOperand()->accept(*this, data); stream << ")"; break; @@ -50,7 +50,7 @@ namespace storm { case BinaryBooleanFunctionExpression::OperatorType::Implies: stream << "(not("; expression.getFirstOperand()->accept(*this, data); - stream << ") or "; + stream << ") | "; expression.getSecondOperand()->accept(*this, data); stream << ")"; break; diff --git a/src/storm/storage/expressions/Variable.cpp b/src/storm/storage/expressions/Variable.cpp index 0cccde8e0..5cd1716ca 100644 --- a/src/storm/storage/expressions/Variable.cpp +++ b/src/storm/storage/expressions/Variable.cpp @@ -3,11 +3,11 @@ namespace storm { namespace expressions { - Variable::Variable() { + Variable::Variable() : manager(nullptr) { // Intentionally left empty. } - Variable::Variable(std::shared_ptr<ExpressionManager const> const& manager, uint_fast64_t index) : manager(manager), index(index) { + Variable::Variable(std::shared_ptr<ExpressionManager const> const& manager, uint_fast64_t index) : manager(manager.get()), index(index) { // Intentionally left empty. } @@ -52,7 +52,8 @@ namespace storm { } ExpressionManager const& Variable::getManager() const { - return *manager.lock(); + STORM_LOG_ASSERT(manager != nullptr, "The variable does not have a manager."); + return *manager; } bool Variable::hasBooleanType() const { diff --git a/src/storm/storage/expressions/Variable.h b/src/storm/storage/expressions/Variable.h index 3ecea02c0..3fe77467c 100644 --- a/src/storm/storage/expressions/Variable.h +++ b/src/storm/storage/expressions/Variable.h @@ -138,7 +138,7 @@ namespace storm { private: // The manager that is responsible for this variable. - std::weak_ptr<ExpressionManager const> manager; + ExpressionManager const* manager; // The index of the variable. uint_fast64_t index; diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 844393c08..919d7d967 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -4,6 +4,7 @@ #include "storm/storage/jani/TemplateEdge.h" #include "storm/storage/jani/Location.h" #include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" +#include "storm/storage/expressions/ExpressionManager.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" @@ -21,6 +22,25 @@ namespace storm { locationToStartingIndex.push_back(0); } + storm::expressions::Variable cloneVariable(storm::expressions::ExpressionManager& manager, storm::expressions::Variable const& var, std::string const& variablePrefix) { + STORM_LOG_ASSERT(var.getManager() == manager, "expected same manager."); + return manager.declareVariable(variablePrefix + var.getName(), var.getType()); + } + + Automaton Automaton::clone(storm::expressions::ExpressionManager& manager, std::string const& nameOfClone, std::string const& variablePrefix) const { + Automaton result(*this); + result.name = nameOfClone; + result.locationExpressionVariable = cloneVariable(manager, result.locationExpressionVariable, variablePrefix); + auto allVars = result.getAllExpressionVariables(); + std::map<storm::expressions::Variable, storm::expressions::Expression> oldToNewVarMap; + for (auto const& v : allVars) { + oldToNewVarMap[v] = cloneVariable(manager, v, variablePrefix).getExpression(); + } + result.variables.substituteExpressionVariables(oldToNewVarMap); + result.substitute(oldToNewVarMap); + return result; + } + std::string const& Automaton::getName() const { return name; } diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index f9c6d857f..dcdb594c5 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -40,6 +40,8 @@ namespace storm { Automaton(Automaton&& other) = default; Automaton& operator=(Automaton&& other) = default; + Automaton clone(storm::expressions::ExpressionManager& manager, std::string const& nameOfClone, std::string const& variablePrefix) const; + /*! * Retrieves the name of the automaton. */ diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 224857989..d5ba829b4 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -955,6 +955,69 @@ namespace storm { return *composition; } + class CompositionSimplificationVisitor : public CompositionVisitor { + public: + CompositionSimplificationVisitor(std::unordered_map<std::string, std::vector<std::string>> const& automatonToCopiesMap) : automatonToCopiesMap(automatonToCopiesMap) {} + + std::shared_ptr<Composition> simplify(Composition const& oldComposition) { + return boost::any_cast<std::shared_ptr<Composition>>(oldComposition.accept(*this, boost::any())); + } + + virtual boost::any visit(AutomatonComposition const& composition, boost::any const& data) override { + std::string name = composition.getAutomatonName(); + if (automatonToCopiesMap.count(name) != 0) { + auto& copies = automatonToCopiesMap[name]; + STORM_LOG_ASSERT(!copies.empty(), "Not enough copies of automaton " << name << "."); + name = copies.back(); + copies.pop_back(); + } + return std::shared_ptr<Composition>(new AutomatonComposition(name, composition.getInputEnabledActions())); + } + + virtual boost::any visit(ParallelComposition const& composition, boost::any const& data) override { + std::vector<std::shared_ptr<Composition>> subcomposition; + for (auto const& p : composition.getSubcompositions()) { + subcomposition.push_back(boost::any_cast<std::shared_ptr<Composition>>(p->accept(*this, data))); + } + return std::shared_ptr<Composition>(new ParallelComposition(subcomposition, composition.getSynchronizationVectors())); + } + + private: + std::unordered_map<std::string, std::vector<std::string>> automatonToCopiesMap; + }; + + void Model::simplifyComposition() { + CompositionInformationVisitor visitor(*this, this->getSystemComposition()); + CompositionInformation info = visitor.getInformation(); + if (info.containsNestedParallelComposition()) { + STORM_LOG_WARN("Unable to simplify non-standard compliant system composition."); + } + + // Check whether we need to copy certain automata + std::unordered_map<std::string, std::vector<std::string>> automatonToCopiesMap; + for (auto const& automatonMultiplicity : info.getAutomatonToMultiplicityMap()) { + if (automatonMultiplicity.second > 1) { + std::vector<std::string> copies = {automatonMultiplicity.first}; + // We need to copy this automaton n-1 times. + for (uint64_t copyIndex = 1; copyIndex < automatonMultiplicity.second; ++copyIndex) { + std::string copyPrefix = "Copy__" + std::to_string(copyIndex) + "_Of"; + std::string copyAutName = copyPrefix + automatonMultiplicity.first; + this->addAutomaton(this->getAutomaton(automatonMultiplicity.first).clone(getManager(), copyAutName, copyPrefix)); + copies.push_back(copyAutName); + } + // For esthetic reasons we reverse the list of copies so that the ones with the lowest index will be pop_back'ed first + std::reverse(copies.begin(), copies.end()); + // We insert the copies in reversed order as they will be popped in reversed order, as well. + automatonToCopiesMap[automatonMultiplicity.first] = std::move(copies); + } + } + + // Traverse the system composition and exchange automata by their copy + auto newComposition = CompositionSimplificationVisitor(automatonToCopiesMap).simplify(getSystemComposition()); + this->setSystemComposition(newComposition); + + } + void Model::setSystemComposition(std::shared_ptr<Composition> const& composition) { this->composition = composition; } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 41e205274..afaa4bda6 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -412,6 +412,13 @@ namespace storm { */ Composition const& getSystemComposition() const; + /*! + * Attempts to simplify the composition. + * Right now, this only means that automata that occur multiple times in the composition will be + * duplicated su that each automata occurs at most once. + */ + void simplifyComposition(); + /*! * Retrieves the set of action names. */ diff --git a/src/storm/storage/jani/Property.cpp b/src/storm/storage/jani/Property.cpp index d24b3a3fe..add01f24d 100644 --- a/src/storm/storage/jani/Property.cpp +++ b/src/storm/storage/jani/Property.cpp @@ -114,6 +114,11 @@ namespace storm { return res; } + void Property::gatherReferencedRewardModels(std::set<std::string>& rewardModelNames) const { + getFilter().getFormula()->gatherReferencedRewardModels(rewardModelNames); + getFilter().getStatesFormula()->gatherReferencedRewardModels(rewardModelNames); + } + std::ostream& operator<<(std::ostream& os, Property const& p) { return os << "(" << p.getName() << "): " << p.getFilter(); } diff --git a/src/storm/storage/jani/Property.h b/src/storm/storage/jani/Property.h index 199dbe19f..757db04a8 100644 --- a/src/storm/storage/jani/Property.h +++ b/src/storm/storage/jani/Property.h @@ -137,6 +137,7 @@ namespace storm { bool containsUndefinedConstants() const; std::set<storm::expressions::Variable> getUsedVariablesAndConstants() const; std::set<std::string> getUsedLabels() const; + void gatherReferencedRewardModels(std::set<std::string>& rewardModelNames) const; std::shared_ptr<storm::logic::Formula const> getRawFormula() const; diff --git a/src/storm/storage/jani/Variable.cpp b/src/storm/storage/jani/Variable.cpp index 6d4c611c3..f693445f1 100644 --- a/src/storm/storage/jani/Variable.cpp +++ b/src/storm/storage/jani/Variable.cpp @@ -26,6 +26,10 @@ namespace storm { storm::expressions::Variable const& Variable::getExpressionVariable() const { return variable; } + + void Variable::setExpressionVariable(storm::expressions::Variable const& newVariable) { + variable = newVariable; + } std::string const& Variable::getName() const { return name; diff --git a/src/storm/storage/jani/Variable.h b/src/storm/storage/jani/Variable.h index d7e3a4b9a..8de11cbba 100644 --- a/src/storm/storage/jani/Variable.h +++ b/src/storm/storage/jani/Variable.h @@ -41,6 +41,11 @@ namespace storm { */ storm::expressions::Variable const& getExpressionVariable() const; + /*! + * Sets the associated expression variable. + */ + void setExpressionVariable(storm::expressions::Variable const& newVariable); + /*! * Retrieves the name of the variable. */ diff --git a/src/storm/storage/jani/VariableSet.cpp b/src/storm/storage/jani/VariableSet.cpp index 10cdd7fba..a2fd5a660 100644 --- a/src/storm/storage/jani/VariableSet.cpp +++ b/src/storm/storage/jani/VariableSet.cpp @@ -1,5 +1,6 @@ #include "storm/storage/jani/VariableSet.h" +#include "storm/storage/expressions/Expressions.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -439,5 +440,15 @@ namespace storm { variable->substitute(substitution); } } + + void VariableSet::substituteExpressionVariables(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + for (auto& variable : variables) { + auto varIt = substitution.find(variable->getExpressionVariable()); + if (varIt != substitution.end()) { + STORM_LOG_ASSERT(varIt->second.isVariable(), "Expected that variables are only substituted by other variables. However, we substitute " << varIt->first.getName() << " by " << varIt->second << "."); + variable->setExpressionVariable(varIt->second.getBaseExpression().asVariableExpression().getVariable()); + } + } + } } } diff --git a/src/storm/storage/jani/VariableSet.h b/src/storm/storage/jani/VariableSet.h index 53f45a359..e4d4e56b9 100644 --- a/src/storm/storage/jani/VariableSet.h +++ b/src/storm/storage/jani/VariableSet.h @@ -282,6 +282,14 @@ namespace storm { */ void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + /*! + * Substitutes the actual variables according to the given substitution. + * @param substitution The substitution. Assumed to only map variables to VariableExpressions. + * @note does not substitute variables in initial expressions, variable bounds, ... + */ + void substituteExpressionVariables(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + + private: /// The vector of all variables. std::vector<std::shared_ptr<Variable>> variables; diff --git a/src/storm/transformer/SymbolicToSparseTransformer.cpp b/src/storm/transformer/SymbolicToSparseTransformer.cpp index 66d3dd1b3..bf43b42e2 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.cpp +++ b/src/storm/transformer/SymbolicToSparseTransformer.cpp @@ -3,6 +3,7 @@ #include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/Add.h" #include "storm/storage/dd/Bdd.h" +#include "storm/storage/sparse/ModelComponents.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/utility/macros.h" @@ -83,7 +84,28 @@ namespace storm { template<storm::dd::DdType Type, typename ValueType> std::shared_ptr<storm::models::sparse::Mdp<ValueType>> SymbolicMdpToSparseMdpTransformer<Type, ValueType>::translate(storm::models::symbolic::Mdp<Type, ValueType> const& symbolicMdp, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { storm::dd::Odd odd = symbolicMdp.getReachableStates().createOdd(); - storm::storage::SparseMatrix<ValueType> transitionMatrix = symbolicMdp.getTransitionMatrix().toMatrix(symbolicMdp.getNondeterminismVariables(), odd, odd); + + // Collect action reward vectors that need translation + std::vector<storm::dd::Add<Type, ValueType>> symbolicActionRewardVectors; + std::map<std::string, uint64_t> rewardNameToActionRewardIndexMap; + for (auto const& rewardModelNameAndModel : symbolicMdp.getRewardModels()) { + if (rewardModelNameAndModel.second.hasStateActionRewards()) { + rewardNameToActionRewardIndexMap.emplace(rewardModelNameAndModel.first, symbolicActionRewardVectors.size()); + symbolicActionRewardVectors.push_back(rewardModelNameAndModel.second.getStateActionRewardVector()); + } + } + // Build transition matrix and (potentially) actionRewardVectors. + storm::storage::SparseMatrix<ValueType> transitionMatrix; + std::vector<std::vector<ValueType>> actionRewardVectors; + if (symbolicActionRewardVectors.empty()) { + transitionMatrix = symbolicMdp.getTransitionMatrix().toMatrix(symbolicMdp.getNondeterminismVariables(), odd, odd); + } else { + auto matrRewards = symbolicMdp.getTransitionMatrix().toMatrixVectors(symbolicActionRewardVectors, symbolicMdp.getNondeterminismVariables(), odd, odd); + transitionMatrix = std::move(matrRewards.first); + actionRewardVectors = std::move(matrRewards.second); + } + + // Translate reward models std::unordered_map<std::string, storm::models::sparse::StandardRewardModel<ValueType>> rewardModels; for (auto const& rewardModelNameAndModel : symbolicMdp.getRewardModels()) { boost::optional<std::vector<ValueType>> stateRewards; @@ -92,12 +114,14 @@ namespace storm { if (rewardModelNameAndModel.second.hasStateRewards()) { stateRewards = rewardModelNameAndModel.second.getStateRewardVector().toVector(odd); } - // Note: .getStateActionRewardVector().toVector(odd); does not work as it needs to have information regarding the nondeterminism - // One could use transitionMatrix().toMatrixVector instead. - STORM_LOG_THROW(!rewardModelNameAndModel.second.hasStateActionRewards(), storm::exceptions::NotImplementedException, "Translation of symbolic to explicit state-action rewards is not yet supported."); + auto actRewIndexIt = rewardNameToActionRewardIndexMap.find(rewardModelNameAndModel.first); + if (actRewIndexIt != rewardNameToActionRewardIndexMap.end()) { + stateActionRewards = std::move(actionRewardVectors[actRewIndexIt->second]); + } STORM_LOG_THROW(!rewardModelNameAndModel.second.hasTransitionRewards(), storm::exceptions::NotImplementedException, "Translation of symbolic to explicit transition rewards is not yet supported."); - rewardModels.emplace(rewardModelNameAndModel.first,storm::models::sparse::StandardRewardModel<ValueType>(stateRewards, stateActionRewards, transitionRewards)); + rewardModels.emplace(rewardModelNameAndModel.first, storm::models::sparse::StandardRewardModel<ValueType>(stateRewards, stateActionRewards, transitionRewards)); } + storm::models::sparse::StateLabeling labelling(transitionMatrix.getRowGroupCount()); labelling.addLabel("init", symbolicMdp.getInitialStates().toVector(odd)); @@ -159,6 +183,72 @@ namespace storm { return std::make_shared<storm::models::sparse::Ctmc<ValueType>>(transitionMatrix, labelling, rewardModels); } + + + template<storm::dd::DdType Type, typename ValueType> + std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> SymbolicMaToSparseMaTransformer<Type, ValueType>::translate(storm::models::symbolic::MarkovAutomaton<Type, ValueType> const& symbolicMa, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { + storm::dd::Odd odd = symbolicMa.getReachableStates().createOdd(); + // Collect action reward vectors that need translation + std::vector<storm::dd::Add<Type, ValueType>> symbolicActionRewardVectors; + std::map<std::string, uint64_t> rewardNameToActionRewardIndexMap; + for (auto const& rewardModelNameAndModel : symbolicMa.getRewardModels()) { + if (rewardModelNameAndModel.second.hasStateActionRewards()) { + rewardNameToActionRewardIndexMap.emplace(rewardModelNameAndModel.first, symbolicActionRewardVectors.size()); + symbolicActionRewardVectors.push_back(rewardModelNameAndModel.second.getStateActionRewardVector()); + } + } + // Build transition matrix and (potentially) actionRewardVectors. + storm::storage::SparseMatrix<ValueType> transitionMatrix; + std::vector<std::vector<ValueType>> actionRewardVectors; + if (symbolicActionRewardVectors.empty()) { + transitionMatrix = symbolicMa.getTransitionMatrix().toMatrix(symbolicMa.getNondeterminismVariables(), odd, odd); + } else { + auto matrRewards = symbolicMa.getTransitionMatrix().toMatrixVectors(symbolicActionRewardVectors, symbolicMa.getNondeterminismVariables(), odd, odd); + transitionMatrix = std::move(matrRewards.first); + actionRewardVectors = std::move(matrRewards.second); + } + + // Translate reward models + std::unordered_map<std::string, storm::models::sparse::StandardRewardModel<ValueType>> rewardModels; + for (auto const& rewardModelNameAndModel : symbolicMa.getRewardModels()) { + boost::optional<std::vector<ValueType>> stateRewards; + boost::optional<std::vector<ValueType>> stateActionRewards; + boost::optional<storm::storage::SparseMatrix<ValueType>> transitionRewards; + if (rewardModelNameAndModel.second.hasStateRewards()) { + stateRewards = rewardModelNameAndModel.second.getStateRewardVector().toVector(odd); + } + auto actRewIndexIt = rewardNameToActionRewardIndexMap.find(rewardModelNameAndModel.first); + if (actRewIndexIt != rewardNameToActionRewardIndexMap.end()) { + stateActionRewards = std::move(actionRewardVectors[actRewIndexIt->second]); + } + STORM_LOG_THROW(!rewardModelNameAndModel.second.hasTransitionRewards(), storm::exceptions::NotImplementedException, "Translation of symbolic to explicit transition rewards is not yet supported."); + rewardModels.emplace(rewardModelNameAndModel.first, storm::models::sparse::StandardRewardModel<ValueType>(stateRewards, stateActionRewards, transitionRewards)); + } + + storm::models::sparse::StateLabeling labelling(transitionMatrix.getRowGroupCount()); + + labelling.addLabel("init", symbolicMa.getInitialStates().toVector(odd)); + labelling.addLabel("deadlock", symbolicMa.getDeadlockStates().toVector(odd)); + if (formulas.empty()) { + for (auto const& label : symbolicMa.getLabels()) { + labelling.addLabel(label, symbolicMa.getStates(label).toVector(odd)); + } + } else { + LabelInformation labelInfo(formulas); + for (auto const& label : labelInfo.atomicLabels) { + labelling.addLabel(label, symbolicMa.getStates(label).toVector(odd)); + } + for (auto const& expressionLabel : labelInfo.expressionLabels) { + labelling.addLabel(expressionLabel.first, symbolicMa.getStates(expressionLabel.second).toVector(odd)); + } + } + storm::storage::BitVector markovianStates = symbolicMa.getMarkovianStates().toVector(odd); + storm::storage::sparse::ModelComponents<ValueType> components(std::move(transitionMatrix), std::move(labelling), std::move(rewardModels), false, std::move(markovianStates)); + components.exitRates = symbolicMa.getExitRateVector().toVector(odd); + + return std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(components)); + } + template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::CUDD, double>; template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::Sylvan, double>; @@ -175,5 +265,10 @@ namespace storm { template class SymbolicCtmcToSparseCtmcTransformer<storm::dd::DdType::Sylvan, storm::RationalNumber>; template class SymbolicCtmcToSparseCtmcTransformer<storm::dd::DdType::Sylvan, storm::RationalFunction>; + template class SymbolicMaToSparseMaTransformer<storm::dd::DdType::CUDD, double>; + template class SymbolicMaToSparseMaTransformer<storm::dd::DdType::Sylvan, double>; + template class SymbolicMaToSparseMaTransformer<storm::dd::DdType::Sylvan, storm::RationalNumber>; + template class SymbolicMaToSparseMaTransformer<storm::dd::DdType::Sylvan, storm::RationalFunction>; + } } diff --git a/src/storm/transformer/SymbolicToSparseTransformer.h b/src/storm/transformer/SymbolicToSparseTransformer.h index e2c191b49..98d486ba3 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.h +++ b/src/storm/transformer/SymbolicToSparseTransformer.h @@ -7,6 +7,8 @@ #include "storm/models/symbolic/Mdp.h" #include "storm/models/sparse/Ctmc.h" #include "storm/models/symbolic/Ctmc.h" +#include "storm/models/sparse/MarkovAutomaton.h" +#include "storm/models/symbolic/MarkovAutomaton.h" #include "storm/storage/dd/Odd.h" @@ -34,5 +36,11 @@ namespace storm { public: static std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> translate(storm::models::symbolic::Ctmc<Type, ValueType> const& symbolicCtmc, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas = std::vector<std::shared_ptr<storm::logic::Formula const>>()); }; + + template<storm::dd::DdType Type, typename ValueType> + class SymbolicMaToSparseMaTransformer { + public: + static std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> translate(storm::models::symbolic::MarkovAutomaton<Type, ValueType> const& symbolicMa, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas = std::vector<std::shared_ptr<storm::logic::Formula const>>()); + }; } } diff --git a/src/storm/utility/Engine.cpp b/src/storm/utility/Engine.cpp new file mode 100644 index 000000000..51711ee1b --- /dev/null +++ b/src/storm/utility/Engine.cpp @@ -0,0 +1,224 @@ +#include "storm/utility/Engine.h" + +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/models/symbolic/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" +#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h" +#include "storm/modelchecker/csl/SparseCtmcCslModelChecker.h" +#include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" + +#include "storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h" +#include "storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h" +#include "storm/modelchecker/csl/HybridCtmcCslModelChecker.h" +#include "storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.h" + +#include "storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h" +#include "storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h" +#include "storm/modelchecker/CheckTask.h" + +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/jani/Property.h" + +#include "storm/utility/macros.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace utility { + + // Returns a list of all available engines (excluding Unknown) + std::vector<Engine> getEngines() { + std::vector<Engine> res; + for (int i = 0; i != static_cast<int>(Engine::Unknown); ++i) { + res.push_back(static_cast<Engine>(i)); + } + return res; + } + + std::string toString(Engine const& engine) { + switch (engine) { + case Engine::Sparse: + return "sparse"; + case Engine::Hybrid: + return "hybrid"; + case Engine::Dd: + return "dd"; + case Engine::DdSparse: + return "dd-to-sparse"; + case Engine::Jit: + return "jit"; + case Engine::Exploration: + return "expl"; + case Engine::AbstractionRefinement: + return "abs"; + case Engine::Portfolio: + return "portfolio"; + case Engine::Unknown: + return "UNKNOWN"; + default: + STORM_LOG_ASSERT(false, "The given engine has no name assigned to it."); + return "UNKNOWN"; + } + } + + std::ostream& operator<<(std::ostream& os, Engine const& engine) { + os << toString(engine); + return os; + } + + Engine engineFromString(std::string const& engineStr) { + for (Engine const& e : getEngines()) { + if (engineStr == toString(e)) { + return e; + } + } + STORM_LOG_ERROR("The engine '" << engineStr << "' was not found."); + return Engine::Unknown; + } + + storm::builder::BuilderType getBuilderType(Engine const& engine) { + switch (engine) { + case Engine::Sparse: + return storm::builder::BuilderType::Explicit; + case Engine::Hybrid: + return storm::builder::BuilderType::Dd; + case Engine::Dd: + return storm::builder::BuilderType::Dd; + case Engine::DdSparse: + return storm::builder::BuilderType::Dd; + case Engine::Jit: + return storm::builder::BuilderType::Jit; + case Engine::Exploration: + return storm::builder::BuilderType::Explicit; + case Engine::AbstractionRefinement: + return storm::builder::BuilderType::Dd; + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given engine has no builder type to it."); + return storm::builder::BuilderType::Explicit; + } + } + + template <typename ValueType> + bool canHandle(storm::utility::Engine const& engine, storm::storage::SymbolicModelDescription::ModelType const& modelType, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& checkTask) { + // Define types to improve readability + typedef storm::storage::SymbolicModelDescription::ModelType ModelType; + // The Dd library does not make much of a difference (in case of exact or parametric models we will switch to sylvan anyway). + // Therefore, we always use sylvan here + storm::dd::DdType const ddType = storm::dd::DdType::Sylvan; + switch (engine) { + case Engine::Sparse: + case Engine::DdSparse: + switch (modelType) { + case ModelType::DTMC: + return storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ValueType>>::canHandleStatic(checkTask); + case ModelType::MDP: + return storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ValueType>>::canHandleStatic(checkTask); + case ModelType::CTMC: + return storm::modelchecker::SparseCtmcCslModelChecker<storm::models::sparse::Ctmc<ValueType>>::canHandleStatic(checkTask); + case ModelType::MA: + return storm::modelchecker::SparseMarkovAutomatonCslModelChecker<storm::models::sparse::MarkovAutomaton<ValueType>>::canHandleStatic(checkTask); + case ModelType::POMDP: + return false; + } + case Engine::Hybrid: + switch (modelType) { + case ModelType::DTMC: + return storm::modelchecker::HybridDtmcPrctlModelChecker<storm::models::symbolic::Dtmc<ddType, ValueType>>::canHandleStatic(checkTask); + case ModelType::MDP: + return storm::modelchecker::HybridMdpPrctlModelChecker<storm::models::symbolic::Mdp<ddType, ValueType>>::canHandleStatic(checkTask); + case ModelType::CTMC: + return storm::modelchecker::HybridCtmcCslModelChecker<storm::models::symbolic::Ctmc<ddType, ValueType>>::canHandleStatic(checkTask); + case ModelType::MA: + return storm::modelchecker::HybridMarkovAutomatonCslModelChecker<storm::models::symbolic::MarkovAutomaton<ddType, ValueType>>::canHandleStatic(checkTask); + case ModelType::POMDP: + return false; + } + case Engine::Dd: + switch (modelType) { + case ModelType::DTMC: + return storm::modelchecker::SymbolicDtmcPrctlModelChecker<storm::models::symbolic::Dtmc<ddType, ValueType>>::canHandleStatic(checkTask); + case ModelType::MDP: + return storm::modelchecker::SymbolicMdpPrctlModelChecker<storm::models::symbolic::Mdp<ddType, ValueType>>::canHandleStatic(checkTask); + case ModelType::CTMC: + case ModelType::MA: + case ModelType::POMDP: + return false; + } + default: + STORM_LOG_ERROR("The selected engine" << engine << " is not considered."); + } + STORM_LOG_ERROR("The selected combination of engine (" << engine << ") and model type (" << modelType << ") does not seem to be supported for this value type."); + return false; + } + + template <> + bool canHandle<storm::RationalFunction>(storm::utility::Engine const& engine, storm::storage::SymbolicModelDescription::ModelType const& modelType, storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction> const& checkTask) { + // Define types to improve readability + typedef storm::storage::SymbolicModelDescription::ModelType ModelType; + // The Dd library does not make much of a difference (in case of exact or parametric models we will switch to sylvan anyway). + // Therefore, we always use sylvan here + storm::dd::DdType const ddType = storm::dd::DdType::Sylvan; + switch (engine) { + case Engine::Sparse: + case Engine::DdSparse: + switch (modelType) { + case ModelType::DTMC: + return storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>>::canHandleStatic(checkTask); + case ModelType::CTMC: + return storm::modelchecker::SparseCtmcCslModelChecker<storm::models::sparse::Ctmc<storm::RationalFunction>>::canHandleStatic(checkTask); + case ModelType::MDP: + case ModelType::MA: + case ModelType::POMDP: + return false; + } + case Engine::Hybrid: + switch (modelType) { + case ModelType::DTMC: + return storm::modelchecker::HybridDtmcPrctlModelChecker<storm::models::symbolic::Dtmc<ddType, storm::RationalFunction>>::canHandleStatic(checkTask); + case ModelType::CTMC: + return storm::modelchecker::HybridCtmcCslModelChecker<storm::models::symbolic::Ctmc<ddType, storm::RationalFunction>>::canHandleStatic(checkTask); + case ModelType::MDP: + case ModelType::MA: + case ModelType::POMDP: + return false; + } + case Engine::Dd: + switch (modelType) { + case ModelType::DTMC: + return storm::modelchecker::SymbolicDtmcPrctlModelChecker<storm::models::symbolic::Dtmc<ddType, storm::RationalFunction>>::canHandleStatic(checkTask); + case ModelType::MDP: + case ModelType::CTMC: + case ModelType::MA: + case ModelType::POMDP: + return false; + } + default: + STORM_LOG_ERROR("The selected engine" << engine << " is not considered."); + } + STORM_LOG_ERROR("The selected combination of engine (" << engine << ") and model type (" << modelType << ") does not seem to be supported for this value type."); + return false; + } + + template <typename ValueType> + bool canHandle(storm::utility::Engine const& engine, std::vector<storm::jani::Property> const& properties, storm::storage::SymbolicModelDescription const& modelDescription) { + // Check handability of properties based on model type + for (auto const& p : properties) { + for (auto const& f : {p.getRawFormula(), p.getFilter().getStatesFormula()}) { + auto task = storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>(*f, true); + if (!canHandle(engine, modelDescription.getModelType(), task)) { + STORM_LOG_INFO("Engine " << engine << " can not handle formula '" << *f << "'."); + return false; + } + } + } + // Check whether the model builder can handle the model description + return storm::builder::canHandle<ValueType>(getBuilderType(engine), modelDescription, properties); + } + + // explicit template instantiations. + template bool canHandle<double>(storm::utility::Engine const&, std::vector<storm::jani::Property> const&, storm::storage::SymbolicModelDescription const&); + template bool canHandle<storm::RationalNumber>(storm::utility::Engine const&, std::vector<storm::jani::Property> const&, storm::storage::SymbolicModelDescription const&); + template bool canHandle<storm::RationalFunction>(storm::utility::Engine const&, std::vector<storm::jani::Property> const&, storm::storage::SymbolicModelDescription const&); + + } +} \ No newline at end of file diff --git a/src/storm/utility/Engine.h b/src/storm/utility/Engine.h new file mode 100644 index 000000000..b193eb448 --- /dev/null +++ b/src/storm/utility/Engine.h @@ -0,0 +1,71 @@ +#pragma once + +#include <ostream> +#include <vector> + +#include "storm/models/ModelType.h" +#include "storm/storage/dd/DdType.h" +#include "storm/builder/BuilderType.h" + +namespace storm { + + // Forward Declarations + namespace jani { + class Property; + } + + namespace logic { + class Formula; + } + namespace modelchecker{ + template<typename FormulaType, typename ValueType> + class CheckTask; + } + namespace storage { + class SymbolicModelDescription; + } + + namespace utility { + + /// An enumeration of all engines. + enum class Engine { + // The last one should always be 'Unknown' to make sure that the getEngines() method below works. + Sparse, Hybrid, Dd, DdSparse, Jit, Exploration, AbstractionRefinement, Portfolio, Unknown + }; + + /*! + * Returns a list of all available engines (excluding Unknown) + */ + std::vector<Engine> getEngines(); + + /*! + * Returns a string representation of the given engine. + */ + std::string toString(Engine const& engine); + + /*! + * Writes the string representation of the given engine to the given stream + */ + std::ostream& operator<<(std::ostream& os, Engine const& engine); + + /*! + * Parses the string representation of an engine and returns the corresponding engine. + * If the engine is not found, we print an error and return Engine::Unknown. + */ + Engine engineFromString(std::string const& engineStr); + + /*! + * Returns the builder type used for the given engine. + */ + storm::builder::BuilderType getBuilderType(storm::utility::Engine const& engine); + + /*! + * Returns false if the given model description and one of the given properties can certainly not be handled by the given engine. + * Notice that the set of handable model checking queries is only overapproximated, i.e. if this returns true, + * the query could still be not supported by the engine. This behavior is due to the fact that we sometimes need + * to actually build the model in order to decide whether it is supported. + */ + template <typename ValueType> + bool canHandle(storm::utility::Engine const& engine, std::vector<storm::jani::Property> const& properties, storm::storage::SymbolicModelDescription const& modelDescription); + } +} \ No newline at end of file diff --git a/src/storm/utility/Portfolio.cpp b/src/storm/utility/Portfolio.cpp new file mode 100644 index 000000000..c45f51d2b --- /dev/null +++ b/src/storm/utility/Portfolio.cpp @@ -0,0 +1,226 @@ +#include "storm/utility/Portfolio.h" + +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/jani/Property.h" + +#include "storm/logic/Formula.h" +#include "storm/logic/FormulaInformation.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidOperationException.h" + +namespace storm { + namespace utility { + + namespace pfinternal { + enum class PropertyType{ + Bounded, + Unbounded, + LongRun + }; + + PropertyType getPropertyType(storm::jani::Property const& property) { + auto formulaInfo = property.getRawFormula()->info(); + if (formulaInfo.containsBoundedUntilFormula() || formulaInfo.containsNextFormula() || formulaInfo.containsCumulativeRewardFormula()) { + STORM_LOG_INFO("Assuming step or time bounded property:" << property); + return PropertyType::Bounded; + } else if (formulaInfo.containsLongRunFormula()) { + STORM_LOG_INFO("Assuming Long Run property:" << property); + return PropertyType::LongRun; + } else { + STORM_LOG_INFO("Unbounded property:" << property); + return PropertyType::Unbounded; + } + } + + struct Features { + Features(storm::storage::SymbolicModelDescription const& modelDescription, storm::jani::Property const& property) { + if (!modelDescription.isJaniModel()) { + initialize(modelDescription.toJani().asJaniModel(), property); + } else { + initialize(modelDescription.asJaniModel(), property); + } + } + + void initialize(storm::jani::Model const& model, storm::jani::Property const& property) { + continuousTime = !model.isDiscreteTimeModel(); + nondeterminism = !model.isDeterministicModel(); + propertyType = getPropertyType(property); + numVariables = model.getTotalNumberOfNonTransientVariables(); + numAutomata = model.getNumberOfAutomata(); + numEdges = model.getNumberOfEdges(); + } + + bool continuousTime; + bool nondeterminism; + PropertyType propertyType; + uint64_t numVariables; + uint64_t numAutomata; + uint64_t numEdges; + uint64_t stateEstimate; + }; + } + + Portfolio::Portfolio() : engine(storm::utility::Engine::Unknown), useBisimulation(false), useExact(false) { + // Intentionally left empty + } + + void Portfolio::predict(storm::storage::SymbolicModelDescription const& modelDescription, storm::jani::Property const& property) { + typedef pfinternal::PropertyType PropertyType; + auto f = pfinternal::Features(modelDescription, property); + + { // Decision tree start + if (f.numEdges <= 618) { + if (!f.continuousTime) { + if (f.numVariables <= 3) { + exact(); + } else { // f.numVariables > 3 + if (f.propertyType == PropertyType::Bounded) { + if (f.numEdges <= 25) { + dd(); + } else { // f.numEdges > 25 + ddbisim(); + } + } else { // !(f.propertyType == PropertyType::Bounded) + if (f.numEdges <= 46) { + if (f.numVariables <= 8) { + hybrid(); + } else { // f.numVariables > 8 + if (f.numAutomata <= 1) { + ddbisim(); + } else { // f.numAutomata > 1 + if (f.numVariables <= 18) { + if (f.numEdges <= 36) { + if (f.numEdges <= 30) { + if (f.numAutomata <= 9) { + sparse(); + } else { // f.numAutomata > 9 + hybrid(); + } + } else { // f.numEdges > 30 + dd(); + } + } else { // f.numEdges > 36 + ddbisim(); + } + } else { // f.numVariables > 18 + hybrid(); + } + } + } + } else { // f.numEdges > 46 + if (!f.nondeterminism) { + if (f.numEdges <= 92) { + ddbisim(); + } else { // f.numEdges > 92 + dd(); + } + } else { // f.nondeterminism + if (f.numVariables <= 51) { + if (f.numAutomata <= 6) { + if (f.numAutomata <= 3) { + if (f.numEdges <= 85) { + sparse(); + } else { // f.numEdges > 85 + hybrid(); + } + } else { // f.numAutomata > 3 + hybrid(); + } + } else { // f.numAutomata > 6 + if (f.numAutomata <= 9) { + ddbisim(); + } else { // f.numAutomata > 9 + hybrid(); + } + } + } else { // f.numVariables > 51 + sparse(); + } + } + } + } + } + } else { // f.continuousTime + if (!f.nondeterminism) { + if (f.numAutomata <= 5) { + hybrid(); + } else { // f.numAutomata > 5 + if (f.numVariables <= 8) { + sparse(); + } else { // f.numVariables > 8 + if (f.numEdges <= 19) { + exact(); + } else { // f.numEdges > 19 + if (f.numVariables <= 21) { + hybrid(); + } else { // f.numVariables > 21 + sparse(); + } + } + } + } + } else { // f.nondeterminism + sparse(); + } + } + } else { // f.numEdges > 618 + sparse(); + } + } // Decision tree end + + } + + void Portfolio::predict(storm::storage::SymbolicModelDescription const& modelDescription, storm::jani::Property const& property, uint64_t stateEstimate) { + typedef pfinternal::PropertyType PropertyType; + auto f = pfinternal::Features(modelDescription, property); + f.stateEstimate = stateEstimate; + // TODO: Actually make use of the estimate + predict(modelDescription, property); + } + + storm::utility::Engine Portfolio::getEngine() const { + STORM_LOG_THROW(engine != storm::utility::Engine::Unknown, storm::exceptions::InvalidOperationException, "Tried to get the engine but apparently no prediction was done before."); + return engine; + } + + bool Portfolio::enableBisimulation() const { + return useBisimulation; + } + + bool Portfolio::enableExact() const { + return useExact; + } + + void Portfolio::sparse() { + engine = storm::utility::Engine::Sparse; + useBisimulation = false; + useExact = false; + } + + void Portfolio::hybrid() { + engine = storm::utility::Engine::Hybrid; + useBisimulation = false; + useExact = false; + } + + void Portfolio::dd() { + engine = storm::utility::Engine::Dd; + useBisimulation = false; + useExact = false; + } + + void Portfolio::exact() { + engine = storm::utility::Engine::Sparse; + useBisimulation = false; + useExact = true; + } + + void Portfolio::ddbisim() { + engine = storm::utility::Engine::DdSparse; + useBisimulation = true; + useExact = false; + } + + } +} \ No newline at end of file diff --git a/src/storm/utility/Portfolio.h b/src/storm/utility/Portfolio.h new file mode 100644 index 000000000..8fceda6b8 --- /dev/null +++ b/src/storm/utility/Portfolio.h @@ -0,0 +1,54 @@ +#pragma once + +#include "storm/utility/Engine.h" + +namespace storm { + + namespace jani { + class Property; + } + + namespace storage { + class SymbolicModelDescription; + } + + namespace utility { + class Portfolio { + public: + Portfolio(); + + /*! + * Predicts "good" settings for the provided model checking query + */ + void predict(storm::storage::SymbolicModelDescription const& modelDescription, storm::jani::Property const& property); + + /*! + * Predicts "good" settings for the provided model checking query + * @param stateEstimate A hint that gives a (rough) estimate for the number of states. + */ + void predict(storm::storage::SymbolicModelDescription const& modelDescription, storm::jani::Property const& property, uint64_t stateEstimate); + + /// Retrieve "good" settings after calling predict. + storm::utility::Engine getEngine() const; + bool enableBisimulation() const; + bool enableExact() const; + + private: + + // some popular configs + void sparse(); + void hybrid(); + void dd(); + void exact(); + void ddbisim(); + + storm::utility::Engine engine; + bool useBisimulation; + bool useExact; + + + + }; + + } +} \ No newline at end of file diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index b774c65da..413e93302 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -737,6 +737,7 @@ namespace storm { std::pair<storm::storage::BitVector, storm::storage::BitVector> result; result.first = performProb0A(backwardTransitions, phiStates, psiStates); + result.second = performProb1E(transitionMatrix, nondeterministicChoiceIndices, backwardTransitions, phiStates, psiStates); return result; } @@ -948,7 +949,10 @@ namespace storm { std::pair<storm::storage::BitVector, storm::storage::BitVector> performProb01Min(storm::storage::SparseMatrix<T> const& transitionMatrix, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) { std::pair<storm::storage::BitVector, storm::storage::BitVector> result; result.first = performProb0E(transitionMatrix, nondeterministicChoiceIndices, backwardTransitions, phiStates, psiStates); - result.second = performProb1A(transitionMatrix, nondeterministicChoiceIndices, backwardTransitions, phiStates, psiStates); + // Instead of calling performProb1A, we call the (more easier) performProb0A on the Prob0E states. + // This is valid because, when minimizing probabilities, states that have prob1 cannot reach a state with prob 0 (and will eventually reach a psiState). + // States that do not have prob1 will eventually reach a state with prob0. + result.second = performProb0A(backwardTransitions, ~psiStates, result.first); return result; } diff --git a/src/storm/utility/numerical.cpp b/src/storm/utility/numerical.cpp index 9c17928ab..2c40d7680 100644 --- a/src/storm/utility/numerical.cpp +++ b/src/storm/utility/numerical.cpp @@ -219,7 +219,7 @@ namespace storm { // Fill the right side of the array, have two cases lambda < 400 & lambda >= 400. if (m < 400) { // Perform the underflow check, according to Fox-Glynn. - STORM_LOG_THROW(result.right <= 600, storm::exceptions::PrecisionExceededException, "Fox-Glynn: " << result.right << " > 600, underflow is possible."); + STORM_LOG_ERROR_COND(result.right <= 600, "Fox-Glynn: " << result.right << " > 600, underflow is possible."); // Compute weights. for (j = m - result.left; j < t; ++j) { diff --git a/src/test/storm/modelchecker/csl/MarkovAutomatonCslModelCheckerTest.cpp b/src/test/storm/modelchecker/csl/MarkovAutomatonCslModelCheckerTest.cpp index 056c47ba8..31c0ca29c 100755 --- a/src/test/storm/modelchecker/csl/MarkovAutomatonCslModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/csl/MarkovAutomatonCslModelCheckerTest.cpp @@ -12,10 +12,13 @@ #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/symbolic/MarkovAutomaton.h" #include "storm/models/sparse/StandardRewardModel.h" +#include "storm/models/symbolic/StandardRewardModel.h" #include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" +#include "storm/modelchecker/csl/HybridMarkovAutomatonCslModelChecker.h" #include "storm/modelchecker/results/QuantitativeCheckResult.h" #include "storm/modelchecker/results/QualitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/settings/modules/CoreSettings.h" @@ -25,7 +28,7 @@ namespace { - enum class MaEngine {PrismSparse, JaniSparse, JitSparse}; + enum class MaEngine {PrismSparse, JaniSparse, JitSparse, JaniHybrid}; class SparseDoubleValueIterationEnvironment { @@ -37,7 +40,7 @@ namespace { typedef storm::models::sparse::MarkovAutomaton<ValueType> ModelType; static storm::Environment createEnvironment() { storm::Environment env; - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration, true); env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-10)); return env; } @@ -51,7 +54,7 @@ namespace { typedef storm::models::sparse::MarkovAutomaton<ValueType> ModelType; static storm::Environment createEnvironment() { storm::Environment env; - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration, true); env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-10)); return env; } @@ -65,7 +68,21 @@ namespace { typedef storm::models::sparse::MarkovAutomaton<ValueType> ModelType; static storm::Environment createEnvironment() { storm::Environment env; - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration, true); + env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-10)); + return env; + } + }; + class JaniHybridDoubleValueIterationEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; + static const MaEngine engine = MaEngine::JaniHybrid; + static const bool isExact = false; + typedef double ValueType; + typedef storm::models::symbolic::MarkovAutomaton<ddType, ValueType> ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration, true); env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-10)); return env; } @@ -80,7 +97,7 @@ namespace { static storm::Environment createEnvironment() { storm::Environment env; env.solver().setForceSoundness(true); - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::IntervalIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::IntervalIteration, true); env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-6)); env.solver().minMax().setRelativeTerminationCriterion(false); return env; @@ -95,7 +112,7 @@ namespace { typedef storm::models::sparse::MarkovAutomaton<ValueType> ModelType; static storm::Environment createEnvironment() { storm::Environment env; - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::PolicyIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::PolicyIteration, true); return env; } }; @@ -108,7 +125,7 @@ namespace { typedef storm::models::sparse::MarkovAutomaton<ValueType> ModelType; static storm::Environment createEnvironment() { storm::Environment env; - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::RationalSearch); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::RationalSearch, true); return env; } }; @@ -150,8 +167,9 @@ namespace { std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result; storm::prism::Program program = storm::api::parseProgram(pathToPrismFile); program = storm::utility::prism::preprocess(program, constantDefinitionString); - result.second = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program)); - result.first = storm::api::buildSymbolicModel<TestType::ddType, ValueType>(program, result.second)->template as<MT>(); + auto janiData = storm::api::convertPrismToJani(program, storm::api::parsePropertiesForPrismProgram(formulasAsString, program)); + result.second = storm::api::extractFormulasFromProperties(janiData.second); + result.first = storm::api::buildSymbolicModel<TestType::ddType, ValueType>(janiData.first, result.second)->template as<MT>(); return result; } @@ -169,16 +187,18 @@ namespace { if (TestType::engine == MaEngine::PrismSparse || TestType::engine == MaEngine::JaniSparse || TestType::engine == MaEngine::JitSparse) { return std::make_shared<storm::modelchecker::SparseMarkovAutomatonCslModelChecker<SparseModelType>>(*model); } + return nullptr; } template <typename MT = typename TestType::ModelType> typename std::enable_if<std::is_same<MT, SymbolicModelType>::value, std::shared_ptr<storm::modelchecker::AbstractModelChecker<MT>>>::type createModelChecker(std::shared_ptr<MT> const& model) const { -// if (TestType::engine == MaEngine::Hybrid) { -// return std::make_shared<storm::modelchecker::HybridMarkovAutomatonCslModelChecker<SymbolicModelType>>(*model); + if (TestType::engine == MaEngine::JaniHybrid) { + return std::make_shared<storm::modelchecker::HybridMarkovAutomatonCslModelChecker<SymbolicModelType>>(*model); // } else if (TestType::engine == MaEngine::Dd) { // return std::make_shared<storm::modelchecker::SymbolicMarkovAutomatonCslModelChecker<SymbolicModelType>>(*model); -// } + } + return nullptr; } bool getQualitativeResultAtInitialState(std::shared_ptr<storm::models::Model<ValueType>> const& model, std::unique_ptr<storm::modelchecker::CheckResult>& result) { @@ -200,8 +220,7 @@ namespace { if (isSparseModel()) { return std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult>(model->template as<SparseModelType>()->getInitialStates()); } else { - // return std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<TestType::ddType>>(model->template as<SymbolicModelType>()->getReachableStates(), model->template as<SymbolicModelType>()->getInitialStates()); - return nullptr; + return std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<TestType::ddType>>(model->template as<SymbolicModelType>()->getReachableStates(), model->template as<SymbolicModelType>()->getInitialStates()); } } }; @@ -210,6 +229,7 @@ namespace { SparseDoubleValueIterationEnvironment, JaniSparseDoubleValueIterationEnvironment, JitSparseDoubleValueIterationEnvironment, + JaniHybridDoubleValueIterationEnvironment, SparseDoubleIntervalIterationEnvironment, SparseRationalPolicyIterationEnvironment, SparseRationalRationalSearchEnvironment @@ -275,6 +295,9 @@ namespace { formulasString += "; R{\"rew2\"}max=? [C]"; formulasString += "; R{\"rew2\"}min=? [C]"; formulasString += "; R{\"rew3\"}min=? [C]"; + formulasString += "; LRAmin=? [s=0 | s=3]"; // 0 + formulasString += "; R{\"rew3\"}max=?[ LRA ]"; // 407 + formulasString += "; R{\"rew3\"}min=?[ LRA ]"; // 27 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/ma/simple2.ma", formulasString); auto model = std::move(modelFormulas.first); @@ -285,26 +308,39 @@ namespace { auto checker = this->createModelChecker(model); std::unique_ptr<storm::modelchecker::CheckResult> result; - result = checker->check(this->env(), tasks[0]); - EXPECT_NEAR(this->parseNumber("2"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); - - result = checker->check(this->env(), tasks[1]); + if (TypeParam::engine != MaEngine::JaniHybrid) { + // Total Reward Formulas are not supported in the hybrid engine (for now). + + result = checker->check(this->env(), tasks[0]); + EXPECT_NEAR(this->parseNumber("2"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[1]); + EXPECT_NEAR(this->parseNumber("0"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[2]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + + result = checker->check(this->env(), tasks[3]); + EXPECT_NEAR(this->parseNumber("7/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[4]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + + result = checker->check(this->env(), tasks[5]); + EXPECT_NEAR(this->parseNumber("7/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[6]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + } + + result = checker->check(this->env(), tasks[7]); EXPECT_NEAR(this->parseNumber("0"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); - result = checker->check(this->env(), tasks[2]); - EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); - - result = checker->check(this->env(), tasks[3]); - EXPECT_NEAR(this->parseNumber("7/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); - - result = checker->check(this->env(), tasks[4]); - EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); - - result = checker->check(this->env(), tasks[5]); - EXPECT_NEAR(this->parseNumber("7/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + result = checker->check(this->env(), tasks[8]); + EXPECT_NEAR(this->parseNumber("407"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); - result = checker->check(this->env(), tasks[6]); - EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + result = checker->check(this->env(), tasks[9]); + EXPECT_NEAR(this->parseNumber("27"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); } } diff --git a/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp b/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp index 26e7f684c..e7a1a8e45 100644 --- a/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp +++ b/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp @@ -35,7 +35,7 @@ TEST(SymbolicModelBisimulationDecomposition, Die_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(11ul, quotient->getNumberOfStates()); EXPECT_EQ(17ul, quotient->getNumberOfTransitions()); @@ -50,7 +50,7 @@ TEST(SymbolicModelBisimulationDecomposition, Die_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(5ul, quotient->getNumberOfStates()); EXPECT_EQ(8ul, quotient->getNumberOfTransitions()); @@ -65,7 +65,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition(*model, storm::storage::BisimulationType::Strong); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Mdp, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); @@ -92,7 +92,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Cudd) { // Perform only one step. decomposition.compute(1); - quotient = decomposition.getQuotient(); + quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Mdp, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD, double>>(); @@ -112,7 +112,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Cudd) { // Perform only one step. decomposition.compute(1); - quotient = decomposition.getQuotient(); + quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Mdp, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD, double>>(); @@ -132,7 +132,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Cudd) { decomposition.compute(1); - quotient = decomposition.getQuotient(); + quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Dtmc, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); std::shared_ptr<storm::models::symbolic::Dtmc<storm::dd::DdType::CUDD, double>> quotientDtmc = quotient->as<storm::models::symbolic::Dtmc<storm::dd::DdType::CUDD, double>>(); @@ -155,7 +155,7 @@ TEST(SymbolicModelBisimulationDecomposition, Die_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(11ul, quotient->getNumberOfStates()); EXPECT_EQ(17ul, quotient->getNumberOfTransitions()); @@ -170,7 +170,7 @@ TEST(SymbolicModelBisimulationDecomposition, Die_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(5ul, quotient->getNumberOfStates()); EXPECT_EQ(8ul, quotient->getNumberOfTransitions()); @@ -185,7 +185,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition(*model, storm::storage::BisimulationType::Strong); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Mdp, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); @@ -212,7 +212,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Sylvan) { // Perform only one step. decomposition.compute(1); - quotient = decomposition.getQuotient(); + quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Mdp, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, double>>(); @@ -232,7 +232,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Sylvan) { // Perform only one step. decomposition.compute(1); - quotient = decomposition.getQuotient(); + quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Mdp, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, double>>(); @@ -252,7 +252,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Sylvan) { decomposition.compute(1); - quotient = decomposition.getQuotient(); + quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); ASSERT_EQ(storm::models::ModelType::Dtmc, quotient->getType()); ASSERT_TRUE(quotient->isSymbolicModel()); std::shared_ptr<storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, double>> quotientDtmc = quotient->as<storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, double>>(); @@ -278,7 +278,7 @@ TEST(SymbolicModelBisimulationDecomposition, Crowds_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(2007ul, quotient->getNumberOfStates()); EXPECT_EQ(3738ul, quotient->getNumberOfTransitions()); @@ -293,7 +293,7 @@ TEST(SymbolicModelBisimulationDecomposition, Crowds_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(65ul, quotient->getNumberOfStates()); EXPECT_EQ(105ul, quotient->getNumberOfTransitions()); @@ -311,7 +311,7 @@ TEST(SymbolicModelBisimulationDecomposition, Crowds_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(2007ul, quotient->getNumberOfStates()); EXPECT_EQ(3738ul, quotient->getNumberOfTransitions()); @@ -326,7 +326,7 @@ TEST(SymbolicModelBisimulationDecomposition, Crowds_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(65ul, quotient->getNumberOfStates()); EXPECT_EQ(105ul, quotient->getNumberOfTransitions()); @@ -341,7 +341,7 @@ TEST(SymbolicModelBisimulationDecomposition, TwoDice_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(77ul, quotient->getNumberOfStates()); EXPECT_EQ(210ul, quotient->getNumberOfTransitions()); @@ -357,7 +357,7 @@ TEST(SymbolicModelBisimulationDecomposition, TwoDice_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(11ul, quotient->getNumberOfStates()); EXPECT_EQ(34ul, quotient->getNumberOfTransitions()); @@ -373,7 +373,7 @@ TEST(SymbolicModelBisimulationDecomposition, TwoDice_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(77ul, quotient->getNumberOfStates()); EXPECT_EQ(210ul, quotient->getNumberOfTransitions()); @@ -389,7 +389,7 @@ TEST(SymbolicModelBisimulationDecomposition, TwoDice_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(11ul, quotient->getNumberOfStates()); EXPECT_EQ(34ul, quotient->getNumberOfTransitions()); @@ -411,7 +411,7 @@ TEST(SymbolicModelBisimulationDecomposition, AsynchronousLeader_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(252ul, quotient->getNumberOfStates()); EXPECT_EQ(624ul, quotient->getNumberOfTransitions()); @@ -424,7 +424,7 @@ TEST(SymbolicModelBisimulationDecomposition, AsynchronousLeader_Cudd) { storm::dd::BisimulationDecomposition<storm::dd::DdType::CUDD, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(1107ul, quotient->getNumberOfStates()); EXPECT_EQ(2684ul, quotient->getNumberOfTransitions()); @@ -446,7 +446,7 @@ TEST(SymbolicModelBisimulationDecomposition, AsynchronousLeader_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition(*model, storm::storage::BisimulationType::Strong); decomposition.compute(); - std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(); + std::shared_ptr<storm::models::Model<double>> quotient = decomposition.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(252ul, quotient->getNumberOfStates()); EXPECT_EQ(624ul, quotient->getNumberOfTransitions()); @@ -459,7 +459,7 @@ TEST(SymbolicModelBisimulationDecomposition, AsynchronousLeader_Sylvan) { storm::dd::BisimulationDecomposition<storm::dd::DdType::Sylvan, double> decomposition2(*model, formulas, storm::storage::BisimulationType::Strong); decomposition2.compute(); - quotient = decomposition2.getQuotient(); + quotient = decomposition2.getQuotient(storm::dd::bisimulation::QuotientFormat::Dd); EXPECT_EQ(1107ul, quotient->getNumberOfStates()); EXPECT_EQ(2684ul, quotient->getNumberOfTransitions());