In Wolfram Research Mathematica it is possible to define a sustitution rule of the type
sustitution = g_[arg___] -> g[Sequence ## Reverse[{arg}]]
Then it is possible to apply it to different expressions involving functions with the following results:
f[x, y] /. sustitution >> f[y,x]
g[x1,x2,x3] >> g[x3,x2,x1]
h[1,z,w,t]/.sustitution >> h[t,w,z,1]
As it is possible to use a pattern with name, g_, for the name of the function and another pattern, arg___, for the arguments, the same sustitution rule is valid no matter the name of the function that appears in the expression.
Is it possible to use WildFunction symbols along with replace to obtain a similar efect with Sympy?
The arg__ is not necessary for a SymPy type arg-remapping function since the args can be retrieved from the function call itself:
>>> from sympy.abc import x,y,z
>>> from sympy import Function
>>> f = Function('f')
>>> g_ = lambda f: f.func(*list(reversed(f.args)))
>>> g_(f(x,y,z))
f(z, y, x)
Another way of changing all user-defined functions the same way within an expression is to use replace as follows:
>>> from sympy.abc import *
>>> from sympy import Function, AppliedUndef
>>> f,g,h,F=symbols('f,g,h,F',cls=Function)
>>> eq=f(x,y,z)+g(y,x,w)*h(1,u,t)**cos(F(x,y,1,w))
>>> eq.replace(
... lambda x: isinstance(x, AppliedUndef),
... lambda x: x.func(*list(reversed(x.args))))
f(z, y, x) + g(w, x, y)*h(t, u, 1)**cos(F(w, 1, y, x))
If you wanted to apply such a transformation to all functions then use Function instead of AppliedUndef.
Related
If I define a symbolic expression inside a function, how do I evaluate that expression using .subs() outside that function. The following code demonstrates the issue:
import sympy as sp
def myFun():
x = sp.symbols("x", positive = True)
y = 3*x
return y
expr = myFun()
print(expr.subs({x:10}))
Running the code above gives NameError: name 'x' is not defined.
How can I perform this evaluation? Two things I could think of is declaring x to be a global variable using global x inside myFun(). However, I want to avoid this method. Another way is to lambdify the expression in myFun() before returning the expression. But I would prefer not to use this method because in the real problem I am working with, I have multiple variables in my expression and would like to substitute only some of the variables at one stage, and the remaining variables at a later stage. Would you adopt one of the two approaches I mentioned or is it possible to evaluate the expression using .subs() using some other approach?
#cards answer is not going to work, the reason is that you have defined x to be positive, instead when calling print(expr.subs({'x':10})) the string 'x' will generate a generic symbol, without assumptions.
You either create your symbols outside of the function, like this:
import sympy as sp
x = sp.symbols("x", positive = True)
def myFun():
y = 3*x
return y
expr = myFun()
print(expr.subs({x:10}))
# out: 30
Or you can retrieve the symbols that make up a symbolic expression with the free_symbol attribute, like this:
import sympy as sp
def myFun():
x = sp.symbols("x", positive = True)
y = 3*x
return y
expr = myFun()
x = expr.free_symbols.pop()
print(expr.subs({x:10}))
# out: 30
EDIT (to accommodate comment):
I was just wondering but what if the expression had three variables, say 5*y + 3*x + 7*z? I tried the code you provided. The line expr.free_symbols.pop() only gives one of the variables - it gives x. Is there a way to use free_symbols to get all three variables?
free_symbols returns a set with all variables. If the expression is expr = 5*y + 3*x + 7*z, then expr.free_symbols returns {x, y, z}.
pop() is a method of Python's set: it returns the first element of a set.
To get all the variables of your expression you could try: x, y, z = expr.free_symbols, or x, y, z = list(expr.free_symbols). However, this creates the following problem: execute print(x, y, z) and you'll get something similar to: y z x. In other words, the symbols returned by expr.free_symbols are unordered. This is the default Python behavior.
Can we get ordered symbols? Yes, we can sort them alphabetically with : x, y, z = sorted(expr.free_symbols, key=str). If we now execute print(x, y, z) we will get x y z.
Let's create an expression with two symbols in it:
In [44]: x, y = symbols('x, y')
In [45]: expr = sin(y) + x**2
Suppose that we only have the expression as a local variable. We can find the symbols it contains using free_symbols. We can use that to build a dict that maps symbol names (as strings) to the symbols themselves:
In [46]: expr.free_symbols
Out[46]: {x, y}
In [47]: syms = {s.name: s for s in expr.free_symbols}
In [48]: syms
Out[48]: {'y': y, 'x': x}
This mapping is important because different symbols with the same names but different assumptions are not interchangeable. With that we can substitute the symbol whose name is 'x' like this:
In [49]: expr.subs(syms['x'], 2)
Out[49]: sin(y) + 4
x as a Symbol object is only declared in the function's body, so it's not accessible from the outside. Use 'x' as a string.
x = list(expr.free_symbols)[0]
print(expr.subs({x: 2}))
I am programming a little calculator using ipython console and sympy.
The setup is
import sympy
x, y, z = symbols('x y z')
f = (x+2)**2
g = lambda y: y+3
It would be nice to see which symbols have already been defined in sympy.
How do I get a list of all sympy symbols? i.e. a list containing x, y, z and f but not g, as g is an ordinary python lambda.
I am looking for something like vars() or globals, but containing only sympy related definitions.
Would this work for you?
>>> b4 = set(dir()) # everything before SymPy work started
>>> ...
>>> from sympy import Basic
>>> [i for i in dir() if not i.startswith("_") and i not in b4 and
... isinstance(globals()[i], Basic)]
Basic could be replaced with Expr if you wanted only symbols that pointed to Expr
I am wondering how to find the symbols connected with Functions in a sympy expression. I am aware of .free_symbols, .atoms(Function) as well as .atoms(AppliedUndef). Here is some code to show why none of these does what I need.
f1 = Function(r'f_1')
f2 = Function(r'f_2')
c1, x = symbols(r'c_1, x')
expr = c1+f1(x)+f2(x)
print(expr)
# c_1 + f_1(x) + f_2(x)
print(expr.free_symbols)
# {x, c_1}
print(expr.atoms(Function))
# {f_1(x), f_2(x)}
from sympy.core.function import AppliedUndef
print(expr.atoms(AppliedUndef))
# {f_1(x), f_2(x)}
(The comments are the outputs of each print line). So .free_symbols is nice, it gives me c_1 and x. However, it does not return the symbols associated with the functions f_1 and f_2. (First question: why? Are they not free somehow?). .atoms(Function) does not help either. It finds the functions, but does not return their associated symbols (e.g. f_1), it returns the whole function call (e.g. f_1(x)).
Main question: How do I find the symbols f_1 and f_2 in above expression?
Background: The reason I want this, is because I would like to lambdify in the following way
expr_num = lambdify([c1, f1, f2, x], expr)
but instead of giving the argument [c1, f1, f2, x] manually, I would like to find all necessary symbols in the expression.
The following obtains free symbols and names of AppliedUndef functions:
>>> s = f(x).free_symbols
>>> func = set([i.func for i in f(x).atoms(Function) if isinstance(i, AppliedUndef)])
>>> s | func
{x, f}
Based on the accepted solution by #smichr, here is a piece of code that can be directly appended to the code in the question (adds nothing interesting, just for convenience):
f1 = Function(r'f_1')
f2 = Function(r'f_2')
c1, x = symbols(r'c_1, x')
syms_and_funs = set(expr.free_symbols) | set([i.func for i in expr.atoms(Function) if isinstance(i, AppliedUndef)])
print(syms_and_funs)
# {x, f_2, f_1, c_1}
expr_num = lambdify(syms_and_funs, expr)
Take an undefined function that happens to be named dot, and make it part of lambdify:
import numpy
import sympy
class dot(sympy.Function):
pass
x = sympy.Symbol('x')
a = sympy.Matrix([1, 0, 0])
f = sympy.lambdify(x, dot(a.T, x))
x = numpy.array([3, 2, 1])
print(f(x))
Surprise: This actually works!
Apparently, the string "dot" is somehow extracted and replaced by an implementation of the dot-product. Does anyone know which?
The result of the above is [3]. I would, however, like to get the scalar 3. (How) can I modify f() to achieve that?
I'm not a sympy user however quoting the documentation for lambdify it says:
If not specified differently by the user, SymPy functions are replaced
as far as possible by either python-math, numpy (if available) or
mpmath functions - exactly in this order. To change this behavior, the
“modules” argument can be used. It accepts:
the strings “math”, “mpmath”, “numpy”, “numexpr”, “sympy”
any modules (e.g. math)
dictionaries that map names of sympy functions to arbitrary functions
lists that contain a mix of the arguments above, with higher priority given to entries appearing first.
So it seems that if you have python-math installed it will use that, if not but you have numpy installed it will use numpy's version, otherwise mpmat and then describes how to modify this behaviour.
In your case just provide a modules value that is a dictionary that maps the name dot to a function that return a scalar as you want.
An example of what I mean:
>>> import numpy as np
>>> import sympy
>>> class dot(sympy.Function): pass
...
>>> x = sympy.Symbol('x')
>>> a = sympy.Matrix([1,0,0])
>>> f = sympy.lambdify(x, dot(a.T, x), modules=[{'dot': lambda x, y: np.dot(x, y)[0]}, 'numpy'])
>>> y = np.array([3,2,1])
>>> print(f(y))
3
>>> print(type(f(y)))
<class 'numpy.int64'>
As you can see by manipulating the modules argument you can achieve what you want. My implementation here is absolutely naive, but you can generalize it like:
>>> def my_dot(x, y):
... res = np.dot(x, y)
... if res.ndim == 1 and res.size == 1:
... return res[0]
... return res
This function checks whether the result of the normal dot is a scalar, and if so returns the plain scalar and otherwise return the same result as np.dot.
How can I get sympy to simplify an expression like log(exp(exp(x))) to exp(x)? It seems to work on simpler expressions like exp(log(x)) => x. This is a minimal example showing what I've tried so far:
import sympy
from sympy import exp, log
x = sympy.symbols('x')
a = exp(log(x))
print a
# Gives `x` automatically, no call to simplify needed
b = log(exp(exp(x)))
print sympy.simplify(b), sympy.powsimp(b,deep=True)
# Gives `log(exp(exp(x)))` back, expected `exp(x)`
This is happening because of lack of information. I think you want to do this:
In [7]: x = Symbol('x', real=True)
In [8]: (log(exp(exp(x)))).simplify()
Out[8]: exp(x)