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

This commit is contained in:
Arash Partow 2014-11-30 20:48:19 +11:00
parent ce23204895
commit 334953ee4d
3 changed files with 1877 additions and 591 deletions

1548
exprtk.hpp

File diff suppressed because it is too large Load Diff

View File

@ -4419,9 +4419,133 @@ struct va_func : public exprtk::ivararg_function<T>
} }
}; };
template <typename T>
struct gen_func : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::generic_type generic_type;
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t;
typedef typename generic_type::scalar_view scalar_t;
typedef typename generic_type::vector_view vector_t;
typedef typename generic_type::string_view string_t;
gen_func()
: scalar_count(0),
vector_count(0),
string_count(0)
{}
inline T operator()(parameter_list_t& params)
{
for (std::size_t i = 0; i < params.size(); ++i)
{
generic_type& gt = params[i];
switch (gt.type)
{
case generic_type::e_scalar : scalar_count++;
break;
case generic_type::e_vector : vector_count++;
break;
case generic_type::e_string : {
if (
("CdEf" != exprtk::to_str(string_t(gt))) &&
("abc123" != exprtk::to_str(string_t(gt)))
)
{
return std::numeric_limits<T>::quiet_NaN();
}
else
string_count++;
}
break;
default : return std::numeric_limits<T>::quiet_NaN();
}
}
return T(0);
}
std::size_t scalar_count;
std::size_t vector_count;
std::size_t string_count;
};
template <typename T>
struct gen_func2 : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t;
gen_func2()
{}
inline T operator()(parameter_list_t&)
{
return T(0);
}
};
template <typename T>
struct inc_func : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::generic_type generic_type;
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t;
typedef typename generic_type::scalar_view scalar_t;
typedef typename generic_type::vector_view vector_t;
typedef typename generic_type::string_view string_t;
inc_func()
{}
inline T operator()(parameter_list_t& params)
{
for (std::size_t i = 0; i < params.size(); ++i)
{
generic_type& gt = params[i];
switch (gt.type)
{
case generic_type::e_scalar : {
scalar_t scalar(gt);
scalar() += T(1);
}
break;
case generic_type::e_vector : {
vector_t vector(gt);
for (std::size_t x = 0; x < vector.size(); ++x)
{
vector[x] += T(1);
}
}
break;
case generic_type::e_string : {
string_t string(gt);
for (std::size_t x = 0; x < string.size(); ++x)
{
string[x] += static_cast<typename string_t::value_t>(1);
}
}
break;
default : return std::numeric_limits<T>::quiet_NaN();
}
}
return T(0);
}
};
template <typename T> template <typename T>
inline bool run_test18() inline bool run_test18()
{ {
{
typedef exprtk::expression<T> expression_t; typedef exprtk::expression<T> expression_t;
T x = T(1.1); T x = T(1.1);
@ -4443,7 +4567,7 @@ inline bool run_test18()
symbol_table.add_variable("u",u); symbol_table.add_variable("u",u);
symbol_table.add_variable("v",v); symbol_table.add_variable("v",v);
symbol_table.add_variable("t",t); symbol_table.add_variable("t",t);
symbol_table.add_vararg_function("va_func",vaf); symbol_table.add_function("va_func",vaf);
static const std::string expr_str_list[] = static const std::string expr_str_list[] =
{ {
@ -4476,7 +4600,7 @@ inline bool run_test18()
if (!parser.compile(expr_str_list[i],expression)) if (!parser.compile(expr_str_list[i],expression))
{ {
printf("run_test18() - Error: %s Expression: %s\n", printf("run_test18() - VarArg Error: %s Expression: %s\n",
parser.error().c_str(), parser.error().c_str(),
expr_str_list[i].c_str()); expr_str_list[i].c_str());
@ -4499,7 +4623,330 @@ inline bool run_test18()
} }
} }
return !failure; if (failure)
return false;
}
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
T x = T(33);
T y = T(77);
T v0[] = { T(1), T(1), T(1), T(1) };
T v1[] = { T(1), T(2), T(3), T(4) };
std::vector<T> v2;
v2.push_back(T(5));
v2.push_back(T(6));
v2.push_back(T(7));
v2.push_back(T(8));
std::string s0 = "AbCdEfGhIj";
gen_func<T> f;
symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable ("x" , x);
symbol_table.add_variable ("y" , y);
symbol_table.add_vector ("v0" ,v0);
symbol_table.add_vector ("v1" ,v1);
symbol_table.add_vector ("v2" ,v2);
symbol_table.add_stringvar("s0", s0);
symbol_table.add_function ("gen_func", f);
std::string expression_list[] =
{
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func('abc123', s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; gen_func(s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3, 'abc123');"
};
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
bool failure = false;
for (std::size_t i = 0; i < expression_list_size; ++i)
{
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
if (!parser.compile(expression_list[i],expression))
{
printf("run_test18() - GenFunc Error: %s Expression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
failure = true;
continue;
}
f.scalar_count = 0;
f.vector_count = 0;
f.string_count = 0;
expression.value();
if (
(4 != f.scalar_count) ||
(3 != f.vector_count) ||
(2 != f.string_count)
)
{
printf("run_test18() - Error in evaluation! (2) Expression: %s "
"sc_count = %d "
"vr_count = %d "
"st_count = %d\n",
expression_list[i].c_str(),
static_cast<int>(f.scalar_count),
static_cast<int>(f.vector_count),
static_cast<int>(f.string_count));
failure = true;
}
}
if (failure)
return false;
}
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
T x = T(33);
T y = T(77);
T v0[] = { T(1), T(1), T(1), T(1) };
T v1[] = { T(1), T(2), T(3), T(4) };
T v2[] = { T(5), T(6), T(7), T(8) };
std::string s0 = "AbCdEfGhIj";
gen_func2<T> f;
symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable ("x" , x);
symbol_table.add_variable ("y" , y);
symbol_table.add_vector ("v0" ,v0);
symbol_table.add_vector ("v1" ,v1);
symbol_table.add_vector ("v2" ,v2);
symbol_table.add_stringvar("s0", s0);
symbol_table.add_function ("foo", f);
std::string expression_list[] =
{
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(x, 2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(2x + y, z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(z, 2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo('abc123', s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3, 'abc123');"
};
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
std::string parameter_type_list[] =
{
"VVTTTTVSS",
"VTTTTVSSV",
"TTTTVSSVV",
"TTTVSSVVT",
"TTVSSVVT*",
"TVSSVVT*" ,
"VSSVVT*" ,
"SSVVTTTTV",
"SVVTTTTVS",
};
bool failure = false;
for (std::size_t i = 0; i < expression_list_size; ++i)
{
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
f.parameter_sequence = parameter_type_list[i];
if (!parser.compile(expression_list[i],expression))
{
printf("run_test18() - GenFunc2 Error: %s Expression: %s Parameter Sequence: %s\n",
parser.error().c_str(),
expression_list[i].c_str(),
parameter_type_list[i].c_str());
failure = true;
continue;
}
expression.value();
}
if (failure)
return false;
}
{
bool failure = false;
std::string expression_list[] =
{
"foo(v0,v1,v2,x,y,s0);",
"foo(v1,v2,x,y,s0,v0);",
"foo(v2,x,y,s0,v0,v1);",
"foo(x,y,s0,v0,v1,v2);",
"foo(y,s0,v0,v1,v2,x);",
"foo(s0,v0,v1,v2,x,y);"
};
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
std::string parameter_type_list[] =
{
"VVVTTS",
"VVTTSV",
"VTTSVV",
"TTSVVV",
"TSVVVT",
"SVVVTT"
};
for (std::size_t i = 0; i < expression_list_size; ++i)
{
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
T x = T(33);
T y = T(77);
T v0[] = { T(1), T(1), T(1), T(1) };
T v1[] = { T(1), T(2), T(3), T(4) };
T v2[] = { T(5), T(6), T(7), T(8) };
std::string s0 = "AbCdEfGhIj";
T x_inc = T(34);
T y_inc = T(78);
T v0_inc[] = { T(2), T(2), T(2), T(2) };
T v1_inc[] = { T(2), T(3), T(4), T(5) };
T v2_inc[] = { T(6), T(7), T(8), T(9) };
std::size_t sizeof_vec = sizeof(v0) / sizeof(T);
std::string s0_inc = "BcDeFgHiJk";
inc_func<T> f;
symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable ("x" , x);
symbol_table.add_variable ("y" , y);
symbol_table.add_vector ("v0" ,v0);
symbol_table.add_vector ("v1" ,v1);
symbol_table.add_vector ("v2" ,v2);
symbol_table.add_stringvar("s0", s0);
symbol_table.add_function ("foo", f);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
f.parameter_sequence = parameter_type_list[i];
if (!parser.compile(expression_list[i],expression))
{
printf("run_test18() - IncFunc Error: %s Expression: %s Parameter Sequence: %s\n",
parser.error().c_str(),
expression_list[i].c_str(),
parameter_type_list[i].c_str());
failure = true;
continue;
}
expression.value();
if (x != x_inc)
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: x\n",
expression_list[i].c_str());
failure = true;
}
if (y != y_inc)
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: y\n",
expression_list[i].c_str());
failure = true;
}
if (s0 != s0_inc)
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: y\n",
expression_list[i].c_str());
failure = true;
}
if (!std::equal(v0,v0 + sizeof_vec,v0_inc))
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: v0\n",
expression_list[i].c_str());
failure = true;
}
if (!std::equal(v1,v1 + sizeof_vec,v1_inc))
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: v1\n",
expression_list[i].c_str());
failure = true;
}
if (!std::equal(v2,v2 + sizeof_vec,v2_inc))
{
printf("run_test18() - Error in evaluation! (3) Expression: %s Check: v2\n",
expression_list[i].c_str());
failure = true;
}
}
if (failure)
return false;
}
return true;
} }
template <typename T> template <typename T>

