SymPy returns no solution for a simple set of trigonometric equations

Question:

I’m trying to solve the following equations:

cos(a) – cos(b) – 1 = 0

and

sin(a) – sin(b) = 0

Using SymPy I get no solutions for (a,b).

from sympy import symbols, sin, cos, solve, Eq

a, b = symbols("a b")
eq1 = Eq(cos(a) - cos(b) - 1, 0)
eq2 = Eq(sin(a) - sin(b), 0)
solve([eq1, eq2], [a, b])

However, there exists at least one solution:

a = 60°

b = 120°

Why can’t SymPy solve the set of trigonometric equations?

Asked By: Andy

||

Answers:

I think solve is not the best tool for this job. It probably fails because there could be many solutions. You can try to use nsolve to numerically solve the system. However, in your case it is really "finicky" on the initial guess. For example:

from sympy import *
a, b = symbols("a b")
eq1 = Eq(cos(a) - cos(b) - 1, 0)
eq2 = Eq(sin(a) - sin(b), 0)

nsolve((cos(a) - cos(b) - 1, sin(a) - sin(b)), [a, b], (0.5, 0.5))
# ZeroDivisionError: matrix is numerically singular

# one solution
nsolve((cos(a) - cos(b) - 1, sin(a) - sin(b)), [a, b], (0.5, 0.6))
# out: Matrix([[7.33038285837618], [8.37758040957278]]) # radians

# the solution you are looking for
nsolve((cos(a) - cos(b) - 1, sin(a) - sin(b)), [a, b], (0.5, 0.95))
# out: Matrix([[1.04719755119660], [2.09439510239320]])

EDIT to clarify comment:

Can you please explain what is the (0.5, 0.5) or (0.5,0.6) and (0.5, 0.95)? How did you arrive at those sets?

Those are the initial guesses that I provided to nsolve. If you have two equations (like in this example), one way to figure them out is to plot the zero-level contours of the equations and look for the intersection of the curves. For example:

import numpy as np
import matplotlib.pyplot as plt

aa, bb = np.mgrid[0:2*np.pi:100j, 0:2*np.pi:100j]
# NOTE: eq1.rewrite(Add) = eq1.lhs - eq1.rhs
f1 = lambdify([a, b], eq1.rewrite(Add))
f2 = lambdify([a, b], eq2.rewrite(Add))

plt.figure()
plt.contour(aa, bb, f1(aa, bb), levels=[0], cmap="hsv")
plt.contour(aa, bb, f2(aa, bb), levels=[0], cmap="Blues_r")
plt.xlabel("a")
plt.xlabel("b")
plt.grid()
plt.show()

enter image description here

With this method you can chose initial guesses very close to the actual solutions.

Answered By: Davide_sd

If you rewrite in terms of exp — and I thought solve did this automatically, but maybe only for a single equation — you get the solution:

>>> solve([i.rewrite(exp) for i in (cos(a) - cos(b) - 1,sin(a) - sin(b))]) 
[{a: pi/3, b: 2*pi/3}, {a: -I*log(-(-1)**(2/3)), b: -2*pi/3}]
Answered By: smichr
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.