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,3026 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.libs.singular
|
|
3
|
+
r"""
|
|
4
|
+
Projective curves
|
|
5
|
+
|
|
6
|
+
Projective curves in Sage are curves in a projective space or a projective plane.
|
|
7
|
+
|
|
8
|
+
EXAMPLES:
|
|
9
|
+
|
|
10
|
+
We can construct curves in either a projective plane::
|
|
11
|
+
|
|
12
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
13
|
+
sage: C = Curve([y*z^2 - x^3], P); C
|
|
14
|
+
Projective Plane Curve over Rational Field defined by -x^3 + y*z^2
|
|
15
|
+
|
|
16
|
+
or in higher dimensional projective spaces::
|
|
17
|
+
|
|
18
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
19
|
+
sage: C = Curve([y*w^3 - x^4, z*w^3 - x^4], P); C
|
|
20
|
+
Projective Curve over Rational Field defined by -x^4 + y*w^3, -x^4 + z*w^3
|
|
21
|
+
|
|
22
|
+
Integral projective curves over finite fields
|
|
23
|
+
---------------------------------------------
|
|
24
|
+
|
|
25
|
+
If the curve is defined over a finite field and integral, that is reduced and
|
|
26
|
+
irreducible, its function field is tightly coupled with the curve so that
|
|
27
|
+
advanced computations based on Sage's global function field machinery are
|
|
28
|
+
available.
|
|
29
|
+
|
|
30
|
+
EXAMPLES::
|
|
31
|
+
|
|
32
|
+
sage: k = GF(2)
|
|
33
|
+
sage: P.<x,y,z> = ProjectiveSpace(k, 2)
|
|
34
|
+
sage: C = Curve(x^2*z - y^3, P)
|
|
35
|
+
sage: C.genus()
|
|
36
|
+
0
|
|
37
|
+
sage: C.function_field()
|
|
38
|
+
Function field in z defined by z + y^3
|
|
39
|
+
|
|
40
|
+
Closed points of arbitrary degree can be computed::
|
|
41
|
+
|
|
42
|
+
sage: C.closed_points()
|
|
43
|
+
[Point (x, y), Point (y, z), Point (x + z, y + z)]
|
|
44
|
+
sage: C.closed_points(2)
|
|
45
|
+
[Point (y^2 + y*z + z^2, x + z)]
|
|
46
|
+
sage: C.closed_points(3)
|
|
47
|
+
[Point (y^3 + y^2*z + z^3, x + y + z),
|
|
48
|
+
Point (x^2 + y*z + z^2, x*y + x*z + y*z, y^2 + x*z + y*z + z^2)]
|
|
49
|
+
|
|
50
|
+
All singular closed points can be found::
|
|
51
|
+
|
|
52
|
+
sage: C.singular_closed_points()
|
|
53
|
+
[Point (x, y)]
|
|
54
|
+
sage: p = _[0]
|
|
55
|
+
sage: p.places() # a unibranch singularity, that is, a cusp
|
|
56
|
+
[Place (1/y)]
|
|
57
|
+
sage: pls = _[0]
|
|
58
|
+
sage: C.place_to_closed_point(pls)
|
|
59
|
+
Point (x, y)
|
|
60
|
+
|
|
61
|
+
It is easy to transit to and from the function field of the curve::
|
|
62
|
+
|
|
63
|
+
sage: fx = C(x/z)
|
|
64
|
+
sage: fy = C(y/z)
|
|
65
|
+
sage: fx^2 - fy^3
|
|
66
|
+
0
|
|
67
|
+
sage: fx.divisor()
|
|
68
|
+
3*Place (1/y)
|
|
69
|
+
- 3*Place (y)
|
|
70
|
+
sage: p, = fx.poles()
|
|
71
|
+
sage: p
|
|
72
|
+
Place (y)
|
|
73
|
+
sage: C.place_to_closed_point(p)
|
|
74
|
+
Point (y, z)
|
|
75
|
+
sage: _.rational_point()
|
|
76
|
+
(1 : 0 : 0)
|
|
77
|
+
sage: _.closed_point()
|
|
78
|
+
Point (y, z)
|
|
79
|
+
sage: _.place()
|
|
80
|
+
Place (y)
|
|
81
|
+
|
|
82
|
+
Integral projective curves over `\QQ`
|
|
83
|
+
-------------------------------------
|
|
84
|
+
|
|
85
|
+
An integral curve over `\QQ` is also equipped with the function field. Unlike
|
|
86
|
+
over finite fields, it is not possible to enumerate closed points.
|
|
87
|
+
|
|
88
|
+
EXAMPLES::
|
|
89
|
+
|
|
90
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
91
|
+
sage: C = Curve(x^2*z^2 - x^4 - y^4, P)
|
|
92
|
+
sage: C.singular_closed_points()
|
|
93
|
+
[Point (x, y)]
|
|
94
|
+
sage: p, = _
|
|
95
|
+
sage: p.places()
|
|
96
|
+
[Place (1/y, 1/y^2*z - 1), Place (1/y, 1/y^2*z + 1)]
|
|
97
|
+
sage: fy = C.function(y/z)
|
|
98
|
+
sage: fy.divisor()
|
|
99
|
+
Place (1/y, 1/y^2*z - 1)
|
|
100
|
+
+ Place (1/y, 1/y^2*z + 1)
|
|
101
|
+
+ Place (y, z - 1)
|
|
102
|
+
+ Place (y, z + 1)
|
|
103
|
+
- Place (y^4 + 1, z)
|
|
104
|
+
sage: supp = _.support()
|
|
105
|
+
sage: pl = supp[0]
|
|
106
|
+
sage: C.place_to_closed_point(pl)
|
|
107
|
+
Point (x, y)
|
|
108
|
+
sage: pl = supp[1]
|
|
109
|
+
sage: C.place_to_closed_point(pl)
|
|
110
|
+
Point (x, y)
|
|
111
|
+
sage: _.rational_point()
|
|
112
|
+
(0 : 0 : 1)
|
|
113
|
+
sage: _ in C
|
|
114
|
+
True
|
|
115
|
+
|
|
116
|
+
AUTHORS:
|
|
117
|
+
|
|
118
|
+
- William Stein (2005-11-13)
|
|
119
|
+
|
|
120
|
+
- David Joyner (2005-11-13)
|
|
121
|
+
|
|
122
|
+
- David Kohel (2006-01)
|
|
123
|
+
|
|
124
|
+
- Moritz Minzlaff (2010-11)
|
|
125
|
+
|
|
126
|
+
- Grayson Jorgenson (2016-08)
|
|
127
|
+
|
|
128
|
+
- Kwankyu Lee (2019-05): added integral projective curves
|
|
129
|
+
"""
|
|
130
|
+
# ****************************************************************************
|
|
131
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
132
|
+
#
|
|
133
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
134
|
+
#
|
|
135
|
+
# The full text of the GPL is available at:
|
|
136
|
+
#
|
|
137
|
+
# https://www.gnu.org/licenses/
|
|
138
|
+
# ****************************************************************************
|
|
139
|
+
|
|
140
|
+
from builtins import sum as add
|
|
141
|
+
|
|
142
|
+
from sage.categories.fields import Fields
|
|
143
|
+
from sage.categories.homset import hom, Hom, End
|
|
144
|
+
from sage.categories.number_fields import NumberFields
|
|
145
|
+
from sage.libs.singular.function import singular_function, lib as singular_lib, get_printlevel, set_printlevel
|
|
146
|
+
from sage.matrix.constructor import matrix
|
|
147
|
+
from sage.misc.cachefunc import cached_method
|
|
148
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
149
|
+
from sage.misc.lazy_import import lazy_import
|
|
150
|
+
from sage.misc.persist import register_unpickle_override
|
|
151
|
+
from sage.rings.integer import Integer
|
|
152
|
+
from sage.rings.integer_ring import IntegerRing
|
|
153
|
+
from sage.rings.polynomial.multi_polynomial_element import degree_lowest_rational_function
|
|
154
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
155
|
+
from sage.rings.rational_field import RationalField
|
|
156
|
+
from sage.schemes.projective.projective_space import ProjectiveSpace, ProjectiveSpace_ring
|
|
157
|
+
from sage.schemes.projective.projective_subscheme import (AlgebraicScheme_subscheme_projective,
|
|
158
|
+
AlgebraicScheme_subscheme_projective_field)
|
|
159
|
+
|
|
160
|
+
lazy_import('sage.interfaces.singular', 'singular')
|
|
161
|
+
lazy_import('sage.misc.sage_eval', 'sage_eval')
|
|
162
|
+
lazy_import('sage.rings.number_field.number_field', 'NumberField')
|
|
163
|
+
lazy_import('sage.rings.qqbar', ['number_field_elements_from_algebraics', 'QQbar'])
|
|
164
|
+
|
|
165
|
+
from .curve import Curve_generic
|
|
166
|
+
|
|
167
|
+
from .point import (ProjectiveCurvePoint_field,
|
|
168
|
+
ProjectivePlaneCurvePoint_field,
|
|
169
|
+
ProjectivePlaneCurvePoint_finite_field,
|
|
170
|
+
IntegralProjectiveCurvePoint,
|
|
171
|
+
IntegralProjectiveCurvePoint_finite_field,
|
|
172
|
+
IntegralProjectivePlaneCurvePoint,
|
|
173
|
+
IntegralProjectivePlaneCurvePoint_finite_field)
|
|
174
|
+
|
|
175
|
+
from .closed_point import IntegralProjectiveCurveClosedPoint
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class ProjectiveCurve(Curve_generic, AlgebraicScheme_subscheme_projective):
|
|
179
|
+
"""
|
|
180
|
+
Curves in projective spaces.
|
|
181
|
+
|
|
182
|
+
INPUT:
|
|
183
|
+
|
|
184
|
+
- ``A`` -- ambient projective space
|
|
185
|
+
|
|
186
|
+
- ``X`` -- list of multivariate polynomials; defining equations of the curve
|
|
187
|
+
|
|
188
|
+
EXAMPLES::
|
|
189
|
+
|
|
190
|
+
sage: P.<x,y,z,w,u> = ProjectiveSpace(GF(7), 4)
|
|
191
|
+
sage: C = Curve([y*u^2 - x^3, z*u^2 - x^3, w*u^2 - x^3, y^3 - x^3], P); C
|
|
192
|
+
Projective Curve over Finite Field of size 7 defined
|
|
193
|
+
by -x^3 + y*u^2, -x^3 + z*u^2, -x^3 + w*u^2, -x^3 + y^3
|
|
194
|
+
|
|
195
|
+
::
|
|
196
|
+
|
|
197
|
+
sage: # needs sage.rings.number_field
|
|
198
|
+
sage: K.<u> = CyclotomicField(11)
|
|
199
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(K, 3)
|
|
200
|
+
sage: C = Curve([y*w - u*z^2 - x^2, x*w - 3*u^2*z*w], P); C
|
|
201
|
+
Projective Curve over Cyclotomic Field of order 11 and degree 10 defined
|
|
202
|
+
by -x^2 + (-u)*z^2 + y*w, x*w + (-3*u^2)*z*w
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
def __init__(self, A, X, category=None):
|
|
206
|
+
"""
|
|
207
|
+
Initialize.
|
|
208
|
+
|
|
209
|
+
EXAMPLES::
|
|
210
|
+
|
|
211
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
212
|
+
sage: C = Curve(x*y^2*z^7 - x^10 - x^2*z^8)
|
|
213
|
+
sage: loads(dumps(C)) == C
|
|
214
|
+
True
|
|
215
|
+
"""
|
|
216
|
+
if not isinstance(A, ProjectiveSpace_ring):
|
|
217
|
+
raise TypeError("A (=%s) must be a projective space" % A)
|
|
218
|
+
|
|
219
|
+
Curve_generic.__init__(self, A, X, category=category)
|
|
220
|
+
|
|
221
|
+
def _repr_type(self):
|
|
222
|
+
r"""
|
|
223
|
+
Return a string representation of the type of this curve.
|
|
224
|
+
|
|
225
|
+
EXAMPLES::
|
|
226
|
+
|
|
227
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
228
|
+
sage: C = Curve([y^3 - z^3 - w^3, z*x^3 - y^4])
|
|
229
|
+
sage: C._repr_type()
|
|
230
|
+
'Projective'
|
|
231
|
+
"""
|
|
232
|
+
return "Projective"
|
|
233
|
+
|
|
234
|
+
def affine_patch(self, i, AA=None):
|
|
235
|
+
r"""
|
|
236
|
+
Return the `i`-th affine patch of this projective curve.
|
|
237
|
+
|
|
238
|
+
INPUT:
|
|
239
|
+
|
|
240
|
+
- ``i`` -- affine coordinate chart of the projective ambient space of
|
|
241
|
+
this curve to compute affine patch with respect to
|
|
242
|
+
|
|
243
|
+
- ``AA`` -- (default: ``None``) ambient affine space, this is constructed
|
|
244
|
+
if it is not given
|
|
245
|
+
|
|
246
|
+
OUTPUT: a curve in affine space
|
|
247
|
+
|
|
248
|
+
EXAMPLES::
|
|
249
|
+
|
|
250
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(CC, 3)
|
|
251
|
+
sage: C = Curve([y*z - x^2, w^2 - x*y], P)
|
|
252
|
+
sage: C.affine_patch(0)
|
|
253
|
+
Affine Curve over Complex Field with 53 bits of precision defined
|
|
254
|
+
by y*z - 1.00000000000000, w^2 - y
|
|
255
|
+
|
|
256
|
+
::
|
|
257
|
+
|
|
258
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
259
|
+
sage: C = Curve(x^3 - x^2*y + y^3 - x^2*z, P)
|
|
260
|
+
sage: C.affine_patch(1)
|
|
261
|
+
Affine Plane Curve over Rational Field defined by x^3 - x^2*z - x^2 + 1
|
|
262
|
+
|
|
263
|
+
::
|
|
264
|
+
|
|
265
|
+
sage: A.<x,y> = AffineSpace(QQ, 2)
|
|
266
|
+
sage: P.<u,v,w> = ProjectiveSpace(QQ, 2)
|
|
267
|
+
sage: C = Curve([u^2 - v^2], P)
|
|
268
|
+
sage: C.affine_patch(1, A).ambient_space() == A
|
|
269
|
+
True
|
|
270
|
+
"""
|
|
271
|
+
from .constructor import Curve
|
|
272
|
+
return Curve(AlgebraicScheme_subscheme_projective.affine_patch(self, i, AA))
|
|
273
|
+
|
|
274
|
+
def projection(self, P=None, PS=None):
|
|
275
|
+
r"""
|
|
276
|
+
Return a projection of this curve into projective space of dimension
|
|
277
|
+
one less than the dimension of the ambient space of this curve.
|
|
278
|
+
|
|
279
|
+
This curve must not already be a plane curve. Over finite fields, if
|
|
280
|
+
this curve contains all points in its ambient space, then an error will
|
|
281
|
+
be returned.
|
|
282
|
+
|
|
283
|
+
INPUT:
|
|
284
|
+
|
|
285
|
+
- ``P`` -- (default: ``None``) a point not on this curve that will be used
|
|
286
|
+
to define the projection map; this is constructed if not specified
|
|
287
|
+
|
|
288
|
+
- ``PS`` -- (default: ``None``) the projective space the projected curve
|
|
289
|
+
will be defined in. This space must be defined over the same base ring
|
|
290
|
+
as this curve, and must have dimension one less than that of the
|
|
291
|
+
ambient space of this curve. This space will be constructed if not
|
|
292
|
+
specified.
|
|
293
|
+
|
|
294
|
+
OUTPUT: a tuple of
|
|
295
|
+
|
|
296
|
+
- a scheme morphism from this curve into a projective space of
|
|
297
|
+
dimension one less than that of the ambient space of this curve
|
|
298
|
+
|
|
299
|
+
- the projective curve that is the image of that morphism
|
|
300
|
+
|
|
301
|
+
EXAMPLES::
|
|
302
|
+
|
|
303
|
+
sage: # needs sage.rings.number_field
|
|
304
|
+
sage: K.<a> = CyclotomicField(3)
|
|
305
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(K, 3)
|
|
306
|
+
sage: C = Curve([y*w - x^2, z*w^2 - a*x^3], P)
|
|
307
|
+
sage: L.<a,b,c> = ProjectiveSpace(K, 2)
|
|
308
|
+
sage: proj1 = C.projection(PS=L)
|
|
309
|
+
sage: proj1
|
|
310
|
+
(Scheme morphism:
|
|
311
|
+
From: Projective Curve over Cyclotomic Field of order 3 and degree 2
|
|
312
|
+
defined by -x^2 + y*w, (-a)*x^3 + z*w^2
|
|
313
|
+
To: Projective Space of dimension 2
|
|
314
|
+
over Cyclotomic Field of order 3 and degree 2
|
|
315
|
+
Defn: Defined on coordinates by sending (x : y : z : w) to
|
|
316
|
+
(x : y : -z + w),
|
|
317
|
+
Projective Plane Curve over Cyclotomic Field of order 3 and degree 2
|
|
318
|
+
defined by a^6 + (-a)*a^3*b^3 - a^4*b*c)
|
|
319
|
+
sage: proj1[1].ambient_space() is L
|
|
320
|
+
True
|
|
321
|
+
sage: proj2 = C.projection()
|
|
322
|
+
sage: proj2[1].ambient_space() is L
|
|
323
|
+
False
|
|
324
|
+
|
|
325
|
+
::
|
|
326
|
+
|
|
327
|
+
sage: P.<x,y,z,w,a,b,c> = ProjectiveSpace(QQ, 6)
|
|
328
|
+
sage: C = Curve([y - x, z - a - b, w^2 - c^2, z - x - a, x^2 - w*z], P)
|
|
329
|
+
sage: C.projection()
|
|
330
|
+
(Scheme morphism:
|
|
331
|
+
From: Projective Curve over Rational Field
|
|
332
|
+
defined by -x + y, z - a - b, w^2 - c^2, -x + z - a, x^2 - z*w
|
|
333
|
+
To: Projective Space of dimension 5 over Rational Field
|
|
334
|
+
Defn: Defined on coordinates by sending (x : y : z : w : a : b : c)
|
|
335
|
+
to (x : y : -z + w : a : b : c),
|
|
336
|
+
Projective Curve over Rational Field defined by x1 - x4, x0 - x4, x2*x3
|
|
337
|
+
+ x3^2 + x2*x4 + 2*x3*x4, x2^2 - x3^2 - 2*x3*x4 + x4^2 - x5^2, x2*x4^2 +
|
|
338
|
+
x3*x4^2 + x4^3 - x3*x5^2 - x4*x5^2, x4^4 - x3^2*x5^2 - 2*x3*x4*x5^2 -
|
|
339
|
+
x4^2*x5^2)
|
|
340
|
+
|
|
341
|
+
::
|
|
342
|
+
|
|
343
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(GF(2), 3)
|
|
344
|
+
sage: C = P.curve([(x - y)*(x - z)*(x - w)*(y - z)*(y - w),
|
|
345
|
+
....: x*y*z*w*(x + y + z + w)])
|
|
346
|
+
sage: C.projection()
|
|
347
|
+
Traceback (most recent call last):
|
|
348
|
+
...
|
|
349
|
+
NotImplementedError: this curve contains all points of its ambient space
|
|
350
|
+
|
|
351
|
+
::
|
|
352
|
+
|
|
353
|
+
sage: P.<x,y,z,w,u> = ProjectiveSpace(GF(7), 4)
|
|
354
|
+
sage: C = P.curve([x^3 - y*z*u, w^2 - u^2 + 2*x*z, 3*x*w - y^2])
|
|
355
|
+
sage: L.<a,b,c,d> = ProjectiveSpace(GF(7), 3)
|
|
356
|
+
sage: C.projection(PS=L)
|
|
357
|
+
(Scheme morphism:
|
|
358
|
+
From: Projective Curve over Finite Field of size 7
|
|
359
|
+
defined by x^3 - y*z*u, 2*x*z + w^2 - u^2, -y^2 + 3*x*w
|
|
360
|
+
To: Projective Space of dimension 3 over Finite Field of size 7
|
|
361
|
+
Defn: Defined on coordinates by sending (x : y : z : w : u) to
|
|
362
|
+
(x : y : z : w),
|
|
363
|
+
Projective Curve over Finite Field of size 7 defined by b^2 - 3*a*d,
|
|
364
|
+
a^5*b + a*b*c^3*d - 3*b*c^2*d^3, a^6 + a^2*c^3*d - 3*a*c^2*d^3)
|
|
365
|
+
sage: Q.<a,b,c> = ProjectiveSpace(GF(7), 2)
|
|
366
|
+
sage: C.projection(PS=Q)
|
|
367
|
+
Traceback (most recent call last):
|
|
368
|
+
...
|
|
369
|
+
TypeError: (=Projective Space of dimension 2 over Finite Field of
|
|
370
|
+
size 7) must have dimension (=3)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
::
|
|
374
|
+
|
|
375
|
+
sage: PP.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
376
|
+
sage: C = PP.curve([x^3 - z^2*y, w^2 - z*x])
|
|
377
|
+
sage: Q = PP([1,0,1,1])
|
|
378
|
+
sage: C.projection(P=Q)
|
|
379
|
+
(Scheme morphism:
|
|
380
|
+
From: Projective Curve over Rational Field
|
|
381
|
+
defined by x^3 - y*z^2, -x*z + w^2
|
|
382
|
+
To: Projective Space of dimension 2 over Rational Field
|
|
383
|
+
Defn: Defined on coordinates by sending (x : y : z : w) to
|
|
384
|
+
(y : -x + z : -x + w),
|
|
385
|
+
Projective Plane Curve over Rational Field defined by x0*x1^5 -
|
|
386
|
+
6*x0*x1^4*x2 + 14*x0*x1^3*x2^2 - 16*x0*x1^2*x2^3 + 9*x0*x1*x2^4 -
|
|
387
|
+
2*x0*x2^5 - x2^6)
|
|
388
|
+
sage: LL.<a,b,c> = ProjectiveSpace(QQ, 2)
|
|
389
|
+
sage: Q = PP([0,0,0,1])
|
|
390
|
+
sage: C.projection(PS=LL, P=Q)
|
|
391
|
+
(Scheme morphism:
|
|
392
|
+
From: Projective Curve over Rational Field
|
|
393
|
+
defined by x^3 - y*z^2, -x*z + w^2
|
|
394
|
+
To: Projective Space of dimension 2 over Rational Field
|
|
395
|
+
Defn: Defined on coordinates by sending (x : y : z : w) to
|
|
396
|
+
(x : y : z),
|
|
397
|
+
Projective Plane Curve over Rational Field defined by a^3 - b*c^2)
|
|
398
|
+
sage: Q = PP([0,0,1,0])
|
|
399
|
+
sage: C.projection(P=Q)
|
|
400
|
+
Traceback (most recent call last):
|
|
401
|
+
...
|
|
402
|
+
TypeError: (=(0 : 0 : 1 : 0)) must be a point not on this curve
|
|
403
|
+
|
|
404
|
+
::
|
|
405
|
+
|
|
406
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
407
|
+
sage: C = P.curve(y^2 - x^2 + z^2)
|
|
408
|
+
sage: C.projection()
|
|
409
|
+
Traceback (most recent call last):
|
|
410
|
+
...
|
|
411
|
+
TypeError: this curve is already a plane curve
|
|
412
|
+
"""
|
|
413
|
+
PP = self.ambient_space()
|
|
414
|
+
n = PP.dimension_relative()
|
|
415
|
+
if n == 2:
|
|
416
|
+
raise TypeError("this curve is already a plane curve")
|
|
417
|
+
if self.base_ring() not in Fields():
|
|
418
|
+
raise TypeError("this curve must be defined over a field")
|
|
419
|
+
if PS is not None:
|
|
420
|
+
if not isinstance(PS, ProjectiveSpace_ring):
|
|
421
|
+
raise TypeError("(=%s) must be a projective space" % PS)
|
|
422
|
+
if PS.dimension_relative() != n - 1:
|
|
423
|
+
raise TypeError("(=%s) must have dimension (=%s)" % (PS, n - 1))
|
|
424
|
+
if PS.base_ring() != PP.base_ring():
|
|
425
|
+
raise TypeError("(=%s) must be defined over the same base field as this curve" % PS)
|
|
426
|
+
if P is None:
|
|
427
|
+
# find a point not on the curve if not given
|
|
428
|
+
if self.base_ring().characteristic() == 0:
|
|
429
|
+
# when working over a characteristic 0 field, we can construct a point not on the curve.
|
|
430
|
+
# we do this by constructing a point on which at least one nonzero element of the defining ideal of
|
|
431
|
+
# this curve does not vanish
|
|
432
|
+
F = 0
|
|
433
|
+
# find a nonzero element
|
|
434
|
+
for i in range(len(self.defining_polynomials())):
|
|
435
|
+
if self.defining_polynomials()[i] != 0:
|
|
436
|
+
F = self.defining_polynomials()[i]
|
|
437
|
+
# find a point on which it doesn't vanish
|
|
438
|
+
l = list(PP.gens())
|
|
439
|
+
for i in range(n + 1):
|
|
440
|
+
l[i] = 0
|
|
441
|
+
while F(l) == 0:
|
|
442
|
+
l[i] += 1
|
|
443
|
+
Q = PP(l) # will be a point not on the curve
|
|
444
|
+
else:
|
|
445
|
+
# if the base ring is a finite field, iterate over all points in the ambient space and check which
|
|
446
|
+
# are on this curve
|
|
447
|
+
Q = None
|
|
448
|
+
for P in PP.rational_points():
|
|
449
|
+
try:
|
|
450
|
+
self(P)
|
|
451
|
+
except TypeError:
|
|
452
|
+
Q = P
|
|
453
|
+
break
|
|
454
|
+
if Q is None:
|
|
455
|
+
raise NotImplementedError("this curve contains all points of its ambient space")
|
|
456
|
+
else:
|
|
457
|
+
# make sure the given point is in the ambient space of the curve, but not on the curve
|
|
458
|
+
Q = None
|
|
459
|
+
try:
|
|
460
|
+
Q = self(P)
|
|
461
|
+
except TypeError:
|
|
462
|
+
pass
|
|
463
|
+
if Q is not None:
|
|
464
|
+
raise TypeError("(=%s) must be a point not on this curve" % P)
|
|
465
|
+
try:
|
|
466
|
+
Q = self.ambient_space()(P)
|
|
467
|
+
except TypeError:
|
|
468
|
+
raise TypeError("(=%s) must be a point in the ambient space of this curve" % P)
|
|
469
|
+
# in order to create the change of coordinates map, need to find a coordinate of Q that is nonzero
|
|
470
|
+
j = 0
|
|
471
|
+
while Q[j] == 0:
|
|
472
|
+
j = j + 1
|
|
473
|
+
# use this Q to project. Apply a change of coordinates to move Q to (0:...:0:1:0:...:0)
|
|
474
|
+
# where 1 is in the jth coordinate
|
|
475
|
+
if PS is None:
|
|
476
|
+
PP2 = ProjectiveSpace(self.base_ring(), n - 1)
|
|
477
|
+
else:
|
|
478
|
+
PP2 = PS
|
|
479
|
+
H = Hom(self, PP2)
|
|
480
|
+
coords = [PP.gens()[i] - Q[i]/Q[j]*PP.gens()[j] for i in range(n + 1)]
|
|
481
|
+
coords.pop(j)
|
|
482
|
+
psi = H(coords)
|
|
483
|
+
# compute image of psi via elimination
|
|
484
|
+
# first construct the image of this curve by the change of coordinates. This can be found by composing the
|
|
485
|
+
# defining polynomials of this curve with the polynomials defining the inverse of the change of coordinates
|
|
486
|
+
invcoords = [Q[i]*PP.gens()[j] + PP.gens()[i] for i in range(n + 1)]
|
|
487
|
+
invcoords[j] = Q[j]*PP.gens()[j]
|
|
488
|
+
id = PP.coordinate_ring().ideal([f(invcoords) for f in self.defining_polynomials()])
|
|
489
|
+
J = id.elimination_ideal(PP.gens()[j])
|
|
490
|
+
K = Hom(PP.coordinate_ring(), PP2.coordinate_ring())
|
|
491
|
+
ll = list(PP2.gens())
|
|
492
|
+
ll.insert(j, 0)
|
|
493
|
+
phi = K(ll)
|
|
494
|
+
G = [phi(f) for f in J.gens()]
|
|
495
|
+
C = PP2.curve(G)
|
|
496
|
+
return (psi, C)
|
|
497
|
+
|
|
498
|
+
def plane_projection(self, PP=None):
|
|
499
|
+
r"""
|
|
500
|
+
Return a projection of this curve into a projective plane.
|
|
501
|
+
|
|
502
|
+
INPUT:
|
|
503
|
+
|
|
504
|
+
- ``PP`` -- (default: ``None``) the projective plane the projected curve
|
|
505
|
+
will be defined in. This space must be defined over the same base field
|
|
506
|
+
as this curve, and must have dimension two. This space is constructed
|
|
507
|
+
if not specified.
|
|
508
|
+
|
|
509
|
+
OUTPUT: a tuple of
|
|
510
|
+
|
|
511
|
+
- a scheme morphism from this curve into a projective plane
|
|
512
|
+
|
|
513
|
+
- the projective curve that is the image of that morphism
|
|
514
|
+
|
|
515
|
+
EXAMPLES::
|
|
516
|
+
|
|
517
|
+
sage: P.<x,y,z,w,u,v> = ProjectiveSpace(QQ, 5)
|
|
518
|
+
sage: C = P.curve([x*u - z*v, w - y, w*y - x^2, y^3*u*2*z - w^4*w])
|
|
519
|
+
sage: L.<a,b,c> = ProjectiveSpace(QQ, 2)
|
|
520
|
+
sage: proj1 = C.plane_projection(PP=L)
|
|
521
|
+
sage: proj1
|
|
522
|
+
(Scheme morphism:
|
|
523
|
+
From: Projective Curve over Rational Field
|
|
524
|
+
defined by x*u - z*v, -y + w, -x^2 + y*w, -w^5 + 2*y^3*z*u
|
|
525
|
+
To: Projective Space of dimension 2 over Rational Field
|
|
526
|
+
Defn: Defined on coordinates by sending (x : y : z : w : u : v) to
|
|
527
|
+
(x : -z + u : -z + v),
|
|
528
|
+
Projective Plane Curve over Rational Field defined by a^8 + 6*a^7*b +
|
|
529
|
+
4*a^5*b^3 - 4*a^7*c - 2*a^6*b*c - 4*a^5*b^2*c + 2*a^6*c^2)
|
|
530
|
+
sage: proj1[1].ambient_space() is L
|
|
531
|
+
True
|
|
532
|
+
sage: proj2 = C.projection()
|
|
533
|
+
sage: proj2[1].ambient_space() is L
|
|
534
|
+
False
|
|
535
|
+
|
|
536
|
+
::
|
|
537
|
+
|
|
538
|
+
sage: P.<x,y,z,w,u> = ProjectiveSpace(GF(7), 4)
|
|
539
|
+
sage: C = P.curve([x^2 - 6*y^2, w*z*u - y^3 + 4*y^2*z, u^2 - x^2])
|
|
540
|
+
sage: C.plane_projection()
|
|
541
|
+
(Scheme morphism:
|
|
542
|
+
From: Projective Curve over Finite Field of size 7
|
|
543
|
+
defined by x^2 + y^2, -y^3 - 3*y^2*z + z*w*u, -x^2 + u^2
|
|
544
|
+
To: Projective Space of dimension 2 over Finite Field of size 7
|
|
545
|
+
Defn: Defined on coordinates by sending (x : y : z : w : u) to
|
|
546
|
+
(x : z : -y + w),
|
|
547
|
+
Projective Plane Curve over Finite Field of size 7
|
|
548
|
+
defined by x0^10 + 2*x0^8*x1^2 + 2*x0^6*x1^4 - 3*x0^6*x1^3*x2
|
|
549
|
+
+ 2*x0^6*x1^2*x2^2 - 2*x0^4*x1^4*x2^2 + x0^2*x1^4*x2^4)
|
|
550
|
+
|
|
551
|
+
::
|
|
552
|
+
|
|
553
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(17), 2)
|
|
554
|
+
sage: C = P.curve(x^2 - y*z - z^2)
|
|
555
|
+
sage: C.plane_projection()
|
|
556
|
+
Traceback (most recent call last):
|
|
557
|
+
...
|
|
558
|
+
TypeError: this curve is already a plane curve
|
|
559
|
+
"""
|
|
560
|
+
PS = self.ambient_space()
|
|
561
|
+
n = PS.dimension_relative()
|
|
562
|
+
if n == 2:
|
|
563
|
+
raise TypeError("this curve is already a plane curve")
|
|
564
|
+
C = self
|
|
565
|
+
H = Hom(PS, PS)
|
|
566
|
+
phi = H([PS.gens()[i] for i in range(n + 1)])
|
|
567
|
+
for i in range(n - 2):
|
|
568
|
+
if i == n - 3:
|
|
569
|
+
L = C.projection(PS=PP)
|
|
570
|
+
else:
|
|
571
|
+
L = C.projection()
|
|
572
|
+
C = L[1]
|
|
573
|
+
# compose the scheme morphisms that are created
|
|
574
|
+
K = Hom(phi.codomain().coordinate_ring(), PS.coordinate_ring())
|
|
575
|
+
psi = K(phi.defining_polynomials())
|
|
576
|
+
H = Hom(self, L[1].ambient_space())
|
|
577
|
+
phi = H([psi(L[0].defining_polynomials()[i]) for i in range(len(L[0].defining_polynomials()))])
|
|
578
|
+
return (phi, C)
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
class ProjectivePlaneCurve(ProjectiveCurve):
|
|
582
|
+
r"""
|
|
583
|
+
Curves in projective planes.
|
|
584
|
+
|
|
585
|
+
INPUT:
|
|
586
|
+
|
|
587
|
+
- ``A`` -- projective plane
|
|
588
|
+
|
|
589
|
+
- ``f`` -- homogeneous polynomial in the homogeneous coordinate ring of the plane
|
|
590
|
+
|
|
591
|
+
EXAMPLES:
|
|
592
|
+
|
|
593
|
+
A projective plane curve defined over an algebraic closure of `\QQ`::
|
|
594
|
+
|
|
595
|
+
sage: # needs sage.rings.number_field
|
|
596
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2)
|
|
597
|
+
sage: set_verbose(-1) # suppress warnings for slow computation
|
|
598
|
+
sage: C = Curve([y*z - x^2 - QQbar.gen()*z^2], P); C
|
|
599
|
+
Projective Plane Curve over Algebraic Field
|
|
600
|
+
defined by -x^2 + y*z + (-I)*z^2
|
|
601
|
+
|
|
602
|
+
A projective plane curve defined over a finite field::
|
|
603
|
+
|
|
604
|
+
sage: # needs sage.rings.finite_rings
|
|
605
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5^2, 'v'), 2)
|
|
606
|
+
sage: C = Curve([y^2*z - x*z^2 - z^3], P); C
|
|
607
|
+
Projective Plane Curve over Finite Field in v of size 5^2
|
|
608
|
+
defined by y^2*z - x*z^2 - z^3
|
|
609
|
+
"""
|
|
610
|
+
|
|
611
|
+
def __init__(self, A, f, category=None):
|
|
612
|
+
"""
|
|
613
|
+
Initialize.
|
|
614
|
+
|
|
615
|
+
EXAMPLES::
|
|
616
|
+
|
|
617
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
618
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
619
|
+
sage: loads(dumps(C)) == C
|
|
620
|
+
True
|
|
621
|
+
"""
|
|
622
|
+
if not (isinstance(A, ProjectiveSpace_ring) and A.dimension != 2):
|
|
623
|
+
raise TypeError("the ambient space is not a projective plane")
|
|
624
|
+
|
|
625
|
+
super().__init__(A, [f], category=category)
|
|
626
|
+
|
|
627
|
+
def _repr_type(self):
|
|
628
|
+
r"""
|
|
629
|
+
Return a string representation of the type of this curve.
|
|
630
|
+
|
|
631
|
+
EXAMPLES::
|
|
632
|
+
|
|
633
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
634
|
+
sage: C = Curve([y*z^3 - 5/7*x^4 + 4*x^3*z - 9*z^4], P)
|
|
635
|
+
sage: C._repr_type()
|
|
636
|
+
'Projective Plane'
|
|
637
|
+
"""
|
|
638
|
+
return "Projective Plane"
|
|
639
|
+
|
|
640
|
+
def divisor_of_function(self, r):
|
|
641
|
+
"""
|
|
642
|
+
Return the divisor of a function on a curve.
|
|
643
|
+
|
|
644
|
+
INPUT:
|
|
645
|
+
|
|
646
|
+
- ``r`` is a rational function on X
|
|
647
|
+
|
|
648
|
+
OUTPUT: list; the divisor of r represented as a list of coefficients
|
|
649
|
+
and points. (TODO: This will change to a more structural output in the
|
|
650
|
+
future.)
|
|
651
|
+
|
|
652
|
+
EXAMPLES::
|
|
653
|
+
|
|
654
|
+
sage: FF = FiniteField(5)
|
|
655
|
+
sage: P2 = ProjectiveSpace(2, FF, names=['x','y','z'])
|
|
656
|
+
sage: R = P2.coordinate_ring()
|
|
657
|
+
sage: x, y, z = R.gens()
|
|
658
|
+
sage: f = y^2*z^7 - x^9 - x*z^8
|
|
659
|
+
sage: C = Curve(f)
|
|
660
|
+
sage: K = FractionField(R)
|
|
661
|
+
sage: r = 1/x
|
|
662
|
+
sage: C.divisor_of_function(r) # todo: not implemented !!!!
|
|
663
|
+
[[-1, (0, 0, 1)]]
|
|
664
|
+
sage: r = 1/x^3
|
|
665
|
+
sage: C.divisor_of_function(r) # todo: not implemented !!!!
|
|
666
|
+
[[-3, (0, 0, 1)]]
|
|
667
|
+
"""
|
|
668
|
+
F = self.base_ring()
|
|
669
|
+
f = self.defining_polynomial()
|
|
670
|
+
x, y, z = f.parent().gens()
|
|
671
|
+
pnts = self.rational_points()
|
|
672
|
+
divf = []
|
|
673
|
+
for P in pnts:
|
|
674
|
+
if P[2] != F(0):
|
|
675
|
+
# What is the '5' in this line and the 'r()' in the next???
|
|
676
|
+
lcs = self.local_coordinates(P, 5)
|
|
677
|
+
ldg = degree_lowest_rational_function(r(lcs[0], lcs[1]), z)
|
|
678
|
+
if ldg != 0:
|
|
679
|
+
divf.append([ldg, P])
|
|
680
|
+
return divf
|
|
681
|
+
|
|
682
|
+
def local_coordinates(self, pt, n):
|
|
683
|
+
r"""
|
|
684
|
+
Return local coordinates to precision n at the given point.
|
|
685
|
+
|
|
686
|
+
Behaviour is flaky - some choices of `n` are worse than
|
|
687
|
+
others.
|
|
688
|
+
|
|
689
|
+
INPUT:
|
|
690
|
+
|
|
691
|
+
- ``pt`` -- a rational point on X which is not a point of ramification
|
|
692
|
+
for the projection `(x,y) \to x`
|
|
693
|
+
|
|
694
|
+
- ``n`` -- the number of terms desired
|
|
695
|
+
|
|
696
|
+
OUTPUT: `x = x0 + t`, `y = y0` + power series in `t`
|
|
697
|
+
|
|
698
|
+
EXAMPLES::
|
|
699
|
+
|
|
700
|
+
sage: FF = FiniteField(5)
|
|
701
|
+
sage: P2 = ProjectiveSpace(2, FF, names=['x','y','z'])
|
|
702
|
+
sage: x, y, z = P2.coordinate_ring().gens()
|
|
703
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
704
|
+
sage: pt = C([2,3,1])
|
|
705
|
+
sage: C.local_coordinates(pt,9) # todo: not implemented !!!!
|
|
706
|
+
[2 + t,
|
|
707
|
+
3 + 3*t^2 + t^3 + 3*t^4 + 3*t^6 + 3*t^7 + t^8 + 2*t^9 + 3*t^11 + 3*t^12]
|
|
708
|
+
"""
|
|
709
|
+
|
|
710
|
+
f = self.defining_polynomial()
|
|
711
|
+
R = f.parent()
|
|
712
|
+
F = self.base_ring()
|
|
713
|
+
p = F.characteristic()
|
|
714
|
+
x0 = F(pt[0])
|
|
715
|
+
y0 = F(pt[1])
|
|
716
|
+
astr = ["a"+str(i) for i in range(1, 2*n)]
|
|
717
|
+
x, y = R.gens()
|
|
718
|
+
R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr)
|
|
719
|
+
vars0 = R0.gens()
|
|
720
|
+
t = vars0[2]
|
|
721
|
+
yt = y0*t**0 + add([vars0[i]*t**(i-2) for i in range(3, 2*n+2)])
|
|
722
|
+
xt = x0+t
|
|
723
|
+
ft = f(xt, yt)
|
|
724
|
+
S = singular
|
|
725
|
+
S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;')
|
|
726
|
+
S.eval('poly f = '+str(ft))
|
|
727
|
+
cmd = 'matrix c = coeffs ('+str(ft)+',t)'
|
|
728
|
+
S.eval(cmd)
|
|
729
|
+
N = int(S.eval('size(c)'))
|
|
730
|
+
b = ','.join("c[{},1]".format(i) for i in range(2, N//2 - 4))
|
|
731
|
+
cmd = 'ideal I = ' + b
|
|
732
|
+
S.eval(cmd)
|
|
733
|
+
c = S.eval('slimgb(I)')
|
|
734
|
+
d = c.split("=")
|
|
735
|
+
d = d[1:]
|
|
736
|
+
d[len(d)-1] += "\n"
|
|
737
|
+
e = [xx[:xx.index("\n")] for xx in d]
|
|
738
|
+
vals = []
|
|
739
|
+
for x in e:
|
|
740
|
+
for y in vars0:
|
|
741
|
+
if str(y) in x:
|
|
742
|
+
if x.replace(str(y), ""):
|
|
743
|
+
i = x.find("-")
|
|
744
|
+
if i > 0:
|
|
745
|
+
vals.append([eval(x[1:i]), x[:i], F(eval(x[i+1:]))])
|
|
746
|
+
i = x.find("+")
|
|
747
|
+
if i > 0:
|
|
748
|
+
vals.append([eval(x[1:i]), x[:i], -F(eval(x[i+1:]))])
|
|
749
|
+
else:
|
|
750
|
+
vals.append([eval(str(y)[1:]), str(y), F(0)])
|
|
751
|
+
vals.sort()
|
|
752
|
+
return [x0 + t, y0 + add(v[2] * t**(j + 1) for j, v in enumerate(vals))]
|
|
753
|
+
|
|
754
|
+
def plot(self, *args, **kwds):
|
|
755
|
+
"""
|
|
756
|
+
Plot the real points of an affine patch of this projective
|
|
757
|
+
plane curve.
|
|
758
|
+
|
|
759
|
+
INPUT:
|
|
760
|
+
|
|
761
|
+
- ``self`` -- an affine plane curve
|
|
762
|
+
|
|
763
|
+
- ``patch`` -- (optional) the affine patch to be plotted; if not
|
|
764
|
+
specified, the patch corresponding to the last projective
|
|
765
|
+
coordinate being nonzero
|
|
766
|
+
|
|
767
|
+
- ``*args`` -- (optional) tuples (variable, minimum, maximum) for
|
|
768
|
+
plotting dimensions
|
|
769
|
+
|
|
770
|
+
- ``**kwds`` -- optional keyword arguments passed on to ``implicit_plot``
|
|
771
|
+
|
|
772
|
+
EXAMPLES:
|
|
773
|
+
|
|
774
|
+
A cuspidal curve::
|
|
775
|
+
|
|
776
|
+
sage: R.<x, y, z> = QQ[]
|
|
777
|
+
sage: C = Curve(x^3 - y^2*z)
|
|
778
|
+
sage: C.plot() # needs sage.plot
|
|
779
|
+
Graphics object consisting of 1 graphics primitive
|
|
780
|
+
|
|
781
|
+
The other affine patches of the same curve::
|
|
782
|
+
|
|
783
|
+
sage: # needs sage.plot
|
|
784
|
+
sage: C.plot(patch=0)
|
|
785
|
+
Graphics object consisting of 1 graphics primitive
|
|
786
|
+
sage: C.plot(patch=1)
|
|
787
|
+
Graphics object consisting of 1 graphics primitive
|
|
788
|
+
|
|
789
|
+
An elliptic curve::
|
|
790
|
+
|
|
791
|
+
sage: # needs sage.plot
|
|
792
|
+
sage: E = EllipticCurve('101a')
|
|
793
|
+
sage: C = Curve(E)
|
|
794
|
+
sage: C.plot()
|
|
795
|
+
Graphics object consisting of 1 graphics primitive
|
|
796
|
+
sage: C.plot(patch=0)
|
|
797
|
+
Graphics object consisting of 1 graphics primitive
|
|
798
|
+
sage: C.plot(patch=1)
|
|
799
|
+
Graphics object consisting of 1 graphics primitive
|
|
800
|
+
|
|
801
|
+
A hyperelliptic curve::
|
|
802
|
+
|
|
803
|
+
sage: # needs sage.plot
|
|
804
|
+
sage: P.<x> = QQ[]
|
|
805
|
+
sage: f = 4*x^5 - 30*x^3 + 45*x - 22
|
|
806
|
+
sage: C = HyperellipticCurve(f)
|
|
807
|
+
sage: C.plot()
|
|
808
|
+
Graphics object consisting of 1 graphics primitive
|
|
809
|
+
sage: C.plot(patch=0)
|
|
810
|
+
Graphics object consisting of 1 graphics primitive
|
|
811
|
+
sage: C.plot(patch=1)
|
|
812
|
+
Graphics object consisting of 1 graphics primitive
|
|
813
|
+
"""
|
|
814
|
+
# if user has not specified a favorite affine patch, take the
|
|
815
|
+
# one avoiding "infinity", i.e. the one corresponding to the
|
|
816
|
+
# last projective coordinate being nonzero
|
|
817
|
+
patch = kwds.pop('patch', self.ngens() - 1)
|
|
818
|
+
from .constructor import Curve
|
|
819
|
+
C = Curve(self.affine_patch(patch))
|
|
820
|
+
return C.plot(*args, **kwds)
|
|
821
|
+
|
|
822
|
+
def is_singular(self, P=None):
|
|
823
|
+
r"""
|
|
824
|
+
Return whether this curve is singular or not, or if a point ``P`` is
|
|
825
|
+
provided, whether ``P`` is a singular point of this curve.
|
|
826
|
+
|
|
827
|
+
INPUT:
|
|
828
|
+
|
|
829
|
+
- ``P`` -- (default: ``None``) a point on this curve
|
|
830
|
+
|
|
831
|
+
OUTPUT:
|
|
832
|
+
|
|
833
|
+
If no point ``P`` is provided, return ``True`` or ``False`` depending
|
|
834
|
+
on whether this curve is singular or not. If a point ``P`` is provided,
|
|
835
|
+
return ``True`` or ``False`` depending on whether ``P`` is or is not a
|
|
836
|
+
singular point of this curve.
|
|
837
|
+
|
|
838
|
+
EXAMPLES:
|
|
839
|
+
|
|
840
|
+
Over `\QQ`::
|
|
841
|
+
|
|
842
|
+
sage: F = QQ
|
|
843
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
844
|
+
sage: C = Curve(X^3 - Y^2*Z)
|
|
845
|
+
sage: C.is_singular()
|
|
846
|
+
True
|
|
847
|
+
|
|
848
|
+
Over a finite field::
|
|
849
|
+
|
|
850
|
+
sage: F = GF(19)
|
|
851
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
852
|
+
sage: C = Curve(X^3 + Y^3 + Z^3)
|
|
853
|
+
sage: C.is_singular()
|
|
854
|
+
False
|
|
855
|
+
sage: D = Curve(X^4 - X*Z^3)
|
|
856
|
+
sage: D.is_singular()
|
|
857
|
+
True
|
|
858
|
+
sage: E = Curve(X^5 + 19*Y^5 + Z^5)
|
|
859
|
+
sage: E.is_singular()
|
|
860
|
+
True
|
|
861
|
+
sage: E = Curve(X^5 + 9*Y^5 + Z^5)
|
|
862
|
+
sage: E.is_singular()
|
|
863
|
+
False
|
|
864
|
+
|
|
865
|
+
Over `\CC`::
|
|
866
|
+
|
|
867
|
+
sage: # needs sage.rings.function_field
|
|
868
|
+
sage: F = CC
|
|
869
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
870
|
+
sage: C = Curve(X)
|
|
871
|
+
sage: C.is_singular()
|
|
872
|
+
False
|
|
873
|
+
sage: D = Curve(Y^2*Z - X^3)
|
|
874
|
+
sage: D.is_singular()
|
|
875
|
+
True
|
|
876
|
+
sage: E = Curve(Y^2*Z - X^3 + Z^3)
|
|
877
|
+
sage: E.is_singular()
|
|
878
|
+
False
|
|
879
|
+
|
|
880
|
+
Showing that :issue:`12187` is fixed::
|
|
881
|
+
|
|
882
|
+
sage: F.<X,Y,Z> = GF(2)[]
|
|
883
|
+
sage: G = Curve(X^2 + Y*Z)
|
|
884
|
+
sage: G.is_singular()
|
|
885
|
+
False
|
|
886
|
+
|
|
887
|
+
::
|
|
888
|
+
|
|
889
|
+
sage: # needs sage.fings.function_field
|
|
890
|
+
sage: P.<x,y,z> = ProjectiveSpace(CC, 2)
|
|
891
|
+
sage: C = Curve([y^4 - x^3*z], P)
|
|
892
|
+
sage: Q = P([0,0,1])
|
|
893
|
+
sage: C.is_singular()
|
|
894
|
+
True
|
|
895
|
+
"""
|
|
896
|
+
if P is None:
|
|
897
|
+
poly = self.defining_polynomial()
|
|
898
|
+
return poly.parent().ideal(poly.gradient()+[poly]).dimension() > 0
|
|
899
|
+
else:
|
|
900
|
+
return not self.is_smooth(P)
|
|
901
|
+
|
|
902
|
+
def degree(self):
|
|
903
|
+
r"""
|
|
904
|
+
Return the degree of this projective curve.
|
|
905
|
+
|
|
906
|
+
For a plane curve, this is just the degree of its defining polynomial.
|
|
907
|
+
|
|
908
|
+
OUTPUT: integer
|
|
909
|
+
|
|
910
|
+
EXAMPLES::
|
|
911
|
+
|
|
912
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
913
|
+
sage: C = P.curve([y^7 - x^2*z^5 + 7*z^7])
|
|
914
|
+
sage: C.degree()
|
|
915
|
+
7
|
|
916
|
+
"""
|
|
917
|
+
return self.defining_polynomial().degree()
|
|
918
|
+
|
|
919
|
+
def tangents(self, P, factor=True):
|
|
920
|
+
r"""
|
|
921
|
+
Return the tangents of this projective plane curve at the point ``P``.
|
|
922
|
+
|
|
923
|
+
These are found by homogenizing the tangents of an affine patch of this
|
|
924
|
+
curve containing ``P``. The point ``P`` must be a point on this curve.
|
|
925
|
+
|
|
926
|
+
INPUT:
|
|
927
|
+
|
|
928
|
+
- ``P`` -- a point on this curve
|
|
929
|
+
|
|
930
|
+
- ``factor`` -- boolean (default: ``True``); whether to attempt computing the
|
|
931
|
+
polynomials of the individual tangent lines over the base field of this
|
|
932
|
+
curve, or to just return the polynomial corresponding to the union of
|
|
933
|
+
the tangent lines (which requires fewer computations)
|
|
934
|
+
|
|
935
|
+
OUTPUT:
|
|
936
|
+
|
|
937
|
+
A list of polynomials in the coordinate ring of the ambient space of
|
|
938
|
+
this curve.
|
|
939
|
+
|
|
940
|
+
EXAMPLES::
|
|
941
|
+
|
|
942
|
+
sage: # needs sage.rings.number_field
|
|
943
|
+
sage: set_verbose(-1)
|
|
944
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2)
|
|
945
|
+
sage: C = Curve([x^3*y + 2*x^2*y^2 + x*y^3 + x^3*z
|
|
946
|
+
....: + 7*x^2*y*z + 14*x*y^2*z + 9*y^3*z], P)
|
|
947
|
+
sage: Q = P([0,0,1])
|
|
948
|
+
sage: C.tangents(Q)
|
|
949
|
+
[x + 4.147899035704788?*y,
|
|
950
|
+
x + (1.426050482147607? + 0.3689894074818041?*I)*y,
|
|
951
|
+
x + (1.426050482147607? - 0.3689894074818041?*I)*y]
|
|
952
|
+
sage: C.tangents(Q, factor=False)
|
|
953
|
+
[6*x^3 + 42*x^2*y + 84*x*y^2 + 54*y^3]
|
|
954
|
+
|
|
955
|
+
::
|
|
956
|
+
|
|
957
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
958
|
+
sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3
|
|
959
|
+
....: + 3*y^7*z^2 + 10*x^2*y^5*z^2 + 9*x^4*y^3*z^2 + 5*x^6*y*z^2
|
|
960
|
+
....: - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z - 7*x^6*y^2*z
|
|
961
|
+
....: - 2*x^8*z + y^9 + 2*x^2*y^7 + 3*x^4*y^5 + 4*x^6*y^3 + 2*x^8*y])
|
|
962
|
+
sage: Q = P([0,1,1])
|
|
963
|
+
sage: C.tangents(Q)
|
|
964
|
+
[-y + z, 3*x^2 - y^2 + 2*y*z - z^2]
|
|
965
|
+
|
|
966
|
+
::
|
|
967
|
+
|
|
968
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
969
|
+
sage: C = P.curve([z^3*x + y^4 - x^2*z^2])
|
|
970
|
+
sage: Q = P([1,1,1])
|
|
971
|
+
sage: C.tangents(Q)
|
|
972
|
+
Traceback (most recent call last):
|
|
973
|
+
...
|
|
974
|
+
TypeError: (=(1 : 1 : 1)) is not a point on (=Projective Plane Curve
|
|
975
|
+
over Rational Field defined by y^4 - x^2*z^2 + x*z^3)
|
|
976
|
+
"""
|
|
977
|
+
PP = self.ambient_space()
|
|
978
|
+
# Check whether P is a point on this curve
|
|
979
|
+
try:
|
|
980
|
+
P = self(P)
|
|
981
|
+
except TypeError:
|
|
982
|
+
raise TypeError("(=%s) is not a point on (=%s)" % (P, self))
|
|
983
|
+
|
|
984
|
+
# Find an affine chart of the ambient space of self that contains P
|
|
985
|
+
i = 0
|
|
986
|
+
while P[i] == 0:
|
|
987
|
+
i += 1
|
|
988
|
+
C = self.affine_patch(i)
|
|
989
|
+
L = C.tangents(C(P.dehomogenize(i)), factor)
|
|
990
|
+
R = PP.coordinate_ring()
|
|
991
|
+
H = Hom(C.ambient_space().coordinate_ring(), R)
|
|
992
|
+
G = list(R.gens())
|
|
993
|
+
x = G.pop(i)
|
|
994
|
+
phi = H(G)
|
|
995
|
+
return [phi(g).homogenize(x) for g in L]
|
|
996
|
+
|
|
997
|
+
def is_ordinary_singularity(self, P):
|
|
998
|
+
r"""
|
|
999
|
+
Return whether the singular point ``P`` of this projective plane curve is an ordinary singularity.
|
|
1000
|
+
|
|
1001
|
+
The point ``P`` is an ordinary singularity of this curve if it is a singular point, and
|
|
1002
|
+
if the tangents of this curve at ``P`` are distinct.
|
|
1003
|
+
|
|
1004
|
+
INPUT:
|
|
1005
|
+
|
|
1006
|
+
- ``P`` -- a point on this curve
|
|
1007
|
+
|
|
1008
|
+
OUTPUT:
|
|
1009
|
+
|
|
1010
|
+
boolean; ``True`` or ``False`` depending on whether ``P`` is or is not
|
|
1011
|
+
an ordinary singularity of this curve, respectively. An error is raised
|
|
1012
|
+
if ``P`` is not a singular point of this curve.
|
|
1013
|
+
|
|
1014
|
+
EXAMPLES::
|
|
1015
|
+
|
|
1016
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1017
|
+
sage: C = Curve([y^2*z^3 - x^5], P)
|
|
1018
|
+
sage: Q = P([0,0,1])
|
|
1019
|
+
sage: C.is_ordinary_singularity(Q)
|
|
1020
|
+
False
|
|
1021
|
+
|
|
1022
|
+
::
|
|
1023
|
+
|
|
1024
|
+
sage: # needs sage.rings.number_field
|
|
1025
|
+
sage: R.<a> = QQ[]
|
|
1026
|
+
sage: K.<b> = NumberField(a^2 - 3)
|
|
1027
|
+
sage: P.<x,y,z> = ProjectiveSpace(K, 2)
|
|
1028
|
+
sage: C = P.curve([x^2*y^3*z^4 - y^6*z^3 - 4*x^2*y^4*z^3 - 4*x^4*y^2*z^3
|
|
1029
|
+
....: + 3*y^7*z^2 + 10*x^2*y^5*z^2 + 9*x^4*y^3*z^2
|
|
1030
|
+
....: + 5*x^6*y*z^2 - 3*y^8*z - 9*x^2*y^6*z - 11*x^4*y^4*z
|
|
1031
|
+
....: - 7*x^6*y^2*z - 2*x^8*z + y^9 + 2*x^2*y^7 + 3*x^4*y^5
|
|
1032
|
+
....: + 4*x^6*y^3 + 2*x^8*y])
|
|
1033
|
+
sage: Q = P([0,1,1])
|
|
1034
|
+
sage: C.is_ordinary_singularity(Q)
|
|
1035
|
+
True
|
|
1036
|
+
|
|
1037
|
+
::
|
|
1038
|
+
|
|
1039
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1040
|
+
sage: C = P.curve([z^5 - y^5 + x^5 + x*y^2*z^2])
|
|
1041
|
+
sage: Q = P([0,1,1])
|
|
1042
|
+
sage: C.is_ordinary_singularity(Q)
|
|
1043
|
+
Traceback (most recent call last):
|
|
1044
|
+
...
|
|
1045
|
+
TypeError: (=(0 : 1 : 1)) is not a singular point of (=Projective Plane
|
|
1046
|
+
Curve over Rational Field defined by x^5 - y^5 + x*y^2*z^2 + z^5)
|
|
1047
|
+
"""
|
|
1048
|
+
r = self.multiplicity(P)
|
|
1049
|
+
if r < 2:
|
|
1050
|
+
raise TypeError("(=%s) is not a singular point of (=%s)" % (P, self))
|
|
1051
|
+
|
|
1052
|
+
# Find an affine chart of the ambient space of self that contains P
|
|
1053
|
+
i = 0
|
|
1054
|
+
while P[i] == 0:
|
|
1055
|
+
i += 1
|
|
1056
|
+
C = self.affine_patch(i)
|
|
1057
|
+
return C.is_ordinary_singularity(C(P.dehomogenize(i)))
|
|
1058
|
+
|
|
1059
|
+
def quadratic_transform(self):
|
|
1060
|
+
r"""
|
|
1061
|
+
Return a birational map from this curve to the proper transform of this curve with respect to the standard
|
|
1062
|
+
Cremona transformation.
|
|
1063
|
+
|
|
1064
|
+
The standard Cremona transformation is the birational automorphism of `\mathbb{P}^{2}` defined
|
|
1065
|
+
`(x : y : z)\mapsto (yz : xz : xy)`.
|
|
1066
|
+
|
|
1067
|
+
OUTPUT:
|
|
1068
|
+
|
|
1069
|
+
- a scheme morphism representing the restriction of the standard Cremona transformation from this curve
|
|
1070
|
+
to the proper transform.
|
|
1071
|
+
|
|
1072
|
+
EXAMPLES::
|
|
1073
|
+
|
|
1074
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1075
|
+
sage: C = Curve(x^3*y - z^4 - z^2*x^2, P)
|
|
1076
|
+
sage: C.quadratic_transform()
|
|
1077
|
+
Scheme morphism:
|
|
1078
|
+
From: Projective Plane Curve over Rational Field
|
|
1079
|
+
defined by x^3*y - x^2*z^2 - z^4
|
|
1080
|
+
To: Projective Plane Curve over Rational Field
|
|
1081
|
+
defined by -x^3*y - x*y*z^2 + z^4
|
|
1082
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1083
|
+
(y*z : x*z : x*y)
|
|
1084
|
+
|
|
1085
|
+
::
|
|
1086
|
+
|
|
1087
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(17), 2)
|
|
1088
|
+
sage: C = P.curve([y^7*z^2 - 16*x^9 + x*y*z^7 + 2*z^9])
|
|
1089
|
+
sage: C.quadratic_transform()
|
|
1090
|
+
Scheme morphism:
|
|
1091
|
+
From: Projective Plane Curve over Finite Field of size 17
|
|
1092
|
+
defined by x^9 + y^7*z^2 + x*y*z^7 + 2*z^9
|
|
1093
|
+
To: Projective Plane Curve over Finite Field of size 17
|
|
1094
|
+
defined by 2*x^9*y^7 + x^8*y^6*z^2 + x^9*z^7 + y^7*z^9
|
|
1095
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1096
|
+
(y*z : x*z : x*y)
|
|
1097
|
+
"""
|
|
1098
|
+
PP = self.ambient_space()
|
|
1099
|
+
R = PP.coordinate_ring()
|
|
1100
|
+
L = R.gens()
|
|
1101
|
+
coords = [L[1]*L[2], L[0]*L[2], L[0]*L[1]]
|
|
1102
|
+
G = self.defining_polynomial()(coords)
|
|
1103
|
+
# remove the component of the curve corresponding to the exceptional divisor
|
|
1104
|
+
degs = [G.degree()]*len(L)
|
|
1105
|
+
for F in G.monomials():
|
|
1106
|
+
for i in range(len(L)):
|
|
1107
|
+
degs[i] = min(F.degree(L[i]), degs[i])
|
|
1108
|
+
T = []
|
|
1109
|
+
for item in G.monomial_coefficients().items():
|
|
1110
|
+
tup = tuple([item[0][i] - degs[i] for i in range(len(L))])
|
|
1111
|
+
T.append((tup, item[1]))
|
|
1112
|
+
G = R(dict(T))
|
|
1113
|
+
H = Hom(self, PP.curve(G))
|
|
1114
|
+
phi = H(coords)
|
|
1115
|
+
return phi
|
|
1116
|
+
|
|
1117
|
+
def excellent_position(self, Q):
|
|
1118
|
+
r"""
|
|
1119
|
+
Return a transformation of this curve into one in excellent position with respect to the point ``Q``.
|
|
1120
|
+
|
|
1121
|
+
Here excellent position is defined as in [Ful1989]_. A curve `C` of degree `d` containing the point
|
|
1122
|
+
`(0 : 0 : 1)` with multiplicity `r` is said to be in excellent position if none of the coordinate lines
|
|
1123
|
+
are tangent to `C` at any of the fundamental points `(1 : 0 : 0)`, `(0 : 1 : 0)`, and `(0 : 0 : 1)`, and
|
|
1124
|
+
if the two coordinate lines containing `(0 : 0 : 1)` intersect `C` transversally in `d - r` distinct
|
|
1125
|
+
non-fundamental points, and if the other coordinate line intersects `C` transversally at `d` distinct,
|
|
1126
|
+
non-fundamental points.
|
|
1127
|
+
|
|
1128
|
+
INPUT:
|
|
1129
|
+
|
|
1130
|
+
- ``Q`` -- a point on this curve
|
|
1131
|
+
|
|
1132
|
+
OUTPUT:
|
|
1133
|
+
|
|
1134
|
+
A scheme morphism from this curve to a curve in excellent position that
|
|
1135
|
+
is a restriction of a change of coordinates map of the projective plane.
|
|
1136
|
+
|
|
1137
|
+
EXAMPLES::
|
|
1138
|
+
|
|
1139
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1140
|
+
sage: C = Curve([x*y - z^2], P)
|
|
1141
|
+
sage: Q = P([1,1,1])
|
|
1142
|
+
sage: C.excellent_position(Q)
|
|
1143
|
+
Scheme morphism:
|
|
1144
|
+
From: Projective Plane Curve over Rational Field defined by x*y - z^2
|
|
1145
|
+
To: Projective Plane Curve over Rational Field
|
|
1146
|
+
defined by -x^2 - 3*x*y - 4*y^2 - x*z - 3*y*z
|
|
1147
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1148
|
+
(-x + 1/2*y + 1/2*z : -1/2*y + 1/2*z : x + 1/2*y - 1/2*z)
|
|
1149
|
+
|
|
1150
|
+
::
|
|
1151
|
+
|
|
1152
|
+
sage: # needs sage.rings.number_field
|
|
1153
|
+
sage: R.<a> = QQ[]
|
|
1154
|
+
sage: K.<b> = NumberField(a^2 - 3)
|
|
1155
|
+
sage: P.<x,y,z> = ProjectiveSpace(K, 2)
|
|
1156
|
+
sage: C = P.curve([z^2*y^3*x^4 - y^6*x^3 - 4*z^2*y^4*x^3 - 4*z^4*y^2*x^3
|
|
1157
|
+
....: + 3*y^7*x^2 + 10*z^2*y^5*x^2 + 9*z^4*y^3*x^2
|
|
1158
|
+
....: + 5*z^6*y*x^2 - 3*y^8*x - 9*z^2*y^6*x - 11*z^4*y^4*x
|
|
1159
|
+
....: - 7*z^6*y^2*x - 2*z^8*x + y^9 + 2*z^2*y^7 + 3*z^4*y^5
|
|
1160
|
+
....: + 4*z^6*y^3 + 2*z^8*y])
|
|
1161
|
+
sage: Q = P([1,0,0])
|
|
1162
|
+
sage: C.excellent_position(Q)
|
|
1163
|
+
Scheme morphism:
|
|
1164
|
+
From: Projective Plane Curve over Number Field in b
|
|
1165
|
+
with defining polynomial a^2 - 3
|
|
1166
|
+
defined by -x^3*y^6 + 3*x^2*y^7 - 3*x*y^8 + y^9 + x^4*y^3*z^2
|
|
1167
|
+
- 4*x^3*y^4*z^2 + 10*x^2*y^5*z^2 - 9*x*y^6*z^2
|
|
1168
|
+
+ 2*y^7*z^2 - 4*x^3*y^2*z^4 + 9*x^2*y^3*z^4
|
|
1169
|
+
- 11*x*y^4*z^4 + 3*y^5*z^4 + 5*x^2*y*z^6
|
|
1170
|
+
- 7*x*y^2*z^6 + 4*y^3*z^6 - 2*x*z^8 + 2*y*z^8
|
|
1171
|
+
To: Projective Plane Curve over Number Field in b
|
|
1172
|
+
with defining polynomial a^2 - 3
|
|
1173
|
+
defined by 900*x^9 - 7410*x^8*y + 29282*x^7*y^2 - 69710*x^6*y^3
|
|
1174
|
+
+ 110818*x^5*y^4 - 123178*x^4*y^5 + 96550*x^3*y^6
|
|
1175
|
+
- 52570*x^2*y^7 + 18194*x*y^8 - 3388*y^9 - 1550*x^8*z
|
|
1176
|
+
+ 9892*x^7*y*z - 30756*x^6*y^2*z + 58692*x^5*y^3*z
|
|
1177
|
+
- 75600*x^4*y^4*z + 67916*x^3*y^5*z - 42364*x^2*y^6*z
|
|
1178
|
+
+ 16844*x*y^7*z - 3586*y^8*z + 786*x^7*z^2
|
|
1179
|
+
- 3958*x^6*y*z^2 + 9746*x^5*y^2*z^2 - 14694*x^4*y^3*z^2
|
|
1180
|
+
+ 15174*x^3*y^4*z^2 - 10802*x^2*y^5*z^2
|
|
1181
|
+
+ 5014*x*y^6*z^2 - 1266*y^7*z^2 - 144*x^6*z^3
|
|
1182
|
+
+ 512*x^5*y*z^3 - 912*x^4*y^2*z^3 + 1024*x^3*y^3*z^3
|
|
1183
|
+
- 816*x^2*y^4*z^3 + 512*x*y^5*z^3 - 176*y^6*z^3
|
|
1184
|
+
+ 8*x^5*z^4 - 8*x^4*y*z^4 - 16*x^3*y^2*z^4
|
|
1185
|
+
+ 16*x^2*y^3*z^4 + 8*x*y^4*z^4 - 8*y^5*z^4
|
|
1186
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1187
|
+
(1/4*y + 1/2*z : -1/4*y + 1/2*z : x + 1/4*y - 1/2*z)
|
|
1188
|
+
|
|
1189
|
+
::
|
|
1190
|
+
|
|
1191
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
1192
|
+
sage: set_verbose(-1)
|
|
1193
|
+
sage: a = QQbar(sqrt(2))
|
|
1194
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQbar, 2)
|
|
1195
|
+
sage: C = Curve([(-1/4*a)*x^3 + (-3/4*a)*x^2*y
|
|
1196
|
+
....: + (-3/4*a)*x*y^2 + (-1/4*a)*y^3 - 2*x*y*z], P)
|
|
1197
|
+
sage: Q = P([0,0,1])
|
|
1198
|
+
sage: C.excellent_position(Q)
|
|
1199
|
+
Scheme morphism:
|
|
1200
|
+
From: Projective Plane Curve over Algebraic Field defined
|
|
1201
|
+
by (-0.3535533905932738?)*x^3 + (-1.060660171779822?)*x^2*y
|
|
1202
|
+
+ (-1.060660171779822?)*x*y^2 + (-0.3535533905932738?)*y^3
|
|
1203
|
+
+ (-2)*x*y*z
|
|
1204
|
+
To: Projective Plane Curve over Algebraic Field defined
|
|
1205
|
+
by (-2.828427124746190?)*x^3 + (-2)*x^2*y + 2*y^3
|
|
1206
|
+
+ (-2)*x^2*z + 2*y^2*z
|
|
1207
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1208
|
+
(1/2*x + 1/2*y : (-1/2)*x + 1/2*y : 1/2*x + (-1/2)*y + z)
|
|
1209
|
+
"""
|
|
1210
|
+
PP = self.ambient_space()
|
|
1211
|
+
# check that Q is on this curve
|
|
1212
|
+
try:
|
|
1213
|
+
Q = self(Q)
|
|
1214
|
+
except TypeError:
|
|
1215
|
+
raise TypeError("(=%s) must be a point on this curve" % Q)
|
|
1216
|
+
r = self.multiplicity(Q)
|
|
1217
|
+
d = self.degree()
|
|
1218
|
+
# first move Q to (0 : 0 : 1), (1 : 0 : 0), or (0 : 1 : 0)
|
|
1219
|
+
# this makes it easier to construct the main transformation
|
|
1220
|
+
i = 0
|
|
1221
|
+
while Q[i] == 0:
|
|
1222
|
+
i += 1
|
|
1223
|
+
coords = [PP.gens()[j] + Q[j]/Q[i]*PP.gens()[i] for j in range(3)]
|
|
1224
|
+
coords[i] = PP.gens()[i]
|
|
1225
|
+
accoords = [PP.gens()[j] - Q[j]/Q[i]*PP.gens()[i] for j in range(3)] # coords used in map construction
|
|
1226
|
+
accoords[i] = PP.gens()[i]
|
|
1227
|
+
baseC = PP.curve(self.defining_polynomial()(coords))
|
|
1228
|
+
P = [0]*3
|
|
1229
|
+
P[i] = 1
|
|
1230
|
+
P = PP(P)
|
|
1231
|
+
l = [0, 1, 2]
|
|
1232
|
+
l.pop(i)
|
|
1233
|
+
# choose points forming a triangle with one vertex at P to map to the coordinate triangle
|
|
1234
|
+
good = False
|
|
1235
|
+
a = 0
|
|
1236
|
+
while not good:
|
|
1237
|
+
a = a + 1
|
|
1238
|
+
# find points to map to (1 : 0 : 0) and (0 : 1 : 0), not on the curve
|
|
1239
|
+
Px = [0]*3
|
|
1240
|
+
Px[l[0]] = a
|
|
1241
|
+
Px[l[1]] = 1
|
|
1242
|
+
Py = [0]*3
|
|
1243
|
+
Py[l[0]] = -a
|
|
1244
|
+
Py[l[1]] = 1
|
|
1245
|
+
Py[i] = 1
|
|
1246
|
+
try:
|
|
1247
|
+
Px = baseC(Px)
|
|
1248
|
+
Py = baseC(Py)
|
|
1249
|
+
continue
|
|
1250
|
+
except TypeError:
|
|
1251
|
+
pass
|
|
1252
|
+
# by construction, P, Px, Py are linearly independent so the following matrix is invertible
|
|
1253
|
+
M = matrix([[Px[j], Py[j], P[j]] for j in range(3)])
|
|
1254
|
+
# M defines a change of coordinates sending (1 : 0 : 0) to Py, (0 : 1 : 0) to Px, (0 : 0 : 1) to P; the
|
|
1255
|
+
# inverse of the transformation we want, used to create the new defining polynomial
|
|
1256
|
+
coords = [sum([M.row(j)[k]*PP.gens()[k] for k in range(3)]) for j in range(3)]
|
|
1257
|
+
C = PP.curve(baseC.defining_polynomial()(coords))
|
|
1258
|
+
# check tangents at (0 : 0 : 1)
|
|
1259
|
+
T = C.tangents(PP([0, 0, 1]), factor=False)[0]
|
|
1260
|
+
if all(e[0] > 0 for e in T.exponents()) or all(e[1] > 0 for e in T.exponents()):
|
|
1261
|
+
continue
|
|
1262
|
+
# check that the other intersections of C with the exceptional lines are correct
|
|
1263
|
+
need_continue = False
|
|
1264
|
+
for j in range(3):
|
|
1265
|
+
poly = C.defining_polynomial().subs({PP.gens()[j]: 0})
|
|
1266
|
+
# this is a homogeneous polynomial in the other two variables
|
|
1267
|
+
# and so should factor completely into homogeneous linear factors
|
|
1268
|
+
# each corresponding to an intersection point where the jth coord is 0.
|
|
1269
|
+
# check if there are enough roots, up to multiplicity (that is, that PP.gens()[j]
|
|
1270
|
+
# doesn't divide the defining polynomial of C)
|
|
1271
|
+
if poly.degree() != d:
|
|
1272
|
+
need_continue = True
|
|
1273
|
+
break
|
|
1274
|
+
# if j != 2, then there should be d - r multiplicity 1 roots,
|
|
1275
|
+
# besides the root corresponding to (0 : 0 : 1)
|
|
1276
|
+
# if j == 2, then all roots should have multiplicity 1
|
|
1277
|
+
npoly = poly
|
|
1278
|
+
if j != 2:
|
|
1279
|
+
# since (0 : 0 : 1) has multiplicity r, divide out by the highest
|
|
1280
|
+
# shared power of the corresponding variable before doing the resultant computations
|
|
1281
|
+
if j == 0:
|
|
1282
|
+
div_pow = min(e[1] for e in npoly.exponents())
|
|
1283
|
+
npoly = PP.coordinate_ring()({(v0, v1 - div_pow, v2): g
|
|
1284
|
+
for (v0, v1, v2), g in npoly.monomial_coefficients().items()})
|
|
1285
|
+
else:
|
|
1286
|
+
div_pow = min(e[0] for e in npoly.exponents())
|
|
1287
|
+
npoly = PP.coordinate_ring()({(v0 - div_pow, v1, v2): g
|
|
1288
|
+
for (v0, v1, v2), g in npoly.monomial_coefficients().items()})
|
|
1289
|
+
# check the degree again
|
|
1290
|
+
if npoly.degree() != d - r:
|
|
1291
|
+
need_continue = True
|
|
1292
|
+
break
|
|
1293
|
+
# check that npoly isn't a constant now
|
|
1294
|
+
if npoly.degree() > 0:
|
|
1295
|
+
t = 0
|
|
1296
|
+
while npoly.degree(PP.gens()[t]) == 0:
|
|
1297
|
+
t = t + 1
|
|
1298
|
+
if npoly.resultant(npoly.derivative(PP.gens()[t]), PP.gens()[t]) == 0:
|
|
1299
|
+
need_continue = True
|
|
1300
|
+
break
|
|
1301
|
+
else:
|
|
1302
|
+
t = 0
|
|
1303
|
+
while npoly.degree(PP.gens()[t]) == 0:
|
|
1304
|
+
t = t + 1
|
|
1305
|
+
if poly.resultant(poly.derivative(PP.gens()[t]), PP.gens()[t]) == 0:
|
|
1306
|
+
need_continue = True
|
|
1307
|
+
break
|
|
1308
|
+
# check that intersections with the line PP.gens()[j] are transverse.
|
|
1309
|
+
# at a simple point P of the curve, the tangent at that point is
|
|
1310
|
+
# given by F_x(P)*x + F_y(P)*y + F_z(P)*z where F is the defining polynomial
|
|
1311
|
+
# of the curve
|
|
1312
|
+
tmp_l = [0, 1, 2]
|
|
1313
|
+
tmp_l.pop(j)
|
|
1314
|
+
poly1 = npoly.derivative(PP.gens()[tmp_l[0]])
|
|
1315
|
+
poly2 = npoly.derivative(PP.gens()[tmp_l[1]])
|
|
1316
|
+
if poly1.degree() > 0 or poly2.degree() > 0:
|
|
1317
|
+
t = 0
|
|
1318
|
+
while poly1.degree(PP.gens()[t]) == 0 and poly2.degree(PP.gens()[t]) == 0:
|
|
1319
|
+
t = t + 1
|
|
1320
|
+
# maybe a stricter check than necessary
|
|
1321
|
+
if poly1.resultant(poly2, PP.gens()[t]) == 0:
|
|
1322
|
+
need_continue = True
|
|
1323
|
+
break
|
|
1324
|
+
if need_continue:
|
|
1325
|
+
continue
|
|
1326
|
+
good = True
|
|
1327
|
+
# coords for map
|
|
1328
|
+
M = M.inverse()
|
|
1329
|
+
accoords2 = [sum([M.row(j)[k]*PP.gens()[k] for k in range(3)]) for j in range(3)]
|
|
1330
|
+
H = Hom(self, C)
|
|
1331
|
+
phi = H([f(accoords) for f in accoords2])
|
|
1332
|
+
return phi
|
|
1333
|
+
|
|
1334
|
+
def ordinary_model(self):
|
|
1335
|
+
r"""
|
|
1336
|
+
Return a birational map from this curve to a plane curve with only ordinary singularities.
|
|
1337
|
+
|
|
1338
|
+
Currently only implemented over number fields. If not all of the coordinates of the non-ordinary
|
|
1339
|
+
singularities of this curve are contained in its base field, then the domain and codomain of the
|
|
1340
|
+
map returned will be defined over an extension. This curve must be irreducible.
|
|
1341
|
+
|
|
1342
|
+
OUTPUT:
|
|
1343
|
+
|
|
1344
|
+
- a scheme morphism from this curve to a curve with only ordinary singularities that defines a
|
|
1345
|
+
birational map between the two curves.
|
|
1346
|
+
|
|
1347
|
+
EXAMPLES::
|
|
1348
|
+
|
|
1349
|
+
sage: # needs sage.rings.number_field
|
|
1350
|
+
sage: set_verbose(-1)
|
|
1351
|
+
sage: K = QuadraticField(3)
|
|
1352
|
+
sage: P.<x,y,z> = ProjectiveSpace(K, 2)
|
|
1353
|
+
sage: C = Curve([x^5 - K.0*y*z^4], P)
|
|
1354
|
+
sage: C.ordinary_model()
|
|
1355
|
+
Scheme morphism:
|
|
1356
|
+
From: Projective Plane Curve over Number Field in a
|
|
1357
|
+
with defining polynomial x^2 - 3 with a = 1.732050807568878?
|
|
1358
|
+
defined by x^5 + (-a)*y*z^4
|
|
1359
|
+
To: Projective Plane Curve over Number Field in a
|
|
1360
|
+
with defining polynomial x^2 - 3 with a = 1.732050807568878?
|
|
1361
|
+
defined by (-a)*x^5*y + (-4*a)*x^4*y^2 + (-6*a)*x^3*y^3
|
|
1362
|
+
+ (-4*a)*x^2*y^4 + (-a)*x*y^5 + (-a - 1)*x^5*z
|
|
1363
|
+
+ (-4*a + 5)*x^4*y*z + (-6*a - 10)*x^3*y^2*z
|
|
1364
|
+
+ (-4*a + 10)*x^2*y^3*z + (-a - 5)*x*y^4*z + y^5*z
|
|
1365
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1366
|
+
(-1/4*x^2 - 1/2*x*y + 1/2*x*z + 1/2*y*z - 1/4*z^2 :
|
|
1367
|
+
1/4*x^2 + 1/2*x*y + 1/2*y*z - 1/4*z^2 :
|
|
1368
|
+
-1/4*x^2 + 1/4*z^2)
|
|
1369
|
+
|
|
1370
|
+
::
|
|
1371
|
+
|
|
1372
|
+
sage: set_verbose(-1)
|
|
1373
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1374
|
+
sage: C = Curve([y^2*z^2 - x^4 - x^3*z], P)
|
|
1375
|
+
sage: D = C.ordinary_model(); D # long time (2 seconds)
|
|
1376
|
+
Scheme morphism:
|
|
1377
|
+
From: Projective Plane Curve over Rational Field defined
|
|
1378
|
+
by -x^4 - x^3*z + y^2*z^2
|
|
1379
|
+
To: Projective Plane Curve over Rational Field defined
|
|
1380
|
+
by 4*x^6*y^3 - 24*x^5*y^4 + 36*x^4*y^5 + 8*x^6*y^2*z
|
|
1381
|
+
- 40*x^5*y^3*z + 24*x^4*y^4*z + 72*x^3*y^5*z - 4*x^6*y*z^2
|
|
1382
|
+
+ 8*x^5*y^2*z^2 - 56*x^4*y^3*z^2 + 104*x^3*y^4*z^2
|
|
1383
|
+
+ 44*x^2*y^5*z^2 + 8*x^6*z^3 - 16*x^5*y*z^3
|
|
1384
|
+
- 24*x^4*y^2*z^3 + 40*x^3*y^3*z^3 + 48*x^2*y^4*z^3
|
|
1385
|
+
+ 8*x*y^5*z^3 - 8*x^5*z^4 + 36*x^4*y*z^4 - 56*x^3*y^2*z^4
|
|
1386
|
+
+ 20*x^2*y^3*z^4 + 40*x*y^4*z^4 - 16*y^5*z^4
|
|
1387
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1388
|
+
(-3/64*x^4 + 9/64*x^2*y^2 - 3/32*x*y^3 - 1/16*x^3*z
|
|
1389
|
+
- 1/8*x^2*y*z + 1/4*x*y^2*z - 1/16*y^3*z - 1/8*x*y*z^2
|
|
1390
|
+
+ 1/16*y^2*z^2 :
|
|
1391
|
+
-1/64*x^4 + 3/64*x^2*y^2 - 1/32*x*y^3 + 1/16*x*y^2*z
|
|
1392
|
+
- 1/16*y^3*z + 1/16*y^2*z^2 :
|
|
1393
|
+
3/64*x^4 - 3/32*x^3*y + 3/64*x^2*y^2 + 1/16*x^3*z
|
|
1394
|
+
- 3/16*x^2*y*z + 1/8*x*y^2*z - 1/8*x*y*z^2 + 1/16*y^2*z^2)
|
|
1395
|
+
sage: all(D.codomain().is_ordinary_singularity(Q) # long time
|
|
1396
|
+
....: for Q in D.codomain().singular_points())
|
|
1397
|
+
True
|
|
1398
|
+
|
|
1399
|
+
::
|
|
1400
|
+
|
|
1401
|
+
sage: set_verbose(-1)
|
|
1402
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1403
|
+
sage: C = Curve([(x^2 + y^2 - y*z - 2*z^2)*(y*z - x^2 + 2*z^2)*z + y^5], P)
|
|
1404
|
+
sage: C.ordinary_model() # long time (5 seconds)
|
|
1405
|
+
Scheme morphism:
|
|
1406
|
+
From: Projective Plane Curve over Number Field in a
|
|
1407
|
+
with defining polynomial y^2 - 2 defined
|
|
1408
|
+
by y^5 - x^4*z - x^2*y^2*z + 2*x^2*y*z^2 + y^3*z^2
|
|
1409
|
+
+ 4*x^2*z^3 + y^2*z^3 - 4*y*z^4 - 4*z^5
|
|
1410
|
+
To: Projective Plane Curve over Number Field in a
|
|
1411
|
+
with defining polynomial y^2 - 2 defined
|
|
1412
|
+
by (-29*a + 1)*x^8*y^6 + (10*a + 158)*x^7*y^7
|
|
1413
|
+
+ (-109*a - 31)*x^6*y^8 + (-80*a - 198)*x^8*y^5*z
|
|
1414
|
+
+ (531*a + 272)*x^7*y^6*z + (170*a - 718)*x^6*y^7*z
|
|
1415
|
+
+ (19*a - 636)*x^5*y^8*z + (-200*a - 628)*x^8*y^4*z^2
|
|
1416
|
+
+ (1557*a - 114)*x^7*y^5*z^2 + (2197*a - 2449)*x^6*y^6*z^2
|
|
1417
|
+
+ (1223*a - 3800)*x^5*y^7*z^2 + (343*a - 1329)*x^4*y^8*z^2
|
|
1418
|
+
+ (-323*a - 809)*x^8*y^3*z^3 + (1630*a - 631)*x^7*y^4*z^3
|
|
1419
|
+
+ (4190*a - 3126)*x^6*y^5*z^3 + (3904*a - 7110)*x^5*y^6*z^3
|
|
1420
|
+
+ (1789*a - 5161)*x^4*y^7*z^3 + (330*a - 1083)*x^3*y^8*z^3
|
|
1421
|
+
+ (-259*a - 524)*x^8*y^2*z^4 + (720*a - 605)*x^7*y^3*z^4
|
|
1422
|
+
+ (3082*a - 2011)*x^6*y^4*z^4 + (4548*a - 5462)*x^5*y^5*z^4
|
|
1423
|
+
+ (2958*a - 6611)*x^4*y^6*z^4 + (994*a - 2931)*x^3*y^7*z^4
|
|
1424
|
+
+ (117*a - 416)*x^2*y^8*z^4 + (-108*a - 184)*x^8*y*z^5
|
|
1425
|
+
+ (169*a - 168)*x^7*y^2*z^5 + (831*a - 835)*x^6*y^3*z^5
|
|
1426
|
+
+ (2225*a - 1725)*x^5*y^4*z^5 + (1970*a - 3316)*x^4*y^5*z^5
|
|
1427
|
+
+ (952*a - 2442)*x^3*y^6*z^5 + (217*a - 725)*x^2*y^7*z^5
|
|
1428
|
+
+ (16*a - 77)*x*y^8*z^5 + (-23*a - 35)*x^8*z^6
|
|
1429
|
+
+ (43*a + 24)*x^7*y*z^6 + (21*a - 198)*x^6*y^2*z^6
|
|
1430
|
+
+ (377*a - 179)*x^5*y^3*z^6 + (458*a - 537)*x^4*y^4*z^6
|
|
1431
|
+
+ (288*a - 624)*x^3*y^5*z^6 + (100*a - 299)*x^2*y^6*z^6
|
|
1432
|
+
+ (16*a - 67)*x*y^7*z^6 - 5*y^8*z^6
|
|
1433
|
+
Defn: Defined on coordinates by sending (x : y : z) to
|
|
1434
|
+
((-5/128*a - 5/128)*x^4 + (-5/32*a + 5/32)*x^3*y
|
|
1435
|
+
+ (-1/16*a + 3/32)*x^2*y^2 + (1/16*a - 1/16)*x*y^3
|
|
1436
|
+
+ (1/32*a - 1/32)*y^4 - 1/32*x^3*z + (3/16*a - 5/8)*x^2*y*z
|
|
1437
|
+
+ (1/8*a - 5/16)*x*y^2*z + (1/8*a + 5/32)*x^2*z^2
|
|
1438
|
+
+ (-3/16*a + 5/16)*x*y*z^2 + (-3/16*a - 1/16)*y^2*z^2
|
|
1439
|
+
+ 1/16*x*z^3 + (1/4*a + 1/4)*y*z^3 + (-3/32*a - 5/32)*z^4 :
|
|
1440
|
+
(-5/128*a - 5/128)*x^4 + (5/32*a)*x^3*y
|
|
1441
|
+
+ (3/32*a + 3/32)*x^2*y^2 + (-1/16*a)*x*y^3
|
|
1442
|
+
+ (-1/32*a - 1/32)*y^4 - 1/32*x^3*z + (-11/32*a)*x^2*y*z
|
|
1443
|
+
+ (1/8*a + 5/16)*x*y^2*z + (3/16*a + 1/4)*y^3*z
|
|
1444
|
+
+ (1/8*a + 5/32)*x^2*z^2 + (-1/16*a - 3/8)*x*y*z^2
|
|
1445
|
+
+ (-3/8*a - 9/16)*y^2*z^2 + 1/16*x*z^3 + (5/16*a + 1/2)*y*z^3
|
|
1446
|
+
+ (-3/32*a - 5/32)*z^4 :
|
|
1447
|
+
(1/64*a + 3/128)*x^4 + (-1/32*a - 1/32)*x^3*y
|
|
1448
|
+
+ (3/32*a - 9/32)*x^2*y^2 + (1/16*a - 3/16)*x*y^3 - 1/32*y^4
|
|
1449
|
+
+ (3/32*a + 1/8)*x^2*y*z + (-1/8*a + 1/8)*x*y^2*z
|
|
1450
|
+
+ (-1/16*a)*y^3*z + (-1/16*a - 3/32)*x^2*z^2
|
|
1451
|
+
+ (1/16*a + 1/16)*x*y*z^2 + (3/16*a + 3/16)*y^2*z^2
|
|
1452
|
+
+ (-3/16*a - 1/4)*y*z^3 + (1/16*a + 3/32)*z^4)
|
|
1453
|
+
"""
|
|
1454
|
+
# helper function for extending the base field
|
|
1455
|
+
|
|
1456
|
+
def extension(self):
|
|
1457
|
+
F = self.base_ring()
|
|
1458
|
+
pts = self.change_ring(F.embeddings(QQbar)[0]).rational_points()
|
|
1459
|
+
L = [t for pt in pts for t in pt]
|
|
1460
|
+
K = number_field_elements_from_algebraics(L)[0]
|
|
1461
|
+
if isinstance(K, RationalField):
|
|
1462
|
+
return F.embeddings(F)[0]
|
|
1463
|
+
else:
|
|
1464
|
+
if isinstance(F, RationalField):
|
|
1465
|
+
return F.embeddings(K)[0]
|
|
1466
|
+
else:
|
|
1467
|
+
# make sure the defining polynomial variable names are the same for K, N
|
|
1468
|
+
N = NumberField(K.defining_polynomial().parent()(F.defining_polynomial()), str(K.gen()))
|
|
1469
|
+
return N.composite_fields(K, both_maps=True)[0][1]*F.embeddings(N)[0]
|
|
1470
|
+
if self.base_ring() not in NumberFields():
|
|
1471
|
+
raise NotImplementedError("the base ring of this curve must be a number field")
|
|
1472
|
+
if not self.is_irreducible():
|
|
1473
|
+
raise TypeError("this curve must be irreducible")
|
|
1474
|
+
C_orig = self
|
|
1475
|
+
C = self
|
|
1476
|
+
PP = C.ambient_space()
|
|
1477
|
+
# extend the base field if necessary to find all singular points
|
|
1478
|
+
emb = extension(C.singular_subscheme())
|
|
1479
|
+
PP = PP.change_ring(emb)
|
|
1480
|
+
C = C.change_ring(emb)
|
|
1481
|
+
C_orig = C_orig.change_ring(emb)
|
|
1482
|
+
pts = C.singular_points()
|
|
1483
|
+
H = End(C)
|
|
1484
|
+
phi = H(list(C.ambient_space().gens()))
|
|
1485
|
+
while pts:
|
|
1486
|
+
for i in range(len(pts) - 1, -1, -1):
|
|
1487
|
+
try:
|
|
1488
|
+
if C.is_ordinary_singularity(pts[i]):
|
|
1489
|
+
pts.pop(i)
|
|
1490
|
+
except TypeError:
|
|
1491
|
+
pts.pop(i)
|
|
1492
|
+
if pts:
|
|
1493
|
+
temp_exc = C.excellent_position(pts[0])
|
|
1494
|
+
temp_qua = temp_exc.codomain().quadratic_transform()
|
|
1495
|
+
C = temp_qua.codomain()
|
|
1496
|
+
phi = temp_qua*temp_exc*phi
|
|
1497
|
+
# transform the old points
|
|
1498
|
+
for i in range(len(pts) - 1, -1, -1):
|
|
1499
|
+
# find image if it is a point the composition map is defined on
|
|
1500
|
+
try:
|
|
1501
|
+
temp_pt = (temp_qua*temp_exc)(temp_exc.domain()(pts[i]))
|
|
1502
|
+
pts.pop(i)
|
|
1503
|
+
if PP(list(temp_pt)) not in [PP(list(tpt)) for tpt in pts]:
|
|
1504
|
+
pts.append(temp_pt)
|
|
1505
|
+
except (TypeError, ValueError):
|
|
1506
|
+
pass
|
|
1507
|
+
# add points from the intersection of C and the line z
|
|
1508
|
+
PPline = ProjectiveSpace(PP.base_ring(), 1)
|
|
1509
|
+
# make sure the conversion happens in the right order
|
|
1510
|
+
ringH = Hom(PP.coordinate_ring(), PPline.coordinate_ring())
|
|
1511
|
+
psi = ringH(list(PPline.gens()) + [0])
|
|
1512
|
+
X = PPline.subscheme([psi(f) for f in C.singular_subscheme().defining_polynomials()])
|
|
1513
|
+
emb = extension(X)
|
|
1514
|
+
PP = PP.change_ring(emb)
|
|
1515
|
+
phi = phi.change_ring(emb)
|
|
1516
|
+
C = C.change_ring(emb)
|
|
1517
|
+
C_orig = C_orig.change_ring(emb)
|
|
1518
|
+
X = X.change_ring(emb)
|
|
1519
|
+
pts = [PP(pt.change_ring(emb)) for pt in pts]
|
|
1520
|
+
newpts = [PP(list(pt) + [0]) for pt in X.rational_points()]
|
|
1521
|
+
# avoid duplicates
|
|
1522
|
+
for pt in newpts:
|
|
1523
|
+
if PP(list(pt)) not in [PP(list(tpt)) for tpt in pts]:
|
|
1524
|
+
pts.append(pt)
|
|
1525
|
+
return phi
|
|
1526
|
+
|
|
1527
|
+
def is_transverse(self, C, P):
|
|
1528
|
+
r"""
|
|
1529
|
+
Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse.
|
|
1530
|
+
|
|
1531
|
+
The intersection at ``P`` is transverse if ``P`` is a nonsingular point of both curves, and if the
|
|
1532
|
+
tangents of the curves at ``P`` are distinct.
|
|
1533
|
+
|
|
1534
|
+
INPUT:
|
|
1535
|
+
|
|
1536
|
+
- ``C`` -- a curve in the ambient space of this curve
|
|
1537
|
+
|
|
1538
|
+
- ``P`` -- a point in the intersection of both curves
|
|
1539
|
+
|
|
1540
|
+
OUTPUT: boolean
|
|
1541
|
+
|
|
1542
|
+
EXAMPLES::
|
|
1543
|
+
|
|
1544
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1545
|
+
sage: C = Curve([x^2 - y^2], P)
|
|
1546
|
+
sage: D = Curve([x - y], P)
|
|
1547
|
+
sage: Q = P([1,1,0])
|
|
1548
|
+
sage: C.is_transverse(D, Q)
|
|
1549
|
+
False
|
|
1550
|
+
|
|
1551
|
+
::
|
|
1552
|
+
|
|
1553
|
+
sage: # needs sage.rings.number_field
|
|
1554
|
+
sage: K = QuadraticField(-1)
|
|
1555
|
+
sage: P.<x,y,z> = ProjectiveSpace(K, 2)
|
|
1556
|
+
sage: C = Curve([y^2*z - K.0*x^3], P)
|
|
1557
|
+
sage: D = Curve([z*x + y^2], P)
|
|
1558
|
+
sage: Q = P([0,0,1])
|
|
1559
|
+
sage: C.is_transverse(D, Q)
|
|
1560
|
+
False
|
|
1561
|
+
|
|
1562
|
+
::
|
|
1563
|
+
|
|
1564
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1565
|
+
sage: C = Curve([x^2 - 2*y^2 - 2*z^2], P)
|
|
1566
|
+
sage: D = Curve([y - z], P)
|
|
1567
|
+
sage: Q = P([2,1,1])
|
|
1568
|
+
sage: C.is_transverse(D, Q)
|
|
1569
|
+
True
|
|
1570
|
+
"""
|
|
1571
|
+
if not self.intersects_at(C, P):
|
|
1572
|
+
raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve" % (P, C))
|
|
1573
|
+
if self.is_singular(P) or C.is_singular(P):
|
|
1574
|
+
return False
|
|
1575
|
+
|
|
1576
|
+
# there is only one tangent at a nonsingular point of a plane curve
|
|
1577
|
+
return not self.tangents(P)[0] == C.tangents(P)[0]
|
|
1578
|
+
|
|
1579
|
+
|
|
1580
|
+
class ProjectiveCurve_field(ProjectiveCurve, AlgebraicScheme_subscheme_projective_field):
|
|
1581
|
+
"""
|
|
1582
|
+
Projective curves over fields.
|
|
1583
|
+
"""
|
|
1584
|
+
_point = ProjectiveCurvePoint_field
|
|
1585
|
+
|
|
1586
|
+
def __init__(self, A, X, category=None):
|
|
1587
|
+
"""
|
|
1588
|
+
Initialize.
|
|
1589
|
+
|
|
1590
|
+
EXAMPLES::
|
|
1591
|
+
|
|
1592
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1593
|
+
sage: C = Curve(x*y^2*z^7 - x^10 - x^2*z^8)
|
|
1594
|
+
sage: loads(dumps(C)) == C
|
|
1595
|
+
True
|
|
1596
|
+
|
|
1597
|
+
TESTS::
|
|
1598
|
+
|
|
1599
|
+
sage: P.<x0,x1,x2,x3,x4> = ProjectiveSpace(QQ, 4)
|
|
1600
|
+
sage: C = Curve([x0^4 - x1^2*x4^2 - 19*x4^4, x2^4 - x3^2*x4^2 - 23*x4^4])
|
|
1601
|
+
Traceback (most recent call last):
|
|
1602
|
+
...
|
|
1603
|
+
ValueError: defining equations (=[x0^4 - x1^2*x4^2 - 19*x4^4, x2^4 - x3^2*x4^2 - 23*x4^4])
|
|
1604
|
+
define a scheme of dimension 2 != 1
|
|
1605
|
+
"""
|
|
1606
|
+
super().__init__(A, X, category=category)
|
|
1607
|
+
|
|
1608
|
+
if A.base_ring() not in Fields():
|
|
1609
|
+
raise TypeError("curve not defined over a field")
|
|
1610
|
+
|
|
1611
|
+
d = super(Curve_generic, self).dimension()
|
|
1612
|
+
if d != 1:
|
|
1613
|
+
raise ValueError(f"defining equations (={X}) define a scheme of dimension {d} != 1")
|
|
1614
|
+
|
|
1615
|
+
@lazy_attribute
|
|
1616
|
+
def _genus(self):
|
|
1617
|
+
"""
|
|
1618
|
+
The geometric genus of this projective curve.
|
|
1619
|
+
|
|
1620
|
+
TESTS:
|
|
1621
|
+
|
|
1622
|
+
Geometric genus is not defined for geometrically reducible curves. You
|
|
1623
|
+
may get a nonsensical answer if the condition is not met::
|
|
1624
|
+
|
|
1625
|
+
sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1626
|
+
sage: C = Curve(x^2 + y^2)
|
|
1627
|
+
sage: C.genus() # indirect test
|
|
1628
|
+
-1
|
|
1629
|
+
"""
|
|
1630
|
+
return self.defining_ideal().genus()
|
|
1631
|
+
|
|
1632
|
+
def arithmetic_genus(self):
|
|
1633
|
+
r"""
|
|
1634
|
+
Return the arithmetic genus of this projective curve.
|
|
1635
|
+
|
|
1636
|
+
This is the arithmetic genus `p_a(C)` as defined in [Har1977]_. If `P`
|
|
1637
|
+
is the Hilbert polynomial of the defining ideal of this curve, then the
|
|
1638
|
+
arithmetic genus of this curve is `1 - P(0)`.
|
|
1639
|
+
|
|
1640
|
+
EXAMPLES::
|
|
1641
|
+
|
|
1642
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
1643
|
+
sage: C = P.curve([w*z - x^2, w^2 + y^2 + z^2])
|
|
1644
|
+
sage: C.arithmetic_genus()
|
|
1645
|
+
1
|
|
1646
|
+
|
|
1647
|
+
::
|
|
1648
|
+
|
|
1649
|
+
sage: P.<x,y,z,w,t> = ProjectiveSpace(GF(7), 4)
|
|
1650
|
+
sage: C = P.curve([t^3 - x*y*w, x^3 + y^3 + z^3, z - w])
|
|
1651
|
+
sage: C.arithmetic_genus()
|
|
1652
|
+
10
|
|
1653
|
+
"""
|
|
1654
|
+
return 1 - self.defining_ideal().hilbert_polynomial()(0)
|
|
1655
|
+
|
|
1656
|
+
def is_complete_intersection(self):
|
|
1657
|
+
r"""
|
|
1658
|
+
Return whether this projective curve is a complete intersection.
|
|
1659
|
+
|
|
1660
|
+
EXAMPLES::
|
|
1661
|
+
|
|
1662
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
1663
|
+
sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P)
|
|
1664
|
+
sage: C.is_complete_intersection()
|
|
1665
|
+
False
|
|
1666
|
+
|
|
1667
|
+
::
|
|
1668
|
+
|
|
1669
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
1670
|
+
sage: C = Curve([y*w - x^2, z*w^2 - x^3], P)
|
|
1671
|
+
sage: C.is_complete_intersection()
|
|
1672
|
+
True
|
|
1673
|
+
|
|
1674
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
1675
|
+
sage: C = Curve([z^2 - y*w, y*z - x*w, y^2 - x*z], P)
|
|
1676
|
+
sage: C.is_complete_intersection()
|
|
1677
|
+
False
|
|
1678
|
+
"""
|
|
1679
|
+
singular_lib("sing.lib")
|
|
1680
|
+
simplify = singular_function("simplify")
|
|
1681
|
+
is_ci = singular_function("is_ci")
|
|
1682
|
+
|
|
1683
|
+
# verbose unless printlevel is -1.
|
|
1684
|
+
saved_printlevel = get_printlevel()
|
|
1685
|
+
set_printlevel(-1)
|
|
1686
|
+
id = simplify(self.defining_ideal(), 10)
|
|
1687
|
+
L = is_ci(id)[-1]
|
|
1688
|
+
set_printlevel(saved_printlevel)
|
|
1689
|
+
|
|
1690
|
+
return len(self.ambient_space().gens()) - len(id) == L
|
|
1691
|
+
|
|
1692
|
+
def tangent_line(self, p):
|
|
1693
|
+
"""
|
|
1694
|
+
Return the tangent line at the point ``p``.
|
|
1695
|
+
|
|
1696
|
+
INPUT:
|
|
1697
|
+
|
|
1698
|
+
- ``p`` -- a rational point of the curve
|
|
1699
|
+
|
|
1700
|
+
EXAMPLES::
|
|
1701
|
+
|
|
1702
|
+
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
|
|
1703
|
+
sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P)
|
|
1704
|
+
sage: p = C(1,1,1,1)
|
|
1705
|
+
sage: C.tangent_line(p)
|
|
1706
|
+
Projective Curve over Rational Field
|
|
1707
|
+
defined by -2*x + y + w, -3*x + z + 2*w
|
|
1708
|
+
"""
|
|
1709
|
+
for i in range(len(p)):
|
|
1710
|
+
if p[i]:
|
|
1711
|
+
C = self.affine_patch(i)
|
|
1712
|
+
q = p.dehomogenize(i)
|
|
1713
|
+
T = C.tangent_line(q)
|
|
1714
|
+
return T.projective_closure(i, self.ambient_space())
|
|
1715
|
+
|
|
1716
|
+
raise TypeError("{} does not define a point in the projective space".format(p))
|
|
1717
|
+
|
|
1718
|
+
|
|
1719
|
+
class ProjectivePlaneCurve_field(ProjectivePlaneCurve, ProjectiveCurve_field):
|
|
1720
|
+
"""
|
|
1721
|
+
Projective plane curves over fields.
|
|
1722
|
+
"""
|
|
1723
|
+
_point = ProjectivePlaneCurvePoint_field
|
|
1724
|
+
|
|
1725
|
+
def arithmetic_genus(self):
|
|
1726
|
+
r"""
|
|
1727
|
+
Return the arithmetic genus of this projective curve.
|
|
1728
|
+
|
|
1729
|
+
This is the arithmetic genus `p_a(C)` as defined in [Har1977]_.
|
|
1730
|
+
|
|
1731
|
+
For an irreducible projective plane curve of degree `d`, this is simply
|
|
1732
|
+
`(d - 1)(d - 2)/2`. It need *not* equal the geometric genus (the genus
|
|
1733
|
+
of the normalization of the curve).
|
|
1734
|
+
|
|
1735
|
+
EXAMPLES::
|
|
1736
|
+
|
|
1737
|
+
sage: x,y,z = PolynomialRing(GF(5), 3, 'xyz').gens()
|
|
1738
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8); C
|
|
1739
|
+
Projective Plane Curve over Finite Field of size 5
|
|
1740
|
+
defined by -x^9 + y^2*z^7 - x*z^8
|
|
1741
|
+
sage: C.arithmetic_genus()
|
|
1742
|
+
28
|
|
1743
|
+
sage: C.genus() # geometric
|
|
1744
|
+
4
|
|
1745
|
+
|
|
1746
|
+
::
|
|
1747
|
+
|
|
1748
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1749
|
+
sage: C = Curve([y^3*x - x^2*y*z - 7*z^4])
|
|
1750
|
+
sage: C.arithmetic_genus()
|
|
1751
|
+
3
|
|
1752
|
+
"""
|
|
1753
|
+
if self.is_irreducible():
|
|
1754
|
+
# use genus-degree formula
|
|
1755
|
+
d = self.defining_polynomial().total_degree()
|
|
1756
|
+
return Integer(d - 1).binomial(2)
|
|
1757
|
+
return super().arithmetic_genus()
|
|
1758
|
+
|
|
1759
|
+
def fundamental_group(self):
|
|
1760
|
+
r"""
|
|
1761
|
+
Return a presentation of the fundamental group of the complement
|
|
1762
|
+
of ``self``.
|
|
1763
|
+
|
|
1764
|
+
.. NOTE::
|
|
1765
|
+
|
|
1766
|
+
The curve must be defined over the rationals or a number field
|
|
1767
|
+
with an embedding over `\QQbar`.
|
|
1768
|
+
|
|
1769
|
+
.. NOTE::
|
|
1770
|
+
|
|
1771
|
+
This functionality requires the ``sirocco`` package to be installed.
|
|
1772
|
+
|
|
1773
|
+
EXAMPLES::
|
|
1774
|
+
|
|
1775
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1776
|
+
sage: C = P.curve(x^2*z - y^3)
|
|
1777
|
+
sage: C.fundamental_group() # needs sirocco
|
|
1778
|
+
Finitely presented group < x0 | x0^3 >
|
|
1779
|
+
sage: g = P.curve(z*(x^2*z - y^3)).fundamental_group() # needs sirocco
|
|
1780
|
+
sage: g.sorted_presentation() # needs sirocco
|
|
1781
|
+
Finitely presented group < x0, x1 | x1^-1*x0^-1*x1^-1*x0*x1*x0 >
|
|
1782
|
+
|
|
1783
|
+
In the case of number fields, they need to have an embedding
|
|
1784
|
+
into the algebraic field::
|
|
1785
|
+
|
|
1786
|
+
sage: # needs sage.rings.number_field
|
|
1787
|
+
sage: a = QQ[x](x^2 + 5).roots(QQbar)[0][0]
|
|
1788
|
+
sage: a
|
|
1789
|
+
-2.236067977499790?*I
|
|
1790
|
+
sage: F = NumberField(a.minpoly(), 'a', embedding=a)
|
|
1791
|
+
sage: P.<x,y,z> = ProjectiveSpace(F, 2)
|
|
1792
|
+
sage: F.inject_variables()
|
|
1793
|
+
Defining a
|
|
1794
|
+
sage: C = P.curve(x^2 + a * y^2)
|
|
1795
|
+
sage: C.fundamental_group() # needs sirocco
|
|
1796
|
+
Finitely presented group < x0 | >
|
|
1797
|
+
|
|
1798
|
+
TESTS::
|
|
1799
|
+
|
|
1800
|
+
sage: # needs sage.combinat
|
|
1801
|
+
sage: F.<x0, x1> = FreeGroup()
|
|
1802
|
+
sage: G = F / [x1^-1*(x1^-1*x0^-1*x1*x0^-1)^2, (x1^-1*x0^-1)^2*x1^-1*(x0*x1)^2*x0]
|
|
1803
|
+
sage: G.order()
|
|
1804
|
+
320
|
|
1805
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1806
|
+
sage: C = P.curve(z^2*y^3 - z*(33*x*z+2*x^2+8*z^2)*y^2
|
|
1807
|
+
....: + (21*z^2+21*x*z-x^2)*(z^2+11*x*z-x^2)*y
|
|
1808
|
+
....: + (x-18*z)*(z^2+11*x*z-x^2)^2)
|
|
1809
|
+
sage: G0 = C.fundamental_group() # needs sirocco
|
|
1810
|
+
sage: G.is_isomorphic(G0) # needs sirocco
|
|
1811
|
+
True
|
|
1812
|
+
sage: C = P.curve(z)
|
|
1813
|
+
sage: C.fundamental_group() # needs sirocco
|
|
1814
|
+
Finitely presented group < | >
|
|
1815
|
+
"""
|
|
1816
|
+
from sage.schemes.curves.zariski_vankampen import fundamental_group
|
|
1817
|
+
F = self.base_ring()
|
|
1818
|
+
from sage.rings.qqbar import QQbar
|
|
1819
|
+
if QQbar.coerce_map_from(F) is None:
|
|
1820
|
+
raise NotImplementedError("the base field must have an embedding"
|
|
1821
|
+
" to the algebraic field")
|
|
1822
|
+
g = self.defining_polynomial()
|
|
1823
|
+
ring = self.ambient_space().affine_patch(2).coordinate_ring()
|
|
1824
|
+
if g.degree() == 1:
|
|
1825
|
+
return fundamental_group(ring.one())
|
|
1826
|
+
f = ring(self.affine_patch(2).defining_polynomial())
|
|
1827
|
+
if f.degree() == self.degree():
|
|
1828
|
+
return fundamental_group(f, projective=True)
|
|
1829
|
+
else: # in this case, the line at infinity is part of the curve, so the complement lies in the affine patch
|
|
1830
|
+
return fundamental_group(f, projective=False)
|
|
1831
|
+
|
|
1832
|
+
def rational_parameterization(self):
|
|
1833
|
+
r"""
|
|
1834
|
+
Return a rational parameterization of this curve.
|
|
1835
|
+
|
|
1836
|
+
This curve must have rational coefficients and be absolutely irreducible (i.e. irreducible
|
|
1837
|
+
over the algebraic closure of the rational field). The curve must also be rational (have
|
|
1838
|
+
geometric genus zero).
|
|
1839
|
+
|
|
1840
|
+
The rational parameterization may have coefficients in a quadratic extension of the rational
|
|
1841
|
+
field.
|
|
1842
|
+
|
|
1843
|
+
OUTPUT: a birational map between `\mathbb{P}^{1}` and this curve, given as a scheme morphism
|
|
1844
|
+
|
|
1845
|
+
EXAMPLES::
|
|
1846
|
+
|
|
1847
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1848
|
+
sage: C = Curve([y^2*z - x^3], P)
|
|
1849
|
+
sage: C.rational_parameterization()
|
|
1850
|
+
Scheme morphism:
|
|
1851
|
+
From: Projective Space of dimension 1 over Rational Field
|
|
1852
|
+
To: Projective Plane Curve over Rational Field
|
|
1853
|
+
defined by -x^3 + y^2*z
|
|
1854
|
+
Defn: Defined on coordinates by sending (s : t) to
|
|
1855
|
+
(s^2*t : s^3 : t^3)
|
|
1856
|
+
|
|
1857
|
+
::
|
|
1858
|
+
|
|
1859
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1860
|
+
sage: C = Curve([x^3 - 4*y*z^2 + x*z^2 - x*y*z], P)
|
|
1861
|
+
sage: C.rational_parameterization()
|
|
1862
|
+
Scheme morphism:
|
|
1863
|
+
From: Projective Space of dimension 1 over Rational Field
|
|
1864
|
+
To: Projective Plane Curve over Rational Field
|
|
1865
|
+
defined by x^3 - x*y*z + x*z^2 - 4*y*z^2
|
|
1866
|
+
Defn: Defined on coordinates by sending (s : t) to
|
|
1867
|
+
(4*s^2*t + s*t^2 : s^2*t + t^3 : 4*s^3 + s^2*t)
|
|
1868
|
+
|
|
1869
|
+
::
|
|
1870
|
+
|
|
1871
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
1872
|
+
sage: C = Curve([x^2 + y^2 + z^2], P)
|
|
1873
|
+
sage: C.rational_parameterization()
|
|
1874
|
+
Scheme morphism:
|
|
1875
|
+
From: Projective Space of dimension 1 over Number Field in a
|
|
1876
|
+
with defining polynomial a^2 + 1
|
|
1877
|
+
To: Projective Plane Curve over Number Field in a
|
|
1878
|
+
with defining polynomial a^2 + 1 defined by x^2 + y^2 + z^2
|
|
1879
|
+
Defn: Defined on coordinates by sending (s : t) to
|
|
1880
|
+
((-a)*s^2 + (-a)*t^2 : s^2 - t^2 : 2*s*t)
|
|
1881
|
+
"""
|
|
1882
|
+
if self.genus():
|
|
1883
|
+
raise TypeError("this curve must have geometric genus zero")
|
|
1884
|
+
if not isinstance(self.base_ring(), RationalField):
|
|
1885
|
+
raise TypeError("this curve must be defined over the rational field")
|
|
1886
|
+
|
|
1887
|
+
singular.lib("paraplanecurves.lib")
|
|
1888
|
+
R = singular.paraPlaneCurve(self.defining_polynomial()) # ring
|
|
1889
|
+
R.set_ring()
|
|
1890
|
+
param = singular('PARA').sage().gens() # ideal
|
|
1891
|
+
R = R.sage()
|
|
1892
|
+
|
|
1893
|
+
C = self.change_ring(R.base_ring())
|
|
1894
|
+
H = Hom(ProjectiveSpace(R.base_ring(), 1, R.gens()), C)
|
|
1895
|
+
return H(param)
|
|
1896
|
+
|
|
1897
|
+
def riemann_surface(self, **kwargs):
|
|
1898
|
+
r"""
|
|
1899
|
+
Return the complex Riemann surface determined by this curve.
|
|
1900
|
+
|
|
1901
|
+
OUTPUT: a :class:`~sage.schemes.riemann_surfaces.riemann_surface.RiemannSurface` object
|
|
1902
|
+
|
|
1903
|
+
EXAMPLES::
|
|
1904
|
+
|
|
1905
|
+
sage: R.<x,y,z> = QQ[]
|
|
1906
|
+
sage: C = Curve(x^3 + 3*y^3 + 5*z^3)
|
|
1907
|
+
sage: C.riemann_surface() # needs sage.graphs
|
|
1908
|
+
Riemann surface defined by polynomial f = x^3 + 3*y^3 + 5 = 0,
|
|
1909
|
+
with 53 bits of precision
|
|
1910
|
+
"""
|
|
1911
|
+
return self.affine_patch(2).riemann_surface(**kwargs)
|
|
1912
|
+
|
|
1913
|
+
|
|
1914
|
+
class ProjectivePlaneCurve_finite_field(ProjectivePlaneCurve_field):
|
|
1915
|
+
"""
|
|
1916
|
+
Projective plane curves over finite fields
|
|
1917
|
+
"""
|
|
1918
|
+
_point = ProjectivePlaneCurvePoint_finite_field
|
|
1919
|
+
|
|
1920
|
+
def rational_points_iterator(self):
|
|
1921
|
+
r"""
|
|
1922
|
+
Return a generator object for the rational points on this curve.
|
|
1923
|
+
|
|
1924
|
+
INPUT:
|
|
1925
|
+
|
|
1926
|
+
- ``self`` -- a projective curve
|
|
1927
|
+
|
|
1928
|
+
OUTPUT: a generator of all the rational points on the curve defined over its base field
|
|
1929
|
+
|
|
1930
|
+
EXAMPLES::
|
|
1931
|
+
|
|
1932
|
+
sage: F = GF(37)
|
|
1933
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
1934
|
+
sage: C = Curve(X^7 + Y*X*Z^5*55 + Y^7*12)
|
|
1935
|
+
sage: len(list(C.rational_points_iterator()))
|
|
1936
|
+
37
|
|
1937
|
+
|
|
1938
|
+
::
|
|
1939
|
+
|
|
1940
|
+
sage: F = GF(2)
|
|
1941
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
1942
|
+
sage: C = Curve(X*Y*Z)
|
|
1943
|
+
sage: a = C.rational_points_iterator()
|
|
1944
|
+
sage: next(a)
|
|
1945
|
+
(1 : 0 : 0)
|
|
1946
|
+
sage: next(a)
|
|
1947
|
+
(0 : 1 : 0)
|
|
1948
|
+
sage: next(a)
|
|
1949
|
+
(1 : 1 : 0)
|
|
1950
|
+
sage: next(a)
|
|
1951
|
+
(0 : 0 : 1)
|
|
1952
|
+
sage: next(a)
|
|
1953
|
+
(1 : 0 : 1)
|
|
1954
|
+
sage: next(a)
|
|
1955
|
+
(0 : 1 : 1)
|
|
1956
|
+
sage: next(a)
|
|
1957
|
+
Traceback (most recent call last):
|
|
1958
|
+
...
|
|
1959
|
+
StopIteration
|
|
1960
|
+
|
|
1961
|
+
::
|
|
1962
|
+
|
|
1963
|
+
sage: # needs sage.rings.finite_rings
|
|
1964
|
+
sage: F = GF(3^2,'a')
|
|
1965
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
1966
|
+
sage: C = Curve(X^3 + 5*Y^2*Z - 33*X*Y*X)
|
|
1967
|
+
sage: b = C.rational_points_iterator()
|
|
1968
|
+
sage: next(b)
|
|
1969
|
+
(0 : 1 : 0)
|
|
1970
|
+
sage: next(b)
|
|
1971
|
+
(0 : 0 : 1)
|
|
1972
|
+
sage: next(b)
|
|
1973
|
+
(2*a + 2 : a : 1)
|
|
1974
|
+
sage: next(b)
|
|
1975
|
+
(2 : a + 1 : 1)
|
|
1976
|
+
sage: next(b)
|
|
1977
|
+
(a + 1 : 2*a + 1 : 1)
|
|
1978
|
+
sage: next(b)
|
|
1979
|
+
(1 : 2 : 1)
|
|
1980
|
+
sage: next(b)
|
|
1981
|
+
(2*a + 2 : 2*a : 1)
|
|
1982
|
+
sage: next(b)
|
|
1983
|
+
(2 : 2*a + 2 : 1)
|
|
1984
|
+
sage: next(b)
|
|
1985
|
+
(a + 1 : a + 2 : 1)
|
|
1986
|
+
sage: next(b)
|
|
1987
|
+
(1 : 1 : 1)
|
|
1988
|
+
sage: next(b)
|
|
1989
|
+
Traceback (most recent call last):
|
|
1990
|
+
...
|
|
1991
|
+
StopIteration
|
|
1992
|
+
"""
|
|
1993
|
+
g = self.defining_polynomial()
|
|
1994
|
+
K = g.parent().base_ring()
|
|
1995
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1996
|
+
R = PolynomialRing(K, 'X')
|
|
1997
|
+
X = R.gen()
|
|
1998
|
+
one = K.one()
|
|
1999
|
+
zero = K.zero()
|
|
2000
|
+
|
|
2001
|
+
# the point with Z = 0 = Y
|
|
2002
|
+
try:
|
|
2003
|
+
t = self.point([one, zero, zero])
|
|
2004
|
+
yield t
|
|
2005
|
+
except TypeError:
|
|
2006
|
+
pass
|
|
2007
|
+
|
|
2008
|
+
# points with Z = 0, Y = 1
|
|
2009
|
+
g10 = R(g(X, one, zero))
|
|
2010
|
+
if g10.is_zero():
|
|
2011
|
+
for x in K:
|
|
2012
|
+
yield self.point([x, one, zero])
|
|
2013
|
+
else:
|
|
2014
|
+
for x in g10.roots(multiplicities=False):
|
|
2015
|
+
yield self.point([x, one, zero])
|
|
2016
|
+
|
|
2017
|
+
# points with Z = 1
|
|
2018
|
+
for y in K:
|
|
2019
|
+
gy1 = R(g(X, y, one))
|
|
2020
|
+
if gy1.is_zero():
|
|
2021
|
+
for x in K:
|
|
2022
|
+
yield self.point([x, y, one])
|
|
2023
|
+
else:
|
|
2024
|
+
for x in gy1.roots(multiplicities=False):
|
|
2025
|
+
yield self.point([x, y, one])
|
|
2026
|
+
|
|
2027
|
+
def _points_via_singular(self, sort=True):
|
|
2028
|
+
r"""
|
|
2029
|
+
Return all rational points on this curve, computed using Singular's
|
|
2030
|
+
Brill-Noether implementation.
|
|
2031
|
+
|
|
2032
|
+
INPUT:
|
|
2033
|
+
|
|
2034
|
+
- ``sort`` -- boolean (default: ``True``); if ``True`` return the
|
|
2035
|
+
point list sorted. If ``False``, returns the points in the order
|
|
2036
|
+
computed by Singular.
|
|
2037
|
+
|
|
2038
|
+
EXAMPLES::
|
|
2039
|
+
|
|
2040
|
+
sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens()
|
|
2041
|
+
sage: f = y^2*z^7 - x^9 - x*z^8
|
|
2042
|
+
sage: C = Curve(f); C
|
|
2043
|
+
Projective Plane Curve over Finite Field of size 5 defined by
|
|
2044
|
+
-x^9 + y^2*z^7 - x*z^8
|
|
2045
|
+
sage: C._points_via_singular()
|
|
2046
|
+
[(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1),
|
|
2047
|
+
(3 : 1 : 1), (3 : 4 : 1)]
|
|
2048
|
+
sage: C._points_via_singular(sort=False) # random
|
|
2049
|
+
[(0 : 1 : 0), (3 : 1 : 1), (3 : 4 : 1), (2 : 2 : 1),
|
|
2050
|
+
(0 : 0 : 1), (2 : 3 : 1)]
|
|
2051
|
+
|
|
2052
|
+
|
|
2053
|
+
.. NOTE::
|
|
2054
|
+
|
|
2055
|
+
The Brill-Noether package does not always work (i.e., the
|
|
2056
|
+
'bn' algorithm. When it fails a :exc:`RuntimeError` exception is
|
|
2057
|
+
raised.
|
|
2058
|
+
"""
|
|
2059
|
+
f = self.defining_polynomial()._singular_()
|
|
2060
|
+
singular = f.parent()
|
|
2061
|
+
singular.lib('brnoeth')
|
|
2062
|
+
try:
|
|
2063
|
+
X1 = f.Adj_div()
|
|
2064
|
+
except (TypeError, RuntimeError) as s:
|
|
2065
|
+
raise RuntimeError(str(s) + "\n\n ** Unable to use the\
|
|
2066
|
+
Brill-Noether Singular package to\
|
|
2067
|
+
compute all points (see above).")
|
|
2068
|
+
|
|
2069
|
+
X2 = singular.NSplaces(1, X1)
|
|
2070
|
+
R = X2[5][1][1]
|
|
2071
|
+
R.set_ring()
|
|
2072
|
+
|
|
2073
|
+
# We use sage_flattened_str_list since iterating through
|
|
2074
|
+
# the entire list through the sage/singular interface directly
|
|
2075
|
+
# would involve hundreds of calls to singular, and timing issues with
|
|
2076
|
+
# the expect interface could crop up. Also, this is vastly
|
|
2077
|
+
# faster (and more robust).
|
|
2078
|
+
v = singular('POINTS').sage_flattened_str_list()
|
|
2079
|
+
pnts = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2]))
|
|
2080
|
+
for i in range(len(v)//3)]
|
|
2081
|
+
# singular always dehomogenizes with respect to the last variable
|
|
2082
|
+
# so if this variable divides the curve equation, we need to add
|
|
2083
|
+
# points at infinity
|
|
2084
|
+
F = self.defining_polynomial()
|
|
2085
|
+
z = F.parent().gens()[-1]
|
|
2086
|
+
if z.divides(F):
|
|
2087
|
+
pnts += [self(1, a, 0) for a in self.base_ring()]
|
|
2088
|
+
pnts += [self(0, 1, 0)]
|
|
2089
|
+
# remove multiple points
|
|
2090
|
+
pnts = list(set(pnts))
|
|
2091
|
+
if sort:
|
|
2092
|
+
pnts.sort()
|
|
2093
|
+
return pnts
|
|
2094
|
+
|
|
2095
|
+
def riemann_roch_basis(self, D):
|
|
2096
|
+
r"""
|
|
2097
|
+
Return a basis for the Riemann-Roch space corresponding to `D`.
|
|
2098
|
+
|
|
2099
|
+
This uses Singular's Brill-Noether implementation.
|
|
2100
|
+
|
|
2101
|
+
INPUT:
|
|
2102
|
+
|
|
2103
|
+
- ``D`` -- a divisor
|
|
2104
|
+
|
|
2105
|
+
OUTPUT: list of function field elements that form a basis of the
|
|
2106
|
+
Riemann-Roch space
|
|
2107
|
+
|
|
2108
|
+
EXAMPLES::
|
|
2109
|
+
|
|
2110
|
+
sage: R.<x,y,z> = GF(2)[]
|
|
2111
|
+
sage: f = x^3*y + y^3*z + x*z^3
|
|
2112
|
+
sage: C = Curve(f); pts = C.rational_points()
|
|
2113
|
+
sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ])
|
|
2114
|
+
sage: C.riemann_roch_basis(D)
|
|
2115
|
+
[x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)]
|
|
2116
|
+
|
|
2117
|
+
::
|
|
2118
|
+
|
|
2119
|
+
sage: R.<x,y,z> = GF(5)[]
|
|
2120
|
+
sage: f = x^7 + y^7 + z^7
|
|
2121
|
+
sage: C = Curve(f); pts = C.rational_points()
|
|
2122
|
+
sage: D = C.divisor([ (3, pts[0]), (-1,pts[1]), (10, pts[5]) ])
|
|
2123
|
+
sage: C.riemann_roch_basis(D)
|
|
2124
|
+
[(-2*x + y)/(x + y), (-x + z)/(x + y)]
|
|
2125
|
+
|
|
2126
|
+
.. NOTE::
|
|
2127
|
+
|
|
2128
|
+
Currently this only works over prime field and divisors
|
|
2129
|
+
supported on rational points.
|
|
2130
|
+
"""
|
|
2131
|
+
F = self.base_ring()
|
|
2132
|
+
if not F.is_prime_field():
|
|
2133
|
+
raise TypeError("only works for curves over prime finite fields")
|
|
2134
|
+
|
|
2135
|
+
f = self.defining_polynomial()._singular_()
|
|
2136
|
+
singular = f.parent()
|
|
2137
|
+
singular.lib('brnoeth')
|
|
2138
|
+
try:
|
|
2139
|
+
X1 = f.Adj_div()
|
|
2140
|
+
except (TypeError, RuntimeError) as s:
|
|
2141
|
+
raise RuntimeError(str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above).")
|
|
2142
|
+
X2 = singular.NSplaces(1, X1)
|
|
2143
|
+
# retrieve list of all computed closed points (possibly of degree >1)
|
|
2144
|
+
v = X2[3].sage_flattened_str_list()
|
|
2145
|
+
# We use sage_flattened_str_list since iterating through
|
|
2146
|
+
# the entire list through the sage/singular interface directly
|
|
2147
|
+
# would involve hundreds of calls to singular, and timing issues with
|
|
2148
|
+
# the expect interface could crop up. Also, this is vastly
|
|
2149
|
+
# faster (and more robust).
|
|
2150
|
+
|
|
2151
|
+
v = [v[i].partition(',') for i in range(len(v))]
|
|
2152
|
+
pnts = [(int(v[i][0]), int(v[i][2])-1) for i in range(len(v))]
|
|
2153
|
+
# retrieve coordinates of rational points
|
|
2154
|
+
R = X2[5][1][1]
|
|
2155
|
+
R.set_ring()
|
|
2156
|
+
v = singular('POINTS').sage_flattened_str_list()
|
|
2157
|
+
coords = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) for i in range(len(v)//3)]
|
|
2158
|
+
# build correct representation of D for singular
|
|
2159
|
+
Dcoeffs = []
|
|
2160
|
+
for x in pnts:
|
|
2161
|
+
if x[0] == 1:
|
|
2162
|
+
Dcoeffs.append(D.coefficient(coords[x[1]]))
|
|
2163
|
+
else:
|
|
2164
|
+
Dcoeffs.append(0)
|
|
2165
|
+
G = singular(','.join(str(x) for x in Dcoeffs), type='intvec')
|
|
2166
|
+
# call singular's brill noether routine and return
|
|
2167
|
+
T = X2[1][2]
|
|
2168
|
+
T.set_ring()
|
|
2169
|
+
LG = G.BrillNoether(X2)
|
|
2170
|
+
LG = [X.split(',\n') for X in LG.sage_structured_str_list()]
|
|
2171
|
+
x, y, z = self.ambient_space().coordinate_ring().gens()
|
|
2172
|
+
vars = {'x': x, 'y': y, 'z': z}
|
|
2173
|
+
V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG]
|
|
2174
|
+
return V
|
|
2175
|
+
|
|
2176
|
+
def rational_points(self, algorithm='enum', sort=True):
|
|
2177
|
+
r"""
|
|
2178
|
+
Return the rational points on this curve.
|
|
2179
|
+
|
|
2180
|
+
INPUT:
|
|
2181
|
+
|
|
2182
|
+
- ``algorithm`` -- one of
|
|
2183
|
+
|
|
2184
|
+
- ``'enum'`` -- straightforward enumeration
|
|
2185
|
+
|
|
2186
|
+
- ``'bn'`` -- via Singular's brnoeth package
|
|
2187
|
+
|
|
2188
|
+
- ``sort`` -- boolean (default: ``True``); whether the output
|
|
2189
|
+
points should be sorted. If ``False``, the order of the output
|
|
2190
|
+
is non-deterministic.
|
|
2191
|
+
|
|
2192
|
+
OUTPUT: list of all the rational points on the curve, possibly sorted
|
|
2193
|
+
|
|
2194
|
+
.. NOTE::
|
|
2195
|
+
|
|
2196
|
+
The Brill-Noether package does not always work (i.e., the 'bn'
|
|
2197
|
+
algorithm. When it fails a :exc:`RuntimeError` exception is raised.
|
|
2198
|
+
|
|
2199
|
+
EXAMPLES::
|
|
2200
|
+
|
|
2201
|
+
sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens()
|
|
2202
|
+
sage: f = y^2*z^7 - x^9 - x*z^8
|
|
2203
|
+
sage: C = Curve(f); C
|
|
2204
|
+
Projective Plane Curve over Finite Field of size 5
|
|
2205
|
+
defined by -x^9 + y^2*z^7 - x*z^8
|
|
2206
|
+
sage: C.rational_points()
|
|
2207
|
+
[(0 : 0 : 1), (0 : 1 : 0), (2 : 2 : 1), (2 : 3 : 1),
|
|
2208
|
+
(3 : 1 : 1), (3 : 4 : 1)]
|
|
2209
|
+
sage: C = Curve(x - y + z)
|
|
2210
|
+
sage: C.rational_points()
|
|
2211
|
+
[(0 : 1 : 1), (1 : 1 : 0), (1 : 2 : 1), (2 : 3 : 1),
|
|
2212
|
+
(3 : 4 : 1), (4 : 0 : 1)]
|
|
2213
|
+
sage: C = Curve(x*z + z^2)
|
|
2214
|
+
sage: C.rational_points('all')
|
|
2215
|
+
[(0 : 1 : 0), (1 : 0 : 0), (1 : 1 : 0), (2 : 1 : 0),
|
|
2216
|
+
(3 : 1 : 0), (4 : 0 : 1), (4 : 1 : 0), (4 : 1 : 1),
|
|
2217
|
+
(4 : 2 : 1), (4 : 3 : 1), (4 : 4 : 1)]
|
|
2218
|
+
|
|
2219
|
+
::
|
|
2220
|
+
|
|
2221
|
+
sage: F = GF(7)
|
|
2222
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
2223
|
+
sage: C = Curve(X^3 + Y^3 - Z^3)
|
|
2224
|
+
sage: C.rational_points()
|
|
2225
|
+
[(0 : 1 : 1), (0 : 2 : 1), (0 : 4 : 1), (1 : 0 : 1), (2 : 0 : 1),
|
|
2226
|
+
(3 : 1 : 0), (4 : 0 : 1), (5 : 1 : 0), (6 : 1 : 0)]
|
|
2227
|
+
|
|
2228
|
+
::
|
|
2229
|
+
|
|
2230
|
+
sage: F = GF(1237)
|
|
2231
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
2232
|
+
sage: C = Curve(X^7 + 7*Y^6*Z + Z^4*X^2*Y*89)
|
|
2233
|
+
sage: len(C.rational_points())
|
|
2234
|
+
1237
|
|
2235
|
+
|
|
2236
|
+
::
|
|
2237
|
+
|
|
2238
|
+
sage: # needs sage.rings.finite_rings
|
|
2239
|
+
sage: F = GF(2^6,'a')
|
|
2240
|
+
sage: P2.<X,Y,Z> = ProjectiveSpace(F, 2)
|
|
2241
|
+
sage: C = Curve(X^5 + 11*X*Y*Z^3 + X^2*Y^3 - 13*Y^2*Z^3)
|
|
2242
|
+
sage: len(C.rational_points())
|
|
2243
|
+
104
|
|
2244
|
+
|
|
2245
|
+
::
|
|
2246
|
+
|
|
2247
|
+
sage: R.<x,y,z> = GF(2)[]
|
|
2248
|
+
sage: f = x^3*y + y^3*z + x*z^3
|
|
2249
|
+
sage: C = Curve(f); pts = C.rational_points()
|
|
2250
|
+
sage: pts
|
|
2251
|
+
[(0 : 0 : 1), (0 : 1 : 0), (1 : 0 : 0)]
|
|
2252
|
+
"""
|
|
2253
|
+
if algorithm == "enum":
|
|
2254
|
+
points = list(self.rational_points_iterator())
|
|
2255
|
+
if sort:
|
|
2256
|
+
points.sort()
|
|
2257
|
+
return points
|
|
2258
|
+
|
|
2259
|
+
F = self.base_ring()
|
|
2260
|
+
if not F.is_prime_field():
|
|
2261
|
+
raise TypeError("other algorithms only works for curves over prime finite fields")
|
|
2262
|
+
|
|
2263
|
+
if algorithm == "bn":
|
|
2264
|
+
return self._points_via_singular(sort=sort)
|
|
2265
|
+
|
|
2266
|
+
if algorithm == "all":
|
|
2267
|
+
S_enum = self.rational_points(algorithm='enum')
|
|
2268
|
+
S_bn = self.rational_points(algorithm='bn')
|
|
2269
|
+
if S_enum != S_bn:
|
|
2270
|
+
raise RuntimeError("Bug in rational_points -- different\
|
|
2271
|
+
algorithms give different answers for\
|
|
2272
|
+
curve %s!" % self)
|
|
2273
|
+
return S_enum
|
|
2274
|
+
|
|
2275
|
+
raise ValueError(f"No algorithm '{algorithm}' known")
|
|
2276
|
+
|
|
2277
|
+
|
|
2278
|
+
class IntegralProjectiveCurve(ProjectiveCurve_field):
|
|
2279
|
+
"""
|
|
2280
|
+
Integral projective curve.
|
|
2281
|
+
"""
|
|
2282
|
+
_point = IntegralProjectiveCurvePoint
|
|
2283
|
+
_closed_point = IntegralProjectiveCurveClosedPoint
|
|
2284
|
+
|
|
2285
|
+
def __init__(self, A, f):
|
|
2286
|
+
"""
|
|
2287
|
+
Initialize.
|
|
2288
|
+
|
|
2289
|
+
TESTS::
|
|
2290
|
+
|
|
2291
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2292
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2293
|
+
sage: loads(dumps(C)) == C
|
|
2294
|
+
True
|
|
2295
|
+
"""
|
|
2296
|
+
super().__init__(A, f)
|
|
2297
|
+
|
|
2298
|
+
ideal = self.defining_ideal()
|
|
2299
|
+
gs = self.ambient_space().gens()
|
|
2300
|
+
for i in range(self.ngens()):
|
|
2301
|
+
if gs[i] not in ideal:
|
|
2302
|
+
self._open_affine = self.affine_patch(i)
|
|
2303
|
+
self._open_affine_index = i
|
|
2304
|
+
break
|
|
2305
|
+
else:
|
|
2306
|
+
raise ValueError("no projective curve defined")
|
|
2307
|
+
|
|
2308
|
+
def function_field(self):
|
|
2309
|
+
"""
|
|
2310
|
+
Return the function field of this curve.
|
|
2311
|
+
|
|
2312
|
+
EXAMPLES::
|
|
2313
|
+
|
|
2314
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
2315
|
+
sage: C = Curve(x^2 + y^2 + z^2, P)
|
|
2316
|
+
sage: C.function_field()
|
|
2317
|
+
Function field in z defined by z^2 + y^2 + 1
|
|
2318
|
+
|
|
2319
|
+
::
|
|
2320
|
+
|
|
2321
|
+
sage: # needs sage.rings.finite_rings
|
|
2322
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2)
|
|
2323
|
+
sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5)
|
|
2324
|
+
sage: C.function_field()
|
|
2325
|
+
Function field in z defined by z^5 + y*z^3 + y^5 + 1
|
|
2326
|
+
"""
|
|
2327
|
+
return self._function_field
|
|
2328
|
+
|
|
2329
|
+
@lazy_attribute
|
|
2330
|
+
def _genus(self):
|
|
2331
|
+
"""
|
|
2332
|
+
The geometric genus of the curve.
|
|
2333
|
+
|
|
2334
|
+
EXAMPLES::
|
|
2335
|
+
|
|
2336
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2)
|
|
2337
|
+
sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5)
|
|
2338
|
+
sage: C.genus() # indirect doctest
|
|
2339
|
+
1
|
|
2340
|
+
"""
|
|
2341
|
+
return self._open_affine.genus()
|
|
2342
|
+
|
|
2343
|
+
def __call__(self, *args):
|
|
2344
|
+
"""
|
|
2345
|
+
Return a rational point, a pointset or a function depending on ``args``.
|
|
2346
|
+
|
|
2347
|
+
EXAMPLES::
|
|
2348
|
+
|
|
2349
|
+
sage: # needs sage.rings.finite_rings
|
|
2350
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2)
|
|
2351
|
+
sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5)
|
|
2352
|
+
sage: C(1,1,1)
|
|
2353
|
+
(1 : 1 : 1)
|
|
2354
|
+
sage: C(y/z)
|
|
2355
|
+
(y/(y^5 + 1))*z^4 + (y^2/(y^5 + 1))*z^2
|
|
2356
|
+
sage: C(GF(4^2))
|
|
2357
|
+
Set of rational points of Closed subscheme of Projective Space of
|
|
2358
|
+
dimension 2 over Finite Field in z4 of size 2^4 defined by:
|
|
2359
|
+
x^5 + y^5 + x*y*z^3 + z^5
|
|
2360
|
+
"""
|
|
2361
|
+
try:
|
|
2362
|
+
return super().__call__(*args)
|
|
2363
|
+
except TypeError as e:
|
|
2364
|
+
try:
|
|
2365
|
+
return self.function(*args)
|
|
2366
|
+
except AttributeError:
|
|
2367
|
+
raise e
|
|
2368
|
+
|
|
2369
|
+
def function(self, f):
|
|
2370
|
+
"""
|
|
2371
|
+
Return the function field element corresponding to ``f``.
|
|
2372
|
+
|
|
2373
|
+
INPUT:
|
|
2374
|
+
|
|
2375
|
+
- ``f`` -- a fraction of homogeneous polynomials of the coordinate ring
|
|
2376
|
+
of the ambient space of the curve
|
|
2377
|
+
|
|
2378
|
+
OUTPUT: an element of the function field
|
|
2379
|
+
|
|
2380
|
+
EXAMPLES::
|
|
2381
|
+
|
|
2382
|
+
sage: # needs sage.rings.finite_rings
|
|
2383
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2)
|
|
2384
|
+
sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5)
|
|
2385
|
+
sage: f = C.function(x/y); f
|
|
2386
|
+
1/y
|
|
2387
|
+
sage: f.divisor()
|
|
2388
|
+
Place (1/y, 1/y^2*z^2 + z2/y*z + 1)
|
|
2389
|
+
+ Place (1/y, 1/y^2*z^2 + ((z2 + 1)/y)*z + 1)
|
|
2390
|
+
+ Place (1/y, 1/y*z + 1)
|
|
2391
|
+
- Place (y, z^2 + z2*z + 1)
|
|
2392
|
+
- Place (y, z^2 + (z2 + 1)*z + 1)
|
|
2393
|
+
- Place (y, z + 1)
|
|
2394
|
+
"""
|
|
2395
|
+
S = self.ambient_space().coordinate_ring()
|
|
2396
|
+
phi = self._map_to_function_field
|
|
2397
|
+
num = S(f.numerator())
|
|
2398
|
+
den = S(f.denominator())
|
|
2399
|
+
if num.degree() != den.degree():
|
|
2400
|
+
raise ValueError("not define a function on the curve")
|
|
2401
|
+
|
|
2402
|
+
return phi(num)/phi(den)
|
|
2403
|
+
|
|
2404
|
+
def coordinate_functions(self, i=None):
|
|
2405
|
+
"""
|
|
2406
|
+
Return the coordinate functions for the ``i``-th affine patch.
|
|
2407
|
+
|
|
2408
|
+
If ``i`` is ``None``, return the homogeneous coordinate functions.
|
|
2409
|
+
|
|
2410
|
+
EXAMPLES::
|
|
2411
|
+
|
|
2412
|
+
sage: # needs sage.rings.finite_rings
|
|
2413
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2)
|
|
2414
|
+
sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5)
|
|
2415
|
+
sage: C.coordinate_functions(0)
|
|
2416
|
+
(y, z)
|
|
2417
|
+
sage: C.coordinate_functions(1)
|
|
2418
|
+
(1/y, 1/y*z)
|
|
2419
|
+
"""
|
|
2420
|
+
coords = self._coordinate_functions
|
|
2421
|
+
if i is None:
|
|
2422
|
+
return coords
|
|
2423
|
+
inv = ~coords[i]
|
|
2424
|
+
return tuple([coords[j]*inv for j in range(len(coords)) if j != i])
|
|
2425
|
+
|
|
2426
|
+
def pull_from_function_field(self, f):
|
|
2427
|
+
"""
|
|
2428
|
+
Return the fraction corresponding to ``f``.
|
|
2429
|
+
|
|
2430
|
+
INPUT:
|
|
2431
|
+
|
|
2432
|
+
- ``f`` -- an element of the function field
|
|
2433
|
+
|
|
2434
|
+
OUTPUT:
|
|
2435
|
+
|
|
2436
|
+
A fraction of homogeneous polynomials in the coordinate ring of the
|
|
2437
|
+
ambient space of the curve.
|
|
2438
|
+
|
|
2439
|
+
EXAMPLES::
|
|
2440
|
+
|
|
2441
|
+
sage: # needs sage.rings.finite_rings
|
|
2442
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(4), 2)
|
|
2443
|
+
sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5)
|
|
2444
|
+
sage: F = C.function_field()
|
|
2445
|
+
sage: C.pull_from_function_field(F.gen())
|
|
2446
|
+
z/x
|
|
2447
|
+
sage: C.pull_from_function_field(F.one())
|
|
2448
|
+
1
|
|
2449
|
+
sage: C.pull_from_function_field(F.zero())
|
|
2450
|
+
0
|
|
2451
|
+
sage: f1 = F.gen()
|
|
2452
|
+
sage: f2 = F.base_ring().gen()
|
|
2453
|
+
sage: C.function(C.pull_from_function_field(f1)) == f1
|
|
2454
|
+
True
|
|
2455
|
+
sage: C.function(C.pull_from_function_field(f2)) == f2
|
|
2456
|
+
True
|
|
2457
|
+
"""
|
|
2458
|
+
return self._map_from_function_field(f)
|
|
2459
|
+
|
|
2460
|
+
@lazy_attribute
|
|
2461
|
+
def _function_field(self):
|
|
2462
|
+
"""
|
|
2463
|
+
Return the abstract function field of the curve.
|
|
2464
|
+
|
|
2465
|
+
TESTS::
|
|
2466
|
+
|
|
2467
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2468
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2469
|
+
sage: C._function_field
|
|
2470
|
+
Function field in z defined by z^8 + 4*y^2*z^7 + 1
|
|
2471
|
+
"""
|
|
2472
|
+
return self._open_affine._function_field
|
|
2473
|
+
|
|
2474
|
+
@lazy_attribute
|
|
2475
|
+
def _map_to_function_field(self):
|
|
2476
|
+
"""
|
|
2477
|
+
Return the map to the function field of the curve.
|
|
2478
|
+
|
|
2479
|
+
TESTS::
|
|
2480
|
+
|
|
2481
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2482
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2483
|
+
sage: C._map_to_function_field
|
|
2484
|
+
Ring morphism:
|
|
2485
|
+
From: Multivariate Polynomial Ring in x, y, z over Finite Field of size 5
|
|
2486
|
+
To: Function field in z defined by z^8 + 4*y^2*z^7 + 1
|
|
2487
|
+
Defn: x |--> 1
|
|
2488
|
+
y |--> y
|
|
2489
|
+
z |--> z
|
|
2490
|
+
"""
|
|
2491
|
+
F = self._function_field
|
|
2492
|
+
S = self.ambient_space().coordinate_ring()
|
|
2493
|
+
return hom(S, F, self._coordinate_functions)
|
|
2494
|
+
|
|
2495
|
+
@lazy_attribute
|
|
2496
|
+
def _coordinate_functions(self):
|
|
2497
|
+
"""
|
|
2498
|
+
Return the homogeneous coordinate functions of the curve.
|
|
2499
|
+
|
|
2500
|
+
TESTS::
|
|
2501
|
+
|
|
2502
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2503
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2504
|
+
sage: C._coordinate_functions
|
|
2505
|
+
(1, y, z)
|
|
2506
|
+
"""
|
|
2507
|
+
# homogeneous coordinate functions
|
|
2508
|
+
coords = list(self._open_affine._coordinate_functions)
|
|
2509
|
+
coords.insert(self._open_affine_index, self._function_field.one())
|
|
2510
|
+
return tuple(coords)
|
|
2511
|
+
|
|
2512
|
+
@lazy_attribute
|
|
2513
|
+
def _map_from_function_field(self):
|
|
2514
|
+
"""
|
|
2515
|
+
Return the map from the function field of the curve.
|
|
2516
|
+
|
|
2517
|
+
TESTS::
|
|
2518
|
+
|
|
2519
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2520
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2521
|
+
sage: F = C.function_field()
|
|
2522
|
+
sage: f = F.random_element()
|
|
2523
|
+
sage: C.function(C._map_from_function_field(f)) == f
|
|
2524
|
+
True
|
|
2525
|
+
"""
|
|
2526
|
+
S = self.ambient_space().coordinate_ring()
|
|
2527
|
+
phi = self._open_affine._nonsingular_model[2]
|
|
2528
|
+
i = self._open_affine_index
|
|
2529
|
+
|
|
2530
|
+
def m(f):
|
|
2531
|
+
pf = phi(f)
|
|
2532
|
+
num = S(pf.numerator()).homogenize(i)
|
|
2533
|
+
den = S(pf.denominator()).homogenize(i)
|
|
2534
|
+
return num / den * S.gen(i) ** (den.total_degree() - num.total_degree())
|
|
2535
|
+
|
|
2536
|
+
return m
|
|
2537
|
+
|
|
2538
|
+
@lazy_attribute
|
|
2539
|
+
def _singularities(self):
|
|
2540
|
+
"""
|
|
2541
|
+
Return a list of the pairs of a singular closed point and the places above it.
|
|
2542
|
+
|
|
2543
|
+
TESTS::
|
|
2544
|
+
|
|
2545
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2546
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2547
|
+
sage: C._singularities
|
|
2548
|
+
[(Point (x, z), [Place (1/y, 1/y*z^5 + 4*y*z^4 + 1/y^2*z)])]
|
|
2549
|
+
sage: D = Curve(x)
|
|
2550
|
+
sage: D._singularities
|
|
2551
|
+
[]
|
|
2552
|
+
"""
|
|
2553
|
+
S = self.ambient_space().coordinate_ring()
|
|
2554
|
+
to_F = self._map_to_function_field
|
|
2555
|
+
sing = self.singular_subscheme() # singular locus
|
|
2556
|
+
|
|
2557
|
+
# for each affine patch, places on which the dehomogenized polynomials
|
|
2558
|
+
# defining the singular locus are collected.
|
|
2559
|
+
places = []
|
|
2560
|
+
for i in range(self.ngens()):
|
|
2561
|
+
denom = self._coordinate_functions[i]
|
|
2562
|
+
if denom:
|
|
2563
|
+
funcs = []
|
|
2564
|
+
for p in S._first_ngens(i) + sing.defining_polynomials():
|
|
2565
|
+
f = to_F(p)/denom**p.degree()
|
|
2566
|
+
if not f.is_zero():
|
|
2567
|
+
funcs.append(f)
|
|
2568
|
+
|
|
2569
|
+
if funcs:
|
|
2570
|
+
f = funcs.pop()
|
|
2571
|
+
pls = f.zeros()
|
|
2572
|
+
for f in funcs:
|
|
2573
|
+
pls = [p for p in pls if f.valuation(p) > 0]
|
|
2574
|
+
|
|
2575
|
+
places.extend(pls)
|
|
2576
|
+
|
|
2577
|
+
# compute closed points below the places lying on the singular locus,
|
|
2578
|
+
# and then collect places lying on each closed points
|
|
2579
|
+
points_and_places = []
|
|
2580
|
+
for place in places:
|
|
2581
|
+
p = self.place_to_closed_point(place)
|
|
2582
|
+
for q, places in points_and_places:
|
|
2583
|
+
if p == q:
|
|
2584
|
+
places.append(place)
|
|
2585
|
+
break
|
|
2586
|
+
else: # new singularity
|
|
2587
|
+
points_and_places.append((p, [place]))
|
|
2588
|
+
|
|
2589
|
+
return points_and_places
|
|
2590
|
+
|
|
2591
|
+
def singular_closed_points(self):
|
|
2592
|
+
"""
|
|
2593
|
+
Return the singular closed points of the curve.
|
|
2594
|
+
|
|
2595
|
+
EXAMPLES::
|
|
2596
|
+
|
|
2597
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
2598
|
+
sage: C = Curve(y^2*z - x^3, P)
|
|
2599
|
+
sage: C.singular_closed_points()
|
|
2600
|
+
[Point (x, y)]
|
|
2601
|
+
|
|
2602
|
+
::
|
|
2603
|
+
|
|
2604
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2605
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2606
|
+
sage: C.singular_closed_points()
|
|
2607
|
+
[Point (x, z)]
|
|
2608
|
+
"""
|
|
2609
|
+
return [p[0] for p in self._singularities]
|
|
2610
|
+
|
|
2611
|
+
@cached_method
|
|
2612
|
+
def place_to_closed_point(self, place):
|
|
2613
|
+
"""
|
|
2614
|
+
Return the closed point at the place.
|
|
2615
|
+
|
|
2616
|
+
INPUT:
|
|
2617
|
+
|
|
2618
|
+
- ``place`` -- a place of the function field of the curve
|
|
2619
|
+
|
|
2620
|
+
EXAMPLES::
|
|
2621
|
+
|
|
2622
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2623
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2624
|
+
sage: pls = C.places()
|
|
2625
|
+
sage: C.place_to_closed_point(pls[-1])
|
|
2626
|
+
Point (x - 2*z, y - 2*z)
|
|
2627
|
+
sage: pls2 = C.places(2)
|
|
2628
|
+
sage: C.place_to_closed_point(pls2[0])
|
|
2629
|
+
Point (y^2 + y*z + z^2, x + y)
|
|
2630
|
+
"""
|
|
2631
|
+
F = self.function_field()
|
|
2632
|
+
|
|
2633
|
+
A = self.ambient_space()
|
|
2634
|
+
S = A.coordinate_ring().change_ring(order='degrevlex') # homogeneous coordinate ring
|
|
2635
|
+
|
|
2636
|
+
# prepare coordinates for the affine patch containing the place
|
|
2637
|
+
vals = [f.valuation(place) for f in self._coordinate_functions]
|
|
2638
|
+
imin = vals.index(min(vals))
|
|
2639
|
+
R = S.remove_var(S.gen(imin))
|
|
2640
|
+
hcoords = self._coordinate_functions
|
|
2641
|
+
coords = [hcoords[i]/hcoords[imin] for i in range(S.ngens()) if i != imin]
|
|
2642
|
+
|
|
2643
|
+
k, from_k, to_k = place.residue_field()
|
|
2644
|
+
V, from_V, to_V = k.vector_space(F.constant_base_field(), map=True)
|
|
2645
|
+
|
|
2646
|
+
# implement an FGLM-like algorithm
|
|
2647
|
+
e = [0 for i in range(R.ngens())]
|
|
2648
|
+
basis = [R.one()]
|
|
2649
|
+
basis_vecs = [to_V(k.one())] # represent as a vector
|
|
2650
|
+
|
|
2651
|
+
gens = []
|
|
2652
|
+
gens_lts = []
|
|
2653
|
+
terminate = False
|
|
2654
|
+
while True: # check FGLM termination condition
|
|
2655
|
+
# compute next exponent in degree reverse lexicographical order
|
|
2656
|
+
j = R.ngens() - 1
|
|
2657
|
+
while j > 0 and not e[j]:
|
|
2658
|
+
j -= 1
|
|
2659
|
+
|
|
2660
|
+
if not j: # j is zero
|
|
2661
|
+
if terminate:
|
|
2662
|
+
break
|
|
2663
|
+
terminate = True
|
|
2664
|
+
d = e[0]
|
|
2665
|
+
e[0] = 0
|
|
2666
|
+
e[-1] = d + 1
|
|
2667
|
+
else:
|
|
2668
|
+
e[j] -= 1
|
|
2669
|
+
e[j-1] += 1
|
|
2670
|
+
|
|
2671
|
+
m = R.monomial(*e)
|
|
2672
|
+
if any(g.divides(m) for g in gens_lts):
|
|
2673
|
+
continue
|
|
2674
|
+
|
|
2675
|
+
prod = 1
|
|
2676
|
+
for i in range(R.ngens()):
|
|
2677
|
+
prod *= coords[i]**e[i]
|
|
2678
|
+
vec = to_V(to_k(prod)) # represent as a vector
|
|
2679
|
+
mat = matrix(basis_vecs)
|
|
2680
|
+
try:
|
|
2681
|
+
s = mat.solve_left(vec)
|
|
2682
|
+
except ValueError: # no solution
|
|
2683
|
+
basis.append(m)
|
|
2684
|
+
basis_vecs.append(vec)
|
|
2685
|
+
terminate = False
|
|
2686
|
+
continue
|
|
2687
|
+
|
|
2688
|
+
gens.append(m - sum([s[i] * basis[i] for i in range(len(basis))]))
|
|
2689
|
+
gens_lts.append(m)
|
|
2690
|
+
|
|
2691
|
+
gens_homo = [S(g).homogenize(imin) for g in gens]
|
|
2692
|
+
prime = S.ideal(gens_homo).groebner_basis().ideal()
|
|
2693
|
+
|
|
2694
|
+
return self._closed_point(self, prime, len(basis))
|
|
2695
|
+
|
|
2696
|
+
def places_on(self, point):
|
|
2697
|
+
"""
|
|
2698
|
+
Return the places on the closed point.
|
|
2699
|
+
|
|
2700
|
+
INPUT:
|
|
2701
|
+
|
|
2702
|
+
- ``point`` -- a closed point of the curve
|
|
2703
|
+
|
|
2704
|
+
EXAMPLES::
|
|
2705
|
+
|
|
2706
|
+
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
|
|
2707
|
+
sage: C = Curve(x*y*z^4 - x^6 - y^6)
|
|
2708
|
+
sage: C.singular_closed_points()
|
|
2709
|
+
[Point (x, y)]
|
|
2710
|
+
sage: p, = _
|
|
2711
|
+
sage: C.places_on(p)
|
|
2712
|
+
[Place (1/y, 1/y^2*z, 1/y^3*z^2, 1/y^4*z^3),
|
|
2713
|
+
Place (y, y*z, y*z^2, y*z^3)]
|
|
2714
|
+
sage: pl1, pl2 =_
|
|
2715
|
+
sage: C.place_to_closed_point(pl1)
|
|
2716
|
+
Point (x, y)
|
|
2717
|
+
sage: C.place_to_closed_point(pl2)
|
|
2718
|
+
Point (x, y)
|
|
2719
|
+
|
|
2720
|
+
::
|
|
2721
|
+
|
|
2722
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2723
|
+
sage: C = Curve(x^2*z - y^3)
|
|
2724
|
+
sage: [C.places_on(p) for p in C.closed_points()]
|
|
2725
|
+
[[Place (1/y)],
|
|
2726
|
+
[Place (y)],
|
|
2727
|
+
[Place (y + 1)],
|
|
2728
|
+
[Place (y + 2)],
|
|
2729
|
+
[Place (y + 3)],
|
|
2730
|
+
[Place (y + 4)]]
|
|
2731
|
+
"""
|
|
2732
|
+
prime = point.prime_ideal()
|
|
2733
|
+
|
|
2734
|
+
# determine the affine patch where the point lies
|
|
2735
|
+
S = prime.ring()
|
|
2736
|
+
for i in range(S.ngens()):
|
|
2737
|
+
if S.gen(i) not in prime:
|
|
2738
|
+
break
|
|
2739
|
+
|
|
2740
|
+
phi = self._map_to_function_field
|
|
2741
|
+
denom = self._coordinate_functions[i]
|
|
2742
|
+
gs = [phi(f)/denom**f.degree() for f in prime.gens()]
|
|
2743
|
+
fs = [g for g in gs if not g.is_zero()]
|
|
2744
|
+
f = fs.pop()
|
|
2745
|
+
places = []
|
|
2746
|
+
for p in f.zeros():
|
|
2747
|
+
if all(f.valuation(p) > 0 for f in fs):
|
|
2748
|
+
places.append(p)
|
|
2749
|
+
return places
|
|
2750
|
+
|
|
2751
|
+
def jacobian(self, model, base_div=None):
|
|
2752
|
+
"""
|
|
2753
|
+
Return the Jacobian of this curve.
|
|
2754
|
+
|
|
2755
|
+
INPUT:
|
|
2756
|
+
|
|
2757
|
+
- ``model`` -- model to use for arithmetic
|
|
2758
|
+
|
|
2759
|
+
- ``base_div`` -- an effective divisor for the model
|
|
2760
|
+
|
|
2761
|
+
The degree of the base divisor should satisfy certain degree condition
|
|
2762
|
+
corresponding to the model used. The following table lists these
|
|
2763
|
+
conditions. Let `g` be the geometric genus of the curve.
|
|
2764
|
+
|
|
2765
|
+
- ``hess``: ideal-based arithmetic; requires base divisor of degree `g`
|
|
2766
|
+
|
|
2767
|
+
- ``km_large``: Khuri-Makdisi's large model; requires base divisor of
|
|
2768
|
+
degree at least `2g + 1`
|
|
2769
|
+
|
|
2770
|
+
- ``km_medium``: Khuri-Makdisi's medium model; requires base divisor of
|
|
2771
|
+
degree at least `2g + 1`
|
|
2772
|
+
|
|
2773
|
+
- ``km_small``: Khuri-Makdisi's small model requires base divisor of
|
|
2774
|
+
degree at least `g + 1`
|
|
2775
|
+
|
|
2776
|
+
We assume the curve (or its function field) has a rational place. If a
|
|
2777
|
+
base divisor is not given, one is chosen using a rational place.
|
|
2778
|
+
|
|
2779
|
+
EXAMPLES::
|
|
2780
|
+
|
|
2781
|
+
sage: A.<x,y> = AffineSpace(GF(5), 2)
|
|
2782
|
+
sage: C = Curve(y^2*(x^3 - 1) - (x^3 - 2)).projective_closure()
|
|
2783
|
+
sage: J = C.jacobian(model='hess'); J
|
|
2784
|
+
Jacobian of Projective Plane Curve over Finite Field of size 5
|
|
2785
|
+
defined by 2*x0^5 - x0^2*x1^3 - x0^3*x2^2 + x1^3*x2^2 (Hess model)
|
|
2786
|
+
sage: J.base_divisor().degree() == C.genus()
|
|
2787
|
+
True
|
|
2788
|
+
"""
|
|
2789
|
+
return self.function_field().jacobian(model, base_div, curve=self)
|
|
2790
|
+
|
|
2791
|
+
|
|
2792
|
+
class IntegralProjectiveCurve_finite_field(IntegralProjectiveCurve):
|
|
2793
|
+
"""
|
|
2794
|
+
Integral projective curve over a finite field.
|
|
2795
|
+
|
|
2796
|
+
INPUT:
|
|
2797
|
+
|
|
2798
|
+
- ``A`` -- an ambient projective space
|
|
2799
|
+
|
|
2800
|
+
- ``f`` -- homogeneous polynomials defining the curve
|
|
2801
|
+
|
|
2802
|
+
EXAMPLES::
|
|
2803
|
+
|
|
2804
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2805
|
+
sage: C = Curve(y^2*z^7 - x^9 - x*z^8)
|
|
2806
|
+
sage: C.function_field()
|
|
2807
|
+
Function field in z defined by z^8 + 4*y^2*z^7 + 1
|
|
2808
|
+
sage: C.closed_points()
|
|
2809
|
+
[Point (x, z),
|
|
2810
|
+
Point (x, y),
|
|
2811
|
+
Point (x - 2*z, y + 2*z),
|
|
2812
|
+
Point (x + 2*z, y + z),
|
|
2813
|
+
Point (x + 2*z, y - z),
|
|
2814
|
+
Point (x - 2*z, y - 2*z)]
|
|
2815
|
+
"""
|
|
2816
|
+
_point = IntegralProjectiveCurvePoint_finite_field
|
|
2817
|
+
|
|
2818
|
+
def places(self, degree=1):
|
|
2819
|
+
"""
|
|
2820
|
+
Return all places on the curve of the ``degree``.
|
|
2821
|
+
|
|
2822
|
+
INPUT:
|
|
2823
|
+
|
|
2824
|
+
- ``degree`` -- positive integer
|
|
2825
|
+
|
|
2826
|
+
EXAMPLES::
|
|
2827
|
+
|
|
2828
|
+
sage: P.<x,y,z> = ProjectiveSpace(GF(5), 2)
|
|
2829
|
+
sage: C = Curve(x^2*z - y^3)
|
|
2830
|
+
sage: C.places()
|
|
2831
|
+
[Place (1/y),
|
|
2832
|
+
Place (y),
|
|
2833
|
+
Place (y + 1),
|
|
2834
|
+
Place (y + 2),
|
|
2835
|
+
Place (y + 3),
|
|
2836
|
+
Place (y + 4)]
|
|
2837
|
+
sage: C.places(2)
|
|
2838
|
+
[Place (y^2 + 2),
|
|
2839
|
+
Place (y^2 + 3),
|
|
2840
|
+
Place (y^2 + y + 1),
|
|
2841
|
+
Place (y^2 + y + 2),
|
|
2842
|
+
Place (y^2 + 2*y + 3),
|
|
2843
|
+
Place (y^2 + 2*y + 4),
|
|
2844
|
+
Place (y^2 + 3*y + 3),
|
|
2845
|
+
Place (y^2 + 3*y + 4),
|
|
2846
|
+
Place (y^2 + 4*y + 1),
|
|
2847
|
+
Place (y^2 + 4*y + 2)]
|
|
2848
|
+
"""
|
|
2849
|
+
F = self.function_field()
|
|
2850
|
+
return F.places(degree)
|
|
2851
|
+
|
|
2852
|
+
def closed_points(self, degree=1):
|
|
2853
|
+
"""
|
|
2854
|
+
Return a list of closed points of ``degree`` of the curve.
|
|
2855
|
+
|
|
2856
|
+
INPUT:
|
|
2857
|
+
|
|
2858
|
+
- ``degree`` -- positive integer
|
|
2859
|
+
|
|
2860
|
+
EXAMPLES::
|
|
2861
|
+
|
|
2862
|
+
sage: # needs sage.rings.finite_rings
|
|
2863
|
+
sage: A.<x,y> = AffineSpace(GF(9),2)
|
|
2864
|
+
sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x-2)
|
|
2865
|
+
sage: Cp = C.projective_closure()
|
|
2866
|
+
sage: Cp.closed_points()
|
|
2867
|
+
[Point (x0, x1),
|
|
2868
|
+
Point (x0 + (-z2 - 1)*x2, x1),
|
|
2869
|
+
Point (x0 + (z2 + 1)*x2, x1),
|
|
2870
|
+
Point (x0 + z2*x2, x1 + (z2 - 1)*x2),
|
|
2871
|
+
Point (x0 + (-z2)*x2, x1 + (-z2 + 1)*x2),
|
|
2872
|
+
Point (x0 + (-z2 - 1)*x2, x1 + (-z2 - 1)*x2),
|
|
2873
|
+
Point (x0 + (z2 + 1)*x2, x1 + (z2 + 1)*x2),
|
|
2874
|
+
Point (x0 + (z2 - 1)*x2, x1 + z2*x2),
|
|
2875
|
+
Point (x0 + (-z2 + 1)*x2, x1 + (-z2)*x2),
|
|
2876
|
+
Point (x0 + x2, x1 - x2),
|
|
2877
|
+
Point (x0 - x2, x1 + x2)]
|
|
2878
|
+
"""
|
|
2879
|
+
F = self.function_field()
|
|
2880
|
+
places_above = F.places(degree)
|
|
2881
|
+
|
|
2882
|
+
points = []
|
|
2883
|
+
|
|
2884
|
+
# consider singular points
|
|
2885
|
+
for p in self.singular_closed_points():
|
|
2886
|
+
if p.degree() == degree:
|
|
2887
|
+
points.append(p)
|
|
2888
|
+
for place in p.places():
|
|
2889
|
+
if place.degree() == degree:
|
|
2890
|
+
places_above.remove(place)
|
|
2891
|
+
|
|
2892
|
+
for place in places_above:
|
|
2893
|
+
p = self.place_to_closed_point(place)
|
|
2894
|
+
assert p.degree() == degree # sanity check
|
|
2895
|
+
points.append(p)
|
|
2896
|
+
|
|
2897
|
+
return points
|
|
2898
|
+
|
|
2899
|
+
@cached_method
|
|
2900
|
+
def L_polynomial(self, name='t'):
|
|
2901
|
+
"""
|
|
2902
|
+
Return the L-polynomial of this possibly singular curve.
|
|
2903
|
+
|
|
2904
|
+
INPUT:
|
|
2905
|
+
|
|
2906
|
+
- ``name`` -- (default: ``t``) name of the variable of the polynomial
|
|
2907
|
+
|
|
2908
|
+
EXAMPLES::
|
|
2909
|
+
|
|
2910
|
+
sage: A.<x,y> = AffineSpace(GF(3), 2)
|
|
2911
|
+
sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2)
|
|
2912
|
+
sage: Cbar = C.projective_closure()
|
|
2913
|
+
sage: Cbar.L_polynomial()
|
|
2914
|
+
9*t^4 - 3*t^3 + t^2 - t + 1
|
|
2915
|
+
"""
|
|
2916
|
+
F = self.function_field()
|
|
2917
|
+
L = F.L_polynomial()
|
|
2918
|
+
|
|
2919
|
+
R = L.parent()
|
|
2920
|
+
T = R.gen()
|
|
2921
|
+
|
|
2922
|
+
f = R.one()
|
|
2923
|
+
for p, places in self._singularities:
|
|
2924
|
+
for place in places:
|
|
2925
|
+
f = f * (1 - T**place.degree())
|
|
2926
|
+
f = f // (1 - T**p.degree())
|
|
2927
|
+
|
|
2928
|
+
return L * f
|
|
2929
|
+
|
|
2930
|
+
def number_of_rational_points(self, r=1):
|
|
2931
|
+
"""
|
|
2932
|
+
Return the number of rational points of the curve with
|
|
2933
|
+
constant field extended by degree ``r``.
|
|
2934
|
+
|
|
2935
|
+
INPUT:
|
|
2936
|
+
|
|
2937
|
+
- ``r`` -- positive integer (default: `1`)
|
|
2938
|
+
|
|
2939
|
+
EXAMPLES::
|
|
2940
|
+
|
|
2941
|
+
sage: # needs sage.rings.finite_rings
|
|
2942
|
+
sage: A.<x,y> = AffineSpace(GF(3), 2)
|
|
2943
|
+
sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2)
|
|
2944
|
+
sage: Cbar = C.projective_closure()
|
|
2945
|
+
sage: Cbar.number_of_rational_points(3)
|
|
2946
|
+
21
|
|
2947
|
+
sage: D = Cbar.change_ring(Cbar.base_ring().extension(3))
|
|
2948
|
+
sage: D.base_ring()
|
|
2949
|
+
Finite Field in z3 of size 3^3
|
|
2950
|
+
sage: len(D.closed_points())
|
|
2951
|
+
21
|
|
2952
|
+
"""
|
|
2953
|
+
q = self.base_ring().order()
|
|
2954
|
+
L = self.L_polynomial()
|
|
2955
|
+
Lp = L.derivative()
|
|
2956
|
+
|
|
2957
|
+
R = IntegerRing()[[L.parent().gen()]] # power series ring
|
|
2958
|
+
L = R(L)
|
|
2959
|
+
Lp = R(Lp)
|
|
2960
|
+
|
|
2961
|
+
f = R(Lp / L, prec=r)
|
|
2962
|
+
n = f[r-1] + q**r + 1
|
|
2963
|
+
|
|
2964
|
+
return n
|
|
2965
|
+
|
|
2966
|
+
|
|
2967
|
+
class IntegralProjectivePlaneCurve(IntegralProjectiveCurve, ProjectivePlaneCurve_field):
|
|
2968
|
+
_point = IntegralProjectivePlaneCurvePoint
|
|
2969
|
+
|
|
2970
|
+
|
|
2971
|
+
class IntegralProjectivePlaneCurve_finite_field(IntegralProjectiveCurve_finite_field,
|
|
2972
|
+
ProjectivePlaneCurve_finite_field):
|
|
2973
|
+
"""
|
|
2974
|
+
Integral projective plane curve over a finite field.
|
|
2975
|
+
|
|
2976
|
+
INPUT:
|
|
2977
|
+
|
|
2978
|
+
- ``A`` -- ambient projective plane
|
|
2979
|
+
|
|
2980
|
+
- ``f`` -- a homogeneous equation that defines the curve
|
|
2981
|
+
|
|
2982
|
+
EXAMPLES::
|
|
2983
|
+
|
|
2984
|
+
sage: # needs sage.rings.finite_rings
|
|
2985
|
+
sage: A.<x,y> = AffineSpace(GF(9), 2)
|
|
2986
|
+
sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2)
|
|
2987
|
+
sage: Cb = C.projective_closure()
|
|
2988
|
+
sage: Cb.singular_closed_points()
|
|
2989
|
+
[Point (x0, x1)]
|
|
2990
|
+
sage: Cb.function_field()
|
|
2991
|
+
Function field in y defined by y^2 + 2*x^5 + 2*x^4 + x^3 + x + 1
|
|
2992
|
+
"""
|
|
2993
|
+
_point = IntegralProjectivePlaneCurvePoint_finite_field
|
|
2994
|
+
|
|
2995
|
+
|
|
2996
|
+
def Hasse_bounds(q, genus=1):
|
|
2997
|
+
r"""
|
|
2998
|
+
Return the Hasse-Weil bounds for the cardinality of a nonsingular
|
|
2999
|
+
curve defined over `\GF{q}` of given ``genus``.
|
|
3000
|
+
|
|
3001
|
+
INPUT:
|
|
3002
|
+
|
|
3003
|
+
- ``q`` -- integer; a prime power
|
|
3004
|
+
|
|
3005
|
+
- ``genus`` -- nonnegative integer (default: 1)
|
|
3006
|
+
|
|
3007
|
+
OUTPUT: tuple; the Hasse bounds (lb,ub) for the cardinality of a curve of
|
|
3008
|
+
genus ``genus`` defined over `\GF{q}`
|
|
3009
|
+
|
|
3010
|
+
EXAMPLES::
|
|
3011
|
+
|
|
3012
|
+
sage: Hasse_bounds(2)
|
|
3013
|
+
(1, 5)
|
|
3014
|
+
sage: Hasse_bounds(next_prime(10^30)) # needs sage.libs.pari
|
|
3015
|
+
(999999999999998000000000000058, 1000000000000002000000000000058)
|
|
3016
|
+
"""
|
|
3017
|
+
if genus == 1:
|
|
3018
|
+
rq = (4*q).isqrt()
|
|
3019
|
+
else:
|
|
3020
|
+
rq = (4*(genus**2)*q).isqrt()
|
|
3021
|
+
return (q+1-rq, q+1+rq)
|
|
3022
|
+
|
|
3023
|
+
|
|
3024
|
+
# Fix pickles from changing class names and plane_curves folder name
|
|
3025
|
+
register_unpickle_override('sage.schemes.plane_curves.projective_curve',
|
|
3026
|
+
'ProjectiveCurve_generic', ProjectivePlaneCurve)
|