The discriminant

Background

Zeroes of polynomials

Recall that a rational function is a quotient of one polynomial by another. It is only defined for values at which its denominator is non-zero. Zeroes of polynomials are therefore essential in determining valid domains of definition for rational functions. A value \(x_0\) is a zero of a polynomial \(f(x)\) if

\[f(x_0) = 0. \]

Note

Recall that evaluation coincides with remainders of polynomial division. Hence if \(x_0\) is a zero of \(f(x)\) this is equivalent to stating \(f(x)\) is divisible by the polynomial \(x - x_0\). That is, \(f(x)\) is a multiple of \((x - x_0)\) and so is referred to as being in the “ideal” generated by \((x - x_0)\). The ring of remainders is \(\mathbb K[x]/(x -x_0)\) and in this ring \(f(x) \mapsto 0\), the zero polynomial.

To better understand the nature of zeroes of a polynomial, recall that polynomials are determing by their coefficients. Varying these coefficients in a suitable way should also result in varying the “location” of these zeroes. Above, with \(x_0\) the zero of the polynomial \(f(x)\), we can refer to \(x_0\) as a location of a zero.

The fundamental theorem of algebra states that any univariate polynomial of degree \(n\) has at most \(n\) many zeroes. If, in addition, the polynomial is complex (i.e., its coefficients are complex numbers) then there will be exactly \(n\) zeroes of the polynomial (counted with multiplicity).

Note

Phrased in another way, one says the field of complex numbers \(\mathbb C\) is algebraically closed. This is contrast to the field of real numbers which are emphatically not algebraically closed.

The discriminant

As mentioned above, varying the coefficients of a polynomial in some regular way ought to reveal important information on the nature of its zeroes. The process of “varying these coefficients” means to construct an analytic function of them. Ideally, we might hope that every instantiation of some function of a polynomial’s coefficients might return a location of a zero. This is generally too much to hope for however.

Yet some partial information may be gleaned from the construction of the discriminant. For the purposes of this document it sufficies to know that the discriminant is an analytic function (in fact, a multivariate polynomial) of the coefficients of a polynomial. It is obtained as a multiple of the resultant of a polynomial and its derivative. For more details and further material on the discriminant see this Wikipedia article.

Library imports

The discriminant method is callable on the class Poly. The following is the appropriate library import.

from class_scripts import polynomial as pnml

The discriminant

The Sylvester matrix

En route to forming the discriminant of any univariate polynomial is the Sylvester matrix and its determinant. For two univariate polynomials \(f(x), g(x)\) of degrees \(d, e\), the Sylvester matrix is a square, \((d + e)\times (d + e)\) dimensional matrix made up of the coefficients of \(f, g\). See this entry for the Sylvester matrix of two polynomials.

The class Poly in the module polynomial.py contains the method SylvesterMatrix(). This passes two instances of Poly and returns their Sylvester matrix. As an illustration, consider the following polynomials

\[ \begin{align} f(x) = -2 + x + 3x^3 + x^5 && \mbox{and} && g(x) = x + 3x^2 - 4x^4 - 2x^6. \end{align} \]

Their Sylvester matrix is:

poly_f = pnml.Poly([-2, 1, 0, 3, 0, 1])
poly_g = pnml.Poly([0, 1, 3, 0, -4, 0, -2])

print(poly_f.SylvesterMatrix(poly_g))
[[-2, 1, 0, 3, 0, 1, 0, 0, 0, 0, 0], [0, -2, 1, 0, 3, 0, 1, 0, 0, 0, 0], [0, 0, -2, 1, 0, 3, 0, 1, 0, 0, 0], [0, 0, 0, -2, 1, 0, 3, 0, 1, 0, 0], [0, 0, 0, 0, -2, 1, 0, 3, 0, 1, 0], [0, 0, 0, 0, 0, -2, 1, 0, 3, 0, 1], [0, 1, 3, 0, -4, 0, -2, 0, 0, 0, 0], [0, 0, 1, 3, 0, -4, 0, -2, 0, 0, 0], [0, 0, 0, 1, 3, 0, -4, 0, -2, 0, 0], [0, 0, 0, 0, 1, 3, 0, -4, 0, -2, 0], [0, 0, 0, 0, 0, 1, 3, 0, -4, 0, -2]]

In more readable format:

for row in poly_f.SylvesterMatrix(poly_g):
    print(row)
[-2, 1, 0, 3, 0, 1, 0, 0, 0, 0, 0]
[0, -2, 1, 0, 3, 0, 1, 0, 0, 0, 0]
[0, 0, -2, 1, 0, 3, 0, 1, 0, 0, 0]
[0, 0, 0, -2, 1, 0, 3, 0, 1, 0, 0]
[0, 0, 0, 0, -2, 1, 0, 3, 0, 1, 0]
[0, 0, 0, 0, 0, -2, 1, 0, 3, 0, 1]
[0, 1, 3, 0, -4, 0, -2, 0, 0, 0, 0]
[0, 0, 1, 3, 0, -4, 0, -2, 0, 0, 0]
[0, 0, 0, 1, 3, 0, -4, 0, -2, 0, 0]
[0, 0, 0, 0, 1, 3, 0, -4, 0, -2, 0]
[0, 0, 0, 0, 0, 1, 3, 0, -4, 0, -2]

As printed above, see that the Sylvester matrix is indeed square and of the correct dimensions. Typically at least one of \(d, e\) are strictly greater than zero. If \(d = 0\) and \(e = 0\), the Sylvester matrix is empty.

Note

Printing pnml.Poly.SylvesterMatrix(poly_f, poly_g) would also return the Sylvester matrix of poly_f and poly_g.

Resultants

The Sylvester matrix is a square matrix and therefore unambiguously defines a determinant. The determinant of the Sylvester matrix of two polynomials is called the resultant of two polynomials. It is callable on instances of Poly. For the polynomials \(f(x), g(x)\) above, their resultant is:

print(round(poly_f.resultant(poly_g), 4))
1798.0

Discriminant

Note that two polynomials of any degrees \(d, e\) respectively can be combined to form the resultant. To any polynomial \(f(x)\) recall that its derivative \(f^\prime(x)\) is also a polynomial. From the Wikipedia entry, the discriminant of \(f(x)\) is a multiple of the resultant of \(f(x)\) and its derivative \(f^\prime(x)\). More precisely:

\[\mathrm{Discriminant}~f(x) = \frac{(-1)^{\frac{1}{2}n(n-1)}}{a_n} \mathrm{Resultant}(f(x), f^\prime(x)) \]

where \(n\) is the degree of \(f\) and \(a_n\) is its leading coefficient (the coefficient of \(x^n\)).

Note

The resultant is polynomial in the coefficients of \(f\). It is not clear a priori that the discriminant is polynomial in the coefficients however since it is obtained by dividing through by \(a_n\). An alternate representation of the discriminant in terms of roots of the polynomial \(f(x)\) shows that it will indeed be polynomial.

On a polynomial \(f(x)\) we can called the method discriminant() to return its discriminant. For our example polynomials \(f(x), g(x)\) from above their discriminants are:

print(f"The discriminant of {poly_f} is: {poly_f.discriminant()}")
print(f"The discrminant of {poly_g} is: {poly_g.discriminant()}")
The discriminant of -2x^0 + 1x^1 + 3x^3 + 1x^5  is: 82176.0
The discrminant of 1x^1 + 3x^2 - 4x^4 - 2x^6  is: 155984.0