diff --git a/README.md b/README.md index 64b3bfb..35c4f77 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SAGEMATH module: superelliptic curves and their Artin-Schreier covers +# SAGEMATH module: superelliptic curves and their abelian p-group covers ## Basic information @@ -9,47 +9,160 @@ The main file is init.sage. In order to use it, type: ```sage: load('init.sage')``` The main two "packages" are intended for: + - superelliptic curves, - $(\mathbb Z/p)^n$-covers of superelliptic curves. +See below and the file examples.sage for examples. + ## Superelliptic curves -In order to define a superelliptic curve $C : y^4 = x^6 + 1$ over the finite field with 9 elements, +In order to define a superelliptic curve $C : y^4 = x^6 + 1$ over the finite field with 25 elements, use the following commands: ``` -F. = GF(9, 'a') +F. = GF(25, 'a') Rx. = PolynomialRing(F) f = x^6 + 1 C = superelliptic(f, 4) ``` + +The class $C$ has an optional argument *prec*, which gives the precision of precomputed +expansions at infinity of the functions of the curve $C$. Note that curve of the form $y^m = f(x)$ has $\delta := GCD(\deg f, m)$ +points at infinity and that $f(x)$ must be separable in order for $C$ to be smooth. + There are three auxilliary classes: superelliptic_function (for functions defined on superelliptic curves), superelliptic_form (for forms defined on superelliptic curves) and superelliptic_cech (for cech cocycles for the de Rham cohomology on superelliptic curves). -For example, in order to define the function $x + y$ on our curve $C$ we can define it like this: +For example, in order to define the function $x + 2y + 1$ on our curve $C$ we can define it like this: ``` Rxy. = PolynomialRing(F, 2) -fct = superelliptic_function(C, x + y) +fct = superelliptic_function(C, x + 2*y + 1) ``` + or simpler: + ``` -fct = C.x + C.y +fct = C.x + 2*C.y + C.one ``` Similarly, in order to define the form $\omega = y \cdot dx$ we may use: + ``` omega = superelliptic_form(C, y) ``` + or simpler: + ``` omega = C.y * C.dx ``` +The cech cocycles are given as triples: +$$ (\omega_0, f, \omega_{\infty}), $$ -## Troubleshooting +where $\omega_0$ is a form regular on $U_0$ (i.e. on the affine curve $y^m = f(x)$), +$\omega_{\infty}$ is a form regular on $U_{\infty}$, the affine curve containing the points at infinity (explicitly given by $w^{\delta} = g(v^M \cdot w^b)$, $g(x) = x^{\deg f} \cdot f(1/x)$, $\delta := GCD(m, \deg f)$, $br - am = \delta$, $M := m/\delta$) and $f$ is a function regular on $U_0 \cap U_{\infty}$ such that $\omega_0 - \omega_{\infty} = df$. See e.g. [Section 2 in article of Kock and Tait](https://arxiv.org/pdf/1709.03422.pdf). In order to access the arguments omega_0, f, omega_{\infty} of a cocyle *eta* we use the arguments *eta.omega0*, *eta.f*, *eta.omega8* respectively. Thus, let us check that the cocycle condition omega_0 - omega_{\infty} = df is satisfied for an exemplary cocycle: + +``` +eta = C.de_rham_basis()[-1] # we pick one of the forms in the de Rham basis of C +print(eta.omega0 - eta.omega8 == eta.f.diffn()) +``` + +The module allows to compute the basis of of holomorphic differential forms: + +``` +print(C.holomorphic_differentials_basis()) +``` + +One may also compute the coordinates of a given holomorphic differential form. On default, +the coordinates are computed with respect to *C.holomorphic_differentials_basis()*. +One may also give a basis as an optional argument. Note that this speeds up computation, since +the basis is not calculated several times. + +``` +omega = (2*C.y^2 - C.y + C.one)/C.y^3 * C.dx +print(omega.coordinates()) +basis = C.holomorphic_differentials_basis() +print(omega.coordinates(basis = basis)) +``` + +The method *expansion_at_infty()* allows to compute the Laurent expansion of a given function at a place at infinity. +The parameter *place* is optional. It is a number from 0 to $\delta - 1$, giving a place at infinity in which +the expansion should be computed. + +``` +print(omega.expansion_at_infty(place=0)) +print(omega.expansion_at_infty(place=1)) +``` + +One can check valuation of form/function at given place at infinity, using *valuation()* method. + +## Abelian covers of superelliptic curves + +This module allows to define $(\mathbb Z/p)^n$-covers of superelliptic curves in characteristic $p$ that +are **ramified over the points of infinity**. +We define now a $(\mathbb Z/3)^2$ cover of curve $C : y^2 = x^3 + x$, given by the equations $z_0^3 - z_0 = x^2 * y$, +$z_1^3 - z_1 = x^3$. + +``` +F = GF(3) +Rx. = PolynomialRing(F) +f = x^3 + x +C = superelliptic(f, 2) + +f1 = C.x^2*C_super.y +f2 = C.x^3 +AS = as_cover(C, [f1, f2], prec=1000) +``` + +Note that defining abelian cover may take quite a long time, since several parameters are computed. Again *prec* parameter is optional +and is required to compute some parameters of the cover. Note that the functions f1, f2 **must be polynomials in x and y** so that AS +has ramification points at infinity. + +Similarly, the are classes _as\_function, as\_form, as\_cech_ and one can write _AS.x, AS.dx_, etc. There are also methods _holomorphic\_differentials\_basis\(\)_, _de\_rham\_basis\(\)_, _coordinates\(\)_, _expansion\_at\_infty\(\)_, *valuation()* etc. +Note that some functions \(e.g. _holomorphic\_differential\_basis_\) have optional _threshold_ parameter. Increase it in case of problems. + +In order to compute the group action of $(\mathbb Z/p)^n$ on a given function/form/cocycle, use *group_action()*, e.g. + +``` +omega = AS.holomorphic_differentials_basis()[1] +print(omega.group_action([1, 0])) #group action by element [1, 0] +print(omega.group_action([0, 1])) #group action by element [0, 1] +``` + +In order to compute the matrices of the action, use *group_action_matrices_holo* and *group_action_matrices_dR*: + +``` +p = 3 +A, B = group_action_matrices_holo(AS) +n = A.dimensions()[0] +#Let us check that they commute and are of order p: +print(A*B == B*A) +print(A^p == identity_matrix(n)) +print(B^p == identity_matrix(n)) +``` + +One can decompose it into indecomposable $(\mathbb Z/p)^2$-modules, using +*magma_module_decomposition*: + +``` +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. + +One can also look for magical elements: + +``` +print(AS.magical_element()) +``` + +## Common errors: + +1. *Increase precision.* - Increase the *prec* argument of the curve. +1. *I haven't found all forms, only x of y* - Increase threshold when computing a basis. +1. *no 12 -th root; divide by 2* - when defining AS cover, one needs to compute roots of some numbers. This error means that a number is not in the field. You can either enlarge the base field, or divide one of the functions by given number and study the modified curve. +1. *unsupported operand parent(s) for %: 'The Infinity Ring' and 'The Infinity Ring'* - One of the power series turned out to be zero. Probably the AS cover that you've given is not connected (for example it is of the form $z_0^p - z_0 = f^p - f$). -- precision -- threshold -- no root in the field -- basis -- coordinates. \ No newline at end of file diff --git a/as_covers/as_auxilliary.sage b/as_covers/as_auxilliary.sage index 1539a79..fbe7828 100644 --- a/as_covers/as_auxilliary.sage +++ b/as_covers/as_auxilliary.sage @@ -1,4 +1,4 @@ -def magmathis(A, B, text = False, prefix="", sufix=""): +def magma_module_decomposition(A, B, text = False, prefix="", sufix=""): """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() diff --git a/as_covers/as_cover_class.sage b/as_covers/as_cover_class.sage index 267f9ae..0659b29 100644 --- a/as_covers/as_cover_class.sage +++ b/as_covers/as_cover_class.sage @@ -145,7 +145,7 @@ class as_cover: 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(): - print("Increase precision.") + raise ValueError("Increase precision.") return forms def cartier_matrix(self, prec=50): diff --git a/as_covers/group_action_matrices.sage b/as_covers/group_action_matrices.sage index edf0e74..b636126 100644 --- a/as_covers/group_action_matrices.sage +++ b/as_covers/group_action_matrices.sage @@ -16,7 +16,8 @@ def group_action_matrices_holo(AS): ei = n*[0] ei[i] = 1 generators += [ei] - return group_action_matrices(AS.holomorphic_differentials_basis(), generators, basis = AS.holomorphic_differentials_basis()) + basis = AS.holomorphic_differentials_basis() + return group_action_matrices(basis, generators, basis = basis) def group_action_matrices_dR(AS, threshold=8): n = AS.height diff --git a/as_covers/tests/group_action_matrices_test.sage b/as_covers/tests/group_action_matrices_test.sage index d71464a..f5a2a7f 100644 --- a/as_covers/tests/group_action_matrices_test.sage +++ b/as_covers/tests/group_action_matrices_test.sage @@ -1,17 +1,18 @@ -p = 7 +p = 3 m = 2 F = GF(p) Rx. = PolynomialRing(F) -f = x^3 + 1 +f = x^3 + x C_super = superelliptic(f, m) -Rxy. = PolynomialRing(F, 2) -f1 = superelliptic_function(C_super, x^2*y) -f2 = superelliptic_function(C_super, x^3) +f1 = C_super.x^2*C_super.y +f2 = C_super.x^3 AS = as_cover(C_super, [f1, f2], prec=1000) A, B = group_action_matrices_holo(AS) n = A.dimensions()[0] print(A*B == B*A) print(A^p == identity_matrix(n)) -print(B^p == identity_matrix(n)) \ No newline at end of file +print(B^p == identity_matrix(n)) + +print(magma_module_decomposition(A, B)) \ No newline at end of file diff --git a/example.sage b/example.sage new file mode 100644 index 0000000..443f01d --- /dev/null +++ b/example.sage @@ -0,0 +1,74 @@ +print('Remember to load init.sage!') +print('Define the superelliptic curve C : y^4 = x^6 + 1 over GF(5)') +F = GF(5) +Rx. = PolynomialRing(F) +f = x^6 + 1 +C = superelliptic(f, 4) +print(C) +print('Is is smooth?') +print(C.is_smooth()) +print('----------------------\n') +print('Define the function x + 2y + 1 on our curve C:') +Rxy. = PolynomialRing(F, 2) +fct1 = superelliptic_function(C, x + 2*y + 1) +fct2 = C.x + 2*C.y + C.one +print('In one way:', fct1, 'In another way:', fct2) +print('----------------------\n') +print('define the form omega = y * dx on C:') +omega1 = superelliptic_form(C, y) +omega2 = C.y * C.dx +print('In one way:', omega1, 'In another way:', omega2) +print('----------------------\n') +print('The holomorphic differentials basis of C:') +print(C.holomorphic_differentials_basis()) +print('Let us compute now coordinates of some differential form.') +omega = (2*C.y^2 - C.y + C.one)/C.y^3 * C.dx +print('First method:', omega.coordinates()) +basis = C.holomorphic_differentials_basis() +print('Second method (faster):', omega.coordinates(basis = basis)) +print('Compute the Laurent expansion of omega, first at one place at infinity and then at the second:') +print(omega.expansion_at_infty(place = 0)) +print(omega.expansion_at_infty(place = 1)) +print('----------------------\n') +print('The basis of de Rham cohomology of C:') +print(C.de_rham_basis()) +print('Elements of de Rham cohomology are Cech cocycles -- triples:') +eta = C.de_rham_basis()[-1] +print(eta) +print('Let us check that the cocycle condition omega_0 - omega_{\infty} = df is satisfied:') +print(eta.omega0 - eta.omega8 == eta.f.diffn()) +print('----------------------\n') +# +# +F = GF(3) +Rx. = PolynomialRing(F) +f = x^3 + x +C = superelliptic(f, 2) + +f1 = C.x^2*C_super.y +f2 = C.x^3 +AS = as_cover(C, [f1, f2], prec=1000) +print(AS) +print('----------------------\n') +print('Compute the group action of $(\mathbb Z/p)^n$ on a form:') +omega = AS.holomorphic_differentials_basis()[1] +print('Form:', omega) +print('Group action by [1, 0]:', omega.group_action([1, 0])) +print('Group action by [0, 1]:', omega.group_action([0, 1])) +print('Let us compute the matrices of the group action:') +p = 3 +A, B = group_action_matrices_holo(AS) +print(A, '\n', B) +n = A.dimensions()[0] +print('Let us check that they commute and are of order p') +print(A*B == B*A) +print(A^p == identity_matrix(n)) +print(B^p == identity_matrix(n)) +print('We decompose it into indecomposable $(\mathbb Z/p)^2$-modules:') +print(magma_module_decomposition(A, B)) + +print('----------------------\n') +print('Let us look for magical elements:') +z = AS.magical_element() +print(z) +print(z.valuation()) \ No newline at end of file diff --git a/init.sage b/init.sage index 088fd47..fa50c9c 100644 --- a/init.sage +++ b/init.sage @@ -27,10 +27,4 @@ load('auxilliaries/hensel.sage') load('auxilliaries/linear_combination_polynomials.sage') load('auxilliaries/laurent_analytic_part.sage') ############## -############## -#load('drafty/convert_superelliptic_into_AS.sage') -load('drafty/draft.sage') -#load('drafty/draft_klein_covers.sage') -#load('drafty/draft_klein_covers.sage') -#load('drafty/2gpcovers.sage') -load('drafty/pole_numbers.sage') \ No newline at end of file +############## \ No newline at end of file diff --git a/superelliptic/superelliptic_form_class.sage b/superelliptic/superelliptic_form_class.sage index b27f4f9..01ae6f0 100644 --- a/superelliptic/superelliptic_form_class.sage +++ b/superelliptic/superelliptic_form_class.sage @@ -206,4 +206,11 @@ class superelliptic_form: omega_regular = omega.regular_form() C = omega.curve p = C.characteristic - return (omega_regular.dx)^p*C.x^(p-1)*C.dx + (omega_regular.dy)^p*C.y^(p-1)*C.y.diffn() \ No newline at end of file + return (omega_regular.dx)^p*C.x^(p-1)*C.dx + (omega_regular.dy)^p*C.y^(p-1)*C.y.diffn() + + 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() \ No newline at end of file diff --git a/superelliptic/superelliptic_function_class.sage b/superelliptic/superelliptic_function_class.sage index 7aed0fe..570fb53 100644 --- a/superelliptic/superelliptic_function_class.sage +++ b/superelliptic/superelliptic_function_class.sage @@ -149,4 +149,11 @@ class superelliptic_function: auxilliary_form = auxilliary_form.cartier() auxilliary_form = C.x * auxilliary_form auxilliary_form = auxilliary_form.form - return superelliptic_function(C, auxilliary_form) \ No newline at end of file + return superelliptic_function(C, auxilliary_form) + + 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() \ No newline at end of file