def _compute_echelon(self): A = Matrix(self.parent(), self.A.rows()) # we create a copy of the matrix U = identity_matrix(self.parent(), A.nrows()) if (self.have_ideal): # we do simplifications A = self.simplify(A) ## Step 1: initialize r = 0 c = 0 # we look from the position (r,c) while (r < A.nrows() and c < A.ncols()): ir = self.__find_pivot(A, r, c) A = self.simplify(A) U = self.simplify(U) # we simplify in case relations pop up if (ir != None): # we found a pivot # We do the swapping (if needed) if (ir != r): A.swap_rows(r, ir) U.swap_rows(r, ir) # We do the bareiss step Arc = A[r][c] Arows = A.rows() Urows = U.rows() for i in range(r): # we create zeros on top of the pivot Aic = A[i][c] A.set_row(i, Arc * Arows[i] - Aic * Arows[r]) U.set_row(i, Arc * Urows[i] - Aic * Urows[r]) # We then leave the row r without change for i in range(r + 1, A.nrows()): # we create zeros below the pivot Aic = A[i][c] A.set_row(i, Aic * Arows[r] - Arc * Arows[i]) U.set_row(i, Aic * Urows[r] - Arc * Urows[i]) r += 1 c += 1 else: # no pivot then only advance in column c += 1 # We finish simplifying the gcds in each row gcds = [gcd(row) for row in A] T = diagonal_matrix([1 / el if el != 0 else 1 for el in gcds]) A = (T * A).change_ring(self.parent()) U = T * U return A, U
def solve_vectors(n,d, verbose=False): def w(i,j): return 0 if i==j else (d[Set([i,j])] + d[Set([i])] + d[Set([j])]) W = Matrix(GF(2),[[w(i,j) for j in range(n)] for i in range(n)]) v = vector(GF(2),[d[Set([i])] for i in range(n)]) if verbose: print("W = {}".format(W)) print("v = {}".format(v)) if W==0: if v==0: return 0 else: return v, v Wrows = [wr for wr in W.rows() if wr] if v==0: x = Wrows[0] y = next(wr for wr in Wrows[1:] if wr!=x) return x, y z = W.row(v.support()[0]) y = next(wr for wr in Wrows if wr!=z) return y+z, y
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 algo64(K, S, BB, T2=None, unit_first = True, verbose=False): r = 1+len(S) if T2 is None: T2 = get_T2(QQ,S, unit_first) if verbose: print("T2 = {}".format(T2)) assert len(T2)==r*(r+1)//2 from KSp import IdealGenerator Sx = [IdealGenerator(P) for P in S] u = -1 if K==QQ else K(K.unit_group().torsion_generator()) Sx = [u] + Sx if unit_first else Sx+[u] if verbose: print("Basis for K(S,2): {}".format(Sx)) #BBdict = dict((k,BB(T2[k])) for k in T2) ap = BB_trace(BB) apdict = dict((k,ap(T2[k])) for k in T2) t4 = BB_t4(BB) t4dict = dict((k,t4(T2[k])) for k in T2) if verbose: print("apdict = {}".format(apdict)) print("t4dict = {}".format(t4dict)) v = vector(GF(2),[t4dict[Set([i])] for i in range(r)]) if verbose: print("v = {}".format(v)) def w(i,j): if i==j: return 0 else: return (t4dict[Set([i,j])] + t4dict[Set([i])] + t4dict[Set([j])]) # Note that W ignores the first coordinate Wd = Matrix(GF(2),[[w(i,j) for j in range(1,r)] for i in range(1,r)]) vd = vector(v.list()[1:]) rkWd = Wd.rank() if verbose: print("W' = \n{} with rank {}".format(Wd,rkWd)) # Case 1: rank(W)=2 if rkWd==2: # x' and y' are any two distinct nonzero rows of W Wrows = [wr for wr in Wd.rows() if wr] xd = Wrows[0] yd = next(wr for wr in Wrows if wr!=xd) zd = xd+yd ud = vd - vector(xi*yi for xi,yi in zip(list(xd),list(yd))) if verbose: print("x' = {}".format(xd)) print("y' = {}".format(yd)) print("z' = {}".format(zd)) print("u' = {}".format(ud)) print("v' = {}".format(vd)) u = vector([1]+ud.list()) v = vector([0]+vd.list()) if t4dict[Set([0])]==1: x = vector([1]+xd.list()) y = vector([1]+yd.list()) z = vector([1]+zd.list()) if verbose: print("x = {}".format(x)) print("y = {}".format(y)) print("z = {}".format(z)) print("u = {}".format(u)) print("v = {}".format(v)) else: raise NotImplementedError("t_4(p_1) case not yet implemented in algo64") return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]] # W==0 raise NotImplementedError("rank(W)=0 case not yet implemented in algo64")
def algo63(K, S, BB, T2=None, unit_first = True, verbose=False): r = 1+len(S) if T2 is None: T2 = get_T2(QQ,S, unit_first) if verbose: print("T2 = {}".format(T2)) assert len(T2)==r*(r+1)//2 from KSp import IdealGenerator Sx = [IdealGenerator(P) for P in S] u = -1 if K==QQ else K(K.unit_group().torsion_generator()) Sx = [u] + Sx if unit_first else Sx+[u] if verbose: print("Basis for K(S,2): {}".format(Sx)) BBdict = dict((k,BB(T2[k])) for k in T2) ap = BB_trace(BB) apdict = dict((k,ap(T2[k])) for k in T2) t2 = BB_t2(BB) t2dict = dict((k,t2(T2[k])) for k in T2) if verbose: print("apdict = {}".format(apdict)) print("t2dict = {}".format(t2dict)) v = vector(GF(2),[t2dict[Set([i])] for i in range(r)]) if verbose: print("v = {}".format(v)) def w(i,j): if i==j: return 0 else: return (t2dict[Set([i,j])] + t2dict[Set([i])] + t2dict[Set([j])]) W = Matrix(GF(2),[[w(i,j) for j in range(r)] for i in range(r)]) rkW = W.rank() if verbose: print("W = \n{} with rank {}".format(W,rkW)) # Case 1: rank(W)=2 if rkW==2: # x and y are any two distinct nonzero rows of W Wrows = [wr for wr in W.rows() if wr] x = Wrows[0] y = next(wr for wr in Wrows if wr!=x) z = x+y u = v - vector(xi*yi for xi,yi in zip(list(x),list(y))) if verbose: print("x = {}".format(x)) print("y = {}".format(y)) print("z = {}".format(z)) print("u = {}".format(u)) else: # W==0 # y=0, x=z u = v y = u-u # zero vector if verbose: print("u = {}".format(u)) print("y = {}".format(y)) t3dict = {} for k in T2: t = 1 if t2dict[k]==0 else -1 t3dict[k] = (BBdict[k](t)//8)%2 s = solve_vectors(r,t3dict) if not s: z = x = y # = 0 if verbose: print("x and y are both zero, so class has >4 vertices") else: x, _ = s z = x if verbose: print("x = {}".format(x)) print("y = {}".format(y)) print("z = {}".format(z)) return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]]
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 charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a = 1): """ INPUT: - ``frob_matrix`` -- a matrix representing the p-power Frobenius lift to Z_q up to some precision - ``charpoly_prec`` -- a vector ai, such that, frob_matrix.change_ring(ZZ).charpoly()[i] will be correct mod p^ai, this can be easily deduced from the hodge numbers and knowing the q-adic precision of frob_matrix - ``p`` -- prime p - ``weight`` -- weight of the motive - ``a`` -- q = q^a OUTPUT: a list of integers corresponding to the characteristic polynomial of the Frobenius action Examples: sage: M = Matrix([[O(17), 8 + O(17)], [O(17), 15 + O(17)]]) sage: charpoly_frobenius(M, [2, 1, 1], 17, 1, 1) [17, 2, 1] sage: R = Zq(17 ** 2 , names=('a',)); sage: M = Matrix(R, [[8*17 + 16*17**2 + O(17**3), 8 + 11*17 + O(17**2)], [7*17**2 + O(17**3), 15 + 8*17 + O(17**2)]]) sage: charpoly_frobenius(M, [3, 2, 2], 17, 1, 2) [289, 30, 1] sage: M = Matrix([[8*31 + 8*31**2 + O(31**3), O(31**3), O(31**3), O(31**3)], [O(31**3), 23*31 + 22*31**2 + O(31**3), O(31**3), O(31**3)], [O(31**3), O(31**3), 27 + 7*31 + O(31**3), O(31**3)], [O(31**3), O(31**3), O(31**3), 4 + 23*31 + O(31**3)]]) sage: charpoly_frobenius(M, [4, 3, 2, 2, 2], 31, 1, 1) [961, 0, 46, 0, 1] sage: M = Matrix([[4*43**2 + O(43**3), 17*43 + 11*43**2 + O(43**3), O(43**3), O(43**3), 17 + 37*43 + O(43**3), O(43**3)], [30*43 + 23*43**2 + O(43**3), 5*43 + O(43**3), O(43**3), O(43**3), 3 + 38*43 + O(43**3), O(43**3)], [O(43**3), O(43**3), 9*43 + 32*43**2 + O(43**3), 13 + 25*43 + O(43**3), O(43**3), 17 + 18*43 + O(43**3)], [O(43**3), O(43**3), 22*43 + 25*43**2 + O(43**3), 11 + 24*43 + O(43**3), O(43**3), 36 + 5*43 + O(43**3)], [42*43 + 15*43**2 + O(43**3), 22*43 + 8*43**2 + O(43**3), O(43**3), O(43**3), 29 + 4*43 + O(43**3), O(43**3)], [O(43**3), O(43**3), 6*43 + 19*43**2 + O(43**3), 8 + 24*43 + O(43**3), O(43**3), 31 + 42*43 + O(43**3)]]) sage: charpoly_frobenius(M, [5, 4, 3, 2, 2, 2, 2], 43, 1, 1) [79507, 27735, 6579, 1258, 153, 15, 1] """ if a > 1: F = frob_matrix sigmaF = F; for _ in range(a - 1): sigmaF = Matrix(F.base_ring(), [[elt.frobenius() for elt in row] for row in sigmaF.rows()]) F = F * sigmaF F = F.change_ring(ZZ) else: F = frob_matrix.change_ring(ZZ) cp = F.charpoly().list(); assert len(charpoly_prec) == len(cp) assert cp[-1] == 1; # reduce cp mod prec degree = F.nrows() mod = [0] * (degree + 1) for i in range(degree): mod[i] = p**charpoly_prec[i] cp[i] = cp[i] % mod[i] # figure out the sign if weight % 2 == 1: # for odd weight the sign is always 1 # it's the charpoly of a USp matrix # and charpoly of a symplectic matrix is reciprocal sign = 1 else: for i in range(degree/2): p_power = p ** min( charpoly_prec[i], charpoly_prec[degree - i] + (a*(degree - 2*i)*weight/2)); # Note: degree*weight = 0 mod 2 if cp[i] % p_power != 0 and cp[degree-i] % p_power != 0: if 0 == (cp[i] + cp[degree - i] * p**(a*(degree-2*i)*weight/2)) % p_power: sign = -1; else: sign = 1; assert 0 == (-sign*cp[i] + cp[degree - i] * p**(a*(degree-2*i)*weight/2)) % p_power; break; cp[0] = sign * p**(a*degree*weight/2) #calculate the i-th power sum of the roots and correct cp allong the way halfdegree = ceil(degree/2) + 1; e = [None]*(halfdegree) for k in range(halfdegree): e[k] = cp[degree - k] if (k%2 ==0) else -cp[degree - k] if k > 0: # verify if p^charpoly_prec[degree - k] > 2*degree/k * q^(w*k/2) assert log(k)/log(p) + charpoly_prec[degree - k] > log(2*degree)/log(p) + a*0.5*weight*k, "log(k)/log(p) + charpoly_prec[degree - k] <= log(2*degree)/log(p) + a*0.5*weight*k, k = %d" % k #e[k] = \sum x_{i_1} x_{i_2} ... x_{i_k} # where x_* are eigenvalues # and i_1 < i_2 ... < i_k #s[k] = \sum x_i ^k for i>0 s = [None]*(halfdegree) for k in range(1, halfdegree): # assume that s[i] and e[i] are correct for i < k # e[k] correct modulo mod[degree - k] # S = sum (-1)^i e[k-i] * s[i] # s[k] = (-1)^(k-1) (k*e[k] + S) ==> (-1)^(k-1) s[k] - S = k*e[k] S = sum( (-1)**i * e[k-i] * s[i] for i in range(1,k)) s[k] = (-1)**(k - 1) * (S + k*e[k]) #hence s[k] is correct modulo k*mod[degree - k] localmod = k*mod[degree - k] s[k] = s[k] % localmod # |x_i| = p^(w*0.5) # => s[k] <= degree*p^(a*w*k*0.5) # recall, 2*degree*p^(a*w*k*0.5) /k < mod[degree - k] if s[k] > degree*p**(a*weight*k*0.5) : s[k] = -(-s[k] % localmod); #now correct e[k] with: # (-1)^(k-1) s[k] - S = k*e[k] e[k] = (-S + (-1)**(k - 1) * s[k])//k; assert (-S + (-1)**(k - 1) * s[k])%k == 0 cp[degree - k] = e[k] if k % 2 == 0 else -e[k] cp[k] = sign*cp[degree - k]*p**(a*(degree-2*k)*weight/2) return cp