def nu3(self): r""" Return the number of elliptic points of order 3 for this congruence subgroup `\Gamma_0(N)`. The number of these is given by a standard formula: 0 if `N` is divisible by 9 or any prime congruent to -1 mod 3, and otherwise `2^d` where d is the number of primes other than 3 dividing `N`. EXAMPLE:: sage: Gamma0(2).nu3() 0 sage: Gamma0(3).nu3() 1 sage: Gamma0(9).nu3() 0 sage: Gamma0(7).nu3() 2 sage: Gamma0(21).nu3() 2 sage: Gamma0(1729).nu3() 8 """ n = self.level() if (n % 9 == 0): return ZZ(0) return prod([1 + kronecker_symbol(-3, p) for p, _ in n.factor()])
def nu3(self): r""" Return the number of elliptic points of order 3 for this congruence subgroup `\Gamma_0(N)`. The number of these is given by a standard formula: 0 if `N` is divisible by 9 or any prime congruent to -1 mod 3, and otherwise `2^d` where d is the number of primes other than 3 dividing `N`. EXAMPLE:: sage: Gamma0(2).nu3() 0 sage: Gamma0(3).nu3() 1 sage: Gamma0(9).nu3() 0 sage: Gamma0(7).nu3() 2 sage: Gamma0(21).nu3() 2 sage: Gamma0(1729).nu3() 8 """ n = self.level() if (n % 9 == 0): return ZZ(0) return prod([ 1 + kronecker_symbol(-3, p) for p, _ in n.factor()])
def residue_ring(N): fac = N.factor() if len(fac) != 1: raise NotImplementedError, "P must be a prime power" from sage.rings.all import kronecker_symbol P, e = fac[0] p = P.smallest_integer() s = kronecker_symbol(p, 5) if e == 1: return P.residue_field() if s == 1: return ResidueRing_split(N, P, p, e) elif s == -1: return ResidueRing_inert(N, P, p, e) else: if e % 2 == 0: # easy case return ResidueRing_ramified_even(N, P, p, e) else: # hardest case return ResidueRing_ramified_odd(N, P, p, e)
def nu2(self): r""" Return the number of elliptic points of order 2 for this congruence subgroup `\Gamma_0(N)`. The number of these is given by a standard formula: 0 if `N` is divisible by 4 or any prime congruent to -1 mod 4, and otherwise `2^d` where d is the number of odd primes dividing `N`. EXAMPLE:: sage: Gamma0(2).nu2() 1 sage: Gamma0(4).nu2() 0 sage: Gamma0(21).nu2() 0 sage: Gamma0(1105).nu2() 8 sage: [Gamma0(n).nu2() for n in [1..19]] [1, 1, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0] """ n = self.level() if n%4 == 0: return ZZ(0) return prod([ 1 + kronecker_symbol(-4, p) for p, _ in n.factor()])
def nu2(self): r""" Return the number of elliptic points of order 2 for this congruence subgroup `\Gamma_0(N)`. The number of these is given by a standard formula: 0 if `N` is divisible by 4 or any prime congruent to -1 mod 4, and otherwise `2^d` where d is the number of odd primes dividing `N`. EXAMPLE:: sage: Gamma0(2).nu2() 1 sage: Gamma0(4).nu2() 0 sage: Gamma0(21).nu2() 0 sage: Gamma0(1105).nu2() 8 sage: [Gamma0(n).nu2() for n in [1..19]] [1, 1, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0] """ n = self.level() if n % 4 == 0: return ZZ(0) return prod([1 + kronecker_symbol(-4, p) for p, _ in n.factor()])
def dimension__jacobi_scalar_f(k, m, f) : if moebius(f) != (-1)**k : return 0 ## We use chapter 6 of Skoruppa's thesis ts = filter(lambda t: gcd(t, m // t) == 1, m.divisors()) ## Eisenstein part eis_dimension = 0 for t in ts : eis_dimension += moebius(gcd(m // t, f)) \ * (t // t.squarefree_part()).isqrt() \ * (2 if (m // t) % 4 == 0 else 1) eis_dimension = eis_dimension // len(ts) if k == 2 and f == 1 : eis_dimension -= len( (m // m.squarefree_part()).isqrt().divisors() ) ## Cuspidal part cusp_dimension = 0 tmp = ZZ(0) for t in ts : tmp += moebius(gcd(m // t, f)) * t tmp = tmp / len(ts) cusp_dimension += tmp * (2 * k - 3) / ZZ(12) print "1: ", cusp_dimension if m % 2 == 0 : tmp = ZZ(0) for t in ts : tmp += moebius(gcd(m // t, f)) * kronecker_symbol(-4, t) tmp = tmp / len(ts) cusp_dimension += 1/ZZ(2) * kronecker_symbol(8, 2 * k - 1) * tmp print "2: ", 1/ZZ(2) * kronecker_symbol(8, 2 * k - 1) * tmp tmp = ZZ(0) for t in ts : tmp += moebius(gcd(m // t, f)) * kronecker_symbol(t, 3) tmp = tmp / len(ts) if m % 3 != 0 : cusp_dimension += 1 / ZZ(3) * kronecker_symbol(k, 3) * tmp print ": ", 1 / ZZ(3) * kronecker_symbol(k, 3) * tmp elif k % 3 == 0 : cusp_dimension += 2 / ZZ(3) * (-1)**k * tmp print "3: ", 2 / ZZ(3) * (-1)**k * tmp else : cusp_dimension += 1 / ZZ(3) * (kronecker_symbol(k, 3) + (-1)**(k - 1)) * tmp print "3: ", 1 / ZZ(3) * (kronecker_symbol(k, 3) + (-1)**(k - 1)) * tmp tmp = ZZ(0) for t in ts : tmp += moebius(gcd(m // t, f)) \ * (t // t.squarefree_part()).isqrt() \ * (2 if (m // t) % 4 == 0 else 1) tmp = tmp / len(ts) cusp_dimension -= 1 / ZZ(2) * tmp print "4: ", -1 / ZZ(2) * tmp tmp = ZZ(0) for t in ts : tmp += moebius(gcd(m // t, f)) \ * sum( (( len(BinaryQF_reduced_representatives(-d, True)) if d not in [3, 4] else ( 1 / ZZ(3) if d == 3 else 1 / ZZ(2) )) if d % 4 == 0 or d % 4 == 3 else 0 ) * kronecker_symbol(-d, m // t) * ( 1 if (m // t) % 2 != 0 else ( 4 if (m // t) % 4 == 0 else 2 * kronecker_symbol(-d, 2) )) for d in (4 * m).divisors() ) tmp = tmp / len(ts) cusp_dimension -= 1 / ZZ(2) * tmp print "5: ", -1 / ZZ(2) * tmp if k == 2 : cusp_dimension += len( (m // f // (m // f).squarefree_part()).isqrt().divisors() ) return eis_dimension + cusp_dimension
def dimension__jacobi_scalar_f(k, m, f): if moebius(f) != (-1)**k: return 0 ## We use chapter 6 of Skoruppa's thesis ts = filter(lambda t: gcd(t, m // t) == 1, m.divisors()) ## Eisenstein part eis_dimension = 0 for t in ts: eis_dimension += moebius(gcd(m // t, f)) \ * (t // t.squarefree_part()).isqrt() \ * (2 if (m // t) % 4 == 0 else 1) eis_dimension = eis_dimension // len(ts) if k == 2 and f == 1: eis_dimension -= len((m // m.squarefree_part()).isqrt().divisors()) ## Cuspidal part cusp_dimension = 0 tmp = ZZ(0) for t in ts: tmp += moebius(gcd(m // t, f)) * t tmp = tmp / len(ts) cusp_dimension += tmp * (2 * k - 3) / ZZ(12) print "1: ", cusp_dimension if m % 2 == 0: tmp = ZZ(0) for t in ts: tmp += moebius(gcd(m // t, f)) * kronecker_symbol(-4, t) tmp = tmp / len(ts) cusp_dimension += 1 / ZZ(2) * kronecker_symbol(8, 2 * k - 1) * tmp print "2: ", 1 / ZZ(2) * kronecker_symbol(8, 2 * k - 1) * tmp tmp = ZZ(0) for t in ts: tmp += moebius(gcd(m // t, f)) * kronecker_symbol(t, 3) tmp = tmp / len(ts) if m % 3 != 0: cusp_dimension += 1 / ZZ(3) * kronecker_symbol(k, 3) * tmp print ": ", 1 / ZZ(3) * kronecker_symbol(k, 3) * tmp elif k % 3 == 0: cusp_dimension += 2 / ZZ(3) * (-1)**k * tmp print "3: ", 2 / ZZ(3) * (-1)**k * tmp else: cusp_dimension += 1 / ZZ(3) * (kronecker_symbol(k, 3) + (-1)**(k - 1)) * tmp print "3: ", 1 / ZZ(3) * (kronecker_symbol(k, 3) + (-1)**(k - 1)) * tmp tmp = ZZ(0) for t in ts: tmp += moebius(gcd(m // t, f)) \ * (t // t.squarefree_part()).isqrt() \ * (2 if (m // t) % 4 == 0 else 1) tmp = tmp / len(ts) cusp_dimension -= 1 / ZZ(2) * tmp print "4: ", -1 / ZZ(2) * tmp tmp = ZZ(0) for t in ts: tmp += moebius(gcd(m // t, f)) \ * sum( (( len(BinaryQF_reduced_representatives(-d, True)) if d not in [3, 4] else ( 1 / ZZ(3) if d == 3 else 1 / ZZ(2) )) if d % 4 == 0 or d % 4 == 3 else 0 ) * kronecker_symbol(-d, m // t) * ( 1 if (m // t) % 2 != 0 else ( 4 if (m // t) % 4 == 0 else 2 * kronecker_symbol(-d, 2) )) for d in (4 * m).divisors() ) tmp = tmp / len(ts) cusp_dimension -= 1 / ZZ(2) * tmp print "5: ", -1 / ZZ(2) * tmp if k == 2: cusp_dimension += len( (m // f // (m // f).squarefree_part()).isqrt().divisors()) return eis_dimension + cusp_dimension