# Algebraic Number Theory 2017

## About Sage / alternative references

Sage is open source mathematics software using the programming language Python.

If you get stuck, or want to familiarise yourself with Sage and Python, check out the notebook "basic Sage" on this server, or the online Sage tutorial

A very nice alternative introduction / tutorial for Sage number fields are the Bordeaux Lectures included with Sage. Particularly, start here.

## What to do with this worksheet

You can type commands in the boxes, and evaluate them by holding [Shift] and pressing [Enter]. Please do this for all the input lines below as you read them.

Actually, this will not work when opening this worksheet for the first time. Create an account as instructed by us during the computer class, and when you have one, click "Edit a copy" on the top left of this page.

R=Integers(3) R(1+1+1)
 0 0
text='go ' text*10
 'go go go go go go go go go go ' 'go go go go go go go go go go '

That's it. Feel free to play around, and ask your own questions to Sage! To add your own cells, click on one of the blue horizontal bars that sometimes appear.

# Some Syntax

l=[1,2,3] l[1]
 2 2
pl=prime_range(40) pl
 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
len(pl)
 12 12
for p in pl: if p%10 == 7: print p
 7 17 37 7 17 37
for p in pl: if p%10 == 7: print p else: print '--' print 'done'
 -- -- -- 7 -- -- 17 -- -- -- -- 37 done -- -- -- 7 -- -- 17 -- -- -- -- 37 done
[p for p in pl if p%10==7]
 [7, 17, 37] [7, 17, 37]
2^4
 16 16
If you know python, or search around on the web for python commands, then the "s" in "srange" looks strange. It is here to make sure that the integers are Sage integers rather than Python integers. Sage integers are able to tell whether they are prime or not (which python integers are not), and Sage integers have a more "mathematical" behaviour for division than integers in Python. For example, see what "/" means for both types of objects:
print "Python int division:" for a in range(10): print str(a) + " / 3 = " + str(a/int(3)) print "Sage Integer division:" for a in srange(10): print str(a) + " / 3 = " + str(a/3)
 Python int division: 0 / 3 = 0 1 / 3 = 0 2 / 3 = 0 3 / 3 = 1 4 / 3 = 1 5 / 3 = 1 6 / 3 = 2 7 / 3 = 2 8 / 3 = 2 9 / 3 = 3 Sage Integer division: 0 / 3 = 0 1 / 3 = 1/3 2 / 3 = 2/3 3 / 3 = 1 4 / 3 = 4/3 5 / 3 = 5/3 6 / 3 = 2 7 / 3 = 7/3 8 / 3 = 8/3 9 / 3 = 3 Python int division: 0 / 3 = 0 1 / 3 = 0 2 / 3 = 0 3 / 3 = 1 4 / 3 = 1 5 / 3 = 1 6 / 3 = 2 7 / 3 = 2 8 / 3 = 2 9 / 3 = 3 Sage Integer division: 0 / 3 = 0 1 / 3 = 1/3 2 / 3 = 2/3 3 / 3 = 1 4 / 3 = 4/3 5 / 3 = 5/3 6 / 3 = 2 7 / 3 = 7/3 8 / 3 = 8/3 9 / 3 = 3

## Functions

