diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index adc4d37876b..b81a9193f18 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -91,7 +91,10 @@ import polynomial_fateman from sage.rings.integer cimport Integer from sage.rings.ideal import is_Ideal +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing +from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing +from sage.misc.cachefunc import cached_function from sage.categories.map cimport Map from sage.categories.morphism cimport Morphism @@ -4891,8 +4894,8 @@ cdef class Polynomial(CommutativeAlgebraElement): .. note:: - Uses the identity `R_n(f) := (-1)^(n (n-1)/2) R(f, - f') a_n^(n-k-2)`, where `n` is the degree of self, + Uses the identity `R_n(f) := (-1)^{n (n-1)/2} R(f, + f') a_n^{n-k-2}`, where `n` is the degree of self, `a_n` is the leading coefficient of self, `f'` is the derivative of `f`, and `k` is the degree of `f'`. Calls :meth:`.resultant`. @@ -4971,10 +4974,41 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R. = PolynomialRing(Qp(2)) sage: (s^2).discriminant() 0 + + TESTS: + + This was fixed by :trac:`16014`:: + + sage: PR. = QQ[] + sage: PRmu. = PR[] + sage: E1 = diagonal_matrix(PR, [1, b^2, -b^2]) + sage: M = matrix(PR, [[1,-t1,x1-t1*y1],[t1,1,y1+t1*x1],[0,0,1]]) + sage: E1 = M.transpose()*E1*M + sage: E2 = E1.subs(t1=t2, x1=x2, y1=y2) + sage: det(mu*E1 + E2).discriminant().degrees() + (24, 12, 12, 8, 8, 8, 8) + + This addresses an issue raised by :trac:`15061`:: + + sage: R. = PowerSeriesRing(QQ) + sage: F = R([1,1],2) + sage: RP. = PolynomialRing(R) + sage: P = x^2 - F + sage: P.discriminant() + 4 + 4*T + O(T^2) """ + # Late import to avoid cyclic dependencies: + from sage.rings.power_series_ring import is_PowerSeriesRing if self.is_zero(): return self.parent().zero_element() n = self.degree() + base_ring = self.parent().base_ring() + if (is_MPolynomialRing(base_ring) or + is_PowerSeriesRing(base_ring)): + # It is often cheaper to compute discriminant of simple + # multivariate polynomial and substitute the real + # coefficients into that result (see #16014). + return universal_discriminant(n)(list(self)) d = self.derivative() k = d.degree() @@ -7354,6 +7388,42 @@ cdef class Polynomial_generic_dense(Polynomial): def make_generic_polynomial(parent, coeffs): return parent(coeffs) +@cached_function +def universal_discriminant(n): + r""" + Return the discriminant of the 'universal' univariate polynomial + `a_n x^n + \cdots + a_1 x + a_0` in `\ZZ[a_0, \ldots, a_n][x]`. + + INPUT: + + - ``n`` - degree of the polynomial + + OUTPUT: + + The discriminant as a polynomial in `n + 1` variables over `\ZZ`. + The result will be cached, so subsequent computations of + discriminants of the same degree will be faster. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polynomial_element import universal_discriminant + sage: universal_discriminant(1) + 1 + sage: universal_discriminant(2) + a1^2 - 4*a0*a2 + sage: universal_discriminant(3) + a1^2*a2^2 - 4*a0*a2^3 - 4*a1^3*a3 + 18*a0*a1*a2*a3 - 27*a0^2*a3^2 + sage: universal_discriminant(4).degrees() + (3, 4, 4, 4, 3) + + .. SEEALSO:: + :meth:`Polynomial.discriminant` + """ + pr1 = PolynomialRing(ZZ, n + 1, 'a') + pr2 = PolynomialRing(pr1, 'x') + p = pr2(list(pr1.gens())) + return (1 - (n&2))*p.resultant(p.derivative())//pr1.gen(n) + cdef class ConstantPolynomialSection(Map): """ This class is used for conversion from a polynomial ring to its base ring.