Lecture 5: Complex and Algebraic Numbers

We have integer, rational, and irrational numbers. Among the irrational numbers, we distinguish between the algebraic and the transcendental numbers. An algebraic number is a root of a polynomial with integer coefficients. For a transcendental number, there does not exist a polynomial with integer coefficients that has that number as one of its roots. Complex numbers are special type algebraic numbers and merit separate treatment.

Sage knows the symbol I as the imaginary unit. While we may define I as the square root of negative one, this definition has its problems, as we then see when we cover algebraic numbers. A complex number is a special algebraic number and arises from the polynomial \(x^2 + 1\), which as no real root, or equivalently, \(x^2 + 1\) does not factor over the field of real numbers. The outcome of the factor command on a polynomial in one variable depends on the choice of coefficient field. We introduce finite fields, multiplication tables, and field extensions.

Complex Numbers

We could define the imaginary unit as the square root of -1 and we see that Sage represents sqrt(-1) with the symbol I.

print(sqrt(-1))
print(type(I))
print(I^2)

The I has type sage.symbolic.expression.Expression and its square evaluates to \(-1\).

In rectangular coordinates, complex numbers have a real part and an imaginary part.

x = 2/3 + 5*I; print(' x =', x, '|x| =', abs(x))
y = complex(2/3,5); print('y =', y, '|x| =', abs(y))
print('x has type', type(x))
print('y has type', type(y))

While x is considers as an expression, the y is the complex type of Python. As an expression, the real and imaginary part of a complex number may be any number type, whereas Python’s complex number is a tuple of two hardware floats.

An alternative to representing a complex number via its real and imaginary part (rectangular coordinates) is the polar representation as its absolute value and an argument. We first must make sure the number belongs to the Complex Double Field, abbreviated by CDF.

ax = CDF(x).argument(); rx = abs(x)
print(ax, rx, 'x =', complex(rx*(cos(ax) + I*sin(ax))))

and we recognize the rectangular representation of x as we defined x above.

Complex numbers are introduced so every polynomial with real coefficients of degree d has d roots, counted with multiplicities. By default, we get complex roots if we solve a polynomial equation. If we want to see the multiplicities of the roots, we must turn on the multiplicities flag.

var('z')
solve(z^2 + 4 == 0, z)
solve(z^2 - 2*z + 1 == 0, z, multiplicities=True)

Defining I as the square root of -1 has its problems, as we will try to illustrate next.

a = (-1 + I)^2; b = (1 - I)^2;

If we apply the sqrt() function to a and b we would expect to see -1 + I and 1 - I respectively. Instead we get sqrt(-2*I) in both cases. Why? Because, if we take a square root, we are solving a quadratic equation.

aq = z^2 - a == 0; bq = z^2 - b == 0;

The solution is \(\pm \sqrt{-2I}\). With the option all we get to see all square roots:

sqrt(a, all=True)

In contrast, we can also prevent evaluation, after coercing the argument of sqrt() to a symbolic ring, denoted by SR.

sqrt(SR(4), hold=True)

Algebraic Numbers

A square root is an algebraic number. The smallest polynomial that has an algebraic number as its root is the minimal polynomial. The command

sqrt(2).minpoly()

returns \(x^2 - 2\) as the minimal polynomial of \(\sqrt{2}\).

The outcome of the factoring of a polynomial depends on the number field.

print(factor(z^2 - 1))
print(factor(z^2 - 2))

The first command will print (z + 1)*(z - 1) whereas the second polynomial does factor and we get z^2 - 2 returned. If a polynomial does not factor over a specific number field (the default number field is the field of rational numbers), then we say that the polynomial is irreducible over that specific number field.

We can define a number field where c is the square root of 2, we can compute modulo the minimal polynomial of sqrt(2), that is c^2 - 2 = 0. We use c^2 = 2 to simplify expressions in c.

K.<c> = NumberField(x^2 - 2); print K
print(c^2 - 2)
print(c^3)

