Orders and Relative Extensions

Orders in Number Fields

An order in a number field \(K\) is a subring of \(K\) whose rank over \(\ZZ\) equals the degree of \(K\). For example, if \(K=\QQ(\sqrt{-1})\), then \(\ZZ[7i]\) is an order in \(K\). A good first exercise is to prove that every element of an order is an algebraic integer.

sage: K.<I> = NumberField(x^2 + 1)
sage: R = K.order(7*I)
sage: R
Order of conductor 7 generated by 7*I
 in Number Field in I with defining polynomial x^2 + 1
sage: R.basis()
[1, 7*I]
>>> from sage.all import *
>>> K = NumberField(x**Integer(2) + Integer(1), names=('I',)); (I,) = K._first_ngens(1)
>>> R = K.order(Integer(7)*I)
>>> R
Order of conductor 7 generated by 7*I
 in Number Field in I with defining polynomial x^2 + 1
>>> R.basis()
[1, 7*I]

Using the discriminant command, we compute the discriminant of this order

sage: factor(R.discriminant())
-1 * 2^2 * 7^2
>>> from sage.all import *
>>> factor(R.discriminant())
-1 * 2^2 * 7^2

Constructing the order with given generators

You can give any list of elements of the number field, and it will generate the smallest ring \(R\) that contains them.

sage: K.<a> = NumberField(x^4 + 2)
sage: K.order([12*a^2, 4*a + 12]).basis()
[1, 4*a, 4*a^2, 16*a^3]
>>> from sage.all import *
>>> K = NumberField(x**Integer(4) + Integer(2), names=('a',)); (a,) = K._first_ngens(1)
>>> K.order([Integer(12)*a**Integer(2), Integer(4)*a + Integer(12)]).basis()
[1, 4*a, 4*a^2, 16*a^3]

If \(R\) isn’t of rank equal to the degree of the number field (i.e., \(R\) isn’t an order), then you’ll get an error message.

sage: K.order([a^2])
Traceback (most recent call last):
...
ValueError: the rank of the span of gens is wrong
>>> from sage.all import *
>>> K.order([a**Integer(2)])
Traceback (most recent call last):
...
ValueError: the rank of the span of gens is wrong

Computing Maximal Orders

We can also compute the maximal order, using the maxima order command, which behind the scenes finds an integral basis using Pari’s nfbasis command. For example, \(\QQ(\sqrt[4]{2})\) has maximal order \(\ZZ[\sqrt[4]{2}]\), and if \(\alpha\) is a root of \(x^3 + x^2 - 2x+8\), then \(\QQ(\alpha)\) has maximal order with \(\ZZ\)-basis

\[1, \frac{1}{2} a^{2} + \frac{1}{2} a, a^{2}.\]
sage: K.<a> = NumberField(x^4 + 2)
sage: K.maximal_order().basis()
[1, a, a^2, a^3]
sage: L.<a> = NumberField(x^3 + x^2 - 2*x+8)
sage: L.maximal_order().basis()
[1, 1/2*a^2 + 1/2*a, a^2]
sage: L.maximal_order().basis()[1].minpoly()
x^3 - 2*x^2 + 3*x - 10
>>> from sage.all import *
>>> K = NumberField(x**Integer(4) + Integer(2), names=('a',)); (a,) = K._first_ngens(1)
>>> K.maximal_order().basis()
[1, a, a^2, a^3]
>>> L = NumberField(x**Integer(3) + x**Integer(2) - Integer(2)*x+Integer(8), names=('a',)); (a,) = L._first_ngens(1)
>>> L.maximal_order().basis()
[1, 1/2*a^2 + 1/2*a, a^2]
>>> L.maximal_order().basis()[Integer(1)].minpoly()
x^3 - 2*x^2 + 3*x - 10

Functionality for non-maximal orders is minimal

There is still much important functionality for computing with non-maximal orders that is missing in Sage. For example, there is no support at all in Sage for computing with modules over orders or with ideals in non-maximal orders.

sage: K.<a> = NumberField(x^3 + 2)
sage: R = K.order(3*a)
sage: R.ideal(5)
Ideal (5, 15*a, 45*a^2) of Order generated by 3*a in Number Field in a with defining polynomial x^3 + 2
sage: R.ideal(5).factor()
Traceback (most recent call last):
...
AttributeError: 'NumberFieldOrderIdeal_generic' object has no attribute 'factor'
>>> from sage.all import *
>>> K = NumberField(x**Integer(3) + Integer(2), names=('a',)); (a,) = K._first_ngens(1)
>>> R = K.order(Integer(3)*a)
>>> R.ideal(Integer(5))
Ideal (5, 15*a, 45*a^2) of Order generated by 3*a in Number Field in a with defining polynomial x^3 + 2
>>> R.ideal(Integer(5)).factor()
Traceback (most recent call last):
...
AttributeError: 'NumberFieldOrderIdeal_generic' object has no attribute 'factor'

Relative Extensions

A relative number field \(L\) is a number field of the form \(K(\alpha)\), where \(K\) is a number field, and an absolute number field is a number field presented in the form \(\QQ(\alpha)\). By the primitive element theorem, any relative number field \(K(\alpha)\) can be written as \(\QQ(\beta)\) for some \(\beta\in L\). However, in practice it is often convenient to view \(L\) as \(K(\alpha)\). In Symbolic Expressions, we constructed the number field \(\QQ(\sqrt{2})(\alpha)\), where \(\alpha\) is a root of \(x^3 + \sqrt{2} x + 5\), but not as a relative field–we obtained just the number field defined by a root of \(x^6 + 10x^3 - 2x^2 + 25\).

