diff --git a/README.md b/README.md index 53707b52..c3ea4508 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,16 @@ CHANGELOG Next release (0.9.0)... ----------------------- +Contributors (0.9.0): + +- Rémy Oudompheng (RO) + +Changes (0.9.0): + +- [gh-312](https://github.com/flintlib/python-flint/pull/312), + Add `discriminant` method to `fmpz_poly`, `fmpq_poly` and + `nmod_poly`. (RO) + 0.8.0 ----- diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index d17da939..896ddf11 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -3045,6 +3045,9 @@ def setbad(obj, i, val): assert x.resultant(x**10 - x**5 + 1) == S(1) assert (x - 1).resultant(x**5 + 1) == S(2) + assert (x**5 + 1).discriminant() == S(3125) + assert (x**5 + 1).resultant(5 * x**4) == S(3125) + for k in range(-10, 10): assert x.resultant(x + S(k)) == S(k) diff --git a/src/flint/types/fmpq_poly.pyi b/src/flint/types/fmpq_poly.pyi index 20594e70..968d6219 100644 --- a/src/flint/types/fmpq_poly.pyi +++ b/src/flint/types/fmpq_poly.pyi @@ -73,6 +73,7 @@ class fmpq_poly(flint_poly[fmpq]): def truncate(self, n: int, /) -> fmpq_poly: ... def gcd(self, other: ifmpq_poly, /) -> fmpq_poly: ... + def discriminant(self) -> fmpq: ... def resultant(self, other: ifmpq_poly, /) -> fmpq: ... def xgcd(self, other: ifmpq_poly, /) -> tuple[fmpq_poly, fmpq_poly, fmpq_poly]: ... diff --git a/src/flint/types/fmpq_poly.pyx b/src/flint/types/fmpq_poly.pyx index dbf1c322..026ab99c 100644 --- a/src/flint/types/fmpq_poly.pyx +++ b/src/flint/types/fmpq_poly.pyx @@ -10,7 +10,8 @@ from flint.types.fmpz cimport any_as_fmpz from flint.flintlib.functions.fmpz cimport fmpz_is_zero from flint.flintlib.functions.fmpz cimport fmpz_set -from flint.flintlib.functions.fmpq cimport fmpq_is_zero +from flint.flintlib.functions.fmpz_poly cimport fmpz_poly_discriminant +from flint.flintlib.functions.fmpq cimport fmpq_is_zero, fmpq_set_fmpz_frac from flint.flintlib.functions.fmpq_poly cimport * from flint.flintlib.functions.arith cimport arith_bernoulli_polynomial from flint.flintlib.functions.arith cimport arith_euler_polynomial @@ -518,6 +519,34 @@ cdef class fmpq_poly(flint_poly): fmpq_poly_gcd(res.val, self.val, (other).val) return res + def discriminant(self): + """ + Return the discriminant of ``self``. + + >>> f = fmpq_poly([1, 2, 3, 4, 5, 6]) + >>> f.discriminant() + 1037232 + >>> f = fmpq_poly([1, 3, 5, 7, 9, 11, 13]) + >>> f.discriminant() + -2238305839 + >>> f = fmpq_poly([1, 3, 5, 7, 9, 11, 13], 10) + >>> f.discriminant() + -2238305839/10000000000 + + """ + # There is no FLINT function for the discriminant of a fmpq_poly, + # we use the fact that disc(f/q) = disc(f)/q^(2d-2) + cdef fmpq res = fmpq.__new__(fmpq) + cdef fmpz rnum = fmpz.__new__(fmpz) + cdef fmpz rden = self.denom()**(2 * self.degree() - 2) + + cdef fmpz_poly x = fmpz_poly.__new__(fmpz_poly) + fmpq_poly_get_numerator(x.val, self.val) + fmpz_poly_discriminant(rnum.val, x.val) + fmpq_set_fmpz_frac(res.val, rnum.val, rden.val) + + return res + def resultant(self, other): """ Returns the resultant of *self* and *other*. diff --git a/src/flint/types/fmpz_poly.pyi b/src/flint/types/fmpz_poly.pyi index a9d1528f..8f745809 100644 --- a/src/flint/types/fmpz_poly.pyi +++ b/src/flint/types/fmpz_poly.pyi @@ -62,6 +62,7 @@ class fmpz_poly(flint_poly[fmpz]): def gcd(self, other: ifmpz_poly, /) -> fmpz_poly: ... def content(self) -> fmpz: ... + def discriminant(self) -> fmpz: ... def resultant(self, other: ifmpz_poly, /) -> fmpz: ... def factor(self) -> tuple[fmpz, list[tuple[fmpz_poly, int]]]: ... def factor_squarefree(self) -> tuple[fmpz, list[tuple[fmpz_poly, int]]]: ... diff --git a/src/flint/types/fmpz_poly.pyx b/src/flint/types/fmpz_poly.pyx index 76e82d5f..659ad7b7 100644 --- a/src/flint/types/fmpz_poly.pyx +++ b/src/flint/types/fmpz_poly.pyx @@ -500,6 +500,22 @@ cdef class fmpz_poly(flint_poly): fmpz_poly_gcd(res.val, self.val, (other).val) return res + def discriminant(self): + """ + Return the discriminant of ``self``. + + >>> f = fmpz_poly([1, 2, 3, 4, 5, 6]) + >>> f.discriminant() + 1037232 + >>> f = fmpz_poly([1, 3, 5, 7, 9, 11, 13]) + >>> f.discriminant() + -2238305839 + + """ + cdef fmpz res = fmpz.__new__(fmpz) + fmpz_poly_discriminant(res.val, self.val) + return res + def resultant(self, other): """ Returns the resultant of *self* and *other*. diff --git a/src/flint/types/nmod_poly.pyi b/src/flint/types/nmod_poly.pyi index 2541a07e..43721968 100644 --- a/src/flint/types/nmod_poly.pyi +++ b/src/flint/types/nmod_poly.pyi @@ -61,6 +61,7 @@ class nmod_poly(flint_poly[nmod]): self, e: int, modulus: inmod_poly, mod_rev_inv: inmod_poly | None = None ) -> nmod_poly: ... def gcd(self, other: inmod_poly) -> nmod_poly: ... + def discriminant(self) -> nmod: ... def resultant(self, other: inmod_poly) -> nmod: ... def xgcd(self, other: inmod_poly) -> tuple[nmod_poly, nmod_poly, nmod_poly]: ... def factor( diff --git a/src/flint/types/nmod_poly.pyx b/src/flint/types/nmod_poly.pyx index b5422835..1f94b341 100644 --- a/src/flint/types/nmod_poly.pyx +++ b/src/flint/types/nmod_poly.pyx @@ -712,6 +712,22 @@ cdef class nmod_poly(flint_poly): nmod_poly_gcd(res.val, self.val, (other).val) return res + def discriminant(self): + """ + Return the discriminant of ``self``. + + >>> f = nmod_poly([1, 2, 3, 4, 5, 6], 65537) + >>> f.discriminant() + 54177 + >>> f = nmod_poly([1, 3, 5, 7, 9, 11, 13], 65537) + >>> f.discriminant() + 44859 + + """ + cdef nmod res = nmod(0, self.modulus()) + res.val = nmod_poly_discriminant(self.val) + return res + def resultant(self, other): """ Returns the resultant of *self* and *other*.