Skip to content

Instantly share code, notes, and snippets.

@user202729
Last active December 2, 2023 07:36
Show Gist options
  • Save user202729/5ea6e7851635f93c6913ba1f5ac17584 to your computer and use it in GitHub Desktop.
Save user202729/5ea6e7851635f93c6913ba1f5ac17584 to your computer and use it in GitHub Desktop.
SageMath cheat sheet companion for the Napkin "number field" chapter
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
%! TEX program = pdflatex
\documentclass{article}
\usepackage{personal}
\usepackage{hyperref}
\usepackage{cleveref}
\begin{typstmathinputaddextrapreamble}
\end{typstmathinputaddextrapreamble}
\ExplSyntaxOn
\RenewDocumentEnvironment{verbatim}{}{
%\umiDeclareMathChar{𝔭}
\expandafter\def\csname u8:𝔭\endcsname{\ensuremath{\mathfrak{p}}}
\Verbatim}{\endVerbatim}
\ExplSyntaxOff
\let\umiMathscr\mathcal
\begin{document}
\typstmathinputprepare{\$}
\title {Cheat sheet for commonly-used SageMath commands}
\author {user202729}
\maketitle
\section{Section 46.2. Algebraic numbers and algebraic integers}
The set of algebraic number is:
\begin{verbatim}
sage: QQbar
Algebraic Field
\end{verbatim}
It appears that SageMath has no equivalent of $β€Ύβ„€$. Nevertheless, you can check whether an algebraic number is integral
by checking if the minimal polynomial has integer coefficients.
\begin{verbatim}
sage: QQbar(2^(1/3)).minpoly()
x^3 - 2
sage: QQbar(sqrt(3)/2).minpoly()
x^2 - 3/4
\end{verbatim}
Meanwhile, |.is_integer()| checks if an algebraic integer is a rational integer.
\section{Section 46.3. Number fields}
\label{note:embedded_number_field}
The number field can be think of as an object by itself, think of $β„š[βˆ›2] β‰… β„š[βˆ›2 Ο‰]$ for instance.
Nevertheless, in SageMath, it is often convenient to consider all number fields as embedded in $β„‚$.
SageMath has a concept of a relative number field (algebraic field extension from another number field instead of $β„š$), but depends on the use case this may be more confusing than helpful.
\begin{verbatim}
sage: K.<a, b>=QQ[2^(1/3), 3^(1/3)]
sage: K
Number Field in a with defining polynomial x^3 - 2 over its base field
sage: a.minpoly()
x^3 - 2
sage: b.minpoly()
x - b
sage: b.absolute_minpoly()
x^3 - 3
sage: b^3
3
sage: N(a)
ValueError: cannot convert a to Number Field in b with defining polynomial x^3 - 3 (regardless of embeddings)
\end{verbatim}
So, it's recommended to use |number_field_elements_from_algebraics| to get an embedded number field instead.
This example assigns $K=β„š(βˆ›2, βˆ›3)$.
\begin{verbatim}
K=number_field_elements_from_algebraics(
[
QQbar(2^(1/3)),
QQbar(3^(1/3))
], embedded=True, minimal=True)[0]
\end{verbatim}
This can be slow sometimes, unfortunately. Refer to \url{https://github.com/sagemath/sage/issues/33811}.
Because of a bug in SageMath\footnote{Refer to \url{https://github.com/sagemath/sage/issues/36735}.}, you should explicitly write down the |QQbar|.
\begin{verbatim}
sage: number_field_elements_from_algebraics([(-1)^(1/3)], embedded=True, minimal=True)[0]
Rational Field
\end{verbatim}
When there's only one generator, you can use the short form for brevity.
\begin{verbatim}
sage: QQ[2^(1/100)]
Number Field in a with defining polynomial x^100 - 2 with a = 1.006955550056719?
\end{verbatim}
Getting the degree of a number field works as you expect.
\begin{verbatim}
sage: K.degree()
9
\end{verbatim}
To make a number field by extended $β„š$ with a root of the polynomial (preferably embedded into $β€Ύβ„š$, because of the reason above), we can do the following.
\begin{verbatim}
sage: QQx.<x>=QQ[]
sage: (x^3-x^2-2*x-8).is_irreducible()
True
sage: (x^3-x^2-2*x-8).roots(QQbar, multiplicities=False)
[2.767345740861966?,
-0.8836728704309828? - 1.452576664644302?*I,
-0.8836728704309828? + 1.452576664644302?*I]
\end{verbatim}
Then create a field extension as usual. Of course, because the polynomial is irreducible, these fields are all isomorphic.
Alternatively,
\begin{verbatim}
sage: QQbar.polynomial_root(x^3-x^2-2*x-8, RIF(2.767, 2.768))
2.767345740861966?
\end{verbatim}
\section{Section 46.4. Primitive element theorem, and monogenic extensions}
As you'd expect.
\begin{verbatim}
sage: K=number_field_elements_from_algebraics(
....: [
....: QQbar(sqrt(3)),
....: QQbar(sqrt(5)),
....: ], embedded=True, minimal=True)[0]
....: QQbar(K.primitive_element())
2.688500258069165?
\end{verbatim}
This doesn't work when $K=β„š$, however (only matters if you want to write a script to automate something).
\begin{verbatim}
sage: K=number_field_elements_from_algebraics(
....: [
....: QQbar(-1)
....: ], embedded=True, minimal=True)[0]
....: K.primitive_element()
AttributeError: 'RationalField_with_category' object has no attribute 'primitive_element'
\end{verbatim}
\section{Section 47.1. Norms and traces}
To compute the Galois conjugates, you can do the expected thing. Note that only conjugates that lies inside the given field will be returned.
\begin{verbatim}
sage: K=QQ[2^(1/3)]
sage: K(2^(1/3)).galois_conjugates(K)
[a]
sage: K(2^(1/3)).galois_conjugates(QQbar)
[1.259921049894873?,
-0.6299605249474365? - 1.091123635971722?*I,
-0.6299605249474365? + 1.091123635971722?*I]
\end{verbatim}
As you can observe, if the extension over $β„š$ is not Galois, then it's possible that not all Galois conjugates will be returned.
Checking whether an element of $β€Ύβ„š$ lies in $K$ works as you expect.
\begin{verbatim}
sage: K(2^(1/3)).galois_conjugates(QQbar)[0] in K
True
sage: K(2^(1/3)).galois_conjugates(QQbar)[1] in K
False
\end{verbatim}
Computing the norm and trace is also as you expect.
\begin{verbatim}
sage: K=QQ[sqrt(2)]
sage: K(3+4*sqrt(2)).norm()
-23
sage: K(3+4*sqrt(2)).trace()
6
\end{verbatim}
I can't find any way to compute it symbolically though. But maybe I simply haven't tried hard enough.
Note that |.norm()| on an element of |QQbar| doesn't work as you expect -- this computes the complex norm $|Ξ±|Β²$ instead.
\begin{verbatim}
sage: (2^(1/3)).norm()
2^(2/3)
sage: QQbar(2^(1/3)).norm()
1.587401051968200?
\end{verbatim}
\section{47.2. The ring of integers}
The computation of the ring of integers is unsurprising.
\begin{verbatim}
sage: K
Number Field in a with defining polynomial y^2 + 5 with a = 2.236067977499790?*I
sage: OK=K.ring_of_integers()
sage: OK
Maximal Order in Number Field in a with defining polynomial y^2 + 5 with a = 2.236067977499790?*I
\end{verbatim}
You can compute a $β„€$-basis of it.
\begin{verbatim}
sage: OK.basis()
[1, a]
\end{verbatim}
Given $x$, to compute the minimal $n$ such that $x=(1/n) Ξ±$ for some $Ξ± ∈ π’ͺ_K$, you can certainly brute force...
\begin{verbatim}
sage: x=QQbar(1/(2^(1/3)+1))
....: next(n
....: for n in (1..)
....: if all(c.is_integer() for c in (x*n).minpoly())
....: )
3
\end{verbatim}
Alternatively, you can first solve exercise 47.2.7, then use that. But you need to factorize the minimal polynomial which is not polynomial-time.
The above works well enough for small numbers anyway.
\section{47.3. On monogenic extensions}
It's a bit difficult to "see" the structure of $π’ͺ_K$ other than looking at the basis, I'll postpone this to the discriminant section.
There doesn't seem to be a good way to check if an integer ring has an integral basis, unfortunately.%
\footnote{See \url{https://ask.sagemath.org/question/61974/}.}
\section{48.2. Ideal arithmetic}
If $K$ is a number field, you can use the following to compute the ideals of the ring $π’ͺ_K$.
We will study what are fractional ideals later, but when all the elements belongs to $π’ͺ_K$, a fractional ideal
is an ideal of $π’ͺ_K$.
\begin{verbatim}
sage: a=K.ideal(2, 1+sqrt(-5))
sage: a
Fractional ideal (2, a + 1)
sage: a.gens_reduced()
(2, a + 1)
sage: a.is_principal()
False
\end{verbatim}
Note that, without using |.gens_reduced()|, sometimes the printed-out value may show two generators even though it's possible to express the ideal with one generator.
\begin{verbatim}
sage: QQx.<x>=QQ[]
sage: L.<a>=(x^3-2).splitting_field()
sage: L.ideal(-1/3*a^5 - 2/3*a^4 - 5/3*a^3 - a - 3)
Fractional ideal (5, -5/9*a^5 - 10/9*a^4 - 10/3*a^3 - 2/3*a^2 - 8/3*a + 1)
\end{verbatim}
One easy way to force displaying one ideal when possible is to set |SMALL_DISC| as documented in |sage/rings/number_field/number_field_ideal.py|:
\begin{verbatim}
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC = 10^20
\end{verbatim}
\section{48.4. Unique factorization works}
Factorization of ideals work as you expect.
\begin{verbatim}
sage: K.ideal(6).factor()
(Fractional ideal (2, a + 1))^2 * (Fractional ideal (3, a + 1)) * (Fractional ideal (3, a + 2))
\end{verbatim}
\section{48.7. The ideal norm}
No surprise.
\begin{verbatim}
sage: K.ideal(5).norm()
25
\end{verbatim}
\section{49.2. The discriminant of a number field}
Again, no surprise.
\begin{verbatim}
sage: K.discriminant()
-20
\end{verbatim}
We'd like to remark that we can actually compute the discriminant of any \emph{order}. This can give a tool to check if an order is maximal, then Dedekind index theorem can be used to work prime by prime.
(we haven't learnt order yet.)
\begin{verbatim}
sage: K=QQ[sqrt(5)]
sage: K.order(1, QQbar(sqrt(5))).discriminant()
20
sage: K.discriminant()
5
\end{verbatim}
\section{49.3. The signature of a number field}
No surprise.
\begin{verbatim}
sage: K=QQ[2^(1/100)]
sage: K
Number Field in a with defining polynomial x^100 - 2 with a = 1.006955550056719?
sage: K.signature()
(2, 49)
\end{verbatim}
To check if an embedding is real, it suffices to check if all the images of the generators are real.
\begin{verbatim}
sage: s=K.embeddings(QQbar)
sage: s[0]
Ring morphism:
From: Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
To: Algebraic Field
Defn: a |--> -0.6299605249474365? - 1.091123635971722?*I
sage: s[0].im_gens()[0] in AA
False
sage: s[2]
Ring morphism:
From: Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
To: Algebraic Field
Defn: a |--> 1.259921049894873?
sage: s[2].im_gens()[0] in AA
True
\end{verbatim}
Of course, you can also get the embeddings into $𝔸=β€Ύβ„šβˆ© ℝ$ directly.
\begin{verbatim}
sage: K.embeddings(AA)
[
Ring morphism:
From: Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
To: Algebraic Real Field
Defn: a |--> 1.259921049894873?
]
\end{verbatim}
\section{Section 49.7. The class group is finite}
Unsurprisingly, SageMath has functions to compute the order of the class group.
\begin{verbatim}
sage: K.class_group().order()
1
\end{verbatim}
Or equivalently |.class_number()|.
\section{Chapter 52. Things Galois}
Computing the splitting field can be done as follows.
\begin{verbatim}
sage: QQx.<x>=QQ[]
sage: L=(x^3-2).splitting_field("a")
sage: L
Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 3*x^3 + 9*x + 9
\end{verbatim}
This does not give an embedded number field however (see \Cref{note:embedded_number_field}),
use the following trick to get an embedded number field.
Since $L$ is Galois over $β„š$, they're all the same.
\begin{verbatim}
sage: QQ[L.embeddings(QQbar)[0](L.primitive_element())]
Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 3*x^3 + 9*x + 9 with a = -1.129960524947437? - 1.957149039756160?*I
\end{verbatim}
Computing the Galois closure is easy.
\begin{verbatim}
sage: K=QQ[2^(1/3)]
sage: K
Number Field in a with defining polynomial x^3 - 2 with a = 1.259921049894873?
sage: L.<a>=K.galois_closure()
sage: L
Number Field in a with defining polynomial x^6 + 108
\end{verbatim}
This field $L$ is in fact the same as the field above, but they will not compare equal.
To check if two fields is in fact the same field, you can do something like the following.
\begin{verbatim}
sage: L
Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 3*x^3 + 9*x + 9 with a = -1.129960524947437? - 1.957149039756160?*I
sage: QQ[(-108)^(1/6)] == L
False
sage: QQ[(-108)^(1/6)].primitive_element() in L
True
sage: L.primitive_element() in QQ[(-108)^(1/6)]
True
\end{verbatim}
If the primitive element of each field belong to the other, clearly they're the same field.
{
\hfuzz=30pt
To compute $Aut(L)$, you can use either |L.automorphisms()| or |L.embeddings(L)|, which returns a \emph{set}.
}
If you want to convert it to a group, use |.galois_group()|.
\begin{verbatim}
sage: g=L.galois_group()
sage: g
Galois group 6T2 ([3]2) with order 6 of x^6 + 3*x^5 + 6*x^4 + 3*x^3 + 9*x + 9
\end{verbatim}
Of course, this allows you to do everything you can do manually -- convert between a ring homomorphism and a group element:
\begin{verbatim}
sage: f=g[1]
sage: f
(1,2)(3,4)(5,6)
sage: f(L(1))
1
sage: f.as_hom()
Ring endomorphism of Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 3*x^3 + 9*x + 9 with a = -1.129960524947437? - 1.957149039756160?*I
Defn: a |--> -1/9*a^5 - 1/3*a^4 - 2/3*a^3 - 2/3*a^2 - a - 2
sage: g(f.as_hom())
(1,2)(3,4)(5,6)
\end{verbatim}
Potentially useful is to view the structure of $g$:
\begin{verbatim}
sage: g.structure_description()
'S3'
\end{verbatim}
\paragraph{Useless methods.} You can also use |PermutationGroup| which wraps over GAP group:
\begin{verbatim}
a=L.automorphisms()
x=L.primitive_element()
xs=x.galois_conjugates(L)
g=PermutationGroup([[xs.index(ai(x))+1 for x in xs] for ai in a])
\end{verbatim}
An element in the automorphism group is represented by a permutation, based on how it permutes the conjugates of $x$.
Alternatively, inspired from Cayley's theorem (a group is determined by how the elements act on its own elements) you can also do:
\begin{verbatim}
g=PermutationGroup([[a.index(ai*aj)+1 for aj in a] for ai in a])
\end{verbatim}
Of course, |L.embeddings(QQbar)| does what you expect, but you cannot compose it even though the image is contained in $L$.
\subsection{Note: relative field extension in SageMath}
\subsection{Miscellaneous}
To compute the element of |QQbar| given an approximate representation: refer to \url{https://github.com/sagemath/sage/issues/36798}.
\section{Section 55.3. Inertial degrees}
\begin{verbatim}
sage: K=QQ[2^(1/3)]
....: L.<a>=K.galois_closure()
sage: 𝔭 = L.primes_above(5)[0]
\end{verbatim}
Then, computing the ramification index is straightforward.
\begin{verbatim}
sage: 𝔭.ramification_index()
1
\end{verbatim}
Computing the inertial degree is not that straightforward. Some possible ways are:
\begin{verbatim}
sage: 𝔭.residue_field().degree()
2
sage: 𝔭.decomposition_group().order()/𝔭.inertia_group().order()
2
\end{verbatim}
\section{Section 55.5. Decomposition/inertia group}
SageMath has built-in support for this.
\begin{verbatim}
sage: 𝔭.inertia_group()
Subgroup generated by [()] of (Galois group 6T2 ([3]2) with order 6 of x^6 + 108)
sage: 𝔭.decomposition_group()
Subgroup generated by [(1,4)(2,6)(3,5)] of (Galois group 6T2 ([3]2) with order 6 of x^6 + 108)
\end{verbatim}
In this example, $𝔭$ is a prime above $p=5$, and its decomposition group has order 2.
Interestingly, in this case, $L=β„š[βˆ›2, βˆ›2Ο‰, βˆ›2ω²]$ is the splitting field of $XΒ³-2$ over $β„š$, thus any element of the Galois group (i.e. a field isomorphism of $L$) is determined by how it permutes the roots of $XΒ³-2$ -- in other words, the Galois group of $L$ is a subgroup of $S₃$. In this case, we know it must exactly be equal to $S₃$, and $S₃$ has no normal subgroup of order $2$, which means \emph{$D$ must not be normal in $G$!}
Of course, we can also let SageMath tell us this instead of thinking about the Galois group:
\begin{verbatim}
sage: 𝔭.decomposition_group().is_normal()
False
\end{verbatim}
As we might have guessed, when $(p)$ is lifted into $K^D$ it doesn't split as cleanly as we have hoped:
\begin{verbatim}
sage: KD=𝔭.decomposition_group().fixed_field()[0]
sage: KD.primes_above(5)[0].residue_field().degree()
1
sage: KD.primes_above(5)[1].residue_field().degree()
2
\end{verbatim}
\end{document}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment