Using sympy for symbolic math, the code runs forever - python

I am trying to solve simultaneous equations for x and y, I am not getting any result (code just keeps on running). I feel the error is related to using sqrt in the equations but not sure. Can someone help me figure this out?
from __future__ import division
from sympy import Symbol,sqrt,solve
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')
a = Symbol('a')
b = Symbol('b')
c = Symbol('c')
d = Symbol('d')
e = Symbol('e')
f = Symbol('f')
g = Symbol('g')
h = Symbol('h')
print (solve((sqrt((c-a)**2+(d-b)**2)+sqrt((x-c)**2+(y-d)**2)-2*sqrt((x-a)**2+(y-b)**2),(y-b)*(e-a)-(x-a)*(f-b)) ,x,y))

This is a(nother) problem were you have to rely on the A of CAS and let SymPy assist you instead of relying on SymPy (in it's current state) to do all the work. The following assumes that eqs is a list of the two equations you want to solve as you gave in the OP.
Notice that the 2nd equation is linear in both symbols. Solve for y and substitute into the first equation.
>>> yis = solve(eqs[1], y)[0]
>>> eq0 = eqs[0].subs(y,yis)
This gives an expression that has a lot of symbols in it and that slows things down. It also has two terms with sqrt that depend on x. Replace those arguments of the sqrt with Dummy symbols and then unrad the expression to get it in polynomial form, restore replacements and factor:
>>> from sympy.solvers.solvers import unrad, S
>>> reps = {i.base:Dummy() for i in eq0.atoms(Pow) if i.has(x) and i.exp==S.Half}
>>> ireps = {v:k for k,v in reps.items()}
>>> poly = unrad(eq0.xreplace(reps), *reps.values())[0].xreplace(ireps).factor()
Using factor is an expensive process to always use, but if you know the problem is going to take a long time without it, it is worth a try. In this case a quartic reduces to a product of quadratics which are easy to solve and don't require checking or simplification:
>>> xis = solve(poly, x)
There are three solutions for x and each of these can be substituted into the expression for y to get the three solutions. The solutions are large enough so they are not shown here.
>>> count_ops(xis)
386

Related

sympy solve function gives wrong result

according to this graph: desmos
print(solve('x**2 + x - 1/x'))
# [-1/3 + (-1/2 - sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3) + 1/(9*(-1/2 - sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3)), -1/3 + 1/(9*(-1/2 + sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3)) + (-1/2 + sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3), -1/3 + 1/(9*(sqrt(69)/18 + 25/54)**(1/3)) + (sqrt(69)/18 + 25/54)**(1/3)]
I was expecting [0.755, 0.57], but, I got something I cannot use in my future program. I desire to get a list of floats as result, so refer to this post, I did following, but I got some even more weird:
def solver(solved, rit=3):
res = []
for val in solved:
if isinstance(val, core.numbers.Add):
flt = val.as_two_terms()[0]
flt = round(flt, rit)
else:
flt = round(val, rit)
if not isinstance(flt, core.numbers.Add):
res.append(flt)
return res
print(solver(solve('x**2 + x - 1/x')))
# [-0.333, -0.333, -0.333]
Now I am really disappointed with sympy, I wonder if there is an accurate way to get a list of floats as result, or I will code my own gradient descent algorithm to find the roots and intersection.
sym.solve solves an equation for the independent variable. If you provide an expression, it'll assume the equation sym.Eq(expr, 0). But this only gives you the x values. You have to substitute said solutions to find the y value.
Your equation has 3 solutions. A conjugate pair of complex solutions and a real one. The latter is where your two graphs meet.
import sympy as sym
x = sym.Symbol('x')
# better to represent it like the equation it is
eq = sym.Eq(x**2, 1/x - x)
sol = sym.solve(eq)
for s in sol:
if s.is_real:
s = s.evalf()
print(s, eq.lhs.subs({x: s})) # eq.rhs works too
There are a variety of things you can do to get the solution. If you know the approximate root location and you want a numerical answer, nsolve is simplest since it has no requirements on the type of expression:
>>> from sympy import nsolve, symbols
>>> x = symbols('x')
>>> eq = x**2 + x - 1/x
>>> nsolve(eq, 1)
0.754877666246693
You can try a guess near 0.57 but it will go to the same solution. So is there really a second real roots? You can't use real_roots on this expression because it isn't in polynomial form. But if you split it into numerator and denominator you can check for the roots of the numerator:
>>> n, d = eq.as_numer_denom()
>>> from sympy import real_roots
>>> real_roots(n)
[CRootOf(x**3 + x**2 - 1, 0)]
So there is only one real root for that expression, the one that nroots gave you.
Note: the answer that solve gives is an exact solution to the cubic equation and it can't figure out definitively which ones are a solution to the equation so it returns all three. If you evaluate them you will find that only one of them is real. But since you don't need the symbolic solution, just stick to nroots.

if condition using sympy equation solver/ sympy very slow

I want to solve this equation witht the following parameters:
gamma = 0.1
F = 0.5
w = 0
A = symbols('A')
a = 1 + w**4 -w**2 + 4*(gamma**2)*w**2
b = 1 - w**2
sol = solve(a*A**2 + (9/16)*A**6 + (3/2)*b*A**4 -F**2)
list_A = []
for i in range(len(sol)):
if(type( solutions[i] )==float ):
print(sol[i])
list_A = sol[i]
However, as supposed, I am getting some real and complex values, and I want to remove the complex ones and only keep the floats. But this condition I implemented is not valid due to the type of sol[i] is either sympy.core.add.Add for complex or sympy.core.numbers.Float for floats.
My question is, how can I modify my condition so that it works for getting only the float values?
In addition, is there a way to speed it up? it is very slow if I put it in a loop for many values of omega.
this is my first time working with sympy
When it is able to validate solutions relative to assumptions on symbols, it will; so if you tell SymPy that A is real then -- if it can verify the solutions -- it will only show the real ones:
>>> A = symbols('A',real=True)
>>> sol = solve(a*A**2 + (9/16)*A**6 + (3/2)*b*A**4 -F**2)
>>> sol
[-0.437286658108243, 0.437286658108243]

Solving quad root equation in sympy

I'm trying to solve the following equation.
(x * x) - 1 = 0
The result should be +1 or -1. But when I try to solve it via sympy, the result is an empty output.
import sympy as sy
x = sy.Symbol('x')
sy.solve((x**2)-1, 0)
# sy.solve((x * x)-1, 0) and sy.solve((x * x), 1) returns the same result
>>> []
What am I doing wrong here?
You should use,
sy.solve((x**2)-1,x)
Instead of,
sy.solve((x**2)-1,0)
The second argument x suggests that the equation should be solved for x. You are solving the equation for 0 which makes no sense.
Carefully read the documentation in the future :)
It is supposed to be
>>> from sympy.solvers import solve
>>> from sympy import Symbol
>>> x = Symbol('x')
>>> solve(x**2 - 1, x)
Read the documentation for the function here
Either do
sp.solve((x**2)-1, x)
or
sp.solve((x**2) - 1)
For further information, you can check out https://docs.sympy.org/latest/modules/solvers/solvers.html
In nsolve the second argument is an initial guess for the value of the variable that will make the univariate expression equal to zero:
>>> nsolve(x**2-1, 0)
1.00000000000000
>>> nsolve(x**2-1, -3)
-1.00000000000000
In solve, however, an initial guess is not needed since the equation will be solved symbolically:
>>> nsolve(x**2-1)
[-1, 1]
But solve can also handle multivariate expressions and in that case the second argument is used to indicate which variable you want to solve for.
>>> solve(x**2-c)
[{c: x**2}]
>>> solve(x**2-c, x)
[-sqrt(c), sqrt(c)]
But you can solve for anything that appears in the expression, even numbers. That's why an error is not raised in your case (though perhaps zero should raise an error). Here are examples of solving for a number:
>>> solve(3*x**2-c, 3)
[c/x**2]
>>> solve(3*x**4-c, 4)
[log(c/3)/log(x)]
>>> solve(2*x**2-c, 2)
[LambertW(c*log(x))/log(x)]

