def canonical_parameters(group, weight, sign, base_ring): """ Return the canonically normalized parameters associated to a choice of group, weight, sign, and base_ring. That is, normalize each of these to be of the correct type, perform all appropriate type checking, etc. EXAMPLES:: sage: p1 = sage.modular.modsym.modsym.canonical_parameters(5,int(2),1,QQ) ; p1 (Congruence Subgroup Gamma0(5), 2, 1, Rational Field) sage: p2 = sage.modular.modsym.modsym.canonical_parameters(Gamma0(5),2,1,QQ) ; p2 (Congruence Subgroup Gamma0(5), 2, 1, Rational Field) sage: p1 == p2 True sage: type(p1[1]) <type 'sage.rings.integer.Integer'> """ sign = rings.Integer(sign) if not (sign in [-1, 0, 1]): raise ValueError("sign must be -1, 0, or 1") weight = rings.Integer(weight) if weight <= 1: raise ValueError("the weight must be at least 2") if isinstance(group, (int, rings.Integer)): group = arithgroup.Gamma0(group) elif isinstance(group, dirichlet.DirichletCharacter): try: eps = group.minimize_base_ring() except NotImplementedError: # TODO -- implement minimize_base_ring over finite fields eps = group G = eps.parent() if eps.is_trivial(): group = arithgroup.Gamma0(eps.modulus()) else: group = (eps, G) if base_ring is None: base_ring = eps.base_ring() if base_ring is None: base_ring = rational_field.RationalField() if not is_CommutativeRing(base_ring): raise TypeError("base_ring (=%s) must be a commutative ring" % base_ring) if not base_ring.is_field(): raise TypeError("(currently) base_ring (=%s) must be a field" % base_ring) return group, weight, sign, base_ring
def parse_label(s): """ Given a string s corresponding to a newform label, return the corresponding group and index. EXAMPLES:: sage: sage.modular.modform.constructor.parse_label('11a') (Congruence Subgroup Gamma0(11), 0) sage: sage.modular.modform.constructor.parse_label('11aG1') (Congruence Subgroup Gamma1(11), 0) sage: sage.modular.modform.constructor.parse_label('11wG1') (Congruence Subgroup Gamma1(11), 22) """ m = re.match(r'(\d+)([a-z]+)((?:G.*)?)$', s) if not m: raise ValueError, "Invalid label: %s" % s N, order, G = m.groups() N = int(N) index = 0 for c in reversed(order): index = 26*index + ord(c)-ord('a') if G == '' or G == 'G0': G = arithgroup.Gamma0(N) elif G == 'G1': G = arithgroup.Gamma1(N) elif G[:2] == 'GH': if G[2] != '[' or G[-1] != ']': raise ValueError, "Invalid congruence subgroup label: %s" % G gens = [int(g.strip()) for g in G[3:-1].split(',')] return arithgroup.GammaH(N, gens) else: raise ValueError, "Invalid congruence subgroup label: %s" % G return G, index
def __init__(self, level, weight, sign, F): """ Initialize a space of boundary symbols of weight k for Gamma_0(N) over base field F. INPUT: - ``level`` - int, the level - ``weight`` - integer weight = 2. - ``sign`` - int, either -1, 0, or 1 - ``F`` - field EXAMPLES:: sage: B = ModularSymbols(Gamma0(2), 5).boundary_space() sage: type(B) <class 'sage.modular.modsym.boundary.BoundarySpace_wtk_g0_with_category'> sage: B == loads(dumps(B)) True """ level = int(level) sign = int(sign) weight = int(weight) if not sign in [-1, 0, 1]: raise ArithmeticError, "sign must be an int in [-1,0,1]" if level <= 0: raise ArithmeticError, "level must be positive" BoundarySpace.__init__(self, weight=weight, group=arithgroup.Gamma0(level), sign=sign, base_ring=F)
def __init__(self, level, weight): r""" Create a space of modular symbols for `\Gamma_0(N)` of given weight defined over `\QQ`. EXAMPLES:: sage: m = ModularForms(Gamma0(11),4); m Modular Forms space of dimension 4 for Congruence Subgroup Gamma0(11) of weight 4 over Rational Field sage: type(m) <class 'sage.modular.modform.ambient_g0.ModularFormsAmbient_g0_Q_with_category'> """ ambient.ModularFormsAmbient.__init__(self, arithgroup.Gamma0(level), weight, rings.QQ)
def __init__(self, group = arithgroup.Gamma0(1), weight = 2, sign = 0, base_ring = rings.QQ, character = None): """ Space of boundary symbols for a congruence subgroup of SL_2(Z). This class is an abstract base class, so only derived classes should be instantiated. INPUT: - ``weight`` - int, the weight - ``group`` - arithgroup.congroup_generic.CongruenceSubgroup, a congruence subgroup. - ``sign`` - int, either -1, 0, or 1 - ``base_ring`` - rings.Ring (defaults to the rational numbers) EXAMPLES:: sage: B = ModularSymbols(Gamma0(11),2).boundary_space() sage: isinstance(B, sage.modular.modsym.boundary.BoundarySpace) True sage: B == loads(dumps(B)) True """ weight = int(weight) if weight <= 1: raise ArithmeticError("weight must be at least 2") if not arithgroup.is_CongruenceSubgroup(group): raise TypeError("group must be a congruence subgroup") sign = int(sign) if not isinstance(base_ring, rings.Ring) and rings.is_CommutativeRing(base_ring): raise TypeError("base_ring must be a commutative ring") if character is None and arithgroup.is_Gamma0(group): character = dirichlet.TrivialCharacter(group.level(), base_ring) (self.__group, self.__weight, self.__character, self.__sign, self.__base_ring) = (group, weight, character, sign, base_ring) self._known_gens = [] self._known_gens_repr = [] self._is_zero = [] hecke.HeckeModule_generic.__init__(self, base_ring, group.level())
def _modular_symbols_space_gamma0(self): """ Return a space of modular symbols for Gamma0, with level a random choice from self.levels, weight from self.weights, and sign chosen randomly from [1, 0, -1]. EXAMPLES: sage: sage.modular.modsym.tests.Test()._modular_symbols_space_gamma0() # random level = 1, weight = 3, sign = 0 Modular Symbols space of dimension 0 for Gamma_0(1) of weight 3 with sign 0 over Rational Field """ level, weight, sign = self._level_weight_sign() M = modsym.ModularSymbols(arithgroup.Gamma0(level), weight, sign) self.current_space = M return M
def canonical_parameters(group, level, weight, base_ring): """ Given a group, level, weight, and base_ring as input by the user, return a canonicalized version of them, where level is a Sage integer, group really is a group, weight is a Sage integer, and base_ring a Sage ring. Note that we can't just get the level from the group, because we have the convention that the character for Gamma1(N) is None (which makes good sense). INPUT: - ``group`` - int, long, Sage integer, group, dirichlet character, or - ``level`` - int, long, Sage integer, or group - ``weight`` - coercible to Sage integer - ``base_ring`` - commutative Sage ring OUTPUT: - ``level`` - Sage integer - ``group`` - congruence subgroup - ``weight`` - Sage integer - ``ring`` - commutative Sage ring EXAMPLES:: sage: from sage.modular.modform.constructor import canonical_parameters sage: v = canonical_parameters(5, 5, int(7), ZZ); v (5, Congruence Subgroup Gamma0(5), 7, Integer Ring) sage: type(v[0]), type(v[1]), type(v[2]), type(v[3]) (<type 'sage.rings.integer.Integer'>, <class 'sage.modular.arithgroup.congroup_gamma0.Gamma0_class_with_category'>, <type 'sage.rings.integer.Integer'>, <type 'sage.rings.integer_ring.IntegerRing_class'>) sage: canonical_parameters( 5, 7, 7, ZZ ) Traceback (most recent call last): ... ValueError: group and level do not match. """ weight = rings.Integer(weight) if weight <= 0: raise NotImplementedError, "weight must be at least 1" if isinstance(group, dirichlet.DirichletCharacter): if ( group.level() != rings.Integer(level) ): raise ValueError, "group.level() and level do not match." group = group.minimize_base_ring() level = rings.Integer(level) elif arithgroup.is_CongruenceSubgroup(group): if ( rings.Integer(level) != group.level() ): raise ValueError, "group.level() and level do not match." # normalize the case of SL2Z if arithgroup.is_SL2Z(group) or \ arithgroup.is_Gamma1(group) and group.level() == rings.Integer(1): group = arithgroup.Gamma0(rings.Integer(1)) elif group is None: pass else: try: m = rings.Integer(group) except TypeError: raise TypeError, "group of unknown type." level = rings.Integer(level) if ( m != level ): raise ValueError, "group and level do not match." group = arithgroup.Gamma0(m) if not is_CommutativeRing(base_ring): raise TypeError, "base_ring (=%s) must be a commutative ring"%base_ring # it is *very* important to include the level as part of the data # that defines the key, since dirichlet characters of different # levels can compare equal, but define much different modular # forms spaces. return level, group, weight, base_ring
def _coerce_cusp(self, c): """ Coerce the cusp c into ``self``. EXAMPLES:: sage: B = ModularSymbols(DirichletGroup(13).0**3, 5, sign=0).boundary_space() sage: [ B(Cusp(i,13)) for i in range(13) ] [[0], [1/13], -zeta4*[1/13], [1/13], -[1/13], -zeta4*[1/13], -zeta4*[1/13], zeta4*[1/13], zeta4*[1/13], [1/13], -[1/13], zeta4*[1/13], -[1/13]] sage: B._is_equiv(Cusp(oo), Cusp(1,13)) (True, 1) sage: B._is_equiv(Cusp(0), Cusp(1,13)) (False, None) sage: B = ModularSymbols(DirichletGroup(13).0**3, 5, sign=1).boundary_space() sage: [ B(Cusp(i,13)) for i in range(13) ] [[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] sage: B._coerce_cusp(Cusp(oo)) 0 sage: B = ModularSymbols(DirichletGroup(13).0**3, 5, sign=-1).boundary_space() sage: [ B(Cusp(i,13)) for i in range(13) ] [0, [1/13], -zeta4*[1/13], [1/13], -[1/13], -zeta4*[1/13], -zeta4*[1/13], zeta4*[1/13], zeta4*[1/13], [1/13], -[1/13], zeta4*[1/13], -[1/13]] sage: B = ModularSymbols(DirichletGroup(13).0**4, 5, sign=1).boundary_space() sage: B._coerce_cusp(Cusp(0)) [0] sage: B = ModularSymbols(DirichletGroup(13).0**4, 5, sign=-1).boundary_space() sage: B._coerce_cusp(Cusp(0)) 0 """ sign = self.sign() i, eps = self._cusp_index(c) if i != -1: if i == -2: return self(0) else: return BoundarySpaceElement(self, {i : eps}) if sign != 0: i2, eps = self._cusp_index(-c) if i2 != -1: if i2 == -2: return self(0) else: return BoundarySpaceElement(self, {i2:sign*eps}) # found a new cusp class g = self._known_gens g.append(c) # Does cusp vanish because of stabiliser? s = arithgroup.Gamma0(self.level()).cusp_data(c)[0] if self.__eps(s[1,1]) != 1: self._zero_cusps.append(c) del self._known_gens[-1] return self(0) # Does class vanish because of sign relations? The relevant # relations are # # [(u,v)] = (-1)^k [(-u,-v)] # [(u,v)] = sign * [(-u,v)] # [(u,v)] = eps(d) * [(-u,v)] # # where, in the last line, eps is the character defining # our space, and [a,b;c,d] takes (u,v) to (-u,v). # # Thus (other than for 0 and Infinity), we have that [(u,v)] # can only be killed by sign relations when the sign is not # equal to eps(d). # if sign: if c.is_zero(): if sign == -1: self._zero_cusps.append(c) del self._known_gens[-1] return self(0) elif c.is_infinity(): if sign != (-1)**self.weight(): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) else: t, s = self._is_equiv(c, -c) if t: if sign != self.__eps(s): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) return BoundarySpaceElement(self, {(len(g)-1):1})