-
Notifications
You must be signed in to change notification settings - Fork 27
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
Add roots, complex_roots and real_roots #62
Comments
Is this a problem because of refactoring (like a cyclic import)? I guess Perhaps e.g. Asking the user to convert to |
By default, This is supported explicitly by the generics system (though not all conversions have been implemented). In
|
The generics system in FLINT3 is really beautiful. Potentially the reworking into submodules in #61 ties in really nicely with the generics from FLINT3, as we can have these as parent classes of specific types. For now what I've marked ready should be "fine" but it's really only baby steps to something which hopefully is more modular and easier to develop. |
Does Flint already have functions for computing these? I didn't see anything in the docs for Is there a more efficient method than just calling I would have thought that linear factors could be found more efficiently somehow than by computing a full factorisation. |
Within the generics system Such code ought to be factored out to dedicated functions at least for the most common cases (e.g.
Yes, this is definitely possible. There is such root-finding code for |
If it is causing refactoring problems then I think that it is fine to just remove the I suggest adding a CHANGELOG section in the README file with a section for version |
Yeah. We can even have a depreciated function for flint_poly.roots() which points to the right way to use acb.roots() |
Just to add to this, the method of python-flint/src/flint/fmpz_poly.pyx Lines 323 to 368 in da48588
|
Yes, that code ought to be changed. |
I was looking at the docs and found that, for example, fmpz_poly has methods to find complex and real roots but not integer roots? https://flintlib.org/doc/fmpz_poly.html Are integer roots a Flint3 thing? Not sure how to progress best with this issue |
A complete factorisation algorithm can always find roots in the ground domain of any polynomial. Both |
Haha I just returned to this issue to say I realised this. I'll work on a naive implementation which returns a list of the (negative of) the constant coefficient of each linear factor and then we can also expose real_roots() and complex_roots() |
Looks like we have Types were these methods do not make sense should raise something like DomainError rather than In [3]: nmod_poly([1, 1], 10).complex_roots()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[3], line 1
----> 1 nmod_poly([1, 1], 10).complex_roots()
File flint/flint_base/flint_base.pyx:262, in flint.flint_base.flint_base.flint_poly.complex_roots()
AttributeError: Complex roots are not supported for this polynomial |
acb_poly
for method definition
Maybe we can go through in a new PR and add failures for the real roots and make sure the error raised is DomainError then? |
Yes, that sounds right. |
I left some comments about There are two things to consider:
In [12]: acb_poly([1, 0, -1]).roots()
Out[12]: [-1.00000000000000, 1.00000000000000]
In [13]: fmpz_poly([1, 0, -1]).roots()
Out[13]: [(1, 1), (-1, 1)] It isn't possible to handle multiplicity correctly for |
Another issue is about overlapping roots: In [3]: r1 = 10**100
In [4]: r2 = 10**100 + 1
In [5]: x = fmpz_poly([0, 1])
In [6]: p = (x - r1)*(x - r2)**2
In [7]: p.complex_roots()
Out[7]:
[([1.00000000000000e+100 +/- 3e+81], 1),
([1.00000000000000e+100 +/- 3e+81], 2)]
In [8]: [(rr1, _), (rr2, _)] = p.complex_roots()
In [9]: rr1.overlaps(rr2)
Out[9]: True Ideally these roots would be refined until they no longer overlap but since they come from distinct square free factors that doesn't happen. If the multiplicities are equal then it should be possible to distinguish them: In [10]: p = (x - r1)*(x - r2)
In [11]: [(rr1, _), (rr2, _)] = p.complex_roots()
In [12]: rr1.overlaps(rr2)
Out[12]: False I guess that is why we want to use Maybe we need to take the square-free part (radical) of the polynomial and use that to compute the roots but then identify each root with a square-free factor of known multiplicity somehow (e.g. by evaluating each factor at each root, but then might need to increase precision...). |
This approach can be used to handle multiplicity of different roots while ensuring that they don't overlap. This is for from flint import *
def complex_roots(p, prec=None):
return _roots(p, prec, real=False)
def real_roots(p, prec=None):
return _roots(p, prec, real=True)
def _roots(p, prec, real):
"""Real roots of an fmpz_poly."""
if prec is None:
prec = ctx.prec
_, fac = p.factor_squarefree()
rad = p / p.gcd(p.derivative())
while True:
roots = _get_roots(fac, rad, prec, real)
if roots is not None:
return roots
prec *= 2
def _get_roots(fac, rad, prec, real):
"""Get real roots from squarefree factors and radical.
If prec is not high enough returns None.
"""
oldprec = ctx.prec
ctx.prec = prec
# Current implementation except should be simplified
# to avoid factorisation.
complex_roots = rad.complex_roots()
# prec affects rad.complex_roots() and f(r)
# May as well use a higher precision for f(r)
ctx.prec *= 2
roots = []
for r, m_ in complex_roots:
assert m_ == 1
if real and not r.imag.overlaps(0):
break
elif real:
r = r.real
roots.append(r)
roots_mult = []
for r in roots:
factor_already_found = False
for f, m in fac:
if f(r).overlaps(0):
if factor_already_found:
# Could be a root of two factors...
return None
else:
factor_already_found = True
roots_mult.append((r, m))
ctx.prec = oldprec
return roots_mult I don't know if there is some better way than this. Of course there should be a shortcut for the case where the original polynomial has only one square-free factor. |
The
flint_poly
is a child class offlint_elem
and is used to build other polynomial types on top of, however,flint_poly
has a methodroots()
which converts the self toacb
type, which I assume is not the intension.Suggestion is to remove this method and include it to
acb
if needed.python-flint/src/flint/pyflint.pyx
Lines 215 to 220 in 71bf110
The text was updated successfully, but these errors were encountered: