Hi, for many computations in algebraic number theory SAGE uses PARI in the background. It seems to me that the relevant functionality for computing ray class groups (that is present in PARI) is not yet wrapped conveniently in SAGE.
There are two ways to proceed: You could use PARI/GP directly from the command line (the functions you're looking for are basically bnrinit
to compute a representation of a ray class group as a product of cyclic groups and bnrisprincipal
to compute the image of an ideal in this representation, from which you can get the order). Alternatively, you can use SAGE's GP-Interface to do the same from within SAGE, I'll demonstrate both ways.
First, an example in PARI/GP to demonstrate the basic computation (some output omitted, $\mathfrak m = (3)$ and $K$ has no real archimedean places):
? K = bnfinit(x^6 + 76*x^4 + 2*x^3 + 2029*x^2 - 158*x + 18955)
? bnfcertify(K)
%2 = 1
? Kr = bnrinit(K, [3, []], 1)
? Kr.clgp.cyc
%4 = [6, 6] # => ray class group is C_6 x C_6
? J = idealhnf(Kr, 5, x^2 + 2*x + 23)
? bnrisprincipal(Kr,J)
%6 = [[4, 4]~, ...] # image of J in ray class group
The following provides a quick and dirty hack to do basically the same from SAGE, using its PARI/GP Interface:
class RayClassGroup(AbelianGroup_class):
def __init__(self, number_field, mod_ideal = 1, mod_archimedean = None):
if mod_archimedean == None:
mod_archimedean = [0] * len(number_field.real_places())
bnf = gp(number_field.pari_bnf())
# Use PARI to compute ray class group
bnr = bnf.bnrinit([mod_ideal, mod_archimedean],1)
invariants = bnr[5][2] # bnr.clgp.cyc
invariants = [ ZZ(x) for x in invariants ]
AbelianGroup_class.__init__(self, len(invariants), invariants)
self.__number_field = number_field
self.__bnr = bnr
def __call__(self, *args, **kwargs):
return group.Group.__call__(self, *args, **kwargs)
def _element_constructor_(self, *args, **kwargs):
if isinstance(args[0], AbelianGroupElement):
return AbelianGroupElement(self, args[0])
else:
I = self.__number_field.ideal(*args, **kwargs)
# Use PARI to compute class of given ideal
g = self.__bnr.bnrisprincipal(I)[1]
g = [ ZZ(x) for x in g ]
return AbelianGroupElement(self, g)
After running the above code (either in a notebook cell or the sage command-line, be careful to preserve the whitespace exactly as is), you can use the class like this:
K.<a> = NumberField(x^6 + 76*x^4 + 2*x^3 + 2029*x^2 - 158*x + 18955)
G = RayClassGroup(K, K.ideal(3), [])
J = K.ideal([5, a^2 + 2*a + 23])
G(J).order()
If you have real places, the infinite part is specified using 0's and 1's, e.g.
K.<a> = NumberField(x^6 - 3*x^5 - 3*x^4 + 10*x^3 + 3*x^2 - 6*x + 1)
G = RayClassGroup(K, K.ideal(1), [0,1,1,1,1,1])
gives trivial ray class group, while
K.<a> = NumberField(x^6 - 3*x^5 - 3*x^4 + 10*x^3 + 3*x^2 - 6*x + 1)
G = RayClassGroup(K, K.ideal(1), [1,1,1,1,1,1])
gives $C_2$. The order of ... (more)