@@ -2200,7 +2200,7 @@ cdef class Polynomial(CommutativePolynomial):
2200
2200
# If you are reaching this error, chances are there's a bug in the code.
2201
2201
raise AssertionError (f" no splitting of degree {degree} found for {self}" )
2202
2202
2203
- def _any_irreducible_factor_squarefree (self , degree = None ):
2203
+ def _any_irreducible_factor_squarefree (self , degree = None , ext_degree = None ):
2204
2204
"""
2205
2205
Helper function for any_irreducible_factor which computes
2206
2206
an irreducible factor from self, assuming the input is
@@ -2210,10 +2210,13 @@ cdef class Polynomial(CommutativePolynomial):
2210
2210
of self and then finds a factor with Cantor-Zassenhaus
2211
2211
splitting.
2212
2212
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
2215
2215
is found.
2216
2216
2217
+ If ext_degree is not ``None``, then only irreducible factors whose
2218
+ degree divides ``ext_degree`` are returned.
2219
+
2217
2220
EXAMPLES::
2218
2221
2219
2222
sage: # needs sage.rings.finite_rings
@@ -2262,10 +2265,13 @@ cdef class Polynomial(CommutativePolynomial):
2262
2265
2263
2266
# Otherwise we use the smallest possible d value
2264
2267
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)
2266
2272
raise ValueError (f" no irreducible factor could be computed from {self}" )
2267
2273
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 ):
2269
2275
"""
2270
2276
Return an irreducible factor of this polynomial.
2271
2277
@@ -2286,6 +2292,11 @@ cdef class Polynomial(CommutativePolynomial):
2286
2292
this polynomial is assumed to be the product of irreducible
2287
2293
polynomials of degree equal to ``degree``.
2288
2294
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
+
2289
2300
EXAMPLES::
2290
2301
2291
2302
sage: # needs sage.rings.finite_rings
@@ -2399,15 +2410,15 @@ cdef class Polynomial(CommutativePolynomial):
2399
2410
if assume_squarefree:
2400
2411
if assume_distinct_deg:
2401
2412
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 )
2403
2414
2404
2415
# Otherwise we compute the squarefree decomposition and check each
2405
2416
# polynomial for a root. If no poly has a root, we raise an error.
2406
2417
SFD = self .squarefree_decomposition()
2407
2418
SFD.sort()
2408
2419
for poly, _ in SFD:
2409
2420
try :
2410
- return poly._any_irreducible_factor_squarefree(degree)
2421
+ return poly._any_irreducible_factor_squarefree(degree, ext_degree )
2411
2422
except ValueError :
2412
2423
pass
2413
2424
@@ -2586,38 +2597,34 @@ cdef class Polynomial(CommutativePolynomial):
2586
2597
except ValueError :
2587
2598
raise ValueError (f" no root of polynomial {self} can be computed" )
2588
2599
return - f[0 ] / f[1 ]
2600
+
2589
2601
# When we have a ring, then we can find an irreducible factor of degree `d` providing
2590
2602
# 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 :
2620
2607
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)
2621
2628
2622
2629
# The old version of `any_root()` allowed degree < 0 to indicate that the input polynomial
2623
2630
# had a distinct degree factorisation, we pass this to any_irreducible_factor as a bool and
0 commit comments