ZZ(1/3)
 Traceback (click to the left of this block for traceback) ... TypeError: no conversion of this rational to integer Traceback (most recent call last): File "", line 1, in File "_sage_input_22.py", line 10, in exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("WlooMS8zKQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py")) File "", line 1, in File "/tmp/tmpvdi7_r/___code___.py", line 3, in exec compile(u'ZZ(_sage_const_1 /_sage_const_3 ) File "", line 1, in File "sage/structure/parent.pyx", line 953, in sage.structure.parent.Parent.__call__ (/home/sage/bin/sage2/src/build/cythonized/sage/structure/parent.c:9126) File "sage/rings/rational.pyx", line 3894, in sage.rings.rational.Q_to_Z._call_ (/home/sage/bin/sage2/src/build/cythonized/sage/rings/rational.c:31282) TypeError: no conversion of this rational to integer
print q(3,125) print q(27*241^3, 5^8*11^9*19*61^3)
 1.42656532963354 1.46527464717558 1.42656532963354 1.46527464717558

Reysat's world champion ABC-triple

a=2 b=3^10*109 print factor(a+b) print q(2,3^10*109)
 23^5 1.62991168412705 23^5 1.62991168412705
bound=2000 print [[a,b] for a in srange(1,bound) for b in srange(a+1,bound) if q(a,b)>1]
 ^C Traceback (click to the left of this block for traceback) ... __SAGE__ ^C Traceback (most recent call last): File "", line 1, in File "_sage_input_26.py", line 10, in exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("Ym91bmQ9MjAwMApwcmludCBbW2EsYl0gZm9yIGEgaW4gc3JhbmdlKDEsYm91bmQpIGZvciBiIGluIHNyYW5nZShhKzEsYm91bmQpIGlmIHEoYSxiKT4xXQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py")) File "", line 1, in File "/tmp/tmp5HU1x6/___code___.py", line 4, in exec compile(u'print [[a,b] for a in srange(_sage_const_1 ,bound) for b in srange(a+_sage_const_1 ,bound) if q(a,b)>_sage_const_1 ] File "", line 1, in File "/tmp/tmpHFIz72/___code___.py", line 7, in q return RR(log(c))/RR(log(radical(c)*radical(b)*radical(a))) File "src/cysignals/signals.pyx", line 225, in cysignals.signals.python_check_interrupt (build/src/cysignals/signals.c:2438) File "src/cysignals/signals.pyx", line 96, in cysignals.signals.sig_raise_exception (build/src/cysignals/signals.c:1125) KeyboardInterrupt __SAGE__

# Plotting

P = plot(sin(x^2), (x,-2,2), rgbcolor=(0.8,0,0.2), thickness=3, linestyle='--', fill='axis') show(P, gridlines=True)
d=[x^2 for x in range(-3,4)] print d list_plot(d)
 [9, 4, 1, 0, 1, 4, 9] [9, 4, 1, 0, 1, 4, 9]
histogram([p%10 for p in primes(50)])
x, y = var('x,y') plot3d(x^2 + y^2, (x,-2,2), (y,-2,2))

# Algebra

m=matrix([[1,2],[-2,1]]) m
 [ 1 2] [-2 1] [ 1 2] [-2 1]
latex(m)
 \left(\begin{array}{rr} 1 & 2 \\ -2 & 1 \end{array}\right) \left(\begin{array}{rr} 1 & 2 \\ -2 & 1 \end{array}\right)
m.charpoly()
 x^2 - 2*x + 5 x^2 - 2*x + 5
m=matrix([[1,-2,-1],[-3,6,3]]) print m
 [ 1 -2 -1] [-3 6 3] [ 1 -2 -1] [-3 6 3]
v=vector([1,2,3])
m.kernel()
print m.left_kernel() print m.right_kernel()
 Free module of degree 2 and rank 1 over Integer Ring Echelon basis matrix: [3 1] Free module of degree 3 and rank 2 over Integer Ring Echelon basis matrix: [ 1 0 1] [ 0 1 -2] Free module of degree 2 and rank 1 over Integer Ring Echelon basis matrix: [3 1] Free module of degree 3 and rank 2 over Integer Ring Echelon basis matrix: [ 1 0 1] [ 0 1 -2]
k.<s>=GF(7^2) print [1,s,s^2]
 [1, s, s + 4] [1, s, s + 4]
f=s.minpoly() f
 x^2 + 6*x + 3 x^2 + 6*x + 3
R.<x>=PolynomialRing(k) R(f).factor()
 (x + s + 6) * (x + 6*s) (x + s + 6) * (x + 6*s)
(x-s)*(x-s^7)
 x^2 + 6*x + 3 x^2 + 6*x + 3

Number fields in Sage

The following command creates two Sage objects: the number field $\QQ[\sqrt[3]{-19}]$ and a generator $a=\sqrt[3]{-19}$.

R.<x>=PolynomialRing(Rationals()) K.<a> = NumberField(x^3+19) discriminant(x^3+19)
 -9747 -9747
When assigning names to objects (such as K above), nothing it printed. If you don't type "=" then something is printed:
 Number Field in a with defining polynomial x^3 + 19 Number Field in a with defining polynomial x^3 + 19
Basic arithmetic works as it should.
(a+3)/(a+1)
 -1/9*a^2 + 1/9*a + 8/9 -1/9*a^2 + 1/9*a + 8/9
a^7
 361*a 361*a
The following commands should speak for themselves.
O = K.maximal_order() O
 Maximal Order in Number Field in a with defining polynomial x^3 + 19 Maximal Order in Number Field in a with defining polynomial x^3 + 19
O.basis()
 [1/3*a^2 + 2/3*a + 1/3, a, a^2] [1/3*a^2 + 2/3*a + 1/3, a, a^2]
There are two ways of creating fractional ideals of the maximal order. The first way is to use the mathematical notation.
p2 = 2*O + (a+1)*O p2
 Fractional ideal (2, 1/3*a^2 - 1/3*a + 4/3) Fractional ideal (2, 1/3*a^2 - 1/3*a + 4/3)
The second way to create fractional ideals of the maximal order is to use the "ideal" method of the number field.
p4 = K.ideal(2,a^2+a+1) p4
 Fractional ideal (2, 1/3*a^2 - 1/3*a + 1/3) Fractional ideal (2, 1/3*a^2 - 1/3*a + 1/3)
You can compute norms of all fractional ideals, and for prime ideals you can also compute residue class degrees and ramification indices. Ideal arithmetic is available too.
print [p2.norm(), p2.residue_class_degree(), p2.ramification_index()] print [p4.norm(), p4.residue_class_degree(), p4.ramification_index()] print p2 * p4 print p2.intersection(p4) print p2 + p4
 [2, 1, 1] [4, 2, 1] Fractional ideal (2) Fractional ideal (2) Fractional ideal (1) [2, 1, 1] [4, 2, 1] Fractional ideal (2) Fractional ideal (2) Fractional ideal (1)
In the cell above we used the "print" command, because normally only one output is printed by the Sage notebook.

Sage also handles ideal factorization. Here is the factorization of the ideal (15):

factorization = K.ideal(15).factor()

The factorization output is interpreted by Sage as a list, so you can take elements.

So here is how this applies to factorizations:
factorization[0]
 (Fractional ideal (3, 1/3*a^2 - 1/3*a + 1/3), 2) (Fractional ideal (3, 1/3*a^2 - 1/3*a + 1/3), 2)
So the elements of the factorization are pairs (p, e) where $p^e$ appears in the factorization. We let p5 be the last prime in the factorization.
p5 = factorization[3][0] p5
 Fractional ideal (5, 1/3*a^2 - 1/3*a - 5/3) Fractional ideal (5, 1/3*a^2 - 1/3*a - 5/3)
Given an element of K and an ideal, we can check inclusion.
print 5 in p5 print a-1 in p5 print 5 in p5 and a-1 in p5
 True True True True True True
And we can check equality of ideals.
p5 == K.ideal([5,a-1])
 True True
The field itself is just an abstract number ring without a chosen embedding into $\CC$, but we can create embeddings into $\CC$.
K.embeddings(CC)
 [ Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Complex Field with 53 bits of precision Defn: a |--> -2.66840164872194, Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Complex Field with 53 bits of precision Defn: a |--> 1.33420082436097 - 2.31090361529348*I, Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Complex Field with 53 bits of precision Defn: a |--> 1.33420082436097 + 2.31090361529348*I ] [ Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Complex Field with 53 bits of precision Defn: a |--> -2.66840164872194, Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Complex Field with 53 bits of precision Defn: a |--> 1.33420082436097 - 2.31090361529348*I, Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Complex Field with 53 bits of precision Defn: a |--> 1.33420082436097 + 2.31090361529348*I ]
We see that one of the embeddings into $\CC$ has its image in $\RR$ and the other two form a pair of complex conjugate embeddings. Here is just the real embedding:
K.embeddings(RR)
 [ Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Real Field with 53 bits of precision Defn: a |--> -2.66840164872194 ] [ Ring morphism: From: Number Field in a with defining polynomial x^3 + 19 To: Real Field with 53 bits of precision Defn: a |--> -2.66840164872194 ]
We create an embedding phi, and use it as follows.
phi = K.embeddings(RR)[0] phi(a)
 -2.66840164872194 -2.66840164872194
a=-(19)^(1/3) parent(a) a^3
 -19 -19
RR simulates the real numbers, but all numbers are rounded to the 53 most significant bits. You can get more bits of precision using RealField(precision).
print K.embeddings(RR)[0](a) print K.embeddings(RealField(100))[0](a) print K.embeddings(RealField(200))[0](a)
 -2.66840164872194 -2.6684016487219448673396273720 -2.6684016487219448673396273719708303350958785691831018656642 -2.66840164872194 -2.6684016487219448673396273720 -2.6684016487219448673396273719708303350958785691831018656642
Similarly with the complex numbers.
C=ComplexField(150) C(-2)^(1/2)
 -9.7433903303394229110546934540595492492491193e-46 + 1.4142135623730950488016887242096980785696719*I -9.7433903303394229110546934540595492492491193e-46 + 1.4142135623730950488016887242096980785696719*I
The basic invariants of number fields are available too:
K.discriminant()
 -1083 -1083
M=K.minkowski_bound() M
 152/9*sqrt(3)/pi 152/9*sqrt(3)/pi
The Minkowski bound is given symbolically. If we want it numerically, we can use the "n" method.
K.minkowski_bound().n()
 9.31133245601249 9.31133245601249
RR(M)
 9.31133245601249 9.31133245601249
RealField(200)(M)
 9.3113324560124879473024030826190394547114161128588199139448 9.3113324560124879473024030826190394547114161128588199139448

## Unit groups and class groups

Sage contains the number theory package Pari, which it uses behind the scenes to compute class groups and unit groups.
x = QQ['x'].gen() K.<a> = NumberField(x^3+19) u = K.unit_group() eta=u.gens()[1] eta.value()
 1/3*a^2 + 2/3*a - 2/3 1/3*a^2 + 2/3*a - 2/3
u is a group, the command "gens" gives a list of generators.
e=u.gens_values()[1] e.minpoly()
 x^3 + 2*x^2 + 14*x + 1 x^3 + 2*x^2 + 14*x + 1
The other half of the work was the class group.
cl = K.class_group() cl
 Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^3 + 19 Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^3 + 19
That does not tell us what the generators are, but Sage knows them, and we can ask for them.
cl.gens()
 (Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3),) (Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3),)
