def get_new_and_oldspace_decomposition(k, N, xi=0): r""" Get decomposition of the new and oldspace S_k(N,xi) into submodules. """ M = ModularSymbols(N, k, sign=1).cuspidal_submodule() L = list() L = [M.new_submodule().dimension()] check_dim = M.new_submodule().dimension() for d in divisors(N): if(d == 1): continue O = M.old_submodule(d) Od = O.dimension() if(d == N and k == 2 or Od == 0): continue S = ModularSymbols(ZZ(N / d), k, sign=1).cuspidal_submodule().new_submodule() Sd = S.dimension() if(Sd == 0): logger.debug("%s, %s" % (O, Od)) logger.debug("%s, %s" % (S, Sd)) mult = len(divisors(ZZ(d))) check_dim = check_dim + mult * Sd L.append((ZZ(N / d), mult, Sd)) check_dim = check_dim - M.dimension() if(check_dim != 0): raise ArithmeticError("Something wrong! check_dim=%s" % check_dim) return str(M.dimension(), L)
def get_new_and_oldspace_decomposition(k, N, xi=0): r""" Get decomposition of the new and oldspace S_k(N,xi) into submodules. """ M = ModularSymbols(N, k, sign=1).cuspidal_submodule() L = list() L = [M.new_submodule().dimension()] check_dim = M.new_submodule().dimension() for d in divisors(N): if (d == 1): continue O = M.old_submodule(d) Od = O.dimension() if (d == N and k == 2 or Od == 0): continue S = ModularSymbols(ZZ(N / d), k, sign=1).cuspidal_submodule().new_submodule() Sd = S.dimension() if (Sd == 0): logger.debug("%s, %s" % (O, Od)) logger.debug("%s, %s" % (S, Sd)) mult = len(divisors(ZZ(d))) check_dim = check_dim + mult * Sd L.append((ZZ(N / d), mult, Sd)) check_dim = check_dim - M.dimension() if (check_dim != 0): raise ArithmeticError("Something wrong! check_dim=%s" % check_dim) return str(M.dimension(), L)
def sigma_rep(Delta, print_divisors=False): s = 0 for DD in divisors(Delta): if is_fundamental_discriminant(-DD): D = -DD for d in divisors(old_div(Delta, D)): s += kronecker(D, d) if print_divisors: print(D, d, kronecker(D, d)) return s
def neg_fdd_div(D): s = 0 for d in divisors(D): if is_fundamental_discriminant(-d): if Zmod(d)(old_div(D, d)).is_square(): s += 1 return s
def CMorbits(D): s = sum([ 2**(len(prime_divisors(old_div(D, d)))) for d in divisors(D) if is_fundamental_discriminant(-d) and Zmod(d) (old_div(D, d)).is_square() ]) + 1 return s
def gammas(self): def subdict(d, v): if d[v] > 1: d[v] -= 1 else: del d[v] a = defaultdict(int) b = defaultdict(int) for x in self.A: a[x] += 1 for x in self.B: b[x] += 1 gamma = [[], []] ab = [a, b] while a or b: m = max(list(a) + list(b)) wh = 0 if m in a else 1 gamma[wh].append(m) subdict(ab[wh], m) for d in divisors(m)[:-1]: if d in ab[wh]: subdict(ab[wh], d) else: ab[1 - wh][d] += 1 gamma[1] = [-1 * z for z in gamma[1]] gamma = gamma[1] + gamma[0] gamma.sort() return gamma
def number_of_hecke_to_check(f): r""" Compute the number of Hecke eigenvalues (at primes) we need to check to identify twists of our given form with characters of conductor dividing the level. """ ## initial bound bd = f.parent().sturm_bound() # we do not check primes dividing the level bd = bd + len(divisors(f.level())) return bd
def compare_formulas_2a(D, k): d1 = dimension_new_cusp_forms(kronecker_character(D), k) if D < 0: D = -D d2 = RR(1 / pi * sqrt(D) * sum([ log(d) * sigma(old_div(D, d), 0) for d in divisors(D) if Zmod(d) (old_div(D, d)).is_square() and is_fundamental_discriminant(-d) ])) return d1 - d2
def compare_formulas_2(D, k): d1 = old_div(RR(abs(D)), RR(6)) if D < 0: D = -D s1 = RR( sqrt(abs(D)) * sum([ log(d) for d in divisors(D) if is_fundamental_discriminant(-d) and kronecker(-d, old_div(D, d)) == 1 ])) d2 = RR((old_div(2, (sqrt(3) * pi))) * s1) return d1 - d2, d2, RR(2 * sqrt(D) * log(D) / pi)
def __JacobiDimension(k, m): if (k % 2) == 0: x = 0 if k == 2: x = (len(divisors(m)) - 1) // 2 for j in range(1, m + 1): x += (__S1k(k + 2 * j) - ((j * j) // (4 * m))) return x x = 0 for j in range(1, m): x += (__S1k(k + 2 * j - 1) - ((j * j) // (4 * m))) return x
def formtest_2(minD, maxD): s = 0 for D in range(minD, maxD): if is_fundamental_discriminant(-D): for d in divisors(D): if is_fundamental_discriminant(-d): sd = RR( RR(1) / RR(6) * (RR(d) + old_div(RR(D), RR(d))) - RR(sqrt(D)) / RR(pi) * log(d)) print(D, d, sd) s += sd if s <= 0: print("s= {0} D={1}".format(s, D))
def atkin_lehner(self, n): r""" Compute the Atkin-Lehner eigenvalue at the cusp of coset nr. n. """ if not self._atkin_lehner.has_key(n): A = self.coset_rep(n) c = Cusp(A[0, 0], A[1, 0]) G = Gamma0(self._level) for Q in divisors(self._level): cQ = Cusp(Q, self._level) if G.are_equivalent(c, cQ): self._atkin_lehner[n] = self._f.atkin_lehner_eigenvalue(Q) break return self._atkin_lehner[n]
def atkin_lehner(self,n): r""" Compute the Atkin-Lehner eigenvalue at the cusp of coset nr. n. """ if not self._atkin_lehner.has_key(n): A = self.coset_rep(n) c = Cusp(A[0,0],A[1,0]) G=Gamma0(self._level) for Q in divisors(self._level): cQ = Cusp(Q,self._level) if G.are_equivalent(c,cQ): self._atkin_lehner[n]=self._f.atkin_lehner_eigenvalue(Q) break return self._atkin_lehner[n]
def gen_generator(E): """generates a random generator for given curve E""" N = E.order() choices = [d for d in divisors(N) if d > MIN_GENERATOR_DIVISOR] if len(choices) == 0: raise ValueError('bad curve, only small divisors :(') n = random.choice(choices) h = N // n while True: P = E.random_point() G = P * h if G != E(0, 1, 0): return G
def _fourier_coefficient(self, content, det_4): def zeta(s): k = ZZ(1 - s) return -bernoulli(k) / k k = self.wt if det_4 < 0: return 0 elif det_4 == 0: return 2 / zeta(1 - k) * sum([d ** (k - 1) for d in divisors(content)]) else: return 2 * quadratic_L_function__exact(2 - k, -det_4) *\ self._fc__unramfactor(content, det_4)\ / (zeta(1 - k) * zeta(3 - 2 * k))
def get_atkin_lehner_eigenvalues(k, N=1, chi=0, fi=0): r""" Compute all Atkin-Lehner eigenvalues that we have. INPUT: - ''k'' -- positive integer : the weight - ''N'' -- positive integer (default 1) : level - ''fi'' -- non-neg. integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi] OUTPUT: - ''s'' -- string representing a dictonary of all existing Atkin-Lehner eigenvalues. EXAMPLES:: sage: get_atkin_lehner_eigenvalues(4,14,0) '{2: 1, 14: 1, 7: 1}' sage: get_atkin_lehner_eigenvalues(4,14,1) '{2: -1, 14: 1, 7: -1}' """ if(chi != 0): return "" res = dict() (t, f) = _get_newform(k, N, chi, fi) if(not t): return f N = f.level() for Q in divisors(N): if(Q == 1): continue if(gcd(Q, ZZ(N / Q)) == 1): try: res[Q] = f.atkin_lehner_eigenvalue(ZZ(Q)) except: pass tbl = dict() tbl['headersh'] = res.keys() tbl['data'] = [0] tbl['data'][0] = list() tbl['corner_label'] = "$Q$" tbl['headersv'] = ["$\epsilon_{Q}$"] for Q in res.keys(): tbl['data'][0].append(res[Q]) s = html_table(tbl) return s
def get_atkin_lehner_eigenvalues(k, N=1, chi=0, fi=0): r""" Compute all Atkin-Lehner eigenvalues that we have. INPUT: - ''k'' -- positive integer : the weight - ''N'' -- positive integer (default 1) : level - ''fi'' -- non-neg. integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi] OUTPUT: - ''s'' -- string representing a dictonary of all existing Atkin-Lehner eigenvalues. EXAMPLES:: sage: get_atkin_lehner_eigenvalues(4,14,0) '{2: 1, 14: 1, 7: 1}' sage: get_atkin_lehner_eigenvalues(4,14,1) '{2: -1, 14: 1, 7: -1}' """ if (chi != 0): return "" res = dict() (t, f) = _get_newform(k, N, chi, fi) if (not t): return f N = f.level() for Q in divisors(N): if (Q == 1): continue if (gcd(Q, ZZ(N / Q)) == 1): try: res[Q] = f.atkin_lehner_eigenvalue(ZZ(Q)) except: pass tbl = dict() tbl['headersh'] = res.keys() tbl['data'] = [0] tbl['data'][0] = list() tbl['corner_label'] = "$Q$" tbl['headersv'] = ["$\epsilon_{Q}$"] for Q in res.keys(): tbl['data'][0].append(res[Q]) s = html_table(tbl) return s
def factorize(n, a, s): """ Recovers the prime factors from a modulus if the order of a mod n is known. More information: M. Johnston A., "Shor’s Algorithm and Factoring: Don’t Throw Away the Odd Orders" :param n: the modulus :param a: the base :param s: the order of a :return: a tuple containing the prime factors, or None if the factors were not found """ assert pow(a, s, n) == 1, "s must be the order of a mod n" for r in divisors(s): b_r = pow(a, s // r, n) p = gcd(b_r - 1, n) if p != 1 and p != n and n % p == 0: return p, n // p
def twist_by(self, x): r""" twist self by a primitive Dirichlet character x """ # xx = x.primitive() assert x.is_primitive() q = x.conductor() # what level will the twist live on? level = self.level() qq = self.character().conductor() new_level = lcm(self.level(), lcm(q * q, q * qq)) D = DirichletGroup(new_level) new_x = D(self.character()) * D(x) * D(x) ix = D.list().index(new_x) # the correct space NS = WebModFormSpace(self._k, new_level, ix, self._prec) # have to find whih form wee want NS.galois_decomposition() M = NS.sturm_bound() + len(divisors(new_level)) C = self.coefficients(range(M)) for label in NS._galois_orbits_labels: wmf_logger.debug("label={0}".format(label)) FT = NS.f(label) CT = FT.f.coefficients(M) wmf_logger.debug("{0}".format(CT)) K = FT.f.hecke_eigenvalue_field() try: for n in range(2, M): if(new_level % n + 1 == 0): continue wmf_logger.debug("n={0}".format(n)) ct = CT[n] c = K(x(n)) * K(C[n]) wmf_logger.debug("{0} {1}".format(ct, c)) if ct != c: raise StopIteration() except StopIteration: pass else: wmf_logger.debug("Twist of f={0}".format(FT)) return FT
def find_r(x, y): d = divisors(x) for r1 in d: if (valid(r1) == False): continue r2 = x // r1 if (valid(r2) == False): continue print('[*] Checking divisors:') print('\t|p1: {0}\n\t|p2: {1}'.format(r1, r2)) g1 = Generator(r1) g2 = Generator(r2) o = g1.getNum() * g2.getNum() if (o == y): return (r1, r2) raise Exception('divisors not found')
def ab2gammas(A, B): ab = [{}, {}] for x in A: incdict(ab[0], x) for x in B: incdict(ab[1], x) gamma = [[], []] while ab[0] or ab[1]: m = max(list(ab[0]) + list(ab[1])) wh = 0 if m in ab[0] else 1 gamma[wh].append(m) subdict(ab[wh], m) for d in divisors(m)[:-1]: if d in ab[wh]: subdict(ab[wh], d) else: incdict(ab[1 - wh], d) gamma[1] = [-1 * z for z in gamma[1]] gamma = gamma[1] + gamma[0] gamma.sort() return gamma
def possible_orders(self): """ Return the possible orders of this torsion subgroup, computed from a known divisor and multiple of the order. EXAMPLES:: sage: from sage_modabvar import J0 sage: J0(11).rational_torsion_subgroup().possible_orders() [5] sage: J0(33).rational_torsion_subgroup().possible_orders() [100, 200] sage: from sage_modabvar import J1 sage: J1(13).rational_torsion_subgroup().possible_orders() [19] sage: J1(16).rational_torsion_subgroup().possible_orders() [1, 2, 4, 5, 10, 20] """ try: return self._possible_orders except AttributeError: pass # return the order of the cuspidal subgroup in the J0(p) case A = self.abelian_variety() if A.is_J0() and A.level().is_prime(): self._order = QQ((A.level()-1)/12).numerator() return [self._order] if A.dimension() == 1: return [A.elliptic_curve().torsion_order()] u = self.multiple_of_order() l = self.divisor_of_order() assert u % l == 0 O = [l * d for d in divisors(u//l)] self._possible_orders = O return O
def compare_formulas_1(D, k): DG = DirichletGroup(abs(D)) chi = DG(kronecker_character(D)) d1 = dimension_new_cusp_forms(chi, k) #if D>0: # lvals=sage.lfunctions.all.lcalc.twist_values(1,2,D) #else: # lvals=sage.lfunctions.all.lcalc.twist_values(1,D,0) #s1=RR(sum([sqrt(abs(lv[0]))*lv[1]*2**len(prime_factors(D/lv[0])) for lv in lvals if lv[0].divides(D) and Zmod(lv[0])(abs(D/lv[0])).is_square()])) #d2=RR(1/pi*s1) d2 = 0 for d in divisors(D): if is_fundamental_discriminant(-d): K = QuadraticField(-d) DD = old_div(ZZ(D), ZZ(d)) ep = euler_phi((chi * DG(kronecker_character(-d))).conductor()) #ep=euler_phi(squarefree_part(abs(D*d))) print("ep=", ep, D, d) ids = [a for a in K.ideals_of_bdd_norm(-DD)[-DD]] eulers1 = [] for a in ids: e = a.euler_phi() if e != 1 and ep == 1: if K(-1).mod(a) != K(1).mod(a): e = old_div(e, (2 * ep)) else: e = old_div(e, ep) eulers1.append(e) print(eulers1, ep) s = sum(eulers1) if ep == 1 and not (d.divides(DD) or abs(DD) == 1): continue print(d, s) if len(eulers1) > 0: d2 += s * K.class_number() return d1 - d2
def possible_orders(self, proof=True): """ Return the possible orders of this torsion subgroup. Outside of special cases, this is done by computing a divisor and multiple of the order. INPUT: - ``proof`` -- a boolean (default: True) OUTPUT: - an array of positive integers The computation of the rational torsion order of J1(p) is conjectural and will only be used if proof=False. See Section 6.2.3 of [CES2003]_. EXAMPLES:: sage: J0(11).rational_torsion_subgroup().possible_orders() [5] sage: J0(33).rational_torsion_subgroup().possible_orders() [100, 200] sage: J1(13).rational_torsion_subgroup().possible_orders() [19] sage: J1(16).rational_torsion_subgroup().possible_orders() [1, 2, 4, 5, 10, 20] """ try: if proof: return self._possible_orders else: return self._possible_orders_proof_false except AttributeError: pass A = self.abelian_variety() N = A.level() # return the order of the cuspidal subgroup in the J0(p) case if A.is_J0() and N.is_prime(): self._possible_orders = [QQ((A.level()-1)/12).numerator()] self._possible_orders_proof_false = self._possible_orders return self._possible_orders # the elliptic curve case if A.dimension() == 1: self._possible_orders = [A.elliptic_curve().torsion_order()] self._possible_orders_proof_false = self._possible_orders return self._possible_orders # the conjectural J1(p) case if not proof and A.is_J1() and N.is_prime(): epsilons = [epsilon for epsilon in DirichletGroup(N) if not epsilon.is_trivial() and epsilon.is_even()] bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons] self._possible_orders_proof_false = [ZZ(N/(2**(N-3))*prod(bernoullis))] return self._possible_orders_proof_false u = self.multiple_of_order() l = self.divisor_of_order() assert u % l == 0 O = [l * d for d in divisors(u//l)] self._possible_orders = O if u == l: self._possible_orders_proof_false = O return O
def set_twist_info(self, prec=10,insert_in_db=True): r""" Try to find forms of lower level which get twisted into self. OUTPUT: -''[t,l]'' -- tuple of a Bool t and a list l. The list l contains all tuples of forms which twists to the given form. The actual minimal one is the first element of this list. t is set to True if self is minimal and False otherwise EXAMPLES:: """ if(len(self._twist_info) > 0): return self._twist_info N = self.level() k = self.weight() if(is_squarefree(ZZ(N))): self._twist_info = [True, None ] return [True, None] # We need to check all square factors of N twist_candidates = list() KF = self.base_ring() # check how many Hecke eigenvalues we need to check max_nump = self._number_of_hecke_eigenvalues_to_check() maxp = max(primes_first_n(max_nump)) for d in divisors(N): if(d == 1): continue # we look at all d such that d^2 divdes N if(not ZZ(d ** 2).divides(ZZ(N))): continue D = DirichletGroup(d) # check possible candidates to twist into f # g in S_k(M,chi) wit M=N/d^2 M = ZZ(N / d ** 2) if(self._verbose > 0): wmf_logger.debug("Checking level {0}".format(M)) for xig in range(euler_phi(M)): (t, glist) = _get_newform(M,k, xig) if(not t): return glist for g in glist: if(self._verbose > 1): wmf_logger.debug("Comparing to function {0}".format(g)) KG = g.base_ring() # we now see if twisting of g by xi in D gives us f for xi in D: try: for p in primes_first_n(max_nump): if(ZZ(p).divides(ZZ(N))): continue bf = self.as_factor().q_eigenform(maxp + 1, names='x')[p] bg = g.q_expansion(maxp + 1)[p] if(bf == 0 and bg == 0): continue elif(bf == 0 and bg != 0 or bg == 0 and bf != 0): raise StopIteration() if(ZZ(p).divides(xi.conductor())): raise ArithmeticError("") xip = xi(p) # make a preliminary check that the base rings match with respect to being # real or not try: QQ(xip) XF = QQ if(KF != QQ or KG != QQ): raise StopIteration except TypeError: # we have a non-rational (i.e. complex) value of the character XF = xip.parent() if((KF.absolute_degree() == 1 or KF.is_totally_real()) and (KG.absolute_degre() == 1 or KG.is_totally_real())): raise StopIteration ## it is diffcult to compare elements from diferent rings in general but we make some checcks # is it possible to see if there is a larger ring which everything can be # coerced into? ok = False try: a = KF(bg / xip) b = KF(bf) ok = True if(a != b): raise StopIteration() except TypeError: pass try: a = KG(bg) b = KG(xip * bf) ok = True if(a != b): raise StopIteration() except TypeError: pass if(not ok): # we could coerce and the coefficients were equal return "Could not compare against possible candidates!" # otherwise if we are here we are ok and found a candidate twist_candidates.append([M, g.q_expansion(prec), xi]) except StopIteration: # they are not equal pass wmf_logger.debug("Candidates=v{0}".format(twist_candidates)) self._twist_info = (False, twist_candidates) if(len(twist_candidates) == 0): self._twist_info = [True, None] else: self._twist_info = [False, twist_candidates] return self._twist_info
def divisors_in_interval(n, a, b): """ given a nonzero integer n and an interval [a,b] returns a list of the divisors of n in [a,b] """ return [d for d in divisors(n) if a <= d and d <= b]
def proper_divisors(N): return [I for I in divisors(N) if I!=1 and I!=N]
def satisfies_maass_relation_for(self, n, r, m): if (n, r, m) == (0, 0, 0): return True return self[(n, r, m)] == sum([d ** (self.wt - 1) * self[(1, r / d, m * n / (d ** 2))] for d in divisors(gcd((n, r, m)))])
def find_inverse_images_of_twists(k, N=1, chi=0, fi=0, prec=10, verbose=0): r""" Checks if f is minimal and if not, returns the associated minimal form to precision prec. INPUT: - ''k'' -- positive integer : the weight - ''N'' -- positive integer (default 1) : level - ''chi'' -- non-neg. integer (default 0) use character nr. chi - ''fi'' -- non-neg. integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi] - ''prec'' -- integer (the number of coefficients to get) - ''verbose'' -- integer OUTPUT: -''[t,l]'' -- tuple of a Bool t and a list l. The list l contains all tuples of forms which twists to the given form. The actual minimal one is the first element of this list. EXAMPLES:: """ (t, f) = _get_newform(k, N, chi, fi) if(not t): return f if(is_squarefree(ZZ(N))): return [True, f] # We need to check all square factors of N logger.debug("investigating: %s" % f) N_sqfree = squarefree_part(ZZ(N)) Nsq = ZZ(N / N_sqfree) twist_candidates = list() KF = f.base_ring() # check how many Hecke eigenvalues we need to check max_nump = number_of_hecke_to_check(f) maxp = max(primes_first_n(max_nump)) for d in divisors(N): # we look at all d such that d^2 divdes N if(not ZZ(d ** 2).divides(ZZ(N))): continue D = DirichletGroup(d) # check possible candidates to twist into f # g in S_k(M,chi) wit M=N/d^2 M = ZZ(N / d ** 2) logger.debug("Checking level %s" % M) for xig in range(euler_phi(M)): (t, glist) = _get_newform(k, M, xig) if(not t): return glist for g in glist: logger.debug("Comparing to function %s" % g) KG = g.base_ring() # we now see if twisting of g by xi in D gives us f for xi in D: try: for p in primes_first_n(max_nump): if(ZZ(p).divides(ZZ(N))): continue bf = f.q_expansion(maxp + 1)[p] bg = g.q_expansion(maxp + 1)[p] if(bf == 0 and bg == 0): continue elif(bf == 0 and bg != 0 or bg == 0 and bf != 0): raise StopIteration() if(ZZ(p).divides(xi.conductor())): raise ArithmeticError("") xip = xi(p) # make a preliminary check that the base rings match with respect to being # real or not try: QQ(xip) XF = QQ if(KF != QQ or KG != QQ): raise StopIteration except TypeError: # we have a non-rational (i.e. complex) value of the character XF = xip.parent() if((KF == QQ or KF.is_totally_real()) and (KG == QQ or KG.is_totally_real())): raise StopIteration ## it is diffcult to compare elements from diferent rings in general but we make some checcks # is it possible to see if there is a larger ring which everything can be # coerced into? ok = False try: a = KF(bg / xip) b = KF(bf) ok = True if(a != b): raise StopIteration() except TypeError: pass try: a = KG(bg) b = KG(xip * bf) ok = True if(a != b): raise StopIteration() except TypeError: pass if(not ok): # we could coerce and the coefficients were equal return "Could not compare against possible candidates!" # otherwise if we are here we are ok and found a candidate twist_candidates.append([dd, g.q_expansion(prec), xi]) except StopIteration: # they are not equal pass # logger.debug("Candidates=%s" % twist_candidates) if(len(twist_candidates) == 0): return (True, None) else: return (False, twist_candidates)
def find_inverse_images_of_twists(k, N=1, chi=0, fi=0, prec=10, verbose=0): r""" Checks if f is minimal and if not, returns the associated minimal form to precision prec. INPUT: - ''k'' -- positive integer : the weight - ''N'' -- positive integer (default 1) : level - ''chi'' -- non-neg. integer (default 0) use character nr. chi - ''fi'' -- non-neg. integer (default 0) We want to use the element nr. fi f=Newforms(N,k)[fi] - ''prec'' -- integer (the number of coefficients to get) - ''verbose'' -- integer OUTPUT: -''[t,l]'' -- tuple of a Bool t and a list l. The list l contains all tuples of forms which twists to the given form. The actual minimal one is the first element of this list. EXAMPLES:: """ (t, f) = _get_newform(k, N, chi, fi) if (not t): return f if (is_squarefree(ZZ(N))): return [True, f] # We need to check all square factors of N logger.debug("investigating: %s" % f) N_sqfree = squarefree_part(ZZ(N)) Nsq = ZZ(N / N_sqfree) twist_candidates = list() KF = f.base_ring() # check how many Hecke eigenvalues we need to check max_nump = number_of_hecke_to_check(f) maxp = max(primes_first_n(max_nump)) for d in divisors(N): # we look at all d such that d^2 divdes N if (not ZZ(d**2).divides(ZZ(N))): continue D = DirichletGroup(d) # check possible candidates to twist into f # g in S_k(M,chi) wit M=N/d^2 M = ZZ(N / d**2) logger.debug("Checking level %s" % M) for xig in range(euler_phi(M)): (t, glist) = _get_newform(k, M, xig) if (not t): return glist for g in glist: logger.debug("Comparing to function %s" % g) KG = g.base_ring() # we now see if twisting of g by xi in D gives us f for xi in D: try: for p in primes_first_n(max_nump): if (ZZ(p).divides(ZZ(N))): continue bf = f.q_expansion(maxp + 1)[p] bg = g.q_expansion(maxp + 1)[p] if (bf == 0 and bg == 0): continue elif (bf == 0 and bg != 0 or bg == 0 and bf != 0): raise StopIteration() if (ZZ(p).divides(xi.conductor())): raise ArithmeticError("") xip = xi(p) # make a preliminary check that the base rings match with respect to being # real or not try: QQ(xip) XF = QQ if (KF != QQ or KG != QQ): raise StopIteration except TypeError: # we have a non-rational (i.e. complex) value of the character XF = xip.parent() if ((KF == QQ or KF.is_totally_real()) and (KG == QQ or KG.is_totally_real())): raise StopIteration ## it is diffcult to compare elements from diferent rings in general but we make some checcks # is it possible to see if there is a larger ring which everything can be # coerced into? ok = False try: a = KF(bg / xip) b = KF(bf) ok = True if (a != b): raise StopIteration() except TypeError: pass try: a = KG(bg) b = KG(xip * bf) ok = True if (a != b): raise StopIteration() except TypeError: pass if ( not ok ): # we could coerce and the coefficients were equal return "Could not compare against possible candidates!" # otherwise if we are here we are ok and found a candidate twist_candidates.append([dd, g.q_expansion(prec), xi]) except StopIteration: # they are not equal pass # logger.debug("Candidates=%s" % twist_candidates) if (len(twist_candidates) == 0): return (True, None) else: return (False, twist_candidates)
def sigma_log(D): return sum([RR(log(d)) for d in divisors(D)])
def set_oldspace_decomposition(self): r""" Get decomposition of the oldspace in self into submodules. """ if not (self._oldspace_decomposition is None or self._oldspace_decomposition == []): return N = self._N k = self._k M = self._modular_symbols.cuspidal_submodule() L = list() L = [] check_dim = self.dimension_newspace() if(check_dim == self.dimension()): return L if(self._verbose > 1): wmf_logger.debug("check_dim:={0}".format(check_dim)) for d in divisors(N): if(d == 1): continue q = N.divide_knowing_divisible_by(d) if(self._verbose > 1): wmf_logger.debug("d={0}".format(d)) # since there is a bug in the current version of sage # we have to try this... try: O = M.old_submodule(d) except AttributeError: O = M.zero_submodule() Od = O.dimension() if(self._verbose > 1): wmf_logger.debug("O={0}".format(O)) wmf_logger.debug("Od={0}".format(Od)) if(d == N and k == 2 or Od == 0): continue if self.character().is_trivial(): # S=ModularSymbols(ZZ(N/d),k,sign=1).cuspidal_submodule().new_submodule(); Sd=S.dimension() wmf_logger.debug("q={0},{1}".format(q, type(q))) wmf_logger.debug("k={0},{1}".format(k, type(k))) Sd = dimension_new_cusp_forms(q, k) if(self._verbose > 1): wmf_logger.debug("Sd={0}".format(Sd)) if Sd > 0: mult = len(divisors(ZZ(d))) check_dim = check_dim + mult * Sd L.append((q, 0, mult, Sd)) else: xd = self.character().decomposition() for xx in xd: if xx.modulus() == q: Sd = dimension_new_cusp_forms(xx, k) if Sd > 0: # identify this character for internal storage... should be optimized x_k = self.conrey_character(xx).number() mult = len(divisors(ZZ(d))) check_dim = check_dim + mult * Sd L.append((q, x_k, mult, Sd)) if(self._verbose > 1): wmf_logger.debug("mult={0},N/d={1},Sd={2}".format(mult, ZZ(N / d), Sd)) wmf_logger.debug("check_dim={0}".format(check_dim)) check_dim = check_dim - M.dimension() if(check_dim != 0): raise ArithmeticError("Something wrong! check_dim=%s" % check_dim) self._oldspace_decomposition = L