Is there a way to do a substitution in sympy of all occurences that satisfy a given pattern? For example, if I have an expression that contains multiple occurances of sqrt(anything), is there a way to substitute all those occurences with anything**0.51?
Here is a code example:
import sympy
from sympy import sqrt, exp
from sympy import *
x,y = symbols('x y')
test = sqrt (x+y) + sqrt (exp(y))
in this case I can do substitution manually:
test.subs(sqrt(x+y), (x + y)**0.51).subs(sqrt (exp(y)) , (exp(y))**0.51)
yielding the expected subsitution. But, is there a way to do it one shot so one can easily apply it to long epxressions?
You can use a Wild symbol to do pattern-matched replacements:
In [7]: w = Wild('w')
In [8]: test
Out[8]:
____
_______ ╱ y
╲╱ x + y + ╲╱ ℯ
In [9]: test.replace(sqrt(w), w**0.51)
Out[9]:
0.51
0.51 ⎛ y⎞
(x + y) + ⎝ℯ ⎠
You can use the replace method. Here is the documentation with a few examples.
In your particular case, the square root is a power with exponent 0.5, so we are going to look for those objects:
test.replace(lambda t: t.is_Pow and t.exp is S.Half, lambda t: t.base**0.51)
Related
I have the following code
import sympy as sp
x, y = sp.symbols('x y', real=True, positive=True)
expr = sp.sqrt(1/(x-y))/sp.sqrt(x+y)
the expression created should be equal to sqrt(1/(x^2 - y^2)) and I would like to rewrite it in that form but I cannot figure out how. I tried .rewrite(sp.sqrt), .rewrite(x**2 - y**2) and similar stuff but it did not help.
Ty for any tips on this,
Franz
The expression that you want is not equivalent to the one that you have:
In [53]: expr1 = sqrt(1/x - y)/sqrt(x + y)
In [54]: expr2 = 1/sqrt(x**2 - y**2)
In [55]: expr1
Out[55]:
________
╱ 1
╱ -y + ─
╲╱ x
────────────
_______
╲╱ x + y
In [56]: expr2
Out[56]:
1
────────────
_________
╱ 2 2
╲╱ x - y
In [58]: expr1.subs({x:1, y:2})
Out[58]:
√3⋅ⅈ
────
3
In [59]: expr2.subs({x:1, y:2})
Out[59]:
-√3⋅ⅈ
──────
3
That being said it should still be possible to do what you want using powsimp(expr1, force=True) but that doesn't seem to work in this case. I recommend opening a bug report about powsimp:
https://github.com/sympy/sympy/issues
I am trying to solve differential equation y'=cot(x) using Sympy:
x = symbols("x")
y = Function("y")(x)
dsolve(diff(y, x) - cot(x))
It gives me solution with logarithm: y(x) = C1 + log(sin(x)).
How I can replace in this expression log by combination log + abs: log(sin(x)) -> log(abs(sin(x)))? I can do it manually, but it's not very convenient. Is there any way to do it with SymPy tools (something like subs command)?
Note that the abs isn't actually needed: the integration constant C1 can include I*pi. The form without abs is valid for all complex x whereas the abs form is only valid for real x.
In any case, you can do it like this:
In [6]: sol
Out[6]: y(x) = C₁ + log(sin(x))
In [7]: sol.replace(log, lambda e: log(abs(e)))
Out[7]: y(x) = C₁ + log(│sin(x)│)
I am using lcapy together with sympy and trying to process complex numbers from a circuit.
I have the following sympy expression:
import sympy
from lcapy import j
expr = sympy.parse_expr('L*w_0*(C*R*w_0 - I)')
expr
Output:
L⋅w₀⋅(C⋅R⋅w₀ - ⅉ)
expr above is an complex expression with ⅉ being the imaginary number. Can I use sympy and remove the brackets from expr in order to view it in the more canonical form for complex numbers as
w₀^2⋅R⋅L⋅C - ⅉ⋅w₀⋅L
And does sympy have support for handling complex numbers? I want to get the argument of expr which should be:
arctan(L⋅w₀ / w₀^2⋅R⋅L⋅C)
I can do (in an isympy session):
In [13]: expr
Out[13]: L⋅w₀⋅(C⋅R⋅w₀ - ⅈ)
In [14]: expr.expand()
Out[14]:
2
C⋅L⋅R⋅w₀ - ⅈ⋅L⋅w₀
edit
try
atan2(im(expr), re(expr))
https://docs.sympy.org/latest/modules/functions/elementary.html
Refining the variables:
In [53]: C,L,R,w_0=symbols('C L R w_0',real=True, positive=True)
In [54]: expr=L*w_0*(C*R*w_0-I)
In [55]: expr
Out[55]: L⋅w₀⋅(C⋅R⋅w₀ - ⅈ)
In [56]: expr.expand()
Out[56]:
2
C⋅L⋅R⋅w₀ - ⅈ⋅L⋅w₀
In [57]: im(_),re(_)
Out[57]:
⎛ 2⎞
⎝-L⋅w₀, C⋅L⋅R⋅w₀ ⎠
Now the atan2 is simplified:
In [59]: atan2(*_)
Out[59]:
⎛ 1 ⎞
-atan⎜──────⎟
⎝C⋅R⋅w₀⎠
And arg does the same:
In [60]: arg(_56)
Out[60]: arg(C⋅R⋅w₀ - ⅈ)
In [62]: arg(expr)
Out[62]: arg(C⋅R⋅w₀ - ⅈ)
In [77]: arg(expr)._eval_rewrite_as_atan2(expr)
Out[77]:
⎛ 1 ⎞
-atan⎜──────⎟
⎝C⋅R⋅w₀⎠
Can Sympy automatically simplify an expression that includes terms like this one:
cos(x)/(cos(x)**2)**(1/2)
which can be simplified to 1 in the domain that I am interested in 0 <= x <= pi/2 ?
(Examples of other terms that could be simplified in that domain: acos(cos(x)); sqrt(sin(x)**2); sqrt(cos(2*x) + 1); etc.)
If you know the functions that are in your expression (such as sin, cos and tan), you can do the following according to this stack overflow question:
from sympy import *
x = symbols("x", positive=True)
ex = cos(x)/(cos(x)**2)**(S(1)/2)
ex = refine(ex, Q.positive(sin(x)))
ex = refine(ex, Q.positive(cos(x)))
ex = refine(ex, Q.positive(tan(x)))
print(ex)
Note that Q.positive(x*(pi/2-x)) did not help in the process of simplification for trig functions even though this is exactly what you want in general.
But what if you might have crazy functions like polygamma? The following works for some arbitrary choices for ex according to my understanding.
It wouldn't be a problem if the expression was already generated before by SymPy, but if you are inputting the expression manually, I suggest using S(1)/2 or Rational(1, 2) to describe one half.
from sympy import *
# define everything as it would have come from previous code
# also define another variable y to be positive
x, y = symbols("x y", positive=True)
ex = cos(x)/(cos(x)**2)**(S(1)/2)
# If you can, always try to use S(1) or Rational(1, 2)
# if you are defining fractions.
# If it's already a pre-calculated variable in sympy,
# it will already understand it as a half, and you
# wouldn't have any problems.
# ex = cos(x)/(cos(x)**2)**(S(1)/2)
# if x = arctan(y) and both are positive,
# then we have implicitly that 0 < x < pi/2
ex = simplify(ex.replace(x, atan(y)))
# revert back to old variable x if x is still present
ex = simplify(ex.replace(y, tan(x)))
print(ex)
This trick can also be used to define other ranges. For example, if you wanted 1 < x, then you could have x = exp(y) where y = Symbol("y", positive=True).
I think subs() will also work instead of replace() but I just like to be forceful with substitutions, since SymPy can sometimes ignore the subs() command for some variable types like lists and stuff.
You can substitute for a symbol that has the assumptions you want:
In [27]: e = cos(x)/(cos(x)**2)**(S(1)/2) + cos(x)
In [28]: e
Out[28]:
cos(x)
cos(x) + ────────────
_________
╱ 2
╲╱ cos (x)
In [29]: cosx = Dummy('cosx', positive=True)
In [30]: e.subs(cos(x), cosx).subs(cosx, cos(x))
Out[30]: cos(x) + 1
I have been working on some integrations and even though the system is working, it takes much more time to work than it should.
The problem is that the expressions are many pages, and even though they are 3 variables only, sy.simplify just crashes the Kernel after 4 hours or so.
Is there a way to make such lengthy expressions more compact?
EDIT:
Trying to recreate a test expression, using cse. I can't really substitute the symbols to make a final expression, equal to the 1st one
sy.var('a:c x')
testexp = sp.log(x)+a*(0.5*x)**2+(b*(0.5*x)**2+b+sp.log(x))/c
r, e = sy.cse(testexp)
FinalFunction = sy.lambdify(r[0:][0]+(a,b,c,x),e[0])
Points = sy.lambdify((a,b,c,x),r[0:][1])
FinalFunction(Points(1,1,1,1),1,1,1,1)
>>>NameError: name 'x1' is not defined
cse(expr) is sometimes a way to get a more compact representation since repeated subexpressions can be replaced with a single symbol. cse returns a list of repeated expressions and a list of expressions (a singleton if you only passed a single expression):
>>> from sympy import solve
>>> var('a:c x');solve(a*x**2+b*x+c, x)
(a, b, c, x)
[(-b + sqrt(-4*a*c + b**2))/(2*a), -(b + sqrt(-4*a*c + b**2))/(2*a)]
>>> r, e = cse(_)
>>> for i in r: pprint(Eq(*i))
...
_____________
╱ 2
x₀ = ╲╱ -4⋅a⋅c + b
1
x₁ = ───
2⋅a
>>> for i in e: pprint(i)
...
x₁⋅(-b + x₀)
-x₁⋅(b + x₀)
You are still going to have long expressions but they will be represented more compactly (and more efficiently for computatation) if cse is able to identify repeated subexpressions.
To use this in SymPy you can create two Lambdas: one to translate the variables into the replacement values and the other to use those values:
>>> v = (a,b,c,x)
>>> Pts = Lambda(v, tuple([i[1] for i in r]+list(v)))
>>> Pts(1,2,3,4)
(2*sqrt(2)*I, 1/2, 1, 2, 3, 4)
>>> Func = Lambda(tuple([i[0] for i in r]+list(v)), tuple(e))
>>> Func(*Pts(1,2,3,4))
(-1 + sqrt(2)*I, -1 - sqrt(2)*I)