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.

Files changed (314) hide show
  1. passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
  2. passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
  3. passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
  4. passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
  5. passagemath_schemes/__init__.py +3 -0
  6. passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
  7. passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
  8. passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
  9. passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
  11. sage/all__sagemath_schemes.py +23 -0
  12. sage/databases/all__sagemath_schemes.py +7 -0
  13. sage/databases/cremona.py +1723 -0
  14. sage/dynamics/all__sagemath_schemes.py +2 -0
  15. sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
  16. sage/dynamics/arithmetic_dynamics/all.py +14 -0
  17. sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
  18. sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
  19. sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
  20. sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
  21. sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
  22. sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
  23. sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
  24. sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
  25. sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
  26. sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +745 -0
  29. sage/lfunctions/pari.py +818 -0
  30. sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
  31. sage/lfunctions/zero_sums.pyx +1847 -0
  32. sage/modular/abvar/abvar.py +5135 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
  34. sage/modular/abvar/abvar_newform.py +244 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +186 -0
  37. sage/modular/abvar/cuspidal_subgroup.py +371 -0
  38. sage/modular/abvar/finite_subgroup.py +896 -0
  39. sage/modular/abvar/homology.py +720 -0
  40. sage/modular/abvar/homspace.py +998 -0
  41. sage/modular/abvar/lseries.py +415 -0
  42. sage/modular/abvar/morphism.py +935 -0
  43. sage/modular/abvar/torsion_point.py +274 -0
  44. sage/modular/abvar/torsion_subgroup.py +740 -0
  45. sage/modular/all.py +43 -0
  46. sage/modular/arithgroup/all.py +20 -0
  47. sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
  48. sage/modular/arithgroup/arithgroup_element.pyx +474 -0
  49. sage/modular/arithgroup/arithgroup_generic.py +1402 -0
  50. sage/modular/arithgroup/arithgroup_perm.py +2692 -0
  51. sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
  52. sage/modular/arithgroup/congroup.pyx +334 -0
  53. sage/modular/arithgroup/congroup_gamma.py +363 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +653 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1469 -0
  57. sage/modular/arithgroup/congroup_generic.py +628 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +267 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1066 -0
  61. sage/modular/arithgroup/tests.py +418 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3753 -0
  64. sage/modular/btquotients/pautomorphicform.py +2570 -0
  65. sage/modular/buzzard.py +100 -0
  66. sage/modular/congroup.py +29 -0
  67. sage/modular/congroup_element.py +13 -0
  68. sage/modular/cusps.py +1109 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +569 -0
  71. sage/modular/dirichlet.py +3310 -0
  72. sage/modular/drinfeld_modform/all.py +2 -0
  73. sage/modular/drinfeld_modform/element.py +446 -0
  74. sage/modular/drinfeld_modform/ring.py +773 -0
  75. sage/modular/drinfeld_modform/tutorial.py +236 -0
  76. sage/modular/etaproducts.py +1065 -0
  77. sage/modular/hecke/algebra.py +746 -0
  78. sage/modular/hecke/all.py +20 -0
  79. sage/modular/hecke/ambient_module.py +1019 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +325 -0
  82. sage/modular/hecke/hecke_operator.py +780 -0
  83. sage/modular/hecke/homspace.py +206 -0
  84. sage/modular/hecke/module.py +1767 -0
  85. sage/modular/hecke/morphism.py +174 -0
  86. sage/modular/hecke/submodule.py +989 -0
  87. sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
  88. sage/modular/hypergeometric_misc.pxd +4 -0
  89. sage/modular/hypergeometric_misc.pyx +166 -0
  90. sage/modular/hypergeometric_motive.py +2017 -0
  91. sage/modular/local_comp/all.py +2 -0
  92. sage/modular/local_comp/liftings.py +292 -0
  93. sage/modular/local_comp/local_comp.py +1071 -0
  94. sage/modular/local_comp/smoothchar.py +1825 -0
  95. sage/modular/local_comp/type_space.py +748 -0
  96. sage/modular/modform/all.py +30 -0
  97. sage/modular/modform/ambient.py +815 -0
  98. sage/modular/modform/ambient_R.py +177 -0
  99. sage/modular/modform/ambient_eps.py +306 -0
  100. sage/modular/modform/ambient_g0.py +124 -0
  101. sage/modular/modform/ambient_g1.py +204 -0
  102. sage/modular/modform/constructor.py +545 -0
  103. sage/modular/modform/cuspidal_submodule.py +708 -0
  104. sage/modular/modform/defaults.py +14 -0
  105. sage/modular/modform/eis_series.py +505 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4131 -0
  108. sage/modular/modform/find_generators.py +59 -0
  109. sage/modular/modform/half_integral.py +154 -0
  110. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  111. sage/modular/modform/j_invariant.py +47 -0
  112. sage/modular/modform/l_series_gross_zagier.py +133 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
  114. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  115. sage/modular/modform/notes.py +45 -0
  116. sage/modular/modform/numerical.py +514 -0
  117. sage/modular/modform/periods.py +14 -0
  118. sage/modular/modform/ring.py +1257 -0
  119. sage/modular/modform/space.py +1860 -0
  120. sage/modular/modform/submodule.py +118 -0
  121. sage/modular/modform/tests.py +64 -0
  122. sage/modular/modform/theta.py +110 -0
  123. sage/modular/modform/vm_basis.py +381 -0
  124. sage/modular/modform/weight1.py +220 -0
  125. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  126. sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
  127. sage/modular/modform_hecketriangle/all.py +30 -0
  128. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  129. sage/modular/modform_hecketriangle/constructor.py +416 -0
  130. sage/modular/modform_hecketriangle/element.py +351 -0
  131. sage/modular/modform_hecketriangle/functors.py +752 -0
  132. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  133. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
  135. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
  136. sage/modular/modform_hecketriangle/readme.py +1214 -0
  137. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  138. sage/modular/modform_hecketriangle/space.py +1037 -0
  139. sage/modular/modform_hecketriangle/subspace.py +423 -0
  140. sage/modular/modsym/all.py +17 -0
  141. sage/modular/modsym/ambient.py +3846 -0
  142. sage/modular/modsym/boundary.py +1420 -0
  143. sage/modular/modsym/element.py +336 -0
  144. sage/modular/modsym/g1list.py +178 -0
  145. sage/modular/modsym/ghlist.py +182 -0
  146. sage/modular/modsym/hecke_operator.py +73 -0
  147. sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
  148. sage/modular/modsym/manin_symbol.pxd +5 -0
  149. sage/modular/modsym/manin_symbol.pyx +497 -0
  150. sage/modular/modsym/manin_symbol_list.py +1295 -0
  151. sage/modular/modsym/modsym.py +400 -0
  152. sage/modular/modsym/modular_symbols.py +384 -0
  153. sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
  154. sage/modular/modsym/p1list.pxd +29 -0
  155. sage/modular/modsym/p1list.pyx +1372 -0
  156. sage/modular/modsym/p1list_nf.py +1241 -0
  157. sage/modular/modsym/relation_matrix.py +591 -0
  158. sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
  159. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  160. sage/modular/modsym/space.py +2468 -0
  161. sage/modular/modsym/subspace.py +455 -0
  162. sage/modular/modsym/tests.py +375 -0
  163. sage/modular/multiple_zeta.py +2632 -0
  164. sage/modular/multiple_zeta_F_algebra.py +786 -0
  165. sage/modular/overconvergent/all.py +6 -0
  166. sage/modular/overconvergent/genus0.py +1878 -0
  167. sage/modular/overconvergent/hecke_series.py +1187 -0
  168. sage/modular/overconvergent/weightspace.py +778 -0
  169. sage/modular/pollack_stevens/all.py +4 -0
  170. sage/modular/pollack_stevens/distributions.py +874 -0
  171. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  172. sage/modular/pollack_stevens/manin_map.py +859 -0
  173. sage/modular/pollack_stevens/modsym.py +1593 -0
  174. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  175. sage/modular/pollack_stevens/sigma0.py +534 -0
  176. sage/modular/pollack_stevens/space.py +1076 -0
  177. sage/modular/quasimodform/all.py +3 -0
  178. sage/modular/quasimodform/element.py +845 -0
  179. sage/modular/quasimodform/ring.py +828 -0
  180. sage/modular/quatalg/all.py +3 -0
  181. sage/modular/quatalg/brandt.py +1642 -0
  182. sage/modular/ssmod/all.py +8 -0
  183. sage/modular/ssmod/ssmod.py +827 -0
  184. sage/rings/all__sagemath_schemes.py +1 -0
  185. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  186. sage/rings/polynomial/binary_form_reduce.py +585 -0
  187. sage/schemes/all.py +41 -0
  188. sage/schemes/berkovich/all.py +6 -0
  189. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  190. sage/schemes/berkovich/berkovich_space.py +748 -0
  191. sage/schemes/curves/affine_curve.py +2928 -0
  192. sage/schemes/curves/all.py +33 -0
  193. sage/schemes/curves/closed_point.py +434 -0
  194. sage/schemes/curves/constructor.py +381 -0
  195. sage/schemes/curves/curve.py +542 -0
  196. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  197. sage/schemes/curves/point.py +463 -0
  198. sage/schemes/curves/projective_curve.py +3026 -0
  199. sage/schemes/curves/zariski_vankampen.py +1932 -0
  200. sage/schemes/cyclic_covers/all.py +2 -0
  201. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  202. sage/schemes/cyclic_covers/constructor.py +137 -0
  203. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  204. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  205. sage/schemes/elliptic_curves/BSD.py +1036 -0
  206. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  207. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  208. sage/schemes/elliptic_curves/all.py +49 -0
  209. sage/schemes/elliptic_curves/cardinality.py +609 -0
  210. sage/schemes/elliptic_curves/cm.py +1102 -0
  211. sage/schemes/elliptic_curves/constructor.py +1552 -0
  212. sage/schemes/elliptic_curves/ec_database.py +175 -0
  213. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
  214. sage/schemes/elliptic_curves/ell_egros.py +459 -0
  215. sage/schemes/elliptic_curves/ell_field.py +2836 -0
  216. sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
  217. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  218. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  219. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  220. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  221. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  222. sage/schemes/elliptic_curves/ell_point.py +4787 -0
  223. sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
  224. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  225. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  226. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  227. sage/schemes/elliptic_curves/formal_group.py +760 -0
  228. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  229. sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
  230. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  231. sage/schemes/elliptic_curves/heegner.py +7335 -0
  232. sage/schemes/elliptic_curves/height.py +2109 -0
  233. sage/schemes/elliptic_curves/hom.py +1406 -0
  234. sage/schemes/elliptic_curves/hom_composite.py +934 -0
  235. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  236. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  237. sage/schemes/elliptic_curves/hom_sum.py +682 -0
  238. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  239. sage/schemes/elliptic_curves/homset.py +271 -0
  240. sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
  241. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  242. sage/schemes/elliptic_curves/jacobian.py +237 -0
  243. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  244. sage/schemes/elliptic_curves/kraus.py +1014 -0
  245. sage/schemes/elliptic_curves/lseries_ell.py +943 -0
  246. sage/schemes/elliptic_curves/mod5family.py +105 -0
  247. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  248. sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
  249. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  250. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  251. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  252. sage/schemes/elliptic_curves/padics.py +1816 -0
  253. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  254. sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
  255. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  256. sage/schemes/elliptic_curves/saturation.py +715 -0
  257. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  258. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  259. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  260. sage/schemes/hyperelliptic_curves/all.py +6 -0
  261. sage/schemes/hyperelliptic_curves/constructor.py +291 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
  265. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  266. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  267. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
  271. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  272. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
  273. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  274. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  275. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
  276. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  277. sage/schemes/jacobians/all.py +2 -0
  278. sage/schemes/overview.py +161 -0
  279. sage/schemes/plane_conics/all.py +22 -0
  280. sage/schemes/plane_conics/con_field.py +1296 -0
  281. sage/schemes/plane_conics/con_finite_field.py +158 -0
  282. sage/schemes/plane_conics/con_number_field.py +456 -0
  283. sage/schemes/plane_conics/con_rational_field.py +406 -0
  284. sage/schemes/plane_conics/con_rational_function_field.py +580 -0
  285. sage/schemes/plane_conics/constructor.py +249 -0
  286. sage/schemes/plane_quartics/all.py +2 -0
  287. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  288. sage/schemes/plane_quartics/quartic_generic.py +73 -0
  289. sage/schemes/riemann_surfaces/all.py +1 -0
  290. sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
  291. sage_wheels/share/cremona/cremona_mini.db +0 -0
  292. sage_wheels/share/ellcurves/rank0 +30427 -0
  293. sage_wheels/share/ellcurves/rank1 +31871 -0
  294. sage_wheels/share/ellcurves/rank10 +6 -0
  295. sage_wheels/share/ellcurves/rank11 +6 -0
  296. sage_wheels/share/ellcurves/rank12 +1 -0
  297. sage_wheels/share/ellcurves/rank14 +1 -0
  298. sage_wheels/share/ellcurves/rank15 +1 -0
  299. sage_wheels/share/ellcurves/rank17 +1 -0
  300. sage_wheels/share/ellcurves/rank19 +1 -0
  301. sage_wheels/share/ellcurves/rank2 +2388 -0
  302. sage_wheels/share/ellcurves/rank20 +1 -0
  303. sage_wheels/share/ellcurves/rank21 +1 -0
  304. sage_wheels/share/ellcurves/rank22 +1 -0
  305. sage_wheels/share/ellcurves/rank23 +1 -0
  306. sage_wheels/share/ellcurves/rank24 +1 -0
  307. sage_wheels/share/ellcurves/rank28 +1 -0
  308. sage_wheels/share/ellcurves/rank3 +836 -0
  309. sage_wheels/share/ellcurves/rank4 +10 -0
  310. sage_wheels/share/ellcurves/rank5 +5 -0
  311. sage_wheels/share/ellcurves/rank6 +5 -0
  312. sage_wheels/share/ellcurves/rank7 +5 -0
  313. sage_wheels/share/ellcurves/rank8 +6 -0
  314. sage_wheels/share/ellcurves/rank9 +7 -0
