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₀⎠
Related
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)
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 would like to see continued fractions with integers displayed in that form with SymPy, but I cannot seem to make SymPy comply. I found this Stack Overflow question and answer very useful (see farther below), but cannot reach my target goal here:
This is the continued fraction expansion of $\frac{13}{5}$. A common notation for this expansion is to give only the boxed terms as does SymPy below, i.e., $[2,1,1,2]$ from the SymPy continued_fraction_iterator:
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
print( Rat_13_5 )
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
( Rat_13_5 )
print( Rat_13_5 )
With output [2, 1, 1, 2].
Pg 37 of the Sympy manual release 1.5 Dec 9, 2019 gives a code snippet to print such an expanded fraction list:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr += i
expr = 1/expr
return l[0] + expr
If you invoke list_to_frac with the Rat_13_5 continued fraction expansion list, SymPy takes off and evaluates it:
print( list_to_frac( Rat_13_5 ) )
with output 13/5
If you use a list of symbols instead, then list_to_frac prints the desired continued fraction, e.g.,
n1, n2, n3, n4, n5, n6, n7, n8, n9 = symbols('n1:10')
cont_frac_list = [n2, n1, n1, n2]
contfrac12201015 = list_to_frac( [n2,n1,n1,n2] )
contfrac122010154
Which produces the desired (I am working in a JupyterLab environment so am actually obtaining typset LaTeX output throughout):
n2 + 1/(n1 + 1/(n1 + 1/n2))
I rewrote list_to_frac to use the UnevaluatedExpr facility presented by Francesco in the StackOverflow question I cited earlier:
def list_to_frac_noEval(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = UnevaluatedExpr(expr + i)
expr = UnevaluatedExpr( 1/expr )
return l[0] + expr
Invoking list_to_frac_noEval on the $\frac{13}{5}$ expansion list:
list_to_frac_noEval( [2,1,1,2] )
I obtain output
2 + (1 + (1 + 2**(-1))**(-1))**(-1)
Some folks use that notation (so I wanted to share list_to_frac_noEval in any case, that being superior to ending up with an evaluated single rational if you want to see the continued fraction), for example Roger Penrose in section $\unicode{x00A7}3.2$ of The Road to Reality (2004), but I still find it annoying that I cannot obtain the explicit continued fraction format when using integers instead of symbols.
I experimented with substituting in integers for symbols with evaluate=False, using both the subs method and the Subs function, looked at various combinations of sympify and srepr and parse_expr with evaluate=False, , but cannot persuade SymPy 1.4 to print the explicit fraction form that I obtain with list_to_frac operating on symbol arguments. Is there a way to accomplish this short of modifying SymPy code or special casing a particular set of numbers?
You can construct the expression explicitly passing evaluate=False to each part of the expression tree:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = Add(i, expr, evaluate=False)
expr = Pow(expr, -1, evaluate=False)
return Add(l[0], expr, evaluate=False)
That gives:
In [2]: nums = list(continued_fraction_iterator(Rational(13, 5)))
In [3]: nums
Out[3]: [2, 1, 1, 2]
In [4]: list_to_frac(nums)
Out[4]:
1
───────────── + 2
1
───────── + 1
1
───── + 1
0 + 2
It looks like it's the wrong way around but that's just the way the printing works with default settings:
In [5]: init_printing(order='old')
In [6]: list_to_frac(nums)
Out[6]:
1
2 + ─────────────
1
1 + ─────────
1
1 + ─────
0 + 2
You can trigger evaluation with doit:
In [7]: _.doit()
Out[7]: 13/5
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