def is_torsion_same(p, K, chi, B=30, uniform=False): """Returns true if the minus part of J0(p) does not gain new torsion when base changing to K""" M = ModularSymbols(p) S = M.cuspidal_subspace() T = S.atkin_lehner_operator() S_min = (T + parent(T)(1)).kernel() J0_min = S_min.abelian_variety() d = K.degree() if uniform: frob_poly_data = [(q, d) for q in prime_range(d + 2, B) if q != p] else: frob_poly_data = [(q, 1) if chi(q) == 1 else (q, d) for q in prime_range(d + 2, B) if gcd(q, p) == 1] point_counts = [] for q, i in frob_poly_data: frob_pol_q = J0_min.frobenius_polynomial(q) frob_mat = companion_matrix(frob_pol_q) point_counts.append((frob_mat**i).charpoly()(1)) # Recall that the rational torsion on J0(p) is entirely contained in # the minus part (theorem of Mazur), so checking no-growth of torsion # in minus part is done simply as follows return J0(p).rational_torsion_order(proof=False) == gcd(point_counts)
def find_known(self): """ Return iterator of 5-tuples of Python ints, defined as follows: (N, k, i, newforms, maxp) (37, 2, 0, 2, 10000) Here N = level, k = weight, i = character, newforms = number of newforms, maxp = integer such that a_p is known for p<=maxp. If no newforms are known but there are newforms (they just haven't been computed), then newforms is set to -1. """ for Nki in os.listdir(self._data): z = Nki.split('-') if len(z) == 3: N, k, i = parse_Nki(z) newforms = [x for x in os.listdir(os.path.join(self._data, Nki)) if x.isdigit()] if len(newforms) == 0: # maybe nothing computed? if i == 0: # program around a bug in dimension_new_cusp_forms: Trac 12640 d = dimension_new_cusp_forms(N) else: chi = character(N, i) d = dimension_new_cusp_forms(chi, k) if d == 0: # definitely no newforms yield (N,k,i,0,0) else: # we just don't know the newforms yet yield (N,k,i,-1,0) else: maxp = None for n in newforms: v = set([]) this_maxp = 0 for X in os.listdir(os.path.join(self._data, Nki, n)): if X.startswith('aplist') and 'meta' not in X: args = [int(a) for a in X.rstrip('.sobj').split('-')[1:]] v.update(prime_range(*args)) this_maxp = max(this_maxp, max(args)) if len(v) != len(prime_range(this_maxp)): # something missing! print "data ranges are missing in the aplist data for %s"%Nki maxp = 100 else: maxp = this_maxp if maxp is None else min(this_maxp, maxp) yield (N,k,i,len(newforms),maxp)
def frobs(nf): frob_at_p = residue_field_degrees_function(nf.gpK()) D = nf.disc() ans = [] seeram = False for p in prime_range(2, 60): if not ZZ(p).divides(D): # [3] , [2,1] dec = frob_at_p(p) vals = list(set(dec)) vals = sorted(vals, reverse=True) dec = [[x, dec.count(x)] for x in vals] #dec2 = ["$" + str(x[0]) + ('^{' + str(x[1]) + '}$' if x[1] > 1 else '$') for x in dec] s = '$' firstone = True for j in dec: if not firstone: s += r'{,}\,' if j[0]<15: s += r'{\href{%s}{%d} }'%(url_for('local_fields.by_label', label="%d.%d.0.1"%(p,j[0])), j[0]) else: s += str(j[0]) if j[1] > 1: s += '^{' + str(j[1]) + '}' firstone = False s += '$' ans.append([p, s]) else: ans.append([p, 'R']) seeram = True return ans, seeram
def see_frobs(frob_data): ans = [] seeram = False plist = [p for p in prime_range(2, 60)] for i in range(len(plist)): p = plist[i] dec = frob_data[i][1] if dec[0] == 0: ans.append([p, 'R']) seeram = True else: s = '$' firstone = True for j in dec: if not firstone: s += r'{,}\,' if j[0]<15: s += r'{\href{%s}{%d} }'%(url_for('local_fields.by_label', label="%d.%d.0.1"%(p,j[0])), j[0]) else: s += str(j[0]) if j[1] > 1: s += '^{' + str(j[1]) + '}' firstone = False s += '$' ans.append([p, s]) return ans, seeram
def get_type_2_primes(K, aux_prime_count=5, bound=None): """Compute a list containing the type 2 primes""" # First compute the superset of type 2 primes which are not of Momose Type 2 output = get_type_2_not_momose(K, aux_prime_count) # Now deal with Momose Type 2 # First get the bound if bound is None: bound = get_type_2_bound(K) print("type_2_bound = {}".format(bound)) # We need to include all primes up to 25 # see Larson/Vaintrob's proof of Theorem 6.4 output = output.union(set(prime_range(25))) for p in pari.primes(25, bound): p_int = Integer(p) if p_int % 4 == 3: # Momose Type 2 primes are necessarily congruent to 3 mod 4 if satisfies_condition_CC(K, p_int): output.add(p_int) # Sort and return output = list(output) output.sort() return output
def anlist_over_nf(E, bound): """ Caution: This method is slow, especially for curves of high conductor, or defined over number fields of high degree. The method is to take the Euler product form, and retrieve the coefficients by expanding each product factor as a power series. The bottleneck is counting points over good reductions. TODO: Cache this method: it is computed when initializing the class dokchitser, if cached would have .num_coeffs() of a_i stored. EXAMPLE:: sage: K.<i> = NumberField(x^2+1) sage: E = EllipticCurve(K,[0,-1,1,0,0]) sage: from psage.ellcurve.lseries.lseries_nf import anlist_over_nf sage: anlist_over_nf(E, 20) [0, 1, -2, 0, 2, 2, 0, 0, 0, -5, -4, 0, 0, 8, 0, 0, -4, -4, 10, 0, 4] """ conductor = E.conductor() coefficients = [0, 1] + [0] * (bound - 1) for p in prime_range(bound + 1): accuracy_p = int(math.floor(old_div(math.log(bound), math.log(p)))) + 1 series_p = get_coeffs_p_over_nf(E, p, accuracy_p, conductor) for i in range(1, accuracy_p): coefficients[p**i] = series_p[i] extend_multiplicatively_generic(coefficients) return coefficients
def __init__(self, signature=0, weight=2, level_limit=34, rank_limit=4, primes=None, simple_color=None, nonsimple_color=None, reduction=True, bound=0): """ Initialize a SimpleModulesGraph containing finite quadratic modules of signature ``signature``. They are checked for being ``weight``-simple if their minimal number of generators is at most `rank_limit`. INPUT: - ``signature``: the signature of the modules - ``weight``: check for cusp forms of weight ``weight`` - ``level_limit``: only check for anisotropic modules with level smaller than ``level_limit`` - ``rank_limit``: an upper bound for the minimal number of generators - ``bound``: upper bound for the dimension (for considered being simple), default=0 OUTPUT: A SimpleModulesGraph object. No computations are done after initialization. Start the computation using the method ``compute()``. """ ########################### # basic parameters ########################### self._level_limit = Integer(level_limit) self._rank_limit = Integer(rank_limit) self._signature = Integer(signature) % 8 self._weight = QQ(weight) self._reduction = reduction self._bound = bound ######################################################### # Initialize the primes that need to be checked # According to Theorem 4.21 in [BEF], # in the worst case, we need to check primes p for which # prime_pol_simple(p, weight) <= bound. ######################################################### if primes is None: p = 2 while True: if prime_pol_simple(p, weight) > self._bound: primes = list(prime_range(p)) break else: p = next_prime(p) self._primes = primes self._simple_color = colors.darkred.rgb( ) if simple_color is None else simple_color self._nonsimple_color = colors.darkgreen.rgb( ) if nonsimple_color is None else nonsimple_color self._vertex_colors = dict() self._vertex_colors[self._simple_color] = list() self._vertex_colors[self._nonsimple_color] = list() self._heights = dict() # a height function for plotting self._simple = list() # will contain the list of k-simple modules super(SimpleModulesGraph, self).__init__()
def check_prime_count(self): """ check that every prime p < 100 occurs exactly once for each hecke_orbit_code """ # TIME about 30s cnt = db.mf_newforms.count({'field_poly':{'$exists':True}}) return accumulate_failures(self.check_count(cnt, {'p': p}) for p in prime_range(100))
def load_result_list(first_prime,last_prime,result_dir="kamienny_run"): l=[] for i in prime_range(first_prime,last_prime): l.append(get_results_from_dir(i,0,result_dir=result_dir)) l.append(get_results_from_dir(i,1,result_dir=result_dir)) l=sum(l,[]) return l
def type_2_primes(K, embeddings, bound=None): """Compute a list containing the type 2 primes""" logger.debug("Starting Type 2 computation ...") # First compute the superset of type 2 primes which are not of Momose Type 2 output = get_type_2_not_momose(K, embeddings) logger.debug("Type 2 not Momose = {}".format(sorted(output))) # Now deal with Momose Type 2 # First get the bound if bound is None: bound = get_type_2_bound(K) logger.info("type_2_bound = {}".format(bound)) # We need to include all primes up to 25 # see Larson/Vaintrob's proof of Theorem 6.4 output = output.union(set(prime_range(25))) for p in pari.primes(25, bound): p_int = Integer(p) if p_int % 4 == 3: # Type 2 primes necessarily congruent to 3 mod 4 if satisfies_condition_CC(K, p_int): output.add(p_int) output = list(output) output.sort() return output
def anlist_over_nf(E, bound): """ Caution: This method is slow, especially for curves of high conductor, or defined over number fields of high degree. The method is to take the Euler product form, and retrieve the coefficients by expanding each product factor as a power series. The bottleneck is counting points over good reductions. TODO: Cache this method: it is computed when initializing the class dokchitser, if cached would have .num_coeffs() of a_i stored. EXAMPLE:: sage: K.<i> = NumberField(x^2+1) sage: E = EllipticCurve(K,[0,-1,1,0,0]) sage: from psage.ellcurve.lseries.lseries_nf import anlist_over_nf sage: anlist_over_nf(E, 20) [0, 1, -2, 0, 2, 2, 0, 0, 0, -5, -4, 0, 0, 8, 0, 0, -4, -4, 10, 0, 4] """ conductor = E.conductor() coefficients = [0,1] + [0]*(bound-1) for p in prime_range(bound+1): accuracy_p = int(math.floor(math.log(bound)/math.log(p))) + 1 series_p = get_coeffs_p_over_nf(E, p, accuracy_p, conductor) for i in range(1, accuracy_p): coefficients[p**i] = series_p[i] extend_multiplicatively_generic(coefficients) return coefficients
def verify_criterion_range(self,degree,n_min,n_max,q_min,q_max,t1mod,v=None,use_rand_vec=True, verbose=False,stop_if_satisfied=True): torsion_order=self.p congruence_type=self.congruence_type algorithm=self.algorithm dependency_spaces=[] results=[] for t1n in range(n_min,n_max): if self.t1_prime(t1n, t1mod) == 0: results.append({"torsion_order":torsion_order,"congruence_type":congruence_type, "algorithm":algorithm,"degree":degree,"n":t1n, "satisfied":False,"message":"","use_rand_vec":use_rand_vec, "result_type":"t1n_is_zero"}) continue for t2q in prime_range(q_min,q_max): if t2q==torsion_order: continue satisfied,message,dependencies=self.verify_criterion(degree,n=t1n,p=t1mod,q=t2q,use_rand_vec=use_rand_vec,verbose=verbose) dependency_spaces.append(dependencies) results.append({"torsion_order":torsion_order,"congruence_type":congruence_type, "algorithm":algorithm,"degree":degree,"n":t1n,"p":t1mod, "q":t2q,"satisfied":satisfied,"message":message,"use_rand_vec":use_rand_vec, "result_type":"single"}) if stop_if_satisfied and satisfied: break if stop_if_satisfied and satisfied: break print [len(i) for i in dependency_spaces]
def get_all_results_in_range(begin,end,result_dir="kamienny_run"): primes=prime_range(begin,end) l=[] for prime in primes: for congruence_type in (0,1): l.extend(get_results_from_dir(prime,congruence_type,result_dir=result_dir)) return l
def type_1_primes(K, C_K, norm_bound=50): """Compute the type 1 primes""" # Get bad formal immersion data bad_formal_immersion_list, bad_aux_prime_dict = cached_bad_formal_immersion_data( K.degree()) aux_primes = prime_range(3, norm_bound + 1) if not aux_primes: # i.e. the user has inserted a silly value of norm_bound, so we add # one aux prime as in the generic case aux_primes = [3] bound_so_far = 0 for q in aux_primes: bound_so_far = get_C_integer_type1(K, q, bad_aux_prime_dict, C_K, bound_so_far) bound_at_2 = get_C_integer_type1(K, 2, bad_aux_prime_dict, C_K, bound_so_far) output = set(bound_so_far.prime_divisors()) logger.debug("Type 1 primes before BFI data = {}".format(sorted(output))) output = apply_formal_immersion_at_2(output, bound_at_2, K.degree()) output = output.union(set(bad_formal_immersion_list)) return sorted(output)
def populate_db(address, level_min, level_max, pmax=100, ncpus=sage.parallel.ncpus.ncpus()): """ Compute and insert into the MongoDB database with the given address the Fourier coefficients a_p for p up to pmax for the optimal elliptic curves of the given range of levels (top level not included), using the given number of threads. Only curves with ap not yet set are affected by this function. """ user, password = userpass() import math, random from sage.all import prime_range, parallel, pari level_min = int(level_min); level_max = int(level_max) P = prime_range(pmax) s = int(math.ceil((level_max - level_min)/float(ncpus))) blocks = [(level_min+i*s, min(level_max,level_min+(i+1)*s)) for i in range(ncpus)] @parallel(ncpus) def f(l_min, l_max): from pymongo import Connection C = Connection(address).research C.authenticate(user, password) C = C.ellcurves for v in C.find({'level':{'$gte':level_min, '$lt':level_max}, 'number':1, 'ap':{'$exists':False}}): E = pari('ellinit(%s,1)'%v['weq']) ap = dict([(str(p),int(E.ellap(p))) for p in P]) C.update({'_id':v['_id']}, {'$set':{'ap':ap}}) for ans in f(blocks): print ans
def set_euler_factors(self): # Sets: # - euler_factors # - bad_lfactors bound = 100 power = self.power if self.curve.genus() == 1: E = self.curve ZZT = PolynomialRing(ZZ, "T") T = ZZT.gen() K = E.base_field() if K == QQ: K = NumberField(T,"a") # making sure SAGE sees K as a numberfield E = E.change_ring(K) N = (E.conductor() * K.discriminant()**2).absolute_norm() assert N == self.conductor def get_eulerfactor(p): Lp = 1 for f, _ in K.fractional_ideal(p).factor(): f = K.fractional_ideal(f) if f.divides(N): local_factor = (1 - E.local_data(f).bad_reduction_type() * T) Lp *= local_factor( T ** f.absolute_norm().valuation(p) ) else: frob = ZZT(E.local_data(f).minimal_model().change_ring(f.residue_field()).frobenius_polynomial()) Lp *= frob.reverse()( T ** f.absolute_norm().valuation(p) ) return list(map(int, Lp)) if power > 1: euler_factors = {} for p, v in self.hard_factors.items(): euler_factors[p] = v for p in prime_range(bound): if p in self.hard_factors: continue _, ma, p = euler_factors(p) euler_factors[p] = sym_pol_ECQ(-ma, p, power) else: euler_factors = {p: get_eulerfactor(p) for p in prime_range(bound)} else: raise NotImplementedError("only implemented for genus 1 at the moment") self.euler_factors = [euler_factors[p] for p in prime_range(bound)] self.bad_lfactors = [[p, euler_factors[p]] for p in Integer(self.conductor).prime_divisors()]
def upper_bound_index_cusps_in_JG_torsion(G, d, bound=60): """ INPUT: - G - a congruence subgroup - d - integer, the size of the rational cuspidal subgroup - bound (optional, default = 60) - the bound for the primes p up to which to use the hecke matrix `T_p - <p> - p` for bounding the torsion subgroup OUTPUT: - an integer `i` such that `(\#J_G(\QQ)_{tors})/d` is a divisor of `i`. EXAMPLES:: sage: from mdsage import * sage: d = rational_cuspidal_classgroup(Gamma1(23)).cardinality() sage: upper_bound_index_cusps_in_JG_torsion(Gamma1(23),d) 1 """ N = G.level() M = ModularSymbols(G) Sint = cuspidal_integral_structure(M) kill_mat = (M.star_involution().matrix().restrict(Sint) - 1) kill = kill_mat.transpose().change_ring(ZZ).row_module() for p in prime_range(3, bound): if not N % p == 0: kill += kill_torsion_coprime_to_q( p, M).restrict(Sint).change_ring(ZZ).transpose().row_module() if kill.matrix().is_square() and kill.matrix().determinant() == d: #print p break kill_mat = kill.matrix().transpose() #print N,"index of torsion in stuff killed",kill.matrix().determinant()/d if kill.matrix().determinant() == d: return 1 pm = integral_period_mapping(M) period_images1 = [ sum([M.coordinate_vector(M([c, infinity])) for c in cusps]) * pm for cusps in galois_orbits(G) ] m = (Matrix(period_images1) * kill_mat).stack(kill_mat) diag = m.change_ring(ZZ).echelon_form().diagonal() #print diag,prod(diag) assert prod(diag) == kill.matrix().determinant() / d period_images2 = [ M.coordinate_vector(M([c, infinity])) * pm for c in G.cusps() if c != Cusp(oo) ] m = (Matrix(period_images2) * kill_mat).stack(kill_mat) m, denom = m._clear_denom() diag = (m.change_ring(ZZ).echelon_form() / denom).diagonal() #print diag #print prod(i.numerator() for i in diag),"if this is 1 then :)" return prod(i.numerator() for i in diag)
def criterion_iterator(torsion_order,degrees=list(range(3,8)),t1n_bound=12,t1mod=65521,t2q_bound=14): iterator=[] for deg in degrees: for t1n in range(2,t1n_bound): for q in prime_range(3,t2q_bound): if q!=torsion_order: iterator.append((deg,t1n,t1mod,q)) return iterator
def __init__(self, E, N, K): self.E = E self.ap = [K(ap) for ap in E.aplist(N)] self.N = N self.primes = [K(p) for p in prime_range(N)] self.K = K self.log_primes = [p.log() for p in self.primes] self.I = K(I)
def criterion_iterator(torsion_order,degrees=range(3,8),t1n_bound=12,t1mod=65521,t2q_bound=14): iterator=[] for deg in degrees: for t1n in range(2,t1n_bound): for q in prime_range(3,t2q_bound): if q!=torsion_order: iterator.append((deg,t1n,t1mod,q)) return iterator
def Yoshida_Lift(F, hhecke_evals, hlevel, hweight=[2, 2], primeprec=100): weight = (hweight[1] + 2) / 2 level = F.disc()**2 * hlevel.norm() lam = {} mu = {} for p in prime_range(primeprec): v = level.valuation(p) if v == 0: if len(F.primes_above(p)) == 1: lam[p] = 0 mu[p] = p**(2 * (weight - 3)) * ( -p**2 - p * hhecke_evals[F.prime_above(p)] - 1) else: lam[p] = p**( (weight - 3)) * p * (hhecke_evals[F.primes_above(p)[0]] + hhecke_evals[F.primes_above(p)[1]]) mu[p] = p**(2 * (weight - 3)) * ( p**2 + p * hhecke_evals[F.primes_above(p)[0]] * hhecke_evals[F.primes_above(p)[1]] - 1) if v == 1: if hlevel.valuation(F.primes_above(p)[0]) == 1: po = F.primes_above(p)[0] pt = F.primes_above(p)[1] else: pt = F.primes_above(p)[0] po = F.primes_above(p)[1] lam[p] = p**((weight - 3)) * (p * hhecke_evals[po] + (p + 1) * hhecke_evals[pt]) mu[p] = p**(2 * (weight - 3)) * (p * hhecke_evals[F.primes_above(p)[0]] * hhecke_evals[F.primes_above(p)[1]]) else: if len(F.primes_above(p)) == 2: lam[p] = p**( (weight - 3)) * p * (hhecke_evals[F.primes_above(p)[0]] + hhecke_evals[F.primes_above(p)[1]]) if hlevel.valuation(F.primes_above(p)[0]) * hlevel.valuation( F.primes_above(p)[1]) == 0: mu[p] = 0 else: mu[p] = p**(2 * (weight - 3)) * (-p**2) else: if F.ideal(p).valuation(F.prime_above(p)) == 2: lam[p] = p * hhecke_evals[F.prime_above(p)] if hlevel.valuation(F.prime_above(p)) == 0: mu[p] = 0 else: mu[p] = p**(2 * (weight - 3)) * (-p**2) else: lam[p] = 0 mu[p] = p**(2 * (weight - 3)) * ( -p**2 - p * hhecke_evals[F.prime_above(p)]) return { 'paramodular_level': level, 'weight': weight, 'T(1,1,p,p)': lam, 'T(1,p,p,p^2)': mu }
def ssp(e, nssp=5, maxp=10000000): pp = [] for p in prime_range(maxp): if e.is_supersingular(p): pp.append(p) if len(pp) == nssp: return pp print("{} has only {} supersingular primes up to {}".format( Elabel(e), len(pp), maxp)) return pp
def render_modlmf_webpage(**args): C = getDBConnection() data = None if 'label' in args: lab = args.get('label') data = C.mod_l_eigenvalues.modlmf.find_one({'label': lab }) if data is None: t = "mod ℓ modular form search error" bread = [('mod ℓ Modular Forms', url_for(".modlmf_render_webpage"))] flash(Markup("Error: <span style='color:black'>%s</span> is not a valid label for a mod ℓ modular form in the database." % (lab)),"error") return render_template("modlmf-error.html", title=t, properties=[], bread=bread, learnmore=learnmore_list()) info = {} info.update(data) info['friends'] = [] bread=[('Modular Forms', "/ModularForm"),('GL(2)',""),('mod ℓ', url_for(".modlmf_render_webpage")), ('%s' % data['label'], ' ')] credit = modlmf_credit f = C.mod_l_eigenvalues.modlmf.find_one({'characteristic':data['characteristic'], 'deg' : data['deg'], 'level' : data['level'],'conductor' : data['conductor'],'min_weight': data['min_weight'], 'dirchar' : data['dirchar'], 'atkinlehner': data['atkinlehner'],'n_coeffs': data['n_coeffs'],'coeffs': data['coeffs']}) for m in ['characteristic','deg','level','conductor','min_weight', 'n_coeffs']: info[m]=int(f[m]) for m in ['coeffs', 'atkinlehner']: info[m]=f[m] info['dirchar']=str(f['dirchar']) if f['deg'] == int(1): info['field']=str('𝔽<sub>%s</sub>' %f['characteristic']) else: try: pol=str(conway_polynomial(f['characteristic'], f['deg'])) info['field']=str('𝔽<sub>%s<sup>%s</sup></sub>𝔽<sub>%s</sub>[x]/(%s)' %(str(f['characteristic']), str(f['deg']), str(f['characteristic']), pol)) except: info['field']="" ncoeff=int(round(50/f['deg'])) if f['coeffs'] != "": coeff=[f['coeffs'][i] for i in range(ncoeff+1)] info['q_exp']=my_latex(print_q_expansion(coeff)) info['q_exp_display'] = url_for(".q_exp_display", label=f['label'], number="") p_range=prime_range(100) info['table_list']=[[p_range[i], f['coeffs'][p_range[i]]] for i in range(len(p_range))] info['download_q_exp'] = [ (i, url_for(".render_modlmf_webpage_download", label=info['label'], lang=i)) for i in ['gp', 'magma','sage']] t = "mod ℓ Modular Form "+info['label'] info['properties'] = [ ('Field characteristic', '%s' %info['characteristic']), ('Field degree', '%s' %info['deg']), ('Level', '%s' %info['level']), ('Conductor', '%s' %info['conductor']), ('Minimal weight', '%s' %info['min_weight']), ('Label', '%s' %info['label'])] return render_template("modlmf-single.html", info=info, credit=credit, title=t, bread=bread, properties2=info['properties'], learnmore=learnmore_list())
def check_angles(self, rec, verbose=False): """ check that angles are null exactly for p dividing the level """ # TIME about 200000s for full table? level = int(rec['label'].split('.')[0]) for p, angle in zip(prime_range(1000), rec['angles']): if (level % p == 0) != (angle is None): if verbose: print "Angle presence failure", p, ZZ(level).factor(), angle return False return True
def compute_aplists(N, k, i, *args): if i == 'all': G = DirichletGroup(N).galois_orbits() sgn = (-1)**k for j, g in enumerate(G): if g[0](-1) == sgn: compute_aplists(N,k,j,*args) return if i == 'quadratic': G = DirichletGroup(N).galois_orbits() sgn = (-1)**k for j, g in enumerate(G): if g[0](-1) == sgn and g[0].order()==2: compute_aplists(N,k,j,*args) return if len(args) == 0: args = (100, ) filename = filenames.ambient(N, k, i) if not os.path.exists(filename): print "Ambient (%s,%s,%s) space not computed."%(N,k,i) return #compute_ambient_space(N, k, i) print "computing aplists for (%s,%s,%s)"%(N,k,i) m = filenames.number_of_known_factors(N, k, i) if m == 0: # nothing to do return M = load_ambient_space(N, k, i) for d in range(m): aplist_file = filenames.factor_aplist(N, k, i, d, False, *args) if os.path.exists(aplist_file): print "skipping computing aplist(%s) for (%s,%s,%s,%s) since it already exists"%(args, N,k,i,d) # already done continue # compute aplist print "computing aplist(%s) for (%s,%s,%s,%s)"%(args, N,k,i,d) t = cputime() A = load_factor(N, k, i, d, M) aplist, _ = A.compact_system_of_eigenvalues(prime_range(*args), 'a') print aplist, aplist_file save(aplist, aplist_file) tm = cputime(t) meta = {'cputime':tm, 'version':version()} save(meta, filenames.meta(aplist_file))
def tensor_get_an_no_deg1(L1, L2, d1, d2, BadPrimeInfo): """ Same as the above in the case no dimension is 1 """ if d1==1 or d2==1: raise ValueError('min(d1,d2) should not be 1, use direct method then') s1 = len(L1) s2 = len(L2) if s1 < s2: S = s1 if s2 <= s1: S = s2 BadPrimes = [] for bpi in BadPrimeInfo: BadPrimes.append(bpi[0]) P = prime_range(S+1) Z = S * [1] S = RealField()(S) for p in P: f = S.log(base=p).floor() q = 1 E1 = [] E2 = [] if not p in BadPrimes: for i in range(f): q=q*p E1.append(L1[q-1]) E2.append(L2[q-1]) e1 = list_to_euler_factor(E1,f+1) e2 = list_to_euler_factor(E2,f+1) # ld1 = d1 # not used # ld2 = d2 # not used else: # either convolve, or have one input be the answer and other 1-t i = BadPrimes.index(p) e1 = BadPrimeInfo[i][1] e2 = BadPrimeInfo[i][2] # ld1 = e1.degree() # not used # ld2 = e2.degree() # not used F = e1.list()[0].parent().fraction_field() R = PowerSeriesRing(F, "T", default_prec=f+1) e1 = R(e1) e2 = R(e2) E = tensor_local_factors(e1,e2,f) A = euler_factor_to_list(E,f) while len(A) < f: A.append(0) q = 1 for i in range(f): q = q*p Z[q-1]=A[i] all_an_from_prime_powers(Z) return Z
def upper_bound_index_cusps_in_JG_torsion(G,d, bound = 60): """ INPUT: - G - a congruence subgroup - d - integer, the size of the rational cuspidal subgroup - bound (optional, default = 60) - the bound for the primes p up to which to use the hecke matrix `T_p - <p> - p` for bounding the torsion subgroup OUTPUT: - an integer `i` such that `(\#J_G(\QQ)_{tors})/d` is a divisor of `i`. EXAMPLES:: sage: from mdsage import * sage: d = rational_cuspidal_classgroup(Gamma1(23)).cardinality() sage: upper_bound_index_cusps_in_JG_torsion(Gamma1(23),d) 1 """ N = G.level() M=ModularSymbols(G); Sint=cuspidal_integral_structure(M) kill_mat=(M.star_involution().matrix().restrict(Sint)-1) kill=kill_mat.transpose().change_ring(ZZ).row_module() for p in prime_range(3,bound): if not N % p ==0: kill+=kill_torsion_coprime_to_q(p,M).restrict(Sint).change_ring(ZZ).transpose().row_module() if kill.matrix().is_square() and kill.matrix().determinant()==d: #print p break kill_mat=kill.matrix().transpose() #print N,"index of torsion in stuff killed",kill.matrix().determinant()/d if kill.matrix().determinant()==d: return 1 pm=integral_period_mapping(M) period_images1=[sum([M.coordinate_vector(M([c,infinity])) for c in cusps])*pm for cusps in galois_orbits(G)] m=(Matrix(period_images1)*kill_mat).stack(kill_mat) diag=m.change_ring(ZZ).echelon_form().diagonal() #print diag,prod(diag) assert prod(diag)==kill.matrix().determinant()/d period_images2=[M.coordinate_vector(M([c,infinity]))*pm for c in G.cusps() if c != Cusp(oo)] m=(Matrix(period_images2)*kill_mat).stack(kill_mat) m,denom=m._clear_denom() diag=(m.change_ring(ZZ).echelon_form()/denom).diagonal() #print diag #print prod(i.numerator() for i in diag),"if this is 1 then :)" return prod(i.numerator() for i in diag)
def tensor_get_an_no_deg1(L1, L2, d1, d2, BadPrimeInfo): """ Same as the above in the case no dimension is 1 """ if d1 == 1 or d2 == 1: raise ValueError('min(d1,d2) should not be 1, use direct method then') s1 = len(L1) s2 = len(L2) if s1 < s2: S = s1 if s2 <= s1: S = s2 BadPrimes = [] for bpi in BadPrimeInfo: BadPrimes.append(bpi[0]) P = prime_range(S + 1) Z = S * [1] S = RealField()(S) for p in P: f = S.log(base=p).floor() q = 1 E1 = [] E2 = [] if not p in BadPrimes: for i in range(f): q = q * p E1.append(L1[q - 1]) E2.append(L2[q - 1]) e1 = list_to_euler_factor(E1, f + 1) e2 = list_to_euler_factor(E2, f + 1) # ld1 = d1 # not used # ld2 = d2 # not used else: # either convolve, or have one input be the answer and other 1-t i = BadPrimes.index(p) e1 = BadPrimeInfo[i][1] e2 = BadPrimeInfo[i][2] # ld1 = e1.degree() # not used # ld2 = e2.degree() # not used F = e1.list()[0].parent().fraction_field() R = PowerSeriesRing(F, "T", default_prec=f + 1) e1 = R(e1) e2 = R(e2) E = tensor_local_factors(e1, e2, f) A = euler_factor_to_list(E, f) while len(A) < f: A.append(0) q = 1 for i in range(f): q = q * p Z[q - 1] = A[i] all_an_from_prime_powers(Z) return Z
def check_amn_slow(self, rec, verbose=False): """ Check that a_{pn} = a_p * a_n for p < 32 prime, n prime to p """ Z = [0] + [CC(*elt) for elt in rec['an_normalized']] for pp in prime_range(len(Z)-1): for k in range(1, (len(Z) - 1)//pp + 1): if gcd(k, pp) == 1: if (Z[pp*k] - Z[pp]*Z[k]).abs() > 1e-13: if verbose: print "amn failure", k, pp, Z[pp*k], Z[pp]*Z[k] return False return True
def __init__(self, signature=0, weight=2, level_limit=34, rank_limit=4, primes=None, simple_color=None, nonsimple_color=None, reduction=True, bound=0): """ Initialize a SimpleModulesGraph containing finite quadratic modules of signature ``signature``. They are checked for being ``weight``-simple if their minimal number of generators is at most `rank_limit`. INPUT: - ``signature``: the signature of the modules - ``weight``: check for cusp forms of weight ``weight`` - ``level_limit``: only check for anisotropic modules with level smaller than ``level_limit`` - ``rank_limit``: an upper bound for the minimal number of generators - ``bound``: upper bound for the dimension (for considered being simple), default=0 OUTPUT: A SimpleModulesGraph object. No computations are done after initialization. Start the computation using the method ``compute()``. """ ########################### # basic parameters ########################### self._level_limit = Integer(level_limit) self._rank_limit = Integer(rank_limit) self._signature = Integer(signature) % 8 self._weight = QQ(weight) self._reduction = reduction self._bound = bound ######################################################### # Initialize the primes that need to be checked # According to Theorem 4.21 in [BEF], # in the worst case, we need to check primes p for which # prime_pol_simple(p, weight) <= bound. ######################################################### if primes is None: p = 2 while True: if prime_pol_simple(p, weight) > self._bound: primes = list(prime_range(p)) break else: p = next_prime(p) self._primes = primes self._simple_color = colors.darkred.rgb() if simple_color is None else simple_color self._nonsimple_color = colors.darkgreen.rgb() if nonsimple_color is None else nonsimple_color self._vertex_colors = dict() self._vertex_colors[self._simple_color] = list() self._vertex_colors[self._nonsimple_color] = list() self._heights = dict() # a height function for plotting self._simple = list() # will contain the list of k-simple modules super(SimpleModulesGraph, self).__init__()
def JG_torsion_upperbound(G, bound=60): """ INPUT: - G - a congruence subgroup - bound (optional, default = 60) - the bound for the primes p up to which to use the hecke matrix `T_p - <p> - p` for bounding the torsion subgroup OUTPUT: - A subgroup of `(S_2(G) \otimes \QQ) / S_2(G)` that is guaranteed to contain the rational torison subgroup, together with a subgroup generated by the rational cusps. The subgroup is given as a subgroup of `S_2(G)/NS_2(G)` for a suitable integer N EXAMPLES:: sage: from mdsage import * sage: d = rational_cuspidal_classgroup(Gamma1(23)).cardinality() sage: upper_bound_index_cusps_in_JG_torsion(Gamma1(23),d) 1 """ N = G.level() M = ModularSymbols(G) Sint = cuspidal_integral_structure(M) kill_mat = (M.star_involution().matrix().restrict(Sint) - 1) kill = kill_mat.transpose().change_ring(ZZ).row_module() for p in prime_range(3, bound): if not N % p == 0: kill += kill_torsion_coprime_to_q( p, M).restrict(Sint).change_ring(ZZ).transpose().row_module() #if kill.matrix().is_square() and kill.matrix().determinant()==d: # #print p # break kill_mat = kill.matrix().transpose() #print N,"index of torsion in stuff killed",kill.matrix().determinant()/d #if kill.matrix().determinant()==d: # return 1 d = prod(kill_mat.smith_form()[0].diagonal()) pm = integral_period_mapping(M) #period_images1=[sum([M.coordinate_vector(M([c,infinity])) for c in cusps])*pm for cusps in galois_orbits(G)] period_images2 = [ M.coordinate_vector(M([c, infinity])) * pm for c in G.cusps() if c != Cusp(oo) ] m = (Matrix(period_images2) * kill_mat).stack(kill_mat) m, d2 = m._clear_denom() d = gcd(d, d2)
def satisfies_condition_CC_uniform(possible_odd_f, p): """Determine whether degrees,p satisfies condition CC. Args: K ([NumberField]): the number field p ([Prime]): the prime p Returns: boolean """ if p % 4 == 1 or p == 2: return False for q in prime_range((p / 4) ^ (1 / max(possible_odd_f)) + 1): if legendre_symbol(q, p) == 1: if all((q**(2 * f) + q**f + 1) % p != 0 for f in possible_odd_f): return False return True
def check_ap2_slow(rec): # Check a_{p^2} = a_p^2 - chi(p) for primes up to 31 ls = rec['lfunction_label'].split('.') level, weight, chi = map(int, [ls[0], ls[1], ls[-2]]) char = DirichletGroup_conrey(level, CC)[chi] Z = rec['an_normalized[0:1000]'] for p in prime_range(31+1): if level % p != 0: # a_{p^2} = a_p^2 - chi(p) charval = CC(2*char.logvalue(int(p)) * CC.pi()*CC.gens()[0]).exp() else: charval = 0 if (CC(*Z[p**2 - 1]) - (CC(*Z[p-1])**2 - charval)).abs() > 1e-11: return False return True
def bad_formal_immersion_data(d): """ This is the Oesterlé for type 1 primes with modular symbols main routine. The computation is actually a two step rocket. First Proposition 6.8 of Derickx-Kamienny-Stein-Stoll is used to replace Parents polynomial of degree 6 bound by something reasonable, and then Proposition 6.3 is used to go from something reasonable to the exact list. """ assert d > 0 p_bad = prime_range(11) p_done = {} q_to_bad_p = {} M = construct_M(d)[0] for p in prime_range(11, 2 * M * d): # first do a relatively cheap test if is_formal_immersion_fast(d, p): continue # this is less cheap but still quite fast if is_formal_immersion_medium(d, p) == 1: continue # this is the most expensive but give the correct answer is_formal = is_formal_immersion(d, p) if is_formal: if is_formal > 1: p_done[p] = is_formal else: p_bad.append(p) for p, q_prod in p_done.items(): for q in prime_divisors(q_prod): q_to_bad_p[q] = q_to_bad_p.get(q, 1) * p return p_bad, q_to_bad_p
def satisfies_condition_CC(K, p): """Determine whether K,p satisfies condition CC. Args: K ([NumberField]): the number field p ([Prime]): the prime p Returns: boolean """ for q in prime_range(p / 4): if (q ** 2 + q + 1) % p != 0: if not K.ideal(q).is_prime(): if legendre_symbol(q, p) == 1: # i.e. not inert return False return True
def JG_torsion_upperbound(G, bound = 60): """ INPUT: - G - a congruence subgroup - bound (optional, default = 60) - the bound for the primes p up to which to use the hecke matrix `T_p - <p> - p` for bounding the torsion subgroup OUTPUT: - A subgroup of `(S_2(G) \otimes \QQ) / S_2(G)` that is guaranteed to contain the rational torison subgroup, together with a subgroup generated by the rational cusps. The subgroup is given as a subgroup of `S_2(G)/NS_2(G)` for a suitable integer N EXAMPLES:: sage: from mdsage import * sage: d = rational_cuspidal_classgroup(Gamma1(23)).cardinality() sage: upper_bound_index_cusps_in_JG_torsion(Gamma1(23),d) 1 """ N = G.level() M=ModularSymbols(G); Sint=cuspidal_integral_structure(M) kill_mat=(M.star_involution().matrix().restrict(Sint)-1) kill=kill_mat.transpose().change_ring(ZZ).row_module() for p in prime_range(3,bound): if not N % p ==0: kill+=kill_torsion_coprime_to_q(p,M).restrict(Sint).change_ring(ZZ).transpose().row_module() #if kill.matrix().is_square() and kill.matrix().determinant()==d: # #print p # break kill_mat=kill.matrix().transpose() #print N,"index of torsion in stuff killed",kill.matrix().determinant()/d #if kill.matrix().determinant()==d: # return 1 d = prod(kill_mat.smith_form()[0].diagonal()) pm=integral_period_mapping(M) #period_images1=[sum([M.coordinate_vector(M([c,infinity])) for c in cusps])*pm for cusps in galois_orbits(G)] period_images2=[M.coordinate_vector(M([c,infinity]))*pm for c in G.cusps() if c != Cusp(oo)] m=(Matrix(period_images2)*kill_mat).stack(kill_mat) m,d2=m._clear_denom() d=gcd(d,d2)
def test_real_quadratic(minp=1, maxp=100, minwt=2, maxwt=1000): for p in prime_range(minp, maxp): if p % 4 == 1: print("p = ", p) gram = Matrix(ZZ, 2, 2, [2, 1, 1, (1 - p) / 2]) M = VectorValuedModularForms(gram) if is_odd(minwt): minwt = minwt + 1 for kk in range(minwt, round(maxwt / 2 - minwt)): k = minwt + 2 * kk if M.dimension_cusp_forms(k) - dimension_cusp_forms( kronecker_character(p), k) / 2 != 0: print("ERROR: {0},{1},{2}".format( k, M.dimension_cusp_forms(k), dimension_cusp_forms(kronecker_character(p), k / 2))) return False return True
def satisfies_condition_CC(K, p): """Determine whether K,p satisfies condition CC. Args: K ([NumberField]): the number field p ([Prime]): the prime p Returns: boolean """ for q in prime_range(p / 4): for frak_q in K.primes_above(q): f = frak_q.residue_class_degree() if f % 2 == 1 and q**f < p / 4: if (q**(2 * f) + q**f + 1) % p != 0: if legendre_symbol(q, p) == 1: # i.e. not inert return False return True
def all_an_from_prime_powers(L): """ L is a list of an such that the terms are correct for all n which are prime powers and all others are equal to 1; this function changes the list in place to make the correct ans for all n """ S = ZZ(len(L)) for p in prime_range(S + 1): q = 1 Sr = RealField()(len(L)) f = Sr.log(base=p).floor() for k in range(f): q = q * p for m in range(2, 1 + (S // q)): if (m % p) != 0: L[m * q - 1] = L[m * q - 1] * L[q - 1]
def all_an_from_prime_powers(L): """ L is a list of an such that the terms are correct for all n which are prime powers and all others are equal to 1; this function changes the list in place to make the correct ans for all n """ S = ZZ(len(L)) for p in prime_range(S+1): q = 1 Sr = RealField()(len(L)) f = Sr.log(base=p).floor() for k in range(f): q = q*p for m in range(2, 1+(S//q)): if (m%p) != 0: L[m*q-1] = L[m*q-1] * L[q-1]
def set_is_CM(self,insert_in_db=True): r""" Checks if f has complex multiplication and if it has then it returns the character. OUTPUT: -''[t,x]'' -- string saying whether f is CM or not and if it is, the corresponding character EXAMPLES:: """ if(len(self._is_CM) > 0): return self._is_CM max_nump = self._number_of_hecke_eigenvalues_to_check() # E,v = self._f.compact_system_of_eigenvalues(max_nump+1) try: coeffs = self.coefficients(range(max_nump + 1),insert_in_db=insert_in_db) except IndexError: return None,None nz = coeffs.count(0) # number of zero coefficients nnz = len(coeffs) - nz # number of non-zero coefficients if(nz == 0): self._is_CM = [False, 0] return self._is_CM # probaly checking too many for D in range(3, ceil(QQ(max_nump) / QQ(2))): try: for x in DirichletGroup(D): if(x.order() != 2): continue # we know that for CM we need x(p) = -1 => c(p)=0 # (for p not dividing N) if(x.values().count(-1) > nz): raise StopIteration() # do not have CM with this char for p in prime_range(max_nump + 1): if(x(p) == -1 and coeffs[p] != 0): raise StopIteration() # do not have CM with this char # if we are here we have CM with x. self._is_CM = [True, x] return self._is_CM except StopIteration: pass self._is_CM = [False, 0] return self._is_CM
def check_ap2_slow(self, rec, verbose=False): """ Check a_{p^2} = a_p^2 - chi(p) for primes up to 31 """ ls = rec['label'].split('.') level, weight, chi = map(int, [ls[0], ls[1], ls[-2]]) char = DirichletGroup_conrey(level, CC)[chi] Z = rec['an_normalized'] for p in prime_range(31+1): if level % p != 0: # a_{p^2} = a_p^2 - chi(p) charval = CC(2*char.logvalue(int(p)) * CC.pi()*CC.gens()[0]).exp() else: charval = 0 if (CC(*Z[p**2 - 1]) - (CC(*Z[p-1])**2 - charval)).abs() > 1e-13: if verbose: print "ap2 failure", p, CC(*Z[p**2 - 1]), CC(*Z[p-1])**2 - charval return False return True
def check_inert_primes(self, rec, verbose=False): """ for each discriminant D in self_twist_discs, check that for each prime p not dividing the level for which (D/p) = -1, check that traces[p] = 0 (we could also check values in mf_hecke_nf and/or mf_hecke_cc, but this would be far more costly) """ # TIME about 3600s for full table N = rec['level'] traces = [0] + rec['traces'] # shift so indexing correct primes = [p for p in prime_range(len(traces)) if N % p != 0] for D in rec['self_twist_discs']: for p in primes: if kronecker_symbol(D, p) == -1 and traces[p] != 0: if verbose: print("CM failure", D, p, traces[p]) return False return True
def check_inert_primes(self, rec, verbose=False): """ for each discriminant D in self_twist_discs, check that for each prime p not dividing the level for which (D/p) = -1, check that traces[p] = 0 (we could also check values in mf_hecke_nf and/or mf_hecke_cc, but this would be far more costly) """ # TIME about 3600s for full table N = rec['level'] traces = [0] + rec['traces'] # shift so indexing correct primes = [p for p in prime_range(len(traces)) if N % p != 0] for D in rec['self_twist_discs']: for p in primes: if kronecker_symbol(D, p) == -1 and traces[p] != 0: if verbose: print "CM failure", D, p, traces[p] return False return True
def Yoshida_Lift(F, hhecke_evals, hlevel, hweight = [2,2], primeprec = 100): weight = (hweight[1] + 2)/2 level = F.disc()**2*hlevel.norm() lam = {} mu = {} for p in prime_range(primeprec): v = level.valuation(p) if v == 0: if len(F.primes_above(p)) == 1: lam[p] = 0 mu[p] = p**(2*(weight -3))*(-p**2 - p*hhecke_evals[F.prime_above(p)] - 1) else: lam[p] = p**((weight - 3))*p*(hhecke_evals[F.primes_above(p)[0]] + hhecke_evals[F.primes_above(p)[1]]) mu[p] = p**(2*(weight - 3))*(p**2 + p*hhecke_evals[F.primes_above(p)[0]]*hhecke_evals[F.primes_above(p)[1]] - 1) if v == 1: if hlevel.valuation(F.primes_above(p)[0]) == 1: po = F.primes_above(p)[0] pt = F.primes_above(p)[1] else: pt = F.primes_above(p)[0] po = F.primes_above(p)[1] lam[p] = p**((weight - 3))*(p*hhecke_evals[po] + (p + 1)*hhecke_evals[pt]) mu[p] = p**(2*(weight - 3))*(p*hhecke_evals[F.primes_above(p)[0]]*hhecke_evals[F.primes_above(p)[1]]) else: if len(F.primes_above(p)) == 2: lam[p] = p**((weight - 3))*p*(hhecke_evals[F.primes_above(p)[0]] + hhecke_evals[F.primes_above(p)[1]]) if hlevel.valuation(F.primes_above(p)[0])*hlevel.valuation(F.primes_above(p)[1]) == 0: mu[p] = 0 else: mu[p] = p**(2*(weight - 3))*(-p**2) else: if F.ideal(p).valuation(F.prime_above(p)) == 2: lam[p] = p*hhecke_evals[F.prime_above(p)] if hlevel.valuation(F.prime_above(p)) == 0: mu[p] = 0 else: mu[p] = p**(2*(weight - 3))*(-p**2) else: lam[p] = 0 mu[p] = p**(2*(weight - 3))*(-p**2-p*hhecke_evals[F.prime_above(p)]) return {'paramodular_level':level, 'weight':weight, 'T(1,1,p,p)':lam, 'T(1,p,p,p^2)':mu}
def tensor_get_an_deg1(L, D, BadPrimeInfo): """ Same as above, except that the BadPrimeInfo is now a list of lists of the form [p,f] where f is a polynomial. """ s1 = len(L) s2 = len(D) if s1 < s2: S = s1 if s2 <= s1: S = s2 BadPrimes = [] for bpi in BadPrimeInfo: BadPrimes.append(bpi[0]) P = prime_range(S+1) Z = S * [1] S = RealField()(S) # fix bug for p in P: f = S.log(base=p).floor() q = 1 u = 1 e = D[p-1] if not p in BadPrimes: for i in range(f): q = q*p u = u*e Z[q-1] = u*L[q-1] else: i = BadPrimes.index(p) e = BadPrimeInfo[i][1] F = e.list()[0].parent().fraction_field() R = PowerSeriesRing(F, "T", default_prec=f+1) e = R(e) A = euler_factor_to_list(e,f) for i in range(f): q = q*p Z[q-1] = A[i] all_an_from_prime_powers(Z) return Z
def an_list(euler_factor_polynomial_fn, upperbound=100000, base_field=QQ): """ Takes a fn that gives for each prime the Euler polynomial of the associated with the prime, given as a list, with independent coefficient first. This list is of length the degree+1. Output the first `upperbound` coefficients built from the Euler polys. Example: The `euler_factor_polynomial_fn` should in practice come from an L-function or data. For a simple example, we construct just the 2 and 3 factors of the Riemann zeta function, which have Euler factors (1 - 1*2^(-s))^(-1) and (1 - 1*3^(-s))^(-1). >>> euler = lambda p: [1, -1] if p <= 3 else [1, 0] >>> an_list(euler)[:20] [1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0] """ from math import ceil, log PP = PowerSeriesRing(base_field, 'x', 1 + ceil(log(upperbound) / log(2.))) prime_l = prime_range(upperbound + 1) result = [1 for i in range(upperbound)] for p in prime_l: euler_factor = (1 / (PP(euler_factor_polynomial_fn(p)))).padded_list() if len(euler_factor) == 1: for j in range(1, 1 + upperbound // p): result[j * p - 1] = 0 continue k = 1 while True: if p ** k > upperbound: break for j in range(1, 1 + upperbound // (p ** k)): if j % p == 0: continue result[j * p ** k - 1] *= euler_factor[k] k += 1 return result
def check_hecke_ring_character_values_and_an(self, rec, verbose=False): """ check that hecke_ring_character_values has the correct format, depending on whether hecke_ring_cyclotomic_generator is set or not check that an has length 100 and that each entry is either a list of integers of length hecke_ring_rank (if hecke_ring_cyclotomic_generator=0) or a list of pairs check that ap has length pi(maxp) and that each entry is formatted correctly (as for an) """ # TIME about 4000s for full table an = rec['an'] if len(an) != 100: if verbose: print "Length an", len(an) return False ap = rec['ap'] maxp = rec['maxp'] if len(ap) != prime_pi(maxp): if verbose: print "Length ap", len(ap), prime_pi(maxp) return False if maxp < 997: if verbose: print "Maxp", maxp return False m = rec['hecke_ring_cyclotomic_generator'] d = rec['hecke_ring_rank'] def check_val(val): if not isinstance(val, list): return False if m == 0: return len(val) == d and all(isinstance(c, integer_types) for c in val) else: for pair in val: if len(pair) != 2: return False if not isinstance(pair[0], integer_types): return False e = pair[1] if not (isinstance(e, integer_types) and 0 <= 2*e < m): return False return True if not all(check_val(a) for a in an): if verbose: for n, a in enumerate(an, 1): if not check_val(a): print "Check an failure (m=%s, d=%s)"%(m, d), n, a return False if not all(check_val(a) for a in ap): if verbose: for p, a in zip(prime_range(maxp), ap): if not check_val(a): print "Check ap failure (m=%s, d=%s)"%(m, d), p, a return False for p, a in zip(prime_range(100), ap): if a != an[p-1]: if verbose: print "Match failure", p, a, an[p-1] return False if rec['char_orbit_index'] != 1: if rec.get('hecke_ring_character_values') is None: if verbose: print "No hecke_ring_character_values" return False N = rec['level'] total_order = 1 for g, val in rec['hecke_ring_character_values']: total_order *= mod(g, N).multiplicative_order() if not check_val(val): if verbose: print "Bad character val (m=%s, d=%s)"%(m, d), g, val return False success = (total_order == euler_phi(N)) if not success and verbose: print "Generators failed", total_order, euler_phi(N) return success return True
def multiple_of_order_using_frobp(self, maxp=None): """ Return a multiple of the order of this torsion group. In the `Gamma_0` case, the multiple is computed using characteristic polynomials of Hecke operators of odd index not dividing the level. In the `Gamma_1` case, the multiple is computed by expressing the frobenius polynomial in terms of the characteristic polynomial of left multiplication by `a_p` for odd primes p not dividing the level. INPUT: - ``maxp`` - (default: None) If maxp is None (the default), return gcd of best bound computed so far with bound obtained by computing GCD's of orders modulo p until this gcd stabilizes for 3 successive primes. If maxp is given, just use all primes up to and including maxp. EXAMPLES:: sage: J = J0(11) sage: G = J.rational_torsion_subgroup() sage: G.multiple_of_order_using_frobp(11) 5 Increasing maxp may yield a tighter bound. If maxp=None, then Sage will use more primes until the multiple stabilizes for 3 successive primes. :: sage: J = J0(389) sage: G = J.rational_torsion_subgroup(); G Torsion subgroup of Abelian variety J0(389) of dimension 32 sage: G.multiple_of_order_using_frobp() 97 sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,11)] [92645296242160800, 7275, 291] sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,13)] [92645296242160800, 7275, 291, 97] sage: [G.multiple_of_order_using_frobp(p) for p in prime_range(3,19)] [92645296242160800, 7275, 291, 97, 97, 97] We can compute the multiple of order of the torsion subgroup for Gamma0 and Gamma1 varieties, and their products. :: sage: A = J0(11) * J0(33) sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 1000 sage: A = J1(23) sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 9406793 sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp(maxp=50) 408991 sage: A = J1(19) * J0(21) sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 35064 The next example illustrates calling this function with a larger input and how the result may be cached when maxp is None:: sage: T = J0(43)[1].rational_torsion_subgroup() sage: T.multiple_of_order_using_frobp() 14 sage: T.multiple_of_order_using_frobp(50) 7 sage: T.multiple_of_order_using_frobp() 7 This function is not implemented for general congruence subgroups unless the dimension is zero. :: sage: A = JH(13,[2]); A Abelian variety J0(13) of dimension 0 sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() 1 sage: A = JH(15, [2]); A Abelian variety JH(15,[2]) of dimension 1 sage: A.rational_torsion_subgroup().multiple_of_order_using_frobp() Traceback (most recent call last): ... NotImplementedError: torsion multiple only implemented for Gamma0 and Gamma1 """ if maxp is None: try: return self.__multiple_of_order_using_frobp except AttributeError: pass A = self.abelian_variety() if A.dimension() == 0: T = ZZ(1) self.__multiple_of_order_using_frobp = T return T if not all((is_Gamma0(G) or is_Gamma1(G) for G in A.groups())): raise NotImplementedError("torsion multiple only implemented for Gamma0 and Gamma1") bnd = ZZ(0) N = A.level() cnt = 0 if maxp is None: X = Primes() else: X = prime_range(maxp+1) for p in X: if (2*N) % p == 0: continue if (len(A.groups()) == 1 and is_Gamma0(A.groups()[0])): f = A.hecke_polynomial(p) b = ZZ(f(p+1)) else: from .constructor import AbelianVariety D = [AbelianVariety(f) for f in A.newform_decomposition('a')] b = 1 for simple in D: G = simple.newform_level()[1] if is_Gamma0(G): f = simple.hecke_polynomial(p) b *= ZZ(f(p+1)) else: f = simple.newform('a') Kf = f.base_ring() eps = f.character() Qe = eps.base_ring() if Kf != QQ: # relativize number fields to compute charpoly of # left multiplication of ap on Kf as a Qe-vector # space. Lf = Kf.relativize(Qe.gen(), 'a') to_Lf = Lf.structure()[1] name = Kf._names[0] ap = to_Lf(f.modular_symbols(1).eigenvalue(p, name)) G_ps = ap.matrix().charpoly() b *= ZZ(Qe(G_ps(1 + to_Lf(eps(p))*p)).norm()) else: ap = f.modular_symbols(1).eigenvalue(p) b *= ZZ(1 + eps(p)*p - ap) if bnd == 0: bnd = b else: bnd_last = bnd bnd = ZZ(gcd(bnd, b)) if bnd == bnd_last: cnt += 1 else: cnt = 0 if maxp is None and cnt >= 2: break # The code below caches the computed bound and # will be used if this function is called # again with maxp equal to None (the default). if maxp is None: # maxp is None but self.__multiple_of_order_using_frobp is # not set, since otherwise we would have immediately # returned at the top of this function self.__multiple_of_order_using_frobp = bnd else: # maxp is given -- record new info we get as # a gcd... try: self.__multiple_of_order_using_frobp = \ gcd(self.__multiple_of_order_using_frobp, bnd) except AttributeError: # ... except in the case when # self.__multiple_of_order_using_frobp was never set. In this # case, we just set it as long as the gcd stabilized for 3 in a # row. if cnt >= 2: self.__multiple_of_order_using_frobp = bnd return bnd
def elliptic_cm_form(E, n, prec, aplist_only=False, anlist_only=False): """ Return q-expansion of the CM modular form associated to the n-th power of the Grossencharacter associated to the elliptic curve E. INPUT: - E -- CM elliptic curve - n -- positive integer - prec -- positive integer - aplist_only -- return list only of ap for p prime - anlist_only -- return list only of an OUTPUT: - power series with integer coefficients EXAMPLES:: sage: from psage.modform.rational.special import elliptic_cm_form sage: f = CuspForms(121,4).newforms(names='a')[0]; f q + 8*q^3 - 8*q^4 + 18*q^5 + O(q^6) sage: E = EllipticCurve('121b') sage: elliptic_cm_form(E, 3, 7) q + 8*q^3 - 8*q^4 + 18*q^5 + O(q^7) sage: g = elliptic_cm_form(E, 3, 100) sage: g == f.q_expansion(100) True """ if not E.has_cm(): raise ValueError, "E must have CM" n = ZZ(n) if n <= 0: raise ValueError, "n must be positive" prec = ZZ(prec) if prec <= 0: return [] elif prec <= 1: return [ZZ(0)] elif prec <= 2: return [ZZ(0), ZZ(1)] # Derive formula for sum of n-th powers of roots a,p,T = SR.var('a,p,T') roots = (T**2 - a*T + p).roots(multiplicities=False) s = sum(alpha**n for alpha in roots).simplify_full() # Create fast callable expression from formula g = fast_callable(s.polynomial(ZZ)) # Compute aplist for the curve v = E.aplist(prec) # Use aplist to compute ap values for the CM form attached to n-th # power of Grossencharacter. P = prime_range(prec) if aplist_only: # case when we only want the a_p (maybe for computing an # L-series via Euler product) return [g(ap,p) for ap,p in zip(v,P)] # Default cause where we want all a_n anlist = [ZZ(0),ZZ(1)] + [None]*(prec-2) for ap,p in zip(v,P): anlist[p] = g(ap,p) # Fill in the prime power a_{p^r} for r >= 2. N = E.conductor() for p in P: prm2 = 1 prm1 = p pr = p*p pn = p**n e = 1 if N%p else 0 while pr < prec: anlist[pr] = anlist[prm1] * anlist[p] if e: anlist[pr] -= pn * anlist[prm2] prm2 = prm1 prm1 = pr pr *= p # fill in a_n with n divisible by at least 2 primes extend_multiplicatively_generic(anlist) if anlist_only: return anlist f = Integer_list_to_polynomial(anlist, 'q') return ZZ[['q']](f, prec=prec)
def render_modlmf_webpage(**args): C = getDBConnection() data = None if 'label' in args: lab = args.get('label') data = C.mod_l_eigenvalues.modlmf.find_one({'label': lab }) if data is None: t = "Mod ℓ modular form search error" bread = [('mod ℓ Modular Forms', url_for(".modlmf_render_webpage"))] flash(Markup("Error: <span style='color:black'>%s</span> is not a valid label for a mod ℓ modular form in the database." % (lab)),"error") return render_template("modlmf-error.html", title=t, properties=[], bread=bread, learnmore=learnmore_list()) info = {} info.update(data) info['friends'] = [] bread=[('Modular Forms', "/ModularForm"),('mod ℓ', url_for(".modlmf_render_webpage")), ('%s' % data['label'], ' ')] credit = modlmf_credit f = C.mod_l_eigenvalues.modlmf.find_one({'characteristic':data['characteristic'], 'deg' : data['deg'], 'level' : data['level'],'weight_grading': data['weight_grading'], 'reducible' : data['reducible'], 'cuspidal_lift': data['cuspidal_lift'], 'dirchar' : data['dirchar'], 'atkinlehner': data['atkinlehner'],'n_coeffs': data['n_coeffs'],'coeffs': data['coeffs'], 'ordinary': data['ordinary'],'min_theta_weight': data['min_theta_weight'], 'theta_cycle' : data['theta_cycle']}) for m in ['characteristic','deg','level','weight_grading', 'n_coeffs', 'min_theta_weight', 'ordinary']: info[m]=int(f[m]) info['atkinlehner']=f['atkinlehner'] info['dirchar']=str(f['dirchar']) info['label']=str(f['label']) if f['reducible']: info['reducible']=f['reducible'] info['cuspidal_lift']=f['cuspidal_lift'] info['cuspidal_lift_weight']=int(f['cuspidal_lift'][0]) info['cuspidal_lift_orbit']=str(f['cuspidal_lift'][1]) if f['cuspidal_lift'][2]=='x': info['cuspidal_hecke_field']=1 else: info['cuspidal_hecke_field']=latex(f['cuspidal_lift'][2]) info['cuspidal_lift_gen']=f['cuspidal_lift'][3] if f['theta_cycle']: info['theta_cycle']=f['theta_cycle'] info['coeffs']=[str(s).replace('x','a').replace('*','') for s in f['coeffs']] if f['deg'] != int(1): try: pol=str(conway_polynomial(f['characteristic'], f['deg'])).replace('x','a').replace('*','') info['field']= pol except: info['field']="" ncoeff=int(round(20/f['deg'])) av_coeffs=min(f['n_coeffs'],100) info['av_coeffs']=int(av_coeffs) if f['coeffs'] != "": coeff=[info['coeffs'][i] for i in range(ncoeff+1)] info['q_exp']=my_latex(print_q_expansion(coeff)) info['q_exp_display'] = url_for(".q_exp_display", label=f['label'], number="") p_range=prime_range(av_coeffs) info['table_list']=[[p_range[i], info['coeffs'][p_range[i]]] for i in range(len(p_range))] info['download_q_exp'] = [ (i, url_for(".render_modlmf_webpage_download", label=info['label'], lang=i)) for i in ['gp', 'magma','sage']] t = "Mod "+str(info['characteristic'])+" Modular Form "+info['label'] info['properties'] = [ ('Label', '%s' %info['label']), ('Field characteristic', '%s' %info['characteristic']), ('Field degree', '%s' %info['deg']), ('Level', '%s' %info['level']), ('Weight grading', '%s' %info['weight_grading'])] return render_template("modlmf-single.html", info=info, credit=credit, title=t, bread=bread, properties2=info['properties'], learnmore=learnmore_list())
display_float, display_complex, round_CBF_to_half_int, polyquo_knowl, display_knowl, factor_base_factorization_latex, integer_options, names_and_urls) from lmfdb.number_fields.web_number_field import nf_display_knowl from lmfdb.number_fields.number_field import field_pretty from lmfdb.galois_groups.transitive_group import small_group_label_display_knowl from lmfdb.sato_tate_groups.main import st_link from web_space import convert_spacelabel_from_conrey, get_bread, cyc_display LABEL_RE = re.compile(r"^[0-9]+\.[0-9]+\.[a-z]+\.[a-z]+$") EMB_LABEL_RE = re.compile(r"^[0-9]+\.[0-9]+\.[a-z]+\.[a-z]+\.[0-9]+\.[0-9]+$") INTEGER_RANGE_RE = re.compile(r"^([0-9]+)-([0-9]+)$") # we may store alpha_p with p <= 3000 primes_for_angles = prime_range(3000) def valid_label(label): return bool(LABEL_RE.match(label)) def valid_emb_label(label): return bool(EMB_LABEL_RE.match(label)) def decode_hecke_orbit(code): level = str(code % 2**24) weight = str((code >> 24) % 2**12) char_orbit_label = cremona_letter_code((code >> 36) % 2**16) hecke_orbit_label = cremona_letter_code(code >> 52) return '.'.join([level, weight, char_orbit_label, hecke_orbit_label]) def encode_hecke_orbit(label):