The defining polynomial of the number field K is x^2 - 2. In this number field, the expression c^2 - c evaluates to zero and c^3 simplifies to 2*c. If we now consider a polynomial ring over the number field K, then the polynomial x^2 - 2 will factor.

R.<x> = PolynomialRing(K)
p = x^2 - 2
factor(p)

On return we see (x - c) * (x + c).

In coding and cryptography we often work with finite fields.

k = GF(8,'c'); print(k)
e = [a for a in k]; print(e)

The GF is an abbreviation for Galois Field. This makes k a field of size \(2^3\) with elements

[0, c, c^2, c + 1, c^2 + c, c^2 + c + 1, c^2 + 1, 1]

In a field every element has a multiplicative inverse. We can see this in table of multiplications.

for x in e: [x*y for y in e]

The multiplication table is

[0, 0, 0, 0, 0, 0, 0, 0]
[0, c^2, c + 1, c^2 + c, c^2 + c + 1, c^2 + 1, 1, c]
[0, c + 1, c^2 + c, c^2 + c + 1, c^2 + 1, 1, c, c^2]
[0, c^2 + c, c^2 + c + 1, c^2 + 1, 1, c, c^2, c + 1]
[0, c^2 + c + 1, c^2 + 1, 1, c, c^2, c + 1, c^2 + c]
[0, c^2 + 1, 1, c, c^2, c + 1, c^2 + c, c^2 + c + 1]
[0, 1, c, c^2, c + 1, c^2 + c, c^2 + c + 1, c^2 + 1]
[0, c, c^2, c + 1, c^2 + c, c^2 + c + 1, c^2 + 1, 1]

Observe that, except for the first row, there is 1 in every row. Except for the first column, there is 1 in every column. To verify, let us look at the 1 in the second row.

print e[1], '* (', e[-2], ') =', e[1]*e[-2]

The output is c * ( c^2 + 1 ) = 1.

We can factor over finite fields. We make a polynomial ring with coefficients in the finite field we just constructed:

R.<x> = PolynomialRing(k)
p = x^3 + x + 1
factor(p)

which leads to (x + c) * (x + c^2) * (x + c^2 + c). Note that over the default field, the polynomial is irreducible.

q = z^3 + z + 1; factor(q)

To verify that the polynomial \(p = x^4 + 3 x + 4\) does not factor over the finite field of five elements, we do

R.<x> = PolynomialRing(GF(5))
p = x^4 + 3*x + 4; print factor(p)

We can then extend the field of five elements with a root of \(p\) as follows

F.<a> = GF(5).extension(p)
e = [n for n in F]; print e

Because the degree of \(p\) is four, every element in the field extension F can be expressed as a polynomial of degree three or less, because every fourth power of \(a\) simplifies via \(a^4 = 2 a + 1\). We have five choices for every coefficient of a degree three polynomials and since we can make those choices independently, we have a field with \(5^4\) elements. Over this field extension, we have a factorization.

R.<y> = PolynomialRing(F)
q = y^4 + 3*y + 4; print(factor(q))

Assignments

  1. The complex number \(z\) in polar representation is given by the radius (absolute value) \(r = 3\) and angle (argument) \(\theta = \pi/3\). Use Sage to find the exact (no floating-point) value of \(z\) in the form \(a + b I\).

  2. Execute solve(x^3 - 5 == 0, x) and show that all solutions of \(x^3 - 5 = 0\) are of the form \(\sqrt[3]{5} e^{I \theta}\), with \(\theta\) being either 0 or \(\pm \frac{2}{3} \pi\).

  3. Take the complex number \(z = 1 + I\) and let Sage compute \(\sqrt{1/z}\) and \(1/\sqrt{z}\). Are the results symbolically the same? Are the results numerically the same? Give reasons for your answers, illustrated with the appropriate Sage instructions.

  4. Use Sage to show that the polynomial \(p = x^4 + 3 x + 4\) is irreducible over the finite field with 5 elements. Declare \(z\) to be a root of \(p\) and express \(z^{13}\) as a polynomial in \(z\) of degree 4 (or less).

  5. Compute all irreducible polynomials of degree 2 over a field with 3 elements.