Note that you used i
to indicate the imaginary number, but in SymPy it is I
.
The reason you see that error is because findroot
requires a numerical function, but you passed in a symbolic expression. You could use lambdify
to convert f
to a numerical function, but we can get away with a different procedure instead.
You could try to use solve
or solveset
, but it is not guaranteed that they find all roots. For example:
sol = solve(f, omega)
sol = [s.n() for s in sol]
for s in sol:
print(s)
# out:
# -0.92071676505822 + 0.74526156471082*I
# 0.92071676505822 + 0.74526156471082*I
# 1.13988532510002 + 0.19223843528918*I
# -1.13988532510002 + 0.19223843528918*I
In this case, we can create a 3D plot with the magnitude of the function and verify that all zeros have been found. To do that, I'm going to use this plotting module:
from spb import *
l = 2
plot_complex(log(f), (omega, -l-l*1j, l+l*1j), n=500,
zlabel="log(abs(f))", threed=True, backend=KB)

The downward spikes are the zeros. The upward spikes are the poles. We can count 4 zeros, which match what solve
found.
Now, let's talk about SymPy's nsolve
(numerical solver), which is going to use mpmath's findroot
: by providing appropriate initial guesses, we can use nsolve
to find the roots. To find appropriate initial guesses, I'm going to plot the magnitude of the complex function:
p1 = plot_complex(f, (omega, -l-l*1j, l+l*1j), {"interpolation": "spline36"},
coloring="e", grid=False, n=1000)

These zebra-stripes represents the magnitude: they are circling around the zeros and poles. In this kind of plot, we can't distinguish between them, however we can obtain a initial guess for nsolve
. For example:
s1 = nsolve(f, omega, -1+0.25j)
s2 = nsolve(f, omega, 1+0.25j)
s3 = nsolve(f, omega, -0.9+0.75j)
s4 = nsolve(f, omega, 0.9+0.75j)
p2 = plot_complex_list([s1, s2, s3, s4], {"marker": "^", "color": "r"}, show=False)
(p1 + p2).show()

This last picture overlays the solutions to the previous plot. If you try to use nsolve
, you'll soon discover that it is very sensitive to the initial guess, in particular for complex functions where, as you can see from the 3D plot, the spatial distance between a zero and a pole might be very small. This means that saddle points might force the algorithm to fall into the same root even with very different initial guesses.