Units and \(S\)-unit groups of number fields#
EXAMPLES:
sage: x = polygen(QQ)
sage: K.<a> = NumberField(x^4 - 8*x^2 + 36)
sage: UK = UnitGroup(K); UK
Unit group with structure C4 x Z of
Number Field in a with defining polynomial x^4 - 8*x^2 + 36
>>> from sage.all import *
>>> x = polygen(QQ)
>>> K = NumberField(x**Integer(4) - Integer(8)*x**Integer(2) + Integer(36), names=('a',)); (a,) = K._first_ngens(1)
>>> UK = UnitGroup(K); UK
Unit group with structure C4 x Z of
Number Field in a with defining polynomial x^4 - 8*x^2 + 36
The first generator is a primitive root of unity in the field:
sage: UK.gens()
(u0, u1)
sage: UK.gens_values() # random
[-1/12*a^3 + 1/6*a, 1/24*a^3 + 1/4*a^2 - 1/12*a - 1]
sage: UK.gen(0).value()
1/12*a^3 - 1/6*a
sage: UK.gen(0)
u0
sage: UK.gen(0) + K.one() # coerce abstract generator into number field
1/12*a^3 - 1/6*a + 1
sage: [u.multiplicative_order() for u in UK.gens()]
[4, +Infinity]
sage: UK.rank()
1
sage: UK.ngens()
2
>>> from sage.all import *
>>> UK.gens()
(u0, u1)
>>> UK.gens_values() # random
[-1/12*a^3 + 1/6*a, 1/24*a^3 + 1/4*a^2 - 1/12*a - 1]
>>> UK.gen(Integer(0)).value()
1/12*a^3 - 1/6*a
>>> UK.gen(Integer(0))
u0
>>> UK.gen(Integer(0)) + K.one() # coerce abstract generator into number field
1/12*a^3 - 1/6*a + 1
>>> [u.multiplicative_order() for u in UK.gens()]
[4, +Infinity]
>>> UK.rank()
1
>>> UK.ngens()
2
Units in the field can be converted into elements of the unit group represented as elements of an abstract multiplicative group:
sage: UK(1)
1
sage: UK(-1)
u0^2
sage: [UK(u) for u in (x^4 - 1).roots(K, multiplicities=False)]
[1, u0^2, u0, u0^3]
sage: UK.fundamental_units() # random
[1/24*a^3 + 1/4*a^2 - 1/12*a - 1]
sage: torsion_gen = UK.torsion_generator(); torsion_gen
u0
sage: torsion_gen.value()
1/12*a^3 - 1/6*a
sage: UK.zeta_order()
4
sage: UK.roots_of_unity()
[1/12*a^3 - 1/6*a, -1, -1/12*a^3 + 1/6*a, 1]
>>> from sage.all import *
>>> UK(Integer(1))
1
>>> UK(-Integer(1))
u0^2
>>> [UK(u) for u in (x**Integer(4) - Integer(1)).roots(K, multiplicities=False)]
[1, u0^2, u0, u0^3]
>>> UK.fundamental_units() # random
[1/24*a^3 + 1/4*a^2 - 1/12*a - 1]
>>> torsion_gen = UK.torsion_generator(); torsion_gen
u0
>>> torsion_gen.value()
1/12*a^3 - 1/6*a
>>> UK.zeta_order()
4
>>> UK.roots_of_unity()
[1/12*a^3 - 1/6*a, -1, -1/12*a^3 + 1/6*a, 1]
Exp and log functions provide maps between units as field elements and exponent vectors with respect to the generators:
sage: u = UK.exp([13,10]); u # random
-41/8*a^3 - 55/4*a^2 + 41/4*a + 55
sage: UK.log(u)
(1, 10)
sage: u = UK.fundamental_units()[0]
sage: [UK.log(u^k) == (0,k) for k in range(10)]
[True, True, True, True, True, True, True, True, True, True]
sage: all(UK.log(u^k) == (0,k) for k in range(10))
True
sage: K.<a> = NumberField(x^5 - 2,'a')
sage: UK = UnitGroup(K)
sage: UK.rank()
2
sage: UK.fundamental_units()
[a^3 + a^2 - 1, a - 1]
>>> from sage.all import *
>>> u = UK.exp([Integer(13),Integer(10)]); u # random
-41/8*a^3 - 55/4*a^2 + 41/4*a + 55
>>> UK.log(u)
(1, 10)
>>> u = UK.fundamental_units()[Integer(0)]
>>> [UK.log(u**k) == (Integer(0),k) for k in range(Integer(10))]
[True, True, True, True, True, True, True, True, True, True]
>>> all(UK.log(u**k) == (Integer(0),k) for k in range(Integer(10)))
True
>>> K = NumberField(x**Integer(5) - Integer(2),'a', names=('a',)); (a,) = K._first_ngens(1)
>>> UK = UnitGroup(K)
>>> UK.rank()
2
>>> UK.fundamental_units()
[a^3 + a^2 - 1, a - 1]
\(S\)-unit groups may be constructed, where \(S\) is a set of primes:
sage: K.<a> = NumberField(x^6 + 2)
sage: S = K.ideal(3).prime_factors(); S
[Fractional ideal (3, a + 1), Fractional ideal (3, a - 1)]
sage: SUK = UnitGroup(K,S=tuple(S)); SUK
S-unit group with structure C2 x Z x Z x Z x Z of
Number Field in a with defining polynomial x^6 + 2
with S = (Fractional ideal (3, a + 1), Fractional ideal (3, a - 1))
sage: SUK.primes()
(Fractional ideal (3, a + 1), Fractional ideal (3, a - 1))
sage: SUK.rank()
4
sage: SUK.gens_values()
[-1, a^2 + 1, -a^5 - a^4 + a^2 + a + 1, a + 1, a - 1]
sage: u = 9*prod(SUK.gens_values()); u
-18*a^5 - 18*a^4 - 18*a^3 - 9*a^2 + 9*a + 27
sage: SUK.log(u)
(1, 3, 1, 7, 7)
sage: u == SUK.exp((1,3,1,7,7))
True
>>> from sage.all import *
>>> K = NumberField(x**Integer(6) + Integer(2), names=('a',)); (a,) = K._first_ngens(1)
>>> S = K.ideal(Integer(3)).prime_factors(); S
[Fractional ideal (3, a + 1), Fractional ideal (3, a - 1)]
>>> SUK = UnitGroup(K,S=tuple(S)); SUK
S-unit group with structure C2 x Z x Z x Z x Z of
Number Field in a with defining polynomial x^6 + 2
with S = (Fractional ideal (3, a + 1), Fractional ideal (3, a - 1))
>>> SUK.primes()
(Fractional ideal (3, a + 1), Fractional ideal (3, a - 1))
>>> SUK.rank()
4
>>> SUK.gens_values()
[-1, a^2 + 1, -a^5 - a^4 + a^2 + a + 1, a + 1, a - 1]
>>> u = Integer(9)*prod(SUK.gens_values()); u
-18*a^5 - 18*a^4 - 18*a^3 - 9*a^2 + 9*a + 27
>>> SUK.log(u)
(1, 3, 1, 7, 7)
>>> u == SUK.exp((Integer(1),Integer(3),Integer(1),Integer(7),Integer(7)))
True
A relative number field example:
sage: L.<a, b> = NumberField([x^2 + x + 1, x^4 + 1])
sage: UL = L.unit_group(); UL
Unit group with structure C24 x Z x Z x Z of
Number Field in a with defining polynomial x^2 + x + 1 over its base field
sage: UL.gens_values() # random
[-b^3*a - b^3, -b^3*a + b, (-b^3 - b^2 - b)*a - b - 1, (-b^3 - 1)*a - b^2 + b - 1]
sage: UL.zeta_order()
24
sage: UL.roots_of_unity()
[-b*a,
-b^2*a - b^2,
-b^3,
-a,
-b*a - b,
-b^2,
b^3*a,
-a - 1,
-b,
b^2*a,
b^3*a + b^3,
-1,
b*a,
b^2*a + b^2,
b^3,
a,
b*a + b,
b^2,
-b^3*a,
a + 1,
b,
-b^2*a,
-b^3*a - b^3,
1]
>>> from sage.all import *
>>> L = NumberField([x**Integer(2) + x + Integer(1), x**Integer(4) + Integer(1)], names=('a', 'b',)); (a, b,) = L._first_ngens(2)
>>> UL = L.unit_group(); UL
Unit group with structure C24 x Z x Z x Z of
Number Field in a with defining polynomial x^2 + x + 1 over its base field
>>> UL.gens_values() # random
[-b^3*a - b^3, -b^3*a + b, (-b^3 - b^2 - b)*a - b - 1, (-b^3 - 1)*a - b^2 + b - 1]
>>> UL.zeta_order()
24
>>> UL.roots_of_unity()
[-b*a,
-b^2*a - b^2,
-b^3,
-a,
-b*a - b,
-b^2,
b^3*a,
-a - 1,
-b,
b^2*a,
b^3*a + b^3,
-1,
b*a,
b^2*a + b^2,
b^3,
a,
b*a + b,
b^2,
-b^3*a,
a + 1,
b,
-b^2*a,
-b^3*a - b^3,
1]
A relative extension example, which worked thanks to the code review by F.W.Clarke:
sage: PQ.<X> = QQ[]
sage: F.<a, b> = NumberField([X^2 - 2, X^2 - 3])
sage: PF.<Y> = F[]
sage: K.<c> = F.extension(Y^2 - (1 + a)*(a + b)*a*b)
sage: K.unit_group()
Unit group with structure C2 x Z x Z x Z x Z x Z x Z x Z of Number Field in c
with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field
>>> from sage.all import *
>>> PQ = QQ['X']; (X,) = PQ._first_ngens(1)
>>> F = NumberField([X**Integer(2) - Integer(2), X**Integer(2) - Integer(3)], names=('a', 'b',)); (a, b,) = F._first_ngens(2)
>>> PF = F['Y']; (Y,) = PF._first_ngens(1)
>>> K = F.extension(Y**Integer(2) - (Integer(1) + a)*(a + b)*a*b, names=('c',)); (c,) = K._first_ngens(1)
>>> K.unit_group()
Unit group with structure C2 x Z x Z x Z x Z x Z x Z x Z of Number Field in c
with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field
AUTHOR:
John Cremona
- class sage.rings.number_field.unit_group.UnitGroup(number_field, proof=True, S=None)[source]#
Bases:
AbelianGroupWithValues_class
The unit group or an \(S\)-unit group of a number field.
- exp(exponents)[source]#
Return unit with given exponents with respect to group generators.
INPUT:
u
– Any object from which an element of the unit group’s number field \(K\) may be constructed; an error is raised if an element of \(K\) cannot be constructed from \(u\), or if the element constructed is not a unit.
OUTPUT: a list of integers giving the exponents of \(u\) with respect to the unit group’s basis.
EXAMPLES:
sage: x = polygen(QQ) sage: K.<z> = CyclotomicField(13) sage: UK = UnitGroup(K) sage: [UK.log(u) for u in UK.gens()] [(1, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0), (0, 0, 0, 1, 0, 0), (0, 0, 0, 0, 1, 0), (0, 0, 0, 0, 0, 1)] sage: vec = [65,6,7,8,9,10] sage: unit = UK.exp(vec) sage: UK.log(unit) (13, 6, 7, 8, 9, 10) sage: u = UK.gens()[-1] sage: UK.exp(UK.log(u)) == u.value() True
>>> from sage.all import * >>> x = polygen(QQ) >>> K = CyclotomicField(Integer(13), names=('z',)); (z,) = K._first_ngens(1) >>> UK = UnitGroup(K) >>> [UK.log(u) for u in UK.gens()] [(1, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0), (0, 0, 0, 1, 0, 0), (0, 0, 0, 0, 1, 0), (0, 0, 0, 0, 0, 1)] >>> vec = [Integer(65),Integer(6),Integer(7),Integer(8),Integer(9),Integer(10)] >>> unit = UK.exp(vec) >>> UK.log(unit) (13, 6, 7, 8, 9, 10) >>> u = UK.gens()[-Integer(1)] >>> UK.exp(UK.log(u)) == u.value() True
An S-unit example:
sage: SUK = UnitGroup(K,S=2) sage: v = (3,1,4,1,5,9,2) sage: u = SUK.exp(v); u 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 sage: SUK.log(u) (3, 1, 4, 1, 5, 9, 2) sage: SUK.log(u) == v True
>>> from sage.all import * >>> SUK = UnitGroup(K,S=Integer(2)) >>> v = (Integer(3),Integer(1),Integer(4),Integer(1),Integer(5),Integer(9),Integer(2)) >>> u = SUK.exp(v); u 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 >>> SUK.log(u) (3, 1, 4, 1, 5, 9, 2) >>> SUK.log(u) == v True
- fundamental_units()[source]#
Return generators for the free part of the unit group, as a list.
EXAMPLES:
sage: x = polygen(QQ) sage: K.<a> = NumberField(x^4 + 23) sage: U = UnitGroup(K) sage: U.fundamental_units() # random [1/4*a^3 - 7/4*a^2 + 17/4*a - 19/4]
>>> from sage.all import * >>> x = polygen(QQ) >>> K = NumberField(x**Integer(4) + Integer(23), names=('a',)); (a,) = K._first_ngens(1) >>> U = UnitGroup(K) >>> U.fundamental_units() # random [1/4*a^3 - 7/4*a^2 + 17/4*a - 19/4]
- log(u)[source]#
Return the exponents of the unit \(u\) with respect to group generators.
INPUT:
u
– Any object from which an element of the unit group’s number field \(K\) may be constructed; an error is raised if an element of \(K\) cannot be constructed from \(u\), or if the element constructed is not a unit.
OUTPUT: a list of integers giving the exponents of \(u\) with respect to the unit group’s basis.
EXAMPLES:
sage: x = polygen(QQ) sage: K.<z> = CyclotomicField(13) sage: UK = UnitGroup(K) sage: [UK.log(u) for u in UK.gens()] [(1, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0), (0, 0, 0, 1, 0, 0), (0, 0, 0, 0, 1, 0), (0, 0, 0, 0, 0, 1)] sage: vec = [65,6,7,8,9,10] sage: unit = UK.exp(vec); unit # random -253576*z^11 + 7003*z^10 - 395532*z^9 - 35275*z^8 - 500326*z^7 - 35275*z^6 - 395532*z^5 + 7003*z^4 - 253576*z^3 - 59925*z - 59925 sage: UK.log(unit) (13, 6, 7, 8, 9, 10)
>>> from sage.all import * >>> x = polygen(QQ) >>> K = CyclotomicField(Integer(13), names=('z',)); (z,) = K._first_ngens(1) >>> UK = UnitGroup(K) >>> [UK.log(u) for u in UK.gens()] [(1, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0), (0, 0, 0, 1, 0, 0), (0, 0, 0, 0, 1, 0), (0, 0, 0, 0, 0, 1)] >>> vec = [Integer(65),Integer(6),Integer(7),Integer(8),Integer(9),Integer(10)] >>> unit = UK.exp(vec); unit # random -253576*z^11 + 7003*z^10 - 395532*z^9 - 35275*z^8 - 500326*z^7 - 35275*z^6 - 395532*z^5 + 7003*z^4 - 253576*z^3 - 59925*z - 59925 >>> UK.log(unit) (13, 6, 7, 8, 9, 10)
An S-unit example:
sage: SUK = UnitGroup(K, S=2) sage: v = (3,1,4,1,5,9,2) sage: u = SUK.exp(v); u 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 sage: SUK.log(u) (3, 1, 4, 1, 5, 9, 2) sage: SUK.log(u) == v True
>>> from sage.all import * >>> SUK = UnitGroup(K, S=Integer(2)) >>> v = (Integer(3),Integer(1),Integer(4),Integer(1),Integer(5),Integer(9),Integer(2)) >>> u = SUK.exp(v); u 8732*z^11 - 15496*z^10 - 51840*z^9 - 68804*z^8 - 51840*z^7 - 15496*z^6 + 8732*z^5 - 34216*z^3 - 64312*z^2 - 64312*z - 34216 >>> SUK.log(u) (3, 1, 4, 1, 5, 9, 2) >>> SUK.log(u) == v True
- number_field()[source]#
Return the number field associated with this unit group.
EXAMPLES:
sage: U = UnitGroup(QuadraticField(-23, 'w')); U Unit group with structure C2 of Number Field in w with defining polynomial x^2 + 23 with w = 4.795831523312720?*I sage: U.number_field() Number Field in w with defining polynomial x^2 + 23 with w = 4.795831523312720?*I
>>> from sage.all import * >>> U = UnitGroup(QuadraticField(-Integer(23), 'w')); U Unit group with structure C2 of Number Field in w with defining polynomial x^2 + 23 with w = 4.795831523312720?*I >>> U.number_field() Number Field in w with defining polynomial x^2 + 23 with w = 4.795831523312720?*I
- primes()[source]#
Return the (possibly empty) list of primes associated with this S-unit group.
EXAMPLES:
sage: K.<a> = QuadraticField(-23) sage: S = tuple(K.ideal(3).prime_factors()); S (Fractional ideal (3, 1/2*a - 1/2), Fractional ideal (3, 1/2*a + 1/2)) sage: U = UnitGroup(K,S=tuple(S)); U S-unit group with structure C2 x Z x Z of Number Field in a with defining polynomial x^2 + 23 with a = 4.795831523312720?*I with S = (Fractional ideal (3, 1/2*a - 1/2), Fractional ideal (3, 1/2*a + 1/2)) sage: U.primes() == S True
>>> from sage.all import * >>> K = QuadraticField(-Integer(23), names=('a',)); (a,) = K._first_ngens(1) >>> S = tuple(K.ideal(Integer(3)).prime_factors()); S (Fractional ideal (3, 1/2*a - 1/2), Fractional ideal (3, 1/2*a + 1/2)) >>> U = UnitGroup(K,S=tuple(S)); U S-unit group with structure C2 x Z x Z of Number Field in a with defining polynomial x^2 + 23 with a = 4.795831523312720?*I with S = (Fractional ideal (3, 1/2*a - 1/2), Fractional ideal (3, 1/2*a + 1/2)) >>> U.primes() == S True
- rank()[source]#
Return the rank of the unit group.
EXAMPLES:
sage: K.<z> = CyclotomicField(13) sage: UnitGroup(K).rank() 5 sage: SUK = UnitGroup(K, S=2); SUK.rank() 6
>>> from sage.all import * >>> K = CyclotomicField(Integer(13), names=('z',)); (z,) = K._first_ngens(1) >>> UnitGroup(K).rank() 5 >>> SUK = UnitGroup(K, S=Integer(2)); SUK.rank() 6
- roots_of_unity()[source]#
Return all the roots of unity in this unit group, primitive or not.
EXAMPLES:
sage: x = polygen(QQ) sage: K.<b> = NumberField(x^2 + 1) sage: U = UnitGroup(K) sage: zs = U.roots_of_unity(); zs [b, -1, -b, 1] sage: [ z**U.zeta_order() for z in zs ] [1, 1, 1, 1]
>>> from sage.all import * >>> x = polygen(QQ) >>> K = NumberField(x**Integer(2) + Integer(1), names=('b',)); (b,) = K._first_ngens(1) >>> U = UnitGroup(K) >>> zs = U.roots_of_unity(); zs [b, -1, -b, 1] >>> [ z**U.zeta_order() for z in zs ] [1, 1, 1, 1]
- torsion_generator()[source]#
Return a generator for the torsion part of the unit group.
EXAMPLES:
sage: x = polygen(QQ) sage: K.<a> = NumberField(x^4 - x^2 + 4) sage: U = UnitGroup(K) sage: U.torsion_generator() u0 sage: U.torsion_generator().value() # random -1/4*a^3 - 1/4*a + 1/2
>>> from sage.all import * >>> x = polygen(QQ) >>> K = NumberField(x**Integer(4) - x**Integer(2) + Integer(4), names=('a',)); (a,) = K._first_ngens(1) >>> U = UnitGroup(K) >>> U.torsion_generator() u0 >>> U.torsion_generator().value() # random -1/4*a^3 - 1/4*a + 1/2
- zeta(n=2, all=False)[source]#
Return one, or a list of all, primitive \(n\)-th root of unity in this unit group.
EXAMPLES:
sage: x = polygen(QQ) sage: K.<z> = NumberField(x^2 + 3) sage: U = UnitGroup(K) sage: U.zeta(1) 1 sage: U.zeta(2) -1 sage: U.zeta(2, all=True) [-1] sage: U.zeta(3) -1/2*z - 1/2 sage: U.zeta(3, all=True) [-1/2*z - 1/2, 1/2*z - 1/2] sage: U.zeta(4) Traceback (most recent call last): ... ValueError: n (=4) does not divide order of generator sage: r.<x> = QQ[] sage: K.<b> = NumberField(x^2 + 1) sage: U = UnitGroup(K) sage: U.zeta(4) b sage: U.zeta(4,all=True) [b, -b] sage: U.zeta(3) Traceback (most recent call last): ... ValueError: n (=3) does not divide order of generator sage: U.zeta(3, all=True) []
>>> from sage.all import * >>> x = polygen(QQ) >>> K = NumberField(x**Integer(2) + Integer(3), names=('z',)); (z,) = K._first_ngens(1) >>> U = UnitGroup(K) >>> U.zeta(Integer(1)) 1 >>> U.zeta(Integer(2)) -1 >>> U.zeta(Integer(2), all=True) [-1] >>> U.zeta(Integer(3)) -1/2*z - 1/2 >>> U.zeta(Integer(3), all=True) [-1/2*z - 1/2, 1/2*z - 1/2] >>> U.zeta(Integer(4)) Traceback (most recent call last): ... ValueError: n (=4) does not divide order of generator >>> r = QQ['x']; (x,) = r._first_ngens(1) >>> K = NumberField(x**Integer(2) + Integer(1), names=('b',)); (b,) = K._first_ngens(1) >>> U = UnitGroup(K) >>> U.zeta(Integer(4)) b >>> U.zeta(Integer(4),all=True) [b, -b] >>> U.zeta(Integer(3)) Traceback (most recent call last): ... ValueError: n (=3) does not divide order of generator >>> U.zeta(Integer(3), all=True) []
- zeta_order()[source]#
Returns the order of the torsion part of the unit group.
EXAMPLES:
sage: x = polygen(QQ) sage: K.<a> = NumberField(x^4 - x^2 + 4) sage: U = UnitGroup(K) sage: U.zeta_order() 6
>>> from sage.all import * >>> x = polygen(QQ) >>> K = NumberField(x**Integer(4) - x**Integer(2) + Integer(4), names=('a',)); (a,) = K._first_ngens(1) >>> U = UnitGroup(K) >>> U.zeta_order() 6