Python: Initiate integer without specifying value

Not sure why I can't find something on this but here's my question:
How do I initiate an integer without giving it a value so I can use it to solve equations.
E.g., if I specified that I had some integer x then I could write something that allows me to solve functions with respect to x.
E.g., an output might be: 2x+5
EX:
# Eisenstein Prime?
# 1J is complex number i
def eisenstein(a,b):
w = e**((2*math.pi*1J)/3)
z=a+b*w
a = a+b*(w**2)
print("Eisenstein Integer as z:")
print(z)
print("Omega as w:")
print(w)
This outputs:
Eisenstein Integer as z:
(-0.9999999999999987+5.196152422706632j)
Omega as w:
(-0.4999999999999998+0.8660254037844387j)
I'd like to have the variable similar to how j appears above.
You can't do that with plain ints. You'll need to install a package for symbolic mathematics.
python -m pip install sympy
Then to use it,
import sympy as sp
x = sp.var('x')
equation = 2*x + 5
print(sp.solve([equation], [x]))
Output:
{x: -5/2}
The solver takes lists because it can do systems of equations. You can also just
sp.solve(equation, x)
And get
[-5/2]
Another example.
import sympy as sp
x, y = sp.var('x y')
equation = 2*x + 5*y # Equations made this way are implicitly "= 0".
print(sp.solveset(equation, y, sp.S.Complexes))
Solved for y, note the output is in terms of x:
{-2*x/5}

Enforce custom ordering on Sympy print

SymPy does a wonderful work keeping track of all the operations I do to my symbolic expressions. But a the moment of printing the result for latex output I would like to enforce a certain ordering of the term. This is just for convention, and unfortunately that convention is not alphabetical on the symbol name(as reasonably sympy does)
import sympy as sp
sp.init_printing()
U,tp, z, d = sp.symbols('U t_\perp z d')
# do many operations with those symbols
# the final expression is:
z+tp**2+U+U/(z-3*tp)+d
My problem is that SymPy presents the expression ordered as
U + U/(-3*t_\perp + z) + d + t_\perp**2 + z
But this ordering is not the convention in my field. For us z has to be the leftmost expression, then tp, then U even if it is capitalized, d is the most irrelevant and is put at the right. All this variables hold a particular meaning and that is the reason we write them in such order, and the reason in the code variables are named in such way.
I don't want to rename z to a and as suggested in Prevent Sympy from rearranging the equation and then at the moment of printing transform that a into z. In Force SymPy to keep the order of terms there is a hint I can write a sorting function but I could not find documentation about it.
If you can put the terms in the order you want then setting the order flag for the Latex printer to 'none' will print them in that order.
>>> import sympy as sp
>>> sp.init_printing()
>>> U,tp, z, d = sp.symbols('U t_\perp z d')
>>> eq=z+tp**2+U+U/(z-3*tp)+d
Here we put them in order (knowing the power of tp is 2) and rebuild as an Add with evaluate=False to keep the order unchanged
>>> p = Add(*[eq.coeff(i)*i for i in (z, U, tp**2, d)],evaluate=False)
And now we print that expression with a printer instance with order='none':
>>> from sympy.printing.latex import LatexPrinter
>>> s=LatexPrinter(dict(order='none'))
>>> s._print_Add(p)
z + U \left(1 + \frac{1}{z - 3 t_\perp}\right) + t_\perp^{2} + d

Categories

Resources