def fixed_prec(r, digs=3): n = RealField(200)(r) * (10**digs) n = str(n.round()) head = int(n[:-digs]) if head >= 10**4: head = comma(head) return str(head) + '.' + n[-digs:]
def fixed_prec(r, digs=3): n = RealField(200)(r)*(10**digs) n = str(n.round()) head = int(n[:-digs]) if head>=10**4: head = comma(head) return str(head)+'.'+n[-digs:]
def polish_approx_hyperbolic_structure(approx_hyperbolic_structure, bits_prec=53, verbose=False): RF = RealField(bits_prec + 20) twoPi = 2 * RF.pi() edge_parameters = vector(RF, approx_hyperbolic_structure.edge_lengths) epsilon = RF(0.5)**bits_prec if not (approx_hyperbolic_structure.exact_edges and approx_hyperbolic_structure.var_edges): raise Exception("Did not pick exact/var edges") for i in range(100): try: result = HyperbolicStructure( approx_hyperbolic_structure.mcomplex, edge_parameters, approx_hyperbolic_structure.exact_edges, approx_hyperbolic_structure.var_edges) except BadDihedralAngleError as e: raise PolishingFailedWithBadDihedralAngleError("When polishing", e) errs = vector( [result.angle_sums[e] - twoPi for e in result.exact_edges]) max_err = max([abs(err) for err in errs]) if verbose: print("Iteration %d: error = %s" % (i, RealField(53)(max_err))) if max_err < epsilon: return result j = result.full_rank_jacobian_submatrix() try: jinv = j.inverse() except ZeroDivisionError: raise PolishingError("Singular matrix") delta = jinv * errs for e, d in zip(result.var_edges, delta): edge_parameters[e] -= d print("Max error", max_err) print(approx_hyperbolic_structure.full_rank_jacobian_submatrix().SVD() [1].diagonal()) raise PolishingError("Newton method did not produce a result")
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 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 special_value(self,n): r""" Compute L(f,n) Recall that L(f,n+1)=(2pii)^(n+1)*(-1)^(n+1)/Gamma(n+1) * r_n(f) """ RF = RealField(self._prec) CF = ComplexField(self._prec) if n < 0 or n>self._w+1: print "{0} is not a special point for this f!".format(n) return if not self._polynomials: self._get_polynomials() rk = self.get_rk(0,n-1) return CF(0,2*RF.pi())**(n)*(-1)**(n)/RF(n).gamma()*rk
def special_value(self, n): r""" Compute L(f,n) Recall that L(f,n+1)=(2pii)^(n+1)*(-1)^(n+1)/Gamma(n+1) * r_n(f) """ RF = RealField(self._prec) CF = ComplexField(self._prec) if n < 0 or n > self._w + 1: print "{0} is not a special point for this f!".format(n) return if not self._polynomials: self._get_polynomials() rk = self.get_rk(0, n - 1) return CF(0, 2 * RF.pi())**(n) * (-1)**(n) / RF(n).gamma() * rk
def get_euler_factor(L,p): """ takes L list of all ans and p is a prime it returns the euler factor at p # utility function to get an Euler factor, unused """ S = RealField()(len(L)) f = S.log(base=p).floor() E = [] q = 1 for i in range(f): q = q*p E.append(L[q-1]) return list_to_euler_factor(E,f)
def get_euler_factor(L, p): """ takes L list of all ans and p is a prime it returns the euler factor at p # utility function to get an Euler factor, unused """ S = RealField()(len(L)) f = S.log(base=p).floor() E = [] q = 1 for i in range(f): q = q * p E.append(L[q - 1]) return list_to_euler_factor(E, f)
def coefficient_at_coset(self, n): r""" Compute Fourier coefficients of f|A_n """ if hasattr(n, "matrix"): n = self._get_coset_n(n) if not self._base_coeffs: self.coefficients_f() CF = ComplexField(self._prec) if not self._coefficients_at_coset.has_key(n): M = self.truncation_M(n) h, w = self.get_shift_and_width_for_coset(n) zN = CyclotomicField(w).gens()[0] prec1 = self._prec + ceil(log_b(M, 2)) RF = RealField(prec1) coeffs = [] fak = RF(w)**-(RF(self._k) / RF(2)) #print "f=",f,n for i in range(M): al = CF(self.atkin_lehner(n)) c0 = self._base_coeffs_embedding[i] #if hasattr(c0,"complex_embeddings"): # c0 = c0.complex_embedding(prec1) #else: # c0 = CF(c0) qN = zN**((i + 1) * h) #print "qN=",qN,type(qN) an = fak * al * c0 * qN.complex_embedding(prec1) #an = self.atkin_lehner(n)*self._base_coeffs[i]*zN**((i+1)*h) #an = f*an.complex_embedding(prec1) coeffs.append(an) self._coefficients_at_coset[n] = coeffs return self._coefficients_at_coset[n]
def coefficients_f(self): r""" Compute the maximum number of coefficients we need to use (with current precision). """ if not self._base_coeffs: kf = 0.5 * (self._k - 1.0) M0 = self.maxM() prec1 = self._prec + ceil(log_b(M0 * 6, 2)) if hasattr(self._f, "O"): self._base_coeffs = self._f.coefficients() if len(self._base_coeffs) < M0: raise ValueError, "Too few coefficients available!" else: self._base_coeffs = self._f.coefficients(ZZ(M0)) self._base_coeffs_embedding = [] #precn = prec1 if hasattr(self._base_coeffs[0], "complex_embedding"): n = 1 #print "kf=",kf #print "kfprec1=",prec1 for a in self._base_coeffs: ## Use precision high enough that c(n)/n^((k-1)/2) have self._prec correct bits precn = prec1 + kf * ceil(log_b(n, 2)) self._base_coeffs_embedding.append( a.complex_embedding(precn)) n += 1 else: ## Here we have a rational number so we can ue the default number of bits n = 1 for a in self._base_coeffs: precn = prec1 + kf * ceil(log_b(n, 2)) aa = RealField(precn)(a) self._base_coeffs_embedding.append(a) #self._RF(a)) n += 1 return self._base_coeffs
def TwoPointsMinusInfinity(self, P, Q): # Creates a divisor class of P + Q - g*\infty maxlower = self.lower xP, yP = self.Rextraprec(P[0]), self.Rextraprec(P[1]) xQ, yQ = self.Rextraprec(Q[0]), self.Rextraprec(Q[1]) assert (self.f(xP) - yP**2).abs() <= (yP**2).abs() * self.almostzero assert (self.f(xQ) - yQ**2).abs() <= (yQ**2).abs() * self.almostzero WPQ = Matrix(self.Rextraprec, self.nZ, 3 * self.g + 7) # H0(3D0 - g*\infty) Ev = Matrix(self.Rextraprec, 2, 3 * self.g + 7) # basis of H0(3D0 - g*\infty) evaluated at P and Q Exps=[] for n in range( 2 * self.g + 4): Exps.append((n,0)) if n > self.g: Exps.append(( n - self.g - 1, 1)) for j in range( 3 * self.g + 7): u, v = Exps[j] for i in range( self.nZ ): x, y = self.Z[i] WPQ[ i, j ] = x**u * y**v Ev[0,j] = xP**u * yP**v Ev[1,j] = xQ**u * yQ**v K, upper, lower = Kernel(Ev, 2) assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) maxlower = max(maxlower, lower); #Returns H0(3*D0 - P - Q - g infty) # note that [P + Q + g infty - D0] ~ P + Q - infty return (WPQ * K).change_ring(self.R), maxlower
def signature_function_of_integral_matrix(V, prec=53): """ Computes the signature function sigma of V via numerical methods. Returns two lists, the first representing a partition of [0, 1]: x_0 = 0 < x_1 < x_2 < ... < x_n = 1 and the second list consisting of the values [v_0, ... , v_(n-1)] of sigma on the interval (x_i, x_(i+1)). Currently, the value of sigma *at* x_i is not computed. """ poly = alexander_poly_from_seifert(V) RR = RealField(prec) CC = ComplexField(prec) pi = RR.pi() I = CC.gen() partition = [RR(0)] + [a for a, e in roots_on_unit_circle(poly, prec) ] + [RR(1)] n = len(partition) - 1 values = [] for i in range(n): omega = exp((2 * pi * I) * (partition[i] + partition[i + 1]) / 2) A = (1 - omega) * V + (1 - omega.conjugate()) * V.transpose() values.append(signature_via_numpy(A)) assert list(reversed(values)) == values return partition, values
def PointMinusInfinity(self, P, sign = 0): # Creates a divisor class of P- \inty_{(-1)**sign} maxlower = self.lower assert self.f.degree() == 2*self.g + 2; sqrtan = (-1)**sign * self.Rextraprec( sqrt( self.Rdoubleextraprec(self.an)) ); xP, yP = self.Rextraprec(P[0]),self.Rextraprec(P[1]) assert (self.f(xP) - yP**2).abs() <= (yP**2).abs() * self.almostzero if xP != 0 and self.a0 != 0: x0 = self.Rextraprec(0); else: x0 = xP while x0 == xP: x0 = self.Rextraprec(ZZ.random_element()) y0 = self.Rextraprec( sqrt( self.Rdoubleextraprec( self.f( x0 )))) # P0 = (x0, y0) WP1 = Matrix(self.Rextraprec, self.nZ, 3 * self.g + 6) # H0(3D0 - P0 - g \infty) = H0(3D0 - P0 - g(\infty_{+} + \infty_{-})) EvP = Matrix(self.Rextraprec, 1, 3 * self.g + 6) # the functions of H0(3D0-P0-g \infty) at P B = Matrix(self.Rextraprec, self.nZ, 3 * self.g + 5) # H0(3D0 - \infty_{sign} - P0 - g\infty) # adds the functions x - x0, (x - x0)**1, ..., (x - x0)**(2g+2) to it for j in xrange(2 * self.g + 2 ): for i, (x, y) in enumerate( self.Z ): WP1[ i, j] = B[ i, j] = (x - x0) ** (j + 1) EvP[ 0, j] = (xP - x0) ** (j + 1) # adds y - y0 for i, (x, y) in enumerate( self.Z ): WP1[ i, 2 * self.g + 2 ] = B[ i, 2 * self.g + 2] = y - y0 EvP[ 0, 2 * self.g + 2] = yP - y0 # adds (x - x0) * y ... (x-x0)**(g+1)*y for j in range(1, self.g + 2): for i, (x,y) in enumerate( self.Z ): WP1[ i, 2 * self.g + 2 + j ] = B[ i, 2 * self.g + 2 + j] = (x-x0)**j * y EvP[ 0, 2 * self.g + 2 + j] = (xP - x0)**j * yP # adds (x - x0)**(2g + 3) and y * (x - x0)**(g + 2) for i,(x,y) in enumerate(self.Z): WP1[ i, 3 * self.g + 4 ] = (x - x0)**( 2 * self.g + 3) WP1[ i, 3 * self.g + 5 ] = y * (x - x0)**(self.g + 2) B[ i, 3 * self.g + 4 ] = (x - x0)**( self.g + 2) * ( y - sqrtan * x**(self.g + 1) ) EvP[ 0, 3 * self.g + 4] = (xP - x0) ** ( 2 * self.g + 3) EvP[ 0, 3 * self.g + 5] = yP * (xP - x0)**(self.g + 2) # A = functions in H0(3D0-P0-g \infty) that vanish at P # = H**0(3D0 - P0 - P -g \infty) K, upper, lower = Kernel(EvP, EvP.ncols() - (3 * self.g + 5)) assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) maxlower = max(maxlower, lower); A = WP1 * K # A - B = P0 + P + g \infty - (\infty_{+} + P0 + g\infty) = P - \inty_{+} res, lower = self.Sub(A,B) maxlower = max(maxlower, lower); return res.change_ring(self.R), maxlower;
def EC_nf_plot(E, base_field_gen_name): K = E.base_field() n1 = K.signature()[0] if n1 == 0: return plot([]) prec = 53 maxprec = 10 ** 6 while prec < maxprec: # Try to base change to R. May fail if resulting curve is almost singular, so increase precision. try: SR = K.embeddings(RealField(prec)) X = [E.base_extend(s) for s in SR] break except ArithmeticError: prec *= 2 if prec >= maxprec: return text("Unable to plot", (1, 1), fontsize="xx-large") X = [e.plot() for e in X] xmin = min([x.xmin() for x in X]) xmax = max([x.xmax() for x in X]) ymin = min([x.ymin() for x in X]) ymax = max([x.ymax() for x in X]) cols = ["blue", "red", "green", "orange", "brown"] # Preset colours, because rainbow tends to return too pale ones if n1 > len(cols): cols = rainbow(n1) return sum([EC_R_plot([SR[i](a) for a in E.ainvs()], xmin, xmax, ymin, ymax, cols[i], "$" + base_field_gen_name + " \mapsto$ " + str(SR[i].im_gens()[0].n(20))) for i in range(n1)])
def real_parabolic_reps_from_ptolemy(M, pari_prec=15): R = PolynomialRing(QQ, 'x') RR = RealField(1000) ans = [] obs_classes = M.ptolemy_obstruction_classes() for obs in obs_classes: V = M.ptolemy_variety(N=2, obstruction_class=obs) #for sol in V.retrieve_solutions(): for sol in V.compute_solutions(engine='magma'): if sol.dimension > 0: print("Positive dimensional component!") continue prec = snappy.pari.set_real_precision(pari_prec) is_geometric = sol.is_geometric() snappy.pari.set_real_precision(prec) cross_ratios = sol.cross_ratios() shapes = [ R(cross_ratios['z_0000_%d' % i].lift()) for i in range(M.num_tetrahedra()) ] s = shapes[0] p = R(sol.number_field()) if p == 0: # Field is Q assert False # print p, '\n' for r in p.roots(RR, False): rho = pe.real_reps.PSL2RRepOf3ManifoldGroup( M, target_meridian_holonomy=RR(1), rough_shapes=[cr(r) for cr in shapes]) rho.is_galois_conj_of_geom = is_geometric ans.append(rho) return ans
def central_char_function(self): dim = self.dimension() dfactor = (-1)**dim # doubling insures integers below # we could test for when we need it, but then we carry the "if" # throughout charf = 2*self.character_field() localfactors = self.local_factors_table() bad = [0 if dim+1>len(z) else 1 for z in localfactors] localfactors = [self.from_conjugacy_class_index_to_polynomial(j+1) for j in range(len(localfactors))] localfactors = [z.leading_coefficient()*dfactor for z in localfactors] # Now take logs to figure out what power these are mypi = RealField(100)(pi) localfactors = [charf*log(z)/(2*I*mypi) for z in localfactors] localfactorsa = [z.real().round() % charf for z in localfactors] # Test to see if we are ok? localfactorsa = [localfactorsa[j] if bad[j]>0 else -1 for j in range(len(localfactorsa))] def myfunc(inp, n): fn = list(factor(inp)) pvals = [[localfactorsa[self.any_prime_to_cc_index(z[0])-1], z[1]] for z in fn] # -1 is the marker that the prime divides the conductor for j in range(len(pvals)): if pvals[j][0] < 0: return -1 pvals = sum([z[0]*z[1] for z in pvals]) return (pvals % n) return myfunc
def display_float(x, digits, method="truncate", extra_truncation_digits=3, try_halfinteger=True): if abs(x) < 10.**(-digits - extra_truncation_digits): return "0" # if small, try to display it as an exact or half integer if try_halfinteger and abs(x) < 10.**digits: if is_exact(x): s = str(x) if len(s) < digits + 2: # 2 = '/' + '-' return str(x) k = round_to_half_int(x) if k == x: k2 = None try: k2 = ZZ(2 * x) except TypeError: pass # the second statment checks for overflow if k2 == 2 * x and (2 * x + 1) - k2 == 1: if k2 % 2 == 0: s = '%s' % (k2 / 2) else: s = '%s' % (float(k2) / 2) return s if method == 'truncate': rnd = 'RNDZ' else: rnd = 'RNDN' no_sci = 'e' not in "%.{}g".format(digits) % float(x) try: s = RealField(max(53, 4 * digits), rnd=rnd)(x).str(digits=digits, no_sci=no_sci) except TypeError: # older versions of Sage don't support the digits keyword s = RealField(max(53, 4 * digits), rnd=rnd)(x).str(no_sci=no_sci) point = s.find('.') if point != -1: if point < digits: s = s[:digits + 1] else: s = s[:point] return s
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 mpmath_matrix_to_sage(A): entries = list(A) if all(isinstance(e, mp.mpf) for e in entries): F = RealField(mp.prec) entries = [F(e) for e in entries] else: F = ComplexField(mp.prec) entries = [F(e.real, e.imag) for e in entries] return matrix(F, A.rows, A.cols, entries)
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 real_root_arguments(p, prec=212): """ Note: if p(x) = g(x + 1/x) then p'(1) = p'(-1) = 0 by the chain rule; in particular, 1 and -1 are *never* simple roots of p(x). """ assert p(1) != 0 and p(-1) != 0 g = compact_form(p) RR = RealField(prec) roots = sorted([(arccos(x/2), e) for x, e in g.roots(RR) if abs(x) <= 2]) return roots
def display_float(x, digits, method = "truncate", extra_truncation_digits=3, try_halfinteger=True): if abs(x) < 10.**(- digits - extra_truncation_digits): return "0" # if small, try to display it as an exact or half integer if try_halfinteger and abs(x) < 10.**digits: if is_exact(x): s = str(x) if len(s) < digits + 2: # 2 = '/' + '-' return str(x) k = round_to_half_int(x) if k == x : k2 = None try: k2 = ZZ(2*x) except TypeError: pass # the second statment checks for overflow if k2 == 2*x and (2*x + 1) - k2 == 1: if k2 % 2 == 0: s = '%s' % (k2/2) else: s = '%s' % (float(k2)/2) return s if method == 'truncate': rnd = 'RNDZ' else: rnd = 'RNDN' no_sci = 'e' not in "%.{}g".format(digits) % float(x) try: s = RealField(max(53,4*digits), rnd=rnd)(x).str(digits=digits, no_sci=no_sci) except TypeError: # older versions of Sage don't support the digits keyword s = RealField(max(53,4*digits), rnd=rnd)(x).str(no_sci=no_sci) point = s.find('.') if point != -1: if point < digits: s = s[:digits+1] else: s = s[:point] return s
def __init__(self, real, imag=None): def find_prec(s): if isinstance(s, string_types): # strip negatives and exponent s = s.replace("-","") if "e" in s: s = s[:s.find("e")] return ceil(len(s) * 3.322) else: try: return s.parent().precision() except Exception: return 53 if imag is None: # Process strings if isinstance(real, string_types): M = CC_RE.match(real) if M is None: raise ValueError("'%s' not a valid complex number" % real) a, b = M.groups() # handle missing coefficient of i if b == '-': b = '-1' elif b in ['+', '']: b = '1' # The following is a good guess for the bit-precision, # but we use LmfdbRealLiterals to ensure that our number # prints the same as we got it. prec = max(find_prec(a), find_prec(b), 53) parent = ComplexField(prec) R = parent._real_field() self._real_literal = LmfdbRealLiteral(R, a) self._imag_literal = LmfdbRealLiteral(R, b) elif isinstance(real, LmfdbRealLiteral): parent = ComplexField(real.parent().precision()) self._real_literal = real self._imag_literal = parent._real_field()(0) elif isintance(real, ComplexLiteral): parent = real.parent() self._real_literal = real._real_literal self._imag_literal = real._imag_literal else: raise TypeError("Object '%s' of type %s not valid input" % (real, type(real))) else: prec = max(find_prec(real), find_prec(imag), 53) R = RealField(prec) parent = ComplexField(prec) for x, xname in [(real, '_real_literal'), (imag, '_imag_literal')]: if isinstance(x, string_types): x = LmfdbRealLiteral(R, x) if not isinstance(x, LmfdbRealLiteral): raise TypeError("Object '%s' of type %s not valid input" % (x, type(x))) setattr(self, xname, x) ComplexNumber.__init__(self, self.real(), self.imag())
def preserves_hermitian_form(SL2C_matrices): """ >>> CC = ComplexField(100) >>> A = matrix(CC, [[1, 1], [1, 2]]); >>> B = matrix(CC, [[0, 1], [-1, 0]]) >>> C = matrix(CC, [[CC('I'),0], [0, -CC('I')]]) >>> ans, sig, form = preserves_hermitian_form([A, B]) >>> ans True >>> sig 'indefinite' >>> form.change_ring(ComplexField(10)) [ 0.00 -1.0*I] [ 1.0*I 0.00] >>> preserves_hermitian_form([A, B, C]) (False, None, None) >>> ans, sig, form = preserves_hermitian_form([B, C]) >>> sig 'definite' """ M = block_matrix(len(SL2C_matrices), 1, [ left_mult_by_adjoint(A) - right_mult_by_inverse(A) for A in SL2C_matrices ]) CC = M.base_ring() mp.prec = CC.prec() RR = RealField(CC.prec()) epsilon = RR(2)**(-int(0.8 * mp.prec)) U, S, V = mp.svd(sage_matrix_to_mpmath(M)) S = list(mp.chop(S, epsilon)) if mp.zero not in S: return False, None, None elif S.count(mp.zero) > 1: for i, A in enumerate(SL2C_matrices): for B in SL2C_matrices[i + 1:]: assert (A * B - B * A).norm() < epsilon sig = 'indefinite' if any(abs(A.trace()) > 2 for A in SL2C_matrices) else 'both' return True, sig, None else: in_kernel = list(mp.chop(V.H.column(S.index(mp.zero)))) J = mp.matrix([in_kernel[:2], in_kernel[2:]]) iJ = mp.mpc(imag=1) * J J1, J2 = J + J.H, iJ + iJ.H J = J1 if mp.norm(J1) >= mp.norm(J2) else J2 J = (1 / mp.sqrt(abs(mp.det(J)))) * J J = mpmath_matrix_to_sage(J) assert all((A.conjugate_transpose() * J * A - J).norm() < epsilon for A in SL2C_matrices) sig = 'definite' if J.det() > 0 else 'indefinite' return True, sig, J
def compute_p_from_w_and_parity(w, parity): """ Compute p such that w - p * pi * i should have imaginary part between -pi and pi and p has the same parity as the given value for parity (the given value is supposed to be 0 or 1). Note that this computation is not verified. """ RF = RealField(w.parent().precision()) real_part = (w.imag().center() / RF(pi) - parity) / 2 return 2 * Integer(real_part.round()) + parity
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 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 sage(self): """ Return as an element of the approriate RealField or ComplexField """ if not _within_sage: raise ImportError("Not within SAGE.") if self.gen.type() == 't_REAL': return RealField(self._precision)(self.gen) elif self.gen.type() == 't_COMPLEX': return ComplexField(self._precision)(self.gen) else: return self.gen.sage()
def evf(cls, m, max_klen, prec=53): """ Estimate norm of target vector. :param m: number of samples :param klen: length of key to recover :param prec: precision to use """ w = 2 ** (max_klen - 1) RR = RealField(prec) w = RR(w) return RR(sqrt(m * (w ** 2 / 3 + 1 / RR(6)) + w ** 2))
def __init__(self, G, k=0, prec=53, multiplier=None, verbose=0, holomorphic=True): r""" Setup the associated space. """ if isinstance(G, (int, Integer)): self._N = G self._group = MySubgroup(Gamma0(G)) else: self._group = G self._N = G.level() self._k = k self._verbose = verbose self._holomorphic = holomorphic self._prec = prec self._RF = RealField(prec) self._CF = ComplexField(prec)
def lifted_slope(M, target_meridian_holonomy_arg, shapes): RR = RealField() target = RR(target_meridian_holonomy_arg) rho = PSL2CRepOf3ManifoldGroup(M, target, rough_shapes=shapes, precision=1000) assert rho.polished_holonomy().check_representation() < 1.0e-100 rho_real = PSL2RRepOf3ManifoldGroup(rho) meridian, longitude = rho.polished_holonomy().peripheral_curves()[0] rho_tilde = rho_real.lift_on_cusped_manifold() M, L = rho_tilde.peripheral_translations() return -L / M
def volf(cls, m, p, klen_list, prec=53): """ Lattice volume. :param m: number of samples :param p: ECDSA modulus :param klen_list: list of lengths of key to recover :param prec: precision to use """ w = 2 ** (max(klen_list) - 1) RR = RealField(prec) f_list = [Integer(w / (2 ** (klen - 1))) for klen in klen_list] return RR(exp(log(p) * (m - 1) + sum(map(log, f_list)) + log(w)))
def compute_kernel(args): if args.seed is not None: set_random_seed(args.seed) FPLLL.set_random_seed(args.seed) ecdsa = ECDSA(nbits=args.nlen) lines, k_list, _ = ecdsa.sample(m=args.m, klen_list=args.klen_list, seed=args.seed, errors=args.e) w_list = [2 ** (klen - 1) for klen in args.klen_list] f_list = [Integer(max(w_list) / wi) for wi in w_list] targetvector = vector([(k - w) * f for k, w, f in zip(k_list, w_list, f_list)] + [max(w_list)]) try: solver = ECDSASolver(ecdsa, lines, m=args.m, d=args.d, threads=args.threads) except KeyError: raise ValueError("Algorithm {alg} unknown".format(alg=args.alg)) expected_length = solver.evf(args.m, max(args.klen_list), prec=args.nlen // 2) gh = solver.ghf(args.m, ecdsa.n, args.klen_list, prec=args.nlen // 2) params = args.params if args.params else {} key, res = solver(solver=args.algorithm, flavor=args.flavor, **params) RR = RealField(args.nlen // 2) logging.info( ( "try: {i:3d}, tag: 0x{tag:016x}, success: {success:1d}, " "|v|: 2^{v:.2f}, |b[0]|: 2^{b0:.2f}, " "|v|/|b[0]|: {b0r:.3f}, " "E|v|/|b[0]|: {eb0r:.3f}, " "|v|/E|b[0]|: {b0er:.3f}, " "cpu: {cpu:10.1f}s, " "wall: {wall:10.1f}s, " "work: {total:d}" ).format( i=args.i, tag=args.tag, success=int(res.success), v=float(log(RR(targetvector.norm()), 2)), b0=float(log(RR(res.b0), 2)), b0r=float(RR(targetvector.norm()) / RR(res.b0)), eb0r=float(RR(expected_length) / RR(res.b0)), b0er=float(RR(targetvector.norm()) / gh), cpu=float(res.cputime), wall=float(res.walltime), total=res.ntests, ) ) return key, res, float(targetvector.norm())
def parse_file(filename, prec=53): from sage.all import RealField, ComplexField RR = RealField(prec) CC = ComplexField(prec) data = open(filename).read() open('polys.txt', 'w').write(data) data = data.split('THE SOLUTIONS')[-1] data = re.subn('[*]{3,}', '', data)[0] ans = [] solutions = re.findall('(solution \d+ : \s* start residual .*?) ==', data, re.DOTALL) for sol in solutions: kind = sol.split('=')[-1].strip() if kind == 'no solution': continue mult = int(re.search('^m : (\d+)', sol, re.MULTILINE).group(1)) err = float(re.search('== err :\s+(.*?)\s+= ', sol).group(1)) coors = re.findall('^ (.*) :\s+(\S*)\s+(\S*)', sol, re.MULTILINE) if kind.startswith('real'): coors = { restore_forbidden(var): RR(real) for var, real, imag in coors } ans.append({ 'kind': 'real', 'mult': mult, 'err': err, 'coors': coors }) elif kind.startswith('complex'): coors = { restore_forbidden(var): CC(RR(real), RR(imag)) for var, real, imag in coors } ans.append({ 'kind': 'complex', 'mult': mult, 'err': err, 'coors': coors }) num_real = int( re.search('Number of real solutions\s+:\s(.*).', data).group(1)) num_complex = int( re.search('Number of complex solutions\s+:\s(.*).', data).group(1)) kinds = [sol['kind'] for sol in ans] assert kinds.count('real') == num_real assert kinds.count('complex') == num_complex return ans
def mvf(cls, m, max_klen, prec=53): """ Maximal norm of target vector. :param m: number of samples :param max_klen: length of key to recover :param prec: precision to use """ w = 2 ** (max_klen - 1) RR = RealField(prec) w = RR(w) d = m + 1 return RR(sqrt(d) * w)
def ghf(cls, m, p, klen_list, prec=53): """ Estimate norm of shortest vector according to Gaussian Heuristic. :param m: number of samples :param p: ECDSA modulus :param klen_list: list of lengths of key to recover :param prec: precision to use """ # NOTE: The Gaussian Heuristic does not hold in small dimensions w = 2 ** (max(klen_list) - 1) RR = RealField(prec) w = RR(w) f_list = [Integer(w / (2 ** (klen - 1))) for klen in klen_list] d = m + 1 log_vol = log(p) * (m - 1) + sum(map(log, f_list)) + log(w) lgh = log_gamma(1 + d / 2.0) * (1.0 / d) - log(sqrt(pi)) + log_vol * (1.0 / d) return RR(exp(lgh))
class PeriodPolynomial(SageObject): r""" Class for (numerical approximations to) period polynomials of modular forms """ def __init__(self,f,prec=53,verbose=0,data={}): r""" Initialize the period polynomial of f. INPUT: - `f` -- Newform - `` EXAMPLES: # First elliptic curve sage: f=Newforms(11,2)[0] sage: pp=PeriodPolynomial(f,prec=103) sage: L=f.cuspform_lseries() sage: pp.petersson_norm() 0.00390834565612459898524738548154 - 5.53300833748482053164300189100e-35*I sage: pp.special_value(1) 0.253841860855910684337758923267 sage: L(1) 0.253841860855911 # We can also study rationality of the coefficients of the sage: pp.test_rationality() P(f 0)^+/omega_+=1.00000000000000000000000000000 P(f 0)^-/omega_-=0 P(f 1)^+/omega_+=-1.00000000000000000000000000000 P(f 1)^-/omega_-=0 P(f 2)^+/omega_+=0 P(f 2)^-/omega_-=1.27412157006452456511355616309e-31 + 1.01489446868406102099789763444e-28*I P(f 3)^+/omega_+=-5.00000000000000000000000000133 P(f 3)^-/omega_-=-1.16793587723237638257725820700e-60 + 8.24993716616779655911027615609e-29*I P(f 4)^+/omega_+=-2.50000000000000000000000000073 P(f 4)^-/omega_-=-3.39765752017206550696948310188e-32 + 2.39999999999999999999999999940*I P(f 5)^+/omega_+=2.50000000000000000000000000073 P(f 5)^-/omega_-=-3.39765752017206550696948310188e-32 + 2.39999999999999999999999999940*I P(f 6)^+/omega_+=5.00000000000000000000000000133 P(f 6)^-/omega_-=1.16793587723237638257725820700e-60 - 8.24993716616779655911027615609e-29*I P(f 7)^+/omega_+=5.00000000000000000000000000133 P(f 7)^-/omega_-=-1.16793587723237638257725820700e-60 + 8.24993716616779655911027615609e-29*I P(f 8)^+/omega_+=2.50000000000000000000000000073 P(f 8)^-/omega_-=3.39765752017206550696948310188e-32 - 2.39999999999999999999999999940*I P(f 9)^+/omega_+=-2.50000000000000000000000000073 P(f 9)^-/omega_-=3.39765752017206550696948310188e-32 - 2.39999999999999999999999999940*I P(f10)^+/omega_+=-5.00000000000000000000000000133 P(f10)^-/omega_-=1.16793587723237638257725820700e-60 - 8.24993716616779655911027615609e-29*I P(f11)^+/omega_+=0 P(f11)^-/omega_-=-1.27412157006452456511355616309e-31 - 1.01489446868406102099789763444e-28*I o1= 0.0404001869188632792144191985239*I o2= -1.36955018267536771772869542629e-33 - 0.0967407815209822856536332369020*I sage: f=Newforms(5,8,names='a')[0];f q - 14*q^2 - 48*q^3 + 68*q^4 + 125*q^5 + O(q^6) sage: L=f.cuspform_lseries() sage: pp=PeriodPolynomial(f,prec=103) sage: pp.special_value(4) -3.34183629241748201816194829811e-29 + 8.45531852674217908762910051272e-60*I sage: pp.special_value(3) -0.729970592499451187790964533256 + 2.56020879251697431818575640846e-31*I sage: L(3) -0.729970592499451 sage: L(4) 0.000000000000000 """ self._f = f self._level = None if data<>{}: self.init_from_dict(data) if self._level==None: self._level = f.level() self._k = f.weight() self._w = self._k - 2 self._verbose = verbose self._polynomials = {} self._prec = prec self._rks = {} self._coset_reps={} self._dim = Gamma0(self._level).index() self._coefficients_at_coset = {} self._base_coeffs=[] self._base_coeffs_embedding=[] self._M = {} self._M0 = 0 self._width={} self._shift={} self._atkin_lehner={} self._integrals={} self._pplus = {} self._pminus={} self._peterson_norm=0 self._canonical_periods=[] # Check assert is_squarefree(self._level) ## Some numerical definitions self._RF = RealField(prec) self._eps = self._RF(2)**-self._RF(prec) self._pi = self._RF.pi() def __repr__(self): s="Period Polynomial associated to the weight {0} and level {1} MF {2}".format(self._k,self._level,self._f) return s def __reduce__(self): return (PeriodPolynomial,(self._f,self._prec,self._verbose,self.__dict__)) ## If the dict is non-empty we initialize from it def init_from_dict(self,data={}): self._level = data.get("_level") self._k = data.get("_k",None) self._w = data.get("_w") self._verbose = data.get("_verbose") self._polynomials = data.get("_polynomials") self._prec = data.get("_prec") self._rks = data.get("_rks") self._coset_reps=data.get("_coset_reps") self._dim = data.get("_dim") self._coefficients_at_coset =data.get("_coefficients_at_coset") self._base_coeffs=data.get("_base_coeffs") self._base_coeffs_embedding=data.get("_base_coeffs_embedding") self._M = data.get("_M") self._M0 = data.get("_M0") self._width=data.get("_width") self._shift=data.get("_shift") self._atkin_lehner=data.get("_atkin_lehner") self._integrals=data.get("_integrals") self._pplus =data.get("_pplus") self._pminus=data.get("_pminus") self._peterson_norm=data.get("_peterson_norm") self._canonical_periods=data.get("_canonical_periods") def level(self): return self._level def weight(self): return self._k def function(self): return self._f def polynomial(self,n): if not self._polynomials: self._get_polynomials() if hasattr(n,"matrix"): if n in SL2Z: n = self._get_coset_n(n) else: raise ValueError,"{0} not in SL(2,Z)".format(n) return self._polynomials.get(n,None) def polynomials(self): r""" Return a list of the polynomials P(f|A_n)(X), 0<=n<dim """ if not self._polynomials: self._get_polynomials() return self._polynomials def special_value(self,n): r""" Compute L(f,n) Recall that L(f,n+1)=(2pii)^(n+1)*(-1)^(n+1)/Gamma(n+1) * r_n(f) """ RF = RealField(self._prec) CF = ComplexField(self._prec) if n < 0 or n>self._w+1: print "{0} is not a special point for this f!".format(n) return if not self._polynomials: self._get_polynomials() rk = self.get_rk(0,n-1) return CF(0,2*RF.pi())**(n)*(-1)**(n)/RF(n).gamma()*rk #print "Warning: r_{0}(f) not computed!".format(n) def polynomial_plus(self,n): if not self._pplus.has_key(n): E = Matrix(ZZ,2,2,[-1,0,0,1]) p1 = self.polynomial(n) p2 = self.slash_action(n,E) self._pplus[n]=(p1+p2)/2 self._pminus[n]=(p1-p2)/2 return self._pplus[n] def polynomial_minus(self,n): if not self._pminus.has_key(n): E = Matrix(ZZ,2,2,[-1,0,0,1]) p1 = self.polynomial(n) p2 = self.slash_action(n,E) self._pplus[n]=(p1+p2)/2 self._pminus[n]=(p1-p2)/2 return self._pminus[n] def petersson_norm(self,type=1): r""" Compute the Petersson norm of f. ALGORITHM: Uses (f,f) = < rho_{f}^{+} | T - T^-1 , rho_f^{-}> for k even and (f,f) = < rho_{f}^{+} | T - T^-1 , rho_f^{+}> for k odd. See e.g. Thm 3.3. in Pasol - Popa "Modular forms and period polynomials" """ if self._peterson_norm<>0: return self._peterson_norm T=SL2Z([1,1,0,1]) Ti=SL2Z([1,-1,0,1]) norm = 0 for n in range(self._dim): if type==1: p1 = self.slash_action(n,T,sym='plus') p2 = self.slash_action(n,Ti,sym='plus') else: p1 = self.slash_action(n,T,sym='minus') p2 = self.slash_action(n,Ti,sym='minus') pL = p1 - p2 #print "Pl=",pL if self.function().weight() % 2 == 1: if type==1: pR = self.polynomial_plus(n) else: pR = self.polynomial_minus(n) else: if type==1: pR = self.polynomial_minus(n) else: pR = self.polynomial_plus(n) #print "PR=",pR t = self.pair_two_pols(pL,pR) #print "t=",t norm+=t CF=ComplexField(self._prec) c2 = CF(3)*CF(0,2)**(self._k-1) self._peterson_norm = -norm/c2 return self._peterson_norm def omega_plus_minus(self): r""" Compute two periods $\omega_+$ and $\omega_{-}$ where we take $\omega_{+}$ to be the highest (non-vanishing) coefficient of $\rho(f)$ (corresponding to the trivial coset) and $\omega_{-}=||f||/\omega_{+}$. OUTPUT: - '\omega_{+},\omega_{-}' """ if self._canonical_periods<>[]: return self._canonical_periods norm = self.petersson_norm() o1 = self.get_rk(0,0) o2 = norm/o1 self._o1 = o1 self._o2 = o2 self._canonical_periods = o1,o2 return o1,o2 def pair_two_pols(self,p1,p2): res = 0 cp1 = p1.coefficients(sparse=False) cp2 = p2.coefficients(sparse=False) for n in range(self._w+1): if n < len(cp1): c1 = cp1[n] else: c1 = 0 k = self._w -n if k < len(cp2): c2 = cp2[k] else: c2 = 0 term = c1*conjugate(c2)*(-1)**(self._w-n)/binomial(self._w,n) res = res + term return res/self._dim def _get_polynomials(self,prec=None): r""" Compute all P(f|A_n)(X), 0<=n<dim """ if prec==None: prec = self._prec for n in range(self._dim): for k in range(self._w+1): self.get_rk(n,k) self._polynomials[n]=self._get_polynomial(n) return self._polynomials def _get_polynomial(self,n): r""" Compute P(f|A_n)(X) """ if self._polynomials.has_key(n): return self._polynomials[n] CF = ComplexField(self._prec) X=CF['X'].gens()[0] k = self._k pols = {} ## For each component we get a polynomial p = X.parent().zero() for l in range(self._w+1): rk = self.get_rk(n,self._w-l) if self._verbose>0: print "rk=",rk fak = binomial(self._w,l)*(-1)**l p+=CF(fak)*CF(rk)*X**l self._polynomials[n]=p return p # self._polynomials = #get_period_pol_from_rks(self._f,self._rks,prec=prec,verbose=self._verbose) def coset_rep(self,n): r""" Return coset rep nr. n """ if not self._coset_reps: self._set_coset_reps() return self._coset_reps[n] def _set_coset_reps(self): if is_prime(self._level): self._coset_reps[0] = SL2Z([1,0,0,1]) for n in range(self._level): self._coset_reps[n+1] = SL2Z([0,-1,1,n]) else: G = Gamma0(self._level) n = 0 for A in G.coset_reps(): self._coset_reps[n] = A n+=1 def _get_coset_n(self,A): r""" Find n s.t. A in Gamma_0(N)A_n """ G = Gamma0(self._level) if A in G: return 0 ## Always use 0 for the trivial coset else: n=0 for n in range(self._dim): An = self.coset_rep(n) if A*An**-1 in G: return n n+=1 raise ArithmeticError,"Can not find coset of A={0}".format(A) def _get_shifted_coset_m(self,n,A): r""" Get the index m s.t. A_n*A**-1 is in Gamma0(N)A_m """ An = self.coset_rep(n) if A.det()==1: m = self._get_coset_n(An*A**-1) elif A.det()==-1 and A[0,1]==0 and A[1,0]==0: AE = SL2Z([An[0,0],-An[0,1],-An[1,0],An[1,1]]) m = self._get_coset_n(AE) else: raise ValueError,"Call with SL2Z element or [-1,0,1,0]. Got:{0}".format(E) return m def slash_action(self,n,gamma,sym='none'): r""" Act of P^{+/-}(f|A_n) with an element of SL2Z """ # First shift the coset m = self._get_shifted_coset_m(n,gamma) #print "m=",m if sym=='plus': P0 = self.polynomial_plus(m) elif sym=='minus': P0 = self.polynomial_minus(m) else: P0 = self.polynomial(m) if P0==None: return X = P0.parent().gens()[0] coeffs = P0.coefficients(sparse=False) p = P0.parent().zero() if hasattr(gamma,"matrix"): a,b,c,d=gamma else: a,b,c,d=gamma.list() denom = (c*X+d) numer = (a*X+b) w = self._w for k in P0.exponents(): ak = coeffs[k] p+=ak*numer**k*denom**(w-k) return p def slash_action_vector(self,gamma,sym=0): res = {} for n in range(self._dim): res[n] = self.polynomial_slash_action(n,gamma,sym=sym) def __mul__(self,l): r""" Acts on all polynomials of self by l """ res = {} for n in range(self._dim): if l in SL2Z: res[n]=self.slash_action(n,l) elif isinstance(l,list): res[n] = self.action_by_lin_comb(n,l) else: raise NotImplementedError return res def action_by_lin_comb(self,n,l,sym=0): r""" Act on polynomial n of self by the element of the group ring c_1*A_1+...+c_k*A_k INPUT: -`l` -- list of pairs (c,A) with c complex and A in SL2Z """ p = self.polynomial(n).parent().zero() try: for c,A in l: p+=c*self.slash_action(n,A,sym=sym) except: raise ValueError,"Need a list of tuples! Got:{0}".format(l) return p def maxM(self): r""" Compute the maximum truncation point. """ if self._M0 == 0: self.get_shifts_and_widths() return self._M0 def set_M(self,Mset): r""" Sets the truncation point to at most a fixed integer Mset """ M0 = self.maxM() for n in range(self._dim): m = self._M[n] if m > Mset: self._M[n] = Mset if M0>Mset: self._M0 = Mset if verbose>0: print "Warning: the precision of results might be lower than expected!" def truncation_M(self,n): r""" Compute the truncation point at coset nr. n. """ if not self._M.has_key(n): h,w = self.get_shift_and_width_for_coset(n) #self._M[n]=self._get_truncation(w,self._k,self._prec) self._M[n]=get_truncation(self._k,w,self._prec) return self._M[n] def coefficients_f(self): r""" Compute the maximum number of coefficients we need to use (with current precision). """ if not self._base_coeffs: kf = 0.5*(self._k-1.0) M0 = self.maxM() prec1 = self._prec + ceil(log_b(M0*6,2)) if hasattr(self._f,"O"): self._base_coeffs = self._f.coefficients() if len(self._base_coeffs)<M0: raise ValueError,"Too few coefficients available!" else: self._base_coeffs = self._f.coefficients(ZZ(M0)) self._base_coeffs_embedding=[] #precn = prec1 if hasattr(self._base_coeffs[0],"complex_embedding"): n=1 #print "kf=",kf #print "kfprec1=",prec1 for a in self._base_coeffs: ## Use precision high enough that c(n)/n^((k-1)/2) have self._prec correct bits precn = prec1 + kf*ceil(log_b(n,2)) self._base_coeffs_embedding.append(a.complex_embedding(precn)) n+=1 else: ## Here we have a rational number so we can ue the default number of bits n=1 for a in self._base_coeffs: precn = prec1 + kf*ceil(log_b(n,2)) aa = RealField(precn)(a) self._base_coeffs_embedding.append(a) #self._RF(a)) n+=1 return self._base_coeffs def coefficient_at_coset(self,n): r""" Compute Fourier coefficients of f|A_n """ if hasattr(n,"matrix"): n = self._get_coset_n(n) if not self._base_coeffs: self.coefficients_f() CF = ComplexField(self._prec) if not self._coefficients_at_coset.has_key(n): M = self.truncation_M(n) h,w = self.get_shift_and_width_for_coset(n) zN = CyclotomicField(w).gens()[0] prec1 = self._prec + ceil(log_b(M,2)) RF = RealField(prec1) coeffs=[] fak = RF(w)**-(RF(self._k)/RF(2)) #print "f=",f,n for i in range(M): al = CF(self.atkin_lehner(n)) c0 = self._base_coeffs_embedding[i] #if hasattr(c0,"complex_embeddings"): # c0 = c0.complex_embedding(prec1) #else: # c0 = CF(c0) qN = zN**((i+1)*h) #print "qN=",qN,type(qN) an = fak*al*c0*qN.complex_embedding(prec1) #an = self.atkin_lehner(n)*self._base_coeffs[i]*zN**((i+1)*h) #an = f*an.complex_embedding(prec1) coeffs.append(an) self._coefficients_at_coset[n] = coeffs return self._coefficients_at_coset[n] def get_rk(self,n,k): r""" Compute the coefficient r_k((f|A_n)) """ if not self._rks.has_key((n,k)): S,T = SL2Z.gens() nstar = self._get_shifted_coset_m(n,S) kstar = self._k-2-k i1 = self.get_integral_from_1_to_oo(n,k) i2 = self.get_integral_from_1_to_oo(nstar,kstar) if self._verbose>0: print "i1=",i1 print "i2=",i2 self._rks[(n,k)] = i1+i2*(-1)**(k+1) return self._rks[(n,k)] def get_integral_from_1_to_oo(self,n,k): r""" Compute \int_{1}^{+Infinity} f|A_n(it) t^k dt """ CF = ComplexField(self._prec) if not self._integrals.has_key((n,k)): c = self.coefficient_at_coset(n) w = self.width(n) my_integral = 0 if self._prec<=53: if w==1: l = 1 for a in c: my_integral+= a*exp_z_integral(CF(0,1),l,k) l+=1 else: l = 1 for a in c: my_integral+= a*exp_z_integral_w(CF(0,1),l,w,k) l+=1 else: l = 1 for a in c: my_integral+= a*exp_z_integral_wmp(CF(0,1),l,w,k) l+=1 self._integrals[(n,k)]=my_integral return self._integrals[(n,k)] def width(self,n): r""" Compute the width of the cusp at coset nr. n. """ if not self._width.has_key(n): self.get_shifts_and_widths() return self._width[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 get_shifts_and_widths(self): r""" Compute the shifts and widths of all cosets. """ self._width[0]=1 self._shift[0]=0 for n in range(0,self._dim): h,w = self.get_shift_and_width_for_coset(n) self._M[n] = get_truncation(self._k,w,self._prec) self._M0 = max(self._M.values()) def get_shift_and_width_for_coset(self,n): r""" Compute the shift and width of coset nr. n. """ if self._shift.has_key(n) and self._width.has_key(n): return self._shift[n],self._width[n] if not is_squarefree(self._level): raise NotImplementedError,"Only square-free levels implemented" G = Gamma0(self._level) A = self.coset_rep(n) a = A[0,0]; c=A[1,0] width = G.cusp_width(Cusp(a,c)) if self._verbose>0: print "width=",width Amat = Matrix(ZZ,2,2,A.matrix().list()) h = -1 for j in range(width): Th = Matrix(ZZ,2,2,[width,-j,0,1]) W = Amat*Th if self._verbose>1: print "W=",W if self.is_involution(W): h = j break if h<0: raise ArithmeticError,"Could not find shift!" self._shift[n]=h self._width[n]=width return h,width def is_involution(self,W,verbose=0): r""" Explicit test if W is an involution of Gamma0(self._level) """ G = Gamma0(self._level) for g in G.gens(): gg = Matrix(ZZ,2,2,g.matrix().list()) g1 = W*gg*W**-1 if verbose>0: print "WgW^-1=",g1 if g1 not in G: return False W2 = W*W c = gcd(W2.list()) if c>1: W2 = W2/c if verbose>0: print "W^2=",W2 if W2 not in G: return False return True def test_relations(self): I = SL2Z([1,0,0,1]) S = SL2Z([0,-1,1,0]) U = SL2Z([1,-1,1,0]) U2 = SL2Z([0,-1,1,-1]) lS = [(1,I),(1,S)] lU = [(1,I),(1,U),(1,U2)] pS = self*lS pU = self*lU maxS = 0; maxU=0 if self._verbose>0: print "pS=",pS print "pU=",pU for p in pS.values(): if hasattr(p,"coeffs"): if p.coefficients(sparse=False)<>[]: tmp = max(map(abs,p.coefficients(sparse=False))) else: tmp = 0 else: tmp = abs(p) if tmp>maxS: maxS = tmp for p in pU.values(): if hasattr(p,"coefficients"): if p.coefficients(sparse=False)<>[]: tmp = max(map(abs,p.coefficients(sparse=False))) else: tmp = 0 else: tmp = abs(p) if tmp>maxU: maxU = tmp print "Max coeff of self|(1+S)=",maxS print "Max coeff of self|(1+U+U^2)=",maxU def test_relations_plusminus(self): I = SL2Z([1,0,0,1]) S = SL2Z([0,-1,1,0]) U = SL2Z([1,-1,1,0]) U2 = SL2Z([0,-1,1,-1]) lS = [(1,I),(1,S)] lU = [(1,I),(1,U),(1,U2)] ppp1={};ppp2={};ppp3={};ppp4={} for n in range(self._dim): p1 = self.action_by_lin_comb(n,lS,sym=1) p2 = self.action_by_lin_comb(n,lU,sym=1) ppp1[n]=p1 ppp2[n]=p2 p1 = self.action_by_lin_comb(n,lS,sym=-1) p2 = self.action_by_lin_comb(n,lU,sym=-1) ppp3[n]=p1 ppp4[n]=p2 for pp in [ppp1,ppp2,ppp3,ppp4]: maxv=0 for p in pp.values(): if hasattr(p,"coeffs"): if p.coefficients(sparse=False)<>[]: tmp = max(map(abs,p.coefficients(sparse=False))) else: tmp = 0 else: tmp = abs(p) if tmp>maxv: maxv = tmp print "maxv=",maxv #print "Max coeff of self|(1+S)=",maxS #print "Max coeff of self|(1+U+U^2)=",maxU def test_rationality(self): omega1 = self.canonical_periods()[0] omega2 = self.canonical_periods()[1] for n in range(self._dim): pp = self.polynomial_plus(n)/omega1 pm = self.polynomial_minus(n)/omega2 print "P(f{0:2d})^+/omega_+={1}".format(n,pp) print "P(f{0:2d})^-/omega_-={1}".format(n,pm) print "o1=",omega1 print "o2=",omega2
def __init__(self,f,prec=53,verbose=0,data={}): r""" Initialize the period polynomial of f. INPUT: - `f` -- Newform - `` EXAMPLES: # First elliptic curve sage: f=Newforms(11,2)[0] sage: pp=PeriodPolynomial(f,prec=103) sage: L=f.cuspform_lseries() sage: pp.petersson_norm() 0.00390834565612459898524738548154 - 5.53300833748482053164300189100e-35*I sage: pp.special_value(1) 0.253841860855910684337758923267 sage: L(1) 0.253841860855911 # We can also study rationality of the coefficients of the sage: pp.test_rationality() P(f 0)^+/omega_+=1.00000000000000000000000000000 P(f 0)^-/omega_-=0 P(f 1)^+/omega_+=-1.00000000000000000000000000000 P(f 1)^-/omega_-=0 P(f 2)^+/omega_+=0 P(f 2)^-/omega_-=1.27412157006452456511355616309e-31 + 1.01489446868406102099789763444e-28*I P(f 3)^+/omega_+=-5.00000000000000000000000000133 P(f 3)^-/omega_-=-1.16793587723237638257725820700e-60 + 8.24993716616779655911027615609e-29*I P(f 4)^+/omega_+=-2.50000000000000000000000000073 P(f 4)^-/omega_-=-3.39765752017206550696948310188e-32 + 2.39999999999999999999999999940*I P(f 5)^+/omega_+=2.50000000000000000000000000073 P(f 5)^-/omega_-=-3.39765752017206550696948310188e-32 + 2.39999999999999999999999999940*I P(f 6)^+/omega_+=5.00000000000000000000000000133 P(f 6)^-/omega_-=1.16793587723237638257725820700e-60 - 8.24993716616779655911027615609e-29*I P(f 7)^+/omega_+=5.00000000000000000000000000133 P(f 7)^-/omega_-=-1.16793587723237638257725820700e-60 + 8.24993716616779655911027615609e-29*I P(f 8)^+/omega_+=2.50000000000000000000000000073 P(f 8)^-/omega_-=3.39765752017206550696948310188e-32 - 2.39999999999999999999999999940*I P(f 9)^+/omega_+=-2.50000000000000000000000000073 P(f 9)^-/omega_-=3.39765752017206550696948310188e-32 - 2.39999999999999999999999999940*I P(f10)^+/omega_+=-5.00000000000000000000000000133 P(f10)^-/omega_-=1.16793587723237638257725820700e-60 - 8.24993716616779655911027615609e-29*I P(f11)^+/omega_+=0 P(f11)^-/omega_-=-1.27412157006452456511355616309e-31 - 1.01489446868406102099789763444e-28*I o1= 0.0404001869188632792144191985239*I o2= -1.36955018267536771772869542629e-33 - 0.0967407815209822856536332369020*I sage: f=Newforms(5,8,names='a')[0];f q - 14*q^2 - 48*q^3 + 68*q^4 + 125*q^5 + O(q^6) sage: L=f.cuspform_lseries() sage: pp=PeriodPolynomial(f,prec=103) sage: pp.special_value(4) -3.34183629241748201816194829811e-29 + 8.45531852674217908762910051272e-60*I sage: pp.special_value(3) -0.729970592499451187790964533256 + 2.56020879251697431818575640846e-31*I sage: L(3) -0.729970592499451 sage: L(4) 0.000000000000000 """ self._f = f self._level = None if data<>{}: self.init_from_dict(data) if self._level==None: self._level = f.level() self._k = f.weight() self._w = self._k - 2 self._verbose = verbose self._polynomials = {} self._prec = prec self._rks = {} self._coset_reps={} self._dim = Gamma0(self._level).index() self._coefficients_at_coset = {} self._base_coeffs=[] self._base_coeffs_embedding=[] self._M = {} self._M0 = 0 self._width={} self._shift={} self._atkin_lehner={} self._integrals={} self._pplus = {} self._pminus={} self._peterson_norm=0 self._canonical_periods=[] # Check assert is_squarefree(self._level) ## Some numerical definitions self._RF = RealField(prec) self._eps = self._RF(2)**-self._RF(prec) self._pi = self._RF.pi()