C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html

This commit is contained in:
Arash Partow 2013-04-23 21:30:49 +10:00
parent e10cdcffcd
commit 9f5db27235
4 changed files with 314 additions and 49 deletions

View File

@ -33,6 +33,7 @@ BUILD_LIST+=exprtk_simple_example_06
BUILD_LIST+=exprtk_simple_example_07 BUILD_LIST+=exprtk_simple_example_07
BUILD_LIST+=exprtk_simple_example_08 BUILD_LIST+=exprtk_simple_example_08
BUILD_LIST+=exprtk_simple_example_09 BUILD_LIST+=exprtk_simple_example_09
BUILD_LIST+=exprtk_simple_example_10
all: $(BUILD_LIST) all: $(BUILD_LIST)
@ -69,6 +70,9 @@ exprtk_simple_example_08: exprtk_simple_example_08.cpp exprtk.hpp
exprtk_simple_example_09: exprtk_simple_example_09.cpp exprtk.hpp exprtk_simple_example_09: exprtk_simple_example_09.cpp exprtk.hpp
$(COMPILER) $(OPTIONS) exprtk_simple_example_09 exprtk_simple_example_09.cpp $(LINKER_OPT) $(COMPILER) $(OPTIONS) exprtk_simple_example_09 exprtk_simple_example_09.cpp $(LINKER_OPT)
exprtk_simple_example_10: exprtk_simple_example_10.cpp exprtk.hpp
$(COMPILER) $(OPTIONS) exprtk_simple_example_10 exprtk_simple_example_10.cpp $(LINKER_OPT)
pgo: exprtk_test.cpp exprtk_benchmark.cpp exprtk.hpp pgo: exprtk_test.cpp exprtk_benchmark.cpp exprtk.hpp
$(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT) $(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT)
./exprtk_benchmark ./exprtk_benchmark
@ -86,6 +90,7 @@ strip_bin:
strip -s exprtk_simple_example_07 strip -s exprtk_simple_example_07
strip -s exprtk_simple_example_08 strip -s exprtk_simple_example_08
strip -s exprtk_simple_example_09 strip -s exprtk_simple_example_09
strip -s exprtk_simple_example_10
valgrind_check: valgrind_check:
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_test valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_test
@ -99,6 +104,7 @@ valgrind_check:
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_07 valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_07
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_08 valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_08
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_09 valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_09
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_10
clean: clean:
rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch

View File

