C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html
This commit is contained in:
parent
334953ee4d
commit
71029f7f97
58
exprtk.hpp
58
exprtk.hpp
|
@ -8344,6 +8344,23 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
typedef range_pack<T> range_pack_t;
|
||||||
|
|
||||||
|
struct range_type
|
||||||
|
{
|
||||||
|
range_type()
|
||||||
|
: range(0),
|
||||||
|
data (0),
|
||||||
|
size (0),
|
||||||
|
type_size(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
range_pack_t* range;
|
||||||
|
void* data;
|
||||||
|
std::size_t size;
|
||||||
|
std::size_t type_size;
|
||||||
|
};
|
||||||
|
|
||||||
typedef type_store<T> type_store_t;
|
typedef type_store<T> type_store_t;
|
||||||
typedef expression_node<T>* expression_ptr;
|
typedef expression_node<T>* expression_ptr;
|
||||||
typedef variable_node<T> variable_node_t;
|
typedef variable_node<T> variable_node_t;
|
||||||
|
@ -8353,13 +8370,11 @@ namespace exprtk
|
||||||
typedef vector_elem_node_t* vector_elem_node_ptr_t;
|
typedef vector_elem_node_t* vector_elem_node_ptr_t;
|
||||||
typedef vector_node_t* vector_node_ptr_t;
|
typedef vector_node_t* vector_node_ptr_t;
|
||||||
typedef range_interface<T> range_interface_t;
|
typedef range_interface<T> range_interface_t;
|
||||||
typedef range_pack<T> range_pack_t;
|
|
||||||
typedef std::pair<expression_ptr,bool> branch_t;
|
typedef std::pair<expression_ptr,bool> branch_t;
|
||||||
typedef std::pair<void*,std::size_t> void_t;
|
typedef std::pair<void*,std::size_t> void_t;
|
||||||
typedef std::pair<range_pack_t*,void_t> range_t;
|
|
||||||
typedef std::vector<T> tmp_vs_t;
|
typedef std::vector<T> tmp_vs_t;
|
||||||
typedef std::vector<type_store_t> typestore_list_t;
|
typedef std::vector<type_store_t> typestore_list_t;
|
||||||
typedef std::vector<range_t> range_list_t;
|
typedef std::vector<range_type> range_list_t;
|
||||||
|
|
||||||
generic_function_node(GenericFunction* func,
|
generic_function_node(GenericFunction* func,
|
||||||
const std::vector<expression_ptr>& arg_list)
|
const std::vector<expression_ptr>& arg_list)
|
||||||
|
@ -8383,8 +8398,7 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
expr_as_vec1_store_.resize(arg_list_.size(),T(0));
|
expr_as_vec1_store_.resize(arg_list_.size(),T(0));
|
||||||
|
|
||||||
range_list_.resize(arg_list_.size(),
|
range_list_.resize(arg_list_.size(),range_type());
|
||||||
range_t((range_pack_t*)0,void_t((void*)0,0)));
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < arg_list_.size(); ++i)
|
for (std::size_t i = 0; i < arg_list_.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -8414,8 +8428,9 @@ namespace exprtk
|
||||||
ts.data = reinterpret_cast<void*>(const_cast<char*>(sbn->base()));
|
ts.data = reinterpret_cast<void*>(const_cast<char*>(sbn->base()));
|
||||||
ts.type = type_store_t::e_string;
|
ts.type = type_store_t::e_string;
|
||||||
|
|
||||||
range_list_[i].second.first = ts.data;
|
range_list_[i].data = ts.data;
|
||||||
range_list_[i].second.second = sizeof(char);
|
range_list_[i].size = ts.size;
|
||||||
|
range_list_[i].type_size = sizeof(char);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
is_string_range_node (arg_list_[i]) ||
|
is_string_range_node (arg_list_[i]) ||
|
||||||
|
@ -8433,10 +8448,10 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
ts.size = rp.n1_c.second - rp.n0_c.second + 1;
|
ts.size = rp.n1_c.second - rp.n0_c.second + 1;
|
||||||
ts.data = static_cast<char*>(ts.data) + rp.n0_c.second;
|
ts.data = static_cast<char*>(ts.data) + rp.n0_c.second;
|
||||||
range_list_[i].first = reinterpret_cast<range_pack_t*>(0);
|
range_list_[i].range = reinterpret_cast<range_pack_t*>(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
range_list_[i].first = &(ri->range_ref());
|
range_list_[i].range = &(ri->range_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_variable_node(arg_list_[i]))
|
else if (is_variable_node(arg_list_[i]))
|
||||||
|
@ -8484,10 +8499,12 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
if (function_)
|
if (function_)
|
||||||
{
|
{
|
||||||
populate_value_list();
|
if (populate_value_list())
|
||||||
|
{
|
||||||
return (*function_)(fwd_typestore_list_);
|
return (*function_)(fwd_typestore_list_);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
return std::numeric_limits<T>::quiet_NaN();
|
return std::numeric_limits<T>::quiet_NaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8498,22 +8515,31 @@ namespace exprtk
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
inline void populate_value_list() const
|
inline bool populate_value_list() const
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < branch_.size(); ++i)
|
for (std::size_t i = 0; i < branch_.size(); ++i)
|
||||||
{
|
{
|
||||||
expr_as_vec1_store_[i] = branch_[i].first->value();
|
expr_as_vec1_store_[i] = branch_[i].first->value();
|
||||||
|
|
||||||
if (range_list_[i].first)
|
if (range_list_[i].range)
|
||||||
{
|
{
|
||||||
range_pack_t& rp = (*range_list_[i].first);
|
range_pack_t& rp = (*range_list_[i].range);
|
||||||
|
std::size_t r0 = 0;
|
||||||
|
std::size_t r1 = 0;
|
||||||
|
|
||||||
|
if (rp(r0,r1,range_list_[i].size))
|
||||||
|
{
|
||||||
typestore_list_[i].size = (rp.cache.second - rp.cache.first) + 1;
|
typestore_list_[i].size = (rp.cache.second - rp.cache.first) + 1;
|
||||||
typestore_list_[i].data = static_cast<char*>(range_list_[i].second.first) + (rp.cache.first * range_list_[i].second.second);
|
typestore_list_[i].data = static_cast<char*>(range_list_[i].data) + (rp.cache.first * range_list_[i].type_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fwd_typestore_list_ = typestore_list_;
|
fwd_typestore_list_ = typestore_list_;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericFunction* function_;
|
GenericFunction* function_;
|
||||||
|
@ -12018,6 +12044,7 @@ namespace exprtk
|
||||||
|
|
||||||
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 overriden.\n"));
|
||||||
return std::numeric_limits<T>::quiet_NaN();
|
return std::numeric_limits<T>::quiet_NaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12044,6 +12071,7 @@ namespace exprtk
|
||||||
|
|
||||||
inline virtual T operator()(parameter_list_t&)
|
inline virtual T operator()(parameter_list_t&)
|
||||||
{
|
{
|
||||||
|
exprtk_debug(("igeneric_function::operator() - Operator has not been overriden.\n"));
|
||||||
return std::numeric_limits<T>::quiet_NaN();
|
return std::numeric_limits<T>::quiet_NaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
170
readme.txt
170
readme.txt
|
@ -2,10 +2,10 @@ C++ Mathematical Expression Toolkit Library
|
||||||
|
|
||||||
[00 - 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 run-time
|
||||||
expression parsing and evaluation engine. The parsing engine supports
|
mathematical expression parsing and evaluation engine. The parsing
|
||||||
numerous forms of functional and logic processing semantics and is
|
engine supports numerous forms of functional and logic processing
|
||||||
easily extendible.
|
semantics and is easily extendible.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ arithmetic operations, functions and processes:
|
||||||
|
|
||||||
(01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp,
|
(01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp,
|
||||||
expm1, floor, frac, log, log10, log1p, log2,
|
expm1, floor, frac, log, log10, log1p, log2,
|
||||||
logn, max, min, mul, ncdf, nequal, root, round,
|
logn, max, min, mul, ncdf, nequal, root,
|
||||||
roundn, sgn, sqrt, sum, swap, trunc
|
round, roundn, sgn, sqrt, sum, swap, trunc
|
||||||
|
|
||||||
(02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2,
|
(02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2,
|
||||||
cos, cosh, cot, csc, sec, sin, sinc, sinh,
|
cos, cosh, cot, csc, sec, sin, sinc, sinh,
|
||||||
|
@ -899,7 +899,7 @@ zero. The following are examples of vector definitions:
|
||||||
(c) Initialise all values to given expression
|
(c) Initialise all values to given expression
|
||||||
var x[3] := [123 + 3y + sin(w/z)];
|
var x[3] := [123 + 3y + sin(w/z)];
|
||||||
|
|
||||||
(d) Initialise the first two values, other elements to zero
|
(d) Initialise the first two values, all other elements to zero
|
||||||
var x[3] := { 1 + x[2], sin(y[0] / x[]) + 3 };
|
var x[3] := { 1 + x[2], sin(y[0] / x[]) + 3 };
|
||||||
|
|
||||||
(e) Initialise the first three (all) values
|
(e) Initialise the first three (all) values
|
||||||
|
@ -1019,7 +1019,8 @@ ExprTk provides a means whereby custom functions can be defined and
|
||||||
utilized within expressions. The concept requires the user to
|
utilized within expressions. The concept requires the user to
|
||||||
provide a reference to the function coupled with an associated name
|
provide a reference to the function coupled with an associated name
|
||||||
that will be invoked within expressions. Function can take in numerous
|
that will be invoked within expressions. Function can take in numerous
|
||||||
inputs but will always return one value.
|
inputs but will always return a single value of the underlying numeric
|
||||||
|
type.
|
||||||
|
|
||||||
During expression compilation when required the reference to the
|
During expression compilation when required the reference to the
|
||||||
function will be obtained from the associated symbol_table and be
|
function will be obtained from the associated symbol_table and be
|
||||||
|
@ -1089,7 +1090,9 @@ parameters and their views are as follows:
|
||||||
(2) vector - vector_view
|
(2) vector - vector_view
|
||||||
(3) string - string_view
|
(3) string - string_view
|
||||||
|
|
||||||
The following example defines a generic function called 'too':
|
The above denoted type views provide non-const reference-like access
|
||||||
|
to each parameter. The following example defines a generic function
|
||||||
|
called 'too':
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct too : public exprtk::igeneric_function<T>
|
struct too : public exprtk::igeneric_function<T>
|
||||||
|
@ -1104,27 +1107,136 @@ The following example defines a generic function called 'too':
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < parameters.size(); ++i)
|
for (std::size_t i = 0; i < parameters.size(); ++i)
|
||||||
{
|
{
|
||||||
|
...
|
||||||
}
|
}
|
||||||
return T(0);
|
return T(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
In the above example, the parameter_list_t type is a type of
|
In the above example, the input 'parameters' to the function operator,
|
||||||
std::vector of type_store. Each type_store instance has a member
|
parameter_list_t, is a type of std::vector of type_store. Each
|
||||||
called 'type' which holds the enumeration pertaining the underlying
|
type_store instance has a member called 'type' which holds the
|
||||||
type of the type_store. There are three type enumerations:
|
enumeration pertaining the underlying type of the type_store. There
|
||||||
|
are three type enumerations:
|
||||||
|
|
||||||
(1) e_scalar - variables, vector elements, general expressions
|
(1) e_scalar - literals, variables, vector elements, expressions
|
||||||
eg: x, y, z, vec[3x + 1], 2x + 3
|
eg: 123.456, x, vec[3x + 1], 2x + 3
|
||||||
|
|
||||||
(2) e_vector - vectors, vector expressions
|
(2) e_vector - vectors, vector expressions
|
||||||
eg: vec1, 2 * vec1 + vec2 / 3
|
eg: vec1, 2 * vec1 + vec2 / 3
|
||||||
|
|
||||||
(3) e_string - string, string literal and range variants of both
|
(3) e_string - strings, string literals and range variants of both
|
||||||
eg: 'AString', s0, 'AString'[x:y], s1[1 + x:]
|
eg: 'AString', s0, 'AString'[x:y], s1[1 + x:]
|
||||||
|
|
||||||
|
|
||||||
|
Each of the parameters can be accessed using its designated view. A
|
||||||
|
typical loop for processing the parameters is as follows:
|
||||||
|
|
||||||
|
inline T operator()(parameter_list_t& parameters)
|
||||||
|
{
|
||||||
|
typedef typename exprtk::igeneric_function<T>::generic_type
|
||||||
|
generic_type;
|
||||||
|
|
||||||
|
typedef typename generic_type::scalar_view scalar_t;
|
||||||
|
typedef typename generic_type::vector_view vector_t;
|
||||||
|
typedef typename generic_type::string_view string_t;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < parameters.size(); ++i)
|
||||||
|
{
|
||||||
|
generic_type& gt = parameters[i];
|
||||||
|
|
||||||
|
if (generic_type::e_scalar == gt.type)
|
||||||
|
{
|
||||||
|
scalar_t x(gt);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
else if (generic_type::e_vector == gt.type)
|
||||||
|
{
|
||||||
|
vector_t vector(gt);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
else if (generic_type::e_string == gt.type)
|
||||||
|
{
|
||||||
|
string_t string(gt);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return T(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Most often than not a custom generic function will require a specific
|
||||||
|
sequence of parameters, rather than some arbitrary sequence of types.
|
||||||
|
In those situations, ExprTk can perform compile-time type checking to
|
||||||
|
validate that function invocations are carried out using the correct
|
||||||
|
sequence of parameters. Furthermore performing the checks at compile
|
||||||
|
-time rather than at run-time (aka every time the function is invoked)
|
||||||
|
will result expression evaluation performance gains.
|
||||||
|
|
||||||
|
Compile-time type checking can be requested by passing a string
|
||||||
|
representing the desired parameter sequence to the constructor of the
|
||||||
|
igeneric_function. The following example demonstrates how this can be
|
||||||
|
done:
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct too : public exprtk::igeneric_function<T>
|
||||||
|
{
|
||||||
|
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||||
|
parameter_list_t;
|
||||||
|
|
||||||
|
too()
|
||||||
|
: exprtk::igeneric_function<T>("SVTT")
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline T operator()(parameter_list_t& parameters)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
In the example above the custom generic function 'too' expects
|
||||||
|
exactly four parameters in the following sequence:
|
||||||
|
|
||||||
|
(a) String
|
||||||
|
(b) Vector
|
||||||
|
(c) Scalar
|
||||||
|
(d) Scalar
|
||||||
|
|
||||||
|
|
||||||
|
One further refinement to the type checking facility is possibility of
|
||||||
|
a variable number of trailing common types which can be accomplished
|
||||||
|
by using a wildcard '*' at the end of the sequence definition.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct too : public exprtk::igeneric_function<T>
|
||||||
|
{
|
||||||
|
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||||
|
parameter_list_t;
|
||||||
|
|
||||||
|
too()
|
||||||
|
: exprtk::igeneric_function<T>("SVTTV*")
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline T operator()(parameter_list_t& parameters)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
In the example above the generic function 'too' expects at least five
|
||||||
|
parameters in the following sequence:
|
||||||
|
|
||||||
|
(a) String
|
||||||
|
(b) Vector
|
||||||
|
(c) Scalar
|
||||||
|
(d) Scalar
|
||||||
|
(e) One or more vectors
|
||||||
|
|
||||||
|
|
||||||
(4) function_compositor
|
(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
|
||||||
|
@ -1173,10 +1285,14 @@ The following demonstrates how all the pieces are put together:
|
||||||
|
|
||||||
foo<double> f;
|
foo<double> f;
|
||||||
boo<double> b;
|
boo<double> b;
|
||||||
|
too<double> t;
|
||||||
|
|
||||||
symbol_table_t symbol_table;
|
symbol_table_t symbol_table;
|
||||||
|
compositor_t compositor(symbol_table);
|
||||||
|
|
||||||
symbol_table.add_function("foo",f);
|
symbol_table.add_function("foo",f);
|
||||||
symbol_table.add_function("boo",b);
|
symbol_table.add_function("boo",b);
|
||||||
|
symbol_table.add_function("too",t);
|
||||||
|
|
||||||
compositor
|
compositor
|
||||||
.add(function_t()
|
.add(function_t()
|
||||||
|
@ -1189,7 +1305,11 @@ The following demonstrates how all the pieces are put together:
|
||||||
expression.register_symbol_table(symbol_table);
|
expression.register_symbol_table(symbol_table);
|
||||||
|
|
||||||
std::string expression_str =
|
std::string expression_str =
|
||||||
"foo(1,2,3) + boo(1) / boo(1/2,2/3,3/4,4/5) + koo(3,4)";
|
" if (foo(1,2,3) + boo(1) > boo(1/2,2/3,3/4,4/5)) "
|
||||||
|
" koo(3,4); "
|
||||||
|
" else "
|
||||||
|
" too(2 * v1 + v2 / 3, 'abcdef'[2:4], 3.3); "
|
||||||
|
" ";
|
||||||
|
|
||||||
parser_t parser;
|
parser_t parser;
|
||||||
parser.compile(expression_str,expression);
|
parser.compile(expression_str,expression);
|
||||||
|
@ -1357,11 +1477,11 @@ into account when using Exprtk:
|
||||||
exist within the set of Real numbers. All other results will be
|
exist within the set of Real numbers. All other results will be
|
||||||
of the value: Not-A-Number (NaN).
|
of the value: Not-A-Number (NaN).
|
||||||
|
|
||||||
(05) Supported user defined types are numeric and string variables
|
(05) Supported user defined types are numeric and string
|
||||||
and functions.
|
variables, numeric vectors and functions.
|
||||||
|
|
||||||
(06) All reserved and key words, variable, vector and function names
|
(06) All reserved words and keywords, variable, vector and function
|
||||||
are case-insensitive.
|
names are case-insensitive.
|
||||||
|
|
||||||
(07) Variable, vector and function names must begin with a letter
|
(07) Variable, vector and function names must begin with a letter
|
||||||
(A-Z or a-z), then can be comprised of any combination of
|
(A-Z or a-z), then can be comprised of any combination of
|
||||||
|
@ -1376,7 +1496,7 @@ into account when using Exprtk:
|
||||||
of that symbol-table, otherwise the result will be undefined
|
of that symbol-table, otherwise the result will be undefined
|
||||||
behavior.
|
behavior.
|
||||||
|
|
||||||
(10) Equal/Nequal are normalized equality routines, which use
|
(10) Equal and Nequal are normalized equality routines, which use
|
||||||
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.
|
||||||
|
|
||||||
|
@ -1398,8 +1518,8 @@ into account when using Exprtk:
|
||||||
|
|
||||||
(15) The inbuilt polynomial functions can be at most of degree 12.
|
(15) The inbuilt polynomial functions can be at most of degree 12.
|
||||||
|
|
||||||
(16) Where appropriate constant folding optimisations may be
|
(16) Where appropriate constant folding optimisations may be applied.
|
||||||
applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)')
|
(eg: The expression '2 + (3 - (x / y))' becomes '5 - (x / y)')
|
||||||
|
|
||||||
(17) If the strength reduction compilation option has been enabled,
|
(17) If the strength reduction compilation option has been enabled,
|
||||||
then where applicable strength reduction optimisations may be
|
then where applicable strength reduction optimisations may be
|
||||||
|
@ -1435,12 +1555,14 @@ into account when using Exprtk:
|
||||||
|
|
||||||
(24) The following are examples of compliant floating point value
|
(24) The following are examples of compliant floating point value
|
||||||
representations:
|
representations:
|
||||||
|
|
||||||
(a) 12345 (e) -123.456
|
(a) 12345 (e) -123.456
|
||||||
(b) +123.456e+12 (f) 123.456E-12
|
(b) +123.456e+12 (f) 123.456E-12
|
||||||
(c) +012.045e+07 (g) .1234
|
(c) +012.045e+07 (g) .1234
|
||||||
(d) 123.456f (h) -321.654E+3L
|
(d) 123.456f (h) -321.654E+3L
|
||||||
|
|
||||||
(25) Expressions may contain any of the following comment styles:
|
(25) Expressions may contain any of the following comment styles:
|
||||||
|
|
||||||
1. // .... \n
|
1. // .... \n
|
||||||
2. # .... \n
|
2. # .... \n
|
||||||
3. /* .... */
|
3. /* .... */
|
||||||
|
|
Loading…
Reference in New Issue