@@ -2560,22 +2560,65 @@ cdef class Polynomial(CommutativePolynomial):
2560
2560
return rs[0 ]
2561
2561
raise ValueError (f" polynomial {self} has no roots" )
2562
2562
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():
2567
2568
try :
2568
- self = self .change_ring(ring)
2569
+ f = self .change_ring(ring)
2569
2570
except ValueError :
2570
2571
raise (f" cannot coerce polynomial {self} to the new ring: {ring}" )
2572
+ return f.any_root()
2571
2573
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 " )
2577
2579
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}" )
2579
2622
2580
2623
# The old version of `any_root()` allowed degree < 0 to indicate that the input polynomial
2581
2624
# had a distinct degree factorisation, we pass this to any_irreducible_factor as a bool and
@@ -2617,11 +2660,8 @@ cdef class Polynomial(CommutativePolynomial):
2617
2660
# FiniteField type if the base field is a non-prime field,
2618
2661
# so this slower option is chosen to ensure the root is
2619
2662
# over explicitly a FiniteField type.
2620
- ring = self .base_ring().extension(f. degree() , names = " a" )
2663
+ ring = self .base_ring().extension(degree, names = " a" )
2621
2664
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.
2625
2665
f = f.change_ring(ring)
2626
2666
return f.any_root()
2627
2667
0 commit comments