Ask Your Question

Revision history [back]

In the past 8 years there have been some changes to SageMath, so it is understandable that this code no longer works. The main issue is that AbelianGroup_class (now) derives from UniqueRepresentation, and this puts some limitations on what can be passed to the constructor (i.e. to __init__). In particular, the arguments should be hashable, so lists (as in the OP from 8 years ago) are not allowed, and should be replaced by tuples. (A way to get around this would be to call the class RayClassGroup_class, and to define an ordinary function RayClassGroup that creates instances of it. This is now a common pattern in the SageMath source code, also used with AbelianGroup.) Also, the constructor of AbelianGroup_class has changed. Further the custom __call__ method seems to be no longer necessary, and as already mentioned some import statements were missing. Here is the updated class:

from sage.groups.abelian_gps.abelian_group import AbelianGroup_class
from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement

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 = tuple(ZZ(x) for x in invariants)

        super().__init__(invariants, names='f')
        self.__number_field = number_field
        self.__bnr = bnr

    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)

As already mentioned, the constructor should be passed tuples, so the examples become:

sage: K.<a> = NumberField(x^6 + 76*x^4 + 2*x^3 + 2029*x^2 - 158*x + 18955)
sage: G = RayClassGroup(K, K.ideal(3), tuple())
sage: J = K.ideal([5, a^2 + 2*a + 23])
sage: G(J).order()
3
sage: K.<a> = NumberField(x^6 - 3*x^5 - 3*x^4 + 10*x^3 + 3*x^2 - 6*x + 1)
sage: G = RayClassGroup(K, K.ideal(1), (0,1,1,1,1,1)); G
Trivial Abelian group
sage: K.<a> = NumberField(x^6 - 3*x^5 - 3*x^4 + 10*x^3 + 3*x^2 - 6*x + 1)
sage: G = RayClassGroup(K, K.ideal(1), (1,1,1,1,1,1)); G
Multiplicative Abelian group isomorphic to C2

I don't know anything about ray class groups, but based on the original post I assume this is correct.