Ray Class Groups

Class Groups of Number Fields

Trac-ticket #15829 adds (among other things) ray class groups to SageMath. The ticket is not yet finished and included into SageMath. It does already contain this file, from Robbert Harron, implementing ray class groups in SageMath. We use this file to have ray class groups functionality available for our adèles and idèles package.

We can compute class groups, ray class groups, and \(S\)-class groups of number fields, and we do so by wrapping the functionality from the PARI C-library. Some of what can be computed includes the group structure, representative ideals, the class of a given ideal, generators of the group, and products of elements. This file also implements moduli of number fields.

AUTHORS:

  • Robert Harron (2016-08-15): implemented ray class groups and moduli

EXAMPLES:

Computations with a ray class group of a quadratic field:

sage: F = QuadraticField(40)
sage: m = F.ideal(3).modulus([0, 1]); m
(Fractional ideal (3)) * infinity_0 * infinity_1
sage: R = F.ray_class_group(m); R
Ray class group of order 8 with structure C4 x C2 of Number Field in a with defining polynomial x^2 - 40 of modulus (Fractional ideal (3)) * infinity_0 * infinity_1

Unlike for class groups and \(S\)-class groups, ray class group elements do not carry around a representative ideal (for reasons of efficiency). Nevertheless, one can be demanded. The returned ideal should be somewhat ‘small.’

sage: R.gens()
(c0, c1)
sage: R.gens_ideals()
(Fractional ideal (430, 1/2*a + 200), Fractional ideal (-3/2*a + 2))
sage: c = R.gens()[0]^3 * R.gens()[1]; c
c0^3*c1
sage: c.ideal()
Fractional ideal (10, a)
sage: c = R(F.ideal(2)); c
c0^2
sage: R.gen(0).ideal()^2
Fractional ideal (30*a - 470)
sage: R(R.gen(0).ideal()^2).ideal()
Fractional ideal (2)
class adeles.ray_class_group.Modulus(finite, infinite=None, check=True)

Bases: sage.structure.sage_object.SageObject

Modulus of a number field

equivalent_coprime_ideal_multiplier(I, other)

Given I coprime to this modulus \(m\), return a number field element \(\beta\) such that \(\beta I\) is coprime to the modulus other and equivalent to I \(\mathrm{mod}^\ast m\); in particular, \(\beta\) will be \(1 \mathrm{mod}^\ast m\).

EXAMPLES:

An example with two prime factors difference between this modulus and other.

sage: F.<a> = QuadraticField(5)
sage: m_small = F.modulus(3/2*a - 1/2, [0, 1])
sage: m_big = F.modulus(2*a - 30, [0, 1])
sage: m_small.equivalent_coprime_ideal_multiplier(F.ideal(6), m_big)
109/54
equivalent_ideal_coprime_to_other(I, other)

Given I coprime to this modulus \(m\), return an ideal \(J\) such that \(J\) is coprime to the modulus other and equivalent to I \(\mathrm{mod}^\ast m\).

This is useful for lowering the level of a non-primitive Hecke character.

INPUT:

  • I – an ideal relatively prime to this modulus (not checked).

  • other – some other modulus.

OUTPUT:

an ideal coprime to other and equivalent to I in the ray class group modulo this modulus.

fix_signs(a)

Given a in self.number_field(), find \(b\) congruent to a \(mod^\ast\) self.finite_part() such that \(b\) is positive at the infinite places dividing self.

class adeles.ray_class_group.RayClassGroup(gens_orders, names, modulus, gens, bnr, proof=True)

Bases: sage.groups.abelian_gps.abelian_group.AbelianGroup_class

Ray class group of a number field

Element

alias of RayClassGroupElement

gens_ideals()

EXAMPLES:

sage: class Foo:
....:     def __init__(self, x):
....:         self._x = x
....:     @cached_method
....:     def f(self):
....:         return self._x^2
sage: a = Foo(2)
sage: print(a.f.cache)
None
sage: a.f()
4
sage: a.f.cache
4
ray_class_field(subgroup=None, names=None, algorithm='stark')

