Commit d465ab3b by Peter Bruin

### substantial improvements inspired by Mascot's paper on Hensel-lifting torsion points

parent 3da06ab8
 ... ... @@ -100,54 +100,30 @@ curve_divisor_IGS (GEN X, GEN W_D, unsigned long i) { multiplication by s induces a map V1 -> V2, return the induced map on quotient spaces. */ GEN curve_divisor_section_as_matrix (GEN X, GEN s, GEN V1, GEN V2, GEN Q1, GEN Q2) { static GEN curve_divisor_section_as_matrix(GEN X, GEN s, GEN C1, GEN piv2, GEN R2) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); pari_sp av = avma; GEN s_V1 = curve_multiply_section_subspace(X, s, V1); GEN M = matsmall_solve(V2, s_V1, p, T); M = matsmall_solve_left(Q1, matsmall_mul(Q2, M, p, T), p, T); GEN s_C1 = curve_multiply_section_subspace(X, s, C1); GEN M = matsmall_mul(R2, rowpermute(s_C1, piv2), p, T); return gerepileupto(av, M); } /* Given an effective divisor D on X, three subspaces V_1, V_2, V_3 of space of the form \Gamma(X,{\cal L}^i) such that V_3 is the product of V_1 and V_2, and quotient maps to the corresponding spaces \Gamma(D,{\cal L}^i), return the bilinear map Q_1 \times Q_2 \to Q_3. such that V_3 is the product of V_1 and V_2, return the induced map on quotient spaces. */ GEN curve_divisor_bilinear_map (GEN X, GEN V1, GEN V2, GEN V3, GEN Q1, GEN Q2, GEN Q3) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); GEN sol, basis, mu; long i, n; static GEN curve_divisor_bilinear_map(GEN X, GEN C1, GEN C2, GEN piv3, GEN R3) { long i, n = lg(C1) - 1; pari_sp av = avma; if(lg(Q1) <= 1 || lg(Q2) <= 1 || lg(Q3) <= 1) pari_err_DIM("curve_divisor_bilinear_map"); n = lg(gel(Q1, 1)) - 1; if(lg(gel(Q2, 1)) - 1 != n || lg(gel(Q3, 1)) - 1 != n) pari_err_DIM("curve_divisor_bilinear_map"); /* Compute a set of vectors in \Gamma(X,{\cal L}) mapping to the standard basis vectors of \Gamma(D,i^*{\cal L}). */ Q1 = matsmall_to_RgM(Q1, p, T); sol = RgM_invimage(Q1, matid(n)); sol = RgM_to_matsmall(sol, p, T); basis = matsmall_mul(V1, sol, p, T); mu = cgetg(n + 1, t_VEC); GEN mu = cgetg(n + 1, t_VEC); for (i = 1; i <= n; i++) gel(mu, i) = curve_divisor_section_as_matrix(X, gel(basis, i), V2, V3, Q2, Q3); gel(mu, i) = curve_divisor_section_as_matrix(X, gel(C1, i), C2, piv3, R3); return gerepileupto(av, mu); } ... ... @@ -172,26 +148,27 @@ curve_divisor_algebra (GEN X, GEN W_D, GEN W_2_D, unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); GEN V = curve_V(X, d); GEN V_2 = curve_V(X, 2 * d); GEN Q = matsmall_quotient(V, W_D, p, T); GEN Q_2 = matsmall_quotient(V_2, W_2_D, p, T); GEN piv2 = curve_pivots_V(X, 2 * d); GEN R_2 = matsmall_coker(rowpermute(W_2_D, piv2), p, T); GEN C; GEN algebra, basis; int try_monogenic = 1; /* TODO: useful criterion */ if (try_monogenic) { GEN s, t, M, N, A, v; GEN s, t, M, N, A = NULL, v; long deg_D = lg(V) - lg(W_D), i; int done = 0; while (1) { s = curve_random_section(X, V); M = curve_divisor_section_as_matrix(X, s, V, V_2, Q, Q_2); if (matsmall_rank(M, p, T) == deg_D) break; } while (!done) { if (A == NULL) { C = matsmall_random_subspace(V, deg_D, 0, p, T); s = curve_random_section(X, V); M = curve_divisor_section_as_matrix(X, s, C, piv2, R_2); } t = curve_random_section(X, V); N = curve_divisor_section_as_matrix(X, t, V, V_2, Q, Q_2); N = curve_divisor_section_as_matrix(X, t, C, piv2, R_2); A = matsmall_solve(M, N, p, T); if (A == NULL) continue; algebra = matsmall_charpoly(A, 0, p, T); while (1) { basis = cgetg(deg_D + 1, t_MAT); ... ... @@ -208,18 +185,19 @@ curve_divisor_algebra (GEN X, GEN W_D, GEN W_2_D, } } } else { GEN mu = curve_divisor_bilinear_map(X, V, V, V_2, Q, Q, Q_2); GEN mu, algebra_basis; C = matsmall_complement(V, W_D, p, T); mu = curve_divisor_bilinear_map(X, C, C, piv2, R_2); /* Compute the algebra \Gamma(D,\O_D) and its action on \Gamma(D,i^*{\cal L}). */ GEN algebra_basis = symmetric_bilinear_map_to_algsmall(mu, p, T); algebra_basis = symmetric_bilinear_map_to_algsmall(mu, p, T); algebra = gel(algebra_basis, 1); basis = gel(algebra_basis, 2); } /* Compute the quotient in terms of the good basis. */ Q = matsmall_solve(basis, Q, p, T); return gerepilecopy(av, mkvec2(algebra, Q)); C = matsmall_mul(C, basis, p, T); return gerepilecopy(av, mkvec2(algebra, C)); } GEN ... ... @@ -298,7 +276,7 @@ curve_decompose_divisor (GEN X, GEN W_D, GEN W_2_D, GEN V = curve_V (X, d); long i, l; pari_sp av; GEN alg_Q, algebra, Q; GEN alg_C, algebra, C; GEN ideals_mult, ideals, points, multiplicities; if(lg(W_D) == lg(V)) { ... ... @@ -309,18 +287,16 @@ curve_decompose_divisor (GEN X, GEN W_D, GEN W_2_D, } av = avma; alg_Q = curve_divisor_algebra(X, W_D, W_2_D, d); algebra = gel(alg_Q, 1); Q = gel(alg_Q, 2); alg_C = curve_divisor_algebra(X, W_D, W_2_D, d); algebra = gel(alg_C, 1); C = gel(alg_C, 2); ideals_mult = algebra_decompose(algebra, p, T); ideals = gel(ideals_mult, 1); multiplicities = gel(ideals_mult, 2); points = cgetg_copy(ideals, &l); for (i = 1; i < l; i++) { GEN tmp = matsmall_inverse_image(Q, gel(ideals, i), p, T); gel(points, i) = matsmall_mul(V, tmp, p, T); } for (i = 1; i < l; i++) gel(points, i) = shallowconcat(W_D, matsmall_mul(C, gel(ideals, i), p, T)); return gerepilecopy(av, mkvec2(points, multiplicities)); } ... ...
 ... ... @@ -5,10 +5,6 @@ GEN curve_divisor_to_point (GEN X, GEN P); GEN curve_point_to_divisor (GEN X, GEN P); GEN curve_point_multiples (GEN X, GEN P); GEN curve_divisor_IGS (GEN X, GEN W_D, unsigned long i); GEN curve_divisor_section_as_matrix (GEN X, GEN s, GEN V1, GEN V2, GEN Q1, GEN Q2); GEN curve_divisor_bilinear_map (GEN X, GEN V1, GEN V2, GEN V3, GEN Q1, GEN Q2, GEN Q3); GEN curve_divisor_algebra (GEN X, GEN W_D, GEN W_2_D, unsigned long d); GEN curve_decompose_divisor (GEN X, GEN W_D, GEN W_2_D, ... ...
 ... ... @@ -260,7 +260,7 @@ jacobian_equal (GEN X, GEN W_D, GEN W_E) { If s != NULL, return a section with divisor D + E + F in *s. */ GEN jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) { jacobian_addflip_cert(GEN X, GEN W_D, GEN W_E, GEN *s, int random) { GEN V = jacobian_V (X); GEN t, W_F; pari_sp av = avma; ... ... @@ -274,7 +274,7 @@ jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) { GEN W0_3_D_E = curve_divide_subspaces (X, W_2_D_E, 4, jacobian_IGS_V_0 (X), 1); GEN W0_5_D_E_F; t = gel(W0_3_D_E, 1); t = random ? curve_random_section(X, W0_3_D_E) : gel(W0_3_D_E, 1); W0_5_D_E_F = curve_multiply_section_subspace(X, t, V); W_F = curve_divide_subspaces(X, W0_5_D_E_F, 5, jacobian_deflate (X, W0_3_D_E), 3); ... ... @@ -289,7 +289,7 @@ jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) { if (jacobian_divisor_small (X, W_D) && jacobian_divisor_small (X, W_E)) { GEN W_D_flip, W_D_E; t = gel(W_D, 1); t = random ? curve_random_section(X, W_D) : gel(W_D, 1); W_D_flip = jacobian_flip(X, W_D, t); W_D_E = curve_divide_subspaces(X, curve_multiply_section_subspace(X, t, W_E), 6, jacobian_deflate(X, W_D_flip), 3); ... ... @@ -319,7 +319,7 @@ jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) { GEN jacobian_addflip (GEN X, GEN W_D, GEN W_E) { return jacobian_addflip_cert (X, W_D, W_E, NULL); return jacobian_addflip_cert(X, W_D, W_E, NULL, 0); } GEN ... ...
 ... ... @@ -38,7 +38,7 @@ int jacobian_is_zero (GEN X, GEN W_D); int jacobian_is_zero_cert (GEN X, GEN W_D, GEN *s); int jacobian_equal (GEN X, GEN W_D, GEN W_E); GEN jacobian_addflip (GEN X, GEN W_D, GEN W_E); GEN jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s); GEN jacobian_addflip_cert(GEN X, GEN W_D, GEN W_E, GEN *s, int random); GEN jacobian_negate (GEN X, GEN W_D); GEN jacobian_add (GEN X, GEN W_D, GEN W_E); GEN jacobian_subtract (GEN X, GEN W_D, GEN W_E); ... ...
 ... ... @@ -10,167 +10,50 @@ static GEN norm_of_section(GEN X, GEN s, GEN V1, GEN V2, GEN Q1, GEN Q2) { norm_of_section(GEN X, GEN s, GEN C1, GEN piv2, GEN R2) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); GEN M = curve_divisor_section_as_matrix(X, s, V1, V2, Q1, Q2); GEN s_C1 = curve_multiply_section_subspace(X, s, C1); GEN M = matsmall_mul(R2, rowpermute(s_C1, piv2), p, T); return matsmall_det(M, p, T); } /* Linearity of the norm functor (thesis, Algorithm IV.2.9, simplified). */ static GEN norm_functor_linearity(GEN X, long i, long j, GEN W_2_E, GEN W_i_2_D1, GEN W_j_2_D2, GEN W_i_j_2_D1_D2, GEN Q_2, GEN Q_i_2_D1, GEN Q_j_2_D2, GEN Q_i_j_2_D1_D2) { static int divisors_disjoint(GEN X, GEN W_D, GEN W_E) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); GEN V_2 = curve_V(X, 2); GEN W_j_4_D2, W_i_j_4_D1_D2; GEN W_j_4_D2_E, W_i_j_4_D1_D2_E; GEN Q_j_4_D2, Q_i_j_4_D1_D2; GEN beta0, beta2; GEN delta0, delta1, delta2, delta3; GEN lambda; pari_sp av = avma; W_j_4_D2 = curve_multiply_subspaces(X, V_2, W_j_2_D2); W_i_j_4_D1_D2 = curve_multiply_subspaces(X, V_2, W_i_j_2_D1_D2); W_j_4_D2_E = curve_multiply_subspaces(X, W_2_E, W_j_2_D2); W_i_j_4_D1_D2_E = curve_multiply_subspaces(X, W_2_E, W_i_j_2_D1_D2); Q_j_4_D2 = matsmall_quotient(W_j_4_D2, W_j_4_D2_E, p, T); Q_i_j_4_D1_D2 = matsmall_quotient(W_i_j_4_D1_D2, W_i_j_4_D1_D2_E, p, T); do { beta0 = curve_random_section(X, V_2); delta0 = norm_of_section(X, beta0, W_j_2_D2, W_j_4_D2, Q_j_2_D2, Q_j_4_D2); } while (gequal0(delta0)); delta1 = norm_of_section(X, beta0, W_i_j_2_D1_D2, W_i_j_4_D1_D2, Q_i_j_2_D1_D2, Q_i_j_4_D1_D2); do { beta2 = curve_random_section(X, W_j_2_D2); delta2 = norm_of_section(X, beta2, V_2, W_j_4_D2, Q_2, Q_j_4_D2); } while (gequal0(delta2)); delta3 = norm_of_section(X, beta2, W_i_2_D1, W_i_j_4_D1_D2, Q_i_2_D1, Q_i_j_4_D1_D2); lambda = gdiv(gmul(delta0, delta3), gmul(delta1, delta2)); return gerepileupto(av, lambda); GEN W_F; W_D = curve_multiply_subspaces(X, W_D, curve_V(X, 1)); W_E = curve_multiply_subspaces(X, W_E, curve_V(X, 1)); W_F = matsmall_image(shallowconcat(W_D, W_E), p, T); return curve_divisor_degree(X, W_F, 3) == 0; } static void quotient_maps(GEN X, GEN D, GEN W_E, GEN *W3_D, GEN *Q3_D) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); long l, m = lg(D) - 2; GEN W3_Dl, W4_Dl_E, W3_Dl_E; *W3_D = cgetg(m + 2, t_VEC); *Q3_D = cgetg(m + 2, t_VEC); for (l = 0; l <= m; l++) { W3_Dl = curve_multiply_subspaces(X, curve_V(X, 1), gel(D, l + 1)); W4_Dl_E = curve_multiply_subspaces(X, gel(D, l + 1), W_E); W3_Dl_E = curve_divide_subspaces(X, W4_Dl_E, 4, curve_IGS_V(X, 1), 1); gel(*W3_D, l + 1) = W3_Dl; gel(*Q3_D, l + 1) = matsmall_quotient(W3_Dl, W3_Dl_E, p, T); static int all_disjoint(GEN X, GEN W_D, GEN W_E) { long i; for (i = 1; i < lg(W_E); i++) { if (!divisors_disjoint(X, W_D, gel(W_E, i))) return 0; } return 1; } static GEN compute_gamma(GEN X, GEN D, GEN c, GEN W_E, GEN s, GEN W2, GEN Q2, GEN W3_D, GEN Q3_D, GEN gamma_0, GEN gamma_1) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); long i, j, l, m = lg(c); GEN Q4_Di_Dj, Q5_Di_Dj_Dl; GEN W6_Di_Dj_Dl, W5_Di_Dj_Dl; GEN W4_Di_Dj, W6_Di_Dj_E, W4_Di_Dj_E; GEN W7_Di_Dj_Dl_E, W5_Di_Dj_Dl_E; GEN gamma, lambda1, lambda2, lambda, M; gamma = cgetg(m + 2, t_VEC); gel(gamma, 1) = gamma_0; gel(gamma, 2) = gamma_1; for (l = 2; l <= m; l++) { i = mael(c, l - 1, 1); j = mael(c, l - 1, 2); W4_Di_Dj = curve_multiply_subspaces(X, gel(D, i + 1), gel(D, j + 1)); W6_Di_Dj_E = curve_multiply_subspaces(X, W4_Di_Dj, W_E); W4_Di_Dj_E = curve_divide_subspaces(X, W6_Di_Dj_E, 6, curve_IGS_V(X, 2), 2); Q4_Di_Dj = matsmall_quotient(W4_Di_Dj, W4_Di_Dj_E, p, T); lambda1 = norm_functor_linearity(X, 1, 1, W_E, gel(W3_D, i + 1), gel(W3_D, j + 1), W4_Di_Dj, Q2, gel(Q3_D, i + 1), gel(Q3_D, j + 1), Q4_Di_Dj); W6_Di_Dj_Dl = curve_multiply_subspaces(X, W4_Di_Dj, gel(D, l + 1)); W5_Di_Dj_Dl = curve_divide_subspaces(X, W6_Di_Dj_Dl, 6, curve_IGS_V(X, 1), 1); W7_Di_Dj_Dl_E = curve_multiply_subspaces(X, W5_Di_Dj_Dl, W_E); W5_Di_Dj_Dl_E = curve_divide_subspaces(X, W7_Di_Dj_Dl_E, 7, curve_IGS_V(X, 2), 2); Q5_Di_Dj_Dl = matsmall_quotient(W5_Di_Dj_Dl, W5_Di_Dj_Dl_E, p, T); M = curve_divisor_section_as_matrix(X, gel(s, l - 1), W2, W5_Di_Dj_Dl, Q2, Q5_Di_Dj_Dl); Q5_Di_Dj_Dl = matsmall_solve(M, Q5_Di_Dj_Dl, p, T); lambda2 = norm_functor_linearity(X, 2, 1, W_E, W4_Di_Dj, gel(W3_D, l + 1), W5_Di_Dj_Dl, Q2, Q4_Di_Dj, gel(Q3_D, l + 1), Q5_Di_Dj_Dl); lambda = gmul(lambda1, lambda2); gel(gamma, l + 1) = gdiv(lambda, gmul(gel(gamma, i + 1), gel(gamma, j + 1))); } return gamma; } /* Compute isomorphisms of the form I^E_{s,t} (thesis, Algorithm IV.3.8). */ static GEN iso(GEN X, GEN c, GEN D, GEN W_E, GEN s, GEN u, GEN v) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); long m = lg(c); GEN W2, Q2, W3_D, Q3_D; GEN gamma, delta, M; pari_sp av = avma; W2 = curve_V(X, 2); Q2 = matsmall_quotient(W2, W_E, p, T); quotient_maps(X, D, W_E, &W3_D, &Q3_D); /* normalise the data for D_0 */ M = curve_divisor_section_as_matrix(X, u, W2, gel(W3_D, 1), Q2, gel(Q3_D, 1)); gel(Q3_D, 1) = matsmall_solve(M, gel(Q3_D, 1), p, T); static void find_disjoint_divisors(GEN J, GEN W_D, GEN *W_E, GEN *u_D0, GEN *W_D0, GEN *u_E0, GEN *W_E0) { while (!divisors_disjoint(J, W_D, *W_E)) *W_E = jacobian_random_presentation(J, *W_E); gamma = compute_gamma(X, D, c, W_E, s, W2, Q2, W3_D, Q3_D, gen_1, gen_1); delta = norm_of_section(X, v, W2, gel(W3_D, m + 1), Q2, gel(Q3_D, m + 1)); return gerepileupto(av, ginv(gmul(gel(gamma, m + 1), delta))); do { *u_D0 = curve_random_section(J, curve_V(J, 1)); *W_D0 = curve_multiply_section_subspace(J, *u_D0, curve_V(J, 1)); } while (!divisors_disjoint(J, *W_D0, *W_E)); do { *u_E0 = curve_random_section(J, curve_V(J, 1)); *W_E0 = curve_multiply_section_subspace(J, *u_E0, curve_V(J, 1)); } while (!divisors_disjoint(J, *W_E0, W_D) || !divisors_disjoint(J, *W_E0, *W_D0)); } /* ... ... @@ -187,8 +70,9 @@ iso(GEN X, GEN c, GEN D, GEN W_E, GEN s, GEN u, GEN v) { */ static void torsion_data(GEN J, GEN W_D, GEN W_D0, GEN c, GEN *D, GEN *s, GEN *v) { GEN *D, GEN *s, GEN *v, GEN W_avoid) { long i, j, l, m = lg(c); int random = (W_avoid != NULL); *D = cgetg(m + 2, t_VEC); *s = cgetg(m, t_VEC); ... ... @@ -197,13 +81,57 @@ torsion_data(GEN J, GEN W_D, GEN W_D0, GEN c, for (l = 2; l <= m; l++) { i = mael(c, l - 1, 1); j = mael(c, l - 1, 2); gel(*D, l + 1) = jacobian_addflip_cert(J, gel(*D, i + 1), gel(*D, j + 1), &gel(*s, l - 1)); do { gel(*D, l + 1) = jacobian_addflip_cert(J, gel(*D, i + 1), gel(*D, j + 1), &gel(*s, l - 1), random); } while (random && !all_disjoint(J, gel(*D, l + 1), W_avoid)); } if (!jacobian_is_zero_cert(J, gel(*D, m + 1), v)) pari_err(e_MISC, "inconsistent: line bundle is non-trivial"); } static GEN eval_half(GEN X, GEN c, GEN u, GEN D, GEN s, GEN v, GEN W_E) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); long i, j, l, m = lg(c); GEN u3, W2, C2, piv3, W3_E, R3, piv5, W5_E, R5, gamma, sigma, tau; W2 = curve_V(X, 2); C2 = matsmall_complement(W2, W_E, p, T); piv3 = curve_pivots_V(X, 3); W3_E = curve_multiply_subspaces(X, curve_V(X, 1), W_E); R3 = matsmall_coker(rowpermute(W3_E, piv3), p, T); piv5 = curve_pivots_V(X, 5); W5_E = curve_multiply_subspaces(X, W2, W3_E); R5 = matsmall_coker(rowpermute(W5_E, piv5), p, T); u3 = curve_multiply_sections(X, u, curve_multiply_sections(X, u, u)); tau = norm_of_section(X, u3, C2, piv5, R5); gamma = cgetg(m + 2, t_VEC); gel(gamma, 1) = gen_1; gel(gamma, 2) = gen_1; for (l = 2; l <= m; l++) { i = mael(c, l - 1, 1); j = mael(c, l - 1, 2); sigma = norm_of_section(X, gel(s, l - 1), C2, piv5, R5); gel(gamma, l + 1) = gdiv(tau, gmul(sigma, gmul(gel(gamma, i + 1), gel(gamma, j + 1)))); } return gmul(gel(gamma, m + 1), gdiv(norm_of_section(X, v, C2, piv3, R3), norm_of_section(X, u, C2, piv3, R3))); } static GEN eval_function(GEN J, GEN c, GEN W_D, GEN W_D0, GEN u_D0, GEN W_E, GEN W_E0) { GEN D, s, v; torsion_data(J, W_D, W_D0, c, &D, &s, &v, mkvec2(W_E, W_E0)); return gdiv(eval_half(J, c, u_D0, D, s, v, W_E), eval_half(J, c, u_D0, D, s, v, W_E0)); } /* Compute the Tate-Lichtenbaum-Frey-Rück pairing: let m be a positive integer not divisible by the characteristic of the ... ... @@ -224,84 +152,20 @@ torsion_data(GEN J, GEN W_D, GEN W_D0, GEN c, GEN jacobian_tate_pairing(GEN J, GEN W_D, GEN W_E, long n) { GEN q = curve_base_field_cardinality(J); GEN c, D, W_D0, s, u, v, Iplus, Iminus; GEN c, u_D0, W_D0, u_E0, W_E0, f_E; pari_sp av = avma; if (n <= 0 || smodis(q, n) != 1) pari_err(e_MISC, "base field does not contain the roots of unity of order %li", n); pari_err(e_MISC, "base field does not contain " "the roots of unity of order %li", n); if (jacobian_type(J) != JACOBIAN_TYPE_MEDIUM) pari_err_IMPL("jacobian_tate_pairing for non-medium models"); c = addflip_chain(stoi(n)); u = gel(curve_V(J, 1), 1); W_D0 = curve_multiply_section_subspace(J, u, curve_V(J, 1)); torsion_data(J, W_D, W_D0, c, &D, &s, &v); Iplus = iso(J, c, D, jacobian_zero(J), s, u, v); Iminus = iso(J, c, D, W_E, s, u, v); return gerepileupto(av, powgi(gdiv(Iplus, Iminus), diviuexact(subis(q, 1), n))); } static GEN eval_half(GEN X, GEN c, GEN u, GEN D, GEN s, GEN v, GEN W_E) { unsigned long p = curve_base_field_characteristic(X); GEN T = curve_base_field_polynomial(X); long m = lg(c); GEN W2, Q2, W3, Q3, W3_E, W3_D, Q3_D; GEN gamma_0, gamma_1, gamma, delta, M0, M1; pari_sp av = avma; W2 = curve_V(X, 2); Q2 = matsmall_quotient(W2, W_E, p, T); W3 = curve_V(X, 3); W3_E = curve_multiply_subspaces(X, curve_V(X, 1), W_E); Q3 = matsmall_quotient(W3, W3_E, p, T); quotient_maps(X, D, W_E, &W3_D, &Q3_D); gamma_0 = norm_of_section(X, u, W2, gel(W3_D, 1), Q2, gel(Q3_D, 1)); M0 = matsmall_solve_left(gel(Q3_D, 1), matsmall_mul(Q3, matsmall_solve(W3, gel(W3_D, 1), p, T), p, T), p, T); M1 = matsmall_solve_left(gel(Q3_D, 2), matsmall_mul(Q3, matsmall_solve(W3, gel(W3_D, 2), p, T), p, T), p, T); gamma_1 = gmul(matsmall_det(matsmall_solve(M0, M1, p, T), p, T), gamma_0); gamma = compute_gamma(X, D, c, W_E, s, W2, Q2, W3_D, Q3_D, gamma_0, gamma_1); delta = norm_of_section(X, v, W2, gel(W3_D, m + 1), Q2, gel(Q3_D, m + 1)); return gerepileupto(av, ginv(gmul(gel(gamma, m + 1), delta))); } static GEN eval_function(GEN J, GEN c, GEN W_D, GEN W_D0, GEN u_D0, GEN W_E, GEN W_E0) { GEN D, s, v; torsion_data(J, W_D, W_D0, c, &D, &s, &v); return gdiv(eval_half(J, c, u_D0, D, s, v, W_E), eval_half(J, c, u_D0, D, s, v, W_E0)); } static long divisors_disjoint(GEN J, GEN W_D, GEN W_E) { unsigned long p = curve_base_field_characteristic(J); GEN T = curve_base_field_polynomial(J); GEN W_F; W_D = curve_multiply_subspaces(J, W_D, curve_V(J, 1)); W_E = curve_multiply_subspaces(J, W_E, curve_V(J, 1)); W_F = matsmall_image(shallowconcat(W_D, W_E), p, T); return curve_divisor_degree(J, W_F, 3) == 0; find_disjoint_divisors(J, W_D, &W_E, &u_D0, &W_D0, &u_E0, &W_E0); f_E = eval_function(J, c, W_D, W_D0, u_D0, W_E, W_E0);