@ -1,14 +1,14 @@
/* /*
**************************************************************** ******************************************************************
* C++ Mathematical Expression Toolkit Library * * C++ Mathematical Expression Toolkit Library *
* * * *
* Author: Arash Partow (1999-2013) * * Author: Arash Partow (1999-2013) *
* URL: http://www.partow.net/programming/exprtk/index.html * * URL: http://www.partow.net/programming/exprtk/index.html *
* * * *
* Copyright notice: * * Copyright notice: *
* Free use of the C++ Mathematical Expression Toolkit Library * * Free use of the C++ Mathematical Expression Toolkit Library is *
* is permitted under the guidelines and in accordance with the * * permitted under the guidelines and in accordance with the most *
* most current version of the Common Public License. * * current version of the Common Public License. *
* http://www.opensource.org/licenses/cpl1.0.php * * http://www.opensource.org/licenses/cpl1.0.php *
* * * *
* Example expressions: * * Example expressions: *
@ -26,7 +26,7 @@
* (11) (12.34sin(x)cos(2y)7+1)==(12.34*sin(x)*cos(2*y)*7+1) * * (11) (12.34sin(x)cos(2y)7+1)==(12.34*sin(x)*cos(2*y)*7+1) *
* (12) (x ilike 's*ri?g') and [y<(3z^7+w)] * * (12) (x ilike 's*ri?g') and [y<(3z^7+w)] *
* * * *
**************************************************************** ******************************************************************
*/ */
@ -2304,7 +2304,7 @@ namespace exprtk
void reset() void reset()
{ {
//msvc doesn't support swap properly. //why? because msvc doesn't support swap properly.
stack_ = std::stack<char>(); stack_ = std::stack<char>();
state_ = true; state_ = true;
error_token_.clear(); error_token_.clear();
@ -9400,6 +9400,27 @@ namespace exprtk
e_commutative_check = 32 e_commutative_check = 32
}; };
struct unknown_symbol_resolver
{
enum symbol_type
{
e_variable_type = 0,
e_constant_type = 1
};
virtual ~unknown_symbol_resolver()
{}
virtual bool process(const std::string& /*unknown_symbol*/, symbol_type& st, T& default_value, std::string& error_message)
{
st = e_variable_type;
default_value = T(0);
error_message = "";
return true;
}
};
static const std::size_t precompile_all_opts = e_replacer + static const std::size_t precompile_all_opts = e_replacer +
e_joiner + e_joiner +
e_numeric_check + e_numeric_check +
@ -9409,7 +9430,9 @@ namespace exprtk
parser(const std::size_t precompile_options = precompile_all_opts) parser(const std::size_t precompile_options = precompile_all_opts)
: symbol_name_caching_(false), : symbol_name_caching_(false),
precompile_options_(precompile_options) precompile_options_(precompile_options),
resolve_unknown_symbol_(false),
unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0))
{ {
init_precompilation(); init_precompilation();
load_operations_map(base_ops_map_); load_operations_map(base_ops_map_);
@ -9729,6 +9752,21 @@ namespace exprtk
return symbol_replacer_.remove(symbol); return symbol_replacer_.remove(symbol);
} }
inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast<unknown_symbol_resolver*>(0))
{
resolve_unknown_symbol_ = true;
if (usr)
unknown_symbol_resolver_ = usr;
else
unknown_symbol_resolver_ = &default_usr_;
}
inline void disable_unknown_symbol_resolver()
{
resolve_unknown_symbol_ = false;
unknown_symbol_resolver_ = &default_usr_;
}
private: private:
inline bool valid_base_operation(const std::string& symbol) inline bool valid_base_operation(const std::string& symbol)
@ -10799,15 +10837,61 @@ namespace exprtk
return error_node(); return error_node();
} }
} }
else
// Should we handle unknown symbols?
if (resolve_unknown_symbol_ && unknown_symbol_resolver_)
{ {
T default_value = T(0);
std::string error_message;
typename unknown_symbol_resolver::symbol_type symbol_type;
if (unknown_symbol_resolver_->process(symbol,symbol_type,default_value,error_message))
{
bool create_result = false;
switch (symbol_type)
{
case unknown_symbol_resolver::e_variable_type : create_result = symbol_table_.create_variable(symbol,default_value);
break;
case unknown_symbol_resolver::e_constant_type : create_result = symbol_table_.add_constant(symbol,default_value);
break;
default : create_result = false;
}
if (create_result)
{
expression_node_ptr variable = symbol_table_.get_variable(symbol);
if (variable)
{
if (symbol_name_caching_)
{
symbol_name_cache_.push_back(symbol);
}
if (symbol_table_.is_constant_node(symbol))
{
variable = expression_generator_(variable->value());
}
next_token();
return variable;
}
}
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR40 - Failed to create variable: '" + symbol + "'"));
return error_node();
}
}
set_error( set_error(
make_error(parser_error::e_syntax, make_error(parser_error::e_syntax,
current_token_, current_token_,
"ERR40 - Undefined variable or function: '" + symbol + "'")); "ERR41 - Undefined variable or function: '" + symbol + "'"));
return error_node(); return error_node();
} }
}
inline expression_node_ptr parse_symbol() inline expression_node_ptr parse_symbol()
{ {
@ -11747,6 +11831,7 @@ namespace exprtk
else if (all_nodes_variables(branch)) else if (all_nodes_variables(branch))
return varnode_optimize_sf3(operation,branch); return varnode_optimize_sf3(operation,branch);
else else
{
switch (operation) switch (operation)
{ {
#define case_stmt(op0,op1) case op0 : return node_allocator_->allocate<details::sf3_node<Type,op1<Type> > >(operation,branch); #define case_stmt(op0,op1) case op0 : return node_allocator_->allocate<details::sf3_node<Type,op1<Type> > >(operation,branch);
@ -11778,6 +11863,7 @@ namespace exprtk
default : return error_node(); default : return error_node();
} }
} }
}
inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
{ {
@ -15524,6 +15610,9 @@ namespace exprtk
std::size_t precompile_options_; std::size_t precompile_options_;
std::deque<std::string> symbol_name_cache_; std::deque<std::string> symbol_name_cache_;
std::deque<parser_error::type> error_list_; std::deque<parser_error::type> error_list_;
bool resolve_unknown_symbol_;
unknown_symbol_resolver* unknown_symbol_resolver_;
unknown_symbol_resolver default_usr_;
base_ops_map_t base_ops_map_; base_ops_map_t base_ops_map_;
unary_op_map_t unary_op_map_; unary_op_map_t unary_op_map_;
binary_op_map_t binary_op_map_; binary_op_map_t binary_op_map_;

View File

@ -3830,6 +3830,165 @@ inline bool run_test19()
return false; return false;
} }
{
T x = T(0);
exprtk::symbol_table<T> symbol_table;
symbol_table.add_constants();
symbol_table.add_variable("x",x);
compositor_t compositor(symbol_table);
compositor
.add("newton_sqrt_impl",
"switch "
"{ "
" case x < 0 : -inf; "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default: "
" ~{ "
" z := 100; "
" y := x / 2; "
" while ((z := (z - 1)) > 0) "
" { "
" if (equal(y * y,x), z := 0, 0);"
" y := (1 / 2) * (y + (x / y)) "
" } "
" }; "
"} ",
"x","y","z");
compositor
.add("newton_sqrt",
"newton_sqrt_impl(x,0,0)","x");
std::string expression_str = "newton_sqrt(x)";
expression_t expression;
expression.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
if (!parser.compile(expression_str,expression))
{
printf("run_test19() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_str.c_str());
return false;
}
bool failure = false;
for (std::size_t i = 0; i < 100; ++i)
{
x = i;
T result = expression.value();
if (not_equal(result,std::sqrt(x),T(0.0000001)))
{
printf("run_test19() - Computation Error "
"Expression: [%s]\tExpected: %12.8f\tResult: %12.8f\n",
expression_str.c_str(),
std::sqrt(x),
result);
failure = true;
}
}
if (failure)
return false;
}
return true;
}
template <typename T>
struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
{
typedef typename exprtk::parser<T>::unknown_symbol_resolver usr_t;
bool process(const std::string& unknown_symbol,
typename usr_t::symbol_type& st,
T& default_value,
std::string& error_message)
{
if (unknown_symbol[0] == 'v')
{
st = usr_t::e_variable_type;
default_value = next_value();
error_message = "";
return true;
}
else if (unknown_symbol[0] == 'w')
{
st = usr_t::e_constant_type;
default_value = next_value();
error_message = "";
return true;
}
else
{
error_message = "Unknown symbol...";
return false;
}
}
T next_value(const bool reset = false)
{
static T value = 0;
if (reset)
return (value = 0);
else
return ++value;
}
};
template <typename T>
inline bool run_test20()
{
typedef exprtk::expression<T> expression_t;
for (std::size_t i = 0; i < 400; ++i)
{
exprtk::symbol_table<T> symbol_table;
symbol_table.add_constants();
expression_t expression;
expression.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
my_usr<T> musr;
musr.next_value(true);
parser.enable_unknown_symbol_resolver(&musr);
std::string expr_str = "v01+w02+v03+w04+v05+w06+v07+w08+v09+w10+"
"v11+w12+v13+w14+v15+w16+v17+w18+v19+w20+"
"v21+w22+v23+w24+v25+w26+v27+w28+v29+w30";
if (!parser.compile(expr_str,expression))
{
printf("run_test18() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str.c_str());
return false;
}
T sum_1_30 = T((1 + 30) * 15);
T result = expression.value();
if (sum_1_30 != result)
{
printf("run_test20() - Error in evaluation! (1) Expression: %s\n",
expr_str.c_str());
return false;
}
}
return true; return true;
} }
@ -3870,6 +4029,7 @@ int main()
perform_test(double,17) perform_test(double,17)
perform_test(double,18) perform_test(double,18)
perform_test(double,19) perform_test(double,19)
perform_test(double,20)
#undef perform_test #undef perform_test