Two different algorithms are possible: pari’s bnrstark and rnfkummer. The first one uses the Stark conjecture and only deals with totally real extensions of a totally real base field. The second one uses Kummer theory and only deals with extensions of prime degree.

INPUT:

  • algorithm – (default: stark) if the value is stark, then pari’s bnrstark function is tried first, and if that fails, rnfkummer will be attempted. If the value is kummer, then pari’s rnfkummer is tried first, with bnrstark as a backup. Using stark_only or kummer_only will just raise an exception if the first attempt fails.

OUTPUT:

The class field corresponding to the given subgroup, or the ray class field if subgroup is None, as a relative number field.

EXAMPLES:

Class fields of \(\QQ(\sqrt{3})\):

sage: F.<a> = QuadraticField(3)
sage: m = F.ideal(7).modulus()
sage: R = F.ray_class_group(m)
sage: R.ray_class_field(names='b')
Number Field in b with defining polynomial x^6 + a*x^5 - 4*x^4 - 4*a*x^3 + 2*x^2 + 2*a*x - 1 over its base field
sage: S = R.subgroup([R.gen()^2])
sage: R.ray_class_field(S, names='b')
Number Field in b with defining polynomial x^2 - a*x - 1 over its base field
sage: m = F.modulus(20)
sage: R = F.ray_class_group(m)
sage: S = R.subgroup([R.gens()[0]^2, R.gens()[1]])
sage: R.ray_class_field(S, names='b')
Number Field in b with defining polynomial x^2 + (a - 1)*x + 2*a - 4 over its base field

An example where pari’s bnrstark fails, but rnfkummer saves the day:

sage: F.<a> = NumberField(x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9)
sage: m = F.ideal(2).modulus()
sage: R = F.ray_class_group(m)
sage: set_verbose(1)
sage: K = R.ray_class_field(names='b'); K
verbose 1 (...: class_group.py, ray_class_field) bnrstark failed; trying rnfkummer.
Number Field in b with defining polynomial x^2 + (1/3*a^6 - 10/3*a^4 + 5*a^2)*x + 1/3*a^6 - 1/3*a^5 - 11/3*a^4 + 3*a^3 + 8*a^2 - 4*a - 5 over its base field
sage: set_verbose(0)
class adeles.ray_class_group.RayClassGroupElement(parent, exponents)

Bases: sage.groups.abelian_gps.abelian_group_element.AbelianGroupElement

Element of a ray class group

ideal(reduce=True)

Return an ideal representing this ray class.

If reduce is True (by default) the returned ideal is reduced to ‘small’ (this can be slow on large inputs).

INPUT:

  • reduce – (default: True) determine whether or not to output a ‘small’ representative.

OUTPUT:

An ideal representing this ray class. If reduce is True, the ideal returned is made ‘small’ by the ideal’s reduce_equiv function (and reduce_equiv is used at each step of computing this representative). Otherwise, the output is just the appropriate product of the powers of the generators of the ray class group.

EXAMPLES:

Over a real quadratic field field of class number 1:

sage: F.<a> = NumberField(x^2 - 5)
sage: m = F.ideal(11).modulus([0, 1])
sage: R = F.ray_class_group(m)
sage: c0, c1 = R.gens()
sage: c = c0^4*c1; c.ideal()
Fractional ideal (-a)
sage: c.ideal(False)
Fractional ideal (-6242265*a + 1268055)

Over a real quadratic field of class number 2:

sage: F = QuadraticField(40)
sage: R = F.ray_class_group(F.prime_above(13).modulus([0, 1]))
sage: for c in R:
...       if R(c.ideal()) != c:
...           print "Bug!"
adeles.ray_class_group.pari_extended_ideal_to_sage(K, Ix)

Convert an ‘extended ideal’ in pari format to an ideal in Sage.

