def add_trace_and_norm_ladic(g, D, alpha_geo, verbose=True): if verbose: print "add_trace_and_norm_ladic()" #load Fields L = D['L'] if L is QQ: QQx = PolynomialRing(QQ, "x") L = NumberField(QQx.gen(), "b") prec = D['prec'] CCap = ComplexField(prec) # load endo alpha = D['alpha'] rosati = bound_rosati(alpha_geo) if alpha.base_ring() is not L: alpha_K = copy(alpha) alpha = Matrix(L, 2, 2) #shift alpha field from K to L for i, row in enumerate(alpha_K.rows()): for j, elt in enumerate(row): if elt not in L: assert elt.base_ring().absolute_polynomial( ) == L.absolute_polynomial() alpha[i, j] = L(elt.list()) else: alpha[i, j] = L(elt) # load algx_poly algx_poly_coeff = D['algx_poly'] #sometimes, by mistake the algx_poly is defined over K where K == L, but with a different name for i, elt in enumerate(algx_poly_coeff): if elt not in L: assert elt.base_ring().absolute_polynomial( ) == L.absolute_polynomial() algx_poly_coeff[i] = L(elt.list()) else: algx_poly_coeff[i] = L(elt) x_poly = vector(CCap, D['x_poly']) for i in [0, 1]: assert almost_equal( x_poly[i], algx_poly_coeff[i]), "%s != %s" % (algx_poly_coeff[i], x_poly[i]) # load P P0 = vector(L, [D['P'][0], D['P'][1]]) for i, elt in enumerate(P0): if elt not in L: assert elt.base_ring().absolute_polynomial( ) == L.absolute_polynomial() P0[i] = L(elt.list()) else: P0[i] = L(elt) if verbose: print "P0 = %s" % (P0, ) # load image points, P1 and P2 L_poly = PolynomialRing(L, "xL") xL = L_poly.gen() Xpoly = L_poly(algx_poly_coeff) if Xpoly.is_irreducible(): M = Xpoly.root_field("c") else: # this avoids bifurcation later on in the code, we don't want to be always checking if M is L M = NumberField(xL, "c") # trying to be sure that we keep the same complex_embedding... M_complex_embedding = 0 if L.gen() not in QQ: M_complex_embedding = None Lgen_CC = toCCap(L.gen(), prec=prec) for i, _ in enumerate(M.complex_embeddings()): if norm(Lgen_CC - M(L.gen()).complex_embedding(prec=prec, i=i) ) < CCap(2)**(-0.7 * Lgen_CC.prec()) * Lgen_CC.abs(): M_complex_embedding = i assert M_complex_embedding is not None, "\nL = %s\n%s = %s\n%s" % ( L, L.gen(), Lgen_CC, M.complex_embeddings()) M_poly = PolynomialRing(M, "xM") xM = M_poly.gen() # convert everything to M P0_M = vector(M, [elt for elt in P0]) alpha_M = Matrix(M, [[elt for elt in row] for row in alpha.rows()]) Xpoly_M = M_poly(Xpoly) for i in [0, 1]: assert almost_equal(x_poly[i], Xpoly_M.list()[i], ithcomplex_embedding=M_complex_embedding ), "%s != %s" % (Xpoly_M.list()[i], x_poly[i]) P1 = vector(M, 2) P1_ap = vector(CCap, D['R'][0]) P2 = vector(M, 2) P2_ap = vector(CCap, D['R'][1]) M_Xpoly_roots = Xpoly_M.roots() assert len(M_Xpoly_roots) > 0 Ypoly_M = prod([xM**2 - g(root) for root, _ in M_Xpoly_roots]) # also \in L_poly assert sum(m for _, m in Ypoly_M.roots(M)) == Ypoly_M.degree( ), "%s != %s\n%s\n%s" % (sum(m for _, m in Ypoly_M.roots(M)), Ypoly_M.degree(), Ypoly_M, Ypoly_M.roots(M)) if len(M_Xpoly_roots) == 1: # we have a double root P1[0] = M_Xpoly_roots[0][0] P2[0] = M_Xpoly_roots[0][0] ae_prec = prec * 0.4 else: assert len(M_Xpoly_roots) == 2 ae_prec = prec # we have two distinct roots P1[0] = M_Xpoly_roots[0][0] P2[0] = M_Xpoly_roots[1][0] if not_equal(P1_ap[0], P1[0], ithcomplex_embedding=M_complex_embedding): P1[0] = M_Xpoly_roots[1][0] P2[0] = M_Xpoly_roots[0][0] assert almost_equal( P1_ap[0], P1[0], ithcomplex_embedding=M_complex_embedding, prec=ae_prec), "\n%s = %s \n != %s" % ( P1[0], toCCap( P1[0], ithcomplex_embedding=M_complex_embedding), CC(P1_ap[0])) assert almost_equal( P2_ap[0], P2[0], ithcomplex_embedding=M_complex_embedding, prec=ae_prec), "\n%s = %s \n != %s" % ( P2[0], toCCap( P2[0], ithcomplex_embedding=M_complex_embedding), CC(P2_ap[0])) # figure out the right square root # pick the default branch P1[1] = sqrt(g(P1[0])) P2[1] = sqrt(g(P2[0])) if 0 in [P1[1], P2[1]]: print "one of image points is a Weirstrass point" print P1 print P2 raise ZeroDivisionError #switch if necessary if not_equal(P1_ap[1], P1[1], ithcomplex_embedding=M_complex_embedding, prec=ae_prec): P1[1] *= -1 if not_equal(P2_ap[1], P2[1], ithcomplex_embedding=M_complex_embedding, prec=ae_prec): P2[1] *= -1 # double check for i in [0, 1]: assert almost_equal(P1_ap[i], P1[i], ithcomplex_embedding=M_complex_embedding, prec=ae_prec), "%s != %s" % (P1_ap[i], P1[i]) assert almost_equal(P2_ap[i], P2[i], ithcomplex_embedding=M_complex_embedding, prec=ae_prec), "%s != %s" % (P2_ap[i], P2[i]) # now alpha, P0 \in L # P1, P2 \in L if verbose: print "P1 = %s\nP2 = %s" % (P1, P2) print "Computing the trace and the norm ladically\n" trace_and_norm = trace_and_norm_ladic(L, M, P0_M, P1, P2, g, 2 * alpha_M, 16 * rosati, primes=ceil(prec * L.degree() / 61)) else: trace_and_norm = trace_and_norm_ladic(L, M, P0_M, P1, P2, g, 2 * alpha_M, 16 * rosati, primes=ceil(prec * L.degree() / 61)) # Convert the coefficients to polynomials trace_numerator, trace_denominator, norm_numerator, norm_denominator = [ L_poly(coeff) for coeff in trace_and_norm ] assert trace_numerator(P0[0]) == trace_denominator( P0[0]) * -algx_poly_coeff[1], "%s/%s (%s) != %s" % ( trace_numerator, trace_denominator, P0[0], -algx_poly_coeff[1]) assert norm_numerator(P0[0]) == norm_denominator( P0[0]) * algx_poly_coeff[0], "%s/%s (%s) != %s" % ( norm_numerator, norm_denominator, P0[0], algx_poly_coeff[0]) buffer = "# x1 + x2 = degree %d/ degree %d\n" % ( trace_numerator.degree(), trace_denominator.degree()) buffer += "# = (%s) / (%s) \n" % (trace_numerator, trace_denominator) buffer += "# max(%d, %d) <= %d\n\n" % ( trace_numerator.degree(), trace_denominator.degree(), 16 * rosati) buffer += "# x1 * x2 = degree %d/ degree %d\n" % ( norm_numerator.degree(), norm_denominator.degree()) buffer += "# = (%s) / (%s) \n" % (norm_numerator, norm_denominator) buffer += "# max(%d, %d) <= %d\n" % ( norm_numerator.degree(), norm_denominator.degree(), 16 * rosati) if verbose: print buffer print "\n" assert max(trace_numerator.degree(), trace_denominator.degree()) <= 16 * rosati assert max(norm_numerator.degree(), norm_denominator.degree()) <= 16 * rosati if verbose: print "Veritfying if x1*x2 and x1 + x2 are correct..." verified = verify_algebraically(g, P0, alpha, trace_and_norm, verbose=verbose) if verbose: print "\nDoes it act on the tangent space as expected? %s\n" % verified print "Done add_trace_and_norm_ladic()" return verified, [ trace_numerator.list(), trace_denominator.list(), norm_numerator.list(), norm_denominator.list() ]
def compute_alpha_point(g, iaj, alpha, P0, digits, power, verbose, aggressive=True, append=""): # input: # * g, defining polynomial of the hyperelliptic curve # * iaj = InvertAJglobal class # * alpha = analytic representation of the endomorphism acting on the tangent space # * digits = how many digits to work with # * power, we will divide by 2**power before inverting the abel jacobi map # * P0, a point in the curve for which we will compute alpha*2(P - \infty) = P1 + P2 - \infty # * verbose # * agressive, raise ZeroDivisionError if we get a P1[0] = P2[0] or one of the points is infty # * append, a string to append to the numberfield generators # # output: a dictionary with the following keys # TODO add the keys output = {} K = alpha.base_ring() CCap = iaj.C prec = CCap.precision() output['prec'] = prec x0, y0 = P0 Kz = PolynomialRing(K, "z") z = Kz.gen() if verbose: print "compute_alpha_point()" print "P0 = %s" % (P0, ) #deal with the field of definition if y0 in K: if K is QQ: L = K from_K_to_L = QQ.hom(1, QQ) else: L = K.change_names("b" + append) from_K_to_L = L.structure()[1] else: L, from_K_to_L = (z**2 - g(x0)).splitting_field("b" + append, simplify_all=True, map=True) output['L'] = L # output['L_str'] = sage_str_numberfield(L, 'x','b'+append); output['from_K_to_L'] = from_K_to_L # output['L_gen'] = toCCap(L.gen(), 53); # figure out y0 in L y0_ap = toCCap(y0, prec) y0s = [elt for elt, _ in (z**2 - g(x0)).roots(L)] assert len(y0s) == 2 y0s_ap = [toCCap(elt, prec) for elt in y0s] if norm(y0_ap - y0s_ap[0]) < norm(y0_ap - y0s_ap[1]): y0 = y0s[0] else: y0 = y0s[1] P0 = vector(L, [x0, y0]) alpha_L = Matrix(L, [[from_K_to_L(elt) for elt in row] for row in alpha.rows()]) alpha_ap = Matrix(CCap, [toCCap_list(row, prec) for row in alpha_L.rows()]) output['P'] = P0 output['alpha'] = alpha_L if verbose: print "L = %s" % L print "%s = %s" % (L.gen(), toCCap(L.gen(), 53)) print "P0 = %s" % (P0, ) print "alpha = %s" % ([[elt for elt in row] for row in alpha_L.rows()], ) P0_ap = vector(CCap, toCCap_list(P0, prec + 192)) if verbose: print "P0_ap = %s" % (vector(CC, P0_ap), ) if verbose: print "Computing AJ of P0..." c, w = cputime(), walltime() ajP0 = vector(CCap, AJ1_digits(g, P0_ap, digits)) print "Time: CPU %.2f s, Wall: %.2f s" % ( cputime(c), walltime(w), ) print else: ajP0 = vector(CCap, AJ1_digits(g, P0_ap, digits)) output['ajP'] = ajP0 aj2P0 = 2 * ajP0 alpha2P0_an = alpha_ap * aj2P0 if verbose: print "Working over %s" % CCap invertAJ_tries = 3 for i in range(invertAJ_tries): #try invertAJ_tries times to invertAJ try: if verbose: print "\n\ninverting AJ..." c, w = cputime(), walltime() alpha2P0_div = iaj.invertAJ(alpha2P0_an, power) print "Time: CPU %.2f s, Wall: %.2f s" % ( cputime(c), walltime(w), ) print "\n\n" else: alpha2P0_div = iaj.invertAJ(alpha2P0_an, power) break except AssertionError as error: print error if verbose: print "an assertion failed while inverting AJ.." if i == invertAJ_tries - 1: if verbose: print "retrying with a new P0" print raise ZeroDivisionError else: iaj.iajlocal.set_basepoints() if verbose: print "retrying again with a new set of base points" if verbose: print "Computing the Mumford coordinates of alpha(2*P0 - 2*W)" c, w = cputime(), walltime() R0, R1 = alpha2P0_div.coordinates() print "Time: CPU %.2f s, Wall: %.2f s" % ( cputime(c), walltime(w), ) else: R0, R1 = alpha2P0_div.coordinates() points = [R0, R1] x_poly = alpha2P0_div.x_coordinates() output['R'] = points output['x_poly'] = x_poly if (R0 in [+Infinity, -Infinity]) or (R1 in [+Infinity, -Infinity]): if aggressive: # we want to avoid these situations if verbose: print "One of the coordinates is at infinity" if R0 in [+Infinity, -Infinity]: print "R0 = %s" % (R0, ) else: print "R1 = %s" % (R1, ) print "retrying with a new P0" print raise ZeroDivisionError else: return output buffer = "# R0 = %s\n" % (vector(CC, R0), ) buffer += "# R1 = %s\n" % (vector(CC, R1), ) buffer += "# and \n# x_poly = %s\n" % (vector(CC, x_poly), ) if verbose: print buffer assert len(x_poly) == 3 algx_poly = [NF_embedding(coeff, L) for coeff in x_poly] buffer = "algx_poly = %s;\n" % (algx_poly, ) if L != QQ: buffer += "#where %s ~ %s\n" % (L.gen(), L.gen().complex_embedding()) buffer += "\n" if verbose: print buffer sys.stdout.flush() sys.stderr.flush() output['algx_poly'] = algx_poly if None in algx_poly: if aggressive: if verbose: print "No algebraic expression for the polynomial" print "retrying with a new P0" sys.stdout.flush() sys.stderr.flush() raise ZeroDivisionError else: return output #c, b, a = algx_poly #if aggressive and b**2 - 4*a*c == 0: # raise ZeroDivisionError if verbose: print "Done compute_alpha_point()" return output
def newton_linear(P0, P1, P2, f, alpha, PSring, prec): assert P0.base_ring() is P1.base_ring() assert P1.base_ring() is P2.base_ring() assert P0.base_ring() is alpha.base_ring() assert P0.base_ring() is PSring.base_ring() assert f.base_ring() in [QQ, ZZ, P0.base_ring()] T = PSring.gen() #xi_0 = xi(0) x0_0 = PSring(P0[0]) x1_0 = PSring(P1[0]) x2_0 = PSring(P2[0]) y0_0 = P0[1] y1_0 = P1[1] y2_0 = P2[1] b0, b1, b2 = 1, 1, 1 py0_0 = sqrt(f(x0_0 + T)).list()[0] py1_0 = sqrt(f(x1_0 + T)).list()[0] py2_0 = sqrt(f(x2_0 + T)).list()[0] if PSring.base_ring().is_exact(): if y0_0 != py0_0: b0 = -1 if y1_0 != py1_0: b1 = -1 if y2_0 != py2_0: b2 = -1 assert y0_0 == b0 * py0_0, "wrong branch at P0? %s != %s" % (y0_0, b0 * py0_0) assert y1_0 == b1 * py1_0, "wrong branch at P1? %s != %s" % (y1_0, b1 * py1_0) assert y2_0 == b2 * py2_0, "wrong branch at P2? %s != %s" % (y2_0, b2 * py2_0) else: if norm(y0_0 - py0_0) > norm(y0_0 + py0_0): b0 = -1 if norm(y1_0 - py1_0) > norm(y1_0 + py1_0): b1 = -1 if norm(y2_0 - py2_0) > norm(y2_0 + py2_0): b2 = -1 closetozero = 2**(-0.8 * PSring.base_ring().prec()) assert norm(y0_0 + b0 * py0_0) > norm(y0_0), "%.3e vs %.3e wrong branch?" % ( norm(y0_0 - b0 * py0_0), norm(y0_0 + b0 * py0_0)) assert norm(y0_0 - b0 * py0_0) < norm( y0_0) * closetozero, "%.3e vs %.3e wrong branch?" % ( norm(y0_0 - b0 * py0_0), norm(y0_0 + b0 * py0_0)) assert norm(y1_0 + b1 * py1_0) > norm(y1_0), "%.3e vs %.3e wrong branch?" % ( norm(y1_0 - b1 * py1_0), norm(y1_0 + b1 * py1_0)) assert norm(y1_0 - b1 * py1_0) < norm( y1_0) * closetozero, "%.3e vs %.3e wrong branch?" % ( norm(y1_0 - b1 * py1_0), norm(y1_0 + b1 * py1_0)) assert norm(y2_0 + b2 * py2_0) > norm(y2_0), "%.3e vs %.3e wrong branch?" % ( norm(y2_0 - b2 * py2_0), norm(y2_0 + b2 * py2_0)) assert norm(y2_0 - b2 * py2_0) < norm( y2_0) * closetozero, "%.3e vs %.3e wrong branch?" % ( norm(y2_0 - b2 * py2_0), norm(y2_0 + b2 * py2_0)) x1 = x1_0 + O(T) x2 = x2_0 + O(T) p = 1 Tsub = x0_0 + T fps = PSring(f)(Tsub) sqrtfps = sqrt(fps) row0 = PSring(alpha.row(0).list())(Tsub) row1 = PSring(alpha.row(1).list())(Tsub) if x1_0 != x2_0: # Iteration to solve the differential equation, gains 1 term # alternatively we could solve a linear ODE to double the number of terms while p < prec: m = b0 / ((x2 - x1) * sqrtfps) dx1 = m * b1 * sqrt(f(x1)) * (row0 * x2 - row1) dx2 = m * b2 * sqrt(f(x2)) * (row1 - row0 * x1) p += 1 x1 = x1_0 + dx1.integral() + O(T**p) x2 = x2_0 + dx2.integral() + O(T**p) else: #the degenerate case row0_y = row0 * b0 / sqrtfps half = P0.base_ring()(1 / 2) while p < prec: dx1 = half * b1 * sqrt(f(x1)) * row0_y x1 = x1_0 + dx1.integral() + O(T**p) p += 1 # check second equation if 2 * x1 * x1.derivative() * b1 / sqrt(f(x1)) != row1 * b0 / sqrtfps: print "x1(0) = x2(0), but x1 != x2" raise ZeroDivisionError x2 = x1 return x1, x2
def support(self, basis): # Input: a basis in H**0( D_0) for H**0((g+1)\infty - E), where E is an effective divisor of degree g/2 # Output: returns the support of E as a list of g points # Computing the intersection of # <1, x, x**2,..., x**g> with <basis> B = basis.augment( identity_matrix(self.g + 1).stack(Matrix(basis.nrows() - (self.g + 1), (self.g + 1)))) KB, upper, lower = Kernel(B, basis.ncols() + self.g ) if self.verbose: print "KB upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) maxlower = self.lower result = [None for _ in range(self.g)] # if dim of the intersection of <1, x, x**2,..., x**g> with <basis> is 1 if self.threshold_check(upper, lower): # we have the expected rank, all the roots are simple, unless E = 2*P # as in genus = 2 we can't have E = tau(P) + P maxlower = max(maxlower, lower); Rw = PolynomialRing(self.Rdoubleextraprec, "T") poly = Rw( KB.column(0)[-(self.g + 1):].list() ) if self.g == 2: a, b, c = list(poly) disc = (b**2 - 4*a*c).abs() #a2 = (a**2).abs() dpoly = poly.derivative() if self.threshold_check((a**2).abs(), disc): xcoordinates = dpoly.complex_roots() + dpoly.complex_roots() maxlower = max(maxlower, disc); else: xcoordinates = poly.complex_roots() else: xcoordinates = poly.complex_roots() for i, x in enumerate(xcoordinates): y0 = self.Rextraprec(sqrt(self.f(x))); x0 = self.Rextraprec(x) vp = vector(self.R, [x0**u * y0**v for u, v in self.Vexps[:basis.nrows()] ]); vn = vector(self.R, [x0**u * (-y0)**v for u, v in self.Vexps[:basis.nrows()] ]); np = norm( vp * basis); nn = norm( vn * basis); #is it a simple root? if dpoly(x).abs() < self.notzero: assert self.g == 2, "one needs to be extra careful for genus > 2" if self.threshold_check(np, nn) and not self.threshold_check(nn, np): #np > nn ~ 0 result[i] = (x0, -y0); maxlower = max(maxlower, nn); elif not self.threshold_check(np, nn) and self.threshold_check(nn, np): #nn > np ~ 0 result[i] = (x0, y0); maxlower = max(maxlower, np); else: print "sign for y is not clear: neg = %s, pos = %s,\ny = %s + %s * I = 0?" % tuple(vector(RealField(15), (nn, np, y0.real(), y0.imag()))); if nn > np: result[i] = (x0, y0); maxlower = max(maxlower, np); else: result[i] = (x0, -y0); maxlower = max(maxlower, nn); # else: # assert self.g == 2, "for now only genus 2" # # for g = 2, we can't have E = P + tau(P), as (x - x0) \in H**0((g+1)\infty - E) # # thus the rank of B should be at most basis.ncols() + 1 # for j, xj in enumerate(xcoordinates[i+1:]): # if (x0 - xj).abs() < self.notzero: # # we might have a double root, and at the moment this should only work for g == 2 # break; # #j is the other root # if self.threshold_check(np, nn) and not self.threshold_check(nn, np): # result[j] = result[i] = (x0, -y0); # elif not self.threshold_check(np, nn) and self.threshold_check(nn, np): # result[j] = result[i] = (x0, y0); # else: # #this covers the case that y0 ~ 0 # if self.f(x0) > self.almostzero: # print "sign for y is not clear: neg = %.2e, pos = %.2e,\nassuming y = %.2e + %.2e * I = 0" % (nn, np, y0.real(), y0.imag()); # result[j] = result[i] = (x0, 0); # # return result, maxlower; else: if self.verbose: print "there is at least a root at infinity, i.e. \inf_{+,-} \in supp E" print (RealField(35)(upper), RealField(35)(lower)) # there is at least a root at infinity, i.e. \inf_{+,-} \in supp E # recall that \inf_{+} + \inf_{-} ~ P + tau(P), and in this case we have booth roots at infinity assert self.g == 2, "for now only genus 2" Ebasis, upper, lower = EqnMatrix(basis, basis.ncols() ) assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) maxlower = max(maxlower, lower); B = basis.augment( identity_matrix(self.g ).stack(Matrix(basis.nrows() - (self.g ), (self.g )))) KB, upper, lower = Kernel(B, basis.ncols() + self.g - 1 ) # 1 \in <basis> v0 = vector(self.R, [0] * basis.nrows()) v0[0] = 1 norm_one = norm(Ebasis * v0) if not self.threshold_check(upper, lower): # dim <1, x> cap <basis> = 2 #1 \in <basis> assert self.threshold_check(1, norm_one), "upper = %s lower = %s norm_one = %s " % (RealField(35)(upper), RealField(35)(lower), RealField(35)(norm_one)); maxlower = max(maxlower, norm_one); #x \in <basis> vx = vector(self.R, [0]*basis.nrows()) vx[1] = 1 lower = norm(Ebasis * vx) assert self.threshold_check(1, lower), "lower = %s" % (RealField(35)(lower),); maxlower = max(maxlower, lower); vx2 = vector(self.R, [0]*basis.nrows()) vx2[2] = 1 lower = norm(Ebasis * vx2) if self.threshold_check(1, lower): # E = \inf_{+} + \inf_{-} # <1, x, x^2> \in H**0((g+1)\infty - E) # x \in H^0 => 0 + 2 \infty - E >= 0 # x^2 \in H^0 => 4 * P_0 + \infty - E >= 0 for all P0 maxlower = max(maxlower, lower); return [+Infinity, -Infinity], maxlower # <1, x> \in H**0((g+1)\infty - E) # but not x^2 # supp(E) \subsetneq { \inf_{+}, \inf_{-} } if self.f.degree() % 2 == 0: # we need to figure out the sign at infinity Maug = Matrix(basis.nrows() - self.g - 1, self.g + 1).stack(identity_matrix(self.g + 1)) B = basis.augment( Maug ) KB, upper, lower = Kernel(B, basis.ncols() + self.g ) a, b, c = KB.column(0)[-(2 + 1):].list() assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) tmp = (-b/c) / sqrt(self.f.list()[-1]); assert self.threshold_check( tmp.real(), tmp.imag()), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) infsign = round(tmp.real()); assert infsign in [1, -1] return [infsign*Infinity, infsign*Infinity], maxlower return [+Infinity, +Infinity], maxlower else: maxlower = max(maxlower, lower); #1 \notin <basis> assert self.threshold_check(norm_one), "upper = %s lower = %s norm_one = %s " % (RealField(35)(upper), RealField(35)(lower), RealField(35)(norm_one)); Rw = PolynomialRing(self.Rdoubleextraprec, "T") xcoordinates = Rw(KB.column(0)[-(self.g):].list()).complex_roots() assert len(xcoordinates) == 1; x0 = xcoordinates[0]; y0 = self.Rextraprec(sqrt(self.f(x0))); # if dim <1, x, x**2> cap <basis> >= 2 # then dim <1, x> cap <basis> >= 1 # we must have <1, x> \subset <basis> # double check that (x - x0) and (x - x0)**2 are in <basis> # (x - x0) v1 = vector(self.R, [0]*basis.nrows()) v1[0] = -x0 v1[1] = 1 lower = norm(Ebasis * v1) assert self.threshold_check(1, lower), "lower = %s" % (RealField(35)(lower),); maxlower = max(maxlower, lower); # (x - x0)**2 v2 = vector(self.R, [0]*basis.nrows()) v2[0] = x0**2 v2[1] = - 2*x0 v2[2] = 1 lower = norm(Ebasis * v2) assert self.threshold_check(1, lower), "lower = %s" % (RealField(35)(lower),); maxlower = max(maxlower, lower); # (x - x0)**3 v3 = vector(self.R, [0]*basis.nrows()) v3[0] = -x0**3 v3[1] = 3*x0**2 v3[2] = -3*x0 v3[3] = 1 nc = norm(Ebasis * v3) vp = vector(self.R, [x0**i * y0**j for i,j in self.Vexps[:basis.nrows()]]); vn = vector(self.R, [x0**i * (-y0)**j for i,j in self.Vexps[:basis.nrows()]]); np = norm( vp * basis); nn = norm( vn * basis); # either E = P + \inf_{+/-} # or E = P + tau(P) with P != \inf_{*}, but in this case E ~ \inf_+ + \inf_- if self.threshold_check(np, nn) and not self.threshold_check(nn, np): #np > nn ~ 0 result[0] = (x0, -y0); maxlower = max(maxlower, nn); elif not self.threshold_check(np, nn) and self.threshold_check(nn, np): #nn > np ~ 0 result[0] = (x0, y0); maxlower = max(maxlower, np); else: if self.threshold_check(1,nc) and self.threshold_check(1,np) and self.threshold_check(1,nn): result[0] = (x0, y0) result[1] = (x0, -y0) maxlower = max(maxlower, nc, np, nn); # this is equivalent to: return result, maxlower return [+Infinity, -Infinity], maxlower if self.f(x0) > self.almostzero : print "sign for y is not clear: neg = %s, pos = %s,\nassuming y = %s + %s * I = 0" % tuple( vector( RealField(15), (nn, np, y0.real(), y0.imag()))); result[0] = (x0, 0); # E = P + \inf_{+/-} # P = result[0] x0, y0 = result[0] # Now figure out what infinity is in the supp of E # by checking if y - s*x**(g+1) - (y0 - s*x0**(g+1)) \in <basis> # for s = sign * sqrt(an) sqrtan = self.Rextraprec( sqrt( self.an) ); # vp -> no pole at inf_{+} -> inf_{+} \in supp E vp = vector(self.R, [0]*basis.nrows()) # vn -> no pole at inf_{-} -> inf_{-} \in supp E vn = vector(self.R, [0]*basis.nrows()) vp[0] = -(y0 - sqrtan*x0**(self.g + 1)) vn[0] = -(y0 + sqrtan*x0**(self.g + 1)) vp[self.g + 1] = -sqrtan vn[self.g + 1] = sqrtan vp[self.g + 2] = 1 vn[self.g + 2] = 1 np = norm( Ebasis * vp ); nn = norm( Ebasis * vn ); if self.threshold_check(np * nc, nn) and not self.threshold_check(nn * nc, np) and not self.threshold_check(nn * np, nc): #np * nc > nn ~ 0 maxlower = max(maxlower, nn); result[1] = -Infinity ; elif not self.threshold_check(np * nc, nn) and self.threshold_check(nn * nc, np) and not self.threshold_check(nn * np, nc): #nn * nc > np ~ 0 maxlower = max(maxlower, np); result[1] = +Infinity elif not self.threshold_check(np * nc, nn) and not self.threshold_check(nn * nc, np) and self.threshold_check(nn * np, nc): # np*nn > nc # this should have been rulled out before, but now it looks more likely to have P + tau(P) # instead of E = P + inf maxlower = max(maxlower, nc); #this is equivalent to: result[1] = (x0, -y0) result = [+Infinity, -Infinity] else: print "inf_{?} \in supp E not clear: neg = %s, pos = %s, conj = %s" % tuple(vector(RealField(15),(nn, np, nc))); mn = min(nn, np, nc) maxlower = max(maxlower, mn); if np == mn: result[1] = +Infinity; elif nn == mn: result[1] = -Infinity; elif nc == mn: #this is equivalent to: result[1] = (x0, -y0) result = [+Infinity, -Infinity] else: assert False, "something went wrong" return result, maxlower
y0 = sqrt(g(x0)) print "\tQi = (%s, -/+%s)" % (x0, y0) Q0, Q1 = vector(CCap, (x0, y0)), vector(CCap, (x0, -y0)) points = [P0, P1, Q0, Q1] pairs = [[P0, Q0], [P0, Q1], [P1, Q0], [P1, Q1]] print "\tTesting P -> Divisor(P, {0,1} ) -> Divisor(P, {0,1}).compute_coordinates() = P - \inf_{(-1)^{0,1}}?" for i, P in enumerate(points): for sign in range(2): #point - \infty_{ (-1)^sign} ~ # point + \inty_{ (-1)^{sign + 1} } - D0 DP = Divisor(Pic, [P], sign) R0, R1 = DP.compute_coordinates() R0 = vector(R0) N = norm(P - R0) N = RealField(15)(N) print "\t\tP + \pm Infinity = R0 + \pm Infinity? : %s" % N if R1 != (-1)**(sign + 1) * Infinity or N > threshold: print "\t\t!! WARNING !!" print "\t\t\tsomething went wrong?" print "\t\t\tsign = %s R1 = %s" % (sign, R1) print "\t\t\tP = %s" % vector(CC, P) print "\t\t\tR0 = %s" % vector(CC, R0) print "\tTesting P, Q -> Divisor(P,Q) -> Divisor(P,Q).compute_coordinates() = P + Q - D0?" for i, pair in enumerate(pairs): p0, p1 = pair Dp0p1 = Divisor(Pic, [p0, p1]) R0, R1 = Dp0p1.coordinates() R0 = vector(R0)
def gram_matrix(N, weight, prec=501, tol=1E-40, sv_min=1E-1, sv_max=1E15, bl=None, set_dim=None, force_prec=False): r""" Computes a matrix of p_{r,D}(r',D') for a basis of P_{r,D}, i.e. dim linearly independent P's INPUT: N = Integer weight = Real OPTIONAL: tol = error bound for the Poincaré series sv_min = minimal allowed singular value when determining whether a given set is linarly independent or not. sv_max = maximally allowed singular value bl = list of pairs (D_i,r_i) from which we compute a matrix of coeffficients p_{D_i,r_i}(D_j,r_j) """ # If we have supplied a list of D's and r's we make a gram matrix relative to these # otherwise we find a basis, i.e. linearly independent forms with correct dimension # find the dimension wt = '%.4f' % weight if (N < 10): stN = "0" + str(N) else: stN = str(N) v = dict() filename_work = "__N" + stN + "-" + wt + "--finding basis.txt" fp = open(filename_work, "write") fp.write("starting to find basis") fp.close() if (silent > 0): print("Forcing precision:{0}".format(force_prec)) set_verbose(0) if (bl != None): dim = len(bl) l = bl else: if (set_dim != None and set_dim > 0): dim = set_dim else: dim = dimension_jac_cusp_forms(int(weight + 0.5), N, -1) l = list_of_basis(N, weight, prec, tol, sv_min, sv_max, set_dim=dim) j = 0 for [D, r] in l.values(): for [Dp, rp] in l.values(): # Recall that the gram matrix is symmetric. We need only compute the upper diagonal if (list(v.values()).count([Dp, rp, D, r]) == 0): v[j] = [D, r, Dp, rp] j = j + 1 # now v is a list we can get into computing coefficients # first we print the "gram data" (list of indices) to the file s = str(N) + ": (AI[" + str(N) + "],[" indices = dict() for j in range(len(l)): Delta = l[j][0] r = l[j][1] diff = (r * r - Delta) % (4 * N) if diff != 0: raise ValueError( "ERROR r^2={0} not congruent to Delta={1} mod {2}!".format( r * r, Delta, 4 * N)) s = s + "(" + str(Delta) + "," + str(r) + ")" indices[j] = [Delta, r] if j < len(l) - 1: s = s + "," else: s = s + "])," s = s + "\n" if silent > 0: print(s + "\n") filename2 = "PS_Gramdata" + stN + "-" + wt + ".txt" fp = open(filename2, "write") fp.write(s) fp.close() try: os.remove(filename_work) except os.error: print("Could not remove file:{0}".format(filename_work)) pass filename_work = "__N" + stN + "-" + wt + "--computing_gram_matrix.txt" fp = open(filename_work, "write") fp.write("") fp.close() #print "tol=",tol #set_verbose(2) #print "force_prec(gram_mat)=",force_prec res = ps_coefficients_holomorphic_vec(N, weight, v, tol, prec, force_prec=force_prec) set_verbose(0) res['indices'] = indices maxerr = 0.0 for j in res['errs'].keys(): tmperr = abs(res['errs'][j]) #print "err(",j,")=",tmperr if (tmperr > maxerr): maxerr = tmperr # switch format for easier vewing res['errs'][j] = RR(tmperr) if silent > 0: print("maxerr={0}".format(RR(maxerr))) res['maxerr'] = maxerr wt_phalf = '%.4f' % (weight + 0.5) filename3 = "PS_Gramerr" + stN + "-" + wt + ".txt" fp = open(filename3, "write") wt s = "MAXERR[" + wt_phalf + "][" + stN + "]=" + str(RR(maxerr)) fp.write(s) fp.close() if (res['ok']): Cps = res['data'] else: print("Failed to compute Fourier coefficients!") return 0 RF = RealField(prec) A = matrix(RF, dim) kappa = weight fourpi = RF(4.0) * pi.n(prec) one = RF(1.0) N4 = RF(4 * N) C = dict() if (silent > 1): print("v={0}".format(v)) print("dim={0}".format(dim)) lastix = 0 # First set the upper right part of A for j in range(dim): ddim = dim - j if (silent > 1): print("j={0} ddim={1} lastix={2]".format(j, ddim, lastix)) for k in range(0, ddim): # need to scale with |D|^(k+0.5) if (silent > 1): print("k={0}".format(k)) print("lastix+k={0}".format(lastix + k)) mm = RF(abs(v[lastix + k][0])) / N4 tmp = RF(mm**(weight - one)) if (silent > 1): print("ddim+k={0}".format(ddim + k)) A[j, j + k] = Cps[lastix + k] * tmp C[v[lastix + k][0], v[lastix + k][1]] = Cps[lastix + k] lastix = lastix + k + 1 # And add the lower triangular part to mak the matrix symmetric for j in range(dim): for k in range(0, j): A[j, k] = A[k, j] # And print the gram matrix res['matrix'] = A dold = mpmath.mp.dps mpmath.mp.dps = int(prec / 3.3) AInt = mpmath.matrix(int(A.nrows()), int(A.ncols())) AMp = mpmath.matrix(int(A.nrows()), int(A.ncols())) for ir in range(A.nrows()): for ik in range(A.ncols()): AInt[ir, ik] = mpmath.mpi(A[ir, ik] - tol, A[ir, ik] + tol) AMp[ir, ik] = mpmath.mpf(A[ir, ik]) d = mpmath.det(AMp) if (silent > 1): print("det(A-as-mpmath)={0}".format(d)) di = mpmath.det(AInt) if (silent > 1): print("det(A-as-interval)={0}".format(di)) res['det'] = (RF(di.a), RF(di.b)) filename = "PS_Gram" + stN + "-" + wt + ".txt" if (silent > 1): print("printing to file: {0}".format(filename)) print_matrix_to_file(A, filename, 'A[' + str(N) + ']') if (silent > 1): print("A-A.transpose()={0}".format(norm(A - A.transpose()))) B = A ^ -1 #[d,B]=mat_inverse(A) if (silent > 1): print("A={0}".format(A.n(100))) print("det(A)={0}".format(di)) print("Done making inverse!") #res['det']=d res['inv'] = B mpmath.mp.dps = dold filename = "PS_Gram-inv" + stN + "-" + wt + ".txt" print_matrix_to_file(B, filename, ' AI[' + str(N) + ']') # first make the filename s = '%.1e' % tol filename3 = "PS_Coeffs" + stN + "-" + wt + "-" + s + ".sobj" # If the file already exist we load it and append the new data if (silent > 0): print("saving data to: {0}".format(filename3)) try: f = open(filename3, "read") except IOError: if (silent > 0): print("no file before!") # do nothing else: if silent > 0: print("file: {0} exists!".format(filename3)) f.close() Cold = load(filename3) for key in Cold.keys(): # print"key:",key if key not in C: # then we add it print("key:", key, " does not exist in the new version!") C[key] = Cold[key] save(C, filename3) ## Save the whole thing filename = "PS_all_gram" + stN + "-" + wt + ".sobj" save(res, filename) ## our work is completed and we can remove the file try: os.remove(filename_work) except os.error: print("Could not remove file: {0}".format(filename_work)) pass return res