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

This commit is contained in:
Arash Partow 2014-12-02 04:48:39 +11:00
parent 334953ee4d
commit 71029f7f97
2 changed files with 204 additions and 54 deletions

View File

@ -8344,6 +8344,23 @@ namespace exprtk
{
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 expression_node<T>* expression_ptr;
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_node_t* vector_node_ptr_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<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<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,
const std::vector<expression_ptr>& arg_list)
@ -8383,8 +8398,7 @@ namespace exprtk
{
expr_as_vec1_store_.resize(arg_list_.size(),T(0));
range_list_.resize(arg_list_.size(),
range_t((range_pack_t*)0,void_t((void*)0,0)));
range_list_.resize(arg_list_.size(),range_type());
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.type = type_store_t::e_string;
range_list_[i].second.first = ts.data;
range_list_[i].second.second = sizeof(char);
range_list_[i].data = ts.data;
range_list_[i].size = ts.size;
range_list_[i].type_size = sizeof(char);
if (
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.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
range_list_[i].first = &(ri->range_ref());
range_list_[i].range = &(ri->range_ref());
}
}
else if (is_variable_node(arg_list_[i]))
@ -8484,11 +8499,13 @@ namespace exprtk
{
if (function_)
{
populate_value_list();
return (*function_)(fwd_typestore_list_);
if (populate_value_list())
{
return (*function_)(fwd_typestore_list_);
}
}
else
return std::numeric_limits<T>::quiet_NaN();
return std::numeric_limits<T>::quiet_NaN();
}
inline typename expression_node<T>::node_type type() const
@ -8498,22 +8515,31 @@ namespace exprtk
private:
inline void populate_value_list() const
inline bool populate_value_list() const
{
for (std::size_t i = 0; i < branch_.size(); ++i)
{
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;
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);
if (rp(r0,r1,range_list_[i].size))
{
typestore_list_[i].size = (rp.cache.second - rp.cache.first) + 1;
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_;
return true;
}
GenericFunction* function_;
@ -12018,6 +12044,7 @@ namespace exprtk
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();
}
@ -12044,6 +12071,7 @@ namespace exprtk
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();
}

View File

@ -2,10 +2,10 @@ C++ Mathematical Expression Toolkit Library
[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
numerous forms of functional and logic processing semantics and is
easily extendible.
to use, easy to integrate and extremely efficient run-time
mathematical expression parsing and evaluation engine. The parsing
engine supports numerous forms of functional and logic processing
semantics and is easily extendible.
@ -15,14 +15,14 @@ arithmetic operations, functions and processes:
(00) Basic operators: +, -, *, /, %, ^
(01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp,
expm1, floor, frac, log, log10, log1p, log2,
logn, max, min, mul, ncdf, nequal, root, round,
roundn, sgn, sqrt, sum, swap, trunc
(01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp,
expm1, floor, frac, log, log10, log1p, log2,
logn, max, min, mul, ncdf, nequal, root,
round, roundn, sgn, sqrt, sum, swap, trunc
(02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2,
cos, cosh, cot, csc, sec, sin, sinc, sinh,
tan, tanh, hypot, rad2deg, deg2grad, deg2rad,
(02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2,
cos, cosh, cot, csc, sec, sin, sinc, sinh,
tan, tanh, hypot, rad2deg, deg2grad, deg2rad,
grad2deg
(03) Equalities &
@ -899,7 +899,7 @@ zero. The following are examples of vector definitions:
(c) Initialise all values to given expression
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 };
(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
provide a reference to the function coupled with an associated name
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
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
(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>
struct too : public exprtk::igeneric_function<T>
@ -1104,25 +1107,134 @@ The following example defines a generic function called 'too':
{
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:
In the above example, the input 'parameters' to the function operator,
parameter_list_t, 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
(1) e_scalar - literals, variables, vector elements, expressions
eg: 123.456, x, 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:]
(3) e_string - strings, string literals and range variants of both
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
@ -1173,10 +1285,14 @@ The following demonstrates how all the pieces are put together:
foo<double> f;
boo<double> b;
too<double> t;
symbol_table_t symbol_table;
compositor_t compositor(symbol_table);
symbol_table.add_function("foo",f);
symbol_table.add_function("boo",b);
symbol_table.add_function("too",t);
compositor
.add(function_t()
@ -1189,7 +1305,11 @@ The following demonstrates how all the pieces are put together:
expression.register_symbol_table(symbol_table);
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.compile(expression_str,expression);
@ -1357,14 +1477,14 @@ into account when using Exprtk:
exist within the set of Real numbers. All other results will be
of the value: Not-A-Number (NaN).
(05) Supported user defined types are numeric and string variables
and functions.
(05) Supported user defined types are numeric and string
variables, numeric vectors and functions.
(06) All reserved and key words, variable, vector and function names
are case-insensitive.
(06) All reserved words and keywords, variable, vector and function
names are case-insensitive.
(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
letters, digits and underscores. (eg: x, var1 or power_func99)
(08) Expression lengths and sub-expression lists are limited only by
@ -1376,8 +1496,8 @@ into account when using Exprtk:
of that symbol-table, otherwise the result will be undefined
behavior.
(10) Equal/Nequal are normalized equality routines, which use
epsilons of 0.0000000001 and 0.000001 for double and float
(10) Equal and Nequal are normalized equality routines, which use
epsilons of 0.0000000001 and 0.000001 for double and float
types respectively.
(11) All trigonometric functions assume radian input unless stated
@ -1398,8 +1518,8 @@ into account when using Exprtk:
(15) The inbuilt polynomial functions can be at most of degree 12.
(16) Where appropriate constant folding optimisations may be
applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)')
(16) Where appropriate constant folding optimisations may be applied.
(eg: The expression '2 + (3 - (x / y))' becomes '5 - (x / y)')
(17) If the strength reduction compilation option has been enabled,
then where applicable strength reduction optimisations may be
@ -1422,25 +1542,27 @@ into account when using Exprtk:
of the ifunction allowing it to be constant folded where
appropriate.
(22) The entity relationship between symbol_table and an expression
is one-to-many. Hence the intended use case where possible is
to have a single symbol table manage the variable and function
(22) The entity relationship between symbol_table and an expression
is one-to-many. Hence the intended use case where possible is
to have a single symbol table manage the variable and function
requirements of multiple expressions.
(23) The common use-case for an expression is to have it compiled
only ONCE and then subsequently have it evaluated multiple
only ONCE and then subsequently have it evaluated multiple
times. An extremely inefficient and suboptimal approach would
be to recompile an expression from its string form every time
it requires evaluating.
(24) The following are examples of compliant floating point value
representations:
(a) 12345 (e) -123.456
(b) +123.456e+12 (f) 123.456E-12
(c) +012.045e+07 (g) .1234
(d) 123.456f (h) -321.654E+3L
(25) Expressions may contain any of the following comment styles:
1. // .... \n
2. # .... \n
3. /* .... */