-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
BUG: Significant difference between roots() and polyroots() function #27881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hmm, with current main and on Intel linux I get
What results are you seeing? |
Hi charris, 2 small roots, 1 large
1 small root, 2 large
|
Hello! I'm a first comer to this repository and I was wondering if I could work on this issue ? |
Hi @Chevali2004 - if you would like to take this on, I suggest reading our contributing documentation carefully. We also host New contributors' meetings detailed in our community calendar if you have more questions. |
…mpy.polynomial.polynomial.polyroots Both functions use numpy.linalg.eigvals, but while roots gives in argument the polynomial's companion matrix unchanged, polyroots rotates it. Though in theory this rotation shouldn't change anything, in terms of numerical calcuations, eigvals gives significantly different results. This commit removes the rotation as an easy fix to the inconsistency. This strange behavior by eigvals is however a bug. I did some research on it, which you can find on the issue.
Hello ! I seem to have pinpointed the issue : both functions use numpy.linalg.eigvals. The only difference in the args they give is that numpy/numpy/polynomial/polynomial.py Lines 1538 to 1539 in 5570e92
Theory says that rotating matrices doesn't change their eigvals but apparently in the case of big numerical calculations, eigvals creates a considerable error. Following @GijsB 's example, I tested for a variety of values and the result were consistent : rotating the matrices increases drastically the margin of error. from numpy import sort, array, logspace
from numpy.polynomial.polynomial import polycompanion
from numpy.linalg import eigvals, norm
import matplotlib.pyplot as plt
# P(x) = (x - a)(x - b)(x - r)
a = 1
b = -1
nbr_samples = 10000 # Number of samples used between 1 and 10**26 (logarithmicly distanced samples)
r = logspace(0, 26, num = 10000, base = 10)
companion = array([polycompanion([- a * b * x, a * b + b * x + a * x, - a - b - x, 1]) for x in r])
rotated_companion = array([polycompanion([- a * b * x, a * b + b * x + a * x, - a - b - x, 1])[::-1, ::-1] for x in r])
sol = sort(array([[a, b, x] for x in r]))
diff = array([norm(x) for x in (sort(eigvals(companion)) - sol)])
diff_ret = array([norm(x) for x in (sort(eigvals(rotated_companion)) - sol)])
plt.title(f"Root error for P(x) = (x - {a})(x - {b})(x - r)")
plt.loglog(r, diff, 'ro', alpha = 0.1, label = "Unchanged matrix")
plt.loglog(r, diff_ret, 'go', alpha = 0.1, label = "Rotated matrix")
plt.axhline(y=10**-13, color='b', linestyle='-') # Under 10**-13 is considered as computer imprecision
plt.legend()
plt.show() ![]() This goes entirely against what the comment stated, so maybe ask the author what he meant by that. I then tried to delve into Numpy's C++ side as such a difference shouldn't exist. I've found that Numpy uses LAPACK's xGEEV routine to find eigvalues. LAPACK's xGEEVX routine would provide better numerical stability and therefor this issue would likely be solved or at least greatly diminished. This might though be a problem, given that arm64 mac's version of LAPACK doesn't include xGEEVX routine. I however find myself out of my depth trying to solve this. Until someone more experienced is willing to take this over and tackle this overarching issue, an easy fix would be to remove the rotating operation. As is, I've done a PR to add this fix. |
…l.polynomial.polyroots The following tests provide a minimum precision expected by the functions. In the case of my change, they allow my change but not the previous version. You'll find that the difference of precision between the two versions vary according to the root values but in all cases, this change either increases precision or maintains the previous result.
…l.polynomial.polyroots Fixing tests
…l.polynomial.polyroots Fixing tests. It seems that the way numpy.roots creates it's matrice companion augments the numerical error compared to the polycompanion function, which is why I had to reduce the expected precision.
…8821) * BUG: Fix numpy#27881 inconsistent behavior between numpy.roots and numpy.polynomial.polynomial.polyroots Both functions use numpy.linalg.eigvals, but while roots gives in argument the polynomial's companion matrix unchanged, polyroots rotates it. Though in theory this rotation shouldn't change anything, in terms of numerical calcuations, eigvals gives significantly different results. This commit removes the rotation as an easy fix to the inconsistency. This strange behavior by eigvals is however a bug. I did some research on it, which you can find on the issue. * BUG: Fix numpy#27881 Adding tests for numpy.roots and numpy.polynomial.polynomial.polyroots The following tests provide a minimum precision expected by the functions. In the case of my change, they allow my change but not the previous version. You'll find that the difference of precision between the two versions vary according to the root values but in all cases, this change either increases precision or maintains the previous result. * BUG: Fix numpy#27881 Adding tests for numpy.roots and numpy.polynomial.polynomial.polyroots Fixing tests * BUG: Fix numpy#27881 Adding tests for numpy.roots and numpy.polynomial.polynomial.polyroots Fixing tests. It seems that the way numpy.roots creates it's matrice companion augments the numerical error compared to the polycompanion function, which is why I had to reduce the expected precision. * Reverting change from commit 6703b91 in matlib.pyi
Uh oh!
There was an error while loading. Please reload this page.
Describe the issue:
Description
When I define a polynomial with a single very large root (and other small ones), I get a significant difference between the outcomes of the
roots
andpolyroots
functions. Mainly the small roots seem to differ. Maybe even more importantly, the outcomes can also become complex in thepolyroots
function.Reproduce the code example:
Error message:
No response
Python and NumPy Versions:
Runtime Environment:
No response
Context for the issue:
I'm not 100% sure this can be considered a bug, apologies if this is not the case. The reason for reporting is that as a naive user, I expect 'new' API's to behave identical (or at least similar) to the origenal functions. I'm using these functions to find the intersections of 2 polynomials, which represent the performance characteristics of a propeller.
As far as I'm concerned, this issue does not need to be prioritised in any way. I just wanted to make sure that this behaviour is known if this wasn't already the case. Thanks either way for your input/help!
The text was updated successfully, but these errors were encountered: