From e05bf77824a1ec5d4deef07d56a84d88b4639450 Mon Sep 17 00:00:00 2001 From: jgarnek Date: Mon, 10 Jun 2024 17:55:49 +0000 Subject: [PATCH] arbitrary p-gp covers, pt 1 --- as_covers/as_auxilliary.sage | 32 ++ as_covers/as_cech_class.sage | 12 +- as_covers/as_cover_class.sage | 44 ++ as_covers/as_form_class.sage | 9 +- as_covers/as_function_class.sage | 6 +- as_covers/as_polyforms.sage | 7 +- as_covers/group_action_matrices.sage | 13 +- as_covers/holomorphic_combinations.sage | 45 +- auxilliaries/hensel.sage | 2 +- elementary_covers/as_auxilliary.sage | 58 +++ elementary_covers/as_cech_class.sage | 112 +++++ elementary_covers/as_cover_class.sage | 444 ++++++++++++++++++ elementary_covers/as_form_class.sage | 205 ++++++++ elementary_covers/as_function_class.sage | 202 ++++++++ elementary_covers/as_polyforms.sage | 221 +++++++++ elementary_covers/as_reduction.sage | 33 ++ elementary_covers/as_transform.sage | 42 ++ elementary_covers/combination_components.sage | 14 + elementary_covers/dual_element.sage | 26 + elementary_covers/group_action_matrices.sage | 53 +++ .../holomorphic_combinations.sage | 149 ++++++ elementary_covers/ith_magical_component.sage | 6 + elementary_covers/tests/as_cover_test.sage | 26 + .../tests/as_polyforms_test.sage | 27 ++ elementary_covers/tests/cartier_test.sage | 11 + elementary_covers/tests/diffn_test.sage | 15 + .../tests/dual_element_test.sage | 20 + .../tests/group_action_matrices_test.sage | 18 + .../tests/ith_component_test.sage | 15 + .../tests/ith_ramification_gp_test.sage | 20 + .../tests/ramification_jumps_test.sage | 25 + elementary_covers/tests/uniformizer_test.sage | 12 + heisenberg_covers/heisenberg_covers.sage | 39 ++ heisenberg_covers/heisenberg_form_class.sage | 11 +- .../heisenberg_function_class.sage | 9 +- quaternion_covers/quaternion_form_class.sage | 2 +- .../quaternion_function_class.sage | 2 +- 37 files changed, 1968 insertions(+), 19 deletions(-) create mode 100644 elementary_covers/as_auxilliary.sage create mode 100644 elementary_covers/as_cech_class.sage create mode 100644 elementary_covers/as_cover_class.sage create mode 100644 elementary_covers/as_form_class.sage create mode 100644 elementary_covers/as_function_class.sage create mode 100644 elementary_covers/as_polyforms.sage create mode 100644 elementary_covers/as_reduction.sage create mode 100644 elementary_covers/as_transform.sage create mode 100644 elementary_covers/combination_components.sage create mode 100644 elementary_covers/dual_element.sage create mode 100644 elementary_covers/group_action_matrices.sage create mode 100644 elementary_covers/holomorphic_combinations.sage create mode 100644 elementary_covers/ith_magical_component.sage create mode 100644 elementary_covers/tests/as_cover_test.sage create mode 100644 elementary_covers/tests/as_polyforms_test.sage create mode 100644 elementary_covers/tests/cartier_test.sage create mode 100644 elementary_covers/tests/diffn_test.sage create mode 100644 elementary_covers/tests/dual_element_test.sage create mode 100644 elementary_covers/tests/group_action_matrices_test.sage create mode 100644 elementary_covers/tests/ith_component_test.sage create mode 100644 elementary_covers/tests/ith_ramification_gp_test.sage create mode 100644 elementary_covers/tests/ramification_jumps_test.sage create mode 100644 elementary_covers/tests/uniformizer_test.sage diff --git a/as_covers/as_auxilliary.sage b/as_covers/as_auxilliary.sage index 503995e..4b281c5 100644 --- a/as_covers/as_auxilliary.sage +++ b/as_covers/as_auxilliary.sage @@ -24,3 +24,35 @@ def magma_module_decomposition(A, B, text = False, prefix="", sufix="", matrices if text: return result return(magma_free(result)) + +def magma_is_isomorphic(A1, B1, A2, B2, text=0): + q = parent(A1).base_ring().order() + p = q.factor()[0][0] + n = A1.dimensions()[0] + A1 = str(list(A1)) + B1 = str(list(B1)) + A2 = str(list(A2)) + B2 = str(list(B2)) + A1 = A1.replace("(", "") + A1 = A1.replace(")", "") + A2 = A2.replace("(", "") + A2 = A2.replace(")", "") + B1 = B1.replace("(", "") + B1 = B1.replace(")", "") + B2 = B2.replace("(", "") + B2 = B2.replace(")", "") + result = "" + if q != p: + result += "F := GF(" + str(q) + ");" + result += "A1 := MatrixAlgebra = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + S = [(eta, eta.expansion_at_infty())] + pr = [list(GF(p)) for _ in range(n)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + ff = as_function(self, prod(z[i1]^(k[i1]) for i1 in range(n))/x^i*y^j) + ff_exp = ff.diffn().expansion_at_infty() + if ff_exp != 0*ff_exp: + S += [(ff, ff_exp)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + ff = as_function(self, prod(z[i1]^(k[i1]) for i1 in range(n))*x^i*y^j) + ff_exp = ff.diffn().expansion_at_infty() + if ff_exp != 0*ff_exp: + S += [(ff, ff_exp)] + forms = holomorphic_combinations_mixed(S) + if len(forms) <= self.genus(): + raise ValueError("Increase threshold!") + result = [] + for ff in forms: + if ff[0] != 0*self.dx: + result += [as_cech(self, ff[0], -ff[1])] + return result + raise ValueError("Unknown.") def de_rham_basis(self, holo_basis = 0, cohomology_basis = 0, threshold = 30): if holo_basis == 0: diff --git a/as_covers/as_form_class.sage b/as_covers/as_form_class.sage index 0b20167..35af778 100644 --- a/as_covers/as_form_class.sage +++ b/as_covers/as_form_class.sage @@ -15,6 +15,9 @@ class as_form: def __repr__(self): return "(" + str(self.form)+") * dx" + def __eq__(self, other): + return self.expansion_at_infty() == other.expansion_at_infty() + def expansion_at_infty(self, place = 0): C = self.curve delta = C.nb_of_pts_at_infty @@ -80,6 +83,10 @@ class as_form: C = self.curve omega = self.form return as_form(C, constant*omega) + + def reduce(self): + aux = as_reduction(self.curve, self.form) + return as_form(self.curve, aux) def group_action(self, ZN_tuple): C = self.curve @@ -121,7 +128,7 @@ class as_form: result = result.form Rxy. = PolynomialRing(F, 2) Qxy = FractionField(Rxy) - result = as_reduction(AS, result) + result = as_reduction(C, result) return superelliptic_form(C_super, Qxy(result)) def residue(self, place=0): diff --git a/as_covers/as_function_class.sage b/as_covers/as_function_class.sage index abd84a0..a72b3bc 100644 --- a/as_covers/as_function_class.sage +++ b/as_covers/as_function_class.sage @@ -132,6 +132,10 @@ class as_function: g = self.function return as_function(C, g.substitute(sub_list)) + def reduce(self): + aux = as_reduction(self.curve, self.function) + return as_function(self.curve, aux) + def trace(self): C = self.curve C_super = C.quotient @@ -151,7 +155,7 @@ class as_function: result = result.function Rxy. = PolynomialRing(F, 2) Qxy = FractionField(Rxy) - result = as_reduction(AS, result) + result = as_reduction(C, result) return superelliptic_function(C_super, Qxy(result)) def coordinates(self, prec = 100, basis = 0): diff --git a/as_covers/as_polyforms.sage b/as_covers/as_polyforms.sage index 5f688cd..cc6f35d 100644 --- a/as_covers/as_polyforms.sage +++ b/as_covers/as_polyforms.sage @@ -11,8 +11,8 @@ class as_polyform: def __repr__(self): return '(' + str(self.form) + ') dx⊗' + str(self.mult) - def expansion_at_infty(self): - return self.form.expansion_at_infty()*(self.curve.dx.expansion_at_infty())^(self.mult) + def expansion_at_infty(self, place): + return self.form.expansion_at_infty(place=place)*(self.curve.dx.expansion_at_infty(place=place))^(self.mult) def coordinates(self, basis = 0): """Find coordinates of the given holomorphic form self in terms of the basis forms in a list holo.""" @@ -27,6 +27,9 @@ class as_polyform: self_with_no_denominator = denom*self.form.function return linear_representation_polynomials(Rxyz(self_with_no_denominator), [Rxyz(omega) for omega in basis]) + def group_action(self, elt): + return as_polyform(self.form.group_action(elt), self.mult) + def as_holo_polydifferentials_basis(AS, mult, threshold = 8): '''Give the basis of H^0(Ω^⊗n) for n = mult.''' diff --git a/as_covers/group_action_matrices.sage b/as_covers/group_action_matrices.sage index 5e0d846..e1be8b1 100644 --- a/as_covers/group_action_matrices.sage +++ b/as_covers/group_action_matrices.sage @@ -23,18 +23,19 @@ def as_group_action_matrices_holo(AS, basis=0, threshold=10): as_cover.group_action_matrices_holo = as_group_action_matrices_holo -def as_group_action_matrices_dR(AS, threshold=8): +def as_group_action_matrices_dR(AS, basis = 0, threshold=8): n = AS.height generators = [] + F = AS.base_ring for i in range(n): ei = n*[0] ei[i] = 1 generators += [ei] - holo_basis = AS.holomorphic_differentials_basis(threshold = threshold) - str_basis = AS.cohomology_of_structure_sheaf_basis(holo_basis = holo_basis, threshold = threshold) - dr_basis = AS.de_rham_basis(holo_basis = holo_basis, cohomology_basis = str_basis, threshold=threshold) - F = AS.base_ring - basis = [holo_basis, str_basis, dr_basis] + if basis == 0: + holo_basis = AS.holomorphic_differentials_basis(threshold = threshold) + str_basis = AS.cohomology_of_structure_sheaf_basis(holo_basis = holo_basis, threshold = threshold) + dr_basis = AS.de_rham_basis(holo_basis = holo_basis, cohomology_basis = str_basis, threshold=threshold) + basis = [holo_basis, str_basis, dr_basis] return as_group_action_matrices(F, basis[2], generators, basis = basis) as_cover.group_action_matrices_dR = as_group_action_matrices_dR diff --git a/as_covers/holomorphic_combinations.sage b/as_covers/holomorphic_combinations.sage index b5fcf34..6f931b0 100644 --- a/as_covers/holomorphic_combinations.sage +++ b/as_covers/holomorphic_combinations.sage @@ -22,7 +22,7 @@ def holomorphic_combinations(S): # Sprawdzamy, jakim formom odpowiadają elementy V. forms = [] for vec in V.basis(): - forma_holo = 0*C_AS.dx + forma_holo = 0*S[0][0] forma_holo_power_series = Rt(0) for vec_wspolrzedna, elt_S in zip(vec, S): eta = elt_S[0] @@ -32,6 +32,49 @@ def holomorphic_combinations(S): forms += [forma_holo] return forms +def holomorphic_combinations_mixed(S): + """Given a list S of pairs (form, corresponding Laurent series at some pt), find their combinations holomorphic at that pt.""" + C_AS = S[0][0].curve + p = C_AS.characteristic + F = C_AS.base_ring + prec = C_AS.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + RtQ = FractionField(Rt) + minimal_valuation = min([g[1].valuation() for g in S]) + print(minimal_valuation) + if minimal_valuation >= 0: + return [s[0] for s in S] + list_of_lists = [] #to będzie lista złożona z list współczynników część nieholomorficznych rozwinięcia form z S + for eta, eta_exp in S: + a = -minimal_valuation + eta_exp.valuation() + list_coeffs = a*[0] + eta_exp.list() + (-minimal_valuation)*[0] + list_coeffs = list_coeffs[:-minimal_valuation] + list_of_lists += [list_coeffs] + M = matrix(F, list_of_lists) + V = M.kernel() #chcemy wyzerować części nieholomorficzne, biorąc kombinacje form z S + + + # Sprawdzamy, jakim formom odpowiadają elementy V. + forms = [] + for vec in V.basis(): + forma_holo = 0*S[0][0] + forma_holo_power_series = Rt(0) + res1 = 0*C_AS.dx + res2 = 0*C_AS.x + res = 0*C_AS.dx + for vec_wspolrzedna, elt_S in zip(vec, S): + eta = elt_S[0] + if isinstance(eta, as_form): + res += vec_wspolrzedna*eta + res1 += vec_wspolrzedna*eta + if isinstance(eta, as_function): + res += vec_wspolrzedna*eta.diffn() + res2 += vec_wspolrzedna*eta + #eta_exp = elt_S[1] + #forma_holo_power_series += vec_wspolrzedna*eta_exp + forms += [(res1, res2)] + return forms + def holomorphic_combinations_fcts(S, pole_order): '''given a set S of (form, corresponding Laurent series at some pt), find their combinations holomorphic at that pt''' C_AS = S[0][0].curve diff --git a/auxilliaries/hensel.sage b/auxilliaries/hensel.sage index 3b35849..e5d055d 100644 --- a/auxilliaries/hensel.sage +++ b/auxilliaries/hensel.sage @@ -10,7 +10,7 @@ def naive_hensel(fct, F, start = 1, prec=10): #while fct not in RptW: # print(fct) # fct *= W - alpha = (fct.derivative())(W = start) + alpha = (fct.derivative())(W = RtQ(start)) w0 = Rt(start) i = 1 while(i < prec): diff --git a/elementary_covers/as_auxilliary.sage b/elementary_covers/as_auxilliary.sage new file mode 100644 index 0000000..4b281c5 --- /dev/null +++ b/elementary_covers/as_auxilliary.sage @@ -0,0 +1,58 @@ +def magma_module_decomposition(A, B, text = False, prefix="", sufix="", matrices=True): + """Find decomposition of Z/p^2-module given by matrices A, B into indecomposables using magma. + If text = True, print the command for Magma. Else - return the output of Magma free.""" + q = parent(A).base_ring().order() + p = q.factor()[0][0] + n = A.dimensions()[0] + A = str(list(A)) + B = str(list(B)) + A = A.replace("(", "") + A = A.replace(")", "") + B = B.replace("(", "") + B = B.replace(")", "") + result = prefix + if q != p: + result += "F := GF(" + str(q) + ");" + result += "A := MatrixAlgebra = PolynomialRing(F, 2) + Rt. = LaurentSeriesRing(F, default_prec=prec) + + all_x_series = {} + all_y_series = {} + all_z_series = {} + all_dx_series = {} + all_jumps = {} + + for pt in self.branch_points: + x_series = superelliptic_function(C, x).expansion(pt=pt, prec=prec) + y_series = superelliptic_function(C, y).expansion(pt=pt, prec=prec) + z_series = [] + jumps = [] + n = len(list_of_fcts) + list_of_power_series = [g.expansion(pt=pt, prec=prec) for g in list_of_fcts] + for j in range(n): + power_series = list_of_power_series[j] + jump, correction, t_old, z = artin_schreier_transform(power_series, prec = prec) + x_series = x_series(t = t_old) + y_series = y_series(t = t_old) + z_series = [zi(t = t_old) for zi in z_series] + z_series += [z] + jumps += [jump] + list_of_power_series = [g(t = t_old) for g in list_of_power_series] + + all_jumps[pt] = jumps + all_x_series[pt] = x_series + all_y_series[pt] = y_series + all_z_series[pt] = z_series + all_dx_series[pt] = x_series.derivative() + self.jumps = all_jumps + self.x_series = all_x_series + self.y_series = all_y_series + self.z_series = all_z_series + self.dx_series = all_dx_series + ############## + #Function field + variable_names = 'x, y' + for i in range(n): + variable_names += ', z' + str(i) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + self.fct_field = (RxyzQ, Rxyz, x, y, z) + self.x = as_function(self, x) + self.y = as_function(self, y) + self.z = [as_function(self, z[j]) for j in range(n)] + self.dx = as_form(self, 1) + self.one = as_function(self, 1) + + + def __repr__(self): + n = self.height + p = self.characteristic + if n==1: + return "(Z/p)-cover of " + str(self.quotient)+" with the equation:\n z^" + str(p) + " - z = " + str(self.functions[0]) + + result = "(Z/p)^"+str(self.height)+ "-cover of " + str(self.quotient)+" with the equations:\n" + for i in range(n): + result += 'z' + str(i) + "^" + str(p) + " - z" + str(i) + " = " + str(self.functions[i]) + "\n" + return result + + def genus(self): + jumps = self.jumps + gY = self.quotient.genus() + n = self.height + branch_pts = self.branch_points + p = self.characteristic + return p^n*gY + (p^n - 1)*(len(branch_pts) - 1) + sum(p^(n-j-1)*(jumps[pt][j]-1)*(p-1)/2 for j in range(n) for pt in branch_pts) + + def exponent_of_different(self, place = 0): + jumps = self.jumps + n = self.height + delta = self.nb_of_pts_at_infty + p = self.characteristic + return sum(p^(n-j-1)*(jumps[place][j]+1)*(p-1) for j in range(n)) + + def exponent_of_different_prim(self, place = 0): + jumps = self.jumps + n = self.height + delta = self.nb_of_pts_at_infty + p = self.characteristic + return sum(p^(n-j-1)*(jumps[place][j])*(p-1) for j in range(n)) + + def holomorphic_differentials_basis(self, threshold = 8): + from itertools import product + x_series = self.x_series + y_series = self.y_series + z_series = self.z_series + dx_series = self.dx_series + delta = self.nb_of_pts_at_infty + p = self.characteristic + n = self.height + prec = self.prec + C = self.quotient + F = self.base_ring + m = C.exponent + r = C.polynomial.degree() + RxyzQ, Rxyz, x, y, z = self.fct_field + Rt. = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + S = [] + pr = [list(GF(p)) for _ in range(n)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + eta = as_form(self, x^i * prod(z[i1]^(k[i1]) for i1 in range(n))/y^j) + eta_exp = eta.expansion(pt=self.branch_points[0]) + S += [(eta, eta_exp)] + + forms = holomorphic_combinations(S) + + for pt in self.branch_points[1:]: + forms = [(omega, omega.expansion(pt=pt)) for omega in forms] + forms = holomorphic_combinations(forms) + + if len(forms) < self.genus(): + print("I haven't found all forms, only ", len(forms), " of ", self.genus()) + return holomorphic_differentials_basis(self, threshold = threshold + 1) + if len(forms) > self.genus(): + raise ValueError("Increase precision.") + return forms + + def cartier_matrix(self, prec=50): + g = self.genus() + F = self.base_ring + M = matrix(F, g, g) + for i, omega in enumerate(self.holomorphic_differentials_basis()): + M[:, i] = vector(omega.cartier().coordinates()) + return M + + def at_most_poles(self, pole_order, threshold = 8): + """ Find fcts with pole order in infty's at most pole_order. Threshold gives a bound on powers of x in the function. + If you suspect that you haven't found all the functions, you may increase it.""" + from itertools import product + x_series = self.x_series + y_series = self.y_series + z_series = self.z_series + delta = self.nb_of_pts_at_infty + p = self.characteristic + n = self.height + prec = self.prec + C = self.quotient + F = self.base_ring + m = C.exponent + r = C.polynomial.degree() + RxyzQ, Rxyz, x, y, z = self.fct_field + F = C.base_ring + Rt. = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + S = [] + RQxyz = FractionField(Rxyz) + pr = [list(GF(p)) for _ in range(n)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + eta = as_function(self, x^i * prod(z[i1]^(k[i1]) for i1 in range(n))*y^j) + eta_exp = eta.expansion_at_infty() + S += [(eta, eta_exp)] + + forms = holomorphic_combinations_fcts(S, pole_order) + + for i in range(1, delta): + forms = [(omega, omega.expansion_at_infty(place = i)) for omega in forms] + forms = holomorphic_combinations_fcts(forms, pole_order) + + return forms + + def magical_element(self, threshold = 8): + list_of_elts = self.at_most_poles(self.exponent_of_different_prim(), threshold) + result = [] + for a in list_of_elts: + if a.trace().function != 0: + result += [a] + return result + + def pseudo_magical_element(self, threshold = 8): + list_of_elts = self.at_most_poles(self.exponent_of_different(), threshold) + result = [] + for a in list_of_elts: + if a.trace().function != 0: + result += [a] + return result + + def at_most_poles_forms(self, pole_order, threshold = 8): + """Find forms with pole order in all the points at infty equat at most to pole_order. Threshold gives a bound on powers of x in the form. + If you suspect that you haven't found all the functions, you may increase it.""" + from itertools import product + x_series = self.x_series + y_series = self.y_series + z_series = self.z_series + delta = self.nb_of_pts_at_infty + p = self.characteristic + n = self.height + prec = self.prec + C = self.quotient + F = self.base_ring + m = C.exponent + r = C.polynomial.degree() + RxyzQ, Rxyz, x, y, z = self.fct_field + Rt. = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + S = [] + RQxyz = FractionField(Rxyz) + pr = [list(GF(p)) for _ in range(n)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + eta = as_form(self, x^i * prod(z[i1]^(k[i1]) for i1 in range(n))/y^j) + eta_exp = eta.expansion_at_infty() + S += [(eta, eta_exp)] + + forms = holomorphic_combinations_forms(S, pole_order) + + for pt in self.branch_points[1:]: + forms = [(omega, omega.expansion(pt=pt)) for omega in forms] + forms = holomorphic_combinations_forms(forms, pole_order) + + return forms + + def uniformizer(self, place = 0): + '''Return uniformizer of curve self at place-th place at infinity.''' + p = self.characteristic + n = self.height + F = self.base_ring + RxyzQ, Rxyz, x, y, z = self.fct_field + fx = as_function(self, x) + z = [as_function(self, zi) for zi in z] + # We create a list of functions. We add there all variables... + list_of_fcts = [fx]+z + vfx = fx.valuation(place) + vz = [zi.valuation(place) for zi in z] + + # Then we subtract powers of variables with the same valuation (so that 1/t^(kp) cancels) and add to this list. + for j1 in range(n): + for j2 in range(n): + if j1>j2: + a = gcd(vz[j1] , vz[j2]) + vz1 = vz[j1]/a + vz2 = vz[j2]/a + for b in F: + if (z[j1]^(vz2) - b*z[j2]^(vz1)).valuation(place) > (z[j2]^(vz1)).valuation(place): + list_of_fcts += [z[j1]^(vz2) - b*z[j2]^(vz1)] + for j1 in range(n): + a = gcd(vz[j1], vfx) + vzj = vz[j1] /a + vfx = vfx/a + for b in F: + if (fx^(vzj) - b*z[j1]^(vfx)).valuation(place) > (z[j1]^(vfx)).valuation(place): + list_of_fcts += [fx^(vzj) - b*z[j1]^(vfx)] + #Finally, we check if on the list there are two elements with the same valuation. + for f1 in list_of_fcts: + for f2 in list_of_fcts: + d, a, b = xgcd(f1.valuation(place), f2.valuation(place)) + if d == 1: + return f1^a*f2^b + raise ValueError("My method of generating fcts with relatively prime valuation failed.") + + + def ith_ramification_gp(self, i, place = 0): + '''Find ith ramification group at place at infty of nb place.''' + G = self.group + t = self.uniformizer(place) + Gi = [G[0]] + for g in G: + if g != G[0]: + tg = t.group_action(g) + v = (tg - t).valuation(place) + if v >= i+1: + Gi += [g] + return Gi + + def ramification_jumps(self, place = 0): + '''Return list of lower ramification jumps at at place at infty of nb place.''' + G = self.group + ramification_jps = [] + i = 0 + while len(G) > 1: + Gi = self.ith_ramification_gp(i+1, place) + if len(Gi) < len(G): + ramification_jps += [i] + G = Gi + i+=1 + return ramification_jps + + def a_number(self): + g = self.genus() + return g - self.cartier_matrix().rank() + + def cohomology_of_structure_sheaf_basis(self, holo_basis = 0, threshold = 8): + if holo_basis == 0: + holo_basis = self.holomorphic_differentials_basis(threshold = threshold) + from itertools import product + x_series = self.x_series + y_series = self.y_series + z_series = self.z_series + delta = self.nb_of_pts_at_infty + p = self.characteristic + n = self.height + prec = self.prec + C = self.quotient + F = self.base_ring + m = C.exponent + r = C.polynomial.degree() + RxyzQ, Rxyz, x, y, z = self.fct_field + Rt. = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + result_fcts = [] + V = VectorSpace(F,self.genus()) + S = V.subspace([]) + RQxyz = FractionField(Rxyz) + pr = [list(GF(p)) for _ in range(n)] + i = 0 + while len(result_fcts) < self.genus(): + for j in range(0, m): + for k in product(*pr): + f = as_function(self, prod(z[i1]^(k[i1]) for i1 in range(n))/x^i*y^j) + f_products = [omega.serre_duality_pairing(f) for omega in holo_basis] + if vector(f_products) not in S: + S = S+V.subspace([V(f_products)]) + result_fcts += [f] + i += 1 + return result_fcts + + def lift_to_de_rham(self, fct, threshold = 30): + '''Given function fct, find form eta regular on affine part such that eta - d(fct) is regular in infty. (Works for one place at infty now)''' + from itertools import product + x_series = self.x_series + y_series = self.y_series + z_series = self.z_series + dx_series = self.dx_series + delta = self.nb_of_pts_at_infty + p = self.characteristic + n = self.height + prec = self.prec + C = self.quotient + F = self.base_ring + m = C.exponent + r = C.polynomial.degree() + RxyzQ, Rxyz, x, y, z = self.fct_field + Rt. = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + S = [(fct.diffn(), fct.diffn().expansion_at_infty())] + pr = [list(GF(p)) for _ in range(n)] + holo = self.holomorphic_differentials_basis(threshold = threshold) + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + eta = as_form(self, x^i*prod(z[i1]^(k[i1]) for i1 in range(n))/y^j) + eta_exp = eta.expansion_at_infty() + S += [(eta, eta_exp)] + forms = holomorphic_combinations(S) + if len(forms) <= self.genus(): + raise ValueError("Increase threshold!") + for omega in forms: + for a in F: + if (a*omega + fct.diffn()).is_regular_on_U0(): + return a*omega + fct.diffn() + raise ValueError("Unknown.") + + def lift_to_de_rham_form(self, eta, threshold = 20): + '''Given form eta regular on affine part find fct such that eta - d(fct) is regular in infty. (Works for one place at infty now)''' + from itertools import product + x_series = self.x_series + y_series = self.y_series + z_series = self.z_series + dx_series = self.dx_series + delta = self.nb_of_pts_at_infty + p = self.characteristic + n = self.height + prec = self.prec + C = self.quotient + F = self.base_ring + m = C.exponent + r = C.polynomial.degree() + RxyzQ, Rxyz, x, y, z = self.fct_field + Rt. = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + S = [(eta, eta.expansion_at_infty())] + pr = [list(GF(p)) for _ in range(n)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + ff = as_function(self, prod(z[i1]^(k[i1]) for i1 in range(n))/x^i*y^j) + ff_exp = ff.diffn().expansion_at_infty() + if ff_exp != 0*ff_exp: + S += [(ff, ff_exp)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + ff = as_function(self, prod(z[i1]^(k[i1]) for i1 in range(n))*x^i*y^j) + ff_exp = ff.diffn().expansion_at_infty() + if ff_exp != 0*ff_exp: + S += [(ff, ff_exp)] + forms = holomorphic_combinations_mixed(S) + if len(forms) <= self.genus(): + raise ValueError("Increase threshold!") + result = [] + for ff in forms: + if ff[0] != 0*self.dx: + result += [as_cech(self, ff[0], -ff[1])] + return result + raise ValueError("Unknown.") + + def de_rham_basis(self, holo_basis = 0, cohomology_basis = 0, threshold = 30): + if holo_basis == 0: + holo_basis = self.holomorphic_differentials_basis(threshold = threshold) + if cohomology_basis == 0: + cohomology_basis = self.cohomology_of_structure_sheaf_basis(holo_basis = holo_basis, threshold = threshold) + result = [] + for omega in holo_basis: + result += [as_cech(self, omega, as_function(self, 0))] + for f in cohomology_basis: + omega = self.lift_to_de_rham(f, threshold = threshold) + result += [as_cech(self, omega, f)] + return result + diff --git a/elementary_covers/as_form_class.sage b/elementary_covers/as_form_class.sage new file mode 100644 index 0000000..35af778 --- /dev/null +++ b/elementary_covers/as_form_class.sage @@ -0,0 +1,205 @@ +class as_form: + def __init__(self, C, g): + self.curve = C + n = C.height + F = C.base_ring + variable_names = 'x, y' + for i in range(n): + variable_names += ', z' + str(i) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + self.form = RxyzQ(g) + + def __repr__(self): + return "(" + str(self.form)+") * dx" + + def __eq__(self, other): + return self.expansion_at_infty() == other.expansion_at_infty() + + def expansion_at_infty(self, place = 0): + C = self.curve + delta = C.nb_of_pts_at_infty + F = C.base_ring + x_series = C.x_series[place] + y_series = C.y_series[place] + z_series = C.z_series[place] + dx_series = C.dx_series[place] + n = C.height + variable_names = 'x, y' + for j in range(n): + variable_names += ', z' + str(j) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + prec = C.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + g = self.form + sub_list = {x : x_series, y : y_series} | {z[j] : z_series[j] for j in range(n)} + return g.substitute(sub_list)*dx_series + + def expansion(self, pt = 0): + '''Same code as expansion_at_infty.''' + C = self.curve + F = C.base_ring + x_series = C.x_series[pt] + y_series = C.y_series[pt] + z_series = C.z_series[pt] + dx_series = C.dx_series[pt] + n = C.height + variable_names = 'x, y' + for j in range(n): + variable_names += ', z' + str(j) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + prec = C.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + g = self.form + sub_list = {x : x_series, y : y_series} | {z[j] : z_series[j] for j in range(n)} + return g.substitute(sub_list)*dx_series + + def __add__(self, other): + C = self.curve + g1 = self.form + g2 = other.form + return as_form(C, g1 + g2) + + def __sub__(self, other): + C = self.curve + g1 = self.form + g2 = other.form + return as_form(C, g1 - g2) + + def __neg__(self): + C = self.curve + g = self.form + return as_form(C, -g) + + def __rmul__(self, constant): + C = self.curve + omega = self.form + return as_form(C, constant*omega) + + def reduce(self): + aux = as_reduction(self.curve, self.form) + return as_form(self.curve, aux) + + def group_action(self, ZN_tuple): + C = self.curve + n = C.height + RxyzQ, Rxyz, x, y, z = C.fct_field + sub_list = {x : x, y : y} | {z[j] : z[j]+ZN_tuple[j] for j in range(n)} + g = self.form + return as_form(C, g.substitute(sub_list)) + + def coordinates(self, basis = 0): + """Find coordinates of the given holomorphic form self in terms of the basis forms in a list holo.""" + C = self.curve + if basis == 0: + basis = C.holomorphic_differentials_basis() + RxyzQ, Rxyz, x, y, z = C.fct_field + # We need to have only polynomials to use monomial_coefficients in linear_representation_polynomials, + # and sometimes basis elements have denominators. Thus we multiply by them. + denom = LCM([denominator(omega.form) for omega in basis]) + basis = [denom*omega for omega in basis] + self_with_no_denominator = denom*self + return linear_representation_polynomials(Rxyz(self_with_no_denominator.form), [Rxyz(omega.form) for omega in basis]) + + def trace(self): + C = self.curve + C_super = C.quotient + n = C.height + F = C.base_ring + variable_names = 'x, y' + for j in range(n): + variable_names += ', z' + str(j) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + result = as_form(C, 0) + G = C.group + for a in G: + result += self.group_action(a) + result = result.form + Rxy. = PolynomialRing(F, 2) + Qxy = FractionField(Rxy) + result = as_reduction(C, result) + return superelliptic_form(C_super, Qxy(result)) + + def residue(self, place=0): + return self.expansion_at_infty(place = place).residue() + + def valuation(self, place=0): + return self.expansion_at_infty(place = place).valuation() + + def serre_duality_pairing(self, fct): + AS = self.curve + return sum((fct*self).residue(place = _) for _ in range(AS.nb_of_pts_at_infty)) + + def cartier(self): + C = self.curve + F = C.base_ring + n = C.height + ff = C.functions + p = F.characteristic() + C_super = C.quotient + (RxyzQ, Rxyz, x, y, z) = C.fct_field + fct = self.form + Rxy. = PolynomialRing(F, 2) + RxyQ = FractionField(Rxy) + x, y = Rxyz.gens()[0], Rxyz.gens()[1] + z = Rxyz.gens()[2:] + num = Rxyz(fct.numerator()) + den = Rxyz(fct.denominator()) + result = RxyzQ(0) + #return (num, den, z, fct) + if den in Rxy: + sub_list = {x : x, y : y} | {z[j] : (z[j]^p - RxyzQ(ff[j].function)) for j in range(n)} + num = RxyzQ(num.substitute(sub_list)) + den1 = Rxyz(num.denominator()) + num = Rxyz(num*den1^p) + for monomial in Rxyz(num).monomials(): + degrees = [monomial.degree(z[i]) for i in range(n)] + product_of_z = prod(z[i]^(degrees[i]) for i in range(n)) + monomial_divided_by_z = monomial/product_of_z + product_of_z_no_p = prod(z[i]^(degrees[i]/p) for i in range(n)) + aux_form = superelliptic_form(C_super, RxyQ(monomial_divided_by_z/den)) + aux_form = aux_form.cartier() + result += product_of_z_no_p * Rxyz(num).monomial_coefficient(monomial) * aux_form.form/den1 + return as_form(C, result) + raise ValueError("Please present first your form as sum z^i omega_i, where omega_i are forms on quotient curve.") + + def is_regular_on_U0(self): + AS = self.curve + C = AS.quotient + m = C.exponent + RxyzQ, Rxyz, x, y, z = AS.fct_field + if y^(m-1)*self.form in Rxyz: + return True + return False + +def are_forms_linearly_dependent(set_of_forms): + from sage.rings.polynomial.toy_variety import is_linearly_dependent + C = set_of_forms[0].curve + F = C.base_ring + n = C.height + variable_names = 'x, y' + for i in range(n): + variable_names += ', z' + str(i) + Rxyz = PolynomialRing(F, n+2, variable_names) + denominators = prod(denominator(omega.form) for omega in set_of_forms) + return is_linearly_dependent([Rxyz(denominators*omega.form) for omega in set_of_forms]) + +def only_log_forms(C_AS): + list1 = AS.at_most_poles_forms(0) + list2 = AS.at_most_poles_forms(1) + result = [] + for a in list2: + if not(are_forms_linearly_dependent(list1 + result + [a])): + result += [a] + return result diff --git a/elementary_covers/as_function_class.sage b/elementary_covers/as_function_class.sage new file mode 100644 index 0000000..a72b3bc --- /dev/null +++ b/elementary_covers/as_function_class.sage @@ -0,0 +1,202 @@ +class as_function: + def __init__(self, C, g): + self.curve = C + F = C.base_ring + n = C.height + variable_names = 'x, y' + for i in range(n): + variable_names += ', z' + str(i) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + self.function = RxyzQ(g) + #self.function = as_reduction(AS, RxyzQ(g)) + + def __repr__(self): + return str(self.function) + + def __eq__(self, other): + AS = self.curve + RxyzQ, Rxyz, x, y, z = AS.fct_field + aux = self - other + aux = RxyzQ(aux.function) + aux = aux.numerator() + aux = as_function(AS, aux) + aux = aux.expansion_at_infty() + if aux.valuation() >= 1: + return True + return False + + def __add__(self, other): + C = self.curve + g1 = self.function + g2 = other.function + return as_function(C, g1 + g2) + + def __sub__(self, other): + C = self.curve + g1 = self.function + g2 = other.function + return as_function(C, g1 - g2) + + def __rmul__(self, constant): + C = self.curve + g = self.function + return as_function(C, constant*g) + + def __neg__(self): + C = self.curve + g = self.function + return as_function(C, -g) + + def __mul__(self, other): + if isinstance(other, as_function): + C = self.curve + g1 = self.function + g2 = other.function + return as_function(C, g1*g2) + if isinstance(other, as_form): + C = self.curve + g1 = self.function + g2 = other.form + return as_form(C, g1*g2) + + def __truediv__(self, other): + C = self.curve + g1 = self.function + g2 = other.function + return as_function(C, g1/g2) + + def __pow__(self, exponent): + C = self.curve + g1 = self.function + return as_function(C, g1^(exponent)) + + def expansion_at_infty(self, place = 0): + C = self.curve + delta = C.nb_of_pts_at_infty + F = C.base_ring + x_series = C.x_series[place] + y_series = C.y_series[place] + z_series = C.z_series[place] + n = C.height + variable_names = 'x, y' + for j in range(n): + variable_names += ', z' + str(j) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + prec = C.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + g = self.function + g = RxyzQ(g) + sub_list = {x : x_series, y : y_series} | {z[j] : z_series[j] for j in range(n)} + return g.substitute(sub_list) + + def expansion(self, pt = 0): + C = self.curve + delta = C.nb_of_pts_at_infty + F = C.base_ring + x_series = C.x_series[pt] + y_series = C.y_series[pt] + z_series = C.z_series[pt] + n = C.height + variable_names = 'x, y' + for j in range(n): + variable_names += ', z' + str(j) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + prec = C.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + g = self.function + g = RxyzQ(g) + sub_list = {x : x_series, y : y_series} | {z[j] : z_series[j] for j in range(n)} + return g.substitute(sub_list) + + def group_action(self, ZN_tuple): + C = self.curve + n = C.height + F = C.base_ring + variable_names = 'x, y' + for j in range(n): + variable_names += ', z' + str(j) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + sub_list = {x : x, y : y} | {z[j] : z[j]+ZN_tuple[j] for j in range(n)} + g = self.function + return as_function(C, g.substitute(sub_list)) + + def reduce(self): + aux = as_reduction(self.curve, self.function) + return as_function(self.curve, aux) + + def trace(self): + C = self.curve + C_super = C.quotient + n = C.height + F = C.base_ring + variable_names = 'x, y' + for j in range(n): + variable_names += ', z' + str(j) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + result = as_function(C, 0) + G = C.group + for a in G: + result += self.group_action(a) + result = result.function + Rxy. = PolynomialRing(F, 2) + Qxy = FractionField(Rxy) + result = as_reduction(C, result) + return superelliptic_function(C_super, Qxy(result)) + + def coordinates(self, prec = 100, basis = 0): + "Return coordinates in H^1(X, OX)." + AS = self.curve + if basis == 0: + basis = [AS.holomorphic_differentials_basis(), AS.cohomology_of_structure_sheaf_basis()] + holo_diffs = basis[0] + coh_basis = basis[1] + f_products = [] + for f in coh_basis: + f_products += [[omega.serre_duality_pairing(f) for omega in holo_diffs]] + product_of_fct_and_omegas = [] + product_of_fct_and_omegas = [omega.serre_duality_pairing(self) for omega in holo_diffs] + + V = (F^(AS.genus())).span_of_basis([vector(a) for a in f_products]) + coh_coordinates = V.coordinates(product_of_fct_and_omegas) + return coh_coordinates + + def diffn(self): + C = self.curve + C_super = C.quotient + n = C.height + RxyzQ, Rxyz, x, y, z = C.fct_field + fcts = C.functions + f = self.function + y_super = superelliptic_function(C_super, y) + dy_super = y_super.diffn().form + dz = [] + for i in range(n): + dfct = fcts[i].diffn().form + dz += [-dfct] + result = f.derivative(x) + result += f.derivative(y)*dy_super + for i in range(n): + result += f.derivative(z[i])*dz[i] + return as_form(C, result) + + def valuation(self, place = 0): + '''Return valuation at i-th place at infinity.''' + C = self.curve + F = C.base_ring + Rt. = LaurentSeriesRing(F) + return Rt(self.expansion_at_infty(place = place)).valuation() diff --git a/elementary_covers/as_polyforms.sage b/elementary_covers/as_polyforms.sage new file mode 100644 index 0000000..cc6f35d --- /dev/null +++ b/elementary_covers/as_polyforms.sage @@ -0,0 +1,221 @@ +class as_polyform: + def __init__(self, form, mult): + '''Elements of H^0(Ω^⊗n). Usage: mult is n, form should be as_function.''' + self.form = form + self.curve = form.curve + self.mult = mult + + def __add__(self, other): + return as_polyform(self.form + other.form, self.mult) + + def __repr__(self): + return '(' + str(self.form) + ') dx⊗' + str(self.mult) + + def expansion_at_infty(self, place): + return self.form.expansion_at_infty(place=place)*(self.curve.dx.expansion_at_infty(place=place))^(self.mult) + + def coordinates(self, basis = 0): + """Find coordinates of the given holomorphic form self in terms of the basis forms in a list holo.""" + AS = self.curve + if basis == 0: + basis = AS.holo_polydifferentials_basis(mult = self.mult) + RxyzQ, Rxyz, x, y, z = AS.fct_field + # We need to have only polynomials to use monomial_coefficients in linear_representation_polynomials, + # and sometimes basis elements have denominators. Thus we multiply by them. + denom = LCM([denominator(omega.form.function) for omega in basis]) + basis = [denom*omega.form.function for omega in basis] + self_with_no_denominator = denom*self.form.function + return linear_representation_polynomials(Rxyz(self_with_no_denominator), [Rxyz(omega) for omega in basis]) + + def group_action(self, elt): + return as_polyform(self.form.group_action(elt), self.mult) + + +def as_holo_polydifferentials_basis(AS, mult, threshold = 8): + '''Give the basis of H^0(Ω^⊗n) for n = mult.''' + v = AS.dx.valuation() + result = AS.at_most_poles(mult*v, threshold=threshold) + result = [as_polyform(omega, mult) for omega in result] + if mult == 1 and len(result) < AS.genus(): + raise ValueError('Increase threshold, not all forms found.') + if mult > 1 and len(result) < (2*mult - 1)*(AS.genus() - 1): + raise ValueError('Increase threshold, not all forms found.') + return result + +as_cover.holo_polydifferentials_basis = as_holo_polydifferentials_basis + +def as_symmetric_power_basis(AS, n, threshold = 8): + '''Give the basis of H^0(Ω)^⊙n for n = mult.''' + g = AS.genus() + B0 = AS.holomorphic_differentials_basis(threshold=threshold) + from itertools import product + indices = [list(range(g)) for i in range(n)] + indices_nonrepeating = [] + for i in product(*indices): + if non_decreasing(i): + indices_nonrepeating += [i] + result = [] + for i in indices_nonrepeating: + tensor_form = [B0[i[j]] for j in range(n)] + tensor_form = [1] + tensor_form + result += [tensor_form] + result = [as_symmetric_product_forms([a]) for a in result] + return result + +def as_canonical_ideal(AS, n, threshold=8): + '''Return the n-th homogeneous part of the canonical ideal.''' + B0 = AS.holomorphic_differentials_basis(threshold=threshold) + F = AS.base_ring + g = AS.genus() + RxyzQ, Rxyz, x, y, z = AS.fct_field + from itertools import product + B1 = as_symmetric_power_basis(AS, n, threshold = 8) + B2 = AS.holo_polydifferentials_basis(n, threshold = threshold) + g = AS.genus() + r = len(B2) + M = matrix(F, len(B1), r) + for i in range(0, len(B1)): + c = B1[i].multiply() + #return M, c.coordinates(basis=B2) + M[i, :] = vector(c.coordinates(basis=B2)) + K = M.kernel().basis() + result = [] + for v in K: + kernel_vector = 0*B1[0] + for i in range(len(v)): + kernel_vector += v[i]*B1[i] + result += [kernel_vector] + return result + +as_cover.canonical_ideal = as_canonical_ideal + +def as_canonical_ideal_polynomials(AS, n, threshold=8): + '''Return the polynomials defining n-th homogeneous part of the canonical ideal.''' + return [a.polynomial() for a in AS.canonical_ideal(n, threshold=threshold)] + +as_cover.canonical_ideal_polynomials = as_canonical_ideal_polynomials + +class as_symmetric_product_forms: + def __init__(self, forms_and_coeffs): + '''Elements of forms_and_coeffs are of the form [coeff, form_1, ..., form_n]''' + self.n = len(forms_and_coeffs[0]) - 1 + forms_and_coeffs1 = [] + for atuple in forms_and_coeffs: + if atuple[0] != 0 and atuple[1:] not in [a[1:] for a in forms_and_coeffs1]: + forms_and_coeffs1 += [atuple] + elif atuple[1:] in [a[1:] for a in forms_and_coeffs1]: + i = [a[1:] for a in forms_and_coeffs1].index(atuple[1:]) + forms_and_coeffs1[i][0] += atuple[0] + if len(forms_and_coeffs1) == 0: + forms_and_coeffs1 = [[0] + forms_and_coeffs[0][1:]] + self.tuples = forms_and_coeffs1 + self.curve = forms_and_coeffs1[0][1].curve + + def coordinates(self, basis = 0): + AS = self.curve + g = AS.genus() + n = self.n + F = AS.base_ring + if basis == 0: + basis = AS.holomorphic_differentials_basis() + from itertools import product + indices = [list(range(g)) for i in range(self.n)] + result = {i : 0 for i in product(*indices)} + for atuple in self.tuples: + coors = [omega.coordinates(basis = basis) for omega in atuple[1:]] + for i in product(*indices): + aux_product = 1 + for j in range(n): + aux_product *= coors[j][i[j]] + result[i] += atuple[0]*aux_product + return result + + def __repr__(self): + result = '' + for atuple in self.tuples: + if atuple[0] !=0: + result += str(atuple[0]) + ' * ' + for j in range(1, self.n+1): + result += "(" + str(atuple[j]) + ")" + if j != self.n: + result + '⊗' + result += ' + ' + return result + + def __add__(self, other): + return as_symmetric_product_forms(self.tuples + other.tuples) + + def __rmul__(self, other): + AS = self.curve + F = AS.base_ring + if isinstance(other, int) or other in ZZ or other in F: + aux_tuples = [] + for atuple in self.tuples: + atuple1 = [other * atuple[0]] + atuple[1:] + aux_tuples += [atuple1] + return as_symmetric_product_forms(aux_tuples) + + def multiply(self): + '''The map H^0(Ω)^⊙n ---> H^0(Ω^⊗n)''' + n = self.n + AS = self.curve + RxyzQ, Rxyz, x, y, z = AS.fct_field + result = as_polyform(0*AS.x, n) + for atuple in self.tuples: + aux_product = Rxyz(1) + for fct in atuple[1:]: + aux_product = aux_product * fct.form + aux_product = as_function(AS, aux_product) + aux_product = as_reduction(AS, aux_product) + aux_product = as_function(AS, aux_product) + result += as_polyform(atuple[0]*aux_product, n) + return result + + def polynomial(self): + '''Return the associated polynomial.''' + AS = self.curve + F = AS.base_ring + g = AS.genus() + M = self.coordinates() + n = self.n + Rg = PolynomialRing(F, 'X', g) + X = Rg.gens() + from itertools import product + indices = [list(range(g)) for i in range(self.n)] + result = Rg(0) + for i in product(*indices): + aux_product = Rg(1) + for j in range(n): + aux_product *= X[i[j]] + result += M[i] * aux_product + return result + + def group_action(self, elt): + p = self.curve.base_ring.characteristic() + n = self.curve.height + aux_tuples = [] + for atuple in self.tuples: + aux_tuple = [atuple[0]] + [a.group_action(elt) for a in atuple[1:]] + aux_tuples += [aux_tuple] + return as_symmetric_product_forms(aux_tuples) + +def non_decreasing(L): + return all(x<=y for x, y in zip(L, L[1:])) + +def as_matrices_group_action_canonical_ideal(AS, mult, threshold = 8): + '''Return the group action matrices for the n-th homogeneous part of the canonical ideal.''' + K = as_canonical_ideal(AS, mult, threshold = threshold) + n = AS.height + F = AS.base_ring + K_polynomials = [a.polynomial() for a in K] + r = len(K) + matrices = [] + for i in range(n): + M = matrix(F, r, r) + K_group_action_polynomials = [a.group_action([j == i for j in range(n)]).polynomial() for a in K] + for i in range(r): + M[i, :] = vector(linear_representation_polynomials(K_group_action_polynomials[i], K_polynomials)) + matrices += [M] + return matrices + +as_cover.group_action_canonical_ideal = as_matrices_group_action_canonical_ideal \ No newline at end of file diff --git a/elementary_covers/as_reduction.sage b/elementary_covers/as_reduction.sage new file mode 100644 index 0000000..343e444 --- /dev/null +++ b/elementary_covers/as_reduction.sage @@ -0,0 +1,33 @@ +def as_reduction(AS, fct): + '''Simplify rational function fct as a function in the function field of AS, so that z[i] appear in powers

= LaurentSeriesRing(F, default_prec=prec) + RtQ = FractionField(Rt) + power_series = RtQ(power_series) + if power_series.valuation() == +Infinity: + raise ValueError("Precision is too low.") + if power_series.valuation() >= 0: + # THIS IS WRONG - THERE ARE SEVERAL PLACES OVER THIS PLACE, AND IT DEPENDS + aux = t^p - t + z = new_reverse(aux, prec = prec) + z = z(t = power_series) + return(0, 0, t, z) + + while(power_series.valuation() % p == 0 and power_series.valuation() < 0): + M = -power_series.valuation()/p + coeff = power_series.list()[0] #wspolczynnik a_(-p) w f_AS + correction += coeff.nth_root(p)*t^(-M) + power_series = power_series - (coeff*t^(-p*M) - coeff.nth_root(p)*t^(-M)) + jump = max(-(power_series.valuation()), 0) + try: + if jump != 0: + T = nth_root2((power_series)^(-1), jump, prec=prec) #T is defined by power_series = 1/T^m + except: + print("no ", str(jump), "-th root; divide by", power_series.list()[0]) + return (jump, power_series.list()[0]) + if jump != 0: + T_rev = new_reverse(T, prec = prec) + t_old = T_rev(t^p/nth_root2(1 - t^((p-1)*jump), jump, prec=prec)) + z = 1/t^(jump) + Rt(correction)(t = t_old) + return(jump, correction, t_old, z) + if jump == 0: + aux = t^p - t + z = new_reverse(aux, prec = prec) + z = z(t = power_series) + z = z + correction + return(0, correction, t, z) \ No newline at end of file diff --git a/elementary_covers/combination_components.sage b/elementary_covers/combination_components.sage new file mode 100644 index 0000000..43894ef --- /dev/null +++ b/elementary_covers/combination_components.sage @@ -0,0 +1,14 @@ +def combination_components(omega, zmag, w): + '''Given a form omega on AS cover and normal basis element zmag, find the decomposition + sum_g g(zmag) omega_g and return sum_g g(w) omega_g.''' + AS = omega.curve + p = AS.characteristic + group_elts = [(j1, j2) for j1 in range(p) for j2 in range(p)] + zvee = dual_elt(AS, zmag) + result = as_form(AS, 0) + for g in AS.group: + omegag = ith_magical_component(omega, zvee, g) + aux_fct1 = w.group_action(g).function + aux_fct2 = omegag.form + result += as_form(AS, aux_fct1*aux_fct2) + return result \ No newline at end of file diff --git a/elementary_covers/dual_element.sage b/elementary_covers/dual_element.sage new file mode 100644 index 0000000..fd0a0bd --- /dev/null +++ b/elementary_covers/dual_element.sage @@ -0,0 +1,26 @@ +def dual_elt(AS, zmag): + '''Find the trace dual of a given elt zmag in the function field of an Artin-Schreier cover AS.''' + p = AS.characteristic + n = AS.height + G = AS.group + variable_names = 'x, y' + for i in range(n): + variable_names += ', z' + str(i) + Rxyz = PolynomialRing(F, n+2, variable_names) + x, y = Rxyz.gens()[:2] + z = Rxyz.gens()[2:] + RxyzQ = FractionField(Rxyz) + M = matrix(RxyzQ, p^n, p^n) + for i in range(p^n): + for j in range(p^n): + elt = (zmag.group_action(G[i])*zmag.group_action(G[j])).trace().function + elt = Rxyz(elt.numerator())/Rxyz(elt.denominator()) + M[i, j] = RxyzQ(elt) + main_det = M.determinant() + zvee = as_function(AS, 0) + for i in range(p^n): + Mprim = matrix(RxyzQ, M) + Mprim[:, i] = vector([(j == 0) for j in range(p^n)]) + fi = Mprim.determinant()/main_det + zvee += as_function(AS, fi*(zmag.group_action(G[i]).function)) + return zvee \ No newline at end of file diff --git a/elementary_covers/group_action_matrices.sage b/elementary_covers/group_action_matrices.sage new file mode 100644 index 0000000..e1be8b1 --- /dev/null +++ b/elementary_covers/group_action_matrices.sage @@ -0,0 +1,53 @@ +def as_group_action_matrices(F, space, list_of_group_elements, basis): + n = len(list_of_group_elements) + d = len(space) + A = [matrix(F, d, d) for i in range(n)] + for i, g in enumerate(list_of_group_elements): + for j, omega in enumerate(space): + omega1 = omega.group_action(g) + v1 = omega1.coordinates(basis = basis) + A[i][:, j] = vector(v1) + return A + +def as_group_action_matrices_holo(AS, basis=0, threshold=10): + n = AS.height + generators = [] + for i in range(n): + ei = n*[0] + ei[i] = 1 + generators += [ei] + if basis == 0: + basis = AS.holomorphic_differentials_basis(threshold=threshold) + F = AS.base_ring + return as_group_action_matrices(F, basis, generators, basis = basis) + +as_cover.group_action_matrices_holo = as_group_action_matrices_holo + +def as_group_action_matrices_dR(AS, basis = 0, threshold=8): + n = AS.height + generators = [] + F = AS.base_ring + for i in range(n): + ei = n*[0] + ei[i] = 1 + generators += [ei] + if basis == 0: + holo_basis = AS.holomorphic_differentials_basis(threshold = threshold) + str_basis = AS.cohomology_of_structure_sheaf_basis(holo_basis = holo_basis, threshold = threshold) + dr_basis = AS.de_rham_basis(holo_basis = holo_basis, cohomology_basis = str_basis, threshold=threshold) + basis = [holo_basis, str_basis, dr_basis] + return as_group_action_matrices(F, basis[2], generators, basis = basis) + +as_cover.group_action_matrices_dR = as_group_action_matrices_dR + +def as_group_action_matrices_log_holo(AS): + n = AS.height + generators = [] + for i in range(n): + ei = n*[0] + ei[i] = 1 + generators += [ei] + F = AS.base_ring + return as_group_action_matrices(F, AS.at_most_poles_forms(1), generators, basis = AS.at_most_poles_forms(1)) + +as_cover.group_action_matrices_log_holo = as_group_action_matrices_log_holo \ No newline at end of file diff --git a/elementary_covers/holomorphic_combinations.sage b/elementary_covers/holomorphic_combinations.sage new file mode 100644 index 0000000..6f931b0 --- /dev/null +++ b/elementary_covers/holomorphic_combinations.sage @@ -0,0 +1,149 @@ +def holomorphic_combinations(S): + """Given a list S of pairs (form, corresponding Laurent series at some pt), find their combinations holomorphic at that pt.""" + C_AS = S[0][0].curve + p = C_AS.characteristic + F = C_AS.base_ring + prec = C_AS.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + RtQ = FractionField(Rt) + minimal_valuation = min([g[1].valuation() for g in S]) + if minimal_valuation >= 0: + return [s[0] for s in S] + list_of_lists = [] #to będzie lista złożona z list współczynników część nieholomorficznych rozwinięcia form z S + for eta, eta_exp in S: + a = -minimal_valuation + eta_exp.valuation() + list_coeffs = a*[0] + eta_exp.list() + (-minimal_valuation)*[0] + list_coeffs = list_coeffs[:-minimal_valuation] + list_of_lists += [list_coeffs] + M = matrix(F, list_of_lists) + V = M.kernel() #chcemy wyzerować części nieholomorficzne, biorąc kombinacje form z S + + + # Sprawdzamy, jakim formom odpowiadają elementy V. + forms = [] + for vec in V.basis(): + forma_holo = 0*S[0][0] + forma_holo_power_series = Rt(0) + for vec_wspolrzedna, elt_S in zip(vec, S): + eta = elt_S[0] + #eta_exp = elt_S[1] + forma_holo += vec_wspolrzedna*eta + #forma_holo_power_series += vec_wspolrzedna*eta_exp + forms += [forma_holo] + return forms + +def holomorphic_combinations_mixed(S): + """Given a list S of pairs (form, corresponding Laurent series at some pt), find their combinations holomorphic at that pt.""" + C_AS = S[0][0].curve + p = C_AS.characteristic + F = C_AS.base_ring + prec = C_AS.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + RtQ = FractionField(Rt) + minimal_valuation = min([g[1].valuation() for g in S]) + print(minimal_valuation) + if minimal_valuation >= 0: + return [s[0] for s in S] + list_of_lists = [] #to będzie lista złożona z list współczynników część nieholomorficznych rozwinięcia form z S + for eta, eta_exp in S: + a = -minimal_valuation + eta_exp.valuation() + list_coeffs = a*[0] + eta_exp.list() + (-minimal_valuation)*[0] + list_coeffs = list_coeffs[:-minimal_valuation] + list_of_lists += [list_coeffs] + M = matrix(F, list_of_lists) + V = M.kernel() #chcemy wyzerować części nieholomorficzne, biorąc kombinacje form z S + + + # Sprawdzamy, jakim formom odpowiadają elementy V. + forms = [] + for vec in V.basis(): + forma_holo = 0*S[0][0] + forma_holo_power_series = Rt(0) + res1 = 0*C_AS.dx + res2 = 0*C_AS.x + res = 0*C_AS.dx + for vec_wspolrzedna, elt_S in zip(vec, S): + eta = elt_S[0] + if isinstance(eta, as_form): + res += vec_wspolrzedna*eta + res1 += vec_wspolrzedna*eta + if isinstance(eta, as_function): + res += vec_wspolrzedna*eta.diffn() + res2 += vec_wspolrzedna*eta + #eta_exp = elt_S[1] + #forma_holo_power_series += vec_wspolrzedna*eta_exp + forms += [(res1, res2)] + return forms + +def holomorphic_combinations_fcts(S, pole_order): + '''given a set S of (form, corresponding Laurent series at some pt), find their combinations holomorphic at that pt''' + C_AS = S[0][0].curve + p = C_AS.characteristic + F = C_AS.base_ring + prec = C_AS.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + RtQ = FractionField(Rt) + minimal_valuation = min([Rt(g[1]).valuation() for g in S]) + if minimal_valuation >= -pole_order: + return [s[0] for s in S] + list_of_lists = [] #to będzie lista złożona z list współczynników część nieholomorficznych rozwinięcia form z S + for eta, eta_exp in S: + a = -minimal_valuation + Rt(eta_exp).valuation() + if eta_exp !=0: + list_coeffs = a*[0] + Rt(eta_exp).list() + (-minimal_valuation)*[0] + list_coeffs = list_coeffs[:-minimal_valuation - pole_order] + else: + list_coeffs = (-minimal_valuation - pole_order)*[0] + list_of_lists += [list_coeffs] + M = matrix(F, list_of_lists) + V = M.kernel() #chcemy wyzerować części nieholomorficzne, biorąc kombinacje form z S + + + # Sprawdzamy, jakim formom odpowiadają elementy V. + forms = [] + for vec in V.basis(): + forma_holo = 0*C_AS.x + forma_holo_power_series = Rt(0) + for vec_wspolrzedna, elt_S in zip(vec, S): + eta = elt_S[0] + #eta_exp = elt_S[1] + forma_holo += vec_wspolrzedna*eta + #forma_holo_power_series += vec_wspolrzedna*eta_exp + forms += [forma_holo] + return forms + +def holomorphic_combinations_forms(S, pole_order): + '''given a set S of (form, corresponding Laurent series at some pt), find their combinations holomorphic at that pt''' + C_AS = S[0][0].curve + p = C_AS.characteristic + F = C_AS.base_ring + prec = C_AS.prec + Rt. = LaurentSeriesRing(F, default_prec=prec) + RtQ = FractionField(Rt) + minimal_valuation = min([Rt(g[1]).valuation() for g in S]) + if minimal_valuation >= -pole_order: + return [s[0] for s in S] + list_of_lists = [] #to będzie lista złożona z list współczynników część nieholomorficznych rozwinięcia form z S + for eta, eta_exp in S: + a = -minimal_valuation + Rt(eta_exp).valuation() + list_coeffs = a*[0] + Rt(eta_exp).list() + (-minimal_valuation)*[0] + list_coeffs = list_coeffs[:-minimal_valuation - pole_order] + list_of_lists += [list_coeffs] + M = matrix(F, list_of_lists) + V = M.kernel() #chcemy wyzerować części nieholomorficzne, biorąc kombinacje form z S + + + # Sprawdzamy, jakim formom odpowiadają elementy V. + forms = [] + for vec in V.basis(): + forma_holo = 0*C_AS.dx + forma_holo_power_series = Rt(0) + for vec_wspolrzedna, elt_S in zip(vec, S): + eta = elt_S[0] + #eta_exp = elt_S[1] + forma_holo += vec_wspolrzedna*eta + #forma_holo_power_series += vec_wspolrzedna*eta_exp + forms += [forma_holo] + return forms + +#print only forms that are log at the branch pts, but not holomorphic \ No newline at end of file diff --git a/elementary_covers/ith_magical_component.sage b/elementary_covers/ith_magical_component.sage new file mode 100644 index 0000000..cfc6d54 --- /dev/null +++ b/elementary_covers/ith_magical_component.sage @@ -0,0 +1,6 @@ +def ith_magical_component(omega, zvee, g): + '''Given a form omega on AS cover, element g of group AS.group and normal basis element zmag, find the decomposition + sum_g g(zmag) omega_g and return omega_g.''' + z_vee_g = zvee.group_action(g) + new_form = z_vee_g*omega + return new_form.trace() \ No newline at end of file diff --git a/elementary_covers/tests/as_cover_test.sage b/elementary_covers/tests/as_cover_test.sage new file mode 100644 index 0000000..15ddb7d --- /dev/null +++ b/elementary_covers/tests/as_cover_test.sage @@ -0,0 +1,26 @@ +p = 5 +m = 2 +F = GF(p^2, 'a') +a = F.gens()[0] +Rx. = PolynomialRing(F) +f = x^3 + x^2 + 1 +C_super = superelliptic(f, m) +Rxy. = PolynomialRing(GF(p), 2) +fArS1 = superelliptic_function(C_super, y*x) +fArS2 = superelliptic_function(C_super, y*x^2) +fArS3 = superelliptic_function(C_super, y + x) +AS1 = as_cover(C_super, [fArS1, fArS2, fArS3], prec=150) +AS2 = as_cover(C_super, [fArS2, fArS3, fArS1], prec=150) +print(AS1.genus() == AS2.genus()) +################## +p = 5 +m = 2 +Rx. = PolynomialRing(GF(p)) +f = x^3 + x^2 + 1 +C_super = superelliptic(f, m) +Rxy. = PolynomialRing(GF(p), 2) +fArS1 = superelliptic_function(C_super, y*x) +fArS2 = superelliptic_function(C_super, y*x^2) +AS1 = as_cover(C_super, [fArS1, fArS2], prec=1000) +omega = as_form(AS1, 1/y) +print(omega.expansion_at_infty().valuation()==AS1.exponent_of_different()) \ No newline at end of file diff --git a/elementary_covers/tests/as_polyforms_test.sage b/elementary_covers/tests/as_polyforms_test.sage new file mode 100644 index 0000000..9ad2d87 --- /dev/null +++ b/elementary_covers/tests/as_polyforms_test.sage @@ -0,0 +1,27 @@ +p = 2 +F = GF(p) +Rx. = PolynomialRing(F) +C = superelliptic(x, 1) +AS = as_cover(C, [C.x^3, C.x^5], prec = 200) +B = AS.holo_polydifferentials_basis(3) +print(len(B) == (2 * 3 - 1) * (AS.genus() - 1)) #is the dimension as predicted by Riemann--Roch? +I2 = AS.canonical_ideal_polynomials(2) +R = I2[0].parent() #ring, to which the polynomials belong +J2 = R.ideal(I2) #ideal defined by the set I +print(J2.is_prime(), len(R.gens()) - J2.dimension() - 1) +I3 = AS.canonical_ideal_polynomials(3) +J3 = R.ideal(I2 + I3) +print(J3.is_prime(), len(R.gens()) - J3.dimension() - 1) + +p = 5 +F = GF(p) +Rx. = PolynomialRing(F) +C = superelliptic(x, 1) +AS = as_cover(C, [C.x^8], prec = 200) +I2 = AS.canonical_ideal_polynomials(2, threshold=15) +R = I2[0].parent() #ring, to which the polynomials belong +J2 = R.ideal(I2) #ideal defined by the set I +print(J2.is_prime(), len(R.gens()) - J2.dimension() - 1) +I3 = AS.canonical_ideal_polynomials(3, threshold=20) +J3 = R.ideal(I2 + I3) +print(J3.is_prime(), len(R.gens()) - J3.dimension() - 1) \ No newline at end of file diff --git a/elementary_covers/tests/cartier_test.sage b/elementary_covers/tests/cartier_test.sage new file mode 100644 index 0000000..a01ba7d --- /dev/null +++ b/elementary_covers/tests/cartier_test.sage @@ -0,0 +1,11 @@ +p = 5 +m = 2 +F = GF(p) +Rx. = PolynomialRing(F) +f = x^3 + x + 1 +C = superelliptic(f, m) +g = f(x^p - x) +C1 = superelliptic(g, m) +ff = superelliptic_function(C, x) +AS = as_cover(C, [ff]) +print(C1.cartier_matrix().rank() == AS.cartier_matrix().rank()) \ No newline at end of file diff --git a/elementary_covers/tests/diffn_test.sage b/elementary_covers/tests/diffn_test.sage new file mode 100644 index 0000000..972e894 --- /dev/null +++ b/elementary_covers/tests/diffn_test.sage @@ -0,0 +1,15 @@ +p = 3 +m = 1 +F = GF(p) +Rx. = PolynomialRing(F) +f = x^2 + 1 +C_super = superelliptic(f, m) + +Rxy. = PolynomialRing(F, 2) +f1 = superelliptic_function(C_super, x^2) +f2 = superelliptic_function(C_super, x^4) +AS = as_cover(C_super, [f1, f2], prec=1000) +RxyzQ, Rxyz, x, y, z = AS.fct_field +f_z = as_function(AS, z[0]*z[1]*y) +df_z = f_z.diffn() +print(df_z.form == -z[0]*z[1]*x + y*z[1]*x - y*z[0]*x^3) \ No newline at end of file diff --git a/elementary_covers/tests/dual_element_test.sage b/elementary_covers/tests/dual_element_test.sage new file mode 100644 index 0000000..bfc30cf --- /dev/null +++ b/elementary_covers/tests/dual_element_test.sage @@ -0,0 +1,20 @@ +p = 5 +m = 1 +F = GF(p) +Rx. = PolynomialRing(F) +f = x +C_super = superelliptic(f, m) + +Rxy. = PolynomialRing(F, 2) +f1 = superelliptic_function(C_super, x^2) +f2 = superelliptic_function(C_super, x^3) +AS = as_cover(C_super, [f1, f2], prec=500) +zmag = (AS.magical_element())[0] +zdual = dual_elt(AS, zmag) + +for i in range(p): + for j in range(p): + if (i, j) == (0, 0): + print((zmag*(zdual.group_action([i, j]))).trace().function == 1) + else: + print((zmag*(zdual.group_action([i, j]))).trace().function == 0) \ No newline at end of file diff --git a/elementary_covers/tests/group_action_matrices_test.sage b/elementary_covers/tests/group_action_matrices_test.sage new file mode 100644 index 0000000..c8fe89f --- /dev/null +++ b/elementary_covers/tests/group_action_matrices_test.sage @@ -0,0 +1,18 @@ +p = 3 +m = 2 +F = GF(p) +Rx. = PolynomialRing(F) +f = x^3 + x +C_super = superelliptic(f, m) + +f1 = C_super.x^2*C_super.y +f2 = C_super.x^3 +AS = as_cover(C_super, [f1, f2], prec=1000) + +A, B = AS.group_action_matrices_holo() +n = A.dimensions()[0] +print(A*B == B*A) +print(A^p == identity_matrix(n)) +print(B^p == identity_matrix(n)) + +print(magma_module_decomposition(A, B)) \ No newline at end of file diff --git a/elementary_covers/tests/ith_component_test.sage b/elementary_covers/tests/ith_component_test.sage new file mode 100644 index 0000000..0e274ae --- /dev/null +++ b/elementary_covers/tests/ith_component_test.sage @@ -0,0 +1,15 @@ +p = 5 +m = 1 +F = GF(p) +Rx. = PolynomialRing(F) +f = x +C_super = superelliptic(f, m) + +Rxy. = PolynomialRing(F, 2) +f1 = superelliptic_function(C_super, x^2) +f2 = superelliptic_function(C_super, x^3) +AS = as_cover(C_super, [f1, f2], prec=500) +zmag = (AS.magical_element())[0] + +om = AS.holomorphic_differentials_basis()[4] +print(combination_components(om, zmag, zmag).form == om.form) \ No newline at end of file diff --git a/elementary_covers/tests/ith_ramification_gp_test.sage b/elementary_covers/tests/ith_ramification_gp_test.sage new file mode 100644 index 0000000..7b58c02 --- /dev/null +++ b/elementary_covers/tests/ith_ramification_gp_test.sage @@ -0,0 +1,20 @@ +p = 3 +m = 1 +F = GF(p) +Rx. = PolynomialRing(F) +f = x +C_super = superelliptic(f, m) + +Rxy. = PolynomialRing(F, 2) +f1 = superelliptic_function(C_super, x^7) +f2 = superelliptic_function(C_super, x^4) +AS = as_cover(C_super, [f1, f2], prec=1000) +n = AS.height +d_test = (p^n - 1) +Gi = AS.group +i = 1 +while(len(Gi) > 1): + Gi = AS.ith_ramification_gp(i) + d_test += len(Gi) - 1 + i+=1 +print(d_test == AS.exponent_of_different()) \ No newline at end of file diff --git a/elementary_covers/tests/ramification_jumps_test.sage b/elementary_covers/tests/ramification_jumps_test.sage new file mode 100644 index 0000000..57d579b --- /dev/null +++ b/elementary_covers/tests/ramification_jumps_test.sage @@ -0,0 +1,25 @@ +p = 5 +m = 1 +F = GF(p) +Rx. = PolynomialRing(F) +f = x +C_super = superelliptic(f, m) + +Rxy. = PolynomialRing(F, 2) +f1 = superelliptic_function(C_super, x^2) +f2 = superelliptic_function(C_super, x^3) +AS = as_cover(C_super, [f1, f2], prec=500) +m = AS.jumps[0] +m1 = m[0] +m2 = m[1] +#We compute jumps from jumps in the tower of two Z/p-covers. +if m1 >= m2: + M1 = m2 + M2 = m2 + p*(m1 - m2) +else: + M1 = m1 + M2 = m2 + +theoretical_jumps = [M1, M2] +theoretical_jumps.sort() +print(theoretical_jumps == AS.ramification_jumps()) \ No newline at end of file diff --git a/elementary_covers/tests/uniformizer_test.sage b/elementary_covers/tests/uniformizer_test.sage new file mode 100644 index 0000000..68ef2ee --- /dev/null +++ b/elementary_covers/tests/uniformizer_test.sage @@ -0,0 +1,12 @@ +p = 3 +m = 1 +F = GF(p) +Rx. = PolynomialRing(F) +f = x +C_super = superelliptic(f, m) + +Rxy. = PolynomialRing(F, 2) +f1 = superelliptic_function(C_super, x^7) +f2 = superelliptic_function(C_super, x^4) +AS = as_cover(C_super, [f1, f2], prec=1000) +print(AS.uniformizer().valuation() == 1) \ No newline at end of file diff --git a/heisenberg_covers/heisenberg_covers.sage b/heisenberg_covers/heisenberg_covers.sage index e3348f9..34c757b 100644 --- a/heisenberg_covers/heisenberg_covers.sage +++ b/heisenberg_covers/heisenberg_covers.sage @@ -474,4 +474,43 @@ def at_most_poles2(self, pole_orders, threshold = 8): print('iteration') forms = [(omega, omega.group_action(g).expansion_at_infty(place = i)) for omega in forms] forms = holomorphic_combinations_fcts(forms, pole_orders[(i, g)]) + return forms + +def at_most_poles_forms2(self, pole_orders, threshold = 8): + """ Find fcts with pole order in infty's at most pole_order from the given dictionary. The keys of the dictionary are pairs (place_at_infty, group element). The items are the poles orders at those places. + Threshold gives a bound on powers of x in the function. If you suspect that you haven't found all the functions, you may increase it.""" + from itertools import product + x_series = self.x_series + y_series = self.y_series + z_series = self.z_series + delta = self.nb_of_pts_at_infty + p = self.characteristic + n = self.height + prec = self.prec + C = self.quotient + F = self.base_ring + m = C.exponent + r = C.polynomial.degree() + RxyzQ, Rxyz, x, y, z = self.fct_field + F = C.base_ring + Rt. = LaurentSeriesRing(F, default_prec=prec) + #Tworzymy zbiór S form z^i x^j y^k dx/y o waluacji >= waluacja z^(p-1)*dx/y + S = [] + RQxyz = FractionField(Rxyz) + pr = [list(GF(p)) for _ in range(n)] + for i in range(0, threshold*r): + for j in range(0, m): + for k in product(*pr): + eta = heisenberg_form(self, x^i * prod(z[i1]^(k[i1]) for i1 in range(n))/y^j) + eta_exp = eta.expansion_at_infty() + S += [(eta, eta_exp)] + + forms = holomorphic_combinations_forms(S, pole_orders[(0, (0, 0, 0))]) + print('iteration') + for i in range(delta): + for g in self.fiber(place = i): + if i!=0 or g != (0, 0, 0): + print('iteration') + forms = [(omega, omega.group_action(g).expansion_at_infty(place = i)) for omega in forms] + forms = holomorphic_combinations_forms(forms, pole_orders[(i, g)]) return forms \ No newline at end of file diff --git a/heisenberg_covers/heisenberg_form_class.sage b/heisenberg_covers/heisenberg_form_class.sage index 4fc4c03..c1860db 100644 --- a/heisenberg_covers/heisenberg_form_class.sage +++ b/heisenberg_covers/heisenberg_form_class.sage @@ -15,6 +15,14 @@ class heisenberg_form: def __repr__(self): return "(" + str(self.form)+") * dx" + def __eq__(self, other): + AS = self.curve + for i in len(AS.nb_of_pts_at_infty): + for g in AS.fiber(place = i): + if (self - other).group_action(g).expansion_at_infty(place = i) != 0: + return False + return True + def expansion_at_infty(self, place = 0): C = self.curve delta = C.nb_of_pts_at_infty @@ -146,7 +154,8 @@ class heisenberg_form: result = result.form Rxy. = PolynomialRing(F, 2) Qxy = FractionField(Rxy) - result = heisenberg_reduction(AS, result) + result = heisenberg_reduction(C, result) + #return heisenberg_form(C, result) return superelliptic_form(C_super, Qxy(result)) def residue(self, place=0): diff --git a/heisenberg_covers/heisenberg_function_class.sage b/heisenberg_covers/heisenberg_function_class.sage index e578757..c5f45ca 100644 --- a/heisenberg_covers/heisenberg_function_class.sage +++ b/heisenberg_covers/heisenberg_function_class.sage @@ -14,7 +14,13 @@ class heisenberg_function: #self.function = heisenberg_reduction(AS, RxyzQ(g)) def __repr__(self): - return str(self.function) + result = str(self.function) + result = result.replace('x', 'H.x') + result = result.replace('y', 'H.y') + result = result.replace('z0', 'H.z[0]') + result = result.replace('z1', 'H.z[1]') + result = result.replace('z2', 'H.z[2]') + return result def __eq__(self, other): AS = self.curve @@ -148,7 +154,6 @@ class heisenberg_function: return self.group_action(elt1).group_action((0, 0, 1)) def trace(self): - print('trace ') C = self.curve C_super = C.quotient n = C.height diff --git a/quaternion_covers/quaternion_form_class.sage b/quaternion_covers/quaternion_form_class.sage index 465f539..f6a5d1b 100644 --- a/quaternion_covers/quaternion_form_class.sage +++ b/quaternion_covers/quaternion_form_class.sage @@ -140,7 +140,7 @@ class quaternion_form: result = result.form Rxy. = PolynomialRing(F, 2) Qxy = FractionField(Rxy) - result = quaternion_reduction(AS, result) + result = quaternion_reduction(C, result) return superelliptic_form(C_super, Qxy(result)) def residue(self, place=0): diff --git a/quaternion_covers/quaternion_function_class.sage b/quaternion_covers/quaternion_function_class.sage index 6090656..c9669e1 100644 --- a/quaternion_covers/quaternion_function_class.sage +++ b/quaternion_covers/quaternion_function_class.sage @@ -160,7 +160,7 @@ class quaternion_function: result = result.function Rxy. = PolynomialRing(F, 2) Qxy = FractionField(Rxy) - result = quaternion_reduction(AS, result) + result = quaternion_reduction(C, result) return superelliptic_function(C_super, Qxy(result)) def coordinates(self, prec = 100, basis = 0):