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)
Related
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.
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 have this expression −0.00117115487626846cos(ϕc)+0.00241553041801322 and it belongs to the type add.add from sympy, i have a list like this which depends on phic or phia, i want to test for several on which one depends. I have tried with in and args, but still not have the answer. Thanks
i hace tried args and in
return:
simplify(expand((u[0,2]*conjugate(u[0,2])).subs(constantes),complex=True))
S13=[]
for i in range(6):
S13.append(s13(U[i]))
I expect the output gives me if the dependence is on phia or phic or both
In general, the free symbols (those symbols on which an expression depends) are available through the free_symbols attribute.
So, you can do something like this:
from sympy import *
x,y = symbols('x y')
exp = x**2 + y**2 + x*y
s = exp.free_symbols
print(s) # {x,y}
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.
Here's my problem (illustraded with an applicable example):
... some code
### x=0.5*t*(copysign(1, t - 0.5) + 1) + 0.1
### x=string value
X= Matrix(len(x),1,x)
>>>print X[0]
0.5*t*(copysign(1, t - 0.5) + 1) + 0.1
>>>print type(X[0])
<class 'sympy.core.add.Add'>
t1=linspace(0,1,2)
REF=[]
for i in range(len(t1)):
REF.append(M_ref[0].subs(t,t1[i]))
>>>print REF
0.100000000000000, 0.5*copysign(1, 0.5) + 0.6
So REF[0] is from the 'sympy.core.numbers.Float' class, but REF[1] is from the 'sympy.core.add.Add' class (as are the rest of list values when I expand the linspace). Therefore I can't use them in the rest of my code. I tried to use evalf but that didn't solve the problem.
I need the values in the REF list to be all floats (or integers).
Any help would be appreciated.
I think I understand what is happening.
You are converting your input from strings. SymPy doesn't have a function called copysign, and sympify doesn't use the math library, so it just creates Function('copysign'), which is an unevaluated object. If you want to evaluate it as the math copysign from the get-go, you can add {'copysign': math.copysign} as a second argument when you call sympify, like sympify('copysign(1, 2)', {'copysign': math.copysign}). If you want a symbolic version, you will need to create one, as it doesn't exist in SymPy yet. Something like
class copysign(Function):
nargs = 2
#classmethod
def eval(cls, x, y):
if x.is_number and y.is_number:
return math.copysign(x, y)
That will work symbolically, but as soon as both arguments are numeric, it will evaluate using the math copysign.
>>> x, y = symbols('x y')
>>> copysign(x, y)
copysign(x, y)
>>> copysign(1, -2)
-1.0
Really, a better way to do it would be to reimplement the copysign logic symbolically, so that it always returns a SymPy type, but I'll leave that to you as an exercise. You can look at how sign is implemented in SymPy to get an idea.