View File

@ -1,6 +1,6 @@
C++ Mathematical Expression Toolkit Library C++ Mathematical Expression Toolkit Library
[INTRODUCTION] [00 - INTRODUCTION]
The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple
to use, easy to integrate and extremely efficient mathematical to use, easy to integrate and extremely efficient mathematical
expression parsing and evaluation engine. The parsing engine supports expression parsing and evaluation engine. The parsing engine supports
@ -9,7 +9,7 @@ very easily extendible.
[CAPABILITIES] [01 - CAPABILITIES]
The ExprTk evaluator supports the following fundamental mathematical The ExprTk evaluator supports the following fundamental mathematical
operations, functions and processes: operations, functions and processes:
@ -42,7 +42,7 @@ operations, functions and processes:
[EXAMPLE EXPRESSIONS] [02 - EXAMPLE EXPRESSIONS]
The following is a short sample of the types of mathematical The following is a short sample of the types of mathematical
expressions that can be parsed and evaluated using the ExprTk library. expressions that can be parsed and evaluated using the ExprTk library.
@ -69,7 +69,7 @@ expressions that can be parsed and evaluated using the ExprTk library.
[COPYRIGHT NOTICE] [03 - COPYRIGHT NOTICE]
Free use of the C++ Mathematical Expression Toolkit Library is Free use of the C++ Mathematical Expression Toolkit Library is
permitted under the guidelines and in accordance with the most current permitted under the guidelines and in accordance with the most current
version of the Common Public License. version of the Common Public License.
@ -78,7 +78,7 @@ http://www.opensource.org/licenses/cpl1.0.php
[DOWNLOADS & UPDATES] [04 - DOWNLOADS & UPDATES]
The most recent version of the C++ Mathematical Expression Toolkit The most recent version of the C++ Mathematical Expression Toolkit
Library including all updates and tests can be found at the following Library including all updates and tests can be found at the following
locations: locations:
@ -88,20 +88,20 @@ locations:
[INSTALLATION] [05 - INSTALLATION]
The header file exprtk.hpp should be placed in a project or system The header file exprtk.hpp should be placed in a project or system
include path (e.g: /usr/include/). include path (e.g: /usr/include/).
[COMPILATION] [06 - COMPILATION]
(1) For a complete build: make clean all (1) For a complete build: make clean all
(2) For a PGO build: make clean pgo (2) For a PGO build: make clean pgo
(3) To strip executables: make strip_bin (3) To strip executables: make strip_bin
[COMPILER COMPATIBILITY] [07 - COMPILER COMPATIBILITY]
(*) GNU Compiler Collection (4.3+) (*) GNU Compiler Collection (4.3+)
(*) Intel® C++ Compiler (9.x+) (*) Intel® C++ Compiler (9.x+)
(*) Clang/LLVM (1.1+) (*) Clang/LLVM (1.1+)
@ -112,7 +112,7 @@ include path (e.g: /usr/include/).
[BUILT-IN OPERATIONS & FUNCTIONS] [08 - BUILT-IN OPERATIONS & FUNCTIONS]
(0) Basic Operators (0) Basic Operators
+-----------+--------------------------------------------------------+ +-----------+--------------------------------------------------------+
@ -344,7 +344,7 @@ include path (e.g: /usr/include/).
[SPECIAL FUNCTIONS] [09 - SPECIAL FUNCTIONS]
The purpose of special functions in ExprTk is to provide compiler The purpose of special functions in ExprTk is to provide compiler
generated equivalents of common mathematical expressions which can be generated equivalents of common mathematical expressions which can be
invoked by using the 'special function' syntax (eg: $f12(x,y,z) or invoked by using the 'special function' syntax (eg: $f12(x,y,z) or
@ -415,7 +415,7 @@ correctly optimize such expressions for a given architecture.
[EXPRTK NOTES] [10 - EXPRTK NOTES]
(00) Precision and performance of expression evaluations are the (00) Precision and performance of expression evaluations are the
dominant principles of the ExprTk library. dominant principles of the ExprTk library.
@ -478,7 +478,7 @@ correctly optimize such expressions for a given architecture.
[SIMPLE EXPRTK EXAMPLE] [11 - SIMPLE EXPRTK EXAMPLE]
--- snip --- --- snip ---
#include <cstdio> #include <cstdio>
#include <string> #include <string>
@ -553,9 +553,19 @@ int main()
[FILES] [12 - FILES]
(00) Makefile (00) Makefile
(01) readme.txt (01) readme.txt
(02) exprtk.hpp (02) exprtk.hpp
(03) exprtk_test.cpp (03) exprtk_test.cpp
(04) exprtk_benchmark.cpp (04) exprtk_benchmark.cpp
(05) exprtk_simple_example_01.cpp
(06) exprtk_simple_example_02.cpp
(07) exprtk_simple_example_03.cpp
(08) exprtk_simple_example_04.cpp
(09) exprtk_simple_example_05.cpp
(10) exprtk_simple_example_06.cpp
(11) exprtk_simple_example_07.cpp
(12) exprtk_simple_example_08.cpp
(13) exprtk_simple_example_09.cpp
(14) exprtk_simple_example_10.cpp