Sage Quickstart for Abstract Algebra¶
This Sage quickstart tutorial was developed for the MAA PREP Workshop “Sage: Using Open-Source Mathematics Software with Undergraduates” (funding provided by NSF DUE 0817071). It is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA).
As computers are discrete and finite, anything with a discrete, finite set of generators is natural to implement and explore.
Group Theory¶
Many common groups are pre-defined, usually as permutation groups: that is, explicitly described as subgroups of symmetric groups.
Every group of order 15 or less is available as a permutation group.
Sometimes they are available under special names, though.
sage: G = QuaternionGroup()
sage: G
Quaternion group of order 8 as a permutation group
>>> from sage.all import *
>>> G = QuaternionGroup()
>>> G
Quaternion group of order 8 as a permutation group
sage: H = AlternatingGroup(5)
sage: H
Alternating group of order 5!/2 as a permutation group
>>> from sage.all import *
>>> H = AlternatingGroup(Integer(5))
>>> H
Alternating group of order 5!/2 as a permutation group
sage: H.is_simple()
True
>>> from sage.all import *
>>> H.is_simple()
True
sage: D = DihedralGroup(8)
sage: D
Dihedral group of order 16 as a permutation group
>>> from sage.all import *
>>> D = DihedralGroup(Integer(8))
>>> D
Dihedral group of order 16 as a permutation group
We can access a lot of information about groups, such as:
A list of subgroups up to conjugacy,
or a stabilizer,
or other things demonstrated below.
sage: for K in D.conjugacy_classes_subgroups():
....: print(K)
Subgroup generated by [()] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(2,8)(3,7)(4,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,2)(3,8)(4,7)(5,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (2,8)(3,7)(4,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,2)(3,8)(4,7)(5,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (2,8)(3,7)(4,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (1,2,3,4,5,6,7,8)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (1,2)(3,8)(4,7)(5,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (2,8)(3,7)(4,6), (1,2,3,4,5,6,7,8)] of (Dihedral group of order 16 as a permutation group)
>>> from sage.all import *
>>> for K in D.conjugacy_classes_subgroups():
... print(K)
Subgroup generated by [()] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(2,8)(3,7)(4,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,2)(3,8)(4,7)(5,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (2,8)(3,7)(4,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,2)(3,8)(4,7)(5,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (2,8)(3,7)(4,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (1,2,3,4,5,6,7,8)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (1,2)(3,8)(4,7)(5,6)] of (Dihedral group of order 16 as a permutation group)
Subgroup generated by [(1,5)(2,6)(3,7)(4,8), (1,3,5,7)(2,4,6,8), (2,8)(3,7)(4,6), (1,2,3,4,5,6,7,8)] of (Dihedral group of order 16 as a permutation group)
In the previous cell we once again did a for loop over a set of objects rather than just a list of numbers. This can be very powerful.
sage: D.stabilizer(3)
Subgroup generated by [(1,5)(2,4)(6,8)] of (Dihedral group of order 16 as a permutation group)
>>> from sage.all import *
>>> D.stabilizer(Integer(3))
Subgroup generated by [(1,5)(2,4)(6,8)] of (Dihedral group of order 16 as a permutation group)
sage: len(D.normal_subgroups())
7
sage: for K in sorted(D.normal_subgroups()):
....: print(K)
Subgroup generated by [()] of (Dihedral group of order 16 as a permutation group)
...
Subgroup generated by [(1,2,3,4,5,6,7,8), (1,8)(2,7)(3,6)(4,5)] of (Dihedral group of order 16 as a permutation group)
>>> from sage.all import *
>>> len(D.normal_subgroups())
7
>>> for K in sorted(D.normal_subgroups()):
... print(K)
Subgroup generated by [()] of (Dihedral group of order 16 as a permutation group)
...
Subgroup generated by [(1,2,3,4,5,6,7,8), (1,8)(2,7)(3,6)(4,5)] of (Dihedral group of order 16 as a permutation group)
We can access specific subgroups if we know the generators as a permutation group.
sage: L = D.subgroup(["(1,3,5,7)(2,4,6,8)"])
>>> from sage.all import *
>>> L = D.subgroup(["(1,3,5,7)(2,4,6,8)"])
sage: L.is_normal(D)
True
>>> from sage.all import *
>>> L.is_normal(D)
True
sage: Q=D.quotient(L)
sage: Q
Permutation Group with generators [(1,2)(3,4), (1,3)(2,4)]
>>> from sage.all import *
>>> Q=D.quotient(L)
>>> Q
Permutation Group with generators [(1,2)(3,4), (1,3)(2,4)]
sage: Q.is_isomorphic(KleinFourGroup())
True
>>> from sage.all import *
>>> Q.is_isomorphic(KleinFourGroup())
True
There are some matrix groups as well, both finite and infinite.
sage: S = SL(2, GF(3))
sage: S
Special Linear Group of degree 2 over Finite Field of size 3
>>> from sage.all import *
>>> S = SL(Integer(2), GF(Integer(3)))
>>> S
Special Linear Group of degree 2 over Finite Field of size 3
We can print out all of the elements of this group.
sage: for a in S:
....: print(a)
[1 0]
[0 1]
...
[2 2]
[2 1]
>>> from sage.all import *
>>> for a in S:
... print(a)
[1 0]
[0 1]
...
[2 2]
[2 1]
sage: SS = SL(2, ZZ)
>>> from sage.all import *
>>> SS = SL(Integer(2), ZZ)
Of course, you have to be careful what you try to do!
sage: SS.list()
Traceback (most recent call last):
...
NotImplementedError: group must be finite
>>> from sage.all import *
>>> SS.list()
Traceback (most recent call last):
...
NotImplementedError: group must be finite
sage: for a in SS.gens():
....: print(a)
[ 0 1]
[-1 0]
...
>>> from sage.all import *
>>> for a in SS.gens():
... print(a)
[ 0 1]
[-1 0]
...
Rings¶
Sage has many pre-defined rings to experiment with. Here is how one would access \(\ZZ/12\ZZ\), for instance.
sage: twelve = Integers(12)
sage: twelve
Ring of integers modulo 12
>>> from sage.all import *
>>> twelve = Integers(Integer(12))
>>> twelve
Ring of integers modulo 12
sage: twelve.is_field()
False
>>> from sage.all import *
>>> twelve.is_field()
False
sage: twelve.is_integral_domain()
False
>>> from sage.all import *
>>> twelve.is_integral_domain()
False
Quaternions, and generalizations¶
We can define generalized quaternion algebras, where \(i^2=a\), \(j^2=b\), and \(k=i\cdot j\), all over \(\QQ\):
sage: quat = QuaternionAlgebra(-1, -1)
sage: quat
Quaternion Algebra (-1, -1) with base ring Rational Field
>>> from sage.all import *
>>> quat = QuaternionAlgebra(-Integer(1), -Integer(1))
>>> quat
Quaternion Algebra (-1, -1) with base ring Rational Field
sage: quat.is_field()
False
>>> from sage.all import *
>>> quat.is_field()
False
sage: quat.is_commutative()
False
>>> from sage.all import *
>>> quat.is_commutative()
False
sage: quat.is_division_algebra()
True
>>> from sage.all import *
>>> quat.is_division_algebra()
True
sage: quat2 = QuaternionAlgebra(5, -7)
>>> from sage.all import *
>>> quat2 = QuaternionAlgebra(Integer(5), -Integer(7))
sage: quat2.is_division_algebra()
True
>>> from sage.all import *
>>> quat2.is_division_algebra()
True
sage: quat2.is_field()
False
>>> from sage.all import *
>>> quat2.is_field()
False
Polynomial Rings¶
Polynomial arithmetic in Sage is a very important tool.
The first cell brings us back to the symbolic world. This is not the same thing as polynomials!
sage: reset('x') # This returns x to being a variable
sage: (x^4 + 2*x).parent()
Symbolic Ring
>>> from sage.all import *
>>> reset('x') # This returns x to being a variable
>>> (x**Integer(4) + Integer(2)*x).parent()
Symbolic Ring
Now we will turn \(x\) into the generator of a polynomial ring. The syntax is a little unusual, but you will see it often.
sage: R.<x> = QQ[]
sage: R
Univariate Polynomial Ring in x over Rational Field
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> R
Univariate Polynomial Ring in x over Rational Field
sage: R.random_element() # random
-5/2*x^2 - 1/4*x - 1
>>> from sage.all import *
>>> R.random_element() # random
-5/2*x^2 - 1/4*x - 1
sage: R.is_integral_domain()
True
>>> from sage.all import *
>>> R.is_integral_domain()
True
sage: (x^4 + 2*x).parent()
Univariate Polynomial Ring in x over Rational Field
>>> from sage.all import *
>>> (x**Integer(4) + Integer(2)*x).parent()
Univariate Polynomial Ring in x over Rational Field
sage: (x^2+x+1).is_irreducible()
True
>>> from sage.all import *
>>> (x**Integer(2)+x+Integer(1)).is_irreducible()
True
sage: F = GF(5)
sage: P.<y> = F[]
>>> from sage.all import *
>>> F = GF(Integer(5))
>>> P = F['y']; (y,) = P._first_ngens(1)
sage: P.random_element() # random
2*y
>>> from sage.all import *
>>> P.random_element() # random
2*y
sage: I = P.ideal(y^3+2*y)
sage: I
Principal ideal (y^3 + 2*y) of Univariate Polynomial Ring in y over Finite Field of size 5
>>> from sage.all import *
>>> I = P.ideal(y**Integer(3)+Integer(2)*y)
>>> I
Principal ideal (y^3 + 2*y) of Univariate Polynomial Ring in y over Finite Field of size 5
sage: Q = P.quotient(I)
>>> from sage.all import *
>>> Q = P.quotient(I)
sage: Q
Univariate Quotient Polynomial Ring in ybar over Finite Field of size 5 with modulus y^3 + 2*y
>>> from sage.all import *
>>> Q
Univariate Quotient Polynomial Ring in ybar over Finite Field of size 5 with modulus y^3 + 2*y
Fields¶
Sage has superb support for finite fields and extensions of the rationals.
Finite Fields¶
sage: F.<a> = GF(3^4)
sage: F
Finite Field in a of size 3^4
>>> from sage.all import *
>>> F = GF(Integer(3)**Integer(4), names=('a',)); (a,) = F._first_ngens(1)
>>> F
Finite Field in a of size 3^4
The generator satisfies a Conway polynomial, by default, or the polynomial can be specified.
sage: F.polynomial()
a^4 + 2*a^3 + 2
>>> from sage.all import *
>>> F.polynomial()
a^4 + 2*a^3 + 2
sage: F.list()
[0, a, a^2, a^3, a^3 + 1, a^3 + a + 1, a^3 + a^2 + a + 1, 2*a^3 + a^2 + a + 1, a^2 + a + 2, a^3 + a^2 + 2*a, 2*a^3 + 2*a^2 + 1, a^3 + a + 2, a^3 + a^2 + 2*a + 1, 2*a^3 + 2*a^2 + a + 1, a^3 + a^2 + a + 2, 2*a^3 + a^2 + 2*a + 1, 2*a^2 + a + 2, 2*a^3 + a^2 + 2*a, 2*a^2 + 2, 2*a^3 + 2*a, 2*a^3 + 2*a^2 + 2, a^3 + 2*a + 2, a^3 + 2*a^2 + 2*a + 1, 2*a^2 + a + 1, 2*a^3 + a^2 + a, a^2 + 2, a^3 + 2*a, a^3 + 2*a^2 + 1, a + 1, a^2 + a, a^3 + a^2, 2*a^3 + 1, 2*a^3 + a + 2, 2*a^3 + a^2 + 2*a + 2, 2*a^2 + 2*a + 2, 2*a^3 + 2*a^2 + 2*a, a^3 + 2*a^2 + 2, 2*a + 1, 2*a^2 + a, 2*a^3 + a^2, 2, 2*a, 2*a^2, 2*a^3, 2*a^3 + 2, 2*a^3 + 2*a + 2, 2*a^3 + 2*a^2 + 2*a + 2, a^3 + 2*a^2 + 2*a + 2, 2*a^2 + 2*a + 1, 2*a^3 + 2*a^2 + a, a^3 + a^2 + 2, 2*a^3 + 2*a + 1, 2*a^3 + 2*a^2 + a + 2, a^3 + a^2 + 2*a + 2, 2*a^3 + 2*a^2 + 2*a + 1, a^3 + 2*a^2 + a + 2, a^2 + 2*a + 1, a^3 + 2*a^2 + a, a^2 + 1, a^3 + a, a^3 + a^2 + 1, 2*a^3 + a + 1, 2*a^3 + a^2 + a + 2, a^2 + 2*a + 2, a^3 + 2*a^2 + 2*a, 2*a^2 + 1, 2*a^3 + a, 2*a^3 + a^2 + 2, 2*a + 2, 2*a^2 + 2*a, 2*a^3 + 2*a^2, a^3 + 2, a^3 + 2*a + 1, a^3 + 2*a^2 + a + 1, a^2 + a + 1, a^3 + a^2 + a, 2*a^3 + a^2 + 1, a + 2, a^2 + 2*a, a^3 + 2*a^2, 1]
>>> from sage.all import *
>>> F.list()
[0, a, a^2, a^3, a^3 + 1, a^3 + a + 1, a^3 + a^2 + a + 1, 2*a^3 + a^2 + a + 1, a^2 + a + 2, a^3 + a^2 + 2*a, 2*a^3 + 2*a^2 + 1, a^3 + a + 2, a^3 + a^2 + 2*a + 1, 2*a^3 + 2*a^2 + a + 1, a^3 + a^2 + a + 2, 2*a^3 + a^2 + 2*a + 1, 2*a^2 + a + 2, 2*a^3 + a^2 + 2*a, 2*a^2 + 2, 2*a^3 + 2*a, 2*a^3 + 2*a^2 + 2, a^3 + 2*a + 2, a^3 + 2*a^2 + 2*a + 1, 2*a^2 + a + 1, 2*a^3 + a^2 + a, a^2 + 2, a^3 + 2*a, a^3 + 2*a^2 + 1, a + 1, a^2 + a, a^3 + a^2, 2*a^3 + 1, 2*a^3 + a + 2, 2*a^3 + a^2 + 2*a + 2, 2*a^2 + 2*a + 2, 2*a^3 + 2*a^2 + 2*a, a^3 + 2*a^2 + 2, 2*a + 1, 2*a^2 + a, 2*a^3 + a^2, 2, 2*a, 2*a^2, 2*a^3, 2*a^3 + 2, 2*a^3 + 2*a + 2, 2*a^3 + 2*a^2 + 2*a + 2, a^3 + 2*a^2 + 2*a + 2, 2*a^2 + 2*a + 1, 2*a^3 + 2*a^2 + a, a^3 + a^2 + 2, 2*a^3 + 2*a + 1, 2*a^3 + 2*a^2 + a + 2, a^3 + a^2 + 2*a + 2, 2*a^3 + 2*a^2 + 2*a + 1, a^3 + 2*a^2 + a + 2, a^2 + 2*a + 1, a^3 + 2*a^2 + a, a^2 + 1, a^3 + a, a^3 + a^2 + 1, 2*a^3 + a + 1, 2*a^3 + a^2 + a + 2, a^2 + 2*a + 2, a^3 + 2*a^2 + 2*a, 2*a^2 + 1, 2*a^3 + a, 2*a^3 + a^2 + 2, 2*a + 2, 2*a^2 + 2*a, 2*a^3 + 2*a^2, a^3 + 2, a^3 + 2*a + 1, a^3 + 2*a^2 + a + 1, a^2 + a + 1, a^3 + a^2 + a, 2*a^3 + a^2 + 1, a + 2, a^2 + 2*a, a^3 + 2*a^2, 1]
sage: (a^3 + 2*a^2 + 2)*(2*a^3 + 2*a + 1)
2*a^3 + a^2 + a + 1
>>> from sage.all import *
>>> (a**Integer(3) + Integer(2)*a**Integer(2) + Integer(2))*(Integer(2)*a**Integer(3) + Integer(2)*a + Integer(1))
2*a^3 + a^2 + a + 1
\(F\) should be the splitting field of the polynomial \(x^{81}-x\), so it is very good that we get no output from the following cell, which combines a loop and a conditional statement.
sage: for a in F:
....: if not (a^81 - a == 0):
....: print("Oops!")
>>> from sage.all import *
>>> for a in F:
... if not (a**Integer(81) - a == Integer(0)):
... print("Oops!")
Field Extensions, Number Fields¶
Most things you will need in an undergraduate algebra classroom are already in Sage.
sage: N = QQ[sqrt(2)]
sage: N
Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?
>>> from sage.all import *
>>> N = QQ[sqrt(Integer(2))]
>>> N
Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?
sage: var('z')
z
sage: M.<a>=NumberField(z^2-2)
sage: M
Number Field in a with defining polynomial z^2 - 2
>>> from sage.all import *
>>> var('z')
z
>>> M = NumberField(z**Integer(2)-Integer(2), names=('a',)); (a,) = M._first_ngens(1)
>>> M
Number Field in a with defining polynomial z^2 - 2
sage: M.degree()
2
>>> from sage.all import *
>>> M.degree()
2
sage: M.is_galois()
True
>>> from sage.all import *
>>> M.is_galois()
True
sage: M.is_isomorphic(N)
True
>>> from sage.all import *
>>> M.is_isomorphic(N)
True