I=cl(K.ideal(2).factor()[1][0]) I
 Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3) Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3)

## Some other things we can do with class groups

x = QQ['x'].gen() K.<a> = NumberField(x^3+19) cl = K.class_group() g = cl.gens()[0]
 Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3) Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3)
This generator $g$ is an ideal class, and we can get a representative ideal from it as well.
g.ideal()
 Fractional ideal (2, 1/3*a^2 - 1/3*a + 4/3) Fractional ideal (2, 1/3*a^2 - 1/3*a + 4/3)
The class group, unlike in the notes, is written multiplicatively, so here is twice the generator.
g^2
 Fractional ideal class (5, -1/3*a^2 + 4/3*a - 1/3) Fractional ideal class (5, -1/3*a^2 + 4/3*a - 1/3)
We can test whether two ideal classes are equal.
print cl(p4) == g^2 print cl(p5) == g^2
 True False True False
We can also list all elements of the class group.
list(cl)
 [Trivial principal fractional ideal class, Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3), Fractional ideal class (2, 1/3*a^2 - 1/3*a + 1/3)] [Trivial principal fractional ideal class, Fractional ideal class (2, 1/3*a^2 - 1/3*a + 4/3), Fractional ideal class (2, 1/3*a^2 - 1/3*a + 1/3)]
And we can check that the representatives that Sage gives are nicely below the Minkowski bound
for c in cl: print c.ideal().norm() < K.minkowski_bound().n()
 True True True True True True
Here the "for" command means that something needs to be done for every c in the class group. Note the ":" and the indentation, they are required.

## Some more things you can do with unit groups

x = QQ['x'].gen() K.<a> = NumberField(x^3+19) unit_group = K.unit_group()
By the way, if we have any element of K, such as a fundamental unit eta, then we can compute its value under any complex embedding, such as the unique real embedding phi.
phi = K.embeddings(RR)[0] eta = unit_group.gens()[1] phi(eta)
 -0.0721453128472985 -0.0721453128472985
Absolute values and logarithms are available, but we can also ask Sage directly for the regulator.
print abs(log(abs(phi(eta)))) print K.regulator()
 2.62907295987392 2.62907295987391 2.62907295987392 2.62907295987391
Here is how to express a unit in terms of the generators of the unit group (where the generators of the unit group are written u0,u1,...,u(r+s_1)) and u0 is torsion).
my_unit = -24508930752*a^2 - 32593494531*a + 87540055984 print norm(my_unit) unit_group(my_unit)
 1 u1^20 1 u1^20
In other words, the output above means that the following is true:
my_unit == eta^20
 True True
You will get an error message if the element is not a unit.
unit_group(my_unit+1)
 Traceback (click to the left of this block for traceback) ... ValueError: -24508930752*a^2 - 32593494531*a + 87540055985 is not a unit Traceback (most recent call last): File "", line 1, in File "_sage_input_52.py", line 10, in exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("dW5pdF9ncm91cChteV91bml0KzEp"),globals())+"\\n"); execfile(os.path.abspath("___code___.py")) File "", line 1, in File "/tmp/tmpFq3tN9/___code___.py", line 3, in exec compile(u'unit_group(my_unit+_sage_const_1 ) File "", line 1, in File "sage/structure/parent.pyx", line 953, in sage.structure.parent.Parent.__call__ (/home/sage/bin/sage2/src/build/cythonized/sage/structure/parent.c:9126) File "sage/structure/coerce_maps.pyx", line 110, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (/home/sage/bin/sage2/src/build/cythonized/sage/structure/coerce_maps.c:4562) File "sage/structure/coerce_maps.pyx", line 105, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (/home/sage/bin/sage2/src/build/cythonized/sage/structure/coerce_maps.c:4450) File "/home/sage/bin/sage2/local/lib/python2.7/site-packages/sage/rings/number_field/unit_group.py", line 358, in _element_constructor_ raise ValueError("%s is not a unit"%u) ValueError: -24508930752*a^2 - 32593494531*a + 87540055985 is not a unit

## Discovering more functionality

If you want to know all available commands for an object, type a dot and press [tab]. For example, press [tab] at the end of the following line.
K.galois_group()
 Traceback (click to the left of this block for traceback) ... TypeError: You must specify the name of the generator. Traceback (most recent call last): File "", line 1, in File "_sage_input_53.py", line 10, in exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("Sy5nYWxvaXNfZ3JvdXAoKQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py")) File "", line 1, in File "/tmp/tmpotTHdP/___code___.py", line 2, in exec compile(u'K.galois_group() File "", line 1, in File "sage/misc/cachefunc.pyx", line 2038, in sage.misc.cachefunc.CachedMethodCaller.__call__ (/home/sage/bin/sage2/src/build/cythonized/sage/misc/cachefunc.c:10183) File "sage/misc/cachefunc.pyx", line 1914, in sage.misc.cachefunc.CachedMethodCaller._instance_call (/home/sage/bin/sage2/src/build/cythonized/sage/misc/cachefunc.c:9647) File "/home/sage/bin/sage2/local/lib/python2.7/site-packages/sage/rings/number_field/number_field.py", line 5045, in galois_group return GaloisGroup_v2(self, names) File "/home/sage/bin/sage2/local/lib/python2.7/site-packages/sage/rings/number_field/galois_group.py", line 184, in __init__ self._galois_closure, self._gc_map = number_field.galois_closure(names=names, map=True) File "/home/sage/bin/sage2/local/lib/python2.7/site-packages/sage/rings/number_field/number_field.py", line 7674, in galois_closure L, self_into_L = self._galois_closure_and_embedding(names) File "/home/sage/bin/sage2/local/lib/python2.7/site-packages/sage/rings/number_field/number_field.py", line 7591, in _galois_closure_and_embedding raise TypeError("You must specify the name of the generator.") TypeError: You must specify the name of the generator.
For all commands starting with certain letter combination, press [tab] after the following.
K.unit_group(
 0 0
For help on a command, press [tab] after the following
K.class_number(
or press enter after the following
K.class_number?
Alternatively, search the internet or www.sagemath.org for what you want to do.

## Your homework done in a second

Exercise (this is just an exercise, it is not your homework):

Compute the unit group and class group of your personal number field from the homework, and play around with the number field a bit.

K.<a>=NumberField(x^3+19) K.class_group?
 File: /home/sage/bin/sage2/local/lib/python2.7/site-packages/sage/rings/number_field/number_field.py Type: Definition: K.class_group(proof=None, names=’c’) Docstring: Return the class group of the ring of integers of this number field. INPUT: proof - if True then compute the class group provably correctly. Default is True. Call number_field_proof to change this default globally. names - names of the generators of this class group. OUTPUT: The class group of this number field. EXAMPLES: sage: K. = NumberField(x^2 + 23) sage: G = K.class_group(); G Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23 sage: G.0 Fractional ideal class (2, 1/2*a - 1/2) sage: G.gens() (Fractional ideal class (2, 1/2*a - 1/2),)  sage: G.number_field() Number Field in a with defining polynomial x^2 + 23 sage: G is K.class_group() True sage: G is K.class_group(proof=False) False sage: G.gens() (Fractional ideal class (2, 1/2*a - 1/2),)  There can be multiple generators: sage: k. = NumberField(x^2 + 20072) sage: G = k.class_group(); G Class group of order 76 with structure C38 x C2 of Number Field in a with defining polynomial x^2 + 20072 sage: G.0 # random Fractional ideal class (41, a + 10) sage: G.0^38 Trivial principal fractional ideal class sage: G.1 # random Fractional ideal class (2, -1/2*a) sage: G.1^2 Trivial principal fractional ideal class  Class groups of Hecke polynomials tend to be very small: sage: f = ModularForms(97, 2).T(2).charpoly() sage: f.factor() (x - 3) * (x^3 + 4*x^2 + 3*x - 1) * (x^4 - 3*x^3 - x^2 + 6*x - 1) sage: [NumberField(g,'a').class_group().order() for g,_ in f.factor()] [1, 1, 1]  File: /home/sage/bin/sage2/local/lib/python2.7/site-packages/sage/rings/number_field/number_field.py Type: Definition: K.class_group(proof=None, names=’c’) Docstring: Return the class group of the ring of integers of this number field. INPUT: proof - if True then compute the class group provably correctly. Default is True. Call number_field_proof to change this default globally. names - names of the generators of this class group. OUTPUT: The class group of this number field. EXAMPLES: sage: K. = NumberField(x^2 + 23) sage: G = K.class_group(); G Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23 sage: G.0 Fractional ideal class (2, 1/2*a - 1/2) sage: G.gens() (Fractional ideal class (2, 1/2*a - 1/2),)  sage: G.number_field() Number Field in a with defining polynomial x^2 + 23 sage: G is K.class_group() True sage: G is K.class_group(proof=False) False sage: G.gens() (Fractional ideal class (2, 1/2*a - 1/2),)  There can be multiple generators: sage: k. = NumberField(x^2 + 20072) sage: G = k.class_group(); G Class group of order 76 with structure C38 x C2 of Number Field in a with defining polynomial x^2 + 20072 sage: G.0 # random Fractional ideal class (41, a + 10) sage: G.0^38 Trivial principal fractional ideal class sage: G.1 # random Fractional ideal class (2, -1/2*a) sage: G.1^2 Trivial principal fractional ideal class  Class groups of Hecke polynomials tend to be very small: sage: f = ModularForms(97, 2).T(2).charpoly() sage: f.factor() (x - 3) * (x^3 + 4*x^2 + 3*x - 1) * (x^4 - 3*x^3 - x^2 + 6*x - 1) sage: [NumberField(g,'a').class_group().order() for g,_ in f.factor()] [1, 1, 1] 

## Special fields

Some fields can be constructed without giving their minimal polynomial.
 Class group of order 8 with structure C8 of Number Field in a with defining polynomial x^2 + 41 Class group of order 8 with structure C8 of Number Field in a with defining polynomial x^2 + 41

K=CyclotomicField(7) # what's the factorization of the discriminant of a generator K.gen().minpoly().discriminant().factor()
#Check O_K=Z[zeta_7] K.discriminant().factor()

Exercise (this is just an exercise, it is not your homework):

Find all imaginary quadratic fields K of class number one with $|\Delta_K|$<200

dl=[d for d in range(-50,-4) if d%4==1 or d%4==0] for d in dl: if QuadraticField(d).class_number()==1: print d
 -48 -44 -43 -36 -32 -28 -27 -19 -16 -12 -11 -8 -7 -48 -44 -43 -36 -32 -28 -27 -19 -16 -12 -11 -8 -7

Exercise (this is just an exercise, it is not your homework):

How many real quadratic fields K of class number one exist with $|\Delta_K|$<200?

K.<a>=NumberField(x^3+19) A=K.class_group() I=K.fractional_ideal(a-1,5) A(I).order()

## Proven class numbers versus non-proven ones

Sage contains the Pari software and uses it for its class group computations. By default, Sage forces Pari to prove the results unconditionally (well, conditionally on there being no bugs in the software of course). For example, the following command...
CyclotomicField(56).class_group()
... takes forever! To interrupt it. Scroll all the way to the top, click on Action and choose Interrupt. If you're ok with a result that is correct under some conjectures, you can choose "proof=False" for the class group computation. It should then only take about 6 seconds.
time CyclotomicField(56).class_group(proof=False)

If it took less than a second, then that is because the computation was already done by the previous command and stored in a cache.

## That's it.

Feel free to experiment some more or read some more (see also the references at the top). The basic Sage worksheet contains some further programming examples, which may be useful for your homework.

As for your homework. Please make backups of your worksheet, as we are not responsible for backing up the Sage notebook server! You can do this by scrolling to the top, clicking "File..." and clicking "Save worksheet to a file...". Note that it opens a pop-up window, which may be blocked, so please make sure you are actually downloading a .sws file.

To hand in your homework, send an email with your .sws file to the assistants and share your worksheet with the assistants. Instructions will appear.