View File

@ -618,7 +618,7 @@ current values assigned to the variables will be used.
y = -9.0; y = -9.0;
expression.value(); // 3.7 * -9 + 3 expression.value(); // 3.7 * -9 + 3
// 'x * -9 + 3' for x in range of [0,100] in steps of 0.0001 // 'x * -9 + 3' for x in range of [0,100) in steps of 0.0001
for (var x = 0; x < 100; x += 0.0001) for (var x = 0; x < 100; x += 0.0001)
{ {
expression.value(); // x * -9 + 3 expression.value(); // x * -9 + 3
@ -1029,7 +1029,8 @@ There are two types of function interface:
(1) ifunction (1) ifunction
(2) ivararg_function (2) ivararg_function
(3) function_compositor (3) igeneric_function
(4) function_compositor
(1) ifunction (1) ifunction
@ -1075,7 +1076,56 @@ example defines a vararg function called 'boo':
}; };
(3) function_compositor (3) igeneric_function
This interface supports a variable number of arguments and types as
input into the function. The function operator interface uses a
std::vector specialized upon the type_store type to facilitate
parameter passing.
The fundamental types that can be passed into the function as
parameters and their views are as follows:
(1) scalar - scalar_view
(2) vector - vector_view
(3) string - string_view
The following example defines a generic function called 'too':
template <typename T>
struct too : public exprtk::igeneric_function<T>
{
typedef typename exprtk::igeneric_function<T>::parameter_list_t
parameter_list_t;
too()
{}
inline T operator()(parameter_list_t& parameters)
{
for (std::size_t i = 0; i < parameters.size(); ++i)
{
}
return T(0);
}
};
In the above example, the parameter_list_t type is a type of
std::vector of type_store. Each type_store instance has a member
called 'type' which holds the enumeration pertaining the underlying
type of the type_store. There are three type enumerations:
(1) e_scalar - variables, vector elements, general expressions
eg: x, y, z, vec[3x + 1], 2x + 3
(2) e_vector - vectors, vector expressions
eg: vec1, 2 * vec1 + vec2 / 3
(3) e_string - string, string literal and range variants of both
eg: 'AString', s0, 'AString'[x:y], s1[1+x:]
(4) function_compositor
The function compositor interface allows a user to define a function The function compositor interface allows a user to define a function
using ExprTk syntax. The functions are limited to returning a single using ExprTk syntax. The functions are limited to returning a single
scalar value and consuming up to six parameters as input. scalar value and consuming up to six parameters as input.
@ -1126,7 +1176,7 @@ The following demonstrates how all the pieces are put together:
symbol_table_t symbol_table; symbol_table_t symbol_table;
symbol_table.add_function("foo",f); symbol_table.add_function("foo",f);
symbol_table.add_vararg_function("boo",b); symbol_table.add_function("boo",b);
compositor compositor
.add(function_t() .add(function_t()
@ -1330,11 +1380,11 @@ into account when using Exprtk:
epsilons of 0.0000000001 and 0.000001 for double and float epsilons of 0.0000000001 and 0.000001 for double and float
types respectively. types respectively.
(11) All trigonometric functions assume radian input unless (11) All trigonometric functions assume radian input unless stated
stated otherwise. otherwise.
(12) Expressions may contain white-space characters such as (12) Expressions may contain white-space characters such as space,
space, tabs, new-lines, control-feed et al. tabs, new-lines, control-feed et al.
('\n', '\r', '\t', '\b', '\v', '\f') ('\n', '\r', '\t', '\b', '\v', '\f')
(13) Strings may be comprised of any combination of letters, digits (13) Strings may be comprised of any combination of letters, digits
@ -1355,9 +1405,9 @@ into account when using Exprtk:
then where applicable strength reduction optimisations may be then where applicable strength reduction optimisations may be
applied. applied.
(18) String processing capabilities are available by default. (18) String processing capabilities are available by default. To
To turn them off, the following needs to be defined at turn them off, the following needs to be defined at compile
compile time: exprtk_disable_string_capabilities time: exprtk_disable_string_capabilities
(19) Composited functions can call themselves or any other functions (19) Composited functions can call themselves or any other functions
that have been defined prior to their own definition. that have been defined prior to their own definition.
@ -1396,9 +1446,10 @@ into account when using Exprtk:
3. /* .... */ 3. /* .... */
(26) The 'null' value type is a special non-zero type that (26) The 'null' value type is a special non-zero type that
incorporates specific semantics when undergoing operations incorporates specific semantics when undergoing operations with
with the standard numeric type. The following is a list of the standard numeric type. The following is a list of type and
type and boolean results associated with the use of 'null': boolean results associated with the use of 'null':
1. null +,-,*,/,% x --> x 1. null +,-,*,/,% x --> x
2. x +,-,*,/,% null --> x 2. x +,-,*,/,% null --> x
3. null +,-,*,/,% null --> null 3. null +,-,*,/,% null --> null
@ -1411,8 +1462,8 @@ into account when using Exprtk:
(27) The following is a list of reserved words and symbols used by (27) The following is a list of reserved words and symbols used by
ExprTk. Attempting to add a variable or custom function to a ExprTk. Attempting to add a variable or custom function to a
symbol table using any of the reserved words will result in symbol table using any of the reserved words will result in a
a failure. failure.
abs, acos, acosh, and, asin, asinh, atan, atan2, atanh, avg, abs, acos, acosh, and, asin, asinh, atan, atan2, atanh, avg,
break, case, ceil, clamp, continue, cosh, cos, cot, csc, break, case, ceil, clamp, continue, cosh, cos, cot, csc,