@@ -0,0 +1,2928 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ # sage.doctest: needs sage.libs.singular
3
+ r"""
4
+ Affine curves
5
+
6
+ Affine curves in Sage are curves in an affine space or an affine plane.
7
+
8
+ EXAMPLES:
9
+
10
+ We can construct curves in either an affine plane::
11
+
12
+ sage: A.<x,y> = AffineSpace(QQ, 2)
13
+ sage: C = Curve([y - x^2], A); C
14
+ Affine Plane Curve over Rational Field defined by -x^2 + y
15
+
16
+ or in higher dimensional affine space::
17
+
18
+ sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
19
+ sage: C = Curve([y - x^2, z - w^3, w - y^4], A); C
20
+ Affine Curve over Rational Field defined by -x^2 + y, -w^3 + z, -y^4 + w
21
+
22
+ Integral affine 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.<a> = GF(2)
33
+ sage: A.<x,y,z> = AffineSpace(k, 3)
34
+ sage: C = Curve([x^2 + x - y^3, y^4 - y - z^3], A)
35
+ sage: C.genus()
36
+ 10
37
+ sage: C.function_field()
38
+ Function field in z defined by z^9 + x^8 + x^6 + x^5 + x^4 + x^3 + x
39
+
40
+ Closed points of arbitrary degree can be computed::
41
+
42
+ sage: # long time
43
+ sage: C.closed_points()
44
+ [Point (x, y, z), Point (x + 1, y, z)]
45
+ sage: C.closed_points(2)
46
+ [Point (x^2 + x + 1, y + 1, z),
47
+ Point (y^2 + y + 1, x + y, z),
48
+ Point (y^2 + y + 1, x + y + 1, z)]
49
+ sage: p = _[0]
50
+ sage: p.places()
51
+ [Place (x^2 + x + 1, (1/(x^4 + x^2 + 1))*z^7 + (1/(x^4 + x^2 + 1))*z^6 + 1)]
52
+
53
+ The places at infinity correspond to the extra closed points of the curve's
54
+ projective closure::
55
+
56
+ sage: C.places_at_infinity() # long time
57
+ [Place (1/x, 1/x*z)]
58
+
59
+ It is easy to transit to and from the function field of the curve::
60
+
61
+ sage: fx = C(x)
62
+ sage: fy = C(y)
63
+ sage: fx^2 + fx - fy^3
64
+ 0
65
+ sage: fx.divisor()
66
+ -9*Place (1/x, 1/x*z)
67
+ + 9*Place (x, z)
68
+ sage: p, = fx.zeros()
69
+ sage: C.place_to_closed_point(p)
70
+ Point (x, y, z)
71
+ sage: _.rational_point()
72
+ (0, 0, 0)
73
+ sage: _.closed_point()
74
+ Point (x, y, z)
75
+ sage: _.place()
76
+ Place (x, z)
77
+
78
+ Integral affine curves over `\QQ`
79
+ ---------------------------------
80
+
81
+ An integral curve over `\QQ` is equipped also with the function field. Unlike
82
+ over finite fields, it is not possible to enumerate closed points.
83
+
84
+ EXAMPLES::
85
+
86
+ sage: A.<x,y> = AffineSpace(QQ, 2)
87
+ sage: C = Curve(x^2 + y^2 -1)
88
+ sage: p = C(0,1)
89
+ sage: p
90
+ (0, 1)
91
+ sage: p.closed_point()
92
+ Point (x, y - 1)
93
+ sage: pl = _.place()
94
+ sage: C.parametric_representation(pl)
95
+ (s + ..., 1 - 1/2*s^2 - 1/8*s^4 - 1/16*s^6 + ...)
96
+ sage: sx, sy = _
97
+ sage: sx = sx.polynomial(10); sx
98
+ s
99
+ sage: sy = sy.polynomial(10); sy
100
+ -7/256*s^10 - 5/128*s^8 - 1/16*s^6 - 1/8*s^4 - 1/2*s^2 + 1
101
+ sage: s = var('s') # needs sage.symbolic
102
+ sage: P1 = parametric_plot([sx, sy], (s, -1, 1), color='red') # needs sage.plot sage.symbolic
103
+ sage: P2 = C.plot((x, -1, 1), (y, 0, 2)) # half circle # needs sage.plot sage.symbolic
104
+ sage: P1 + P2 # needs sage.plot sage.symbolic
105
+ Graphics object consisting of 2 graphics primitives
106
+
107
+ AUTHORS:
108
+
109
+ - William Stein (2005-11-13)
110
+
111
+ - David Joyner (2005-11-13)
112
+
113
+ - David Kohel (2006-01)
114
+
115
+ - Grayson Jorgenson (2016-08)
116
+
117
+ - Kwankyu Lee (2019-05): added integral affine curves
118
+ """
119
+ # ****************************************************************************
120
+ # Copyright (C) 2005 William Stein <wstein@gmail.com>
121
+ #
122
+ # Distributed under the terms of the GNU General Public License (GPL)
123
+ # as published by the Free Software Foundation; either version 2 of
124
+ # the License, or (at your option) any later version.
125
+ # https://www.gnu.org/licenses/
126
+ # ****************************************************************************
127
+
128
+ from builtins import sum as add
129
+
130
+ import sage.rings.abc
131
+
132
+ from sage.arith.misc import binomial
133
+ from sage.categories.fields import Fields
134
+ from sage.categories.finite_fields import FiniteFields
135
+ from sage.categories.homset import Hom, End, hom
136
+ from sage.categories.number_fields import NumberFields
137
+ from sage.matrix.constructor import matrix
138
+ from sage.misc.cachefunc import cached_method
139
+ from sage.misc.lazy_attribute import lazy_attribute
140
+ from sage.misc.lazy_import import lazy_import
141
+ from sage.rings.infinity import infinity
142
+ from sage.rings.polynomial.multi_polynomial_element import degree_lowest_rational_function
143
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
144
+ from sage.rings.rational_field import RationalField
145
+
146
+ from sage.schemes.affine.affine_space import AffineSpace, AffineSpace_generic
147
+ from sage.schemes.affine.affine_subscheme import (AlgebraicScheme_subscheme_affine,
148
+ AlgebraicScheme_subscheme_affine_field)
149
+
150
+ lazy_import('sage.interfaces.singular', 'singular')
151
+ lazy_import('sage.rings.number_field.number_field', 'NumberField')
152
+ lazy_import('sage.rings.qqbar', 'number_field_elements_from_algebraics')
153
+
154
+ from .curve import Curve_generic
155
+
156
+ from .point import (AffineCurvePoint_field,
157
+ AffinePlaneCurvePoint_field,
158
+ AffinePlaneCurvePoint_finite_field,
159
+ IntegralAffineCurvePoint,
160
+ IntegralAffineCurvePoint_finite_field,
161
+ IntegralAffinePlaneCurvePoint,
162
+ IntegralAffinePlaneCurvePoint_finite_field)
163
+
164
+ from .closed_point import IntegralAffineCurveClosedPoint
165
+
166
+
167
+ class AffineCurve(Curve_generic, AlgebraicScheme_subscheme_affine):
168
+ """
169
+ Affine curves.
170
+
171
+ EXAMPLES::
172
+
173
+ sage: # needs sage.rings.number_field
174
+ sage: R.<v> = QQ[]
175
+ sage: K.<u> = NumberField(v^2 + 3)
176
+ sage: A.<x,y,z> = AffineSpace(K, 3)
177
+ sage: C = Curve([z - u*x^2, y^2], A); C
178
+ Affine Curve over Number Field in u with defining polynomial v^2 + 3
179
+ defined by (-u)*x^2 + z, y^2
180
+
181
+ ::
182
+
183
+ sage: A.<x,y,z> = AffineSpace(GF(7), 3)
184
+ sage: C = Curve([x^2 - z, z - 8*x], A); C
185
+ Affine Curve over Finite Field of size 7 defined by x^2 - z, -x + z
186
+ """
187
+
188
+ def __init__(self, A, X):
189
+ r"""
190
+ Initialize.
191
+
192
+ EXAMPLES::
193
+
194
+ sage: # needs sage.rings.number_field
195
+ sage: R.<v> = QQ[]
196
+ sage: K.<u> = NumberField(v^2 + 3)
197
+ sage: A.<x,y,z> = AffineSpace(K, 3)
198
+ sage: C = Curve([z - u*x^2, y^2], A); C
199
+ Affine Curve over Number Field in u with defining polynomial v^2 + 3
200
+ defined by (-u)*x^2 + z, y^2
201
+
202
+ ::
203
+
204
+ sage: A.<x,y,z> = AffineSpace(GF(7), 3)
205
+ sage: C = Curve([x^2 - z, z - 8*x], A); C
206
+ Affine Curve over Finite Field of size 7 defined by x^2 - z, -x + z
207
+ """
208
+ if not isinstance(A, AffineSpace_generic):
209
+ raise TypeError("A (={}) must be an affine space".format(A))
210
+
211
+ Curve_generic.__init__(self, A, X)
212
+
213
+ def _repr_type(self):
214
+ r"""
215
+ Return a string representation of the type of this curve.
216
+
217
+ EXAMPLES::
218
+
219
+ sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
220
+ sage: C = Curve([x - y, z - w, w - x], A)
221
+ sage: C._repr_type()
222
+ 'Affine'
223
+ """
224
+ return "Affine"
225
+
226
+ def projective_closure(self, i=0, PP=None):
227
+ r"""
228
+ Return the projective closure of this affine curve.
229
+
230
+ INPUT:
231
+
232
+ - ``i`` -- (default: 0) the index of the affine coordinate chart of the
233
+ projective space that the affine ambient space of this curve embeds into
234
+
235
+ - ``PP`` -- (default: ``None``) ambient projective space to compute the
236
+ projective closure in; this is constructed if it is not given
237
+
238
+ OUTPUT: a curve in projective space
239
+
240
+ EXAMPLES::
241
+
242
+ sage: A.<x,y,z> = AffineSpace(QQ, 3)
243
+ sage: C = Curve([y-x^2,z-x^3], A)
244
+ sage: C.projective_closure()
245
+ Projective Curve over Rational Field defined by x1^2 - x0*x2,
246
+ x1*x2 - x0*x3, x2^2 - x1*x3
247
+
248
+ ::
249
+
250
+ sage: A.<x,y,z> = AffineSpace(QQ, 3)
251
+ sage: C = Curve([y - x^2, z - x^3], A)
252
+ sage: C.projective_closure()
253
+ Projective Curve over Rational Field defined by
254
+ x1^2 - x0*x2, x1*x2 - x0*x3, x2^2 - x1*x3
255
+
256
+ ::
257
+
258
+ sage: A.<x,y> = AffineSpace(CC, 2)
259
+ sage: C = Curve(y - x^3 + x - 1, A)
260
+ sage: C.projective_closure(1)
261
+ Projective Plane Curve over Complex Field with 53 bits of precision defined by
262
+ x0^3 - x0*x1^2 + x1^3 - x1^2*x2
263
+
264
+ ::
265
+
266
+ sage: A.<x,y> = AffineSpace(QQ, 2)
267
+ sage: P.<u,v,w> = ProjectiveSpace(QQ, 2)
268
+ sage: C = Curve([y - x^2], A)
269
+ sage: C.projective_closure(1, P).ambient_space() == P
270
+ True
271
+ """
272
+ from .constructor import Curve
273
+ return Curve(AlgebraicScheme_subscheme_affine.projective_closure(self, i, PP))
274
+
275
+
276
+ class AffinePlaneCurve(AffineCurve):
277
+ """
278
+ Affine plane curves.
279
+ """
280
+
281
+ def __init__(self, A, f):
282
+ r"""
283
+ Initialize.
284
+
285
+ EXAMPLES::
286
+
287
+ sage: A.<x,y> = AffineSpace(QQ, 2)
288
+ sage: C = Curve([x^3 - y^2], A); C
289
+ Affine Plane Curve over Rational Field defined by x^3 - y^2
290
+
291
+ ::
292
+
293
+ sage: A.<x,y> = AffineSpace(CC, 2)
294
+ sage: C = Curve([y^2 + x^2], A); C
295
+ Affine Plane Curve over Complex Field with 53 bits of precision defined
296
+ by x^2 + y^2
297
+ """
298
+ if not (isinstance(A, AffineSpace_generic) and A.dimension != 2):
299
+ raise TypeError("Argument A (= %s) must be an affine plane." % A)
300
+
301
+ super().__init__(A, [f])
302
+
303
+ def _repr_type(self):
304
+ r"""
305
+ Return a string representation of the type of this curve.
306
+
307
+ EXAMPLES::
308
+
309
+ sage: A.<x,y> = AffineSpace(QQ, 2)
310
+ sage: C = Curve([y - 7/2*x^5 + x - 3], A)
311
+ sage: C._repr_type()
312
+ 'Affine Plane'
313
+ """
314
+ return "Affine Plane"
315
+
316
+ def divisor_of_function(self, r):
317
+ """
318
+ Return the divisor of a function on a curve.
319
+
320
+ INPUT:
321
+
322
+ - ``r`` -- a rational function on X
323
+
324
+ OUTPUT:
325
+
326
+ - ``list`` -- the divisor of r represented as a list of coefficients
327
+ and points. (TODO: This will change to a more structural output in
328
+ the future.)
329
+
330
+ EXAMPLES::
331
+
332
+ sage: F = GF(5)
333
+ sage: P2 = AffineSpace(2, F, names='xy')
334
+ sage: R = P2.coordinate_ring()
335
+ sage: x, y = R.gens()
336
+ sage: f = y^2 - x^9 - x
337
+ sage: C = Curve(f)
338
+ sage: K = FractionField(R)
339
+ sage: r = 1/x
340
+ sage: C.divisor_of_function(r) # not implemented (broken)
341
+ [[-1, (0, 0, 1)]]
342
+ sage: r = 1/x^3
343
+ sage: C.divisor_of_function(r) # not implemented (broken)
344
+ [[-3, (0, 0, 1)]]
345
+ """
346
+ F = self.base_ring()
347
+ f = self.defining_polynomial()
348
+ pts = self.places_on_curve()
349
+ R = f.parent()
350
+ x, y = R.gens()
351
+ R0 = PolynomialRing(F, 3, names=[str(x), str(y), "t"])
352
+ vars0 = R0.gens()
353
+ t = vars0[2]
354
+ divf = []
355
+ for pt0 in pts:
356
+ if pt0[2] != F(0):
357
+ lcs = self.local_coordinates(pt0, 5)
358
+ yt = lcs[1]
359
+ xt = lcs[0]
360
+ ldg = degree_lowest_rational_function(r(xt, yt), t)
361
+ if ldg != 0:
362
+ divf.append([ldg, pt0])
363
+ return divf
364
+
365
+ def local_coordinates(self, pt, n):
366
+ r"""
367
+ Return local coordinates to precision n at the given point.
368
+
369
+ Behaviour is flaky - some choices of `n` are worst that
370
+ others.
371
+
372
+
373
+ INPUT:
374
+
375
+ - ``pt`` -- an F-rational point on X which is not a
376
+ point of ramification for the projection (x,y) - x
377
+
378
+ - ``n`` -- the number of terms desired
379
+
380
+ OUTPUT: x = x0 + t y = y0 + power series in t
381
+
382
+ EXAMPLES::
383
+
384
+ sage: F = GF(5)
385
+ sage: pt = (2,3)
386
+ sage: R = PolynomialRing(F, 2, names = ['x','y'])
387
+ sage: x,y = R.gens()
388
+ sage: f = y^2 - x^9 - x
389
+ sage: C = Curve(f)
390
+ sage: C.local_coordinates(pt, 9)
391
+ [t + 2, -2*t^12 - 2*t^11 + 2*t^9 + t^8 - 2*t^7 - 2*t^6 - 2*t^4 + t^3 - 2*t^2 - 2]
392
+ """
393
+ f = self.defining_polynomial()
394
+ R = f.parent()
395
+ F = self.base_ring()
396
+ p = F.characteristic()
397
+ x0 = F(pt[0])
398
+ y0 = F(pt[1])
399
+ astr = ["a" + str(i) for i in range(1, 2 * n)]
400
+ x, y = R.gens()
401
+ R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr)
402
+ vars0 = R0.gens()
403
+ t = vars0[2]
404
+ yt = y0*t**0+add([vars0[i]*t**(i-2) for i in range(3, 2*n+2)])
405
+ xt = x0+t
406
+ ft = f(xt, yt)
407
+ S = singular
408
+ S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;')
409
+ S.eval('poly f = '+str(ft) + ';')
410
+ c = S('coeffs(%s, t)' % ft)
411
+ N = int(c.size())
412
+ b = ','.join("%s[%s,1]" % (c.name(), i) for i in range(2, N//2-4))
413
+ cmd = 'ideal I = ' + b
414
+ S.eval(cmd)
415
+ S.eval('short=0') # print using *'s and ^'s.
416
+ c = S.eval('slimgb(I)')
417
+ d = c.split("=")
418
+ d = d[1:]
419
+ d[len(d)-1] += "\n"
420
+ e = [xx[:xx.index("\n")] for xx in d]
421
+ vals = []
422
+ for x in e:
423
+ for y in vars0:
424
+ if str(y) in x:
425
+ if x.replace(str(y), ""):
426
+ i = x.find("-")
427
+ if i > 0:
428
+ vals.append([eval(x[1:i]), x[:i], F(eval(x[i+1:]))])
429
+ i = x.find("+")
430
+ if i > 0:
431
+ vals.append([eval(x[1:i]), x[:i], -F(eval(x[i+1:]))])
432
+ else:
433
+ vals.append([eval(str(y)[1:]), str(y), F(0)])
434
+ vals.sort()
435
+ return [x0 + t, y0 + add(v[2] * t**(j + 1) for j, v in enumerate(vals))]
436
+
437
+ def plot(self, *args, **kwds):
438
+ r"""
439
+ Plot the real points on this affine plane curve.
440
+
441
+ INPUT:
442
+
443
+ - ``*args`` -- (optional) tuples (variable, minimum, maximum) for
444
+ plotting dimensions
445
+
446
+ - ``**kwds`` -- optional keyword arguments passed on to ``implicit_plot``
447
+
448
+ EXAMPLES:
449
+
450
+ A cuspidal curve::
451
+
452
+ sage: R.<x, y> = QQ[]
453
+ sage: C = Curve(x^3 - y^2)
454
+ sage: C.plot() # needs sage.plot
455
+ Graphics object consisting of 1 graphics primitive
456
+
457
+ A 5-nodal curve of degree 11. This example also illustrates
458
+ some of the optional arguments::
459
+
460
+ sage: # needs sage.plot
461
+ sage: R.<x, y> = ZZ[]
462
+ sage: C = Curve(32*x^2 - 2097152*y^11 + 1441792*y^9
463
+ ....: - 360448*y^7 + 39424*y^5 - 1760*y^3 + 22*y - 1)
464
+ sage: C.plot((x, -1, 1), (y, -1, 1), plot_points=400)
465
+ Graphics object consisting of 1 graphics primitive
466
+
467
+ A line over `\mathbf{RR}`::
468
+
469
+ sage: # needs sage.symbolic sage.plot
470
+ sage: R.<x, y> = RR[]
471
+ sage: C = Curve(R(y - sqrt(2)*x))
472
+ sage: C.plot()
473
+ Graphics object consisting of 1 graphics primitive
474
+ """
475
+ Id = self.defining_ideal()
476
+ return Id.plot(*args, **kwds)
477
+
478
+ def is_transverse(self, C, P):
479
+ r"""
480
+ Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse.
481
+
482
+ The intersection at ``P`` is transverse if ``P`` is a nonsingular point of both curves, and if the
483
+ tangents of the curves at ``P`` are distinct.
484
+
485
+ INPUT:
486
+
487
+ - ``C`` -- a curve in the ambient space of this curve
488
+
489
+ - ``P`` -- a point in the intersection of both curves
490
+
491
+ OUTPUT: boolean
492
+
493
+ EXAMPLES::
494
+
495
+ sage: A.<x,y> = AffineSpace(QQ, 2)
496
+ sage: C = Curve([x^2 + y^2 - 1], A)
497
+ sage: D = Curve([x - 1], A)
498
+ sage: Q = A([1,0])
499
+ sage: C.is_transverse(D, Q)
500
+ False
501
+
502
+ ::
503
+
504
+ sage: # needs sage.rings.number_field
505
+ sage: R.<a> = QQ[]
506
+ sage: K.<b> = NumberField(a^3 + 2)
507
+ sage: A.<x,y> = AffineSpace(K, 2)
508
+ sage: C = A.curve([x*y])
509
+ sage: D = A.curve([y - b*x])
510
+ sage: Q = A([0,0])
511
+ sage: C.is_transverse(D, Q)
512
+ False
513
+
514
+ ::
515
+
516
+ sage: A.<x,y> = AffineSpace(QQ, 2)
517
+ sage: C = Curve([y - x^3], A)
518
+ sage: D = Curve([y + x], A)
519
+ sage: Q = A([0,0])
520
+ sage: C.is_transverse(D, Q)
521
+ True
522
+ """
523
+ if not self.intersects_at(C, P):
524
+ raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve" % (P, C))
525
+ if self.is_singular(P) or C.is_singular(P):
526
+ return False
527
+
528
+ # there is only one tangent at a nonsingular point of a plane curve
529
+ return not self.tangents(P)[0] == C.tangents(P)[0]
530
+
531
+ def multiplicity(self, P):
532
+ r"""
533
+ Return the multiplicity of this affine plane curve at the point ``P``.
534
+
535
+ In the special case of affine plane curves, the multiplicity of an affine
536
+ plane curve at the point (0,0) can be computed as the minimum of the degrees
537
+ of the homogeneous components of its defining polynomial. To compute the
538
+ multiplicity of a different point, a linear change of coordinates is used.
539
+
540
+ This curve must be defined over a field. An error if raised if ``P`` is
541
+ not a point on this curve.
542
+
543
+ INPUT:
544
+
545
+ - ``P`` -- a point in the ambient space of this curve
546
+
547
+ OUTPUT: integer
548
+
549
+ EXAMPLES::
550
+
551
+ sage: A.<x,y> = AffineSpace(QQ, 2)
552
+ sage: C = Curve([y^2 - x^3], A)
553
+ sage: Q1 = A([1,1])
554
+ sage: C.multiplicity(Q1)
555
+ 1
556
+ sage: Q2 = A([0,0])
557
+ sage: C.multiplicity(Q2)
558
+ 2
559
+
560
+ ::
561
+
562
+ sage: # needs sage.rings.number_field
563
+ sage: A.<x,y> = AffineSpace(QQbar,2)
564
+ sage: C = Curve([-x^7 + (-7)*x^6 + y^6 + (-21)*x^5 + 12*y^5
565
+ ....: + (-35)*x^4 + 60*y^4 + (-35)*x^3 + 160*y^3
566
+ ....: + (-21)*x^2 + 240*y^2 + (-7)*x + 192*y + 63], A)
567
+ sage: Q = A([-1,-2])
568
+ sage: C.multiplicity(Q)
569
+ 6
570
+
571
+ ::
572
+
573
+ sage: A.<x,y> = AffineSpace(QQ, 2)
574
+ sage: C = A.curve([y^3 - x^3 + x^6])
575
+ sage: Q = A([1,1])
576
+ sage: C.multiplicity(Q)
577
+ Traceback (most recent call last):
578
+ ...
579
+ TypeError: (=(1, 1)) is not a point on (=Affine Plane Curve over
580
+ Rational Field defined by x^6 - x^3 + y^3)
581
+ """
582
+ if self.base_ring() not in Fields():
583
+ raise TypeError("curve must be defined over a field")
584
+
585
+ # Check whether P is a point on this curve
586
+ try:
587
+ P = self(P)
588
+ except TypeError:
589
+ raise TypeError("(=%s) is not a point on (=%s)" % (P, self))
590
+
591
+ # Apply a linear change of coordinates to self so that P becomes (0,0)
592
+ AA = self.ambient_space()
593
+ f = self.defining_polynomials()[0](AA.gens()[0] + P[0], AA.gens()[1] + P[1])
594
+
595
+ # Compute the multiplicity of the new curve at (0,0), which is the minimum of the degrees of its
596
+ # nonzero terms
597
+ return min([g.degree() for g in f.monomials()])
598
+
599
+ def tangents(self, P, factor=True):
600
+ r"""
601
+ Return the tangents of this affine plane curve at the point ``P``.
602
+
603
+ The point ``P`` must be a point on this curve.
604
+
605
+ INPUT:
606
+
607
+ - ``P`` -- a point on this curve
608
+
609
+ - ``factor`` -- boolean (default: ``True``); whether to attempt computing the
610
+ polynomials of the individual tangent lines over the base field of this
611
+ curve, or to just return the polynomial corresponding to the union of
612
+ the tangent lines (which requires fewer computations)
613
+
614
+ OUTPUT: list of polynomials in the coordinate ring of the ambient space
615
+
616
+ EXAMPLES::
617
+
618
+ sage: # needs sage.rings.number_field
619
+ sage: set_verbose(-1)
620
+ sage: A.<x,y> = AffineSpace(QQbar, 2)
621
+ sage: C = Curve([x^5*y^3 + 2*x^4*y^4 + x^3*y^5 + 3*x^4*y^3
622
+ ....: + 6*x^3*y^4 + 3*x^2*y^5 + 3*x^3*y^3
623
+ ....: + 6*x^2*y^4 + 3*x*y^5 + x^5 + 10*x^4*y
624
+ ....: + 40*x^3*y^2 + 81*x^2*y^3 + 82*x*y^4 + 33*y^5], A)
625
+ sage: Q = A([0,0])
626
+ sage: C.tangents(Q)
627
+ [x + 3.425299577684700?*y,
628
+ x + (1.949159013086856? + 1.179307909383728?*I)*y,
629
+ x + (1.949159013086856? - 1.179307909383728?*I)*y,
630
+ x + (1.338191198070795? + 0.2560234251008043?*I)*y,
631
+ x + (1.338191198070795? - 0.2560234251008043?*I)*y]
632
+ sage: C.tangents(Q, factor=False)
633
+ [120*x^5 + 1200*x^4*y + 4800*x^3*y^2 + 9720*x^2*y^3 + 9840*x*y^4 + 3960*y^5]
634
+
635
+ ::
636
+
637
+ sage: # needs sage.rings.number_field
638
+ sage: R.<a> = QQ[]
639
+ sage: K.<b> = NumberField(a^2 - 3)
640
+ sage: A.<x,y> = AffineSpace(K, 2)
641
+ sage: C = Curve([(x^2 + y^2 - 2*x)^2 - x^2 - y^2], A)
642
+ sage: Q = A([0,0])
643
+ sage: C.tangents(Q)
644
+ [x + (-1/3*b)*y, x + (1/3*b)*y]
645
+
646
+ ::
647
+
648
+ sage: A.<x,y> = AffineSpace(QQ, 2)
649
+ sage: C = A.curve([y^2 - x^3 - x^2])
650
+ sage: Q = A([0,0])
651
+ sage: C.tangents(Q)
652
+ [x - y, x + y]
653
+
654
+ ::
655
+
656
+ sage: A.<x,y> = AffineSpace(QQ, 2)
657
+ sage: C = A.curve([y*x - x^4 + 2*x^2])
658
+ sage: Q = A([1,1])
659
+ sage: C.tangents(Q)
660
+ Traceback (most recent call last):
661
+ ...
662
+ TypeError: (=(1, 1)) is not a point on (=Affine Plane Curve over
663
+ Rational Field defined by -x^4 + 2*x^2 + x*y)
664
+ """
665
+ r = self.multiplicity(P)
666
+ f = self.defining_polynomial()
667
+ # move P to (0,0)
668
+ vars = self.ambient_space().gens()
669
+ coords = [vars[0] + P[0], vars[1] + P[1]]
670
+ f = f(coords)
671
+ coords = [vars[0] - P[0], vars[1] - P[1]] # coords to change back with
672
+ deriv = [f.derivative(vars[0], i).derivative(vars[1], r-i)([0, 0]) for i in range(r+1)]
673
+ T = sum([binomial(r, i)*deriv[i]*(vars[0])**i*(vars[1])**(r-i) for i in range(r+1)])
674
+ if not factor:
675
+ return [T(coords)]
676
+ if isinstance(self.base_ring(), sage.rings.abc.AlgebraicField):
677
+ fact = []
678
+ # first add tangents corresponding to vars[0], vars[1] if they divide T
679
+ t = min([e[0] for e in T.exponents()])
680
+ # vars[0] divides T
681
+ if t > 0:
682
+ fact.append(vars[0])
683
+ # divide T by that power of vars[0]
684
+ T = self.ambient_space().coordinate_ring()({(v[0] - t, v[1]): h for (v, h) in T.dict().items()})
685
+ t = min([e[1] for e in T.exponents()])
686
+ # vars[1] divides T
687
+ if t > 0:
688
+ fact.append(vars[1])
689
+ # divide T by that power of vars[1]
690
+ T = self.ambient_space().coordinate_ring()({(v[0], v[1] - t): h for (v, h) in T.dict().items()})
691
+ # T is homogeneous in var[0], var[1] if nonconstant, so dehomogenize
692
+ if T not in self.base_ring():
693
+ if T.degree(vars[0]) > 0:
694
+ T = T(vars[0], 1)
695
+ roots = T.univariate_polynomial().roots()
696
+ fact.extend([vars[0] - roots[i][0]*vars[1] for i in range(len(roots))])
697
+ else:
698
+ T = T(1, vars[1])
699
+ roots = T.univariate_polynomial().roots()
700
+ fact.extend([vars[1] - roots[i][0]*vars[0] for i in range(len(roots))])
701
+ return [ff(coords) for ff in fact]
702
+ else:
703
+ return [ll[0](coords) for ll in T.factor()]
704
+
705
+ def is_ordinary_singularity(self, P):
706
+ r"""
707
+ Return whether the singular point ``P`` of this affine plane curve is
708
+ an ordinary singularity.
709
+
710
+ The point ``P`` is an ordinary singularity of this curve if it is a
711
+ singular point, and if the tangents of this curve at ``P`` are
712
+ distinct.
713
+
714
+ INPUT:
715
+
716
+ - ``P`` -- a point on this curve
717
+
718
+ OUTPUT:
719
+
720
+ ``True`` or ``False`` depending on whether ``P`` is or is not an ordinary
721
+ singularity of this curve, respectively. An error is raised if ``P`` is
722
+ not a singular point of this curve.
723
+
724
+ EXAMPLES::
725
+
726
+ sage: A.<x,y> = AffineSpace(QQ, 2)
727
+ sage: C = Curve([y^2 - x^3], A)
728
+ sage: Q = A([0,0])
729
+ sage: C.is_ordinary_singularity(Q)
730
+ False
731
+
732
+ ::
733
+
734
+ sage: # needs sage.rings.number_field
735
+ sage: R.<a> = QQ[]
736
+ sage: K.<b> = NumberField(a^2 - 3)
737
+ sage: A.<x,y> = AffineSpace(K, 2)
738
+ sage: C = Curve([(x^2 + y^2 - 2*x)^2 - x^2 - y^2], A)
739
+ sage: Q = A([0,0])
740
+ sage: C.is_ordinary_singularity(Q)
741
+ True
742
+
743
+ ::
744
+
745
+ sage: A.<x,y> = AffineSpace(QQ, 2)
746
+ sage: C = A.curve([x^2*y - y^2*x + y^2 + x^3])
747
+ sage: Q = A([-1,-1])
748
+ sage: C.is_ordinary_singularity(Q)
749
+ Traceback (most recent call last):
750
+ ...
751
+ TypeError: (=(-1, -1)) is not a singular point of (=Affine Plane Curve
752
+ over Rational Field defined by x^3 + x^2*y - x*y^2 + y^2)
753
+ """
754
+ r = self.multiplicity(P)
755
+ if r < 2:
756
+ raise TypeError("(=%s) is not a singular point of (=%s)" % (P, self))
757
+
758
+ T = self.tangents(P, factor=False)[0]
759
+ vars = self.ambient_space().gens()
760
+
761
+ # use resultants to determine if there is a higher multiplicity tangent
762
+ if T.degree(vars[0]) > 0:
763
+ return T.resultant(T.derivative(vars[0]), vars[0]) != 0
764
+ else:
765
+ return T.resultant(T.derivative(vars[1]), vars[1]) != 0
766
+
767
+ def rational_parameterization(self):
768
+ r"""
769
+ Return a rational parameterization of this curve.
770
+
771
+ This curve must have rational coefficients and be absolutely irreducible (i.e. irreducible
772
+ over the algebraic closure of the rational field). The curve must also be rational (have
773
+ geometric genus zero).
774
+
775
+ The rational parameterization may have coefficients in a quadratic extension of the rational
776
+ field.
777
+
778
+ OUTPUT: a birational map between `\mathbb{A}^{1}` and this curve, given
779
+ as a scheme morphism
780
+
781
+ EXAMPLES::
782
+
783
+ sage: A.<x,y> = AffineSpace(QQ, 2)
784
+ sage: C = Curve([y^2 - x], A)
785
+ sage: C.rational_parameterization()
786
+ Scheme morphism:
787
+ From: Affine Space of dimension 1 over Rational Field
788
+ To: Affine Plane Curve over Rational Field defined by y^2 - x
789
+ Defn: Defined on coordinates by sending (t) to
790
+ (t^2, t)
791
+
792
+ ::
793
+
794
+ sage: A.<x,y> = AffineSpace(QQ, 2)
795
+ sage: C = Curve([(x^2 + y^2 - 2*x)^2 - x^2 - y^2], A)
796
+ sage: C.rational_parameterization()
797
+ Scheme morphism:
798
+ From: Affine Space of dimension 1 over Rational Field
799
+ To: Affine Plane Curve over Rational Field defined by x^4 +
800
+ 2*x^2*y^2 + y^4 - 4*x^3 - 4*x*y^2 + 3*x^2 - y^2
801
+ Defn: Defined on coordinates by sending (t) to
802
+ ((-12*t^4 + 6*t^3 + 4*t^2 - 2*t)/(-25*t^4 + 40*t^3 - 26*t^2 +
803
+ 8*t - 1), (-9*t^4 + 12*t^3 - 4*t + 1)/(-25*t^4 + 40*t^3 - 26*t^2 + 8*t - 1))
804
+
805
+ ::
806
+
807
+ sage: A.<x,y> = AffineSpace(QQ, 2)
808
+ sage: C = Curve([x^2 + y^2 + 7], A)
809
+ sage: C.rational_parameterization()
810
+ Scheme morphism:
811
+ From: Affine Space of dimension 1 over Number Field in a with defining polynomial a^2 + 7
812
+ To: Affine Plane Curve over Number Field in a with defining
813
+ polynomial a^2 + 7 defined by x^2 + y^2 + 7
814
+ Defn: Defined on coordinates by sending (t) to
815
+ ((-7*t^2 + 7)/((-a)*t^2 + (-a)), 14*t/((-a)*t^2 + (-a)))
816
+ """
817
+ para = self.projective_closure(i=0).rational_parameterization().defining_polynomials()
818
+ # these polynomials are homogeneous in two indeterminants, so dehomogenize wrt one of the variables
819
+ R = para[0].parent()
820
+ A_line = AffineSpace(R.base_ring(), 1, 't')
821
+ para = [A_line.coordinate_ring()(para[i].substitute({R.gens()[0]: 1})) for i in range(3)]
822
+ C = self.change_ring(R.base_ring())
823
+ # because of the parameter i=0, the projective closure is constructed with respect to the
824
+ # affine patch corresponding to the first coordinate being nonzero. Thus para[0] will not be
825
+ # the zero polynomial, and dehomogenization won't change this
826
+ H = Hom(A_line, C)
827
+ return H([para[1]/para[0], para[2]/para[0]])
828
+
829
+
830
+ class AffineCurve_field(AffineCurve, AlgebraicScheme_subscheme_affine_field):
831
+ """
832
+ Affine curves over fields.
833
+ """
834
+ _point = AffineCurvePoint_field
835
+
836
+ def __init__(self, A, X):
837
+ r"""
838
+ Initialize.
839
+
840
+ EXAMPLES::
841
+
842
+ sage: # needs sage.rings.number_field
843
+ sage: R.<v> = QQ[]
844
+ sage: K.<u> = NumberField(v^2 + 3)
845
+ sage: A.<x,y,z> = AffineSpace(K, 3)
846
+ sage: C = Curve([z - u*x^2, y^2], A); C
847
+ Affine Curve over Number Field in u with defining polynomial v^2 + 3
848
+ defined by (-u)*x^2 + z, y^2
849
+
850
+ ::
851
+
852
+ sage: A.<x,y,z> = AffineSpace(GF(7), 3)
853
+ sage: C = Curve([x^2 - z, z - 8*x], A); C
854
+ Affine Curve over Finite Field of size 7 defined by x^2 - z, -x + z
855
+
856
+ TESTS::
857
+
858
+ sage: K.<x,y,z,t> = QQ[]
859
+ sage: t1 = x^2*z^2 + y*t
860
+ sage: t2 = y*z^2 + x^2*t
861
+ sage: C = Curve([x^4 - y^2 - 19, z^4 - t^2 - 23, t1^2 - t2^2 - 19*23])
862
+ Traceback (most recent call last):
863
+ ...
864
+ ValueError: defining equations (=[x^4 - y^2 - 19, z^4 - t^2 - 23,
865
+ x^4*z^4 - y^2*z^4 - x^4*t^2 + y^2*t^2 - 437]) define a scheme of dimension 2 != 1
866
+ """
867
+ super().__init__(A, X)
868
+
869
+ if A.base_ring() not in Fields():
870
+ raise TypeError("curve not defined over a field")
871
+
872
+ d = super(Curve_generic, self).dimension()
873
+ if d != 1:
874
+ raise ValueError("defining equations (={}) define a scheme of dimension {} != 1".format(X, d))
875
+
876
+ def projection(self, indices, AS=None):
877
+ r"""
878
+ Return the projection of this curve onto the coordinates specified by
879
+ ``indices``.
880
+
881
+ INPUT:
882
+
883
+ - ``indices`` -- list or tuple of distinct integers specifying the
884
+ indices of the coordinates to use in the projection. Can also be a list
885
+ or tuple consisting of variables of the coordinate ring of the ambient
886
+ space of this curve. If integers are used to specify the coordinates, 0
887
+ denotes the first coordinate. The length of ``indices`` must be between
888
+ two and one less than the dimension of the ambient space of this curve,
889
+ inclusive.
890
+
891
+ - ``AS`` -- (default: ``None``) the affine space the projected curve will
892
+ be defined in. This space must be defined over the same base field as
893
+ this curve, and must have dimension equal to the length of ``indices``.
894
+ This space is constructed if not specified.
895
+
896
+ OUTPUT: a tuple of
897
+
898
+ - a scheme morphism from this curve to affine space of dimension equal
899
+ to the number of coordinates specified in ``indices``
900
+
901
+ - the affine subscheme that is the image of that morphism. If the image
902
+ is a curve, the second element of the tuple will be a curve.
903
+
904
+ EXAMPLES::
905
+
906
+ sage: A.<x,y,z> = AffineSpace(QQ, 3)
907
+ sage: C = Curve([y^7 - x^2 + x^3 - 2*z, z^2 - x^7 - y^2], A)
908
+ sage: C.projection([0,1])
909
+ (Scheme morphism:
910
+ From: Affine Curve over Rational Field
911
+ defined by y^7 + x^3 - x^2 - 2*z, -x^7 - y^2 + z^2
912
+ To: Affine Space of dimension 2 over Rational Field
913
+ Defn: Defined on coordinates by sending (x, y, z) to
914
+ (x, y),
915
+ Affine Plane Curve over Rational Field defined by x1^14 + 2*x0^3*x1^7 -
916
+ 2*x0^2*x1^7 - 4*x0^7 + x0^6 - 2*x0^5 + x0^4 - 4*x1^2)
917
+ sage: C.projection([0,1,3,4])
918
+ Traceback (most recent call last):
919
+ ...
920
+ ValueError: (=[0, 1, 3, 4]) must be a list or tuple of length between 2
921
+ and (=2), inclusive
922
+
923
+ ::
924
+
925
+ sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
926
+ sage: C = Curve([x - 2, y - 3, z - 1], A)
927
+ sage: B.<a,b,c> = AffineSpace(QQ, 3)
928
+ sage: C.projection([0,1,2], AS=B)
929
+ (Scheme morphism:
930
+ From: Affine Curve over Rational Field defined by x - 2, y - 3, z - 1
931
+ To: Affine Space of dimension 3 over Rational Field
932
+ Defn: Defined on coordinates by sending (x, y, z, w) to
933
+ (x, y, z),
934
+ Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
935
+ c - 1,
936
+ b - 3,
937
+ a - 2)
938
+
939
+ ::
940
+
941
+ sage: A.<x,y,z,w,u> = AffineSpace(GF(11), 5)
942
+ sage: C = Curve([x^3 - 5*y*z + u^2, x - y^2 + 3*z^2,
943
+ ....: w^2 + 2*u^3*y, y - u^2 + z*x], A)
944
+ sage: B.<a,b,c> = AffineSpace(GF(11), 3)
945
+ sage: proj1 = C.projection([1,2,4], AS=B); proj1
946
+ (Scheme morphism:
947
+ From: Affine Curve over Finite Field of size 11 defined by x^3 -
948
+ 5*y*z + u^2, -y^2 + 3*z^2 + x, 2*y*u^3 + w^2, x*z - u^2 + y
949
+ To: Affine Space of dimension 3 over Finite Field of size 11
950
+ Defn: Defined on coordinates by sending (x, y, z, w, u) to
951
+ (y, z, u),
952
+ Affine Curve over Finite Field of size 11 defined by a^2*b - 3*b^3 -
953
+ c^2 + a, c^6 - 5*a*b^4 + b^3*c^2 - 3*a*c^4 + 3*a^2*c^2 - a^3, a^2*c^4 -
954
+ 3*b^2*c^4 - 2*a^3*c^2 - 5*a*b^2*c^2 + a^4 - 5*a*b^3 + 2*b^4 + b^2*c^2 -
955
+ 3*b*c^2 + 3*a*b, a^4*c^2 + 2*b^4*c^2 - a^5 - 2*a*b^4 + 5*b*c^4 + a*b*c^2
956
+ - 5*a*b^2 + 4*b^3 + b*c^2 + 5*c^2 - 5*a, a^6 - 5*b^6 - 5*b^3*c^2 +
957
+ 5*a*b^3 + 2*c^4 - 4*a*c^2 + 2*a^2 - 5*a*b + c^2)
958
+ sage: proj1[1].ambient_space() is B
959
+ True
960
+ sage: proj2 = C.projection([1,2,4])
961
+ sage: proj2[1].ambient_space() is B
962
+ False
963
+ sage: C.projection([1,2,3,5], AS=B)
964
+ Traceback (most recent call last):
965
+ ...
966
+ TypeError: (=Affine Space of dimension 3 over Finite Field of size 11)
967
+ must have dimension (=4)
968
+
969
+ ::
970
+
971
+ sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
972
+ sage: C = A.curve([x*y - z^3, x*z - w^3, w^2 - x^3])
973
+ sage: C.projection([y,z])
974
+ (Scheme morphism:
975
+ From: Affine Curve over Rational Field defined by
976
+ -z^3 + x*y, -w^3 + x*z, -x^3 + w^2
977
+ To: Affine Space of dimension 2 over Rational Field
978
+ Defn: Defined on coordinates by sending (x, y, z, w) to (y, z),
979
+ Affine Plane Curve over Rational Field defined by x1^23 - x0^7*x1^4)
980
+ sage: B.<x,y,z> = AffineSpace(QQ, 3)
981
+ sage: C.projection([x,y,z], AS=B)
982
+ (Scheme morphism:
983
+ From: Affine Curve over Rational Field defined by
984
+ -z^3 + x*y, -w^3 + x*z, -x^3 + w^2
985
+ To: Affine Space of dimension 3 over Rational Field
986
+ Defn: Defined on coordinates by sending (x, y, z, w) to
987
+ (x, y, z),
988
+ Affine Curve over Rational Field defined by
989
+ z^3 - x*y, x^8 - x*z^2, x^7*z^2 - x*y*z)
990
+ sage: C.projection([y,z,z])
991
+ Traceback (most recent call last):
992
+ ...
993
+ ValueError: (=[y, z, z]) must be a list or tuple of distinct indices or
994
+ variables
995
+ """
996
+ AA = self.ambient_space()
997
+ n = AA.dimension_relative()
998
+ if n == 2:
999
+ raise TypeError("this curve is already a plane curve")
1000
+ if self.base_ring() not in Fields():
1001
+ raise TypeError("this curve must be defined over a field")
1002
+ if len(indices) < 2 or len(indices) >= n:
1003
+ raise ValueError("(=%s) must be a list or tuple of length between 2 and (=%s), inclusive" % (indices, n - 1))
1004
+ if len(set(indices)) < len(indices):
1005
+ raise ValueError("(=%s) must be a list or tuple of distinct indices or variables" % indices)
1006
+ if AS is not None:
1007
+ if not isinstance(AS, AffineSpace_generic):
1008
+ raise TypeError("(=%s) must be an affine space" % AS)
1009
+ if AS.dimension_relative() != len(indices):
1010
+ raise TypeError("(=%s) must have dimension (=%s)" % (AS, len(indices)))
1011
+ if AS.base_ring() != AA.base_ring():
1012
+ raise TypeError("(=%s) must be defined over the same base field as this curve" % AS)
1013
+ indices = list(indices)
1014
+ if all(f in AA.gens() for f in indices):
1015
+ indices = [AA.gens().index(f) for f in indices]
1016
+ indices.sort()
1017
+ else:
1018
+ indices = [int(i) for i in indices] # type checking
1019
+ indices.sort()
1020
+ if indices[0] < 0 or indices[-1] > n - 1:
1021
+ raise ValueError("index values must be between 0 and one "
1022
+ "minus the dimension of the ambient space "
1023
+ "of this curve")
1024
+ # construct the projection map
1025
+ if AS is None:
1026
+ AA2 = AffineSpace(self.base_ring(), len(indices))
1027
+ else:
1028
+ AA2 = AS
1029
+ H = Hom(self, AA2)
1030
+ psi = H([AA.gens()[i] for i in indices])
1031
+ # compute the image via elimination
1032
+ removecoords = list(AA.gens())
1033
+ for i in range(len(indices) - 1, -1, -1):
1034
+ removecoords.pop(indices[i])
1035
+ J = self.defining_ideal().elimination_ideal(removecoords)
1036
+ K = Hom(AA.coordinate_ring(), AA2.coordinate_ring())
1037
+ ll = [0]*(n)
1038
+ for i in range(len(indices)):
1039
+ ll[indices[i]] = AA2.gens()[i]
1040
+ phi = K(ll)
1041
+ G = [phi(f) for f in J.gens()]
1042
+ try:
1043
+ C = AA2.curve(G)
1044
+ except (TypeError, ValueError):
1045
+ C = AA2.subscheme(G)
1046
+ return (psi, C)
1047
+
1048
+ def plane_projection(self, AP=None):
1049
+ r"""
1050
+ Return a projection of this curve into an affine plane so that the
1051
+ image of the projection is a plane curve.
1052
+
1053
+ INPUT:
1054
+
1055
+ - ``AP`` -- (default: ``None``) the affine plane to project this curve
1056
+ into. This space must be defined over the same base field as this
1057
+ curve, and must have dimension two. This space will be constructed if
1058
+ not specified.
1059
+
1060
+ OUTPUT: a tuple of
1061
+
1062
+ - a scheme morphism from this curve into an affine plane
1063
+
1064
+ - the plane curve that defines the image of that morphism
1065
+
1066
+ EXAMPLES::
1067
+
1068
+ sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
1069
+ sage: C = Curve([x^2 - y*z*w, z^3 - w, w + x*y - 3*z^3], A)
1070
+ sage: C.plane_projection()
1071
+ (Scheme morphism:
1072
+ From: Affine Curve over Rational Field defined by
1073
+ -y*z*w + x^2, z^3 - w, -3*z^3 + x*y + w
1074
+ To: Affine Space of dimension 2 over Rational Field
1075
+ Defn: Defined on coordinates by sending (x, y, z, w) to (x, y),
1076
+ Affine Plane Curve over Rational Field defined by
1077
+ x0^2*x1^7 - 16*x0^4)
1078
+
1079
+ ::
1080
+
1081
+ sage: # needs sage.rings.number_field
1082
+ sage: R.<a> = QQ[]
1083
+ sage: K.<b> = NumberField(a^2 + 2)
1084
+ sage: A.<x,y,z> = AffineSpace(K, 3)
1085
+ sage: C = A.curve([x - b, y - 2])
1086
+ sage: B.<a,b> = AffineSpace(K, 2)
1087
+ sage: proj1 = C.plane_projection(AP=B)
1088
+ sage: proj1
1089
+ (Scheme morphism:
1090
+ From: Affine Curve over Number Field in b
1091
+ with defining polynomial a^2 + 2 defined by x + (-b), y - 2
1092
+ To: Affine Space of dimension 2 over Number Field in b
1093
+ with defining polynomial a^2 + 2
1094
+ Defn: Defined on coordinates by sending (x, y, z) to
1095
+ (x, z),
1096
+ Affine Plane Curve over Number Field in b
1097
+ with defining polynomial a^2 + 2 defined by a + (-b))
1098
+ sage: proj1[1].ambient_space() is B
1099
+ True
1100
+ sage: proj2 = C.plane_projection()
1101
+ sage: proj2[1].ambient_space() is B
1102
+ False
1103
+ """
1104
+ n = self.ambient_space().dimension_relative()
1105
+ # finds a projection that will have a plane curve as its image
1106
+ # the following iterates over all pairs (i,j) with j > i to test all
1107
+ # possible projections
1108
+ for i in range(n - 1):
1109
+ for j in range(i + 1, n):
1110
+ L = self.projection([i, j], AP)
1111
+ if isinstance(L[1], Curve_generic):
1112
+ return L
1113
+
1114
+ def blowup(self, P=None):
1115
+ r"""
1116
+ Return the blow up of this affine curve at the point ``P``.
1117
+
1118
+ The blow up is described by affine charts. This curve must be irreducible.
1119
+
1120
+ INPUT:
1121
+
1122
+ - ``P`` -- (default: ``None``) a point on this curve at which to blow up;
1123
+ if ``None``, then ``P`` is taken to be the origin
1124
+
1125
+ OUTPUT: a tuple of
1126
+
1127
+ - a tuple of curves in affine space of the same dimension as the
1128
+ ambient space of this curve, which define the blow up in each affine
1129
+ chart.
1130
+
1131
+ - a tuple of tuples such that the j-th element of the i-th tuple is the
1132
+ transition map from the i-th affine patch to the j-th affine patch.
1133
+
1134
+ - a tuple consisting of the restrictions of the projection map from the
1135
+ blow up back to the original curve, restricted to each affine patch.
1136
+ There the i-th element will be the projection from the i-th affine patch.
1137
+
1138
+ EXAMPLES::
1139
+
1140
+ sage: A.<x,y> = AffineSpace(QQ, 2)
1141
+ sage: C = Curve([y^2 - x^3], A)
1142
+ sage: C.blowup()
1143
+ ((Affine Plane Curve over Rational Field defined by s1^2 - x,
1144
+ Affine Plane Curve over Rational Field defined by y*s0^3 - 1),
1145
+ ([Scheme endomorphism of Affine Plane Curve over Rational Field
1146
+ defined by s1^2 - x
1147
+ Defn: Defined on coordinates by sending (x, s1) to (x, s1),
1148
+ Scheme morphism:
1149
+ From: Affine Plane Curve over Rational Field defined by s1^2 - x
1150
+ To: Affine Plane Curve over Rational Field defined by y*s0^3 - 1
1151
+ Defn: Defined on coordinates by sending (x, s1) to (x*s1, 1/s1)],
1152
+ [Scheme morphism:
1153
+ From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1
1154
+ To: Affine Plane Curve over Rational Field defined by s1^2 - x
1155
+ Defn: Defined on coordinates by sending (y, s0) to (y*s0, 1/s0),
1156
+ Scheme endomorphism of Affine Plane Curve over Rational Field
1157
+ defined by y*s0^3 - 1
1158
+ Defn: Defined on coordinates by sending (y, s0) to (y, s0)]),
1159
+ (Scheme morphism:
1160
+ From: Affine Plane Curve over Rational Field defined by s1^2 - x
1161
+ To: Affine Plane Curve over Rational Field defined by -x^3 + y^2
1162
+ Defn: Defined on coordinates by sending (x, s1) to (x, x*s1),
1163
+ Scheme morphism:
1164
+ From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1
1165
+ To: Affine Plane Curve over Rational Field defined by -x^3 + y^2
1166
+ Defn: Defined on coordinates by sending (y, s0) to (y*s0, y)))
1167
+
1168
+ ::
1169
+
1170
+ sage: # needs sage.rings.number_field
1171
+ sage: K.<a> = QuadraticField(2)
1172
+ sage: A.<x,y,z> = AffineSpace(K, 3)
1173
+ sage: C = Curve([y^2 - a*x^5, x - z], A)
1174
+ sage: B = C.blowup()
1175
+ sage: B[0]
1176
+ (Affine Curve over Number Field in a with defining polynomial x^2 - 2
1177
+ with a = 1.414213562373095? defined by s2 - 1, 2*x^3 + (-a)*s1^2,
1178
+ Affine Curve over Number Field in a with defining polynomial x^2 - 2
1179
+ with a = 1.414213562373095? defined by s0 - s2, 2*y^3*s2^5 + (-a),
1180
+ Affine Curve over Number Field in a with defining polynomial x^2 - 2
1181
+ with a = 1.414213562373095? defined by s0 - 1, 2*z^3 + (-a)*s1^2)
1182
+ sage: B[1][0][2]
1183
+ Scheme morphism:
1184
+ From: Affine Curve over Number Field in a
1185
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1186
+ defined by s2 - 1, 2*x^3 + (-a)*s1^2
1187
+ To: Affine Curve over Number Field in a
1188
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1189
+ defined by s0 - 1, 2*z^3 + (-a)*s1^2
1190
+ Defn: Defined on coordinates by sending (x, s1, s2) to
1191
+ (x*s2, 1/s2, s1/s2)
1192
+ sage: B[1][2][0]
1193
+ Scheme morphism:
1194
+ From: Affine Curve over Number Field in a
1195
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1196
+ defined by s0 - 1, 2*z^3 + (-a)*s1^2
1197
+ To: Affine Curve over Number Field in a
1198
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1199
+ defined by s2 - 1, 2*x^3 + (-a)*s1^2
1200
+ Defn: Defined on coordinates by sending (z, s0, s1) to
1201
+ (z*s0, s1/s0, 1/s0)
1202
+ sage: B[2]
1203
+ (Scheme morphism:
1204
+ From: Affine Curve over Number Field in a
1205
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1206
+ defined by s2 - 1, 2*x^3 + (-a)*s1^2
1207
+ To: Affine Curve over Number Field in a
1208
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1209
+ defined by (-a)*x^5 + y^2, x - z
1210
+ Defn: Defined on coordinates by sending (x, s1, s2) to
1211
+ (x, x*s1, x*s2),
1212
+ Scheme morphism:
1213
+ From: Affine Curve over Number Field in a
1214
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1215
+ defined by s0 - s2, 2*y^3*s2^5 + (-a)
1216
+ To: Affine Curve over Number Field in a
1217
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1218
+ defined by (-a)*x^5 + y^2, x - z
1219
+ Defn: Defined on coordinates by sending (y, s0, s2) to
1220
+ (y*s0, y, y*s2),
1221
+ Scheme morphism:
1222
+ From: Affine Curve over Number Field in a
1223
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1224
+ defined by s0 - 1, 2*z^3 + (-a)*s1^2
1225
+ To: Affine Curve over Number Field in a
1226
+ with defining polynomial x^2 - 2 with a = 1.414213562373095?
1227
+ defined by (-a)*x^5 + y^2, x - z
1228
+ Defn: Defined on coordinates by sending (z, s0, s1) to
1229
+ (z*s0, z*s1, z))
1230
+
1231
+ ::
1232
+
1233
+ sage: A.<x,y> = AffineSpace(QQ, 2)
1234
+ sage: C = A.curve((y - 3/2)^3 - (x + 2)^5 - (x + 2)^6)
1235
+ sage: Q = A([-2,3/2])
1236
+ sage: C.blowup(Q)
1237
+ ((Affine Plane Curve over Rational Field
1238
+ defined by x^3 - s1^3 + 7*x^2 + 16*x + 12,
1239
+ Affine Plane Curve over Rational Field
1240
+ defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5
1241
+ + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8),
1242
+ ([Scheme endomorphism of Affine Plane Curve over Rational Field
1243
+ defined by x^3 - s1^3 + 7*x^2 + 16*x + 12
1244
+ Defn: Defined on coordinates by sending (x, s1) to (x, s1),
1245
+ Scheme morphism:
1246
+ From: Affine Plane Curve over Rational Field
1247
+ defined by x^3 - s1^3 + 7*x^2 + 16*x + 12
1248
+ To: Affine Plane Curve over Rational Field
1249
+ defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5
1250
+ + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8
1251
+ Defn: Defined on coordinates by sending (x, s1) to
1252
+ (x*s1 + 2*s1 + 3/2, 1/s1)],
1253
+ [Scheme morphism:
1254
+ From: Affine Plane Curve over Rational Field
1255
+ defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5
1256
+ + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8
1257
+ To: Affine Plane Curve over Rational Field
1258
+ defined by x^3 - s1^3 + 7*x^2 + 16*x + 12
1259
+ Defn: Defined on coordinates by sending (y, s0) to
1260
+ (y*s0 - 3/2*s0 - 2, 1/s0),
1261
+ Scheme endomorphism of Affine Plane Curve over Rational Field
1262
+ defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5 + 54*y*s0^6
1263
+ - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8
1264
+ Defn: Defined on coordinates by sending (y, s0) to (y, s0)]),
1265
+ (Scheme morphism:
1266
+ From: Affine Plane Curve over Rational Field
1267
+ defined by x^3 - s1^3 + 7*x^2 + 16*x + 12
1268
+ To: Affine Plane Curve over Rational Field
1269
+ defined by -x^6 - 13*x^5 - 70*x^4 - 200*x^3 + y^3
1270
+ - 320*x^2 - 9/2*y^2 - 272*x + 27/4*y - 795/8
1271
+ Defn: Defined on coordinates by sending (x, s1) to
1272
+ (x, x*s1 + 2*s1 + 3/2),
1273
+ Scheme morphism:
1274
+ From: Affine Plane Curve over Rational Field
1275
+ defined by 8*y^3*s0^6 - 36*y^2*s0^6 + 8*y^2*s0^5
1276
+ + 54*y*s0^6 - 24*y*s0^5 - 27*s0^6 + 18*s0^5 - 8
1277
+ To: Affine Plane Curve over Rational Field
1278
+ defined by -x^6 - 13*x^5 - 70*x^4 - 200*x^3 + y^3
1279
+ - 320*x^2 - 9/2*y^2 - 272*x + 27/4*y - 795/8
1280
+ Defn: Defined on coordinates by sending (y, s0) to
1281
+ (y*s0 - 3/2*s0 - 2, y)))
1282
+
1283
+ ::
1284
+
1285
+ sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
1286
+ sage: C = A.curve([((x + 1)^2 + y^2)^3 - 4*(x + 1)^2*y^2, y - z, w - 4])
1287
+ sage: Q = C([-1,0,0,4])
1288
+ sage: B = C.blowup(Q)
1289
+ sage: B[0]
1290
+ (Affine Curve over Rational Field defined by s3, s1 - s2,
1291
+ x^2*s2^6 + 2*x*s2^6 + 3*x^2*s2^4 + s2^6 + 6*x*s2^4
1292
+ + 3*x^2*s2^2 + 3*s2^4 + 6*x*s2^2 + x^2 - s2^2 + 2*x + 1,
1293
+ Affine Curve over Rational Field defined by s3, s2 - 1,
1294
+ y^2*s0^6 + 3*y^2*s0^4 + 3*y^2*s0^2 + y^2 - 4*s0^2,
1295
+ Affine Curve over Rational Field defined by s3, s1 - 1,
1296
+ z^2*s0^6 + 3*z^2*s0^4 + 3*z^2*s0^2 + z^2 - 4*s0^2,
1297
+ Closed subscheme of Affine Space of dimension 4 over Rational Field
1298
+ defined by: 1)
1299
+ sage: Q = A([6,2,3,1])
1300
+ sage: B = C.blowup(Q)
1301
+ Traceback (most recent call last):
1302
+ ...
1303
+ TypeError: (=(6, 2, 3, 1)) must be a point on this curve
1304
+
1305
+ ::
1306
+
1307
+ sage: # needs sage.rings.number_field
1308
+ sage: A.<x,y> = AffineSpace(QuadraticField(-1), 2)
1309
+ sage: C = A.curve([y^2 + x^2])
1310
+ sage: C.blowup()
1311
+ Traceback (most recent call last):
1312
+ ...
1313
+ TypeError: this curve must be irreducible
1314
+ """
1315
+ A = self.ambient_space()
1316
+ n = A.dimension_relative()
1317
+ if P is None:
1318
+ P = A([0]*n)
1319
+ try:
1320
+ self(P)
1321
+ except TypeError:
1322
+ raise TypeError("(=%s) must be a point on this curve" % P)
1323
+ if self.base_ring() not in Fields():
1324
+ raise TypeError("the base ring of this curve must be a field")
1325
+ if not self.is_irreducible():
1326
+ raise TypeError("this curve must be irreducible")
1327
+ # attempt to make the variable names more organized
1328
+ # the convention used here is to have the homogeneous coordinates for the projective component of the
1329
+ # product space the blow up resides in be generated from the letter 's'. The following loop is in place
1330
+ # to prevent conflicts in the names from occurring
1331
+ rf = 1
1332
+ for i in range(n):
1333
+ if str(A.gens()[i])[0] == 's' and len(str(A.gens()[i])) > rf:
1334
+ rf = len(str(A.gens()[i]))
1335
+ var_names = [str(A.gens()[i]) for i in range(n)] + ['s'*rf + str(i) for i in range(n)]
1336
+ R = PolynomialRing(A.base_ring(), 2*n, var_names)
1337
+ # move the defining polynomials of this curve into R
1338
+ H = Hom(A.coordinate_ring(), R)
1339
+ psi = H([R.gens()[i] for i in range(n)])
1340
+ n_polys = [psi(f) for f in self.defining_polynomials()]
1341
+ # the blow up ideal of A at P is the ideal generated by
1342
+ # (z_i - p_i)*s_j - (z_j - p_j)*s_i for i != j from 0,...,n-1
1343
+ # in the mixed product space of A^n and P^{n-1} where the z_i are the gens
1344
+ # of A^n, the s_i are the gens for P^{n-1}, and P = (p_1,...,p_n). We describe the
1345
+ # blow up of this curve at P in each affine chart
1346
+ patches = []
1347
+ for i in range(n):
1348
+ # in this chart, s_i is assumed to be 1
1349
+ # substitute in z_j = (z_i - p_i)*s_j + p_j for each j != i
1350
+ coords = list(R.gens())
1351
+ for j in range(n):
1352
+ if j != i:
1353
+ coords[j] = (R.gens()[i] - P[i])*R.gens()[j + n] + P[j]
1354
+ c_polys = [f(coords) for f in n_polys]
1355
+ var_names = list(R.gens())[n:2*n]
1356
+ var_names.pop(i)
1357
+ var_names.insert(0, R.gens()[i])
1358
+ c_A = AffineSpace(R.base_ring(), n, var_names)
1359
+ H = Hom(R, c_A.coordinate_ring())
1360
+ coords = [0]*(2*n)
1361
+ coords[i] = c_A.gens()[0]
1362
+ t = 1
1363
+ for j in range(n):
1364
+ if j != i:
1365
+ coords[j + n] = c_A.gens()[t]
1366
+ t = t + 1
1367
+ else:
1368
+ coords[j + n] = 1
1369
+ psi = H(coords)
1370
+ c_polys = [psi(f) for f in c_polys]
1371
+ # choose the component of the subscheme defined by these polynomials
1372
+ # that corresponds to the proper transform
1373
+ irr_comps = c_A.subscheme(c_polys).irreducible_components()
1374
+ for j in range(len(irr_comps)):
1375
+ proper_transform = True
1376
+ for f in irr_comps[j].defining_polynomials():
1377
+ if (c_A.gens()[0] - P[i]).divides(f):
1378
+ proper_transform = False
1379
+ break
1380
+ if proper_transform:
1381
+ patches.append(c_A.curve(irr_comps[j].defining_polynomials()))
1382
+ break
1383
+ elif j + 1 == len(irr_comps):
1384
+ # patch of blowup in this chart is empty
1385
+ patches.append(c_A.subscheme(1))
1386
+ # create the transition maps between the charts
1387
+ t_maps = []
1388
+ for i in range(n):
1389
+ maps = []
1390
+ for j in range(n):
1391
+ AA = patches[i].ambient_space()
1392
+ H = Hom(patches[i], patches[j])
1393
+ vars = AA.gens()
1394
+ homvars = list(AA.gens())
1395
+ homvars.pop(0)
1396
+ homvars.insert(i, 1)
1397
+ coords = [(vars[0] - P[i])*homvars[j] + P[j]]
1398
+ for t in range(n):
1399
+ if t != j:
1400
+ coords.append(homvars[t]/homvars[j])
1401
+ maps.append(H(coords))
1402
+ t_maps.append(maps)
1403
+ # create the restrictions of the projection map
1404
+ proj_maps = []
1405
+ for i in range(n):
1406
+ p_A = patches[i].ambient_space()
1407
+ H = Hom(patches[i], self)
1408
+ homvars = list(p_A.gens())[1:n]
1409
+ homvars.insert(i, 1)
1410
+ coords = [(p_A.gens()[0] - P[i])*homvars[j] + P[j] for j in range(n)]
1411
+ proj_maps.append(H(coords))
1412
+ return (tuple(patches), tuple(t_maps), tuple(proj_maps))
1413
+
1414
+ def resolution_of_singularities(self, extend=False):
1415
+ r"""
1416
+ Return a nonsingular model for this affine curve created by blowing up
1417
+ its singular points.
1418
+
1419
+ The nonsingular model is given as a collection of affine patches that
1420
+ cover it. If ``extend`` is ``False`` and if the base field is a number
1421
+ field, or if the base field is a finite field, the model returned may
1422
+ have singularities with coordinates not contained in the base field. An
1423
+ error is returned if this curve is already nonsingular, or if it has no
1424
+ singular points over its base field. This curve must be irreducible,
1425
+ and must be defined over a number field or finite field.
1426
+
1427
+ INPUT:
1428
+
1429
+ - ``extend`` -- boolean (default: ``False``); specifies whether to
1430
+ extend the base field when necessary to find all singular points when
1431
+ this curve is defined over a number field. If ``extend`` is
1432
+ ``False``, then only singularities with coordinates in the base field
1433
+ of this curve will be resolved. However, setting ``extend`` to
1434
+ ``True`` will slow down computations.
1435
+
1436
+ OUTPUT: a tuple of
1437
+
1438
+ - a tuple of curves in affine space of the same dimension as the
1439
+ ambient space of this curve, which represent affine patches of the
1440
+ resolution of singularities.
1441
+
1442
+ - a tuple of tuples such that the j-th element of the i-th tuple is the
1443
+ transition map from the i-th patch to the j-th patch.
1444
+
1445
+ - a tuple consisting of birational maps from the patches back to the
1446
+ original curve that were created by composing the projection maps
1447
+ generated from the blow up computations. There the i-th element will
1448
+ be a map from the i-th patch.
1449
+
1450
+ EXAMPLES::
1451
+
1452
+ sage: A.<x,y> = AffineSpace(QQ, 2)
1453
+ sage: C = Curve([y^2 - x^3], A)
1454
+ sage: C.resolution_of_singularities()
1455
+ ((Affine Plane Curve over Rational Field defined by s1^2 - x,
1456
+ Affine Plane Curve over Rational Field defined by y*s0^3 - 1),
1457
+ ((Scheme endomorphism of Affine Plane Curve over Rational Field
1458
+ defined by s1^2 - x
1459
+ Defn: Defined on coordinates by sending (x, s1) to (x, s1),
1460
+ Scheme morphism:
1461
+ From: Affine Plane Curve over Rational Field defined by s1^2 - x
1462
+ To: Affine Plane Curve over Rational Field defined by y*s0^3 - 1
1463
+ Defn: Defined on coordinates by sending (x, s1) to (x*s1, 1/s1)),
1464
+ (Scheme morphism:
1465
+ From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1
1466
+ To: Affine Plane Curve over Rational Field defined by s1^2 - x
1467
+ Defn: Defined on coordinates by sending (y, s0) to (y*s0, 1/s0),
1468
+ Scheme endomorphism of Affine Plane Curve over Rational Field
1469
+ defined by y*s0^3 - 1
1470
+ Defn: Defined on coordinates by sending (y, s0) to (y, s0))),
1471
+ (Scheme morphism:
1472
+ From: Affine Plane Curve over Rational Field defined by s1^2 - x
1473
+ To: Affine Plane Curve over Rational Field defined by -x^3 + y^2
1474
+ Defn: Defined on coordinates by sending (x, s1) to (x, x*s1),
1475
+ Scheme morphism:
1476
+ From: Affine Plane Curve over Rational Field defined by y*s0^3 - 1
1477
+ To: Affine Plane Curve over Rational Field defined by -x^3 + y^2
1478
+ Defn: Defined on coordinates by sending (y, s0) to (y*s0, y)))
1479
+
1480
+ ::
1481
+
1482
+ sage: # needs sage.rings.number_field
1483
+ sage: set_verbose(-1)
1484
+ sage: K.<a> = QuadraticField(3)
1485
+ sage: A.<x,y> = AffineSpace(K, 2)
1486
+ sage: C = A.curve(x^4 + 2*x^2 + a*y^3 + 1)
1487
+ sage: C.resolution_of_singularities(extend=True)[0] # long time (2 s)
1488
+ (Affine Plane Curve over Number Field in a0
1489
+ with defining polynomial y^4 - 4*y^2 + 16
1490
+ defined by 24*x^2*ss1^3 + 24*ss1^3 + (a0^3 - 8*a0),
1491
+ Affine Plane Curve over Number Field in a0
1492
+ with defining polynomial y^4 - 4*y^2 + 16
1493
+ defined by 24*s1^2*ss0 + (a0^3 - 8*a0)*ss0^2 + (-6*a0^3)*s1,
1494
+ Affine Plane Curve over Number Field in a0
1495
+ with defining polynomial y^4 - 4*y^2 + 16
1496
+ defined by 8*y^2*s0^4 + (4*a0^3)*y*s0^3 - 32*s0^2 + (a0^3 - 8*a0)*y)
1497
+
1498
+ ::
1499
+
1500
+ sage: A.<x,y,z> = AffineSpace(GF(5), 3)
1501
+ sage: C = Curve([y - x^3, (z - 2)^2 - y^3 - x^3], A)
1502
+ sage: R = C.resolution_of_singularities()
1503
+ sage: R[0]
1504
+ (Affine Curve over Finite Field of size 5
1505
+ defined by x^2 - s1, s1^4 - x*s2^2 + s1, x*s1^3 - s2^2 + x,
1506
+ Affine Curve over Finite Field of size 5
1507
+ defined by y*s2^2 - y^2 - 1, s2^4 - s0^3 - y^2 - 2, y*s0^3 - s2^2 + y,
1508
+ Affine Curve over Finite Field of size 5
1509
+ defined by s0^3*s1 + z*s1^3 + s1^4 - 2*s1^3 - 1,
1510
+ z*s0^3 + z*s1^3 - 2*s0^3 - 2*s1^3 - 1,
1511
+ z^2*s1^3 + z*s1^3 - s1^3 - z + s1 + 2)
1512
+
1513
+ ::
1514
+
1515
+ sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
1516
+ sage: C = A.curve([((x - 2)^2 + y^2)^2 - (x - 2)^2 - y^2 + (x - 2)^3,
1517
+ ....: z - y - 7, w - 4])
1518
+ sage: B = C.resolution_of_singularities()
1519
+ sage: B[0]
1520
+ (Affine Curve over Rational Field defined by s3, s1 - s2,
1521
+ x^2*s2^4 - 4*x*s2^4 + 2*x^2*s2^2 + 4*s2^4 - 8*x*s2^2
1522
+ + x^2 + 7*s2^2 - 3*x + 1,
1523
+ Affine Curve over Rational Field defined by s3, s2 - 1,
1524
+ y^2*s0^4 + 2*y^2*s0^2 + y*s0^3 + y^2 - s0^2 - 1,
1525
+ Affine Curve over Rational Field defined by s3, s1 - 1,
1526
+ z^2*s0^4 - 14*z*s0^4 + 2*z^2*s0^2 + z*s0^3 + 49*s0^4
1527
+ - 28*z*s0^2 - 7*s0^3 + z^2 + 97*s0^2 - 14*z + 48,
1528
+ Closed subscheme of Affine Space of dimension 4 over Rational Field
1529
+ defined by: 1)
1530
+
1531
+ ::
1532
+
1533
+ sage: A.<x,y> = AffineSpace(QQ, 2)
1534
+ sage: C = Curve([y - x^2 + 1], A)
1535
+ sage: C.resolution_of_singularities()
1536
+ Traceback (most recent call last):
1537
+ ...
1538
+ TypeError: this curve is already nonsingular
1539
+
1540
+ ::
1541
+
1542
+ sage: A.<x,y> = AffineSpace(QQ, 2)
1543
+ sage: C = A.curve([(x^2 + y^2 - y - 2)*(y - x^2 + 2) + y^3])
1544
+ sage: C.resolution_of_singularities()
1545
+ Traceback (most recent call last):
1546
+ ...
1547
+ TypeError: this curve has no singular points over its base field. If
1548
+ working over a number field use extend=True
1549
+ """
1550
+ # helper function for extending the base field (in the case of working over a number field)
1551
+
1552
+ def extension(self):
1553
+ F = self.base_ring()
1554
+ from sage.rings.qqbar import QQbar
1555
+ pts = self.change_ring(F.embeddings(QQbar)[0]).rational_points()
1556
+ L = [t for pt in pts for t in pt]
1557
+ K = number_field_elements_from_algebraics(L)[0]
1558
+ if isinstance(K, RationalField):
1559
+ return F.embeddings(F)[0]
1560
+ else:
1561
+ if isinstance(F, RationalField):
1562
+ return F.embeddings(K)[0]
1563
+ else:
1564
+ # make sure the defining polynomial variable names are the same for K, N
1565
+ N = NumberField(K.defining_polynomial().parent()(F.defining_polynomial()), str(K.gen()))
1566
+ return N.composite_fields(K, both_maps=True)[0][1]*F.embeddings(N)[0]
1567
+ # find the set of singular points of this curve
1568
+ # in the case that the base field is a number field, extend it as needed (if extend == True)
1569
+ C = self
1570
+ n = C.ambient_space().dimension_relative()
1571
+ if not self.is_irreducible():
1572
+ raise TypeError("this curve must be irreducible")
1573
+ if not (self.base_ring() in NumberFields() or self.base_ring() in FiniteFields()):
1574
+ raise NotImplementedError("this curve must be defined over either a number field or a finite field")
1575
+ if C.base_ring() in NumberFields() and extend:
1576
+ C = C.change_ring(extension(C.singular_subscheme()))
1577
+ H = End(C)
1578
+ placeholder = H(C.ambient_space().gens())
1579
+ # the list res holds the data for the patches of the resolution of singularities
1580
+ # each element is a list consisting of the curve defining the patch, a list
1581
+ # of the transition maps from that patch to the other patches, a projection
1582
+ # map from the patch to the original curve, and the set of singular points
1583
+ # of the patch
1584
+ res = [[C, [placeholder], placeholder, C.singular_points()]]
1585
+ if not res[0][3]:
1586
+ if C.is_smooth():
1587
+ raise TypeError("this curve is already nonsingular")
1588
+ else:
1589
+ raise TypeError("this curve has no singular points over "
1590
+ "its base field. If working over "
1591
+ "a number field use extend=True")
1592
+ not_resolved = True
1593
+ t = 0
1594
+ # loop through the patches and blow up each until no patch has singular points
1595
+ while not_resolved:
1596
+ BC, t_maps, pi, pts = res[t][0], res[t][1], res[t][2], res[t][3]
1597
+ # check if there are any singular points in this patch
1598
+ if not pts:
1599
+ t += 1
1600
+ if t == len(res):
1601
+ not_resolved = False
1602
+ continue
1603
+ # the identity map should be replaced for each of the charts of the blow up
1604
+ t_maps.pop(t)
1605
+ # blow up pts[0]
1606
+ B = list(BC.blowup(pts[0]))
1607
+ B = [list(B[0]), [list(B[1][i]) for i in range(len(B[1]))], list(B[2])]
1608
+ # the t-th element of res will be replaced with the new data corresponding to the charts
1609
+ # of the blow up
1610
+ res.pop(t)
1611
+ # take out the transition maps from the other resolution patches to the t-th patch
1612
+ old_maps = [res[i][1].pop(t) for i in range(len(res))]
1613
+ patches_to_add = []
1614
+ # generate the needed data for each patch of the blow up
1615
+ for i in range(len(B[0])):
1616
+ # check if there are any singular points where this patch meets the exceptional divisor
1617
+ AA = AffineSpace(B[0][i].base_ring(), n - 1, 'x')
1618
+ coords = [pts[0][i]]
1619
+ coords.extend(list(AA.gens()))
1620
+ H = Hom(B[0][i].ambient_space().coordinate_ring(), AA.coordinate_ring())
1621
+ poly_hom = H(coords)
1622
+ X = AA.subscheme([poly_hom(f) for f in B[0][i].defining_polynomials()])
1623
+ # in the case of working over a number field, it might be necessary to extend the base
1624
+ # field in order to find all intersection points
1625
+ n_pts = []
1626
+ if B[0][i].base_ring() in NumberFields() and extend:
1627
+ emb = extension(X)
1628
+ X = X.change_ring(emb)
1629
+ tmp_curve = B[0][i].change_ring(emb)
1630
+ for pt in X.rational_points():
1631
+ tmp_pt = tmp_curve([pts[0][i]] + list(pt))
1632
+ if tmp_curve.is_singular(tmp_pt):
1633
+ n_pts.append(tmp_pt)
1634
+ # avoid needlessly extending the base field
1635
+ if n_pts:
1636
+ # coerce everything to the new base field
1637
+ BC = BC.change_ring(emb)
1638
+ t_maps = [t_maps[j].change_ring(emb) for j in range(len(t_maps))]
1639
+ old_maps = [old_maps[j].change_ring(emb) for j in range(len(old_maps))]
1640
+ pi = pi.change_ring(emb)
1641
+ pts = [pt.change_ring(emb) for pt in pts]
1642
+ # coerce the current blow up data
1643
+ for j in range(len(B[0])):
1644
+ B[0][j] = B[0][j].change_ring(emb)
1645
+ for j in range(len(B[1])):
1646
+ for k in range(len(B[1])):
1647
+ B[1][j][k] = B[1][j][k].change_ring(emb)
1648
+ for j in range(len(B[2])):
1649
+ B[2][j] = B[2][j].change_ring(emb)
1650
+ # coerce the other data in res
1651
+ for j in range(len(res)):
1652
+ res[j][0] = res[j][0].change_ring(emb)
1653
+ for k in range(len(res[j][1])):
1654
+ res[j][1][k] = res[j][1][k].change_ring(emb)
1655
+ res[j][2].change_ring(emb)
1656
+ for k in range(len(res[j][3])):
1657
+ res[j][3][k] = res[j][3][k].change_ring(emb)
1658
+ else:
1659
+ for pt in X.rational_points():
1660
+ tmp_pt = B[0][i]([pts[0][i]] + list(pt))
1661
+ if B[0][i].is_singular(tmp_pt):
1662
+ n_pts.append(tmp_pt)
1663
+ b_data = [B[0][i]]
1664
+ # projection map and its inverse
1665
+ t_pi = B[2][i]
1666
+ coords = [(BC.ambient_space().gens()[j] - pts[0][j]) / (BC.ambient_space().gens()[i] - pts[0][i])
1667
+ for j in range(n)]
1668
+ coords.pop(i)
1669
+ coords.insert(0, BC.ambient_space().gens()[i])
1670
+ H = Hom(BC, B[0][i])
1671
+ t_pi_inv = H(coords)
1672
+ # compose the current transition maps from the original curve to the other patches
1673
+ # with the projection map
1674
+ L = list(t_maps)
1675
+ for j in range(len(t_maps)):
1676
+ L[j] = L[j] * t_pi
1677
+ for j in range(len(B[1][i])):
1678
+ L.insert(t + j, B[1][i][j])
1679
+ b_data.append(L)
1680
+ # update transition maps of each other element of res
1681
+ for j in range(len(res)):
1682
+ new_t_map = t_pi_inv*old_maps[j]
1683
+ res[j][1].insert(t + i, new_t_map)
1684
+ # create the projection map
1685
+ b_data.append(pi*t_pi)
1686
+ # singular points
1687
+ # translate the singular points of the parent patch (other than that which was the center of the
1688
+ # blow up) by the inverse of the first projection map
1689
+ for j in range(1, len(pts)):
1690
+ # make sure this point is in this chart before attempting to map it
1691
+ try:
1692
+ n_pts.append(t_pi_inv(BC(pts[j])))
1693
+ except (TypeError, ZeroDivisionError):
1694
+ pass
1695
+ b_data.append(n_pts)
1696
+ patches_to_add.append(b_data)
1697
+ for i in range(len(patches_to_add)):
1698
+ res.insert(t + i, patches_to_add[i])
1699
+ t = 0
1700
+ patches = [res[i][0] for i in range(len(res))]
1701
+ t_maps = [tuple(res[i][1]) for i in range(len(res))]
1702
+ p_maps = [res[i][2] for i in range(len(res))]
1703
+ return (tuple(patches), tuple(t_maps), tuple(p_maps))
1704
+
1705
+ def tangent_line(self, p):
1706
+ """
1707
+ Return the tangent line at the point ``p``.
1708
+
1709
+ INPUT:
1710
+
1711
+ - ``p`` -- a rational point of the curve
1712
+
1713
+ EXAMPLES::
1714
+
1715
+ sage: A3.<x,y,z> = AffineSpace(3, QQ)
1716
+ sage: C = Curve([x + y + z, x^2 - y^2*z^2 + z^3])
1717
+ sage: p = C(0,0,0)
1718
+ sage: C.tangent_line(p)
1719
+ Traceback (most recent call last):
1720
+ ...
1721
+ ValueError: the curve is not smooth at (0, 0, 0)
1722
+ sage: p = C(1,0,-1)
1723
+ sage: C.tangent_line(p)
1724
+ Affine Curve over Rational Field defined by x + y + z, 2*x + 3*z + 1
1725
+
1726
+ We check that the tangent line at ``p`` is the tangent space at ``p``,
1727
+ translated to ``p``. ::
1728
+
1729
+ sage: Tp = C.tangent_space(p)
1730
+ sage: Tp
1731
+ Closed subscheme of Affine Space of dimension 3 over Rational Field
1732
+ defined by: x + y + z, 2*x + 3*z
1733
+ sage: phi = A3.translation(A3.origin(), p)
1734
+ sage: T = phi * Tp.embedding_morphism()
1735
+ sage: T.image()
1736
+ Closed subscheme of Affine Space of dimension 3 over Rational Field
1737
+ defined by: -2*y + z + 1, x + y + z
1738
+ sage: _ == C.tangent_line(p)
1739
+ True
1740
+ """
1741
+ A = self.ambient_space()
1742
+ R = A.coordinate_ring()
1743
+ gens = R.gens()
1744
+
1745
+ Tp = self.tangent_space(p)
1746
+
1747
+ if Tp.dimension() > 1:
1748
+ raise ValueError("the curve is not smooth at {}".format(p))
1749
+
1750
+ from sage.schemes.curves.constructor import Curve
1751
+
1752
+ # translate to p
1753
+ I0 = []
1754
+ for poly in Tp.defining_polynomials():
1755
+ I0.append(poly.subs({x: x - c for x, c in zip(gens, p)}))
1756
+
1757
+ return Curve(I0, A)
1758
+
1759
+
1760
+ class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field):
1761
+ """
1762
+ Affine plane curves over fields.
1763
+ """
1764
+ _point = AffinePlaneCurvePoint_field
1765
+
1766
+ def has_vertical_asymptote(self) -> bool:
1767
+ """
1768
+ Check if the curve is not a line and has vertical asymptotes.
1769
+
1770
+ EXAMPLES::
1771
+
1772
+ sage: A2.<x,y> = AffineSpace(2, QQ)
1773
+ sage: Curve(x).has_vertical_asymptote()
1774
+ False
1775
+ sage: Curve(y^2 * x + x + y).has_vertical_asymptote()
1776
+ True
1777
+ """
1778
+ A = self.ambient_space()
1779
+ R = A.coordinate_ring()
1780
+ x, y = R.gens()
1781
+ f = self.defining_polynomial().radical()
1782
+ dy = f.degree(y)
1783
+ dxy = f.coefficient({y: dy}).degree()
1784
+ return dxy > 0 and f.degree() > 1
1785
+
1786
+ def is_vertical_line(self) -> bool:
1787
+ """
1788
+ Check if the curve is a vertical line.
1789
+
1790
+ EXAMPLES::
1791
+
1792
+ sage: A2.<x, y> = AffineSpace(2, QQ)
1793
+ sage: Curve(x - 1).is_vertical_line()
1794
+ True
1795
+ sage: Curve(x - y).is_vertical_line()
1796
+ False
1797
+ sage: Curve(y^2 * x + x + y).is_vertical_line()
1798
+ False
1799
+ """
1800
+ A = self.ambient_space()
1801
+ R = A.coordinate_ring()
1802
+ x, y = R.gens()
1803
+ f = self.defining_polynomial().radical()
1804
+ return f.degree(y) == 0 and f.degree() == 1
1805
+
1806
+ @cached_method
1807
+ def fundamental_group(self, simplified=True, puiseux=True):
1808
+ r"""
1809
+ Return a presentation of the fundamental group of the complement
1810
+ of ``self``.
1811
+
1812
+ INPUT:
1813
+
1814
+ - ``simplified`` -- boolean (default: ``True``); to simplify the presentation
1815
+
1816
+ - ``puiseux`` -- boolean (default: ``True``); to decide if the
1817
+ presentation is constructed in the classical way or using Puiseux
1818
+ shortcut
1819
+
1820
+ OUTPUT:
1821
+
1822
+ A presentation with generators `x_1, \dots, x_d` and relations. If ``puiseux``
1823
+ is ``False`` the relations are `(x_j\cdot \tau)\cdot x_j^{-1}` for `1\leq j<d`
1824
+ and `tau` a braid in the braid monodromy; finally the presentation
1825
+ is simplified. If ``puiseux`` is ``True``, each
1826
+ `tau` is decomposed as `\alpha^{-1}\cdot\beta\cdot\alpha`, where `\beta` is
1827
+ a positive braid; the relations are `((x_j\cdot \beta)\cdot x_j^{-1})\cdot \alpha`
1828
+ where `j` is an integer of the ``Tietze`` word of `\beta`. This presentation
1829
+ is not simplified by default since it represents the homotopy type of
1830
+ the complement of the curve.
1831
+
1832
+ .. NOTE::
1833
+
1834
+ The curve must be defined over the rationals or a number field
1835
+ with an embedding over `\QQbar`. This functionality requires
1836
+ the ``sirocco`` package to be installed.
1837
+
1838
+ EXAMPLES::
1839
+
1840
+ sage: # needs sirocco
1841
+ sage: A.<x,y> = AffineSpace(QQ, 2)
1842
+ sage: C = A.curve(y^2 - x^3 - x^2)
1843
+ sage: C.fundamental_group(puiseux=False)
1844
+ Finitely presented group < x0 | >
1845
+ sage: bm = C.braid_monodromy()
1846
+ sage: g = C.fundamental_group(simplified=False)
1847
+ sage: g.sorted_presentation()
1848
+ Finitely presented group < x0, x1 | x1^-1*x0^-1*x1*x0, x1^-1*x0 >
1849
+ sage: g.simplified()
1850
+ Finitely presented group < x0 | >
1851
+
1852
+ In the case of number fields, they need to have an embedding
1853
+ to the algebraic field::
1854
+
1855
+ sage: # needs sage.rings.number_field
1856
+ sage: x = polygen(ZZ)
1857
+ sage: a = QQ[x](x^2 + 5).roots(QQbar)[0][0]
1858
+ sage: F = NumberField(a.minpoly(), 'a', embedding=a)
1859
+ sage: F.inject_variables()
1860
+ Defining a
1861
+ sage: A.<x,y> = AffineSpace(F, 2)
1862
+ sage: C = A.curve(y^2 - a*x^3 - x^2)
1863
+ sage: C.fundamental_group() # needs sirocco
1864
+ Finitely presented group < x0 | >
1865
+ sage: C = A.curve(x * (x - 1))
1866
+ sage: C.fundamental_group() # needs sirocco
1867
+ Finitely presented group < x0, x1 | >
1868
+ """
1869
+ from sage.schemes.curves.zariski_vankampen import fundamental_group_from_braid_mon
1870
+ bm = self.braid_monodromy()
1871
+ if not bm:
1872
+ f = self.defining_polynomial()
1873
+ x, y = f.parent().gens()
1874
+ d0 = f.degree(y)
1875
+ f0 = f.coefficient({y: d0})
1876
+ d = d0 + f0.degree(x)
1877
+ else:
1878
+ d = bm[0].parent().strands()
1879
+ G = fundamental_group_from_braid_mon(bm, degree=d,
1880
+ simplified=simplified,
1881
+ puiseux=puiseux)
1882
+ if simplified:
1883
+ G = G.simplified()
1884
+ return G
1885
+
1886
+ @cached_method
1887
+ def braid_monodromy(self):
1888
+ r"""
1889
+ Compute the braid monodromy of a projection of the curve.
1890
+
1891
+ OUTPUT:
1892
+
1893
+ A list of braids. The braids correspond to paths based in the same point;
1894
+ each of this paths is the conjugated of a loop around one of the points
1895
+ in the discriminant of the projection of ``self``.
1896
+
1897
+ .. NOTE::
1898
+
1899
+ The projection over the `x` axis is used if there are no vertical asymptotes.
1900
+ Otherwise, a linear change of variables is done to fall into the previous case.
1901
+
1902
+ .. NOTE::
1903
+
1904
+ This functionality requires the ``sirocco`` package to be installed.
1905
+
1906
+ EXAMPLES::
1907
+
1908
+ sage: A.<x,y> = AffineSpace(QQ, 2)
1909
+ sage: C = A.curve((x^2-y^3)*(x+3*y-5))
1910
+ sage: C.braid_monodromy() # needs sirocco
1911
+ [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1,
1912
+ s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1,
1913
+ s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1,
1914
+ s1*s0*s2*s0^-1*s2*s1^-1]
1915
+ sage: T.<t> = QQ[]
1916
+ sage: K.<a> = NumberField(t^3 + 2, 'a')
1917
+ sage: A.<x, y> = AffineSpace(K, 2)
1918
+ sage: Curve(y^2 + a * x).braid_monodromy() # needs sage.graphs
1919
+ Traceback (most recent call last):
1920
+ ...
1921
+ NotImplementedError: the base field must have an embedding to the algebraic field
1922
+ """
1923
+ from sage.schemes.curves.zariski_vankampen import braid_monodromy
1924
+ F = self.base_ring()
1925
+ from sage.rings.qqbar import QQbar
1926
+ if QQbar.coerce_map_from(F) is None:
1927
+ raise NotImplementedError("the base field must have an embedding"
1928
+ " to the algebraic field")
1929
+ f = self.defining_polynomial()
1930
+ return braid_monodromy(f)[0]
1931
+
1932
+ def riemann_surface(self, **kwargs):
1933
+ r"""
1934
+ Return the complex Riemann surface determined by this curve.
1935
+
1936
+ OUTPUT: a :class:`~sage.schemes.riemann_surfaces.riemann_surface.RiemannSurface` object
1937
+
1938
+ EXAMPLES::
1939
+
1940
+ sage: R.<x,y> = QQ[]
1941
+ sage: C = Curve(x^3 + 3*y^3 + 5)
1942
+ sage: C.riemann_surface() # needs sage.graphs
1943
+ Riemann surface defined by polynomial f = x^3 + 3*y^3 + 5 = 0,
1944
+ with 53 bits of precision
1945
+ """
1946
+ from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface
1947
+ S = RiemannSurface(self.defining_polynomial(), **kwargs)
1948
+ S._curve = self
1949
+ return S
1950
+
1951
+
1952
+ class AffinePlaneCurve_finite_field(AffinePlaneCurve_field):
1953
+ """
1954
+ Affine plane curves over finite fields.
1955
+ """
1956
+ _point = AffinePlaneCurvePoint_finite_field
1957
+
1958
+ # CHECK WHAT ASSUMPTIONS ARE MADE REGARDING AFFINE VS. PROJECTIVE MODELS!!!
1959
+ # THIS IS VERY DIRTY STILL -- NO DATASTRUCTURES FOR DIVISORS.
1960
+ def riemann_roch_basis(self, D):
1961
+ r"""
1962
+ Return a basis of the Riemann-Roch space of the divisor ``D``.
1963
+
1964
+ This interfaces with Singular's Brill-Noether command.
1965
+
1966
+ This curve is assumed to be a plane curve defined by a polynomial
1967
+ equation `f(x,y) = 0` over a prime finite field `F = GF(p)` in 2
1968
+ variables `x,y` representing a curve `X: f(x,y) = 0` having `n`
1969
+ `F`-rational points (see the Sage function ``places_on_curve``)
1970
+
1971
+ INPUT:
1972
+
1973
+ - ``D`` -- an `n`-tuple of integers `(d_1, ..., d_n)` representing the
1974
+ divisor `Div = d_1P_1 + \dots + d_nP_n`, where `X(F) = \{P_1, \dots,
1975
+ P_n\}`. The ordering is that dictated by ``places_on_curve``.
1976
+
1977
+ OUTPUT: a basis of `L(Div)`.
1978
+
1979
+ EXAMPLES::
1980
+
1981
+ sage: R = PolynomialRing(GF(5), 2, names=["x","y"])
1982
+ sage: x, y = R.gens()
1983
+ sage: f = y^2 - x^9 - x
1984
+ sage: C = Curve(f)
1985
+ sage: D = [6,0,0,0,0,0]
1986
+ sage: C.riemann_roch_basis(D)
1987
+ [1, (-x*z^5 + y^2*z^4)/x^6, (-x*z^6 + y^2*z^5)/x^7, (-x*z^7 + y^2*z^6)/x^8]
1988
+ """
1989
+ F = self.base_ring()
1990
+ if not F.is_prime_field():
1991
+ raise TypeError("only works for curves over prime finite fields")
1992
+
1993
+ p = F.characteristic()
1994
+ f = self.defining_polynomial()
1995
+ gens = f.parent().gens()
1996
+
1997
+ G = singular(','.join(str(x) for x in D), type='intvec')
1998
+
1999
+ singular.lib('brnoeth')
2000
+ singular.ring(p, gens, 'lp')
2001
+
2002
+ X = singular(f).Adj_div()
2003
+ P = singular.NSplaces(1, X)
2004
+ T = P[1][2]
2005
+ T.set_ring() # necessary
2006
+
2007
+ return [g[1].sage() / g[2].sage() for g in G.BrillNoether(P)]
2008
+
2009
+ def rational_points(self, algorithm='enum'):
2010
+ r"""
2011
+ Return sorted list of all rational points on this curve.
2012
+
2013
+ INPUT:
2014
+
2015
+ - ``algorithm`` -- possible choices:
2016
+
2017
+ + ``'enum'`` -- use *very* naive point enumeration to find all
2018
+ rational points on this curve over a finite field.
2019
+
2020
+ + ``'bn'`` -- via Singular's Brill-Noether package.
2021
+
2022
+ + ``'all'`` -- use all implemented algorithms and verify that they
2023
+ give the same answer, then return it
2024
+
2025
+ .. NOTE::
2026
+
2027
+ The Brill-Noether package does not always work. When it fails, a
2028
+ :exc:`RuntimeError` exception is raised.
2029
+
2030
+ EXAMPLES::
2031
+
2032
+ sage: x, y = (GF(5)['x,y']).gens()
2033
+ sage: f = y^2 - x^9 - x
2034
+ sage: C = Curve(f); C
2035
+ Affine Plane Curve over Finite Field of size 5 defined by -x^9 + y^2 - x
2036
+ sage: C.rational_points(algorithm='bn')
2037
+ [(0, 0), (2, 2), (2, 3), (3, 1), (3, 4)]
2038
+ sage: C = Curve(x - y + 1)
2039
+ sage: C.rational_points()
2040
+ [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)]
2041
+
2042
+ We compare Brill-Noether and enumeration::
2043
+
2044
+ sage: x, y = (GF(17)['x,y']).gens()
2045
+ sage: C = Curve(x^2 + y^5 + x*y - 19)
2046
+ sage: v = C.rational_points(algorithm='bn')
2047
+ sage: w = C.rational_points(algorithm='enum')
2048
+ sage: len(v)
2049
+ 20
2050
+ sage: v == w
2051
+ True
2052
+
2053
+ sage: # needs sage.rings.finite_rings
2054
+ sage: A.<x,y> = AffineSpace(2, GF(9,'a'))
2055
+ sage: C = Curve(x^2 + y^2 - 1); C
2056
+ Affine Plane Curve over Finite Field in a of size 3^2
2057
+ defined by x^2 + y^2 - 1
2058
+ sage: C.rational_points()
2059
+ [(0, 1), (0, 2), (1, 0), (2, 0), (a + 1, a + 1),
2060
+ (a + 1, 2*a + 2), (2*a + 2, a + 1), (2*a + 2, 2*a + 2)]
2061
+ """
2062
+ if algorithm == "enum":
2063
+ f = self.defining_polynomial()
2064
+ K = f.parent().base_ring()
2065
+ return sorted(self((x, y)) for x in K for y in K if f(x, y) == 0)
2066
+
2067
+ F = self.base_ring()
2068
+ if not F.is_prime_field():
2069
+ raise TypeError("other algorithms only work for curves over prime finite fields")
2070
+
2071
+ if algorithm == "bn":
2072
+ f = self.defining_polynomial()._singular_()
2073
+ singular = f.parent()
2074
+ singular.lib('brnoeth')
2075
+ try:
2076
+ X1 = f.Adj_div()
2077
+ except (TypeError, RuntimeError) as s:
2078
+ raise RuntimeError(str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above).")
2079
+
2080
+ X2 = singular.NSplaces(1, X1)
2081
+ R = X2[5][1][1]
2082
+ singular.set_ring(R)
2083
+
2084
+ # We use sage_flattened_str_list since iterating through
2085
+ # the entire list through the sage/singular interface directly
2086
+ # would involve hundreds of calls to singular, and timing issues
2087
+ # with the expect interface could crop up. Also, this is vastly
2088
+ # faster (and more robust).
2089
+ v = singular('POINTS').sage_flattened_str_list()
2090
+ pnts = [self(int(v[3*i]), int(v[3*i+1]))
2091
+ for i in range(len(v)//3) if int(v[3*i+2])]
2092
+ # remove multiple points
2093
+ return sorted(set(pnts))
2094
+
2095
+ elif algorithm == "all":
2096
+ S_enum = self.rational_points(algorithm='enum')
2097
+ S_bn = self.rational_points(algorithm='bn')
2098
+ if S_enum != S_bn:
2099
+ raise RuntimeError("Bug in rational_points -- different algorithms give different answers for curve %s!" % self)
2100
+ return S_enum
2101
+ else:
2102
+ raise ValueError("No algorithm '%s' known" % algorithm)
2103
+
2104
+
2105
+ class IntegralAffineCurve(AffineCurve_field):
2106
+ """
2107
+ Base class for integral affine curves.
2108
+ """
2109
+ _point = IntegralAffineCurvePoint
2110
+ _closed_point = IntegralAffineCurveClosedPoint
2111
+
2112
+ def function_field(self):
2113
+ """
2114
+ Return the function field of the curve.
2115
+
2116
+ EXAMPLES::
2117
+
2118
+ sage: A.<x,y> = AffineSpace(QQ, 2)
2119
+ sage: C = Curve(x^3 - y^2 - x^4 - y^4)
2120
+ sage: C.function_field()
2121
+ Function field in y defined by y^4 + y^2 + x^4 - x^3
2122
+
2123
+ ::
2124
+
2125
+ sage: # needs sage.rings.finite_rings
2126
+ sage: A.<x,y> = AffineSpace(GF(8), 2)
2127
+ sage: C = Curve(x^5 + y^5 + x*y + 1)
2128
+ sage: C.function_field()
2129
+ Function field in y defined by y^5 + x*y + x^5 + 1
2130
+ """
2131
+ return self._function_field
2132
+
2133
+ @lazy_attribute
2134
+ def _genus(self):
2135
+ """
2136
+ The geometric genus of the curve.
2137
+
2138
+ EXAMPLES::
2139
+
2140
+ sage: A.<x,y> = AffineSpace(GF(2), 2)
2141
+ sage: C = Curve(x^5 + y^5 + x*y + 1)
2142
+ sage: C.genus() # indirect doctest
2143
+ 1
2144
+
2145
+ TESTS::
2146
+
2147
+ sage: # needs sage.rings.number_field
2148
+ sage: R.<T> = QQ[]
2149
+ sage: N.<a> = NumberField(T^2 + 1)
2150
+ sage: A2.<x,y> = AffineSpace(N, 2)
2151
+ sage: C = Curve(y^2 - x^3 + x, A2)
2152
+ sage: C.genus()
2153
+ 1
2154
+ """
2155
+ # Singular's genus command is usually much faster than the genus method
2156
+ # of function fields in Sage. But unfortunately Singular's genus
2157
+ # command does not work over extension fields.
2158
+ if self.base_ring().degree() > 1:
2159
+ return self._function_field.genus()
2160
+
2161
+ # call Singular's genus command
2162
+ return self.defining_ideal().genus()
2163
+
2164
+ def __call__(self, *args):
2165
+ """
2166
+ Return a rational point, a pointset or a function depending on ``args``.
2167
+
2168
+ EXAMPLES::
2169
+
2170
+ sage: # needs sage.rings.finite_rings
2171
+ sage: A.<x,y> = AffineSpace(GF(8), 2)
2172
+ sage: C = Curve(x^5 + y^5 + x*y + 1)
2173
+ sage: C(1,1)
2174
+ (1, 1)
2175
+ sage: C(x/y)
2176
+ (x/(x^5 + 1))*y^4 + x^2/(x^5 + 1)
2177
+ sage: C(GF(8^2))
2178
+ Set of rational points of Closed subscheme of Affine Space of dimension 2
2179
+ over Finite Field in z6 of size 2^6 defined by: x^5 + y^5 + x*y + 1
2180
+
2181
+ ::
2182
+
2183
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2184
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2185
+ sage: C([0,0,0])
2186
+ (0, 0, 0)
2187
+ sage: C(y)
2188
+ z^2
2189
+ sage: C(A.coordinate_ring()(y))
2190
+ z^2
2191
+ """
2192
+ try:
2193
+ return super().__call__(*args)
2194
+ except TypeError as e:
2195
+ try:
2196
+ return self.function(*args)
2197
+ except AttributeError:
2198
+ raise e
2199
+
2200
+ def function(self, f):
2201
+ """
2202
+ Return the function field element coerced from ``f``.
2203
+
2204
+ INPUT:
2205
+
2206
+ - ``f`` -- an element of the fraction field of the coordinate ring of
2207
+ the ambient space or the coordinate ring of the curve
2208
+
2209
+ OUTPUT: an element of the function field of this curve
2210
+
2211
+ EXAMPLES::
2212
+
2213
+ sage: # needs sage.rings.finite_rings
2214
+ sage: A.<x,y> = AffineSpace(GF(8), 2)
2215
+ sage: C = Curve(x^5 + y^5 + x*y + 1)
2216
+ sage: f = C.function(x/y)
2217
+ sage: f
2218
+ (x/(x^5 + 1))*y^4 + x^2/(x^5 + 1)
2219
+ sage: df = f.differential(); df
2220
+ ((1/(x^10 + 1))*y^4 + x^6/(x^10 + 1)) d(x)
2221
+ sage: df.divisor() # long time
2222
+ 2*Place (1/x, 1/x^4*y^4 + 1/x^3*y^3 + 1/x^2*y^2 + 1/x*y + 1)
2223
+ + 2*Place (1/x, 1/x*y + 1)
2224
+ - 2*Place (x + 1, y)
2225
+ - 2*Place (x^4 + x^3 + x^2 + x + 1, y)
2226
+ """
2227
+ R = self.ambient_space().coordinate_ring()
2228
+ if f not in R and f.parent() is self.coordinate_ring():
2229
+ f = f.lift()
2230
+
2231
+ phi = self._map_to_function_field
2232
+ num = R(f.numerator())
2233
+ den = R(f.denominator())
2234
+ return phi(num) / phi(den)
2235
+
2236
+ def coordinate_functions(self):
2237
+ """
2238
+ Return the coordinate functions.
2239
+
2240
+ EXAMPLES::
2241
+
2242
+ sage: # needs sage.rings.finite_rings
2243
+ sage: A.<x,y> = AffineSpace(GF(8), 2)
2244
+ sage: C = Curve(x^5 + y^5 + x*y + 1)
2245
+ sage: x, y = C.coordinate_functions()
2246
+ sage: x^5 + y^5 + x*y + 1
2247
+ 0
2248
+ """
2249
+ return self._coordinate_functions
2250
+
2251
+ def pull_from_function_field(self, f):
2252
+ """
2253
+ Return the fraction corresponding to ``f``.
2254
+
2255
+ INPUT:
2256
+
2257
+ - ``f`` -- an element of the function field
2258
+
2259
+ OUTPUT:
2260
+
2261
+ A fraction of polynomials in the coordinate ring of the ambient space
2262
+ of the curve.
2263
+
2264
+ EXAMPLES::
2265
+
2266
+ sage: # needs sage.rings.finite_rings
2267
+ sage: A.<x,y> = AffineSpace(GF(8), 2)
2268
+ sage: C = Curve(x^5 + y^5 + x*y + 1)
2269
+ sage: F = C.function_field()
2270
+ sage: C.pull_from_function_field(F.gen())
2271
+ y
2272
+ sage: C.pull_from_function_field(F.one())
2273
+ 1
2274
+ sage: C.pull_from_function_field(F.zero())
2275
+ 0
2276
+ sage: f1 = F.gen()
2277
+ sage: f2 = F.base_ring().gen()
2278
+ sage: C.function(C.pull_from_function_field(f1)) == f1
2279
+ True
2280
+ sage: C.function(C.pull_from_function_field(f2)) == f2
2281
+ True
2282
+ """
2283
+ return self._map_from_function_field(f)
2284
+
2285
+ @lazy_attribute
2286
+ def _nonsingular_model(self):
2287
+ """
2288
+ Return the data of a nonsingular model of the curve.
2289
+
2290
+ The data consists of an abstract function field `M`, a map from the
2291
+ fraction field of the coordinate ring `R` of the ambient space of the
2292
+ curve to the function field, and the inverse map.
2293
+
2294
+ The coordinate ring of the curve is the quotient of `R` by the kernel
2295
+ of the map restricted to `R`.
2296
+
2297
+ TESTS::
2298
+
2299
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2300
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2301
+ sage: C._nonsingular_model
2302
+ (Function field in z defined by z^3 + 10*x,
2303
+ Ring morphism:
2304
+ From: Fraction Field of Multivariate Polynomial Ring in x, y, z
2305
+ over Finite Field of size 11
2306
+ To: Function field in z defined by z^3 + 10*x
2307
+ Defn: x |--> x
2308
+ y |--> z^2
2309
+ z |--> z,
2310
+ Ring morphism:
2311
+ From: Function field in z defined by z^3 + 10*x
2312
+ To: Fraction Field of Multivariate Polynomial Ring in x, y, z
2313
+ over Finite Field of size 11)
2314
+ """
2315
+ from sage.structure.sequence import Sequence
2316
+ from sage.rings.fraction_field import FractionField
2317
+ from sage.rings.function_field.constructor import FunctionField
2318
+ from sage.rings.function_field.maps import FunctionFieldRingMorphism
2319
+
2320
+ k = self.base_ring()
2321
+ I = self.defining_ideal()
2322
+
2323
+ # invlex is the lex order with x < y < z for R = k[x,y,z] for instance
2324
+ R = I.parent().ring().change_ring(order='invlex')
2325
+ I0 = I.change_ring(R)
2326
+ n = R.ngens()
2327
+
2328
+ names = R.variable_names()
2329
+
2330
+ gbasis = I0.groebner_basis()
2331
+
2332
+ if not I0.is_prime():
2333
+ raise TypeError("the curve is not integral")
2334
+
2335
+ # Suppose the generators of the defining ideal I of the curve is
2336
+ #
2337
+ # -y^2 + x*z, -z^2 + y, -y*z + x.
2338
+ #
2339
+ # Then the Groebner basis of the ideal with respect to the elimination
2340
+ # order invlex is
2341
+ #
2342
+ # f0 = z^2 - y,
2343
+ # f1 = y*z - x,
2344
+ # f2 = x*z - y^2,
2345
+ # f3 = y^3 - x^2.
2346
+ #
2347
+ # Now the task is to find f that has minimal degree as a polynomial
2348
+ # in the i-th variable. The result is
2349
+ #
2350
+ # f0 z^2
2351
+ # f1 y*z
2352
+ # f2 x*z o
2353
+ # f3 y^3 o
2354
+ # ------------------------------
2355
+ # k[x] k[x,y] k[x,y,z]
2356
+ #
2357
+ # Hence x is an independent variable; f3 is the syzygy for y; f2 is the
2358
+ # syzygy for z. Now x is the generator of a rational function field F0;
2359
+ # y is the generator of the extension F1 of F0 by f3; z is the
2360
+ # generator of the extension F2 of F1 by f2.
2361
+
2362
+ basis = list(gbasis)
2363
+ syzygy = {}
2364
+ for i in range(n):
2365
+ S = k[R._first_ngens(i + 1)]
2366
+ while basis:
2367
+ f = basis.pop()
2368
+ if f in S:
2369
+ if i not in syzygy and f:
2370
+ syzygy[i] = f
2371
+ else:
2372
+ basis.append(f)
2373
+ break
2374
+
2375
+ # sanity check
2376
+ indeps = [i for i in range(n) if i not in syzygy]
2377
+ if len(indeps) != 1:
2378
+ raise TypeError("not a curve")
2379
+ indep = indeps[0]
2380
+
2381
+ F = FunctionField(k, names[indep])
2382
+ coords = {indep: F.gen()}
2383
+
2384
+ for i in range(n):
2385
+ if i == indep:
2386
+ continue
2387
+ P = PolynomialRing(F, 'T')
2388
+ f = P([R(c).subs(coords) for c in syzygy[i].polynomial(R.gen(i))])
2389
+ F = F.extension(f, names[i])
2390
+ coords[i] = F.gen()
2391
+
2392
+ proper_extension = F.base_field() is not F
2393
+
2394
+ if proper_extension:
2395
+ N, from_N, to_N = F.simple_model()
2396
+ M, from_M, to_M = N.separable_model()
2397
+ coordinate_functions = tuple([to_M(to_N(F(coords[i]))) for i in range(n)])
2398
+ else:
2399
+ M = F # is rational function field
2400
+ coordinate_functions = tuple([coords[i] for i in range(n)])
2401
+
2402
+ # map to M
2403
+
2404
+ FR = FractionField(I.ring())
2405
+ map_to_function_field = hom(FR, M, coordinate_functions)
2406
+
2407
+ # map from M
2408
+
2409
+ def convert(f, i):
2410
+ if i == indep:
2411
+ i = i - 1
2412
+ if i < 0:
2413
+ return f._x # fraction representing rational function field element
2414
+ fx = f._x # polynomial representing function field element
2415
+ if not fx:
2416
+ fxlist = [fx.base_ring().zero()]
2417
+ else:
2418
+ fxlist = fx.list()
2419
+ coeffs = Sequence(convert(c, i - 1) for c in fxlist)
2420
+ B = coeffs.universe()
2421
+ S = B[names[i]]
2422
+ return S(coeffs)
2423
+
2424
+ z = M.gen()
2425
+
2426
+ if proper_extension:
2427
+ Z = FR(convert(from_N(from_M(z)), n - 1))
2428
+
2429
+ def evaluate(f):
2430
+ coeffs = f._x.list()
2431
+ v = 0
2432
+ while coeffs:
2433
+ v = v * Z + coeffs.pop()._x
2434
+ return FR(v)
2435
+ else:
2436
+ def evaluate(f):
2437
+ return FR(f._x)
2438
+
2439
+ map_from_function_field = FunctionFieldRingMorphism(Hom(M, FR), evaluate)
2440
+
2441
+ # sanity check
2442
+ assert all(map_to_function_field(f).is_zero() for f in I.gens())
2443
+ assert map_to_function_field(map_from_function_field(z)) == z
2444
+
2445
+ return M, map_to_function_field, map_from_function_field
2446
+
2447
+ @lazy_attribute
2448
+ def _function_field(self):
2449
+ """
2450
+ Return the abstract function field of the curve.
2451
+
2452
+ TESTS::
2453
+
2454
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2455
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2456
+ sage: C._function_field
2457
+ Function field in z defined by z^3 + 10*x
2458
+ """
2459
+ return self._nonsingular_model[0]
2460
+
2461
+ @lazy_attribute
2462
+ def _map_to_function_field(self):
2463
+ """
2464
+ Return the map to the function field of the curve.
2465
+
2466
+ TESTS::
2467
+
2468
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2469
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2470
+ sage: C._map_to_function_field
2471
+ Ring morphism:
2472
+ From: Fraction Field of Multivariate Polynomial Ring in x, y, z
2473
+ over Finite Field of size 11
2474
+ To: Function field in z defined by z^3 + 10*x
2475
+ Defn: x |--> x
2476
+ y |--> z^2
2477
+ z |--> z
2478
+ """
2479
+ return self._nonsingular_model[1]
2480
+
2481
+ @lazy_attribute
2482
+ def _coordinate_functions(self):
2483
+ """
2484
+ Return the coordinate functions of the curve.
2485
+
2486
+ TESTS::
2487
+
2488
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2489
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2490
+ sage: C._coordinate_functions
2491
+ [x, z^2, z]
2492
+ """
2493
+ return self._nonsingular_model[1].im_gens()
2494
+
2495
+ @lazy_attribute
2496
+ def _map_from_function_field(self):
2497
+ """
2498
+ Return the map from the function field of the curve.
2499
+
2500
+ TESTS::
2501
+
2502
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2503
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2504
+ sage: C._map_from_function_field
2505
+ Ring morphism:
2506
+ From: Function field in z defined by z^3 + 10*x
2507
+ To: Fraction Field of Multivariate Polynomial Ring in x, y, z
2508
+ over Finite Field of size 11
2509
+ """
2510
+ return self._nonsingular_model[2]
2511
+
2512
+ @lazy_attribute
2513
+ def _singularities(self):
2514
+ """
2515
+ Return a list of the pairs of a singular closed point and the places
2516
+ above it.
2517
+
2518
+ TESTS::
2519
+
2520
+ sage: # needs sage.rings.finite_rings
2521
+ sage: A.<x,y> = AffineSpace(GF(7^2), 2)
2522
+ sage: C = Curve(x^2 - x^4 - y^4)
2523
+ sage: C._singularities # long time
2524
+ [(Point (x, y),
2525
+ [Place (x, 1/x*y^3 + 1/x*y^2 + 1), Place (x, 1/x*y^3 + 1/x*y^2 + 6)])]
2526
+ """
2527
+ to_F = self._map_to_function_field
2528
+ sing = self.singular_subscheme()
2529
+
2530
+ funcs = []
2531
+ for p in sing.defining_polynomials():
2532
+ f = to_F(p)
2533
+ if not f.is_zero():
2534
+ funcs.append(f)
2535
+
2536
+ if funcs:
2537
+ f = funcs.pop()
2538
+ places = f.zeros()
2539
+ for f in funcs:
2540
+ places = [p for p in places if f.valuation(p) > 0]
2541
+ else:
2542
+ places = []
2543
+
2544
+ points = []
2545
+ for place in places:
2546
+ p = self.place_to_closed_point(place)
2547
+
2548
+ for q, places in points:
2549
+ if p == q:
2550
+ places.append(place)
2551
+ break
2552
+ else: # new singularity
2553
+ points.append((p, [place]))
2554
+
2555
+ return points
2556
+
2557
+ def singular_closed_points(self):
2558
+ """
2559
+ Return the singular closed points of the curve.
2560
+
2561
+ EXAMPLES::
2562
+
2563
+ sage: # needs sage.rings.finite_rings
2564
+ sage: A.<x,y> = AffineSpace(GF(7^2), 2)
2565
+ sage: C = Curve(x^2 - x^4 - y^4)
2566
+ sage: C.singular_closed_points()
2567
+ [Point (x, y)]
2568
+
2569
+ ::
2570
+
2571
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2572
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2573
+ sage: C.singular_closed_points()
2574
+ []
2575
+ """
2576
+ return [p for p, _ in self._singularities]
2577
+
2578
+ @cached_method
2579
+ def place_to_closed_point(self, place):
2580
+ """
2581
+ Return the closed point on the place.
2582
+
2583
+ INPUT:
2584
+
2585
+ - ``place`` -- a place of the function field of the curve
2586
+
2587
+ EXAMPLES::
2588
+
2589
+ sage: # needs sage.rings.finite_rings
2590
+ sage: A.<x,y> = AffineSpace(GF(4), 2)
2591
+ sage: C = Curve(x^5 + y^5 + x*y + 1)
2592
+ sage: F = C.function_field()
2593
+ sage: pls = F.places(1)
2594
+ sage: C.place_to_closed_point(pls[-1])
2595
+ Point (x + 1, y + 1)
2596
+ sage: C.place_to_closed_point(pls[-2])
2597
+ Point (x + 1, y + 1)
2598
+ """
2599
+ F = self.function_field()
2600
+
2601
+ A = self.ambient_space()
2602
+ R = A.coordinate_ring().change_ring(order='degrevlex')
2603
+
2604
+ coords = self._coordinate_functions
2605
+
2606
+ if any(f.valuation(place) < 0 for f in coords):
2607
+ raise ValueError("the place is at infinity")
2608
+
2609
+ k, from_k, to_k = place.residue_field()
2610
+ V, from_V, to_V = k.vector_space(F.constant_base_field(), map=True)
2611
+
2612
+ # implement an FGLM-like algorithm
2613
+ e = [0 for i in range(R.ngens())]
2614
+ basis = [R.one()]
2615
+ basis_vecs = [to_V(k.one())] # represent as a vector
2616
+
2617
+ gens = []
2618
+ gens_lts = []
2619
+ terminate = False
2620
+ while True: # check FGLM termination condition
2621
+ # compute next exponent in degree reverse lexicographical order
2622
+ j = R.ngens() - 1
2623
+ while j > 0 and not e[j]:
2624
+ j -= 1
2625
+
2626
+ if not j: # j is zero
2627
+ if terminate:
2628
+ break
2629
+ terminate = True
2630
+ d = e[0]
2631
+ e[0] = 0
2632
+ e[-1] = d + 1
2633
+ else:
2634
+ e[j] -= 1
2635
+ e[j - 1] += 1
2636
+
2637
+ m = R.monomial(*e)
2638
+ if any(g.divides(m) for g in gens_lts):
2639
+ continue
2640
+
2641
+ prod = 1
2642
+ for i in range(R.ngens()):
2643
+ prod *= coords[i]**e[i]
2644
+ vec = to_V(to_k(prod)) # represent as a vector
2645
+ mat = matrix(basis_vecs)
2646
+ try:
2647
+ s = mat.solve_left(vec)
2648
+ except ValueError: # no solution
2649
+ basis.append(m)
2650
+ basis_vecs.append(vec)
2651
+ terminate = False
2652
+ continue
2653
+
2654
+ gens.append(m - sum([s[i] * basis[i] for i in range(len(basis))]))
2655
+ gens_lts.append(m)
2656
+
2657
+ prime = R.ideal(gens).groebner_basis().ideal()
2658
+
2659
+ return self._closed_point(self, prime, len(basis))
2660
+
2661
+ def places_at_infinity(self):
2662
+ """
2663
+ Return the places of the curve at infinity.
2664
+
2665
+ EXAMPLES::
2666
+
2667
+ sage: A.<x,y> = AffineSpace(QQ, 2)
2668
+ sage: C = Curve(x^3 - y^2 - x^4 - y^4)
2669
+ sage: C.places_at_infinity()
2670
+ [Place (1/x, 1/x^2*y, 1/x^3*y^2, 1/x^4*y^3)]
2671
+
2672
+ ::
2673
+
2674
+ sage: # needs sage.rings.finite_rings
2675
+ sage: F = GF(9)
2676
+ sage: A2.<x,y> = AffineSpace(F, 2)
2677
+ sage: C = A2.curve(y^3 + y - x^4)
2678
+ sage: C.places_at_infinity()
2679
+ [Place (1/x, 1/x^3*y^2)]
2680
+
2681
+ ::
2682
+
2683
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2684
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A)
2685
+ sage: C.places_at_infinity()
2686
+ [Place (1/x, 1/x*z^2)]
2687
+ """
2688
+ return list({p for f in self._coordinate_functions if f for p in f.poles()})
2689
+
2690
+ def places_on(self, point):
2691
+ """
2692
+ Return the places on the closed point.
2693
+
2694
+ INPUT:
2695
+
2696
+ - ``point`` -- a closed point of the curve
2697
+
2698
+ OUTPUT: list of the places of the function field of the curve
2699
+
2700
+ EXAMPLES::
2701
+
2702
+ sage: A.<x,y> = AffineSpace(QQ, 2)
2703
+ sage: C = Curve(x^3 - y^2 - x^4 - y^4)
2704
+ sage: C.singular_closed_points()
2705
+ [Point (x, y)]
2706
+ sage: p, = _
2707
+ sage: C.places_on(p)
2708
+ [Place (x, y, y^2, 1/x*y^3 + 1/x*y)]
2709
+
2710
+ ::
2711
+
2712
+ sage: # needs sage.rings.finite_rings
2713
+ sage: k.<a> = GF(9)
2714
+ sage: A.<x,y> = AffineSpace(k, 2)
2715
+ sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2)
2716
+ sage: pts = C.closed_points()
2717
+ sage: pts
2718
+ [Point (x, y + (a + 1)),
2719
+ Point (x, y + (-a - 1)),
2720
+ Point (x + (a + 1), y + (a - 1)),
2721
+ Point (x + (a + 1), y + (-a + 1)),
2722
+ Point (x - 1, y + (a + 1)),
2723
+ Point (x - 1, y + (-a - 1)),
2724
+ Point (x + (-a - 1), y + a),
2725
+ Point (x + (-a - 1), y + (-a)),
2726
+ Point (x + 1, y + 1),
2727
+ Point (x + 1, y - 1)]
2728
+ sage: p1, p2, p3 = pts[:3]
2729
+ sage: C.places_on(p1)
2730
+ [Place (x, y + a + 1)]
2731
+ sage: C.places_on(p2)
2732
+ [Place (x, y + 2*a + 2)]
2733
+ sage: C.places_on(p3)
2734
+ [Place (x + a + 1, y + a + 2)]
2735
+
2736
+ ::
2737
+
2738
+ sage: # needs sage.rings.finite_rings
2739
+ sage: F.<a> = GF(8)
2740
+ sage: P.<x,y,z> = ProjectiveSpace(F, 2)
2741
+ sage: Cp = Curve(x^3*y + y^3*z + x*z^3)
2742
+ sage: C = Cp.affine_patch(0)
2743
+ """
2744
+ phi = self._map_to_function_field
2745
+ gs = [phi(g) for g in point.prime_ideal().gens()]
2746
+ fs = [g for g in gs if not g.is_zero()]
2747
+ f = fs.pop()
2748
+ places = []
2749
+ for p in f.zeros():
2750
+ if all(f.valuation(p) > 0 for f in fs):
2751
+ places.append(p)
2752
+ return places
2753
+
2754
+ def parametric_representation(self, place, name=None):
2755
+ """
2756
+ Return a power series representation of the branch of the
2757
+ curve given by ``place``.
2758
+
2759
+ INPUT:
2760
+
2761
+ - ``place`` -- a place on the curve
2762
+
2763
+ EXAMPLES::
2764
+
2765
+ sage: A.<x,y> = AffineSpace(QQ, 2)
2766
+ sage: C = Curve(x^2 + y^2 -1)
2767
+ sage: p = C(0,1)
2768
+ sage: p.closed_point()
2769
+ Point (x, y - 1)
2770
+ sage: pl = _.place()
2771
+ sage: C.parametric_representation(pl)
2772
+ (s + ..., 1 - 1/2*s^2 - 1/8*s^4 - 1/16*s^6 + ...)
2773
+
2774
+ ::
2775
+
2776
+ sage: # needs sage.rings.finite_rings
2777
+ sage: A.<x,y> = AffineSpace(GF(7^2), 2)
2778
+ sage: C = Curve(x^2 - x^4 - y^4)
2779
+ sage: p, = C.singular_closed_points()
2780
+ sage: b1, b2 = p.places()
2781
+ sage: xs, ys = C.parametric_representation(b1)
2782
+ sage: f = xs^2 - xs^4 - ys^4
2783
+ sage: [f.coefficient(i) for i in range(5)]
2784
+ [0, 0, 0, 0, 0]
2785
+ sage: xs, ys = C.parametric_representation(b2)
2786
+ sage: f = xs^2 - xs^4 - ys^4
2787
+ sage: [f.coefficient(i) for i in range(5)]
2788
+ [0, 0, 0, 0, 0]
2789
+ """
2790
+ F = place.function_field()
2791
+ F_place = F.completion(place, prec=infinity, name=name)
2792
+
2793
+ return tuple(F_place._expand_lazy(c) for c in self._coordinate_functions)
2794
+
2795
+
2796
+ class IntegralAffineCurve_finite_field(IntegralAffineCurve):
2797
+ """
2798
+ Integral affine curves.
2799
+
2800
+ INPUT:
2801
+
2802
+ - ``A`` -- an ambient space in which the curve lives
2803
+
2804
+ - ``X`` -- list of polynomials that define the curve
2805
+
2806
+ EXAMPLES::
2807
+
2808
+ sage: A.<x,y,z> = AffineSpace(GF(11), 3)
2809
+ sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A); C
2810
+ Affine Curve over Finite Field of size 11
2811
+ defined by -y^2 + x*z, -z^2 + y, -y*z + x
2812
+ sage: C.function_field()
2813
+ Function field in z defined by z^3 + 10*x
2814
+ """
2815
+ _point = IntegralAffineCurvePoint_finite_field
2816
+
2817
+ def places(self, degree=1):
2818
+ """
2819
+ Return all places on the curve of the ``degree``.
2820
+
2821
+ INPUT:
2822
+
2823
+ - ``degree`` -- positive integer
2824
+
2825
+ EXAMPLES::
2826
+
2827
+ sage: # needs sage.rings.finite_rings
2828
+ sage: F = GF(9)
2829
+ sage: A2.<x,y> = AffineSpace(F, 2)
2830
+ sage: C = A2.curve(y^3 + y - x^4)
2831
+ sage: C.places()
2832
+ [Place (1/x, 1/x^3*y^2),
2833
+ Place (x, y),
2834
+ Place (x, y + z2 + 1),
2835
+ Place (x, y + 2*z2 + 2),
2836
+ Place (x + z2, y + 2),
2837
+ Place (x + z2, y + z2),
2838
+ Place (x + z2, y + 2*z2 + 1),
2839
+ Place (x + z2 + 1, y + 1),
2840
+ Place (x + z2 + 1, y + z2 + 2),
2841
+ Place (x + z2 + 1, y + 2*z2),
2842
+ Place (x + 2*z2 + 1, y + 2),
2843
+ Place (x + 2*z2 + 1, y + z2),
2844
+ Place (x + 2*z2 + 1, y + 2*z2 + 1),
2845
+ Place (x + 2, y + 1),
2846
+ Place (x + 2, y + z2 + 2),
2847
+ Place (x + 2, y + 2*z2),
2848
+ Place (x + 2*z2, y + 2),
2849
+ Place (x + 2*z2, y + z2),
2850
+ Place (x + 2*z2, y + 2*z2 + 1),
2851
+ Place (x + 2*z2 + 2, y + 1),
2852
+ Place (x + 2*z2 + 2, y + z2 + 2),
2853
+ Place (x + 2*z2 + 2, y + 2*z2),
2854
+ Place (x + z2 + 2, y + 2),
2855
+ Place (x + z2 + 2, y + z2),
2856
+ Place (x + z2 + 2, y + 2*z2 + 1),
2857
+ Place (x + 1, y + 1),
2858
+ Place (x + 1, y + z2 + 2),
2859
+ Place (x + 1, y + 2*z2)]
2860
+ """
2861
+ F = self.function_field()
2862
+ return F.places(degree)
2863
+
2864
+ @cached_method(do_pickle=True)
2865
+ def closed_points(self, degree=1):
2866
+ """
2867
+ Return a list of the closed points of ``degree`` of the curve.
2868
+
2869
+ INPUT:
2870
+
2871
+ - ``degree`` -- positive integer
2872
+
2873
+ EXAMPLES::
2874
+
2875
+ sage: A.<x,y> = AffineSpace(GF(7), 2)
2876
+ sage: C = Curve(x^2 - x^4 - y^4)
2877
+ sage: C.closed_points()
2878
+ [Point (x, y),
2879
+ Point (x + 1, y),
2880
+ Point (x + 2, y + 2),
2881
+ Point (x + 2, y - 2),
2882
+ Point (x - 2, y + 2),
2883
+ Point (x - 2, y - 2),
2884
+ Point (x - 1, y)]
2885
+ """
2886
+ F = self.function_field()
2887
+ places_above = F.places(degree)
2888
+
2889
+ points = []
2890
+
2891
+ # consider singular points
2892
+ for p in self.singular_closed_points():
2893
+ if p.degree() == degree:
2894
+ points.append(p)
2895
+ for place in p.places():
2896
+ if place.degree() == degree:
2897
+ places_above.remove(place)
2898
+
2899
+ for place in places_above:
2900
+ try:
2901
+ p = self.place_to_closed_point(place)
2902
+ except ValueError: # place is at infinity
2903
+ continue
2904
+ assert p.degree() == degree # sanity check
2905
+ points.append(p)
2906
+
2907
+ return points
2908
+
2909
+
2910
+ class IntegralAffinePlaneCurve(IntegralAffineCurve, AffinePlaneCurve_field):
2911
+ _point = IntegralAffinePlaneCurvePoint
2912
+
2913
+
2914
+ class IntegralAffinePlaneCurve_finite_field(AffinePlaneCurve_finite_field, IntegralAffineCurve_finite_field):
2915
+ """
2916
+ Integral affine plane curve over a finite field.
2917
+
2918
+ EXAMPLES::
2919
+
2920
+ sage: # needs sage.rings.finite_rings
2921
+ sage: A.<x,y> = AffineSpace(GF(8), 2)
2922
+ sage: C = Curve(x^5 + y^5 + x*y + 1); C
2923
+ Affine Plane Curve over Finite Field in z3 of size 2^3
2924
+ defined by x^5 + y^5 + x*y + 1
2925
+ sage: C.function_field()
2926
+ Function field in y defined by y^5 + x*y + x^5 + 1
2927
+ """
2928
+ _point = IntegralAffinePlaneCurvePoint_finite_field