def is_subgroup(self, right): """ Return True if self is a subgroup of right. EXAMPLES:: sage: Gamma1(3).is_subgroup(SL2Z) True sage: Gamma1(3).is_subgroup(Gamma1(5)) False sage: Gamma1(3).is_subgroup(Gamma1(6)) False sage: Gamma1(6).is_subgroup(Gamma1(3)) True sage: Gamma1(6).is_subgroup(Gamma0(2)) True sage: Gamma1(80).is_subgroup(GammaH(40, [])) True sage: Gamma1(80).is_subgroup(GammaH(40, [21])) True """ if right.level() == 1: return True if is_GammaH(right): return self.level() % right.level() == 0 else: raise NotImplementedError
def _new_group_from_level(self, level): r""" Return a new group of the same type (Gamma0, Gamma1, or GammaH) as self of the given level. In the case that self is of type GammaH, we take the largest H inside `(\ZZ/ \text{level}\ZZ)^\times` which maps to H, namely its inverse image under the natural reduction map. EXAMPLES:: sage: G = Gamma0(20) sage: G._new_group_from_level(4) Congruence Subgroup Gamma0(4) sage: G._new_group_from_level(40) Congruence Subgroup Gamma0(40) sage: G = Gamma1(10) sage: G._new_group_from_level(6) Traceback (most recent call last): ... ValueError: one level must divide the other sage: G = GammaH(50,[7]); G Congruence Subgroup Gamma_H(50) with H generated by [7] sage: G._new_group_from_level(25) Congruence Subgroup Gamma_H(25) with H generated by [7] sage: G._new_group_from_level(10) Congruence Subgroup Gamma0(10) sage: G._new_group_from_level(100) Congruence Subgroup Gamma_H(100) with H generated by [7, 57] """ from congroup_gamma0 import is_Gamma0 from congroup_gamma1 import is_Gamma1 from congroup_gammaH import is_GammaH from all import Gamma0, Gamma1, GammaH N = self.level() if (level % N) and (N % level): raise ValueError, "one level must divide the other" if is_Gamma0(self): return Gamma0(level) elif is_Gamma1(self): return Gamma1(level) elif is_GammaH(self): H = self._generators_for_H() if level > N: d = level // N diffs = [N * i for i in range(d)] newH = [h + diff for h in H for diff in diffs] return GammaH(level, [x for x in newH if gcd(level, x) == 1]) else: return GammaH(level, [h % level for h in H]) else: raise NotImplementedError
def __cmp__(self, other): """ Compare self to other. The ordering on congruence subgroups of the form `\Gamma_H(N)` for some H is first by level and then by the subgroup H. In particular, this means that we have `\Gamma_1(N) < \Gamma_H(N) < \Gamma_0(N)` for every nontrivial subgroup H. EXAMPLES:: sage: G = Gamma1(86) sage: G.__cmp__(G) 0 sage: G.__cmp__(GammaH(86, [11])) is not 0 True sage: Gamma1(12) < Gamma0(12) True sage: Gamma1(10) < Gamma1(12) True sage: Gamma1(11) == GammaH(11, []) True sage: Gamma1(1) == SL2Z True sage: Gamma1(2) == Gamma0(2) True """ from all import is_GammaH if not is_CongruenceSubgroup(other): return cmp(type(self), type(other)) c = cmp(self.level(), other.level()) if c: return c # Since Gamma1(N) is GammaH(N) for H all of (Z/N)^\times, # we know how to compare it to any other GammaH without having # to look at self._list_of_elements_in_H(). if is_GammaH(other): if is_Gamma1(other): return 0 else: H = other._generators_for_H() return cmp(0,len(H)) return cmp(type(self), type(other))
def __cmp__(self, other): """ Compare self to other. The ordering on congruence subgroups of the form `\Gamma_H(N)` for some H is first by level and then by the subgroup H. In particular, this means that we have `\Gamma_1(N) < \Gamma_H(N) < \Gamma_0(N)` for every nontrivial subgroup H. EXAMPLES:: sage: G = Gamma1(86) sage: G.__cmp__(G) 0 sage: G.__cmp__(GammaH(86, [11])) is not 0 True sage: Gamma1(12) < Gamma0(12) True sage: Gamma1(10) < Gamma1(12) True sage: Gamma1(11) == GammaH(11, []) True sage: Gamma1(1) == SL2Z True sage: Gamma1(2) == Gamma0(2) True """ from all import is_GammaH if not is_CongruenceSubgroup(other): return cmp(type(self), type(other)) c = cmp(self.level(), other.level()) if c: return c # Since Gamma1(N) is GammaH(N) for H all of (Z/N)^\times, # we know how to compare it to any other GammaH without having # to look at self._list_of_elements_in_H(). if is_GammaH(other): if is_Gamma1(other): return 0 else: H = other._generators_for_H() return cmp(0, len(H)) return cmp(type(self), type(other))