passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-schemes might be problematic. Click here for more details.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,1914 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.rings.finite_rings
|
|
3
|
+
r"""
|
|
4
|
+
Hyperelliptic curves over a finite field
|
|
5
|
+
|
|
6
|
+
EXAMPLES::
|
|
7
|
+
|
|
8
|
+
sage: K.<a> = GF(9, 'a')
|
|
9
|
+
sage: x = polygen(K)
|
|
10
|
+
sage: C = HyperellipticCurve(x^7 - x^5 - 2, x^2 + a)
|
|
11
|
+
sage: C._points_fast_sqrt()
|
|
12
|
+
[(0 : 1 : 0), (a + 1 : a : 1), (a + 1 : a + 1 : 1), (2 : a + 1 : 1),
|
|
13
|
+
(2*a : 2*a + 2 : 1), (2*a : 2*a : 1), (1 : a + 1 : 1)]
|
|
14
|
+
|
|
15
|
+
AUTHORS:
|
|
16
|
+
|
|
17
|
+
- David Kohel (2006)
|
|
18
|
+
|
|
19
|
+
- Robert Bradshaw (2007)
|
|
20
|
+
|
|
21
|
+
- Alyson Deines, Marina Gresham, Gagan Sekhon, (2010)
|
|
22
|
+
|
|
23
|
+
- Daniel Krenn (2011)
|
|
24
|
+
|
|
25
|
+
- Jean-Pierre Flori, Jan Tuitman (2013)
|
|
26
|
+
|
|
27
|
+
- Kiran Kedlaya (2016)
|
|
28
|
+
|
|
29
|
+
- Dean Bisogno (2017): Fixed Hasse-Witt computation
|
|
30
|
+
"""
|
|
31
|
+
# ****************************************************************************
|
|
32
|
+
# Copyright (C) 2006 David Kohel <kohel@maths.usyd.edu>
|
|
33
|
+
# Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu>
|
|
34
|
+
# Copyright (C) 2010 Alyson Deines <aly.deines@gmail.com>, Marina Gresham
|
|
35
|
+
# <marina.gresham@coloradocollege.edu>, Gagan Sekhon <gagan.d.sekhon@gmail.com>
|
|
36
|
+
# Copyright (C) 2011 Daniel Krenn
|
|
37
|
+
# Copyright (C) 2013 Jean-Pierre Flori <jean-pierre.flori@ssi.gouv.fr>,
|
|
38
|
+
# Jan Tuitman <jan.tuitman@wis.kuleuven.be>
|
|
39
|
+
# Copyright (C) 2016 Kiran Kedlaya <kedlaya@ucsd.edu>
|
|
40
|
+
#
|
|
41
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
42
|
+
#
|
|
43
|
+
# This code is distributed in the hope that it will be useful,
|
|
44
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
45
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
46
|
+
# General Public License for more details.
|
|
47
|
+
#
|
|
48
|
+
# The full text of the GPL is available at:
|
|
49
|
+
#
|
|
50
|
+
# https://www.gnu.org/licenses/
|
|
51
|
+
# ****************************************************************************
|
|
52
|
+
|
|
53
|
+
from sage.rings.integer_ring import ZZ
|
|
54
|
+
from sage.rings.real_mpfr import RR
|
|
55
|
+
from sage.rings.rational_field import QQ
|
|
56
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
|
|
57
|
+
from sage.arith.misc import binomial
|
|
58
|
+
from sage.rings.power_series_ring import PowerSeriesRing
|
|
59
|
+
from . import hyperelliptic_generic
|
|
60
|
+
from sage.misc.cachefunc import cached_method
|
|
61
|
+
from sage.matrix.constructor import identity_matrix, matrix
|
|
62
|
+
from sage.misc.functional import rank
|
|
63
|
+
from sage.misc.lazy_import import lazy_import
|
|
64
|
+
|
|
65
|
+
lazy_import('sage.libs.pari', 'pari')
|
|
66
|
+
lazy_import('sage.schemes.hyperelliptic_curves.hypellfrob', 'hypellfrob')
|
|
67
|
+
|
|
68
|
+
from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_finite_field
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class HyperellipticCurve_finite_field(hyperelliptic_generic.HyperellipticCurve_generic,
|
|
72
|
+
ProjectivePlaneCurve_finite_field):
|
|
73
|
+
def _frobenius_coefficient_bound_charpoly(self):
|
|
74
|
+
r"""
|
|
75
|
+
Compute bound on number of `p`-adic digits needed to recover
|
|
76
|
+
frobenius polynomial computing the characteristic polynomial
|
|
77
|
+
of the frobenius matrix, i.e. return `B` so that knowledge of
|
|
78
|
+
`a_1`, ..., `a_g` modulo `p^B` determine frobenius polynomial
|
|
79
|
+
uniquely.
|
|
80
|
+
|
|
81
|
+
The bound used here stems from the expression of the coefficients
|
|
82
|
+
of the characteristic polynomial of the Frobenius as sums
|
|
83
|
+
of products of its eigenvalues:
|
|
84
|
+
|
|
85
|
+
.. MATH::
|
|
86
|
+
|
|
87
|
+
\| a_i \| \leq \binom{2g}{i} \sqrt{q}^i
|
|
88
|
+
|
|
89
|
+
EXAMPLES::
|
|
90
|
+
|
|
91
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
92
|
+
sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
93
|
+
1
|
|
94
|
+
sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
95
|
+
2
|
|
96
|
+
sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
97
|
+
3
|
|
98
|
+
|
|
99
|
+
sage: R.<t> = PolynomialRing(GF(next_prime(10^9)))
|
|
100
|
+
sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
101
|
+
1
|
|
102
|
+
sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
103
|
+
2
|
|
104
|
+
sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
105
|
+
2
|
|
106
|
+
sage: HyperellipticCurve(t^9 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
107
|
+
3
|
|
108
|
+
sage: HyperellipticCurve(t^11 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
109
|
+
3
|
|
110
|
+
sage: HyperellipticCurve(t^13 + t + 1)._frobenius_coefficient_bound_charpoly()
|
|
111
|
+
4
|
|
112
|
+
"""
|
|
113
|
+
assert self.base_ring().is_finite()
|
|
114
|
+
p = self.base_ring().characteristic()
|
|
115
|
+
q = self.base_ring().order()
|
|
116
|
+
sqrtq = RR(q).sqrt()
|
|
117
|
+
g = self.genus()
|
|
118
|
+
|
|
119
|
+
# note: this bound is from Kedlaya's paper, but he tells me it's not
|
|
120
|
+
# the best possible
|
|
121
|
+
M = 2 * binomial(2*g, g) * sqrtq**g
|
|
122
|
+
B = ZZ(M.ceil()).exact_log(p)
|
|
123
|
+
if p**B < M:
|
|
124
|
+
B += 1
|
|
125
|
+
return B
|
|
126
|
+
|
|
127
|
+
def _frobenius_coefficient_bound_traces(self, n=1):
|
|
128
|
+
r"""
|
|
129
|
+
Compute bound on number of `p`-adic digits needed to recover
|
|
130
|
+
the number of rational points on `n` extensions computing
|
|
131
|
+
traces of the frobenius matrix powers, i.e. return `B` so that
|
|
132
|
+
knowledge of `\tr(M^1)`, ..., `\tr(M^n)` modulo `p^B` determine
|
|
133
|
+
`N_1`, ..., `N_n` uniquely.
|
|
134
|
+
|
|
135
|
+
The formula stems from the expression of the trace of the Frobenius
|
|
136
|
+
as a sum of `i`-th powers of its eigenvalues.
|
|
137
|
+
|
|
138
|
+
.. MATH::
|
|
139
|
+
|
|
140
|
+
\| \tr(M^i) \| \leq 2 g \sqrt{q}^i
|
|
141
|
+
|
|
142
|
+
EXAMPLES::
|
|
143
|
+
|
|
144
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
145
|
+
sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound_traces()
|
|
146
|
+
1
|
|
147
|
+
sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound_traces()
|
|
148
|
+
2
|
|
149
|
+
sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound_traces()
|
|
150
|
+
2
|
|
151
|
+
|
|
152
|
+
sage: R.<t> = PolynomialRing(GF(next_prime(10^9)))
|
|
153
|
+
sage: HyperellipticCurve(t^3 + t + 1)._frobenius_coefficient_bound_traces()
|
|
154
|
+
1
|
|
155
|
+
sage: HyperellipticCurve(t^5 + t + 1)._frobenius_coefficient_bound_traces()
|
|
156
|
+
1
|
|
157
|
+
sage: HyperellipticCurve(t^7 + t + 1)._frobenius_coefficient_bound_traces()
|
|
158
|
+
1
|
|
159
|
+
sage: HyperellipticCurve(t^9 + t + 1)._frobenius_coefficient_bound_traces(n=3)
|
|
160
|
+
2
|
|
161
|
+
sage: HyperellipticCurve(t^11 + t + 1)._frobenius_coefficient_bound_traces(n=3)
|
|
162
|
+
2
|
|
163
|
+
sage: HyperellipticCurve(t^13 + t + 1)._frobenius_coefficient_bound_traces(n=5)
|
|
164
|
+
3
|
|
165
|
+
|
|
166
|
+
sage: R.<t> = PolynomialRing(GF(11))
|
|
167
|
+
sage: H = HyperellipticCurve(t^5 - t + 1)
|
|
168
|
+
sage: H._frobenius_coefficient_bound_traces()
|
|
169
|
+
2
|
|
170
|
+
"""
|
|
171
|
+
p = self.base_ring().characteristic()
|
|
172
|
+
q = self.base_ring().order()
|
|
173
|
+
sqrtq = RR(q).sqrt()
|
|
174
|
+
g = self.genus()
|
|
175
|
+
|
|
176
|
+
M = 4 * g * sqrtq**n
|
|
177
|
+
B = ZZ(M.ceil()).exact_log(p)
|
|
178
|
+
if p**B < M:
|
|
179
|
+
B += 1
|
|
180
|
+
return B
|
|
181
|
+
|
|
182
|
+
def frobenius_matrix_hypellfrob(self, N=None):
|
|
183
|
+
r"""
|
|
184
|
+
Compute `p`-adic frobenius matrix to precision `p^N`.
|
|
185
|
+
If `N` not supplied, a default value is selected, which is the
|
|
186
|
+
minimum needed to recover the charpoly unambiguously.
|
|
187
|
+
|
|
188
|
+
.. NOTE::
|
|
189
|
+
|
|
190
|
+
Implemented using ``hypellfrob``, which means it only works
|
|
191
|
+
over the prime field `GF(p)`, and requires `p > (2g+1)(2N-1)`.
|
|
192
|
+
|
|
193
|
+
EXAMPLES::
|
|
194
|
+
|
|
195
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
196
|
+
sage: H = HyperellipticCurve(t^5 + t + 2)
|
|
197
|
+
sage: H.frobenius_matrix_hypellfrob()
|
|
198
|
+
[1258 + O(37^2) 925 + O(37^2) 132 + O(37^2) 587 + O(37^2)]
|
|
199
|
+
[1147 + O(37^2) 814 + O(37^2) 241 + O(37^2) 1011 + O(37^2)]
|
|
200
|
+
[1258 + O(37^2) 1184 + O(37^2) 1105 + O(37^2) 482 + O(37^2)]
|
|
201
|
+
[1073 + O(37^2) 999 + O(37^2) 772 + O(37^2) 929 + O(37^2)]
|
|
202
|
+
|
|
203
|
+
The ``hypellfrob`` program doesn't support non-prime fields::
|
|
204
|
+
|
|
205
|
+
sage: K.<z> = GF(37**3)
|
|
206
|
+
sage: R.<t> = PolynomialRing(K)
|
|
207
|
+
sage: H = HyperellipticCurve(t^9 + z*t^3 + 1)
|
|
208
|
+
sage: H.frobenius_matrix_hypellfrob()
|
|
209
|
+
Traceback (most recent call last):
|
|
210
|
+
...
|
|
211
|
+
NotImplementedError: Computation of Frobenius matrix only implemented
|
|
212
|
+
for hyperelliptic curves defined over prime fields.
|
|
213
|
+
|
|
214
|
+
nor too small characteristic::
|
|
215
|
+
|
|
216
|
+
sage: K = GF(7)
|
|
217
|
+
sage: R.<t> = PolynomialRing(K)
|
|
218
|
+
sage: H = HyperellipticCurve(t^9 + t^3 + 1)
|
|
219
|
+
sage: H.frobenius_matrix_hypellfrob()
|
|
220
|
+
Traceback (most recent call last):
|
|
221
|
+
...
|
|
222
|
+
ValueError: In the current implementation, p must be greater than (2g+1)(2N-1) = 81
|
|
223
|
+
"""
|
|
224
|
+
p = self.base_ring().characteristic()
|
|
225
|
+
e = self.base_ring().degree()
|
|
226
|
+
if e != 1:
|
|
227
|
+
raise NotImplementedError("Computation of Frobenius matrix only implemented for hyperelliptic curves defined over prime fields.")
|
|
228
|
+
|
|
229
|
+
f, h = self.hyperelliptic_polynomials()
|
|
230
|
+
if h != 0:
|
|
231
|
+
# need y^2 = f(x)
|
|
232
|
+
raise NotImplementedError("only implemented for curves y^2 = f(x)")
|
|
233
|
+
|
|
234
|
+
sign = 1
|
|
235
|
+
if not f.is_monic():
|
|
236
|
+
# at this time we need a monic f
|
|
237
|
+
c = f.leading_coefficient()
|
|
238
|
+
f = f / c
|
|
239
|
+
if c.is_square():
|
|
240
|
+
# solutions of $y^2 = c * f(x)$ correspond naturally to
|
|
241
|
+
# solutions of $(sqrt(c) y)^2 = f(x)$
|
|
242
|
+
pass
|
|
243
|
+
else:
|
|
244
|
+
# we'll count points on a twist and then correct by untwisting...
|
|
245
|
+
sign = -1
|
|
246
|
+
assert f.is_monic()
|
|
247
|
+
|
|
248
|
+
# By default, use precision enough to be able to compute the
|
|
249
|
+
# frobenius minimal polynomial
|
|
250
|
+
if N is None:
|
|
251
|
+
N = self._frobenius_coefficient_bound_charpoly()
|
|
252
|
+
|
|
253
|
+
matrix_of_frobenius = hypellfrob(p, N, f)
|
|
254
|
+
matrix_of_frobenius = sign * matrix_of_frobenius
|
|
255
|
+
return matrix_of_frobenius
|
|
256
|
+
|
|
257
|
+
def frobenius_matrix(self, N=None, algorithm='hypellfrob'):
|
|
258
|
+
r"""
|
|
259
|
+
Compute `p`-adic frobenius matrix to precision `p^N`.
|
|
260
|
+
If `N` not supplied, a default value is selected, which is the
|
|
261
|
+
minimum needed to recover the charpoly unambiguously.
|
|
262
|
+
|
|
263
|
+
.. NOTE::
|
|
264
|
+
|
|
265
|
+
Currently only implemented using ``hypellfrob``,
|
|
266
|
+
which means it only works over the prime field `GF(p)`,
|
|
267
|
+
and requires `p > (2g+1)(2N-1)`.
|
|
268
|
+
|
|
269
|
+
EXAMPLES::
|
|
270
|
+
|
|
271
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
272
|
+
sage: H = HyperellipticCurve(t^5 + t + 2)
|
|
273
|
+
sage: H.frobenius_matrix()
|
|
274
|
+
[1258 + O(37^2) 925 + O(37^2) 132 + O(37^2) 587 + O(37^2)]
|
|
275
|
+
[1147 + O(37^2) 814 + O(37^2) 241 + O(37^2) 1011 + O(37^2)]
|
|
276
|
+
[1258 + O(37^2) 1184 + O(37^2) 1105 + O(37^2) 482 + O(37^2)]
|
|
277
|
+
[1073 + O(37^2) 999 + O(37^2) 772 + O(37^2) 929 + O(37^2)]
|
|
278
|
+
|
|
279
|
+
The ``hypellfrob`` program doesn't support non-prime fields::
|
|
280
|
+
|
|
281
|
+
sage: K.<z> = GF(37**3)
|
|
282
|
+
sage: R.<t> = PolynomialRing(K)
|
|
283
|
+
sage: H = HyperellipticCurve(t^9 + z*t^3 + 1)
|
|
284
|
+
sage: H.frobenius_matrix(algorithm='hypellfrob')
|
|
285
|
+
Traceback (most recent call last):
|
|
286
|
+
...
|
|
287
|
+
NotImplementedError: Computation of Frobenius matrix only implemented
|
|
288
|
+
for hyperelliptic curves defined over prime fields.
|
|
289
|
+
|
|
290
|
+
nor too small characteristic::
|
|
291
|
+
|
|
292
|
+
sage: K = GF(7)
|
|
293
|
+
sage: R.<t> = PolynomialRing(K)
|
|
294
|
+
sage: H = HyperellipticCurve(t^9 + t^3 + 1)
|
|
295
|
+
sage: H.frobenius_matrix(algorithm='hypellfrob')
|
|
296
|
+
Traceback (most recent call last):
|
|
297
|
+
...
|
|
298
|
+
ValueError: In the current implementation, p must be greater than (2g+1)(2N-1) = 81
|
|
299
|
+
"""
|
|
300
|
+
if algorithm != 'hypellfrob':
|
|
301
|
+
raise ValueError("Unknown algorithm")
|
|
302
|
+
|
|
303
|
+
# By default, use precision enough to be able to compute the
|
|
304
|
+
# frobenius minimal polynomial
|
|
305
|
+
if N is None:
|
|
306
|
+
N = self._frobenius_coefficient_bound_charpoly()
|
|
307
|
+
|
|
308
|
+
return self.frobenius_matrix_hypellfrob(N=N)
|
|
309
|
+
|
|
310
|
+
def frobenius_polynomial_cardinalities(self, a=None):
|
|
311
|
+
r"""
|
|
312
|
+
Compute the charpoly of frobenius, as an element of `\ZZ[x]`,
|
|
313
|
+
by computing the number of points on the curve over `g` extensions
|
|
314
|
+
of the base field where `g` is the genus of the curve.
|
|
315
|
+
|
|
316
|
+
.. WARNING::
|
|
317
|
+
|
|
318
|
+
This is highly inefficient when the base field or the genus of the
|
|
319
|
+
curve are large.
|
|
320
|
+
|
|
321
|
+
EXAMPLES::
|
|
322
|
+
|
|
323
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
324
|
+
sage: H = HyperellipticCurve(t^5 + t + 2)
|
|
325
|
+
sage: H.frobenius_polynomial_cardinalities()
|
|
326
|
+
x^4 + x^3 - 52*x^2 + 37*x + 1369
|
|
327
|
+
|
|
328
|
+
A quadratic twist::
|
|
329
|
+
|
|
330
|
+
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
|
|
331
|
+
sage: H.frobenius_polynomial_cardinalities()
|
|
332
|
+
x^4 - x^3 - 52*x^2 - 37*x + 1369
|
|
333
|
+
|
|
334
|
+
Curve over a non-prime field::
|
|
335
|
+
|
|
336
|
+
sage: K.<z> = GF(7**2)
|
|
337
|
+
sage: R.<t> = PolynomialRing(K)
|
|
338
|
+
sage: H = HyperellipticCurve(t^5 + z*t + z^2)
|
|
339
|
+
sage: H.frobenius_polynomial_cardinalities()
|
|
340
|
+
x^4 + 8*x^3 + 70*x^2 + 392*x + 2401
|
|
341
|
+
|
|
342
|
+
This method may actually be useful when ``hypellfrob`` does not work::
|
|
343
|
+
|
|
344
|
+
sage: K = GF(7)
|
|
345
|
+
sage: R.<t> = PolynomialRing(K)
|
|
346
|
+
sage: H = HyperellipticCurve(t^9 + t^3 + 1)
|
|
347
|
+
sage: H.frobenius_polynomial_matrix(algorithm='hypellfrob')
|
|
348
|
+
Traceback (most recent call last):
|
|
349
|
+
...
|
|
350
|
+
ValueError: In the current implementation, p must be greater than (2g+1)(2N-1) = 81
|
|
351
|
+
sage: H.frobenius_polynomial_cardinalities()
|
|
352
|
+
x^8 - 5*x^7 + 7*x^6 + 36*x^5 - 180*x^4 + 252*x^3 + 343*x^2 - 1715*x + 2401
|
|
353
|
+
"""
|
|
354
|
+
g = self.genus()
|
|
355
|
+
q = self.base_ring().cardinality()
|
|
356
|
+
|
|
357
|
+
if a is None:
|
|
358
|
+
# this may actually call frobenius_polynomial()
|
|
359
|
+
a = self.count_points(g)
|
|
360
|
+
# maybe calling count_points_exhaustive() would make more sense
|
|
361
|
+
# but the method is currently only called with a precomputed list
|
|
362
|
+
# of number of points so it does not really matter
|
|
363
|
+
|
|
364
|
+
# computation of the reciprocal polynomial
|
|
365
|
+
s = [ai - q**(i+1) - 1 for i, ai in enumerate(a)]
|
|
366
|
+
coeffs = [1]
|
|
367
|
+
for i in range(1, g + 1):
|
|
368
|
+
c = 0
|
|
369
|
+
for j in range(i):
|
|
370
|
+
c += s[i-1-j]*coeffs[j]
|
|
371
|
+
coeffs.append(c/i)
|
|
372
|
+
coeffs = coeffs + [coeffs[g-i] * q**(i) for i in range(1, g + 1)]
|
|
373
|
+
|
|
374
|
+
return ZZ['x'](coeffs).reverse()
|
|
375
|
+
|
|
376
|
+
def frobenius_polynomial_matrix(self, M=None, algorithm='hypellfrob'):
|
|
377
|
+
r"""
|
|
378
|
+
Compute the charpoly of frobenius, as an element of `\ZZ[x]`,
|
|
379
|
+
by computing the charpoly of the frobenius matrix.
|
|
380
|
+
|
|
381
|
+
This is currently only supported when the base field is prime
|
|
382
|
+
and large enough using the ``hypellfrob`` library.
|
|
383
|
+
|
|
384
|
+
EXAMPLES::
|
|
385
|
+
|
|
386
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
387
|
+
sage: H = HyperellipticCurve(t^5 + t + 2)
|
|
388
|
+
sage: H.frobenius_polynomial_matrix()
|
|
389
|
+
x^4 + x^3 - 52*x^2 + 37*x + 1369
|
|
390
|
+
|
|
391
|
+
A quadratic twist::
|
|
392
|
+
|
|
393
|
+
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
|
|
394
|
+
sage: H.frobenius_polynomial_matrix()
|
|
395
|
+
x^4 - x^3 - 52*x^2 - 37*x + 1369
|
|
396
|
+
|
|
397
|
+
Curves defined over larger prime fields::
|
|
398
|
+
|
|
399
|
+
sage: K = GF(49999)
|
|
400
|
+
sage: R.<t> = PolynomialRing(K)
|
|
401
|
+
sage: H = HyperellipticCurve(t^9 + t^5 + 1)
|
|
402
|
+
sage: H.frobenius_polynomial_matrix()
|
|
403
|
+
x^8 + 281*x^7 + 55939*x^6 + 14144175*x^5 + 3156455369*x^4 + 707194605825*x^3
|
|
404
|
+
+ 139841906155939*x^2 + 35122892542149719*x + 6249500014999800001
|
|
405
|
+
sage: H = HyperellipticCurve(t^15 + t^5 + 1)
|
|
406
|
+
sage: H.frobenius_polynomial_matrix() # long time, 8s on a Corei7
|
|
407
|
+
x^14 - 76*x^13 + 220846*x^12 - 12984372*x^11 + 24374326657*x^10 - 1203243210304*x^9
|
|
408
|
+
+ 1770558798515792*x^8 - 74401511415210496*x^7 + 88526169366991084208*x^6
|
|
409
|
+
- 3007987702642212810304*x^5 + 3046608028331197124223343*x^4
|
|
410
|
+
- 81145833008762983138584372*x^3 + 69007473838551978905211279154*x^2
|
|
411
|
+
- 1187357507124810002849977200076*x + 781140631562281254374947500349999
|
|
412
|
+
|
|
413
|
+
This ``hypellfrob`` program doesn't support non-prime fields::
|
|
414
|
+
|
|
415
|
+
sage: K.<z> = GF(37**3)
|
|
416
|
+
sage: R.<t> = PolynomialRing(K)
|
|
417
|
+
sage: H = HyperellipticCurve(t^9 + z*t^3 + 1)
|
|
418
|
+
sage: H.frobenius_polynomial_matrix(algorithm='hypellfrob')
|
|
419
|
+
Traceback (most recent call last):
|
|
420
|
+
...
|
|
421
|
+
NotImplementedError: Computation of Frobenius matrix only implemented
|
|
422
|
+
for hyperelliptic curves defined over prime fields.
|
|
423
|
+
"""
|
|
424
|
+
K = self.base_ring()
|
|
425
|
+
p = K.characteristic()
|
|
426
|
+
q = K.cardinality()
|
|
427
|
+
g = self.genus()
|
|
428
|
+
N = self._frobenius_coefficient_bound_charpoly()
|
|
429
|
+
# compute charpoly over ZZ and then reduce back
|
|
430
|
+
# (because charpoly of p-adic matrices sometimes loses precision)
|
|
431
|
+
M = self.frobenius_matrix(N=N, algorithm=algorithm).change_ring(ZZ)
|
|
432
|
+
|
|
433
|
+
# get a_g, ..., a_0 in ZZ (i.e. with correct signs)
|
|
434
|
+
f = M.charpoly().list()[g:2*g+1]
|
|
435
|
+
ppow = p**N
|
|
436
|
+
f = [x % ppow for x in f]
|
|
437
|
+
f = [x if 2*x < ppow else x - ppow for x in f]
|
|
438
|
+
|
|
439
|
+
# get a_{2g}, ..., a_{g+1}
|
|
440
|
+
f = [f[g-i] * q**(g-i) for i in range(g)] + f
|
|
441
|
+
|
|
442
|
+
return ZZ['x'](f)
|
|
443
|
+
|
|
444
|
+
def frobenius_polynomial_pari(self):
|
|
445
|
+
r"""
|
|
446
|
+
Compute the charpoly of frobenius, as an element of `\ZZ[x]`,
|
|
447
|
+
by calling the PARI function ``hyperellcharpoly``.
|
|
448
|
+
|
|
449
|
+
EXAMPLES::
|
|
450
|
+
|
|
451
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
452
|
+
sage: H = HyperellipticCurve(t^5 + t + 2)
|
|
453
|
+
sage: H.frobenius_polynomial_pari()
|
|
454
|
+
x^4 + x^3 - 52*x^2 + 37*x + 1369
|
|
455
|
+
|
|
456
|
+
A quadratic twist::
|
|
457
|
+
|
|
458
|
+
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
|
|
459
|
+
sage: H.frobenius_polynomial_pari()
|
|
460
|
+
x^4 - x^3 - 52*x^2 - 37*x + 1369
|
|
461
|
+
|
|
462
|
+
Slightly larger example::
|
|
463
|
+
|
|
464
|
+
sage: K = GF(2003)
|
|
465
|
+
sage: R.<t> = PolynomialRing(K)
|
|
466
|
+
sage: H = HyperellipticCurve(t^7 + 487*t^5 + 9*t + 1)
|
|
467
|
+
sage: H.frobenius_polynomial_pari()
|
|
468
|
+
x^6 - 14*x^5 + 1512*x^4 - 66290*x^3 + 3028536*x^2 - 56168126*x + 8036054027
|
|
469
|
+
|
|
470
|
+
Curves defined over a non-prime field are supported as well::
|
|
471
|
+
|
|
472
|
+
sage: K.<a> = GF(7^2)
|
|
473
|
+
sage: R.<t> = PolynomialRing(K)
|
|
474
|
+
sage: H = HyperellipticCurve(t^5 + a*t + 1)
|
|
475
|
+
sage: H.frobenius_polynomial_pari()
|
|
476
|
+
x^4 + 4*x^3 + 84*x^2 + 196*x + 2401
|
|
477
|
+
|
|
478
|
+
sage: K.<z> = GF(23**3)
|
|
479
|
+
sage: R.<t> = PolynomialRing(K)
|
|
480
|
+
sage: H = HyperellipticCurve(t^3 + z*t + 4)
|
|
481
|
+
sage: H.frobenius_polynomial_pari()
|
|
482
|
+
x^2 - 15*x + 12167
|
|
483
|
+
|
|
484
|
+
Over prime fields of odd characteristic, `h` may be nonzero::
|
|
485
|
+
|
|
486
|
+
sage: K = GF(101)
|
|
487
|
+
sage: R.<t> = PolynomialRing(K)
|
|
488
|
+
sage: H = HyperellipticCurve(t^5 + 27*t + 3, t)
|
|
489
|
+
sage: H.frobenius_polynomial_pari()
|
|
490
|
+
x^4 + 2*x^3 - 58*x^2 + 202*x + 10201
|
|
491
|
+
|
|
492
|
+
TESTS:
|
|
493
|
+
|
|
494
|
+
Check that :issue:`28789` is fixed::
|
|
495
|
+
|
|
496
|
+
sage: P.<x> = PolynomialRing(GF(3))
|
|
497
|
+
sage: u = x^10 + x^9 + x^8 + x
|
|
498
|
+
sage: C = HyperellipticCurve(u)
|
|
499
|
+
sage: C.frobenius_polynomial_pari()
|
|
500
|
+
x^8 + 2*x^7 + 6*x^6 + 9*x^5 + 18*x^4 + 27*x^3 + 54*x^2 + 54*x + 81
|
|
501
|
+
"""
|
|
502
|
+
f, h = self.hyperelliptic_polynomials()
|
|
503
|
+
return ZZ['x'](pari([f, h]).hyperellcharpoly())
|
|
504
|
+
|
|
505
|
+
@cached_method
|
|
506
|
+
def frobenius_polynomial(self):
|
|
507
|
+
r"""
|
|
508
|
+
Compute the charpoly of frobenius, as an element of `\ZZ[x]`.
|
|
509
|
+
|
|
510
|
+
EXAMPLES::
|
|
511
|
+
|
|
512
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
513
|
+
sage: H = HyperellipticCurve(t^5 + t + 2)
|
|
514
|
+
sage: H.frobenius_polynomial()
|
|
515
|
+
x^4 + x^3 - 52*x^2 + 37*x + 1369
|
|
516
|
+
|
|
517
|
+
A quadratic twist::
|
|
518
|
+
|
|
519
|
+
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
|
|
520
|
+
sage: H.frobenius_polynomial()
|
|
521
|
+
x^4 - x^3 - 52*x^2 - 37*x + 1369
|
|
522
|
+
|
|
523
|
+
Slightly larger example::
|
|
524
|
+
|
|
525
|
+
sage: K = GF(2003)
|
|
526
|
+
sage: R.<t> = PolynomialRing(K)
|
|
527
|
+
sage: H = HyperellipticCurve(t^7 + 487*t^5 + 9*t + 1)
|
|
528
|
+
sage: H.frobenius_polynomial()
|
|
529
|
+
x^6 - 14*x^5 + 1512*x^4 - 66290*x^3 + 3028536*x^2 - 56168126*x + 8036054027
|
|
530
|
+
|
|
531
|
+
Curves defined over a non-prime field of odd characteristic,
|
|
532
|
+
or an odd prime field which is too small compared to the genus,
|
|
533
|
+
are supported via PARI::
|
|
534
|
+
|
|
535
|
+
sage: K.<z> = GF(23**3)
|
|
536
|
+
sage: R.<t> = PolynomialRing(K)
|
|
537
|
+
sage: H = HyperellipticCurve(t^3 + z*t + 4)
|
|
538
|
+
sage: H.frobenius_polynomial()
|
|
539
|
+
x^2 - 15*x + 12167
|
|
540
|
+
|
|
541
|
+
sage: K.<z> = GF(3**3)
|
|
542
|
+
sage: R.<t> = PolynomialRing(K)
|
|
543
|
+
sage: H = HyperellipticCurve(t^5 + z*t + z**3)
|
|
544
|
+
sage: H.frobenius_polynomial()
|
|
545
|
+
x^4 - 3*x^3 + 10*x^2 - 81*x + 729
|
|
546
|
+
|
|
547
|
+
Over prime fields of odd characteristic, `h` may be nonzero::
|
|
548
|
+
|
|
549
|
+
sage: K = GF(101)
|
|
550
|
+
sage: R.<t> = PolynomialRing(K)
|
|
551
|
+
sage: H = HyperellipticCurve(t^5 + 27*t + 3, t)
|
|
552
|
+
sage: H.frobenius_polynomial()
|
|
553
|
+
x^4 + 2*x^3 - 58*x^2 + 202*x + 10201
|
|
554
|
+
|
|
555
|
+
Over prime fields of odd characteristic, `f` may have even degree::
|
|
556
|
+
|
|
557
|
+
sage: H = HyperellipticCurve(t^6 + 27*t + 3)
|
|
558
|
+
sage: H.frobenius_polynomial()
|
|
559
|
+
x^4 + 25*x^3 + 322*x^2 + 2525*x + 10201
|
|
560
|
+
|
|
561
|
+
In even characteristic, the naive algorithm could cover all cases
|
|
562
|
+
because we can easily check for squareness in quotient rings of
|
|
563
|
+
polynomial rings over finite fields but these rings unfortunately
|
|
564
|
+
do not support iteration::
|
|
565
|
+
|
|
566
|
+
sage: K.<z> = GF(2**5)
|
|
567
|
+
sage: R.<t> = PolynomialRing(K)
|
|
568
|
+
sage: H = HyperellipticCurve(t^5 + z*t + z**3, t)
|
|
569
|
+
sage: H.frobenius_polynomial()
|
|
570
|
+
x^4 - x^3 + 16*x^2 - 32*x + 1024
|
|
571
|
+
|
|
572
|
+
TESTS:
|
|
573
|
+
|
|
574
|
+
Check that :issue:`28789` is fixed::
|
|
575
|
+
|
|
576
|
+
sage: P.<x> = PolynomialRing(GF(3))
|
|
577
|
+
sage: u = x^10 + x^9 + x^8 + x
|
|
578
|
+
sage: C = HyperellipticCurve(u)
|
|
579
|
+
sage: C.frobenius_polynomial()
|
|
580
|
+
x^8 + 2*x^7 + 6*x^6 + 9*x^5 + 18*x^4 + 27*x^3 + 54*x^2 + 54*x + 81
|
|
581
|
+
"""
|
|
582
|
+
K = self.base_ring()
|
|
583
|
+
e = K.degree()
|
|
584
|
+
q = K.cardinality()
|
|
585
|
+
|
|
586
|
+
g = self.genus()
|
|
587
|
+
f, h = self.hyperelliptic_polynomials()
|
|
588
|
+
|
|
589
|
+
if (e == 1 and
|
|
590
|
+
q >= (2*g+1)*(2*self._frobenius_coefficient_bound_charpoly()-1) and
|
|
591
|
+
h == 0 and f.degree() % 2):
|
|
592
|
+
return self.frobenius_polynomial_matrix()
|
|
593
|
+
elif q % 2 == 1:
|
|
594
|
+
return self.frobenius_polynomial_pari()
|
|
595
|
+
else:
|
|
596
|
+
return self.frobenius_polynomial_cardinalities()
|
|
597
|
+
|
|
598
|
+
def _points_fast_sqrt(self):
|
|
599
|
+
"""
|
|
600
|
+
List points by enumerating over x and solving the resulting
|
|
601
|
+
quadratic for y.
|
|
602
|
+
|
|
603
|
+
EXAMPLES::
|
|
604
|
+
|
|
605
|
+
sage: K.<a> = GF(9, 'a')
|
|
606
|
+
sage: x = polygen(K)
|
|
607
|
+
sage: C = HyperellipticCurve(x^7 - 1, x^2 + a)
|
|
608
|
+
sage: C._points_fast_sqrt()
|
|
609
|
+
[(0 : 1 : 0), (a : 2*a + 1 : 1), (2 : a + 1 : 1), (2*a + 2 : 2*a : 1),
|
|
610
|
+
(2*a + 2 : 1 : 1), (1 : 2*a + 2 : 1), (1 : 0 : 1)]
|
|
611
|
+
sage: K.<a> = GF(49, 'a')
|
|
612
|
+
sage: x = polygen(K)
|
|
613
|
+
sage: C = HyperellipticCurve(x^5 - x^2 - 1, x^2 + a)
|
|
614
|
+
sage: len(C._points_fast_sqrt())
|
|
615
|
+
31
|
|
616
|
+
|
|
617
|
+
TESTS::
|
|
618
|
+
|
|
619
|
+
sage: x = polygen(GF(16, 'a'))
|
|
620
|
+
sage: C = HyperellipticCurve(x^5 - x + 1, x^2 + x + 1)
|
|
621
|
+
sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())
|
|
622
|
+
True
|
|
623
|
+
sage: x = polygen(GF(19))
|
|
624
|
+
sage: C = HyperellipticCurve(x^5 + 5*x^2 + 1, x + 1)
|
|
625
|
+
sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())
|
|
626
|
+
True
|
|
627
|
+
sage: x = polygen(GF(13))
|
|
628
|
+
sage: C = HyperellipticCurve(x^3 + x^2 - 1)
|
|
629
|
+
sage: C._points_fast_sqrt()
|
|
630
|
+
[(0 : 1 : 0), (0 : 5 : 1), (0 : 8 : 1), (1 : 1 : 1), (1 : 12 : 1),
|
|
631
|
+
(3 : 3 : 1), (3 : 10 : 1), (4 : 1 : 1), (4 : 12 : 1), (6 : 2 : 1),
|
|
632
|
+
(6 : 11 : 1), (7 : 1 : 1), (7 : 12 : 1), (8 : 4 : 1), (8 : 9 : 1),
|
|
633
|
+
(9 : 4 : 1), (9 : 9 : 1), (12 : 5 : 1), (12 : 8 : 1)]
|
|
634
|
+
sage: set(C._points_fast_sqrt()) == set(C._points_cache_sqrt())
|
|
635
|
+
True
|
|
636
|
+
"""
|
|
637
|
+
# For givaro finite fields, taking square roots is very fast
|
|
638
|
+
# so no need to cache as in prime case
|
|
639
|
+
K = self.base_ring()
|
|
640
|
+
f, h = self.hyperelliptic_polynomials()
|
|
641
|
+
one = K(1)
|
|
642
|
+
|
|
643
|
+
# start with the points at infinity
|
|
644
|
+
P = self.defining_polynomial()
|
|
645
|
+
if not P(K(0), K(1), K(0)):
|
|
646
|
+
# (0:1:0) is a point on the curve
|
|
647
|
+
points = [self.point([K(0), K(1), K(0)], check=True)]
|
|
648
|
+
else:
|
|
649
|
+
points = []
|
|
650
|
+
if P.degree() > 2:
|
|
651
|
+
# P(1, y, 0) = r*y + s
|
|
652
|
+
s = P(K(1), K(0), K(0))
|
|
653
|
+
r = P(K(1), K(1), K(0)) - s
|
|
654
|
+
if r: # r not zero
|
|
655
|
+
points.append(self.point([K(1), -s/r, K(0)], check=True))
|
|
656
|
+
# the case r = 0 need not be considered
|
|
657
|
+
elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2
|
|
658
|
+
# quadratic equation doesn't work in characteristic 2 so use brute
|
|
659
|
+
# force
|
|
660
|
+
points += [self.point([K(1), y, K(0)], check=True) for y in K
|
|
661
|
+
if not P(K(1), y, K(0))]
|
|
662
|
+
else: # deg(P) = 2 and char(K) not 2
|
|
663
|
+
# P(1, y, 0) = y^2 + r*y + s
|
|
664
|
+
s = -f[2]
|
|
665
|
+
r = h[1]
|
|
666
|
+
d = r**2/4 - s
|
|
667
|
+
if not d: # d = 0
|
|
668
|
+
points.append(self.point([K(1), -r/2, K(0)], check=True))
|
|
669
|
+
elif d.is_square():
|
|
670
|
+
sqrtd = d.sqrt()
|
|
671
|
+
points.append(self.point([K(1), -r/2+sqrtd, K(0)], check=True))
|
|
672
|
+
points.append(self.point([K(1), -r/2-sqrtd, K(0)], check=True))
|
|
673
|
+
|
|
674
|
+
if K.characteristic() == 2:
|
|
675
|
+
# quadratic equation doesn't work in characteristic 2
|
|
676
|
+
if h.is_zero():
|
|
677
|
+
for x in K:
|
|
678
|
+
points.append(self.point([x, f(x).sqrt(), one], check=True))
|
|
679
|
+
else:
|
|
680
|
+
a_sqrts = { } # Artin-Schreier 2-roots
|
|
681
|
+
for x in K:
|
|
682
|
+
a_sqrts[x**2 + x] = x # char 2 => x^2 - x == x^2 + x
|
|
683
|
+
for x in K:
|
|
684
|
+
b = h(x)
|
|
685
|
+
c = f(x)
|
|
686
|
+
if b:
|
|
687
|
+
try:
|
|
688
|
+
r = a_sqrts[c / b**2]
|
|
689
|
+
points.append(self.point([x, r*b, one], check=True))
|
|
690
|
+
points.append(self.point([x, r*b+b, one], check=True))
|
|
691
|
+
except KeyError:
|
|
692
|
+
# y^2 + by + c irreducible, so yields no points
|
|
693
|
+
pass
|
|
694
|
+
else: # b == 0
|
|
695
|
+
points.append(self.point([x, c.sqrt(), one], check=True))
|
|
696
|
+
elif h.is_zero():
|
|
697
|
+
# special case to save work if we are of the form y^2 = f(x)
|
|
698
|
+
for x in K:
|
|
699
|
+
y2 = f(x)
|
|
700
|
+
if not y2: # y = 0
|
|
701
|
+
points.append(self.point([x, y2, one], check=True))
|
|
702
|
+
elif y2.is_square():
|
|
703
|
+
y = y2.sqrt()
|
|
704
|
+
points.append(self.point([x, y, one], check=True))
|
|
705
|
+
points.append(self.point([x, -y, one], check=True))
|
|
706
|
+
else:
|
|
707
|
+
b = -h/2
|
|
708
|
+
D = b*b + f
|
|
709
|
+
for x in K:
|
|
710
|
+
Dval = D(x)
|
|
711
|
+
if not Dval: # D(x) = 0
|
|
712
|
+
points.append(self.point([x, b(x), one], check=True))
|
|
713
|
+
elif Dval.is_square():
|
|
714
|
+
sqrtD = Dval.sqrt()
|
|
715
|
+
v = b(x)
|
|
716
|
+
points.append(self.point([x, v+sqrtD, one], check=True))
|
|
717
|
+
points.append(self.point([x, v-sqrtD, one], check=True))
|
|
718
|
+
return points
|
|
719
|
+
|
|
720
|
+
def _points_cache_sqrt(self, brute_force=False):
|
|
721
|
+
"""
|
|
722
|
+
List points by enumerating over x and solving the resulting
|
|
723
|
+
quadratic for y.
|
|
724
|
+
|
|
725
|
+
Caches all square roots ahead of time by squaring every element of
|
|
726
|
+
the field. Elements must have an __index__ method.
|
|
727
|
+
|
|
728
|
+
EXAMPLES::
|
|
729
|
+
|
|
730
|
+
sage: x = polygen(GF(7))
|
|
731
|
+
sage: C = HyperellipticCurve(x^3 + x^2 - 1)
|
|
732
|
+
sage: C._points_cache_sqrt()
|
|
733
|
+
[(0 : 1 : 0), (1 : 6 : 1), (1 : 1 : 1), (2 : 5 : 1), (2 : 2 : 1),
|
|
734
|
+
(3 : 0 : 1), (4 : 4 : 1), (4 : 3 : 1), (5 : 4 : 1), (5 : 3 : 1)]
|
|
735
|
+
sage: set(C._points_cache_sqrt()) == set(C._points_cache_sqrt(brute_force=True))
|
|
736
|
+
True
|
|
737
|
+
"""
|
|
738
|
+
K = self.base_ring()
|
|
739
|
+
if K.characteristic() != 2:
|
|
740
|
+
# cache the squares (faster than O(p) sqrts)
|
|
741
|
+
square_roots = [None] * len(K)
|
|
742
|
+
for x in K:
|
|
743
|
+
square_roots[x*x] = x
|
|
744
|
+
f, h = self.hyperelliptic_polynomials()
|
|
745
|
+
one = K(1)
|
|
746
|
+
|
|
747
|
+
# start with the points at infinity
|
|
748
|
+
P = self.defining_polynomial()
|
|
749
|
+
if not P(K(0), K(1), K(0)):
|
|
750
|
+
# (0:1:0) is a point on the curve
|
|
751
|
+
points = [self.point([K(0), K(1), K(0)], check=True)]
|
|
752
|
+
else:
|
|
753
|
+
points = []
|
|
754
|
+
if P.degree() > 2:
|
|
755
|
+
# P(1, y, 0) = r*y + s
|
|
756
|
+
s = P(K(1), K(0), K(0))
|
|
757
|
+
r = P(K(1), K(1), K(0)) - s
|
|
758
|
+
if r: # r not zero
|
|
759
|
+
points.append(self.point([K(1), -s/r, K(0)], check=True))
|
|
760
|
+
# the case r = 0 need not be considered
|
|
761
|
+
elif K.characteristic() == 2: # deg(P) = 2 and char(K) = 2
|
|
762
|
+
# quadratic equation doesn't work in characteristic 2 so use brute
|
|
763
|
+
# force
|
|
764
|
+
points += [self.point([K(1), y, K(0)], check=True) for y in K
|
|
765
|
+
if not P(K(1), y, K(0))]
|
|
766
|
+
else: # deg(P) = 2 and char(K) not 2
|
|
767
|
+
# P(1, y, 0) = y^2 + r*y + s
|
|
768
|
+
s = -f[2]
|
|
769
|
+
r = h[1]
|
|
770
|
+
d = r**2/4 - s
|
|
771
|
+
sqrtd = square_roots[d]
|
|
772
|
+
if not d: # d = 0
|
|
773
|
+
points.append(self.point([K(1), -r/2, K(0)], check=True))
|
|
774
|
+
elif sqrtd is not None:
|
|
775
|
+
points.append(self.point([K(1), -r/2+sqrtd, K(0)], check=True))
|
|
776
|
+
points.append(self.point([K(1), -r/2-sqrtd, K(0)], check=True))
|
|
777
|
+
|
|
778
|
+
if K.characteristic() == 2 or brute_force:
|
|
779
|
+
# quadratic equation doesn't work in characteristic 2
|
|
780
|
+
# but there are only 4 affine points, so just test them
|
|
781
|
+
f = self.defining_polynomial()
|
|
782
|
+
points += [self.point([x, y, one], check=True) for x in K for y in K if not f(x, y, one)]
|
|
783
|
+
elif h.is_zero():
|
|
784
|
+
# special case to save work if we are of the form y^2 = f(x)
|
|
785
|
+
for x in K:
|
|
786
|
+
y2 = f(x)
|
|
787
|
+
y = square_roots[y2]
|
|
788
|
+
if not y2: # y = 0
|
|
789
|
+
points.append(self.point([x, y2, one], check=True))
|
|
790
|
+
elif y is not None:
|
|
791
|
+
points.append(self.point([x, y, one], check=True))
|
|
792
|
+
points.append(self.point([x, -y, one], check=True))
|
|
793
|
+
else:
|
|
794
|
+
b = -h/2
|
|
795
|
+
D = b*b + f # this is really disc/4
|
|
796
|
+
for x in K:
|
|
797
|
+
Dval = D(x)
|
|
798
|
+
sqrtD = square_roots[Dval]
|
|
799
|
+
if not Dval: # D(x) = 0
|
|
800
|
+
points.append(self.point([x, b(x), one], check=True))
|
|
801
|
+
elif sqrtD is not None:
|
|
802
|
+
v = b(x)
|
|
803
|
+
points.append(self.point([x, v+sqrtD, one], check=True))
|
|
804
|
+
points.append(self.point([x, v-sqrtD, one], check=True))
|
|
805
|
+
return points
|
|
806
|
+
|
|
807
|
+
def points(self):
|
|
808
|
+
r"""
|
|
809
|
+
All the points on this hyperelliptic curve.
|
|
810
|
+
|
|
811
|
+
EXAMPLES::
|
|
812
|
+
|
|
813
|
+
sage: x = polygen(GF(7))
|
|
814
|
+
sage: C = HyperellipticCurve(x^7 - x^2 - 1)
|
|
815
|
+
sage: C.points()
|
|
816
|
+
[(0 : 1 : 0), (2 : 5 : 1), (2 : 2 : 1), (3 : 0 : 1), (4 : 6 : 1),
|
|
817
|
+
(4 : 1 : 1), (5 : 0 : 1), (6 : 5 : 1), (6 : 2 : 1)]
|
|
818
|
+
|
|
819
|
+
::
|
|
820
|
+
|
|
821
|
+
sage: x = polygen(GF(121, 'a'))
|
|
822
|
+
sage: C = HyperellipticCurve(x^5 + x - 1, x^2 + 2)
|
|
823
|
+
sage: len(C.points())
|
|
824
|
+
122
|
|
825
|
+
|
|
826
|
+
Conics are allowed (the issue reported at :issue:`11800`
|
|
827
|
+
has been resolved)::
|
|
828
|
+
|
|
829
|
+
sage: R.<x> = GF(7)[]
|
|
830
|
+
sage: H = HyperellipticCurve(3*x^2 + 5*x + 1)
|
|
831
|
+
sage: H.points()
|
|
832
|
+
[(0 : 6 : 1), (0 : 1 : 1), (1 : 4 : 1), (1 : 3 : 1), (2 : 4 : 1),
|
|
833
|
+
(2 : 3 : 1), (3 : 6 : 1), (3 : 1 : 1)]
|
|
834
|
+
|
|
835
|
+
The method currently lists points on the plane projective model, that
|
|
836
|
+
is the closure in `\mathbb{P}^2` of the curve defined by `y^2+hy=f`.
|
|
837
|
+
This means that one point `(0:1:0)` at infinity is returned if the
|
|
838
|
+
degree of the curve is at least 4 and `\deg(f)>\deg(h)+1`. This point
|
|
839
|
+
is a singular point of the plane model. Later implementations may
|
|
840
|
+
consider a smooth model instead since that would be a more relevant
|
|
841
|
+
object. Then, for a curve whose only singularity is at `(0:1:0)`, the
|
|
842
|
+
point at infinity would be replaced by a number of rational points of
|
|
843
|
+
the smooth model. We illustrate this with an example of a genus 2
|
|
844
|
+
hyperelliptic curve::
|
|
845
|
+
|
|
846
|
+
sage: R.<x>=GF(11)[]
|
|
847
|
+
sage: H = HyperellipticCurve(x*(x+1)*(x+2)*(x+3)*(x+4)*(x+5))
|
|
848
|
+
sage: H.points()
|
|
849
|
+
[(0 : 1 : 0), (0 : 0 : 1), (1 : 7 : 1), (1 : 4 : 1), (5 : 7 : 1), (5 : 4 : 1),
|
|
850
|
+
(6 : 0 : 1), (7 : 0 : 1), (8 : 0 : 1), (9 : 0 : 1), (10 : 0 : 1)]
|
|
851
|
+
|
|
852
|
+
The plane model of the genus 2 hyperelliptic curve in the above example
|
|
853
|
+
is the curve in `\mathbb{P}^2` defined by `y^2z^4=g(x,z)` where
|
|
854
|
+
`g(x,z)=x(x+z)(x+2z)(x+3z)(x+4z)(x+5z).` This model has one point at
|
|
855
|
+
infinity `(0:1:0)` which is also the only singular point of the plane
|
|
856
|
+
model. In contrast, the hyperelliptic curve is smooth and imbeds via
|
|
857
|
+
the equation `y^2=g(x,z)` into weighted projected space
|
|
858
|
+
`\mathbb{P}(1,3,1)`. The latter model has two points at infinity:
|
|
859
|
+
`(1:1:0)` and `(1:-1:0)`.
|
|
860
|
+
"""
|
|
861
|
+
from sage.rings.finite_rings.finite_field_constructor import zech_log_bound
|
|
862
|
+
try:
|
|
863
|
+
return self.__points
|
|
864
|
+
except AttributeError:
|
|
865
|
+
pass
|
|
866
|
+
|
|
867
|
+
if self.base_ring().is_prime_field():
|
|
868
|
+
self.__points = self._points_cache_sqrt()
|
|
869
|
+
else:
|
|
870
|
+
if self.base_ring().order() < zech_log_bound:
|
|
871
|
+
self.__points = self._points_fast_sqrt() # this is fast using Zech logarithms
|
|
872
|
+
else:
|
|
873
|
+
self.__points = self._points_cache_sqrt()
|
|
874
|
+
|
|
875
|
+
return self.__points
|
|
876
|
+
|
|
877
|
+
def count_points_matrix_traces(self, n=1, M=None, N=None):
|
|
878
|
+
r"""
|
|
879
|
+
Count the number of points on the curve over the first `n` extensions
|
|
880
|
+
of the base field by computing traces of powers of the frobenius
|
|
881
|
+
matrix.
|
|
882
|
+
This requires less `p`-adic precision than computing the charpoly
|
|
883
|
+
of the matrix when `n < g` where `g` is the genus of the curve.
|
|
884
|
+
|
|
885
|
+
EXAMPLES::
|
|
886
|
+
|
|
887
|
+
sage: K = GF(49999)
|
|
888
|
+
sage: R.<t> = PolynomialRing(K)
|
|
889
|
+
sage: H = HyperellipticCurve(t^19 + t + 1)
|
|
890
|
+
sage: H.count_points_matrix_traces(3)
|
|
891
|
+
[49491, 2500024375, 124992509154249]
|
|
892
|
+
|
|
893
|
+
TESTS:
|
|
894
|
+
|
|
895
|
+
Check that :issue:`18831` is fixed::
|
|
896
|
+
|
|
897
|
+
sage: R.<t> = PolynomialRing(GF(11))
|
|
898
|
+
sage: H = HyperellipticCurve(t^5 - t + 1)
|
|
899
|
+
sage: H.count_points_matrix_traces()
|
|
900
|
+
Traceback (most recent call last):
|
|
901
|
+
...
|
|
902
|
+
ValueError: In the current implementation, p must be greater than (2g+1)(2N-1) = 15
|
|
903
|
+
"""
|
|
904
|
+
if N is None:
|
|
905
|
+
N = self._frobenius_coefficient_bound_traces(n=n)
|
|
906
|
+
|
|
907
|
+
if M is None:
|
|
908
|
+
M = self.frobenius_matrix(N=N)
|
|
909
|
+
|
|
910
|
+
K = self.base_ring()
|
|
911
|
+
p = K.characteristic()
|
|
912
|
+
q = K.cardinality()
|
|
913
|
+
ppow = p**N
|
|
914
|
+
|
|
915
|
+
t = []
|
|
916
|
+
Mpow = 1
|
|
917
|
+
for i in range(n):
|
|
918
|
+
Mpow *= M
|
|
919
|
+
t.append(Mpow.trace())
|
|
920
|
+
|
|
921
|
+
t = [x.lift() for x in t]
|
|
922
|
+
t = [x if 2*x < ppow else x - ppow for x in t]
|
|
923
|
+
|
|
924
|
+
return [q**(i+1) + 1 - t[i] for i in range(n)]
|
|
925
|
+
|
|
926
|
+
def count_points_frobenius_polynomial(self, n=1, f=None):
|
|
927
|
+
r"""
|
|
928
|
+
Count the number of points on the curve over the first `n` extensions
|
|
929
|
+
of the base field by computing the frobenius polynomial.
|
|
930
|
+
|
|
931
|
+
EXAMPLES::
|
|
932
|
+
|
|
933
|
+
sage: K = GF(49999)
|
|
934
|
+
sage: R.<t> = PolynomialRing(K)
|
|
935
|
+
sage: H = HyperellipticCurve(t^19 + t + 1)
|
|
936
|
+
|
|
937
|
+
The following computation takes a long time as the complete
|
|
938
|
+
characteristic polynomial of the frobenius is computed::
|
|
939
|
+
|
|
940
|
+
sage: H.count_points_frobenius_polynomial(3) # long time, 20s on a Corei7 (when computed before the following test of course)
|
|
941
|
+
[49491, 2500024375, 124992509154249]
|
|
942
|
+
|
|
943
|
+
As the polynomial is cached, further computations of number of points
|
|
944
|
+
are really fast::
|
|
945
|
+
|
|
946
|
+
sage: H.count_points_frobenius_polynomial(19) # long time, because of the previous test
|
|
947
|
+
[49491,
|
|
948
|
+
2500024375,
|
|
949
|
+
124992509154249,
|
|
950
|
+
6249500007135192947,
|
|
951
|
+
312468751250758776051811,
|
|
952
|
+
15623125093747382662737313867,
|
|
953
|
+
781140631562281338861289572576257,
|
|
954
|
+
39056250437482500417107992413002794587,
|
|
955
|
+
1952773465623687539373429411200893147181079,
|
|
956
|
+
97636720507718753281169963459063147221761552935,
|
|
957
|
+
4881738388665429945305281187129778704058864736771824,
|
|
958
|
+
244082037694882831835318764490138139735446240036293092851,
|
|
959
|
+
12203857802706446708934102903106811520015567632046432103159713,
|
|
960
|
+
610180686277519628999996211052002771035439565767719719151141201339,
|
|
961
|
+
30508424133189703930370810556389262704405225546438978173388673620145499,
|
|
962
|
+
1525390698235352006814610157008906752699329454643826047826098161898351623931,
|
|
963
|
+
76268009521069364988723693240288328729528917832735078791261015331201838856825193,
|
|
964
|
+
3813324208043947180071195938321176148147244128062172555558715783649006587868272993991,
|
|
965
|
+
190662397077989315056379725720120486231213267083935859751911720230901597698389839098903847]
|
|
966
|
+
"""
|
|
967
|
+
if f is None:
|
|
968
|
+
f = self.frobenius_polynomial()
|
|
969
|
+
|
|
970
|
+
q = self.base_ring().cardinality()
|
|
971
|
+
S = PowerSeriesRing(QQ, default_prec=n+1, names='t')
|
|
972
|
+
frev = f.reverse()
|
|
973
|
+
# the coefficients() method of power series only returns
|
|
974
|
+
# nonzero coefficients so let us use the list() method but
|
|
975
|
+
# this does not work for zero which gives the empty list
|
|
976
|
+
flog = S(frev).log()
|
|
977
|
+
return [q**(i+1) + 1 + ZZ((i+1)*flog[i+1]) for i in range(n)]
|
|
978
|
+
|
|
979
|
+
def count_points_exhaustive(self, n=1, naive=False):
|
|
980
|
+
r"""
|
|
981
|
+
Count the number of points on the curve over the first `n` extensions
|
|
982
|
+
of the base field by exhaustive search if `n` if smaller than `g`,
|
|
983
|
+
the genus of the curve, and by computing the frobenius polynomial
|
|
984
|
+
after performing exhaustive search on the first `g` extensions if
|
|
985
|
+
`n > g` (unless ``naive == True``).
|
|
986
|
+
|
|
987
|
+
EXAMPLES::
|
|
988
|
+
|
|
989
|
+
sage: K = GF(5)
|
|
990
|
+
sage: R.<t> = PolynomialRing(K)
|
|
991
|
+
sage: H = HyperellipticCurve(t^9 + t^3 + 1)
|
|
992
|
+
sage: H.count_points_exhaustive(n=5)
|
|
993
|
+
[9, 27, 108, 675, 3069]
|
|
994
|
+
|
|
995
|
+
When `n > g`, the frobenius polynomial is computed from the numbers
|
|
996
|
+
of points of the curve over the first `g` extension, so that computing
|
|
997
|
+
the number of points on extensions of degree `n > g` is not much more
|
|
998
|
+
expensive than for `n == g`::
|
|
999
|
+
|
|
1000
|
+
sage: H.count_points_exhaustive(n=15)
|
|
1001
|
+
[9,
|
|
1002
|
+
27,
|
|
1003
|
+
108,
|
|
1004
|
+
675,
|
|
1005
|
+
3069,
|
|
1006
|
+
16302,
|
|
1007
|
+
78633,
|
|
1008
|
+
389475,
|
|
1009
|
+
1954044,
|
|
1010
|
+
9768627,
|
|
1011
|
+
48814533,
|
|
1012
|
+
244072650,
|
|
1013
|
+
1220693769,
|
|
1014
|
+
6103414827,
|
|
1015
|
+
30517927308]
|
|
1016
|
+
|
|
1017
|
+
This behavior can be disabled by passing ``naive=True``::
|
|
1018
|
+
|
|
1019
|
+
sage: H.count_points_exhaustive(n=6, naive=True) # long time, 7s on a Corei7
|
|
1020
|
+
[9, 27, 108, 675, 3069, 16302]
|
|
1021
|
+
"""
|
|
1022
|
+
g = self.genus()
|
|
1023
|
+
a = []
|
|
1024
|
+
for i in range(1, min(n, g) + 1):
|
|
1025
|
+
a.append(self.cardinality_exhaustive(extension_degree=i))
|
|
1026
|
+
|
|
1027
|
+
if n <= g:
|
|
1028
|
+
return a
|
|
1029
|
+
|
|
1030
|
+
if naive:
|
|
1031
|
+
for i in range(g + 1, n + 1):
|
|
1032
|
+
a.append(self.cardinality_exhaustive(extension_degree=i))
|
|
1033
|
+
|
|
1034
|
+
# let's not be too naive and compute the frobenius polynomial
|
|
1035
|
+
f = self.frobenius_polynomial_cardinalities(a=a)
|
|
1036
|
+
return self.count_points_frobenius_polynomial(n=n, f=f)
|
|
1037
|
+
|
|
1038
|
+
def count_points_hypellfrob(self, n=1, N=None, algorithm=None):
|
|
1039
|
+
r"""
|
|
1040
|
+
Count the number of points on the curve over the first `n` extensions
|
|
1041
|
+
of the base field using the ``hypellfrob`` program.
|
|
1042
|
+
|
|
1043
|
+
This only supports prime fields of large enough characteristic.
|
|
1044
|
+
|
|
1045
|
+
EXAMPLES::
|
|
1046
|
+
|
|
1047
|
+
sage: K = GF(49999)
|
|
1048
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1049
|
+
sage: H = HyperellipticCurve(t^21 + 3*t^5 + 5)
|
|
1050
|
+
sage: H.count_points_hypellfrob()
|
|
1051
|
+
[49804]
|
|
1052
|
+
sage: H.count_points_hypellfrob(2)
|
|
1053
|
+
[49804, 2499799038]
|
|
1054
|
+
|
|
1055
|
+
sage: K = GF(2**7-1)
|
|
1056
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1057
|
+
sage: H = HyperellipticCurve(t^11 + 3*t^5 + 5)
|
|
1058
|
+
sage: H.count_points_hypellfrob()
|
|
1059
|
+
[127]
|
|
1060
|
+
sage: H.count_points_hypellfrob(n=5)
|
|
1061
|
+
[127, 16335, 2045701, 260134299, 33038098487]
|
|
1062
|
+
|
|
1063
|
+
sage: K = GF(2**7-1)
|
|
1064
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1065
|
+
sage: H = HyperellipticCurve(t^13 + 3*t^5 + 5)
|
|
1066
|
+
sage: H.count_points(n=6)
|
|
1067
|
+
[112, 16360, 2045356, 260199160, 33038302802, 4195868633548]
|
|
1068
|
+
|
|
1069
|
+
The base field should be prime::
|
|
1070
|
+
|
|
1071
|
+
sage: K.<z> = GF(19**10)
|
|
1072
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1073
|
+
sage: H = HyperellipticCurve(t^9 + (z+1)*t^5 + 1)
|
|
1074
|
+
sage: H.count_points_hypellfrob()
|
|
1075
|
+
Traceback (most recent call last):
|
|
1076
|
+
...
|
|
1077
|
+
ValueError: hypellfrob does not support non-prime fields
|
|
1078
|
+
|
|
1079
|
+
and the characteristic should be large enough::
|
|
1080
|
+
|
|
1081
|
+
sage: K = GF(7)
|
|
1082
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1083
|
+
sage: H = HyperellipticCurve(t^9 + t^3 + 1)
|
|
1084
|
+
sage: H.count_points_hypellfrob()
|
|
1085
|
+
Traceback (most recent call last):
|
|
1086
|
+
...
|
|
1087
|
+
ValueError: p=7 should be greater than (2*g+1)(2*N-1)=27
|
|
1088
|
+
"""
|
|
1089
|
+
K = self.base_ring()
|
|
1090
|
+
e = K.degree()
|
|
1091
|
+
|
|
1092
|
+
if e != 1:
|
|
1093
|
+
raise ValueError("hypellfrob does not support non-prime fields")
|
|
1094
|
+
|
|
1095
|
+
# K is a prime field
|
|
1096
|
+
p = K.cardinality()
|
|
1097
|
+
g = self.genus()
|
|
1098
|
+
|
|
1099
|
+
if algorithm is None:
|
|
1100
|
+
if n < g:
|
|
1101
|
+
algorithm = 'traces'
|
|
1102
|
+
else:
|
|
1103
|
+
algorithm = 'charpoly'
|
|
1104
|
+
|
|
1105
|
+
if N is None:
|
|
1106
|
+
if algorithm == 'traces':
|
|
1107
|
+
N = self._frobenius_coefficient_bound_traces(n)
|
|
1108
|
+
elif algorithm == 'charpoly':
|
|
1109
|
+
N = self._frobenius_coefficient_bound_charpoly()
|
|
1110
|
+
else:
|
|
1111
|
+
raise ValueError("Unknown algorithm")
|
|
1112
|
+
|
|
1113
|
+
if p <= (2*g+1)*(2*N-1):
|
|
1114
|
+
raise ValueError("p=%d should be greater than (2*g+1)(2*N-1)=%d" % (p,(2*g+1)*(2*N-1)))
|
|
1115
|
+
|
|
1116
|
+
if algorithm == 'traces':
|
|
1117
|
+
M = self.frobenius_matrix(N=N, algorithm='hypellfrob')
|
|
1118
|
+
return self.count_points_matrix_traces(n=n,M=M,N=N)
|
|
1119
|
+
elif algorithm == 'charpoly':
|
|
1120
|
+
f = self.frobenius_polynomial_matrix(algorithm='hypellfrob')
|
|
1121
|
+
return self.count_points_frobenius_polynomial(n=n,f=f)
|
|
1122
|
+
else:
|
|
1123
|
+
raise ValueError("Unknown algorithm")
|
|
1124
|
+
|
|
1125
|
+
def count_points(self, n=1):
|
|
1126
|
+
r"""
|
|
1127
|
+
Count points over finite fields.
|
|
1128
|
+
|
|
1129
|
+
INPUT:
|
|
1130
|
+
|
|
1131
|
+
- ``n`` -- integer
|
|
1132
|
+
|
|
1133
|
+
OUTPUT:
|
|
1134
|
+
|
|
1135
|
+
An integer. The number of points over `\GF{q}, \ldots,
|
|
1136
|
+
\GF{q^n}` on a hyperelliptic curve over a finite field `\GF{q}`.
|
|
1137
|
+
|
|
1138
|
+
.. WARNING::
|
|
1139
|
+
|
|
1140
|
+
This is currently using exhaustive search for hyperelliptic curves
|
|
1141
|
+
over non-prime fields, which can be awfully slow.
|
|
1142
|
+
|
|
1143
|
+
EXAMPLES::
|
|
1144
|
+
|
|
1145
|
+
sage: P.<x> = PolynomialRing(GF(3))
|
|
1146
|
+
sage: C = HyperellipticCurve(x^3+x^2+1)
|
|
1147
|
+
sage: C.count_points(4)
|
|
1148
|
+
[6, 12, 18, 96]
|
|
1149
|
+
sage: C.base_extend(GF(9,'a')).count_points(2)
|
|
1150
|
+
[12, 96]
|
|
1151
|
+
|
|
1152
|
+
sage: K = GF(2**31-1)
|
|
1153
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1154
|
+
sage: H = HyperellipticCurve(t^5 + 3*t + 5)
|
|
1155
|
+
sage: H.count_points() # long time, 2.4 sec on a Corei7
|
|
1156
|
+
[2147464821]
|
|
1157
|
+
sage: H.count_points(n=2) # long time, 30s on a Corei7
|
|
1158
|
+
[2147464821, 4611686018988310237]
|
|
1159
|
+
|
|
1160
|
+
sage: K = GF(2**7-1)
|
|
1161
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1162
|
+
sage: H = HyperellipticCurve(t^13 + 3*t^5 + 5)
|
|
1163
|
+
sage: H.count_points(n=6)
|
|
1164
|
+
[112, 16360, 2045356, 260199160, 33038302802, 4195868633548]
|
|
1165
|
+
|
|
1166
|
+
sage: P.<x> = PolynomialRing(GF(3))
|
|
1167
|
+
sage: H = HyperellipticCurve(x^3+x^2+1)
|
|
1168
|
+
sage: C1 = H.count_points(4); C1
|
|
1169
|
+
[6, 12, 18, 96]
|
|
1170
|
+
sage: C2 = sage.schemes.generic.scheme.Scheme.count_points(H,4); C2 # long time, 2s on a Corei7
|
|
1171
|
+
[6, 12, 18, 96]
|
|
1172
|
+
sage: C1 == C2 # long time, because we need C2 to be defined
|
|
1173
|
+
True
|
|
1174
|
+
|
|
1175
|
+
sage: P.<x> = PolynomialRing(GF(9,'a'))
|
|
1176
|
+
sage: H = HyperellipticCurve(x^5+x^2+1)
|
|
1177
|
+
sage: H.count_points(5)
|
|
1178
|
+
[18, 78, 738, 6366, 60018]
|
|
1179
|
+
|
|
1180
|
+
sage: F.<a> = GF(4); P.<x> = F[]
|
|
1181
|
+
sage: H = HyperellipticCurve(x^5+a*x^2+1, x+a+1)
|
|
1182
|
+
sage: H.count_points(6)
|
|
1183
|
+
[2, 24, 74, 256, 1082, 4272]
|
|
1184
|
+
|
|
1185
|
+
This example shows that :issue:`20391` is resolved::
|
|
1186
|
+
|
|
1187
|
+
sage: x = polygen(GF(4099))
|
|
1188
|
+
sage: H = HyperellipticCurve(x^6 + x + 1)
|
|
1189
|
+
sage: H.count_points(1)
|
|
1190
|
+
[4106]
|
|
1191
|
+
"""
|
|
1192
|
+
K = self.base_ring()
|
|
1193
|
+
q = K.cardinality()
|
|
1194
|
+
e = K.degree()
|
|
1195
|
+
g = self.genus()
|
|
1196
|
+
f, h = self.hyperelliptic_polynomials()
|
|
1197
|
+
|
|
1198
|
+
if e == 1 and h == 0 and f.degree() % 2 == 1:
|
|
1199
|
+
N1 = self._frobenius_coefficient_bound_traces(n)
|
|
1200
|
+
N2 = self._frobenius_coefficient_bound_charpoly()
|
|
1201
|
+
if n < g and q > (2*g+1)*(2*N1-1):
|
|
1202
|
+
return self.count_points_hypellfrob(n, N=N1, algorithm='traces')
|
|
1203
|
+
elif q > (2*g+1)*(2*N2-1):
|
|
1204
|
+
return self.count_points_hypellfrob(n, N=N2, algorithm='charpoly')
|
|
1205
|
+
|
|
1206
|
+
# No smart method available
|
|
1207
|
+
return self.count_points_exhaustive(n)
|
|
1208
|
+
|
|
1209
|
+
def cardinality_exhaustive(self, extension_degree=1, algorithm=None):
|
|
1210
|
+
r"""
|
|
1211
|
+
Count points on a single extension of the base field
|
|
1212
|
+
by enumerating over x and solving the resulting quadratic
|
|
1213
|
+
equation for y.
|
|
1214
|
+
|
|
1215
|
+
EXAMPLES::
|
|
1216
|
+
|
|
1217
|
+
sage: K.<a> = GF(9, 'a')
|
|
1218
|
+
sage: x = polygen(K)
|
|
1219
|
+
sage: C = HyperellipticCurve(x^7 - 1, x^2 + a)
|
|
1220
|
+
sage: C.cardinality_exhaustive()
|
|
1221
|
+
7
|
|
1222
|
+
|
|
1223
|
+
sage: K = GF(next_prime(1<<10))
|
|
1224
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1225
|
+
sage: H = HyperellipticCurve(t^7 + 3*t^5 + 5)
|
|
1226
|
+
sage: H.cardinality_exhaustive()
|
|
1227
|
+
1025
|
|
1228
|
+
|
|
1229
|
+
sage: P.<x> = PolynomialRing(GF(9,'a'))
|
|
1230
|
+
sage: H = HyperellipticCurve(x^5+x^2+1)
|
|
1231
|
+
sage: H.count_points(5)
|
|
1232
|
+
[18, 78, 738, 6366, 60018]
|
|
1233
|
+
|
|
1234
|
+
sage: F.<a> = GF(4); P.<x> = F[]
|
|
1235
|
+
sage: H = HyperellipticCurve(x^5+a*x^2+1, x+a+1)
|
|
1236
|
+
sage: H.count_points(6)
|
|
1237
|
+
[2, 24, 74, 256, 1082, 4272]
|
|
1238
|
+
|
|
1239
|
+
TESTS:
|
|
1240
|
+
|
|
1241
|
+
Check for :issue:`19122`::
|
|
1242
|
+
|
|
1243
|
+
sage: x = polygen(GF(19), 'x')
|
|
1244
|
+
sage: f = 15*x^4 + 7*x^3 + 3*x^2 + 7*x + 18
|
|
1245
|
+
sage: HyperellipticCurve(f).cardinality_exhaustive(1)
|
|
1246
|
+
19
|
|
1247
|
+
|
|
1248
|
+
Points at infinity on general curves of genus 1 are counted
|
|
1249
|
+
correctly (see :issue:`21195`)::
|
|
1250
|
+
|
|
1251
|
+
sage: S.<z> = PolynomialRing(ZZ)
|
|
1252
|
+
sage: C = HyperellipticCurve(-z^2 + z, z^2)
|
|
1253
|
+
sage: C.base_extend(GF(2)).count_points_exhaustive()
|
|
1254
|
+
[5]
|
|
1255
|
+
sage: C.base_extend(GF(3)).count_points_exhaustive()
|
|
1256
|
+
[5]
|
|
1257
|
+
"""
|
|
1258
|
+
K = self.base_ring()
|
|
1259
|
+
g = self.genus()
|
|
1260
|
+
n = extension_degree
|
|
1261
|
+
|
|
1262
|
+
if g == 0:
|
|
1263
|
+
# here is the projective line
|
|
1264
|
+
return K.cardinality() ** n + 1
|
|
1265
|
+
|
|
1266
|
+
f, h = self.hyperelliptic_polynomials()
|
|
1267
|
+
a = 0
|
|
1268
|
+
|
|
1269
|
+
if n == 1:
|
|
1270
|
+
# the base field
|
|
1271
|
+
L = K
|
|
1272
|
+
fext = f
|
|
1273
|
+
hext = h
|
|
1274
|
+
else:
|
|
1275
|
+
# extension of the base field
|
|
1276
|
+
from sage.categories.homset import Hom
|
|
1277
|
+
L = GF(K.cardinality()**n, names='z')
|
|
1278
|
+
P = L['t']
|
|
1279
|
+
emb = Hom(K, L)[0]
|
|
1280
|
+
fext = P([emb(c) for c in f])
|
|
1281
|
+
hext = P([emb(c) for c in h])
|
|
1282
|
+
|
|
1283
|
+
# We solve equations of the form y^2 + r*y - s == 0.
|
|
1284
|
+
# For the points at infinity (on the smooth model),
|
|
1285
|
+
# solve y^2 + h[g+1]*y == f[2*g+2].
|
|
1286
|
+
# For the affine points with given x-coordinate,
|
|
1287
|
+
# solve y^2 + h(x)*y == f(x).
|
|
1288
|
+
|
|
1289
|
+
if K.characteristic() == 2:
|
|
1290
|
+
# points at infinity
|
|
1291
|
+
r = h[g+1]
|
|
1292
|
+
if not r:
|
|
1293
|
+
a += 1
|
|
1294
|
+
elif n % 2 == 0 or (f[2*g+2]/r**2).trace() == 0:
|
|
1295
|
+
# Artin-Schreier equation t^2 + t = s/r^2
|
|
1296
|
+
# always has a solution in extensions of even degree
|
|
1297
|
+
a += 2
|
|
1298
|
+
# affine points
|
|
1299
|
+
for x in L:
|
|
1300
|
+
r = hext(x)
|
|
1301
|
+
if not r:
|
|
1302
|
+
a += 1
|
|
1303
|
+
elif (fext(x)/r**2).trace() == 0:
|
|
1304
|
+
a += 2
|
|
1305
|
+
else:
|
|
1306
|
+
# points at infinity
|
|
1307
|
+
d = h[g+1]**2 + 4*f[2*g+2]
|
|
1308
|
+
if not d:
|
|
1309
|
+
a += 1
|
|
1310
|
+
elif n % 2 == 0 or d.is_square():
|
|
1311
|
+
a += 2
|
|
1312
|
+
# affine points
|
|
1313
|
+
for x in L:
|
|
1314
|
+
d = hext(x)**2 + 4*fext(x)
|
|
1315
|
+
if not d:
|
|
1316
|
+
a += 1
|
|
1317
|
+
elif d.is_square():
|
|
1318
|
+
a += 2
|
|
1319
|
+
|
|
1320
|
+
return a
|
|
1321
|
+
|
|
1322
|
+
def cardinality_hypellfrob(self, extension_degree=1, algorithm=None):
|
|
1323
|
+
r"""
|
|
1324
|
+
Count points on a single extension of the base field
|
|
1325
|
+
using the ``hypellfrob`` program.
|
|
1326
|
+
|
|
1327
|
+
EXAMPLES::
|
|
1328
|
+
|
|
1329
|
+
sage: K = GF(next_prime(1<<10))
|
|
1330
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1331
|
+
sage: H = HyperellipticCurve(t^7 + 3*t^5 + 5)
|
|
1332
|
+
sage: H.cardinality_hypellfrob()
|
|
1333
|
+
1025
|
|
1334
|
+
|
|
1335
|
+
sage: K = GF(49999)
|
|
1336
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1337
|
+
sage: H = HyperellipticCurve(t^7 + 3*t^5 + 5)
|
|
1338
|
+
sage: H.cardinality_hypellfrob()
|
|
1339
|
+
50162
|
|
1340
|
+
sage: H.cardinality_hypellfrob(3)
|
|
1341
|
+
124992471088310
|
|
1342
|
+
"""
|
|
1343
|
+
# the following actually computes the cardinality for several extensions
|
|
1344
|
+
# but the overhead is negligible
|
|
1345
|
+
return self.count_points_hypellfrob(n=extension_degree, algorithm=algorithm)[-1]
|
|
1346
|
+
|
|
1347
|
+
@cached_method
|
|
1348
|
+
def cardinality(self, extension_degree=1):
|
|
1349
|
+
r"""
|
|
1350
|
+
Count points on a single extension of the base field.
|
|
1351
|
+
|
|
1352
|
+
EXAMPLES::
|
|
1353
|
+
|
|
1354
|
+
sage: K = GF(101)
|
|
1355
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1356
|
+
sage: H = HyperellipticCurve(t^9 + 3*t^5 + 5)
|
|
1357
|
+
sage: H.cardinality()
|
|
1358
|
+
106
|
|
1359
|
+
sage: H.cardinality(15)
|
|
1360
|
+
1160968955369992567076405831000
|
|
1361
|
+
sage: H.cardinality(100)
|
|
1362
|
+
270481382942152609326719471080753083367793838278100277689020104911710151430673927943945601434674459120495370826289654897190781715493352266982697064575800553229661690000887425442240414673923744999504000
|
|
1363
|
+
|
|
1364
|
+
sage: K = GF(37)
|
|
1365
|
+
sage: R.<t> = PolynomialRing(K)
|
|
1366
|
+
sage: H = HyperellipticCurve(t^9 + 3*t^5 + 5)
|
|
1367
|
+
sage: H.cardinality()
|
|
1368
|
+
40
|
|
1369
|
+
sage: H.cardinality(2)
|
|
1370
|
+
1408
|
|
1371
|
+
sage: H.cardinality(3)
|
|
1372
|
+
50116
|
|
1373
|
+
|
|
1374
|
+
The following example shows that :issue:`20391` has been resolved::
|
|
1375
|
+
|
|
1376
|
+
sage: F=GF(23)
|
|
1377
|
+
sage: x=polygen(F)
|
|
1378
|
+
sage: C=HyperellipticCurve(x^8+1)
|
|
1379
|
+
sage: C.cardinality()
|
|
1380
|
+
24
|
|
1381
|
+
"""
|
|
1382
|
+
K = self.base_ring()
|
|
1383
|
+
q = K.cardinality()
|
|
1384
|
+
e = K.degree()
|
|
1385
|
+
g = self.genus()
|
|
1386
|
+
f, h = self.hyperelliptic_polynomials()
|
|
1387
|
+
n = extension_degree
|
|
1388
|
+
|
|
1389
|
+
# We may:
|
|
1390
|
+
# - check for actual field of definition of the curve (up to isomorphism)
|
|
1391
|
+
if e == 1 and h == 0 and f.degree() % 2 == 1:
|
|
1392
|
+
N1 = self._frobenius_coefficient_bound_traces(n)
|
|
1393
|
+
N2 = self._frobenius_coefficient_bound_charpoly()
|
|
1394
|
+
if n < g and q > (2*g+1)*(2*N1-1):
|
|
1395
|
+
return self.cardinality_hypellfrob(n, algorithm='traces')
|
|
1396
|
+
elif q > (2*g+1)*(2*N2-1):
|
|
1397
|
+
return self.cardinality_hypellfrob(n, algorithm='charpoly')
|
|
1398
|
+
|
|
1399
|
+
# No smart method available
|
|
1400
|
+
return self.cardinality_exhaustive(n)
|
|
1401
|
+
|
|
1402
|
+
def zeta_function(self):
|
|
1403
|
+
r"""
|
|
1404
|
+
Compute the zeta function of the hyperelliptic curve.
|
|
1405
|
+
|
|
1406
|
+
EXAMPLES::
|
|
1407
|
+
|
|
1408
|
+
sage: F = GF(2); R.<t> = F[]
|
|
1409
|
+
sage: H = HyperellipticCurve(t^9 + t, t^4)
|
|
1410
|
+
sage: H.zeta_function()
|
|
1411
|
+
(16*x^8 + 8*x^7 + 8*x^6 + 4*x^5 + 6*x^4 + 2*x^3 + 2*x^2 + x + 1)/(2*x^2 - 3*x + 1)
|
|
1412
|
+
|
|
1413
|
+
sage: F.<a> = GF(4); R.<t> = F[]
|
|
1414
|
+
sage: H = HyperellipticCurve(t^5 + t^3 + t^2 + t + 1, t^2 + t + 1)
|
|
1415
|
+
sage: H.zeta_function()
|
|
1416
|
+
(16*x^4 + 8*x^3 + x^2 + 2*x + 1)/(4*x^2 - 5*x + 1)
|
|
1417
|
+
|
|
1418
|
+
sage: F.<a> = GF(9); R.<t> = F[]
|
|
1419
|
+
sage: H = HyperellipticCurve(t^5 + a*t)
|
|
1420
|
+
sage: H.zeta_function()
|
|
1421
|
+
(81*x^4 + 72*x^3 + 32*x^2 + 8*x + 1)/(9*x^2 - 10*x + 1)
|
|
1422
|
+
|
|
1423
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
1424
|
+
sage: H = HyperellipticCurve(t^5 + t + 2)
|
|
1425
|
+
sage: H.zeta_function()
|
|
1426
|
+
(1369*x^4 + 37*x^3 - 52*x^2 + x + 1)/(37*x^2 - 38*x + 1)
|
|
1427
|
+
|
|
1428
|
+
A quadratic twist::
|
|
1429
|
+
|
|
1430
|
+
sage: R.<t> = PolynomialRing(GF(37))
|
|
1431
|
+
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
|
|
1432
|
+
sage: H.zeta_function()
|
|
1433
|
+
(1369*x^4 - 37*x^3 - 52*x^2 - x + 1)/(37*x^2 - 38*x + 1)
|
|
1434
|
+
"""
|
|
1435
|
+
q = self.base_ring().cardinality()
|
|
1436
|
+
P = self.frobenius_polynomial()
|
|
1437
|
+
x = P.parent().gen(0)
|
|
1438
|
+
return P.reverse() / ((1-x)*(1-q*x))
|
|
1439
|
+
|
|
1440
|
+
# This where Cartier Matrix is actually computed. This is either called by
|
|
1441
|
+
# E.Cartier_matrix, E.a_number, or E.Hasse_Witt.
|
|
1442
|
+
@cached_method
|
|
1443
|
+
def _Cartier_matrix_cached(self):
|
|
1444
|
+
r"""
|
|
1445
|
+
INPUT:
|
|
1446
|
+
|
|
1447
|
+
- ``self`` -- Hyperelliptic Curve of the form `y^2 = f(x)` over a
|
|
1448
|
+
finite field, `\GF{q}`
|
|
1449
|
+
|
|
1450
|
+
OUTPUT:
|
|
1451
|
+
|
|
1452
|
+
- 'matrix(Fq,M)' The matrix `M = (c_(pi-j)), f(x)^((p-1)/2) = \sum c_i x^i`
|
|
1453
|
+
- 'Coeff' List of Coeffs of F, this is needed for Hasse-Witt function.
|
|
1454
|
+
- 'g' genus of the curve self, this is needed by a-number.
|
|
1455
|
+
- 'Fq' is the base field of self, and it is needed for Hasse-Witt
|
|
1456
|
+
- 'p' is the char(Fq), this is needed for Hasse-Witt.
|
|
1457
|
+
- 'E' The initial elliptic curve to check some caching conditions.
|
|
1458
|
+
|
|
1459
|
+
EXAMPLES::
|
|
1460
|
+
|
|
1461
|
+
sage: K.<x>=GF(9,'x')[]
|
|
1462
|
+
sage: C=HyperellipticCurve(x^7-1,0)
|
|
1463
|
+
sage: C._Cartier_matrix_cached()
|
|
1464
|
+
(
|
|
1465
|
+
[0 0 2]
|
|
1466
|
+
[0 0 0]
|
|
1467
|
+
[0 1 0], [2, 0, 0, 0, 0, 0, 0, 1, 0], 3, Finite Field in x of size 3^2, 3, Hyperelliptic Curve over Finite Field in x of size 3^2 defined by y^2 = x^7 + 2
|
|
1468
|
+
)
|
|
1469
|
+
sage: K.<x>=GF(49,'x')[]
|
|
1470
|
+
sage: C=HyperellipticCurve(x^5+1,0)
|
|
1471
|
+
sage: C._Cartier_matrix_cached()
|
|
1472
|
+
(
|
|
1473
|
+
[0 3]
|
|
1474
|
+
[0 0], [1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1], 2, Finite Field in x of size 7^2, 7, Hyperelliptic Curve over Finite Field in x of size 7^2 defined by y^2 = x^5 + 1
|
|
1475
|
+
)
|
|
1476
|
+
|
|
1477
|
+
sage: P.<x>=GF(9,'a')[]
|
|
1478
|
+
sage: C=HyperellipticCurve(x^29+1,0)
|
|
1479
|
+
sage: C._Cartier_matrix_cached()
|
|
1480
|
+
(
|
|
1481
|
+
[0 0 1 0 0 0 0 0 0 0 0 0 0 0]
|
|
1482
|
+
[0 0 0 0 0 1 0 0 0 0 0 0 0 0]
|
|
1483
|
+
[0 0 0 0 0 0 0 0 1 0 0 0 0 0]
|
|
1484
|
+
[0 0 0 0 0 0 0 0 0 0 0 1 0 0]
|
|
1485
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1486
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1487
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1488
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1489
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1490
|
+
[1 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1491
|
+
[0 0 0 1 0 0 0 0 0 0 0 0 0 0]
|
|
1492
|
+
[0 0 0 0 0 0 1 0 0 0 0 0 0 0]
|
|
1493
|
+
[0 0 0 0 0 0 0 0 0 1 0 0 0 0]
|
|
1494
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 1 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 14, Finite Field in a of size 3^2, 3, Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 = x^29 + 1
|
|
1495
|
+
)
|
|
1496
|
+
|
|
1497
|
+
TESTS::
|
|
1498
|
+
|
|
1499
|
+
sage: K.<x>=GF(2,'x')[]
|
|
1500
|
+
sage: C=HyperellipticCurve(x^7-1,x)
|
|
1501
|
+
sage: C._Cartier_matrix_cached()
|
|
1502
|
+
Traceback (most recent call last):
|
|
1503
|
+
...
|
|
1504
|
+
ValueError: p must be odd
|
|
1505
|
+
|
|
1506
|
+
sage: K.<x>=GF(5,'x')[]
|
|
1507
|
+
sage: C=HyperellipticCurve(x^7-1,4)
|
|
1508
|
+
sage: C._Cartier_matrix_cached()
|
|
1509
|
+
Traceback (most recent call last):
|
|
1510
|
+
...
|
|
1511
|
+
ValueError: E must be of the form y^2 = f(x)
|
|
1512
|
+
|
|
1513
|
+
sage: K.<x>=GF(5,'x')[]
|
|
1514
|
+
sage: C=HyperellipticCurve(x^8-1,0)
|
|
1515
|
+
sage: C._Cartier_matrix_cached()
|
|
1516
|
+
Traceback (most recent call last):
|
|
1517
|
+
...
|
|
1518
|
+
ValueError: In this implementation the degree of f must be odd
|
|
1519
|
+
|
|
1520
|
+
sage: K.<x>=GF(5,'x')[]
|
|
1521
|
+
sage: C=HyperellipticCurve(x^5+1,0,check_squarefree=False)
|
|
1522
|
+
sage: C._Cartier_matrix_cached()
|
|
1523
|
+
Traceback (most recent call last):
|
|
1524
|
+
...
|
|
1525
|
+
ValueError: curve is not smooth
|
|
1526
|
+
"""
|
|
1527
|
+
# Compute the finite field and prime p.
|
|
1528
|
+
Fq = self.base_ring()
|
|
1529
|
+
p = Fq.characteristic()
|
|
1530
|
+
#checks
|
|
1531
|
+
|
|
1532
|
+
if p == 2:
|
|
1533
|
+
raise ValueError("p must be odd")
|
|
1534
|
+
|
|
1535
|
+
g = self.genus()
|
|
1536
|
+
|
|
1537
|
+
#retrieve the function f(x) ,where y^2=f(x)
|
|
1538
|
+
f,h = self.hyperelliptic_polynomials()
|
|
1539
|
+
#This implementation only deals with h=0
|
|
1540
|
+
if h != 0:
|
|
1541
|
+
raise ValueError("E must be of the form y^2 = f(x)")
|
|
1542
|
+
|
|
1543
|
+
d = f.degree()
|
|
1544
|
+
#this implementation is for odd degree only, even degree will be handled later.
|
|
1545
|
+
if d % 2 == 0:
|
|
1546
|
+
raise ValueError("In this implementation the degree of f must be odd")
|
|
1547
|
+
#Compute resultant to make sure no repeated roots
|
|
1548
|
+
df = f.derivative()
|
|
1549
|
+
R = df.resultant(f)
|
|
1550
|
+
if R == 0:
|
|
1551
|
+
raise ValueError("curve is not smooth")
|
|
1552
|
+
|
|
1553
|
+
#computing F, since the entries of the matrix are c_i where F= \sum c_i x^i
|
|
1554
|
+
|
|
1555
|
+
F = f**((p-1)/2)
|
|
1556
|
+
|
|
1557
|
+
#coefficients returns a_0, ... , a_n where f(x) = a_n x^n + ... + a_0
|
|
1558
|
+
|
|
1559
|
+
Coeff = F.list()
|
|
1560
|
+
|
|
1561
|
+
#inserting zeros when necessary-- that is, when deg(F) < p*g-1, (simplified if p <2g-1)
|
|
1562
|
+
#which is the highest powered coefficient needed for our matrix
|
|
1563
|
+
#So we don't have enough coefficients we add extra zeros to have the same poly,
|
|
1564
|
+
#but enough coeff.
|
|
1565
|
+
|
|
1566
|
+
zeros = [0 for i in range(p*g-len(Coeff))]
|
|
1567
|
+
Coeff = Coeff + zeros
|
|
1568
|
+
|
|
1569
|
+
# compute each row of matrix as list and then M=list of lists(rows)
|
|
1570
|
+
|
|
1571
|
+
M = []
|
|
1572
|
+
for j in range(1,g+1):
|
|
1573
|
+
H = [Coeff[i] for i in range((p*j-1), (p*j-g-1),-1)]
|
|
1574
|
+
M.append(H)
|
|
1575
|
+
return matrix(Fq,M), Coeff, g, Fq,p, self
|
|
1576
|
+
|
|
1577
|
+
# This is what is called from command line
|
|
1578
|
+
def Cartier_matrix(self):
|
|
1579
|
+
r"""
|
|
1580
|
+
INPUT:
|
|
1581
|
+
|
|
1582
|
+
- ``self`` -- Hyperelliptic Curve of the form `y^2 = f(x)` over a
|
|
1583
|
+
finite field, `\GF{q}`
|
|
1584
|
+
|
|
1585
|
+
OUTPUT:
|
|
1586
|
+
|
|
1587
|
+
The matrix `M = (c_{pi-j})`, where `c_i` are the coefficients of
|
|
1588
|
+
`f(x)^{(p-1)/2} = \sum c_i x^i`.
|
|
1589
|
+
|
|
1590
|
+
REFERENCES:
|
|
1591
|
+
|
|
1592
|
+
N. Yui. On the Jacobian varieties of hyperelliptic curves over fields of characteristic `p > 2`.
|
|
1593
|
+
|
|
1594
|
+
EXAMPLES::
|
|
1595
|
+
|
|
1596
|
+
sage: K.<x> = GF(9,'x')[]
|
|
1597
|
+
sage: C = HyperellipticCurve(x^7 - 1, 0)
|
|
1598
|
+
sage: C.Cartier_matrix()
|
|
1599
|
+
[0 0 2]
|
|
1600
|
+
[0 0 0]
|
|
1601
|
+
[0 1 0]
|
|
1602
|
+
|
|
1603
|
+
sage: K.<x> = GF(49, 'x')[]
|
|
1604
|
+
sage: C = HyperellipticCurve(x^5 + 1, 0)
|
|
1605
|
+
sage: C.Cartier_matrix()
|
|
1606
|
+
[0 3]
|
|
1607
|
+
[0 0]
|
|
1608
|
+
|
|
1609
|
+
sage: P.<x> = GF(9, 'a')[]
|
|
1610
|
+
sage: E = HyperellipticCurve(x^29 + 1, 0)
|
|
1611
|
+
sage: E.Cartier_matrix()
|
|
1612
|
+
[0 0 1 0 0 0 0 0 0 0 0 0 0 0]
|
|
1613
|
+
[0 0 0 0 0 1 0 0 0 0 0 0 0 0]
|
|
1614
|
+
[0 0 0 0 0 0 0 0 1 0 0 0 0 0]
|
|
1615
|
+
[0 0 0 0 0 0 0 0 0 0 0 1 0 0]
|
|
1616
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1617
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1618
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1619
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1620
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1621
|
+
[1 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1622
|
+
[0 0 0 1 0 0 0 0 0 0 0 0 0 0]
|
|
1623
|
+
[0 0 0 0 0 0 1 0 0 0 0 0 0 0]
|
|
1624
|
+
[0 0 0 0 0 0 0 0 0 1 0 0 0 0]
|
|
1625
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 1 0]
|
|
1626
|
+
|
|
1627
|
+
TESTS::
|
|
1628
|
+
|
|
1629
|
+
sage: K.<x>=GF(2,'x')[]
|
|
1630
|
+
sage: C=HyperellipticCurve(x^7-1,x)
|
|
1631
|
+
sage: C.Cartier_matrix()
|
|
1632
|
+
Traceback (most recent call last):
|
|
1633
|
+
...
|
|
1634
|
+
ValueError: p must be odd
|
|
1635
|
+
|
|
1636
|
+
sage: K.<x>=GF(5,'x')[]
|
|
1637
|
+
sage: C=HyperellipticCurve(x^7-1,4)
|
|
1638
|
+
sage: C.Cartier_matrix()
|
|
1639
|
+
Traceback (most recent call last):
|
|
1640
|
+
...
|
|
1641
|
+
ValueError: E must be of the form y^2 = f(x)
|
|
1642
|
+
|
|
1643
|
+
sage: K.<x>=GF(5,'x')[]
|
|
1644
|
+
sage: C=HyperellipticCurve(x^8-1,0)
|
|
1645
|
+
sage: C.Cartier_matrix()
|
|
1646
|
+
Traceback (most recent call last):
|
|
1647
|
+
...
|
|
1648
|
+
ValueError: In this implementation the degree of f must be odd
|
|
1649
|
+
|
|
1650
|
+
sage: K.<x>=GF(5,'x')[]
|
|
1651
|
+
sage: C=HyperellipticCurve(x^5+1,0,check_squarefree=False)
|
|
1652
|
+
sage: C.Cartier_matrix()
|
|
1653
|
+
Traceback (most recent call last):
|
|
1654
|
+
...
|
|
1655
|
+
ValueError: curve is not smooth
|
|
1656
|
+
"""
|
|
1657
|
+
#checking first that Cartier matrix is not already cached. Since
|
|
1658
|
+
#it can be called by either Hasse_Witt or a_number.
|
|
1659
|
+
#This way it does not matter which function is called first
|
|
1660
|
+
#in the code.
|
|
1661
|
+
# Github Issue #11115: Why shall we waste time by studying
|
|
1662
|
+
# the cache manually? We only need to check whether the cached
|
|
1663
|
+
# data belong to self.
|
|
1664
|
+
M, Coeffs,g, Fq, p, E = self._Cartier_matrix_cached()
|
|
1665
|
+
if E != self:
|
|
1666
|
+
self._Cartier_matrix_cached.clear_cache()
|
|
1667
|
+
M, Coeffs,g, Fq, p, E = self._Cartier_matrix_cached()
|
|
1668
|
+
return M
|
|
1669
|
+
|
|
1670
|
+
@cached_method
|
|
1671
|
+
def _Hasse_Witt_cached(self):
|
|
1672
|
+
r"""
|
|
1673
|
+
This is where Hasse_Witt is actually computed.
|
|
1674
|
+
|
|
1675
|
+
This is either called by E.Hasse_Witt or E.p_rank.
|
|
1676
|
+
|
|
1677
|
+
INPUT:
|
|
1678
|
+
|
|
1679
|
+
- ``E`` -- hyperelliptic Curve of the form `y^2 = f(x)` over
|
|
1680
|
+
a finite field, `\GF{q}`
|
|
1681
|
+
|
|
1682
|
+
OUTPUT:
|
|
1683
|
+
|
|
1684
|
+
- ``N`` -- the matrix `N = M M^p \dots M^{p^{g-1}}` where
|
|
1685
|
+
`M = c_{pi-j}, f(x)^{(p-1)/2} = \sum c_i x^i`
|
|
1686
|
+
|
|
1687
|
+
- ``E`` -- the initial curve to check some caching conditions
|
|
1688
|
+
|
|
1689
|
+
EXAMPLES::
|
|
1690
|
+
|
|
1691
|
+
sage: K.<x> = GF(9,'x')[]
|
|
1692
|
+
sage: C = HyperellipticCurve(x^7-1,0)
|
|
1693
|
+
sage: C._Hasse_Witt_cached()
|
|
1694
|
+
(
|
|
1695
|
+
[0 0 0]
|
|
1696
|
+
[0 0 0]
|
|
1697
|
+
[0 0 0], Hyperelliptic Curve over Finite Field in x of size 3^2 defined by y^2 = x^7 + 2
|
|
1698
|
+
)
|
|
1699
|
+
|
|
1700
|
+
sage: K.<x> = GF(49,'x')[]
|
|
1701
|
+
sage: C = HyperellipticCurve(x^5+1,0)
|
|
1702
|
+
sage: C._Hasse_Witt_cached()
|
|
1703
|
+
(
|
|
1704
|
+
[0 0]
|
|
1705
|
+
[0 0], Hyperelliptic Curve over Finite Field in x of size 7^2 defined by y^2 = x^5 + 1
|
|
1706
|
+
)
|
|
1707
|
+
|
|
1708
|
+
sage: P.<x> = GF(9,'a')[]
|
|
1709
|
+
sage: C = HyperellipticCurve(x^29+1,0)
|
|
1710
|
+
sage: C._Hasse_Witt_cached()
|
|
1711
|
+
(
|
|
1712
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1713
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1714
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1715
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1716
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1717
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1718
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1719
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1720
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1721
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1722
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1723
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1724
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1725
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0], Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 = x^29 + 1
|
|
1726
|
+
)
|
|
1727
|
+
|
|
1728
|
+
TESTS:
|
|
1729
|
+
|
|
1730
|
+
This shows that the bug at :issue:`23181` is fixed::
|
|
1731
|
+
|
|
1732
|
+
sage: K.<z> = PolynomialRing(GF(5))
|
|
1733
|
+
sage: L.<a> = GF(5).extension(z^3+3*z+3,'a')
|
|
1734
|
+
sage: H.<x> = L[]
|
|
1735
|
+
sage: E = HyperellipticCurve(x^5+x^4+a^92*x^3+a^18*x^2+a^56*x,0)
|
|
1736
|
+
sage: E.p_rank()
|
|
1737
|
+
0
|
|
1738
|
+
"""
|
|
1739
|
+
# If Cartier Matrix is already cached for this curve, use that or evaluate it to get M,
|
|
1740
|
+
#Coeffs, genus, Fq=base field of self, p=char(Fq). This is so we have one less matrix to
|
|
1741
|
+
#compute.
|
|
1742
|
+
|
|
1743
|
+
#We use caching here since Cartier matrix is needed to compute Hasse Witt. So if the Cartier
|
|
1744
|
+
#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply
|
|
1745
|
+
#compute it. If it is cached then we need to make sure that we have the correct one. So check
|
|
1746
|
+
#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check
|
|
1747
|
+
#the last entry in A. If it does not match, clear A and compute Cartier.
|
|
1748
|
+
#
|
|
1749
|
+
#Since Github Issue #11115, there is a different cache for methods
|
|
1750
|
+
#that don't accept arguments. Anyway, the easiest is to call
|
|
1751
|
+
#the cached method and simply see whether the data belong to self.
|
|
1752
|
+
M, Coeffs, g, Fq, p, E = self._Cartier_matrix_cached()
|
|
1753
|
+
if E != self:
|
|
1754
|
+
self._Cartier_matrix_cached.clear_cache()
|
|
1755
|
+
M, Coeffs, g, Fq, p, E = self._Cartier_matrix_cached()
|
|
1756
|
+
|
|
1757
|
+
#This compute the action of p^kth Frobenius on list of coefficients
|
|
1758
|
+
def frob_mat(Coeffs, k):
|
|
1759
|
+
a = p ** k
|
|
1760
|
+
mat = []
|
|
1761
|
+
Coeffs_pow = [c ** a for c in Coeffs]
|
|
1762
|
+
for i in range(1, g + 1):
|
|
1763
|
+
H = [(Coeffs_pow[j]) for j in range((p*i-1), (p*i - g-1), -1)]
|
|
1764
|
+
mat.append(H)
|
|
1765
|
+
return matrix(Fq, mat)
|
|
1766
|
+
|
|
1767
|
+
#Computes all the different possible action of frobenius on matrix M and stores in list Mall
|
|
1768
|
+
Mall = [M] + [frob_mat(Coeffs, k) for k in range(1, g)]
|
|
1769
|
+
Mall = reversed(Mall)
|
|
1770
|
+
#initial N=I, so we can go through Mall and multiply all matrices with I and
|
|
1771
|
+
#get the Hasse-Witt matrix.
|
|
1772
|
+
N = identity_matrix(Fq, g)
|
|
1773
|
+
for l in Mall:
|
|
1774
|
+
N = N * l
|
|
1775
|
+
return N, E
|
|
1776
|
+
|
|
1777
|
+
# This is the function which is actually called by command line
|
|
1778
|
+
def Hasse_Witt(self):
|
|
1779
|
+
r"""
|
|
1780
|
+
INPUT:
|
|
1781
|
+
|
|
1782
|
+
- ``self`` -- Hyperelliptic Curve of the form `y^2 = f(x)` over a
|
|
1783
|
+
finite field, `\GF{q}`
|
|
1784
|
+
|
|
1785
|
+
OUTPUT:
|
|
1786
|
+
|
|
1787
|
+
The matrix `N = M M^p \dots M^{p^{g-1}}` where `M = c_{pi-j}`, and
|
|
1788
|
+
`f(x)^{(p-1)/2} = \sum c_i x^i`.
|
|
1789
|
+
|
|
1790
|
+
Reference-N. Yui. On the Jacobian varieties of hyperelliptic curves over fields of characteristic `p > 2`.
|
|
1791
|
+
|
|
1792
|
+
EXAMPLES::
|
|
1793
|
+
|
|
1794
|
+
sage: K.<x> = GF(9, 'x')[]
|
|
1795
|
+
sage: C = HyperellipticCurve(x^7 - 1, 0)
|
|
1796
|
+
sage: C.Hasse_Witt()
|
|
1797
|
+
[0 0 0]
|
|
1798
|
+
[0 0 0]
|
|
1799
|
+
[0 0 0]
|
|
1800
|
+
|
|
1801
|
+
sage: K.<x> = GF(49, 'x')[]
|
|
1802
|
+
sage: C = HyperellipticCurve(x^5 + 1, 0)
|
|
1803
|
+
sage: C.Hasse_Witt()
|
|
1804
|
+
[0 0]
|
|
1805
|
+
[0 0]
|
|
1806
|
+
|
|
1807
|
+
sage: P.<x> = GF(9, 'a')[]
|
|
1808
|
+
sage: E = HyperellipticCurve(x^29 + 1, 0)
|
|
1809
|
+
sage: E.Hasse_Witt()
|
|
1810
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1811
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1812
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1813
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1814
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1815
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1816
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1817
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1818
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1819
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1820
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1821
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1822
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1823
|
+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
1824
|
+
"""
|
|
1825
|
+
# Since Github Issue #11115, there is a special
|
|
1826
|
+
# type of cached for those methods that don't
|
|
1827
|
+
# accept arguments. We want to get Hasse-Witt
|
|
1828
|
+
# from the cache - but apparently it could be
|
|
1829
|
+
# that the cached value does not belong to self.
|
|
1830
|
+
# So, the easiest is:
|
|
1831
|
+
N, E = self._Hasse_Witt_cached()
|
|
1832
|
+
if E != self:
|
|
1833
|
+
self._Hasse_Witt_cached.clear_cache()
|
|
1834
|
+
N, E = self._Hasse_Witt_cached()
|
|
1835
|
+
return N
|
|
1836
|
+
|
|
1837
|
+
def a_number(self):
|
|
1838
|
+
r"""
|
|
1839
|
+
INPUT:
|
|
1840
|
+
|
|
1841
|
+
- ``self`` -- Hyperelliptic Curve of the form `y^2 = f(x)` over a
|
|
1842
|
+
finite field, `\GF{q}`
|
|
1843
|
+
|
|
1844
|
+
OUTPUT: a-number
|
|
1845
|
+
|
|
1846
|
+
EXAMPLES::
|
|
1847
|
+
|
|
1848
|
+
sage: K.<x> = GF(49, 'x')[]
|
|
1849
|
+
sage: C = HyperellipticCurve(x^5 + 1, 0)
|
|
1850
|
+
sage: C.a_number()
|
|
1851
|
+
1
|
|
1852
|
+
|
|
1853
|
+
sage: K.<x> = GF(9, 'x')[]
|
|
1854
|
+
sage: C = HyperellipticCurve(x^7 - 1, 0)
|
|
1855
|
+
sage: C.a_number()
|
|
1856
|
+
1
|
|
1857
|
+
|
|
1858
|
+
sage: P.<x> = GF(9, 'a')[]
|
|
1859
|
+
sage: E = HyperellipticCurve(x^29 + 1, 0)
|
|
1860
|
+
sage: E.a_number()
|
|
1861
|
+
5
|
|
1862
|
+
"""
|
|
1863
|
+
#We use caching here since Cartier matrix is needed to compute a_number. So if the Cartier
|
|
1864
|
+
#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply
|
|
1865
|
+
#compute it. If it is cached then we need to make sure that we have the correct one. So check
|
|
1866
|
+
#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check
|
|
1867
|
+
#the last entry in A. If it does not match, clear A and compute Cartier.
|
|
1868
|
+
# Since Github Issue #11115, there is a special cache for methods
|
|
1869
|
+
# that don't accept arguments. The easiest is: Call the cached
|
|
1870
|
+
# method, and test whether the last entry is self.
|
|
1871
|
+
M,Coeffs,g, Fq, p,E = self._Cartier_matrix_cached()
|
|
1872
|
+
if E != self:
|
|
1873
|
+
self._Cartier_matrix_cached.clear_cache()
|
|
1874
|
+
M,Coeffs,g, Fq, p,E = self._Cartier_matrix_cached()
|
|
1875
|
+
return g - rank(M)
|
|
1876
|
+
|
|
1877
|
+
def p_rank(self):
|
|
1878
|
+
r"""
|
|
1879
|
+
INPUT:
|
|
1880
|
+
|
|
1881
|
+
- ``self`` -- Hyperelliptic Curve of the form `y^2 = f(x)` over a
|
|
1882
|
+
finite field, `\GF{q}`
|
|
1883
|
+
|
|
1884
|
+
OUTPUT: p-rank
|
|
1885
|
+
|
|
1886
|
+
EXAMPLES::
|
|
1887
|
+
|
|
1888
|
+
sage: K.<x> = GF(49, 'x')[]
|
|
1889
|
+
sage: C = HyperellipticCurve(x^5 + 1, 0)
|
|
1890
|
+
sage: C.p_rank()
|
|
1891
|
+
0
|
|
1892
|
+
|
|
1893
|
+
sage: K.<x> = GF(9, 'x')[]
|
|
1894
|
+
sage: C = HyperellipticCurve(x^7 - 1, 0)
|
|
1895
|
+
sage: C.p_rank()
|
|
1896
|
+
0
|
|
1897
|
+
|
|
1898
|
+
sage: P.<x> = GF(9, 'a')[]
|
|
1899
|
+
sage: E = HyperellipticCurve(x^29 + 1, 0)
|
|
1900
|
+
sage: E.p_rank()
|
|
1901
|
+
0
|
|
1902
|
+
"""
|
|
1903
|
+
#We use caching here since Hasse Witt is needed to compute p_rank. So if the Hasse Witt
|
|
1904
|
+
#is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply
|
|
1905
|
+
#compute it. If it is cached then we need to make sure that we have the correct one. So check
|
|
1906
|
+
#which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check
|
|
1907
|
+
#the last entry in A. If it does not match, clear A and compute Hasse Witt.
|
|
1908
|
+
# However, it seems a waste of time to manually analyse the cache
|
|
1909
|
+
# -- See Github Issue #11115
|
|
1910
|
+
N, E = self._Hasse_Witt_cached()
|
|
1911
|
+
if E != self:
|
|
1912
|
+
self._Hasse_Witt_cached.clear_cache()
|
|
1913
|
+
N, E = self._Hasse_Witt_cached()
|
|
1914
|
+
return rank(N)
|