Make a string with a mathematical expression behave as a Python function.
Representation of a string formula as a function of one or more variables, optionally with parameters.
Example on usage:
>>> from scitools.StringFunction import StringFunction
>>> f = StringFunction('1+sin(2*x)')
>>> f(1.2)
1.6754631805511511
>>> f = StringFunction('1+sin(2*t)', independent_variable='t')
>>> f(1.2)
1.6754631805511511
>>> f = StringFunction('1+A*sin(w*t)', independent_variable='t', A=0.1, w=3.14159)
>>> f(1.2)
0.94122173238695939
>>> f.set_parameters(A=1, w=1)
>>> f(1.2)
1.9320390859672263
>>> f(1.2, A=2, w=1) # can also set parameters in the call
2.8640781719344526
>>> # function of two variables:
>>> f = StringFunction('1+sin(2*x)*cos(y)', independent_variables=('x','y'))
>>> f(1.2,-1.1)
1.3063874788637866
>>> f = StringFunction('1+V*sin(w*x)*exp(-b*t)', independent_variables=('x','t'))
>>> f.set_parameters(V=0.1, w=1, b=0.1)
>>> f(1.0,0.1)
1.0833098208613807
>>> str(f) # print formula with parameters substituted by values
'1+0.1*sin(1*x)*exp(-0.1*t)'
>>> repr(f)
"StringFunction('1+V*sin(w*x)*exp(-b*t)', independent_variables=('x', 't'), b=0.10000000000000001, w=1, V=0.10000000000000001)"
>>> # vector field of x and y:
>>> f = StringFunction('[a+b*x,y]', independent_variables=('x','y'))
>>> f.set_parameters(a=1, b=2)
>>> f(2,1) # [1+2*2, 1]
[5, 1]
StringFunction expressions may contain fractions like 1/2 and these always result in float division (not integer division). Here is an example:
>>> from scitools.StringFunction import StringFunction
>>> f = StringFunction('1/4 + 1/2*x')
>>> f(2)
1.25
The string parameter can, instead of a valid Python expression, be a function in a file (module). The string is then the complete path to the function, typically of the form somepackage.somemodule.function_name. This functionality is useful when simple string formulas cannot describe the function, e.g., when there are multiple if-branches inside the function expression.
As an example, there is a function called _test_function:
def _test_function(x, c=0, a=1, b=2):
if x > c:
return a*(x-c) + b
else:
return -a*(x-c) + b
in the module scitools.misc (i.e., the misc.py file in the scitools package). We can then specify the complete path of this function as “string expression”:
>>> f = StringFunction('scitools.misc._test_function', independent_variable='x', a=10)
>>> f(4) # 10*(4-0) + 2 = 42
42
(Note that in Python 2.5 the _test_function can be coded as a simple string expression a*(x-c)+b if x > c else -a*(x-c)+b.)
Giving the name of a function in a file (module) is convenient in user interfaces because the user can then write the name of the function as a standard Python module.function path. StringFunction turns this name, as a string, into a working module.function path.
Troubleshooting:
1) The StringFunction class can work with sin, cos, exp, and other mathematical functions if the argument is a scalar (float or int) type. If the argument is a vector, the NumPy versions of sin, cos, exp, etc., are needed. A common error message in the latter case is:
TypeError: only rank-0 arrays can be converted to Python scalars.
Make something like:
from numpy import *
# or
from scitools.std import *
# or
from numpy import sin, cos
in the calling code and supply globals=globals() as argument to the constructor:
f = StringFunction('1+x*y', independent_variables=('x', 'y'),
globals=globals())
# f(p,q) will now work for NumPy arrays p and q.
You can also omit the globals argument when constructing the StringFunction and later call f.vectorize(globals()) to allow array arguments.
2) StringFunction builds a lambda function and evaluates this. You can see the lambda function as a string by accessing the _lambda attribute.
Methods
C_code([function_name, inline]) | Dump the string expressions as a C function. |
Cpp_code([function_name]) | Dump the string expression to C++. |
F77_code([function_name]) | Dump the string expressions as a Fortran 77 function or subroutine. |
F77_pow() | Generate an F77 function pow(x,a) (x**a). In some |
set_parameters(**kwargs) | Set keyword parameters in the function. |
troubleshoot(*args, **kwargs) | Perform function evaluation call with lots of testing to |
vectorize(globals_dict) | Allow the StringFunction object to take NumPy array |
Dump the string expressions as a C function. If inline is true, the C++ inline keyword is inserted to make the function inline.
Dump the string expression to C++. In C++ we use a plain function if there are no parameters, otherwise we use a function object with operator() for the function evaluation.
Dump the string expressions as a Fortran 77 function or subroutine.
Note: if pow(x,a) is used in the expression, this is translated to x**a by a simple regex, which may fail if there are function calls inside pow(.,.).
Generate an F77 function pow(x,a) (x**a). In some string expressions that are to be translated to C/C++, pow(x,a) must be used instead of x**a, but pow is not defined in F77. This code dumpes the necessary F77 version of pow such that string functions can be seamlessly translated to C, C++, and F77.
Note: this function is difficult to use since it expects exactly a single-precision power. We now rely on regular expressions to replace pow(x,a) by x**a in F77_code instead.
Return the string function formula as a string, with parameters substituted by their values.
The return value can be used when creating Fortran or C/C++ functions out of the string formula: f = StringFunction(‘a + p*x’, a=1, p=0) somefile.write(‘double somefunc(double x) { return %s; }’ % str(f))
Perform function evaluation call with lots of testing to try to help the user with problems.
Allow the StringFunction object to take NumPy array arguments. The calling code must have done a from numpy import * or similar and send the globals() dictionary as the argument globals_dict. Alternatively, the globals() dictionary can be supplied as a globals keyword argument to the constructor.
Methods
__call__(x) |
Methods
__call__(x) |
Methods
__call__(x) | |
set_parameters(code) |
Methods
__call__(x) | |
set_parameters(**kwargs) | |
test([x]) |
Bases: scitools.StringFunction.StringFunction_v4
Extension of class StringFunction_v4 to an arbitrary number of independent variables.
Methods
__call__(*args) | |
set_parameters(**kwargs) | |
test([x]) |