Skip to content

Commit 732d3b3

Browse files
committed
Try and speed up any_root
1 parent 30b3d78 commit 732d3b3

File tree

1 file changed

+55
-15
lines changed

1 file changed

+55
-15
lines changed

src/sage/rings/polynomial/polynomial_element.pyx

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,22 +2560,65 @@ cdef class Polynomial(CommutativePolynomial):
25602560
return rs[0]
25612561
raise ValueError(f"polynomial {self} has no roots")
25622562

2563-
# When the degree is none, we only look for a linear factor
2564-
if degree is None:
2565-
# if a ring is given try and coerce the polynomial into this ring
2566-
if ring is not None:
2563+
# Ensure that a provided ring is appropriate for the function
2564+
if ring is not None:
2565+
# If the new ring is not a finite field, attempt to coerce the polynomial
2566+
# and call the function to use naive factoring
2567+
if not ring in FiniteFields():
25672568
try:
2568-
self = self.change_ring(ring)
2569+
f = self.change_ring(ring)
25692570
except ValueError:
25702571
raise(f"cannot coerce polynomial {self} to the new ring: {ring}")
2572+
return f.any_root()
25712573

2572-
# try and find a linear irreducible polynomial from f to compute a root
2573-
try:
2574-
f = self.any_irreducible_factor(degree=1, assume_squarefree=assume_squarefree)
2575-
except ValueError:
2576-
raise ValueError(f"no root of polynomial {self} can be computed")
2574+
# If the ring is a finite field, ensure it's an extension of the base ring
2575+
if self.base_ring().characteristic() != ring.characteristic():
2576+
raise ValueError("ring must have the same characteristic as the base ring")
2577+
if not self.base_ring().degree().divides(ring.degree()):
2578+
raise ValueError("ring must be an extension of the base ring")
25772579

2578-
return - f[0] / f[1]
2580+
# When the degree is none, we only look for a linear factor
2581+
if degree is None:
2582+
# When ring is None, we attempt to find a linear factor of self
2583+
if ring is None:
2584+
try:
2585+
f = self.any_irreducible_factor(degree=1, assume_squarefree=assume_squarefree)
2586+
except ValueError:
2587+
raise ValueError(f"no root of polynomial {self} can be computed")
2588+
return - f[0] / f[1]
2589+
# When we have a ring, then we can find an irreducible factor of degree `d` providing
2590+
# that d divides the degree of the extension from the base ring to the given ring
2591+
else:
2592+
allowed_extension_degree = ring.degree() // self.base_ring().degree()
2593+
for d in allowed_extension_degree.divisors():
2594+
try:
2595+
f = self.any_irreducible_factor(degree=d, assume_squarefree=assume_squarefree)
2596+
except ValueError:
2597+
continue
2598+
# When d != 1 we then find the smallest extension
2599+
# TODO: This is really annoying. What we should do here is compute some minimal
2600+
# extension F_ext = self.base_ring().extension(d, names="a") and find a
2601+
# root here and then coerce this root into the parent ring. This means we
2602+
# would work with the smallest possible extension.
2603+
# However, if we have some element of GF(p^k) and we try and coerce this to
2604+
# some element GF(p^(k*n)) this can fail, even though mathematically it
2605+
# should be fine. As a result, we simply coerce straight to the user supplied
2606+
# ring and find a root here.
2607+
# TODO: Additionally, if the above was solved, it would be faster to extend the base
2608+
# ring with the irreducible factor however, if the base ring is an extension
2609+
# then the type of self.base_ring().extension(f) is a Univariate Quotient Polynomial Ring
2610+
# and not a finite field. So we do the slower option here to ensure the type is
2611+
# maintained.
2612+
if not d.is_one():
2613+
f = f.change_ring(ring)
2614+
2615+
# Now we find the root of this irreducible polynomial over this extension
2616+
root = f.any_root()
2617+
return ring(root)
2618+
2619+
2620+
# If the loop ends and we returned nothing, then no root exists
2621+
raise ValueError(f"no root of polynomial {self} can be computed over the ring {ring}")
25792622

25802623
# The old version of `any_root()` allowed degree < 0 to indicate that the input polynomial
25812624
# had a distinct degree factorisation, we pass this to any_irreducible_factor as a bool and
@@ -2617,11 +2660,8 @@ cdef class Polynomial(CommutativePolynomial):
26172660
# FiniteField type if the base field is a non-prime field,
26182661
# so this slower option is chosen to ensure the root is
26192662
# over explicitly a FiniteField type.
2620-
ring = self.base_ring().extension(f.degree(), names="a")
2663+
ring = self.base_ring().extension(degree, names="a")
26212664

2622-
# Now we look for a linear root of this irreducible polynomial of degree `degree`
2623-
# over the user supplied ring or the extension we just computed. If the user sent
2624-
# a bad ring here of course there may be no root found.
26252665
f = f.change_ring(ring)
26262666
return f.any_root()
26272667

0 commit comments

Comments
 (0)