INPUT:

  • K – number field to which the ideal belongs

  • Ix – A pair whose first entry is a pari ideal and whose second entry is a pari factorization matrix representing an algebraic number.

OUTPUT:

  • The ideal that is the product of the ideal Ix[0] and the principal ideal generated by Ix[1].

EXAMPLES:

sage: F = NumberField(x^3 - 2, 'z')
sage: I = F.ideal(27)
sage: a = Matrix(0)
sage: pari_extended_ideal_to_sage(F, pari([I, a])) == I
True
sage: factorization_matrix = pari([pari([pari([31, 0, 1]).Col(), 1]).Mat(), pari([pari([5, 1, 0]).Col(), 1]).Mat()]).Col().matconcat()
sage: pari_extended_ideal_to_sage(F, pari([I, factorization_matrix]))
Fractional ideal (-135*z^2 - 837*z - 4239)
sage: pari_extended_ideal_to_sage(F, F.ray_class_group(I).gens_values()[0])
Fractional ideal (-8*z^2 - 9*z + 1)
adeles.ray_class_group.pari_real_places_to_sage(K)

Return a list converting from the ordering of real places in pari to that of Sage’s places().

EXAMPLES:

A totally real quartic field where the pari and Sage orderings are different.

sage: x = polygen(QQ)
sage: f = x^4 - x^3 - 3*x^2 + x + 1
sage: F.<a> = NumberField(f(1-2*x))
sage: F.defining_polynomial()
16*x^4 - 24*x^3 + 8*x - 1
sage: F.pari_polynomial()
x^4 - 6*x^2 - 5*x - 1
sage: pari_real_places_to_sage(F)
(0, 3, 2, 1)

A quintic field with three real places.

sage: x = polygen(QQ)
sage: f = x^5 - x^3 - 2 * x^2 + 1
sage: F.<a> = NumberField(f(1 - x))
sage: pari_real_places_to_sage(F)
(2, 1, 0)
adeles.ray_class_group.ray_class_group(K, modulus, proof=True, names='c')

Return the ray class group modulo modulus.

EXAMPLES:

Ray class group of a real quadratic field of class number 1.

sage: F = NumberField(x^2 - 5, 'a')
sage: m = F.modulus(F.prime_above(5) * F.prime_above(29), [0, 1])
sage: G = F.ray_class_group(m); G
Ray class group of order 8 with structure C4 x C2 of Number Field in a with defining polynomial x^2 - 5 of modulus (Fractional ideal (-11/2*a - 5/2)) * infinity_0 * infinity_1
sage: G.elementary_divisors()
(2, 4)
sage: G.gens_ideals()
(Fractional ideal (31), Fractional ideal (12672))
sage: G.gens_orders()
(4, 2)

Ray class group of an imaginary quadratic field of class number 3.

sage: F.<a> = QuadraticField(-23)
sage: R = F.ray_class_group(F.ideal(3/2 + a/2)); R
Ray class group of order 6 with structure C6 of Number Field in a with defining polynomial x^2 + 23 of modulus Fractional ideal (1/2*a + 3/2)
sage: R.gens_ideals()
(Fractional ideal (3, 1/2*a + 1/2),)
sage: R.modulus().finite_part().norm()
8
sage: F.class_group().gens_ideals()
(Fractional ideal (2, 1/2*a - 1/2),)

Over \(\QQ\), the ray class group modulo \((m)\infty\) is the unit group of \(\ZZ/m\ZZ\), while the ray class group modulo \((m)\) is the latter modulo \(\{\pm1\}\).

sage: Q = NumberField(x - 1, 'a')
sage: Q.ray_class_group(Q.ideal(40).modulus([0])).gens_ideals()
(Fractional ideal (17), Fractional ideal (31), Fractional ideal (21))
sage: Zmod(40).unit_gens()
(31, 21, 17)
sage: Q.ray_class_group(Q.ideal(40)).gens_ideals()
(Fractional ideal (17), Fractional ideal (21))