def _has(self, pattern):
"""Helper for .has()"""
from sympy.core.function import UndefinedFunction, Function
if isinstance(pattern, UndefinedFunction):
return any(f.func == pattern or f == pattern
for f in self.atoms(Function, UndefinedFunction))
pattern = sympify(pattern)
if isinstance(pattern, BasicType):
return any(isinstance(arg, pattern)
for arg in preorder_traversal(self))
try:
match = pattern._has_matcher()
return any(match(arg) for arg in preorder_traversal(self))
except AttributeError:
return any(arg == pattern for arg in preorder_traversal(self))
python类Function()的实例源码
def test_function_series1():
"""Create our new "sin" function."""
class my_function(Function):
def fdiff(self, argindex=1):
return cos(self.args[0])
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(0)
#Test that the taylor series is correct
assert my_function(x).series(x, 0, 10) == sin(x).series(x, 0, 10)
assert limit(my_function(x)/x, x, 0) == 1
def test_function_series2():
"""Create our new "cos" function."""
class my_function2(Function):
def fdiff(self, argindex=1):
return -sin(self.args[0])
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(1)
#Test that the taylor series is correct
assert my_function2(x).series(x, 0, 10) == cos(x).series(x, 0, 10)
def test_function_series3():
"""
Test our easy "tanh" function.
This test tests two things:
* that the Function interface works as expected and it's easy to use
* that the general algorithm for the series expansion works even when the
derivative is defined recursively in terms of the original function,
since tanh(x).diff(x) == 1-tanh(x)**2
"""
class mytanh(Function):
def fdiff(self, argindex=1):
return 1 - mytanh(self.args[0])**2
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(0)
e = tanh(x)
f = mytanh(x)
assert tanh(x).series(x, 0, 6) == mytanh(x).series(x, 0, 6)
def test_as_integral():
from sympy import Function, Integral
f = Function('f')
assert mellin_transform(f(x), x, s).rewrite('Integral') == \
Integral(x**(s - 1)*f(x), (x, 0, oo))
assert fourier_transform(f(x), x, s).rewrite('Integral') == \
Integral(f(x)*exp(-2*I*pi*s*x), (x, -oo, oo))
assert laplace_transform(f(x), x, s).rewrite('Integral') == \
Integral(f(x)*exp(-s*x), (x, 0, oo))
assert str(inverse_mellin_transform(f(s), s, x, (a, b)).rewrite('Integral')) \
== "Integral(x**(-s)*f(s), (s, _c - oo*I, _c + oo*I))"
assert str(inverse_laplace_transform(f(s), s, x).rewrite('Integral')) == \
"Integral(f(s)*exp(s*x), (s, _c - oo*I, _c + oo*I))"
assert inverse_fourier_transform(f(s), s, x).rewrite('Integral') == \
Integral(f(s)*exp(2*I*pi*s*x), (s, -oo, oo))
# NOTE this is stuck in risch because meijerint cannot handle it
def test_namespace_order():
# lambdify had a bug, such that module dictionaries or cached module
# dictionaries would pull earlier namespaces into themselves.
# Because the module dictionaries form the namespace of the
# generated lambda, this meant that the behavior of a previously
# generated lambda function could change as a result of later calls
# to lambdify.
n1 = {'f': lambda x: 'first f'}
n2 = {'f': lambda x: 'second f',
'g': lambda x: 'function g'}
f = sympy.Function('f')
g = sympy.Function('g')
if1 = lambdify(x, f(x), modules=(n1, "sympy"))
assert if1(1) == 'first f'
if2 = lambdify(x, g(x), modules=(n2, "sympy"))
# previously gave 'second f'
assert if1(1) == 'first f'
def test_imps():
# Here we check if the default returned functions are anonymous - in
# the sense that we can have more than one function with the same name
f = implemented_function('f', lambda x: 2*x)
g = implemented_function('f', lambda x: math.sqrt(x))
l1 = lambdify(x, f(x))
l2 = lambdify(x, g(x))
assert str(f(x)) == str(g(x))
assert l1(3) == 6
assert l2(3) == math.sqrt(3)
# check that we can pass in a Function as input
func = sympy.Function('myfunc')
assert not hasattr(func, '_imp_')
my_f = implemented_function(func, lambda x: 2*x)
assert hasattr(func, '_imp_')
# Error for functions with same name and different implementation
f2 = implemented_function("f", lambda x: x + 101)
raises(ValueError, lambda: lambdify(x, f(f2(x))))
def test_dummification():
t = symbols('t')
F = Function('F')
G = Function('G')
#"\alpha" is not a valid python variable name
#lambdify should sub in a dummy for it, and return
#without a syntax error
alpha = symbols(r'\alpha')
some_expr = 2 * F(t)**2 / G(t)
lam = lambdify((F(t), G(t)), some_expr)
assert lam(3, 9) == 2
lam = lambdify(sin(t), 2 * sin(t)**2)
assert lam(F(t)) == 2 * F(t)**2
#Test that \alpha was properly dummified
lam = lambdify((alpha, t), 2*alpha + t)
assert lam(2, 1) == 5
raises(SyntaxError, lambda: lambdify(F(t) * G(t), F(t) * G(t) + 5))
raises(SyntaxError, lambda: lambdify(2 * F(t), 2 * F(t) + 5))
raises(SyntaxError, lambda: lambdify(2 * F(t), 4 * F(t) + 5))
def _extractFunctionsFromSympy(self, expr, top=False):
newVars = []
newArgs = []
isExpensive = False
for arg in expr.args:
(newVarsFromArg, newArg,dontcare) = self._extractFunctionsFromSympy(arg)
newVars += newVarsFromArg
newArgs.append(newArg)
if newVars:
expr = expr.func(*newArgs)
if isinstance(expr.func, type(sympy.Function)) or (
expr.func == sympy.Pow and (
not expr.exp.is_constant or
int(expr.exp) != expr.exp)):
if top:
isExpensive = True
else:
newSym = self.addSSA("_expensive_functions", expr)
expr = newSym
newVars.append(newSym)
return (newVars, expr, isExpensive)
def test_variance_prop():
x, y, z = symbols('x y z')
phi, t = consts = symbols('phi t')
a = RandomSymbol(x)
var_x = Variance(a)
var_y = Variance(RandomSymbol(y))
var_z = Variance(RandomSymbol(z))
f = Function('f')(x)
cases = {
x + y: var_x + var_y,
a + y: var_x + var_y,
x + y + z: var_x + var_y + var_z,
2*x: 4*var_x,
x*y: var_x*y**2 + var_y*x**2,
1/x: var_x/x**4,
x/y: (var_x*y**2 + var_y*x**2)/y**4,
exp(x): var_x*exp(2*x),
exp(2*x): 4*var_x*exp(4*x),
exp(-x*t): t**2*var_x*exp(-2*t*x),
f: Variance(f),
}
for inp, out in cases.items():
obs = variance_prop(inp, consts=consts)
assert out == obs
def test_differentiate_finite():
x, y = symbols('x y')
f = Function('f')
res0 = differentiate_finite(f(x, y) + exp(42), x, y)
xm, xp, ym, yp = [v + sign*S(1)/2 for v, sign in product([x, y], [-1, 1])]
ref0 = f(xm, ym) + f(xp, yp) - f(xm, yp) - f(xp, ym)
assert (res0 - ref0).simplify() == 0
g = Function('g')
res1 = differentiate_finite(f(x)*g(x) + 42, x)
ref1 = (-f(x - S(1)/2) + f(x + S(1)/2))*g(x) + \
(-g(x - S(1)/2) + g(x + S(1)/2))*f(x)
assert (res1 - ref1).simplify() == 0
res2 = differentiate_finite(f(x) + x**3 + 42, x, points=[x-1, x+1],
evaluate=False)
ref2 = (f(x + 1) + (x + 1)**3 - f(x - 1) - (x - 1)**3)/2
assert (res2 - ref2).simplify() == 0
def test_function_series1():
"""Create our new "sin" function."""
class my_function(Function):
def fdiff(self, argindex=1):
return cos(self.args[0])
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(0)
#Test that the taylor series is correct
assert my_function(x).series(x, 0, 10) == sin(x).series(x, 0, 10)
assert limit(my_function(x)/x, x, 0) == 1
def test_function_series2():
"""Create our new "cos" function."""
class my_function2(Function):
def fdiff(self, argindex=1):
return -sin(self.args[0])
@classmethod
def eval(cls, arg):
arg = sympify(arg)
if arg == 0:
return sympify(1)
#Test that the taylor series is correct
assert my_function2(x).series(x, 0, 10) == cos(x).series(x, 0, 10)
def test_as_integral():
from sympy import Function, Integral
f = Function('f')
assert mellin_transform(f(x), x, s).rewrite('Integral') == \
Integral(x**(s - 1)*f(x), (x, 0, oo))
assert fourier_transform(f(x), x, s).rewrite('Integral') == \
Integral(f(x)*exp(-2*I*pi*s*x), (x, -oo, oo))
assert laplace_transform(f(x), x, s).rewrite('Integral') == \
Integral(f(x)*exp(-s*x), (x, 0, oo))
assert str(inverse_mellin_transform(f(s), s, x, (a, b)).rewrite('Integral')) \
== "Integral(x**(-s)*f(s), (s, _c - oo*I, _c + oo*I))"
assert str(inverse_laplace_transform(f(s), s, x).rewrite('Integral')) == \
"Integral(f(s)*exp(s*x), (s, _c - oo*I, _c + oo*I))"
assert inverse_fourier_transform(f(s), s, x).rewrite('Integral') == \
Integral(f(s)*exp(2*I*pi*s*x), (s, -oo, oo))
# NOTE this is stuck in risch because meijerint cannot handle it
def test_namespace_order():
# lambdify had a bug, such that module dictionaries or cached module
# dictionaries would pull earlier namespaces into themselves.
# Because the module dictionaries form the namespace of the
# generated lambda, this meant that the behavior of a previously
# generated lambda function could change as a result of later calls
# to lambdify.
n1 = {'f': lambda x: 'first f'}
n2 = {'f': lambda x: 'second f',
'g': lambda x: 'function g'}
f = sympy.Function('f')
g = sympy.Function('g')
if1 = lambdify(x, f(x), modules=(n1, "sympy"))
assert if1(1) == 'first f'
if2 = lambdify(x, g(x), modules=(n2, "sympy"))
# previously gave 'second f'
assert if1(1) == 'first f'
def test_imps():
# Here we check if the default returned functions are anonymous - in
# the sense that we can have more than one function with the same name
f = implemented_function('f', lambda x: 2*x)
g = implemented_function('f', lambda x: math.sqrt(x))
l1 = lambdify(x, f(x))
l2 = lambdify(x, g(x))
assert str(f(x)) == str(g(x))
assert l1(3) == 6
assert l2(3) == math.sqrt(3)
# check that we can pass in a Function as input
func = sympy.Function('myfunc')
assert not hasattr(func, '_imp_')
my_f = implemented_function(func, lambda x: 2*x)
assert hasattr(func, '_imp_')
# Error for functions with same name and different implementation
f2 = implemented_function("f", lambda x: x + 101)
raises(ValueError, lambda: lambdify(x, f(f2(x))))
def test_dummification():
t = symbols('t')
F = Function('F')
G = Function('G')
#"\alpha" is not a valid python variable name
#lambdify should sub in a dummy for it, and return
#without a syntax error
alpha = symbols(r'\alpha')
some_expr = 2 * F(t)**2 / G(t)
lam = lambdify((F(t), G(t)), some_expr)
assert lam(3, 9) == 2
lam = lambdify(sin(t), 2 * sin(t)**2)
assert lam(F(t)) == 2 * F(t)**2
#Test that \alpha was properly dummified
lam = lambdify((alpha, t), 2*alpha + t)
assert lam(2, 1) == 5
raises(SyntaxError, lambda: lambdify(F(t) * G(t), F(t) * G(t) + 5))
raises(SyntaxError, lambda: lambdify(2 * F(t), 2 * F(t) + 5))
raises(SyntaxError, lambda: lambdify(2 * F(t), 4 * F(t) + 5))
def as_symbol(expr):
"""
Extract the "main" symbol from a SymPy object.
"""
try:
return Number(expr)
except (TypeError, ValueError):
pass
if isinstance(expr, str):
return Symbol(expr)
elif isinstance(expr, Dimension):
return Symbol(expr.name)
elif expr.is_Symbol:
return expr
elif isinstance(expr, Indexed):
return expr.base.label
elif isinstance(expr, Function):
return Symbol(expr.__class__.__name__)
else:
raise TypeError("Cannot extract symbol from type %s" % type(expr))
def __new__(cls, *args, **kwargs):
options = kwargs.get('options', {})
if cls in _SymbolCache:
newobj = sympy.Symbol.__new__(cls, *args, **options)
newobj._cached_init()
else:
name = kwargs.get('name')
# Create the new Function object and invoke __init__
newcls = cls._symbol_type(name)
newobj = sympy.Symbol.__new__(newcls, name, *args, **options)
newobj.__init__(*args, **kwargs)
# Store new instance in symbol cache
newcls._cache_put(newobj)
return newobj
def __new__(cls, *args, **kwargs):
if cls in _SymbolCache:
options = kwargs.get('options', {})
newobj = sympy.Function.__new__(cls, *args, **options)
newobj._cached_init()
else:
name = kwargs.get('name')
if len(args) < 1:
args = cls._indices(**kwargs)
# Create the new Function object and invoke __init__
newcls = cls._symbol_type(name)
options = kwargs.get('options', {})
newobj = sympy.Function.__new__(newcls, *args, **options)
newobj.__init__(*args, **kwargs)
# All objects cached on the AbstractFunction /newobj/ keep a reference
# to /newobj/ through the /function/ field. Thus, all indexified
# object will point to /newobj/, the "actual Function".
newobj.function = newobj
# Store new instance in symbol cache
newcls._cache_put(newobj)
return newobj
def _indices(cls, **kwargs):
"""Return the default dimension indices for a given data shape
:param grid: :class:`Grid` that defines the spatial domain.
:param dimensions: Optional, list of :class:`Dimension`
objects that defines data layout.
:return: Dimension indices used for each axis.
..note::
Only one of :param grid: or :param dimensions: is required.
"""
grid = kwargs.get('grid', None)
dimensions = kwargs.get('dimensions', None)
if grid is None:
if dimensions is None:
error("Creating a Function object requries either "
"a 'grid' or the 'dimensions' argument.")
raise ValueError("Unknown symbol dimensions or shape")
else:
if dimensions is not None:
warning("Creating Function with 'grid' and 'dimensions' "
"argument; ignoring the 'dimensions' and using 'grid'.")
dimensions = grid.dimensions
return dimensions
def _indices(cls, **kwargs):
"""Return the default dimension indices for a given data shape
:param grid: :class:`Grid` object from which to infer the data
shape and :class:`Dimension` indices.
:return: Dimension indices used for each axis.
"""
save = kwargs.get('save', None)
grid = kwargs.get('grid', None)
time_dim = kwargs.get('time_dim', None)
if grid is None:
error('TimeFunction objects require a grid parameter.')
raise ValueError('No grid provided for TimeFunction.')
if time_dim is None:
time_dim = grid.time_dim if save else grid.stepping_dim
elif not isinstance(time_dim, TimeDimension):
raise ValueError("time_dim must be a TimeDimension, not %s" % type(time_dim))
assert(isinstance(time_dim, Dimension) and time_dim.is_Time)
_indices = Function._indices(**kwargs)
return tuple([time_dim] + list(_indices))
def __init__(self, *args, **kwargs):
if not self._cached():
self.nt = kwargs.get('nt', 0)
self.npoint = kwargs.get('npoint')
kwargs['shape'] = (self.nt, self.npoint)
super(SparseFunction, self).__init__(self, *args, **kwargs)
if self.grid is None:
error('SparseFunction objects require a grid parameter.')
raise ValueError('No grid provided for SparseFunction.')
# Allocate and copy coordinate data
d = Dimension('d')
self.coordinates = Function(name='%s_coords' % self.name,
dimensions=[self.indices[-1], d],
shape=(self.npoint, self.grid.dim))
self._children.append(self.coordinates)
coordinates = kwargs.get('coordinates', None)
if coordinates is not None:
self.coordinates.data[:] = coordinates[:]
def _test_f():
# FIXME: we get infinite recursion here:
f = Function("f")
assert residue(f(x)/x**5, x, 0) == f.diff(x, 4)/24
def test_var_cls():
f = var('f', cls=Function)
assert isinstance(f, FunctionClass)
g, h = var('g,h', cls=Function)
assert isinstance(g, FunctionClass)
assert isinstance(h, FunctionClass)
def test_function():
f = Function('f')
l, x = map(Symbol, 'lx')
assert exp(l(x))*l(x)/exp(l(x)) == l(x)
assert exp(f(x))*f(x)/exp(f(x)) == f(x)
def test_sympy__physics__quantum__operator__DifferentialOperator():
from sympy.physics.quantum.operator import DifferentialOperator
from sympy import Derivative, Function
f = Function('f')
assert _test_args(DifferentialOperator(1/x*Derivative(f(x), x), f(x)))
def test_apply_finite_diff():
x, h = symbols('x h')
f = Function('f')
assert (apply_finite_diff(1, [x-h, x+h], [f(x-h), f(x+h)], x) -
(f(x+h)-f(x-h))/(2*h)).simplify() == 0
assert (apply_finite_diff(1, [5, 6, 7], [f(5), f(6), f(7)], 5) -
(-S(3)/2*f(5) + 2*f(6) - S(1)/2*f(7))).simplify() == 0
def fct_sym_array(str_lst, coords=None):
"""
Construct list of symbols or functions with names in 'str_lst'. If
'coords' are given (tuple of symbols) function list constructed,
otherwise a symbol list is constructed.
"""
if coords is None:
fs_lst = []
for sym_str in str_lst:
fs_lst.append(Symbol(sym_str))
else:
fs_lst = []
for fct_str in str_lst:
fs_lst.append(Function(fct_str)(*coords))
return fs_lst
def test_rsolve_raises():
x = Function('x')
raises(ValueError, lambda: rsolve(y(n) - y(k + 1), y(n)))
raises(ValueError, lambda: rsolve(y(n) - y(n + 1), x(n)))
raises(ValueError, lambda: rsolve(y(n) - x(n + 1), y(n)))
raises(ValueError, lambda: rsolve(y(n) - sqrt(n)*y(n + 1), y(n)))
raises(ValueError, lambda: rsolve(y(n) - y(n + 1), y(n), {x(0): 0}))