cexprtk
is a cython wrapper around the "ExprTK: C++ Mathematical Expression Toolkit Library " by Arash Partow. Using cexprtk
a powerful mathematical expression engine can be incorporated into your python project.
- Installation
- Usage
- API Reference
- Authors
- License
The latest version of cexprtk
can be installed using pip :
$ pip install cexprtk
Note: Installation requires a compatible C++ compiler to be installed (unless installing from a binary wheel).
The following examples show the major features of cexprtk
.
The following shows how the arithmetic expression (5+5) * 23
can be evaluated:
>>> import cexprtk
>>> cexprtk.evaluate_expression("(5+5) * 23", {})
230.0
Variables can be used within expressions by passing a dictionary to the evaluate_expression
function. This maps variable names to their values. The expression from the previous example can be re-calculated using variable values:
>>> import cexprtk
>>> cexprtk.evaluate_expression("(A+B) * C", {"A" : 5, "B" : 5, "C" : 23})
230.0
When using the evaluate_expression()
function, the mathematical expression is parsed, evaluated and then immediately thrown away. This example shows how to re-use an Expression
for multiple evaluations.
- An expression will be defined to calculate the circumference of circle, this will then be re-used to calculate the value for several different radii.
- First a
Symbol_Table
is created containing a variabler
(for radius), it is also populated with some useful constants such as π.
>>> import cexprtk
>>> st = cexprtk.Symbol_Table({'r' : 1.0}, add_constants= True)
- Now an instance of
Expression
is created, defining our function:
>>> circumference = cexprtk.Expression('2*pi*r', st)
- The
Symbol_Table
was initialised withr=1
, the expression can be evaluated for this radius simply by calling it:
>>> circumference()
6.283185307179586
- Now update the radius to a value of 3.0 using the dictionary like object returned by the
Symbol_Table
's.variables
property:
>>> st.variables['r'] = 3.0
>>> circumference()
18.84955592153876
Python functions can be registered with a Symbol_Table
then used in an Expression
. In this example a custom function will be defined which produces a random number within a given range.
A suitable function exists in the random
module, namely random.uniform
. As this is an instance method it needs to be wrapped in function:
>>> import random
>>> def rnd(low, high):
... return random.uniform(low,high)
...
Our rnd
function now needs to be registered with a Symbol_Table
:
>>> import cexprtk
>>> st = cexprtk.Symbol_Table({})
>>> st.functions["rand"] = rnd
The functions
property of the Symbol_Table
is accessed like a dictionary. In the preceding code snippet, a symbol table is created and then the rnd
function is assigned to the rand
key. This key is used as the function's name in a cexprtk
expression. The key cannot be the same as an existing variable, constant or reserved function name.
The rand
function will now be used in an expression. This expression chooses a random number between 5 and 8 and then multiplies it by 10. The followin snippet shows the instantiation of the Expression
which is then evaluated a few times. You will probably get different numbers out of your expression than shown, this is because your random number generator will have been initialised with a different seed than used in the example.
>>> e = cexprtk.Expression("rand(5,8) * 10", st)
>>> e()
61.4668441077191
>>> e()
77.13523163246415
>>> e()
59.14881842716157
>>> e()
69.1476535568958
A callback can be passed to the Expression
constructor through the unknown_symbol_resolver_callback
parameter. This callback is invoked during expression parsing when a variable or constant is encountered that isn't in the Symbol_Table
associated with the Expression
.
The callback can be used to provide some logic that leads to a new symbol being registered or for an error condition to be flagged.
The Problem: The following example shows a potential use for the symbol resolver:
- An expression contains variables of the form
m_VARIABLENAME
andf_VARIABLENAME
. m_
orf_
prefix the actual variable name (perhaps indicating gender).VARIABLENAME
should be used to look up the desired value in a dictionary.- The dictionary value of
VARIABLENAME
should then be weighted according to its prefix:m_
variables should be multiplied by 0.8.f_
variables should be multiplied by 1.1.
The Solution:
-
First the
VARIABLENAME
dictionary is defined:variable_values = { 'county_a' : 82, 'county_b' : 76}
-
Now the callback is defined. This takes a single argument, symbol, which gives the name of the missing variable found in the expression:
def callback(symbol): # Tokenize the symbol name into prefix and VARIABLENAME components. prefix,variablename = symbol.split("_", 1) # Get the value for this VARIABLENAME from the variable_values dict value = variable_values[variablename] # Find the correct weight for the prefix if prefix == 'm': weight = 0.8 elif prefix == 'f': weight = 1.1 else: # Flag an error condition if prefix not found. errormsg = "Unknown prefix "+ str(prefix) return (False, cexprtk.USRSymbolType.VARIABLE, 0.0, errormsg) # Apply the weight to the value *= weight # Indicate success and return value to cexprtk return (True, cexprtk.USRSymbolType.VARIABLE, value, "")
-
All that remains is to register the callback with an instance of
Expression
and to evaluate an expression. The expression to be evaluated is:(m_county_a - f_county_b)
- This should give a value of
(0.8*82) - (1.1*76) = -18
>>> st = cexprtk.Symbol_Table({}) >>> e = cexprtk.Expression("(m_county_a - f_county_b)", st, callback) >>> e.value() -18.0
Exprtk expressions can return multiple values the results these expressions can be accessed through the results()
method.
The following example shows the result of adding a constant value to a vector containing numbers:
>>> st = cexprtk.Symbol_Table({})
>>> e = cexprtk.Expression("var v[3] := {1,2,3}; return [v+1];", st)
>>> e.value()
nan
>>> e.results()
[[2.0, 3.0, 4.0]]
Note that expression has to be evaluated before calling the results()
method.
The value accessed through results()
can contain a mixture of strings, vectors and real values:
>>> st = cexprtk.Symbol_Table({'c' : 3})
>>> e = cexprtk.Expression("if(c>1){return ['bigger than one', c];} else { return ['not bigger than one',c];};",st)
>>> e.value()
nan
>>> e.results()
['bigger than one', 3.0]
>>> st.variables['c']=0.5
>>> e.value()
nan
>>> e.results()
['not bigger than one', 0.5]
For information about expressions supported by cexprtk
please refer to the original C++ ExprTK documentation:
Class representing mathematical expression.
- Following instantiation, the expression is evaluated calling the expression or invoking its
value()
method. - The variable values used by the Expression can be modified through the
variables
property of theSymbol_Table
instance associated with the expression. TheSymbol_Table
can be accessed using theExpression.symbol_table
property.
The unknown_symbol_resolver_callback
argument to the Expression
constructor accepts a callable which is invoked whenever a symbol (i.e. a
variable or a constant), is not found in the Symbol_Table
given by the
symbol_table
argument. The unknown_symbol_resolver_callback
can be
used to provide a value for the missing value or to set an error condition.
The callable should have following signature:
def callback(symbol_name):
...
Where symbol_name
is a string identifying the missing symbol.
The callable should return a tuple of the form:
(HANDLED_FLAG, USR_SYMBOL_TYPE, SYMBOL_VALUE, ERROR_STRING)
Where:
HANDLED_FLAG
is a boolean:True
indicates that callback was able handle the error condition and thatSYMBOL_VALUE
should be used for the missing symbol.False
, flags and error condition, the reason why the unknown symbol could not be resolved by the callback is described byERROR_STRING
.
USR_SYMBOL_TYPE
gives type of symbol (constant or variable) that should be added to thesymbol_table
when unkown symbol is resolved. Value should be one of those given incexprtk.USRSymbolType
. e.g.cexprtk.USRSymbolType.VARIABLE
cexprtk.USRSymbolType.CONSTANT
SYMBOL_VALUE
, floating point value that should be used when resolving missing symbol.ERROR_STRING
whenHANDLED_FLAG
isFalse
this can be used to describe error condition.
Instantiate Expression
from a text string giving formula and Symbol_Table
instance encapsulating variables and constants used by the expression.
Parameters:
- expression (str) String giving expression to be calculated.
- symbol_table (Symbol_Table) Object defining variables and constants.
- unknown_symbol_resolver_callback (callable) See description above.
If an expression contains a return []
statement, the returned values are accessed using this method.
A python list is returned which may contain real values, strings or vectors.
Note: the expression should be evaluated by calling value()
before trying to access results.
Returns:
- (list) List of values produced by expression's
return
statement.
Evaluate expression using variable values currently set within associated Symbol_Table
Returns:
- (float) Value resulting from evaluation of expression.
Equivalent to calling value()
method.
Returns:
- (float) Value resulting from evaluation of expression.
Read only property that returns Symbol_Table
instance associated with this expression.
Returns:
- (Symbol_Table)
Symbol_Table
associated with thisExpression
.
Class for providing variable and constant values to Expression
instances.
def init(self, variables, constants = {}, add_constants = False, functions = {}, string_variables = {}):
Instantiate Symbol_Table
defining variables and constants for use with Expression
class.
Example:
-
To instantiate a
Symbol_Table
with:x = 1
y = 5
- define a constant
k = 1.3806488e-23
-
The following code would be used:
st = cexprtk.Symbol_Table({'x' : 1, 'y' : 5}, {'k'= 1.3806488e-23})
Parameters:
- variables (dict) Mapping between variable name and initial variable value.
- constants (dict) Dictionary containing values that should be added to
Symbol_Table
as constants. These can be used a variables within expressions but their values cannot be updated followingSymbol_Table
instantiation. - add_constants (bool) If
True
, add the standard constantspi
,inf
,epsilon
to the 'constants' dictionary before populating theSymbol_Table
- functions (dict) Dictionary containing custom functions to be made available to expressions. Dictionary keys specify function names and values should be functions.
- string_variables (dict) Mapping between variable name and initial variable value for string variables.
Returns dictionary like object containing variable values. Symbol_Table
values can be updated through this object.
Example:
>>> import cexprtk
>>> st = cexprtk.Symbol_Table({'x' : 5, 'y' : 5})
>>> expression = cexprtk.Expression('x+y', st)
>>> expression()
10.0
Update the value of x
in the symbol table and re-evaluate the expression:
>>> expression.symbol_table.variables['x'] = 11.0
>>> expression()
16.0
Returns:
- Dictionary like giving variables stored in this
Symbol_Table
. Keys are variables names and these map to variable values.
Property giving constants stored in this Symbol_Table
.
Returns:
- Read-only dictionary like object mapping constant names stored in
Symbol_Table
to their values.
Returns dictionary like object containing custom python functions to use in expressions.
Returns:
- Dictionary like giving function stored in this
Symbol_Table
. Keys are function names (as used inExpression
) and these map to python callable objects including functions, functors, andfunctools.partial
.
Returns dictionary like object containing string variable values. Symbol_Table
values can be updated through this object.
Example:
>>> import cexprtk
>>> st = cexprtk.Symbol_Table({})
>>> st.string_variables['s1'] = 'he'
>>> st.string_variables['s2'] = 'l'
>>> st.string_variables['s3'] = 'lo'
>>> expression = cexprtk.Expression("return[s1+s2+s3+' world']", st)
>>> expression.value()
nan
>>> expression.results()
['hello world']
Returns:
- Dictionary like giving the string variables stored in this
Symbol_Table
. Keys are variables names and these map to string values.
Defines constant values used to determine symbol type returned by unknown_symbol_resolver_callback
(see Expression
constructor documentation for more).
Value that should be returned by an unknown_symbol_resolver_callback
to define a variable.
Value that should be returned by an unknown_symbol_resolver_callback
to define a constant.
Check that expression can be parsed. If successful do nothing, if unsuccessful raise ParseException
.
Parameters:
- expression (str) Formula to be evaluated
Raises:
ParseException
: If expression is invalid.
Evaluate a mathematical formula using the exprtk library and return result.
For more information about supported functions and syntax see the exprtk C++ library website.
Parameters:
- expression (str) Expression to be evaluated.
- variables (dict) Dictionary containing variable name, variable value pairs to be used in expression.
Returns:
- (float): Evaluated expression
Raises:
ParseException
: if expression is invalid.
Cython wrapper by Michael Rushton ([email protected]), although most credit should go to Arash Partow for creating the underlying ExprTK library.
Thanks to:
- jciskey for adding the
Expression.results()
support. - Caleb Hattingh for getting cexprtk to build using MSVC on Windows.
cexprtk
is released under the same terms as the ExprTK library the Common Public License Version 1.0 (CPL).