SymPy returns no solution for a simple set of trigonometric equations

Viewed 74

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?

2 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.

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}]
Related