diff --git a/README.md b/README.md index b6ea847..31c6e0c 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ Rx. = PolynomialRing(F) f = x^3 + x C = superelliptic(f, 2) -f1 = C.x^2*C_super.y +f1 = C.x^2*C.y f2 = C.x^3 AS = as_cover(C, [f1, f2], prec=1000) ``` @@ -149,7 +149,7 @@ One can decompose it into indecomposable $(\mathbb Z/p)^2$-modules, using print(magma_module_decomposition(A, B)) ``` -Note that this won't work for large genus of AS, as it uses free Magma with limited input. +Note that this won't work for large genus of AS, as it uses free Magma with limited input. You may however use it with argument *text=True*, to obtain Magma command on output. One can also look for magical elements: @@ -157,6 +157,71 @@ One can also look for magical elements: print(AS.magical_element()) ``` +## Polydifferential forms on abelian covers + +For any $(\mathbb Z/p)^n$\-cover as above, one can define a polydifferential form (i.e. a section of $\Omega^{\otimes n}$) as follows: +``` +F = GF(3) +Rx. = PolynomialRing(F) +f = x^3 + x +C = superelliptic(f, 2) +AS = as_cover(C, [C.x^2*C.y, C.x^3], prec=1000) +omega = as_polyform(AS.x^5, 3) # the first argument is a function on AS, the second is the multiplicity of polyform +print(omega) +print(omega.expansion_at_infty()) +``` +Using the command *holo_polydifferentials_basis* one may compute the basis of $H^0(\Omega^{\otimes n})$: +``` +p = 5 +F = GF(p) +Rx. = PolynomialRing(F) +C = superelliptic(x, 1) +AS = as_cover(C, [C.x^8], prec = 200) +print(AS.holo_polydifferentials_basis(2, threshold = 15)) #we increase the threshold if needed, see below +``` + +The class *as_symmetric_product_forms* may be used to define an element of $\textrm{Sym}^n \, H^0(\Omega_X)$. The command *as_symmetric_power_basis* returns a basis of $\textrm{Sym}^n \, H^0(\Omega_X)$. +``` +p = 5 +F = GF(p) +Rx. = PolynomialRing(F) +C = superelliptic(x, 1) +AS = as_cover(C, [C.x^8], prec = 200) +omega = as_symmetric_product_forms([[2, AS.dx, AS.z[0]*AS.dx], [-1, AS.x*AS.dx, AS.z[0]*AS.dx]]) +#note that the argument is a list of lists (first coefficient, then forms that occur in the given simple tensor) +print(omega) +print(as_symmetric_power_basis(AS, 2)) +``` +The method *canonical_ideal* computes the elements of $\textrm{Sym}^n \, H^0(\Omega_X)$ that are in the kernel of the multiplication map with codomain in $H^0(\Omega_X^{\otimes n})$ (i.e. the n-th homogeneous part of the canonical ideal). The method *canonical_ideal_polynomials* computes the corresponding polynomials and *group_action_canonical_ideal* the matrices of the group action on the n-th homogeneous part of the canonical ideal. +``` +p = 5 +F = GF(p) +Rx. = PolynomialRing(F) +C = superelliptic(x, 1) +AS = as_cover(C, [C.x^8], prec = 200) +print(AS.canonical_ideal(2, threshold = 15)) +print(AS.canonical_ideal_polynomials(2, threshold = 15)) +print(AS.group_action_canonical_ideal(2, threshold = 15)) +``` + +## Quaternion covers + +Some of the above methods are also implemented for quaternion covers in characteristic $2$. Those are defined by the equations $z_0^2 + z_0 = f_0, z_1^2 + z_1 = f_1, z_2^2 + z_2 = f_2 + z_0f_0 + z_1 (f_0 + f_1)$. The arguments of *quaternion_cover* are: the covered superelliptic curve $C$ and the functions $f_0$, $f_1$, $f_2$ on $C$. +``` +p = 2 +F. = GF(p^2) +Rx. = PolynomialRing(F) +C = superelliptic(x, 1) +Q = quaternion_cover(C, [C.x^3, a*C.x^3, 0*C.x], prec = 300) +print(Q) +print(Q.genus()) +print(Q.holomorphic_differentials_basis()) +print(Q.canonical_ideal_polynomials(2)) +Qi, Qj = QuaternionGroup().gens() +omega = Q.z[2]*Q.dx +print(omega.group_action(Qi), omega.group_action(Qj)) +``` + ## Common errors: 1. *Increase precision.* - Increase the *prec* argument of the curve. diff --git a/as_covers/as_polyforms.sage b/as_covers/as_polyforms.sage index 27f34e7..5f688cd 100644 --- a/as_covers/as_polyforms.sage +++ b/as_covers/as_polyforms.sage @@ -1,5 +1,6 @@ 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 @@ -28,6 +29,7 @@ class as_polyform: 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] @@ -40,6 +42,7 @@ def as_holo_polydifferentials_basis(AS, mult, threshold = 8): 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 @@ -57,6 +60,7 @@ def as_symmetric_power_basis(AS, n, threshold = 8): 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() @@ -83,13 +87,14 @@ def as_canonical_ideal(AS, n, threshold=8): 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, form1, ..., formn]''' + '''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: @@ -148,6 +153,7 @@ class as_symmetric_product_forms: 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 @@ -163,6 +169,7 @@ class as_symmetric_product_forms: return result def polynomial(self): + '''Return the associated polynomial.''' AS = self.curve F = AS.base_ring g = AS.genus() @@ -193,6 +200,7 @@ 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 @@ -205,4 +213,6 @@ def as_matrices_group_action_canonical_ideal(AS, mult, threshold = 8): for i in range(r): M[i, :] = vector(linear_representation_polynomials(K_group_action_polynomials[i], K_polynomials)) matrices += [M] - return matrices \ No newline at end of file + return matrices + +as_cover.group_action_canonical_ideal = as_matrices_group_action_canonical_ideal \ No newline at end of file diff --git a/as_covers/tests/as_polyforms_test.sage b/as_covers/tests/as_polyforms_test.sage new file mode 100644 index 0000000..9ad2d87 --- /dev/null +++ b/as_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/quaternion_covers/tests/quaternion_covers_tests.sage b/quaternion_covers/tests/quaternion_covers_tests.sage new file mode 100644 index 0000000..68ed928 --- /dev/null +++ b/quaternion_covers/tests/quaternion_covers_tests.sage @@ -0,0 +1,12 @@ +p = 2 +F. = GF(p^2) +Rx. = PolynomialRing(F) +C = superelliptic(x, 1) +Q = quaternion_cover(C, [C.x^3, a*C.x^3, 0*C.x], prec = 300) +print(Q.genus() == len(Q.holomorphic_differentials_basis())) +I2 = Q.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) +A, B = quaternion_matrices_group_action_canonical_ideal(Q, 2) +print(A * B == B^3*A, A^2 == B^2, A^4 == identity_matrix(A.dimensions()[0])) \ No newline at end of file diff --git a/tests.sage b/tests.sage index 6dd5760..e04742f 100644 --- a/tests.sage +++ b/tests.sage @@ -27,11 +27,12 @@ #load('as_covers/tests/diffn_test.sage') #print("Cartier test:") #load('as_covers/tests/cartier_test.sage') -print("Decomposition into g0, g8/ omega0, omega8 test:") -load('superelliptic_drw/tests/decomposition_into_g0_g8_tests.sage') -print("Auxilliary decomposition test:") -load('superelliptic_drw/tests/auxilliary_decompositions_test.sage') -print("Superelliptic de Rham-Witt test:") -load('superelliptic_drw/tests/superelliptic_drw_tests.sage') - +print("Polydifferentials test:") +load('as_covers/tests/as_polyforms_test.sage') +#print("Decomposition into g0, g8/ omega0, omega8 test:") +#load('superelliptic_drw/tests/decomposition_into_g0_g8_tests.sage') +#print("Auxilliary decomposition test:") +#load('superelliptic_drw/tests/auxilliary_decompositions_test.sage') +#print("Superelliptic de Rham-Witt test:") +#load('superelliptic_drw/tests/superelliptic_drw_tests.sage')