Constructing a relative number field step by step

To construct this number field as a relative number field, first we let \(K\) be \(\QQ(\sqrt{2})\).

sage: K.<sqrt2> = QuadraticField(2)
>>> from sage.all import *
>>> K = QuadraticField(Integer(2), names=('sqrt2',)); (sqrt2,) = K._first_ngens(1)

Next we create the univariate polynomial ring \(R = K[X]\). In Sage, we do this by typing R.<X> = K[]. Here R.<X> means “create the object \(R\) with generator \(X\)” and K[] means a “polynomial ring over \(K\)”, where the generator is named based on the aforementioned \(X\) (to create a polynomial ring in two variables \(X,Y\) simply replace R.<X> by R.<X,Y>).

sage: R.<X> = K[]
sage: R
Univariate Polynomial Ring in X over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?
>>> from sage.all import *
>>> R = K['X']; (X,) = R._first_ngens(1)
>>> R
Univariate Polynomial Ring in X over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?

Now we can make a polynomial over the number field \(K=\QQ(\sqrt{2})\), and construct the extension of \(K\) obtained by adjoining a root of that polynomial to \(K\).

sage: L.<a> = K.extension(X^3 + sqrt2*X + 5)
sage: L
Number Field in a with defining polynomial X^3 + sqrt2*X + 5...
>>> from sage.all import *
>>> L = K.extension(X**Integer(3) + sqrt2*X + Integer(5), names=('a',)); (a,) = L._first_ngens(1)
>>> L
Number Field in a with defining polynomial X^3 + sqrt2*X + 5...

Finally, \(L\) is the number field \(\QQ(\sqrt{2})(\alpha)\), where \(\alpha\) is a root of \(X^3 + \sqrt{2}\alpha + 5\). We can do now do arithmetic in this number field, and of course include \(\sqrt{2}\) in expressions.

sage: a^3
-sqrt2*a - 5
sage: a^3 + sqrt2*a
-5
>>> from sage.all import *
>>> a**Integer(3)
-sqrt2*a - 5
>>> a**Integer(3) + sqrt2*a
-5

Functions on relative number fields

The relative number field \(L\) also has numerous functions, many of which have both relative and absolute version. For example the relative_degree function on \(L\) returns the relative degree of \(L\) over \(K\); the degree of \(L\) over \(\QQ\) is given by the absolute_degree function. To avoid possible ambiguity degree is not implemented for relative number fields.

sage: L.relative_degree()
3
sage: L.absolute_degree()
6
>>> from sage.all import *
>>> L.relative_degree()
3
>>> L.absolute_degree()
6

Extra structure on relative number fields

Given any relative number field you can also an absolute number field that is isomorphic to it. Below we create \(M = \QQ(b)\), which is isomorphic to \(L\), but is an absolute field over \(\QQ\).

sage: M.<b> = L.absolute_field()
sage: M
Number Field in b with defining
polynomial x^6 + 10*x^3 - 2*x^2 + 25
>>> from sage.all import *
>>> M = L.absolute_field(names=('b',)); (b,) = M._first_ngens(1)
>>> M
Number Field in b with defining
polynomial x^6 + 10*x^3 - 2*x^2 + 25

The structure function returns isomorphisms in both directions between \(M\) and \(L\).

sage: M.structure()
(Isomorphism map:
  From: Number Field in b with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25
  To:   Number Field in a with defining polynomial X^3 + sqrt2*X + 5 over its base field, Isomorphism map:
  From: Number Field in a with defining polynomial X^3 + sqrt2*X + 5 over its base field
  To:   Number Field in b with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25)
>>> from sage.all import *
>>> M.structure()
(Isomorphism map:
  From: Number Field in b with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25
  To:   Number Field in a with defining polynomial X^3 + sqrt2*X + 5 over its base field, Isomorphism map:
  From: Number Field in a with defining polynomial X^3 + sqrt2*X + 5 over its base field
  To:   Number Field in b with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25)

Arbitrary towers of relative number fields

In Sage one can create arbitrary towers of relative number fields (unlike in Pari, where a relative extension must be a single extension of an absolute field).

sage: R.<X> = L[]
sage: Z.<b> = L.extension(X^3 - a)
sage: Z
Number Field in b with defining polynomial X^3 - a over its base field
sage: Z.absolute_degree()
18
>>> from sage.all import *
>>> R = L['X']; (X,) = R._first_ngens(1)
>>> Z = L.extension(X**Integer(3) - a, names=('b',)); (b,) = Z._first_ngens(1)
>>> Z
Number Field in b with defining polynomial X^3 - a over its base field
>>> Z.absolute_degree()
18

Note

Exercise: Construct the relative number field \(L = K(\sqrt[3]{\sqrt{2}+\sqrt{3}})\), where \(K=\QQ(\sqrt{2}, \sqrt{3})\).

Relative number field arithmetic can be slow

One shortcoming with relative extensions in Sage is that behind the scenes all arithmetic is done in terms of a single absolute defining polynomial, and in some cases this can be very slow (much slower than Magma). Perhaps this could be fixed by using Singular’s multivariate polynomials modulo an appropriate ideal, since Singular polynomial arithmetic is extremely fast. Also, Sage has very little direct support for constructive class field theory, which is a major motivation for explicit computation with relative orders; it would be good to expose more of Pari’s functionality in this regard.