Skip to content

Commit 2569e61

Browse files
committed
Slightly more intelligent way to find correct degree irr
1 parent e3b12dd commit 2569e61

File tree

1 file changed

+43
-36
lines changed

1 file changed

+43
-36
lines changed

src/sage/rings/polynomial/polynomial_element.pyx

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,7 +2200,7 @@ cdef class Polynomial(CommutativePolynomial):
22002200
# If you are reaching this error, chances are there's a bug in the code.
22012201
raise AssertionError(f"no splitting of degree {degree} found for {self}")
22022202

2203-
def _any_irreducible_factor_squarefree(self, degree=None):
2203+
def _any_irreducible_factor_squarefree(self, degree=None, ext_degree=None):
22042204
"""
22052205
Helper function for any_irreducible_factor which computes
22062206
an irreducible factor from self, assuming the input is
@@ -2210,10 +2210,13 @@ cdef class Polynomial(CommutativePolynomial):
22102210
of self and then finds a factor with Cantor-Zassenhaus
22112211
splitting.
22122212
2213-
If degree is not None, then only irreducible factors of degree
2214-
`degree` are searched for, otherwise the smallest degree factor
2213+
If degree is not ``None``, then only irreducible factors of degree
2214+
``degree`` are searched for, otherwise the smallest degree factor
22152215
is found.
22162216
2217+
If ext_degree is not ``None``, then only irreducible factors whose
2218+
degree divides ``ext_degree`` are returned.
2219+
22172220
EXAMPLES::
22182221
22192222
sage: # needs sage.rings.finite_rings
@@ -2262,10 +2265,13 @@ cdef class Polynomial(CommutativePolynomial):
22622265

22632266
# Otherwise we use the smallest possible d value
22642267
for (poly, d) in self._distinct_degree_factorisation_squarefree():
2265-
return poly._cantor_zassenhaus_split_to_irreducible(d)
2268+
if ext_degree is None:
2269+
return poly._cantor_zassenhaus_split_to_irreducible(d)
2270+
elif ZZ(d).divides(ext_degree):
2271+
return poly._cantor_zassenhaus_split_to_irreducible(d)
22662272
raise ValueError(f"no irreducible factor could be computed from {self}")
22672273

2268-
def any_irreducible_factor(self, degree=None, assume_squarefree=False, assume_distinct_deg=False):
2274+
def any_irreducible_factor(self, degree=None, assume_squarefree=False, assume_distinct_deg=False, ext_degree=None):
22692275
"""
22702276
Return an irreducible factor of this polynomial.
22712277
@@ -2286,6 +2292,11 @@ cdef class Polynomial(CommutativePolynomial):
22862292
this polynomial is assumed to be the product of irreducible
22872293
polynomials of degree equal to ``degree``.
22882294
2295+
- ``ext_degree`` (None or positive integer) -- (default: ``None``).
2296+
Used for polynomials over finite fields. If not ``None`` only returns
2297+
irreducible factors of ``self`` whose degree divides ``ext_degree``.
2298+
Assumes that ``degree`` is ``None``.
2299+
22892300
EXAMPLES::
22902301
22912302
sage: # needs sage.rings.finite_rings
@@ -2399,15 +2410,15 @@ cdef class Polynomial(CommutativePolynomial):
23992410
if assume_squarefree:
24002411
if assume_distinct_deg:
24012412
return self._cantor_zassenhaus_split_to_irreducible(degree)
2402-
return self._any_irreducible_factor_squarefree(degree)
2413+
return self._any_irreducible_factor_squarefree(degree, ext_degree)
24032414

24042415
# Otherwise we compute the squarefree decomposition and check each
24052416
# polynomial for a root. If no poly has a root, we raise an error.
24062417
SFD = self.squarefree_decomposition()
24072418
SFD.sort()
24082419
for poly, _ in SFD:
24092420
try:
2410-
return poly._any_irreducible_factor_squarefree(degree)
2421+
return poly._any_irreducible_factor_squarefree(degree, ext_degree)
24112422
except ValueError:
24122423
pass
24132424

@@ -2586,38 +2597,34 @@ cdef class Polynomial(CommutativePolynomial):
25862597
except ValueError:
25872598
raise ValueError(f"no root of polynomial {self} can be computed")
25882599
return - f[0] / f[1]
2600+
25892601
# When we have a ring, then we can find an irreducible factor of degree `d` providing
25902602
# 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-
# If the loop ends and we returned nothing, then no root exists
2603+
allowed_extension_degree = ring.degree() // self.base_ring().degree()
2604+
try:
2605+
f = self.any_irreducible_factor(assume_squarefree=assume_squarefree, ext_degree=allowed_extension_degree)
2606+
except ValueError:
26202607
raise ValueError(f"no root of polynomial {self} can be computed over the ring {ring}")
2608+
# When d != 1 we then find the smallest extension
2609+
# TODO: This is really annoying. What we should do here is compute some minimal
2610+
# extension F_ext = self.base_ring().extension(d, names="a") and find a
2611+
# root here and then coerce this root into the parent ring. This means we
2612+
# would work with the smallest possible extension.
2613+
# However, if we have some element of GF(p^k) and we try and coerce this to
2614+
# some element GF(p^(k*n)) this can fail, even though mathematically it
2615+
# should be fine. As a result, we simply coerce straight to the user supplied
2616+
# ring and find a root here.
2617+
# TODO: Additionally, if the above was solved, it would be faster to extend the base
2618+
# ring with the irreducible factor however, if the base ring is an extension
2619+
# then the type of self.base_ring().extension(f) is a Univariate Quotient Polynomial Ring
2620+
# and not a finite field. So we do the slower option here to ensure the type is
2621+
# maintained.
2622+
if not f.degree().is_one():
2623+
f = f.change_ring(ring)
2624+
2625+
# Now we find the root of this irreducible polynomial over this extension
2626+
root = f.any_root()
2627+
return ring(root)
26212628

26222629
# The old version of `any_root()` allowed degree < 0 to indicate that the input polynomial
26232630
# had a distinct degree factorisation, we pass this to any_irreducible_factor as a bool and

0 commit comments

Comments
 (0)