scitools.StringFunction

Make a string with a mathematical expression behave as a Python function.

class scitools.StringFunction.StringFunction(expression, **kwargs)[source]

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
C_code(function_name='somefunc', inline=False)[source]

Dump the string expressions as a C function. If inline is true, the C++ inline keyword is inserted to make the function inline.

Cpp_code(function_name='somefunc')[source]

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.

F77_code(function_name='somefunc')[source]

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(.,.).

F77_pow()[source]

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.

__init__(expression, **kwargs)[source]
__module__ = 'scitools.StringFunction'
__repr__()[source]

Return the code required to reconstruct this instance.

__str__()[source]

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))

set_parameters(**kwargs)[source]

Set keyword parameters in the function.

troubleshoot(*args, **kwargs)[source]

Perform function evaluation call with lots of testing to try to help the user with problems.

vectorize(globals_dict)[source]

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.

class scitools.StringFunction.StringFunction_v1(expression)[source]

Methods

__call__(x)
__call__(x)[source]
__init__(expression)[source]
__module__ = 'scitools.StringFunction'
class scitools.StringFunction.StringFunction_v2(expression)[source]

Methods

__call__(x)
__call__(x)[source]
__init__(expression)[source]
__module__ = 'scitools.StringFunction'
class scitools.StringFunction.StringFunction_v3(expression, independent_variable='x', set_parameters='')[source]

Methods

__call__(x)
set_parameters(code)
__call__(x)[source]
__init__(expression, independent_variable='x', set_parameters='')[source]
__module__ = 'scitools.StringFunction'
set_parameters(code)[source]
class scitools.StringFunction.StringFunction_v4(expression, **kwargs)[source]

Methods

__call__(x)
set_parameters(**kwargs)
test([x])
__call__(x)[source]
__init__(expression, **kwargs)[source]
__module__ = 'scitools.StringFunction'
__repr__()[source]
__str__()[source]
set_parameters(**kwargs)[source]
test(x=1.4325)[source]
class scitools.StringFunction.StringFunction_v5(expression, **kwargs)[source]

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])
__call__(*args)[source]
__init__(expression, **kwargs)[source]
__module__ = 'scitools.StringFunction'
__repr__()[source]
__str__()[source]
set_parameters(**kwargs)
test(x=1.4325)

This Page