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_08
BUILD_LIST+=exprtk_simple_example_09
BUILD_LIST+=exprtk_simple_example_10
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
$(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
$(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT)
./exprtk_benchmark
@ -86,6 +90,7 @@ strip_bin:
strip -s exprtk_simple_example_07
strip -s exprtk_simple_example_08
strip -s exprtk_simple_example_09
strip -s exprtk_simple_example_10
valgrind_check:
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_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_10
clean:
rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch

View File

@ -1,32 +1,32 @@
/*
****************************************************************
* C++ Mathematical Expression Toolkit Library *
* *
* Author: Arash Partow (1999-2013) *
* URL: http://www.partow.net/programming/exprtk/index.html *
* *
* Copyright notice: *
* Free use of the C++ Mathematical Expression Toolkit Library *
* is permitted under the guidelines and in accordance with the *
* most current version of the Common Public License. *
* http://www.opensource.org/licenses/cpl1.0.php *
* *
* Example expressions: *
* (00) (y+x/y)*(x-y/x) *
* (01) (x^2/sin(2*pi/y))-x/2 *
* (02) sqrt(1-(x^2)) *
* (03) 1-sin(2*x)+cos(pi/y) *
* (04) a*exp(2*t)+c *
* (05) if(((x+2)==3)and((y+5)<=9),1+w,2/z) *
* (06) if(avg(x,y)<=x+y,x-y,x*y)+2*pi/x *
* (07) z:=x+sin(2*pi/y) *
* (08) u:=2*(pi*z)/(w:=x+cos(y/pi)) *
* (09) clamp(-1,sin(2*pi*x)+cos(y/2*pi),+1) *
* (10) inrange(-2,m,+2)==if(({-2<=m} and [m<=+2]),1,0) *
* (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)] *
* *
****************************************************************
******************************************************************
* C++ Mathematical Expression Toolkit Library *
* *
* Author: Arash Partow (1999-2013) *
* URL: http://www.partow.net/programming/exprtk/index.html *
* *
* Copyright notice: *
* Free use of the C++ Mathematical Expression Toolkit Library is *
* permitted under the guidelines and in accordance with the most *
* current version of the Common Public License. *
* http://www.opensource.org/licenses/cpl1.0.php *
* *
* Example expressions: *
* (00) (y+x/y)*(x-y/x) *
* (01) (x^2/sin(2*pi/y))-x/2 *
* (02) sqrt(1-(x^2)) *
* (03) 1-sin(2*x)+cos(pi/y) *
* (04) a*exp(2*t)+c *
* (05) if(((x+2)==3)and((y+5)<=9),1+w,2/z) *
* (06) if(avg(x,y)<=x+y,x-y,x*y)+2*pi/x *
* (07) z:=x+sin(2*pi/y) *
* (08) u:=2*(pi*z)/(w:=x+cos(y/pi)) *
* (09) clamp(-1,sin(2*pi*x)+cos(y/2*pi),+1) *
* (10) inrange(-2,m,+2)==if(({-2<=m} and [m<=+2]),1,0) *
* (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)] *
* *
******************************************************************
*/
@ -2304,7 +2304,7 @@ namespace exprtk
void reset()
{
//msvc doesn't support swap properly.
//why? because msvc doesn't support swap properly.
stack_ = std::stack<char>();
state_ = true;
error_token_.clear();
@ -9400,6 +9400,27 @@ namespace exprtk
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 +
e_joiner +
e_numeric_check +
@ -9409,7 +9430,9 @@ namespace exprtk
parser(const std::size_t precompile_options = precompile_all_opts)
: 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();
load_operations_map(base_ops_map_);
@ -9729,6 +9752,21 @@ namespace exprtk
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:
inline bool valid_base_operation(const std::string& symbol)
@ -10799,14 +10837,60 @@ namespace exprtk
return error_node();
}
}
else
// Should we handle unknown symbols?
if (resolve_unknown_symbol_ && unknown_symbol_resolver_)
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR40 - Undefined variable or function: '" + symbol + "'"));
return error_node();
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(
make_error(parser_error::e_syntax,
current_token_,
"ERR41 - Undefined variable or function: '" + symbol + "'"));
return error_node();
}
inline expression_node_ptr parse_symbol()
@ -11747,6 +11831,7 @@ namespace exprtk
else if (all_nodes_variables(branch))
return varnode_optimize_sf3(operation,branch);
else
{
switch (operation)
{
#define case_stmt(op0,op1) case op0 : return node_allocator_->allocate<details::sf3_node<Type,op1<Type> > >(operation,branch);
@ -11777,6 +11862,7 @@ namespace exprtk
#undef case_stmt
default : return error_node();
}
}
}
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::deque<std::string> symbol_name_cache_;
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_;
unary_op_map_t unary_op_map_;
binary_op_map_t binary_op_map_;

View File

@ -3830,6 +3830,165 @@ inline bool run_test19()
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;
}
@ -3870,6 +4029,7 @@ int main()
perform_test(double,17)
perform_test(double,18)
perform_test(double,19)
perform_test(double,20)
#undef perform_test

View File

@ -1,6 +1,6 @@
C++ Mathematical Expression Toolkit Library
[INTRODUCTION]
[00 - INTRODUCTION]
The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple
to use, easy to integrate and extremely efficient mathematical
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
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
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
permitted under the guidelines and in accordance with the most current
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
Library including all updates and tests can be found at the following
locations:
@ -88,20 +88,20 @@ locations:
[INSTALLATION]
[05 - INSTALLATION]
The header file exprtk.hpp should be placed in a project or system
include path (e.g: /usr/include/).
[COMPILATION]
[06 - COMPILATION]
(1) For a complete build: make clean all
(2) For a PGO build: make clean pgo
(3) To strip executables: make strip_bin
[COMPILER COMPATIBILITY]
[07 - COMPILER COMPATIBILITY]
(*) GNU Compiler Collection (4.3+)
(*) Intel® C++ Compiler (9.x+)
(*) 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
+-----------+--------------------------------------------------------+
@ -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
generated equivalents of common mathematical expressions which can be
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
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 ---
#include <cstdio>
#include <string>
@ -553,9 +553,19 @@ int main()
[FILES]
[12 - FILES]
(00) Makefile
(01) readme.txt
(02) exprtk.hpp
(03) exprtk_test.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