passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-schemes might be problematic. Click here for more details.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
sage/modular/cusps.py
ADDED
|
@@ -0,0 +1,1109 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
The set `\mathbb{P}^1(\QQ)` of cusps
|
|
4
|
+
|
|
5
|
+
EXAMPLES::
|
|
6
|
+
|
|
7
|
+
sage: Cusps
|
|
8
|
+
Set P^1(QQ) of all cusps
|
|
9
|
+
|
|
10
|
+
::
|
|
11
|
+
|
|
12
|
+
sage: Cusp(oo)
|
|
13
|
+
Infinity
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
# ****************************************************************************
|
|
17
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
18
|
+
#
|
|
19
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
20
|
+
#
|
|
21
|
+
# This code is distributed in the hope that it will be useful,
|
|
22
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
23
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
24
|
+
# General Public License for more details.
|
|
25
|
+
#
|
|
26
|
+
# The full text of the GPL is available at:
|
|
27
|
+
#
|
|
28
|
+
# https://www.gnu.org/licenses/
|
|
29
|
+
# ****************************************************************************
|
|
30
|
+
from typing import Any
|
|
31
|
+
|
|
32
|
+
from sage.misc.cachefunc import cached_method
|
|
33
|
+
from sage.misc.fast_methods import Singleton
|
|
34
|
+
from sage.modular.modsym.p1list import lift_to_sl2z_llong
|
|
35
|
+
from sage.rings.infinity import Infinity, InfinityRing
|
|
36
|
+
from sage.rings.integer import Integer
|
|
37
|
+
from sage.rings.integer_ring import ZZ
|
|
38
|
+
from sage.rings.rational import Rational
|
|
39
|
+
from sage.rings.rational_field import QQ
|
|
40
|
+
from sage.structure.element import Element, InfinityElement
|
|
41
|
+
from sage.structure.element import Matrix
|
|
42
|
+
from sage.structure.parent import Parent
|
|
43
|
+
from sage.structure.richcmp import richcmp
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
from sage.libs.pari import pari
|
|
47
|
+
from cypari2.gen import Gen as pari_gen
|
|
48
|
+
except ImportError:
|
|
49
|
+
pari_gen = ()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Cusp(Element):
|
|
53
|
+
"""
|
|
54
|
+
A cusp.
|
|
55
|
+
|
|
56
|
+
A cusp is either a rational number or infinity, i.e., an element of
|
|
57
|
+
the projective line over Q. A Cusp is stored as a pair (a,b), where
|
|
58
|
+
gcd(a,b)=1 and a,b are of type Integer.
|
|
59
|
+
|
|
60
|
+
EXAMPLES::
|
|
61
|
+
|
|
62
|
+
sage: a = Cusp(2/3); b = Cusp(oo)
|
|
63
|
+
sage: a.parent()
|
|
64
|
+
Set P^1(QQ) of all cusps
|
|
65
|
+
sage: a.parent() is b.parent()
|
|
66
|
+
True
|
|
67
|
+
"""
|
|
68
|
+
def __init__(self, a, b=None, parent=None, check=True):
|
|
69
|
+
r"""
|
|
70
|
+
Create the cusp a/b in `\mathbb{P}^1(\QQ)`, where if b=0
|
|
71
|
+
this is the cusp at infinity.
|
|
72
|
+
|
|
73
|
+
When present, b must either be Infinity or coercible to an
|
|
74
|
+
Integer.
|
|
75
|
+
|
|
76
|
+
EXAMPLES::
|
|
77
|
+
|
|
78
|
+
sage: Cusp(2,3)
|
|
79
|
+
2/3
|
|
80
|
+
sage: Cusp(3,6)
|
|
81
|
+
1/2
|
|
82
|
+
sage: Cusp(1,0)
|
|
83
|
+
Infinity
|
|
84
|
+
sage: Cusp(infinity)
|
|
85
|
+
Infinity
|
|
86
|
+
sage: Cusp(5)
|
|
87
|
+
5
|
|
88
|
+
sage: Cusp(1/2)
|
|
89
|
+
1/2
|
|
90
|
+
sage: Cusp(1.5)
|
|
91
|
+
3/2
|
|
92
|
+
sage: Cusp(int(7))
|
|
93
|
+
7
|
|
94
|
+
sage: Cusp(1, 2, check=False)
|
|
95
|
+
1/2
|
|
96
|
+
sage: Cusp('sage', 2.5, check=False) # don't do this!
|
|
97
|
+
sage/2.50000000000000
|
|
98
|
+
|
|
99
|
+
::
|
|
100
|
+
|
|
101
|
+
sage: I**2
|
|
102
|
+
-1
|
|
103
|
+
sage: Cusp(I)
|
|
104
|
+
Traceback (most recent call last):
|
|
105
|
+
...
|
|
106
|
+
TypeError: unable to convert I to a cusp
|
|
107
|
+
|
|
108
|
+
::
|
|
109
|
+
|
|
110
|
+
sage: a = Cusp(2,3)
|
|
111
|
+
sage: loads(a.dumps()) == a
|
|
112
|
+
True
|
|
113
|
+
|
|
114
|
+
::
|
|
115
|
+
|
|
116
|
+
sage: Cusp(1/3,0)
|
|
117
|
+
Infinity
|
|
118
|
+
sage: Cusp((1,0))
|
|
119
|
+
Infinity
|
|
120
|
+
|
|
121
|
+
TESTS::
|
|
122
|
+
|
|
123
|
+
sage: Cusp("1/3", 5)
|
|
124
|
+
1/15
|
|
125
|
+
sage: Cusp(Cusp(3/5), 7)
|
|
126
|
+
3/35
|
|
127
|
+
sage: Cusp(5/3, 0)
|
|
128
|
+
Infinity
|
|
129
|
+
sage: Cusp(3,oo)
|
|
130
|
+
0
|
|
131
|
+
sage: Cusp((7,3), 5)
|
|
132
|
+
7/15
|
|
133
|
+
sage: Cusp(int(5), 7)
|
|
134
|
+
5/7
|
|
135
|
+
|
|
136
|
+
::
|
|
137
|
+
|
|
138
|
+
sage: Cusp(0,0)
|
|
139
|
+
Traceback (most recent call last):
|
|
140
|
+
...
|
|
141
|
+
TypeError: unable to convert (0, 0) to a cusp
|
|
142
|
+
|
|
143
|
+
::
|
|
144
|
+
|
|
145
|
+
sage: Cusp(oo,oo)
|
|
146
|
+
Traceback (most recent call last):
|
|
147
|
+
...
|
|
148
|
+
TypeError: unable to convert (+Infinity, +Infinity) to a cusp
|
|
149
|
+
|
|
150
|
+
::
|
|
151
|
+
|
|
152
|
+
sage: Cusp(Cusp(oo),oo)
|
|
153
|
+
Traceback (most recent call last):
|
|
154
|
+
...
|
|
155
|
+
TypeError: unable to convert (Infinity, +Infinity) to a cusp
|
|
156
|
+
|
|
157
|
+
Conversion from PARI is supported (see :issue:`32091`)::
|
|
158
|
+
|
|
159
|
+
sage: Cusp(pari.oo())
|
|
160
|
+
Infinity
|
|
161
|
+
sage: Cusp(pari(2/3))
|
|
162
|
+
2/3
|
|
163
|
+
"""
|
|
164
|
+
if parent is None:
|
|
165
|
+
parent = Cusps
|
|
166
|
+
Element.__init__(self, parent)
|
|
167
|
+
|
|
168
|
+
if not check:
|
|
169
|
+
self.__a = a
|
|
170
|
+
self.__b = b
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
if b is None:
|
|
174
|
+
if isinstance(a, Integer):
|
|
175
|
+
self.__a = a
|
|
176
|
+
self.__b = ZZ.one()
|
|
177
|
+
elif isinstance(a, Rational):
|
|
178
|
+
self.__a = a.numer()
|
|
179
|
+
self.__b = a.denom()
|
|
180
|
+
elif (isinstance(a, InfinityElement) or
|
|
181
|
+
(isinstance(a, pari_gen) and a.type() == 't_INFINITY')):
|
|
182
|
+
self.__a = ZZ.one()
|
|
183
|
+
self.__b = ZZ.zero()
|
|
184
|
+
elif isinstance(a, Cusp):
|
|
185
|
+
self.__a = a.__a
|
|
186
|
+
self.__b = a.__b
|
|
187
|
+
elif isinstance(a, int):
|
|
188
|
+
self.__a = ZZ(a)
|
|
189
|
+
self.__b = ZZ.one()
|
|
190
|
+
elif isinstance(a, (tuple, list)):
|
|
191
|
+
if len(a) != 2:
|
|
192
|
+
raise TypeError("unable to convert %r to a cusp" % a)
|
|
193
|
+
if ZZ(a[1]) == 0:
|
|
194
|
+
self.__a = ZZ.one()
|
|
195
|
+
self.__b = ZZ.zero()
|
|
196
|
+
return
|
|
197
|
+
try:
|
|
198
|
+
r = QQ((a[0], a[1]))
|
|
199
|
+
self.__a = r.numer()
|
|
200
|
+
self.__b = r.denom()
|
|
201
|
+
except (ValueError, TypeError):
|
|
202
|
+
raise TypeError(f"unable to convert {a} to a cusp")
|
|
203
|
+
else:
|
|
204
|
+
try:
|
|
205
|
+
r = QQ(a)
|
|
206
|
+
self.__a = r.numer()
|
|
207
|
+
self.__b = r.denom()
|
|
208
|
+
except (ValueError, TypeError):
|
|
209
|
+
raise TypeError("unable to convert %r to a cusp" % a)
|
|
210
|
+
return
|
|
211
|
+
|
|
212
|
+
if isinstance(b, InfinityElement):
|
|
213
|
+
if isinstance(a, InfinityElement) or (isinstance(a, Cusp) and a.is_infinity()):
|
|
214
|
+
raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
|
|
215
|
+
self.__a = ZZ.zero()
|
|
216
|
+
self.__b = ZZ.one()
|
|
217
|
+
return
|
|
218
|
+
elif not b:
|
|
219
|
+
if not a:
|
|
220
|
+
raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
|
|
221
|
+
self.__a = ZZ.one()
|
|
222
|
+
self.__b = ZZ.zero()
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
if isinstance(a, (Integer, Rational)):
|
|
226
|
+
r = a / ZZ(b)
|
|
227
|
+
elif isinstance(a, InfinityElement):
|
|
228
|
+
self.__a = ZZ.one()
|
|
229
|
+
self.__b = ZZ.zero()
|
|
230
|
+
return
|
|
231
|
+
elif isinstance(a, Cusp):
|
|
232
|
+
if a.__b:
|
|
233
|
+
r = a.__a / (a.__b * b)
|
|
234
|
+
else:
|
|
235
|
+
self.__a = ZZ.one()
|
|
236
|
+
self.__b = ZZ.zero()
|
|
237
|
+
return
|
|
238
|
+
elif isinstance(a, int):
|
|
239
|
+
r = ZZ(a) / b
|
|
240
|
+
elif isinstance(a, (tuple, list)):
|
|
241
|
+
if len(a) != 2:
|
|
242
|
+
raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
|
|
243
|
+
r = ZZ(a[0]) / (ZZ(a[1]) * b)
|
|
244
|
+
else:
|
|
245
|
+
try:
|
|
246
|
+
r = QQ(a) / b
|
|
247
|
+
except (ValueError, TypeError):
|
|
248
|
+
raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
|
|
249
|
+
|
|
250
|
+
self.__a = r.numer()
|
|
251
|
+
self.__b = r.denom()
|
|
252
|
+
|
|
253
|
+
def __hash__(self):
|
|
254
|
+
"""
|
|
255
|
+
EXAMPLES::
|
|
256
|
+
|
|
257
|
+
sage: hash(Cusp(1/3)) == hash((1,3))
|
|
258
|
+
True
|
|
259
|
+
sage: hash(Cusp(oo)) == hash((1,0))
|
|
260
|
+
True
|
|
261
|
+
"""
|
|
262
|
+
return hash((self.__a, self.__b))
|
|
263
|
+
|
|
264
|
+
def _richcmp_(self, right, op):
|
|
265
|
+
"""
|
|
266
|
+
Compare the cusps ``self`` and ``right``.
|
|
267
|
+
|
|
268
|
+
Comparison is as for rational numbers, except with the cusp oo
|
|
269
|
+
greater than everything but itself.
|
|
270
|
+
|
|
271
|
+
The ordering in comparison is only really meaningful for infinity
|
|
272
|
+
or elements that coerce to the rationals.
|
|
273
|
+
|
|
274
|
+
EXAMPLES::
|
|
275
|
+
|
|
276
|
+
sage: Cusp(2/3) == Cusp(oo)
|
|
277
|
+
False
|
|
278
|
+
|
|
279
|
+
sage: Cusp(2/3) < Cusp(oo)
|
|
280
|
+
True
|
|
281
|
+
|
|
282
|
+
sage: Cusp(2/3)> Cusp(oo)
|
|
283
|
+
False
|
|
284
|
+
|
|
285
|
+
sage: Cusp(2/3) > Cusp(5/2)
|
|
286
|
+
False
|
|
287
|
+
|
|
288
|
+
sage: Cusp(2/3) < Cusp(5/2)
|
|
289
|
+
True
|
|
290
|
+
|
|
291
|
+
sage: Cusp(2/3) == Cusp(5/2)
|
|
292
|
+
False
|
|
293
|
+
|
|
294
|
+
sage: Cusp(oo) == Cusp(oo)
|
|
295
|
+
True
|
|
296
|
+
|
|
297
|
+
sage: 19/3 < Cusp(oo)
|
|
298
|
+
True
|
|
299
|
+
|
|
300
|
+
sage: Cusp(oo) < 19/3
|
|
301
|
+
False
|
|
302
|
+
|
|
303
|
+
sage: Cusp(2/3) < Cusp(11/7)
|
|
304
|
+
True
|
|
305
|
+
|
|
306
|
+
sage: Cusp(11/7) < Cusp(2/3)
|
|
307
|
+
False
|
|
308
|
+
|
|
309
|
+
sage: 2 < Cusp(3)
|
|
310
|
+
True
|
|
311
|
+
"""
|
|
312
|
+
if not self.__b:
|
|
313
|
+
s = Infinity
|
|
314
|
+
else:
|
|
315
|
+
s = self._rational_()
|
|
316
|
+
if not right.__b:
|
|
317
|
+
o = Infinity
|
|
318
|
+
else:
|
|
319
|
+
o = right._rational_()
|
|
320
|
+
return richcmp(s, o, op)
|
|
321
|
+
|
|
322
|
+
def is_infinity(self) -> bool:
|
|
323
|
+
"""
|
|
324
|
+
Return ``True`` if this is the cusp infinity.
|
|
325
|
+
|
|
326
|
+
EXAMPLES::
|
|
327
|
+
|
|
328
|
+
sage: Cusp(3/5).is_infinity()
|
|
329
|
+
False
|
|
330
|
+
sage: Cusp(1,0).is_infinity()
|
|
331
|
+
True
|
|
332
|
+
sage: Cusp(0,1).is_infinity()
|
|
333
|
+
False
|
|
334
|
+
"""
|
|
335
|
+
return not self.__b
|
|
336
|
+
|
|
337
|
+
def numerator(self):
|
|
338
|
+
"""
|
|
339
|
+
Return the numerator of the cusp a/b.
|
|
340
|
+
|
|
341
|
+
EXAMPLES::
|
|
342
|
+
|
|
343
|
+
sage: x = Cusp(6,9); x
|
|
344
|
+
2/3
|
|
345
|
+
sage: x.numerator()
|
|
346
|
+
2
|
|
347
|
+
sage: Cusp(oo).numerator()
|
|
348
|
+
1
|
|
349
|
+
sage: Cusp(-5/10).numerator()
|
|
350
|
+
-1
|
|
351
|
+
"""
|
|
352
|
+
return self.__a
|
|
353
|
+
|
|
354
|
+
def denominator(self):
|
|
355
|
+
"""
|
|
356
|
+
Return the denominator of the cusp a/b.
|
|
357
|
+
|
|
358
|
+
EXAMPLES::
|
|
359
|
+
|
|
360
|
+
sage: x = Cusp(6,9); x
|
|
361
|
+
2/3
|
|
362
|
+
sage: x.denominator()
|
|
363
|
+
3
|
|
364
|
+
sage: Cusp(oo).denominator()
|
|
365
|
+
0
|
|
366
|
+
sage: Cusp(-5/10).denominator()
|
|
367
|
+
2
|
|
368
|
+
"""
|
|
369
|
+
return self.__b
|
|
370
|
+
|
|
371
|
+
@cached_method
|
|
372
|
+
def _rational_(self):
|
|
373
|
+
"""
|
|
374
|
+
Coerce to a rational number.
|
|
375
|
+
|
|
376
|
+
EXAMPLES::
|
|
377
|
+
|
|
378
|
+
sage: QQ(Cusp(oo))
|
|
379
|
+
Traceback (most recent call last):
|
|
380
|
+
...
|
|
381
|
+
TypeError: cusp Infinity is not a rational number
|
|
382
|
+
sage: QQ(Cusp(-3,7))
|
|
383
|
+
-3/7
|
|
384
|
+
sage: Cusp(11,2)._rational_()
|
|
385
|
+
11/2
|
|
386
|
+
"""
|
|
387
|
+
if not self.__b:
|
|
388
|
+
raise TypeError("cusp %s is not a rational number" % self)
|
|
389
|
+
return self.__a / self.__b
|
|
390
|
+
|
|
391
|
+
def _integer_(self, ZZ=None):
|
|
392
|
+
"""
|
|
393
|
+
Coerce to an integer.
|
|
394
|
+
|
|
395
|
+
EXAMPLES::
|
|
396
|
+
|
|
397
|
+
sage: ZZ(Cusp(-19))
|
|
398
|
+
-19
|
|
399
|
+
sage: Cusp(4,2)._integer_()
|
|
400
|
+
2
|
|
401
|
+
|
|
402
|
+
::
|
|
403
|
+
|
|
404
|
+
sage: ZZ(Cusp(oo))
|
|
405
|
+
Traceback (most recent call last):
|
|
406
|
+
...
|
|
407
|
+
TypeError: cusp Infinity is not an integer
|
|
408
|
+
sage: ZZ(Cusp(-3,7))
|
|
409
|
+
Traceback (most recent call last):
|
|
410
|
+
...
|
|
411
|
+
TypeError: cusp -3/7 is not an integer
|
|
412
|
+
"""
|
|
413
|
+
if self.__b != 1:
|
|
414
|
+
raise TypeError("cusp %s is not an integer" % self)
|
|
415
|
+
return self.__a
|
|
416
|
+
|
|
417
|
+
def _repr_(self):
|
|
418
|
+
"""
|
|
419
|
+
String representation of this cusp.
|
|
420
|
+
|
|
421
|
+
EXAMPLES::
|
|
422
|
+
|
|
423
|
+
sage: a = Cusp(2/3); a
|
|
424
|
+
2/3
|
|
425
|
+
sage: a._repr_()
|
|
426
|
+
'2/3'
|
|
427
|
+
sage: a.rename('2/3(cusp)'); a
|
|
428
|
+
2/3(cusp)
|
|
429
|
+
"""
|
|
430
|
+
if self.__b.is_zero():
|
|
431
|
+
return "Infinity"
|
|
432
|
+
if self.__b != 1:
|
|
433
|
+
return "%s/%s" % (self.__a, self.__b)
|
|
434
|
+
else:
|
|
435
|
+
return str(self.__a)
|
|
436
|
+
|
|
437
|
+
def _latex_(self):
|
|
438
|
+
r"""
|
|
439
|
+
Latex representation of this cusp.
|
|
440
|
+
|
|
441
|
+
EXAMPLES::
|
|
442
|
+
|
|
443
|
+
sage: latex(Cusp(-2/7))
|
|
444
|
+
\frac{-2}{7}
|
|
445
|
+
sage: latex(Cusp(oo))
|
|
446
|
+
\infty
|
|
447
|
+
sage: latex(Cusp(oo)) == Cusp(oo)._latex_()
|
|
448
|
+
True
|
|
449
|
+
"""
|
|
450
|
+
if self.__b.is_zero():
|
|
451
|
+
return "\\infty"
|
|
452
|
+
if self.__b != 1:
|
|
453
|
+
return "\\frac{%s}{%s}" % (self.__a, self.__b)
|
|
454
|
+
else:
|
|
455
|
+
return str(self.__a)
|
|
456
|
+
|
|
457
|
+
def __neg__(self):
|
|
458
|
+
"""
|
|
459
|
+
The negative of this cusp.
|
|
460
|
+
|
|
461
|
+
EXAMPLES::
|
|
462
|
+
|
|
463
|
+
sage: -Cusp(2/7)
|
|
464
|
+
-2/7
|
|
465
|
+
sage: -Cusp(oo)
|
|
466
|
+
Infinity
|
|
467
|
+
"""
|
|
468
|
+
return Cusp(-self.__a, self.__b)
|
|
469
|
+
|
|
470
|
+
def is_gamma0_equiv(self, other, N,
|
|
471
|
+
transformation=None) -> bool | tuple[bool, Any]:
|
|
472
|
+
r"""
|
|
473
|
+
Return whether ``self`` and ``other`` are equivalent modulo the action of
|
|
474
|
+
`\Gamma_0(N)` via linear fractional transformations.
|
|
475
|
+
|
|
476
|
+
INPUT:
|
|
477
|
+
|
|
478
|
+
- ``other`` -- cusp
|
|
479
|
+
|
|
480
|
+
- ``N`` -- integer (specifies the group `\Gamma_0(N)`)
|
|
481
|
+
|
|
482
|
+
- ``transformation`` -- ``None`` (default) or either the string 'matrix' or
|
|
483
|
+
``'corner'``. If ``'matrix'``, it also returns a matrix in `\Gamma_0(N)` that
|
|
484
|
+
sends ``self`` to ``other``. The matrix is chosen such that the lower
|
|
485
|
+
left entry is as small as possible in absolute value. If ``'corner'`` (or
|
|
486
|
+
``True`` for backwards compatibility), it returns only the upper left
|
|
487
|
+
entry of such a matrix.
|
|
488
|
+
|
|
489
|
+
OUTPUT:
|
|
490
|
+
|
|
491
|
+
- a boolean -- ``True`` if ``self`` and ``other`` are equivalent
|
|
492
|
+
|
|
493
|
+
- a matrix or an integer -- returned only if transformation is 'matrix'
|
|
494
|
+
or 'corner', respectively
|
|
495
|
+
|
|
496
|
+
EXAMPLES::
|
|
497
|
+
|
|
498
|
+
sage: x = Cusp(2,3)
|
|
499
|
+
sage: y = Cusp(4,5)
|
|
500
|
+
sage: x.is_gamma0_equiv(y, 2)
|
|
501
|
+
True
|
|
502
|
+
sage: _, ga = x.is_gamma0_equiv(y, 2, 'matrix'); ga
|
|
503
|
+
[-1 2]
|
|
504
|
+
[-2 3]
|
|
505
|
+
sage: x.is_gamma0_equiv(y, 3)
|
|
506
|
+
False
|
|
507
|
+
sage: x.is_gamma0_equiv(y, 3, 'matrix')
|
|
508
|
+
(False, None)
|
|
509
|
+
sage: Cusp(1/2).is_gamma0_equiv(1/3,11,'corner')
|
|
510
|
+
(True, 19)
|
|
511
|
+
|
|
512
|
+
sage: Cusp(1,0)
|
|
513
|
+
Infinity
|
|
514
|
+
sage: z = Cusp(1,0)
|
|
515
|
+
sage: x.is_gamma0_equiv(z, 3, 'matrix')
|
|
516
|
+
(
|
|
517
|
+
[-1 1]
|
|
518
|
+
True, [-3 2]
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
ALGORITHM: See Proposition 2.2.3 of Cremona's book 'Algorithms for
|
|
523
|
+
Modular Elliptic Curves', or Prop 2.27 of Stein's Ph.D. thesis.
|
|
524
|
+
"""
|
|
525
|
+
if transformation not in [False, True, "matrix", None, "corner"]:
|
|
526
|
+
raise ValueError("Value %s of the optional argument transformation is not valid.")
|
|
527
|
+
|
|
528
|
+
if not isinstance(other, Cusp):
|
|
529
|
+
other = Cusp(other)
|
|
530
|
+
N = ZZ(N)
|
|
531
|
+
u1 = self.__a
|
|
532
|
+
v1 = self.__b
|
|
533
|
+
u2 = other.__a
|
|
534
|
+
v2 = other.__b
|
|
535
|
+
|
|
536
|
+
zero = ZZ.zero()
|
|
537
|
+
one = ZZ.one()
|
|
538
|
+
|
|
539
|
+
if transformation == "matrix":
|
|
540
|
+
from sage.matrix.constructor import matrix
|
|
541
|
+
|
|
542
|
+
if v1 == v2 and u1 == u2:
|
|
543
|
+
if not transformation:
|
|
544
|
+
return True
|
|
545
|
+
elif transformation == "matrix":
|
|
546
|
+
return True, matrix(ZZ, [[1, 0], [0, 1]])
|
|
547
|
+
else:
|
|
548
|
+
return True, one
|
|
549
|
+
|
|
550
|
+
# a necessary, but not sufficient condition unless N is square-free
|
|
551
|
+
if v1.gcd(N) != v2.gcd(N):
|
|
552
|
+
if not transformation:
|
|
553
|
+
return False
|
|
554
|
+
else:
|
|
555
|
+
return False, None
|
|
556
|
+
|
|
557
|
+
if (u1, v1) != (zero, one):
|
|
558
|
+
if v1 in [zero, one]:
|
|
559
|
+
s1 = one
|
|
560
|
+
else:
|
|
561
|
+
s1 = u1.inverse_mod(v1)
|
|
562
|
+
else:
|
|
563
|
+
s1 = 0
|
|
564
|
+
if (u2, v2) != (zero, one):
|
|
565
|
+
if v2 in [zero, one]:
|
|
566
|
+
s2 = one
|
|
567
|
+
else:
|
|
568
|
+
s2 = u2.inverse_mod(v2)
|
|
569
|
+
else:
|
|
570
|
+
s2 = zero
|
|
571
|
+
g = (v1 * v2).gcd(N)
|
|
572
|
+
a = s1 * v2 - s2 * v1
|
|
573
|
+
if a % g != 0:
|
|
574
|
+
if not transformation:
|
|
575
|
+
return False
|
|
576
|
+
else:
|
|
577
|
+
return False, None
|
|
578
|
+
|
|
579
|
+
if not transformation:
|
|
580
|
+
return True
|
|
581
|
+
|
|
582
|
+
# Now we know the cusps are equivalent. Use the proof of Prop 2.2.3
|
|
583
|
+
# of Cremona to find a matrix in Gamma_0(N) relating them.
|
|
584
|
+
if v1 == 0: # the first is oo
|
|
585
|
+
if v2 == 0: # both are oo
|
|
586
|
+
if transformation == "matrix":
|
|
587
|
+
return (True, matrix(ZZ, [[1, 0], [0, 1]]))
|
|
588
|
+
else:
|
|
589
|
+
return (True, one)
|
|
590
|
+
else:
|
|
591
|
+
dum, s2, r2 = u2.xgcd(-v2)
|
|
592
|
+
assert dum.is_one()
|
|
593
|
+
if transformation == "matrix":
|
|
594
|
+
return (True, matrix(ZZ, [[u2, r2], [v2, s2]]))
|
|
595
|
+
else:
|
|
596
|
+
return (True, u2)
|
|
597
|
+
|
|
598
|
+
elif v2 == 0: # the second is oo
|
|
599
|
+
dum, s1, r1 = u1.xgcd(-v1)
|
|
600
|
+
assert dum.is_one()
|
|
601
|
+
if transformation == "matrix":
|
|
602
|
+
return (True, matrix(ZZ, [[s1, -r1], [-v1, u1]]))
|
|
603
|
+
else:
|
|
604
|
+
return (True, s1)
|
|
605
|
+
|
|
606
|
+
dum, s2, r2 = u2.xgcd(-v2)
|
|
607
|
+
assert dum.is_one()
|
|
608
|
+
dum, s1, r1 = u1.xgcd(-v1)
|
|
609
|
+
assert dum.is_one()
|
|
610
|
+
a = s1 * v2 - s2 * v1
|
|
611
|
+
assert (a % g).is_zero()
|
|
612
|
+
# solve x*v1*v2 + a = 0 (mod N).
|
|
613
|
+
d, x0, y0 = (v1 * v2).xgcd(N) # x0*v1*v2 + y0*N = d = g.
|
|
614
|
+
# so x0*v1*v2 - g = 0 (mod N)
|
|
615
|
+
x = -x0 * ZZ(a / g)
|
|
616
|
+
# now x*v1*v2 + a = 0 (mod N)
|
|
617
|
+
|
|
618
|
+
# the rest is all added in trac #10926
|
|
619
|
+
s1p = s1 + x * v1
|
|
620
|
+
M = N // g
|
|
621
|
+
|
|
622
|
+
if transformation == "matrix":
|
|
623
|
+
C = s1p * v2 - s2 * v1
|
|
624
|
+
if C % (M * v1 * v2) == 0:
|
|
625
|
+
k = - C // (M * v1 * v2)
|
|
626
|
+
else:
|
|
627
|
+
k = - (C / (M * v1 * v2)).round("away")
|
|
628
|
+
|
|
629
|
+
s1pp = s1p + k * M * v1
|
|
630
|
+
# C += k*M*v1*v2 # is now the smallest in absolute value
|
|
631
|
+
C = s1pp * v2 - s2 * v1
|
|
632
|
+
A = u2 * s1pp - r2 * v1
|
|
633
|
+
|
|
634
|
+
r1pp = r1 + (x + k * M) * u1
|
|
635
|
+
B = r2 * u1 - r1pp * u2
|
|
636
|
+
D = s2 * u1 - r1pp * v2
|
|
637
|
+
|
|
638
|
+
ga = matrix(ZZ, [[A, B], [C, D]])
|
|
639
|
+
assert ga.det() == 1
|
|
640
|
+
assert C % N == 0
|
|
641
|
+
assert (A * u1 + B * v1) / (C * u1 + D * v1) == u2 / v2
|
|
642
|
+
return (True, ga)
|
|
643
|
+
|
|
644
|
+
else:
|
|
645
|
+
# mainly for backwards compatibility and
|
|
646
|
+
# for how it is used in modular symbols
|
|
647
|
+
A = (u2 * s1p - r2 * v1)
|
|
648
|
+
if u2 != 0 and v1 != 0:
|
|
649
|
+
A = A % (u2 * v1 * M)
|
|
650
|
+
return (True, A)
|
|
651
|
+
|
|
652
|
+
def is_gamma1_equiv(self, other, N) -> tuple[bool, int]:
|
|
653
|
+
r"""
|
|
654
|
+
Return whether ``self`` and ``other`` are equivalent modulo the action of
|
|
655
|
+
`\Gamma_1(N)` via linear fractional transformations.
|
|
656
|
+
|
|
657
|
+
INPUT:
|
|
658
|
+
|
|
659
|
+
- ``other`` -- cusp
|
|
660
|
+
|
|
661
|
+
- ``N`` -- integer (specifies the group `\Gamma_1(N)`)
|
|
662
|
+
|
|
663
|
+
OUTPUT:
|
|
664
|
+
|
|
665
|
+
- ``bool`` -- ``True`` if ``self`` and ``other`` are equivalent
|
|
666
|
+
|
|
667
|
+
- ``int`` -- 0, 1 or -1, gives further information
|
|
668
|
+
about the equivalence: If the two cusps are u1/v1 and u2/v2, then
|
|
669
|
+
they are equivalent if and only if v1 = v2 (mod N) and u1 = u2 (mod
|
|
670
|
+
gcd(v1,N)) or v1 = -v2 (mod N) and u1 = -u2 (mod gcd(v1,N)) The
|
|
671
|
+
sign is +1 for the first and -1 for the second. If the two cusps
|
|
672
|
+
are not equivalent then 0 is returned.
|
|
673
|
+
|
|
674
|
+
EXAMPLES::
|
|
675
|
+
|
|
676
|
+
sage: x = Cusp(2,3)
|
|
677
|
+
sage: y = Cusp(4,5)
|
|
678
|
+
sage: x.is_gamma1_equiv(y,2)
|
|
679
|
+
(True, 1)
|
|
680
|
+
sage: x.is_gamma1_equiv(y,3)
|
|
681
|
+
(False, 0)
|
|
682
|
+
sage: z = Cusp(QQ(x) + 10)
|
|
683
|
+
sage: x.is_gamma1_equiv(z,10)
|
|
684
|
+
(True, 1)
|
|
685
|
+
sage: z = Cusp(1,0)
|
|
686
|
+
sage: x.is_gamma1_equiv(z, 3)
|
|
687
|
+
(True, -1)
|
|
688
|
+
sage: Cusp(0).is_gamma1_equiv(oo, 1)
|
|
689
|
+
(True, 1)
|
|
690
|
+
sage: Cusp(0).is_gamma1_equiv(oo, 3)
|
|
691
|
+
(False, 0)
|
|
692
|
+
"""
|
|
693
|
+
if not isinstance(other, Cusp):
|
|
694
|
+
other = Cusp(other)
|
|
695
|
+
N = ZZ(N)
|
|
696
|
+
u1 = self.__a
|
|
697
|
+
v1 = self.__b
|
|
698
|
+
u2 = other.__a
|
|
699
|
+
v2 = other.__b
|
|
700
|
+
g = v1.gcd(N)
|
|
701
|
+
if ((v2 - v1) % N == 0 and (u2 - u1) % g == 0):
|
|
702
|
+
return True, 1
|
|
703
|
+
elif ((v2 + v1) % N == 0 and (u2 + u1) % g == 0):
|
|
704
|
+
return True, -1
|
|
705
|
+
return False, 0
|
|
706
|
+
|
|
707
|
+
def is_gamma_h_equiv(self, other, G) -> tuple[bool, int]:
|
|
708
|
+
r"""
|
|
709
|
+
Return a pair ``(b, t)``, where ``b`` is ``True`` or ``False`` as
|
|
710
|
+
``self`` and ``other`` are equivalent under the action of `G`, and `t`
|
|
711
|
+
is 1 or -1, as described below.
|
|
712
|
+
|
|
713
|
+
Two cusps `u1/v1` and `u2/v2` are equivalent modulo
|
|
714
|
+
Gamma_H(N) if and only if `v1 = h*v2 (\mathrm{mod} N)` and
|
|
715
|
+
`u1 = h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` or
|
|
716
|
+
`v1 = -h*v2 (mod N)` and
|
|
717
|
+
`u1 = -h^{(-1)}*u2 (\mathrm{mod} gcd(v1,N))` for some
|
|
718
|
+
`h \in H`. Then t is 1 or -1 as c and c' fall into the
|
|
719
|
+
first or second case, respectively.
|
|
720
|
+
|
|
721
|
+
INPUT:
|
|
722
|
+
|
|
723
|
+
- ``other`` -- cusp
|
|
724
|
+
|
|
725
|
+
- ``G`` -- a congruence subgroup Gamma_H(N)
|
|
726
|
+
|
|
727
|
+
OUTPUT:
|
|
728
|
+
|
|
729
|
+
- ``bool`` -- ``True`` if ``self`` and ``other`` are equivalent
|
|
730
|
+
|
|
731
|
+
- ``int`` -- -1, 0, 1; extra info
|
|
732
|
+
|
|
733
|
+
EXAMPLES::
|
|
734
|
+
|
|
735
|
+
sage: # needs sage.libs.pari
|
|
736
|
+
sage: x = Cusp(2,3)
|
|
737
|
+
sage: y = Cusp(4,5)
|
|
738
|
+
sage: x.is_gamma_h_equiv(y,GammaH(13,[2]))
|
|
739
|
+
(True, 1)
|
|
740
|
+
sage: x.is_gamma_h_equiv(y,GammaH(13,[5]))
|
|
741
|
+
(False, 0)
|
|
742
|
+
sage: x.is_gamma_h_equiv(y,GammaH(5,[]))
|
|
743
|
+
(False, 0)
|
|
744
|
+
sage: x.is_gamma_h_equiv(y,GammaH(23,[4]))
|
|
745
|
+
(True, -1)
|
|
746
|
+
|
|
747
|
+
Enumerating the cusps for a space of modular symbols uses this
|
|
748
|
+
function.
|
|
749
|
+
|
|
750
|
+
::
|
|
751
|
+
|
|
752
|
+
sage: # needs sage.libs.pari
|
|
753
|
+
sage: G = GammaH(25,[6]); M = G.modular_symbols(); M
|
|
754
|
+
Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25)
|
|
755
|
+
with H generated by [6] of weight 2 with sign 0 over Rational Field
|
|
756
|
+
sage: M.cusps()
|
|
757
|
+
[8/25, 1/3, 6/25, 1/4, 1/15, -7/15, 7/15, 4/15, 1/20, 3/20, 7/20, 9/20]
|
|
758
|
+
sage: len(M.cusps())
|
|
759
|
+
12
|
|
760
|
+
|
|
761
|
+
This is always one more than the associated space of weight 2 Eisenstein
|
|
762
|
+
series.
|
|
763
|
+
|
|
764
|
+
::
|
|
765
|
+
|
|
766
|
+
sage: # needs sage.libs.pari
|
|
767
|
+
sage: G.dimension_eis(2)
|
|
768
|
+
11
|
|
769
|
+
sage: M.cuspidal_subspace()
|
|
770
|
+
Modular Symbols subspace of dimension 0 of
|
|
771
|
+
Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25)
|
|
772
|
+
with H generated by [6] of weight 2 with sign 0 over Rational Field
|
|
773
|
+
sage: G.dimension_cusp_forms(2)
|
|
774
|
+
0
|
|
775
|
+
"""
|
|
776
|
+
from sage.modular.arithgroup.all import GammaH_class
|
|
777
|
+
if not isinstance(other, Cusp):
|
|
778
|
+
other = Cusp(other)
|
|
779
|
+
if not isinstance(G, GammaH_class):
|
|
780
|
+
raise TypeError("G must be a group GammaH(N).")
|
|
781
|
+
|
|
782
|
+
H = G._list_of_elements_in_H()
|
|
783
|
+
N = ZZ(G.level())
|
|
784
|
+
u1 = self.__a
|
|
785
|
+
v1 = self.__b
|
|
786
|
+
u2 = other.__a
|
|
787
|
+
v2 = other.__b
|
|
788
|
+
g = v1.gcd(N)
|
|
789
|
+
|
|
790
|
+
for h in H:
|
|
791
|
+
v_tmp = (h * v1) % N
|
|
792
|
+
u_tmp = (h * u2) % N
|
|
793
|
+
if (v_tmp - v2) % N == 0 and (u_tmp - u1) % g == 0:
|
|
794
|
+
return True, 1
|
|
795
|
+
if (v_tmp + v2) % N == 0 and (u_tmp + u1) % g == 0:
|
|
796
|
+
return True, -1
|
|
797
|
+
return False, 0
|
|
798
|
+
|
|
799
|
+
def _acted_upon_(self, g, self_on_left):
|
|
800
|
+
r"""
|
|
801
|
+
Implement the left action of `SL_2(\ZZ)` on ``self``.
|
|
802
|
+
|
|
803
|
+
EXAMPLES::
|
|
804
|
+
|
|
805
|
+
sage: g = matrix(ZZ, 2, [1,1,0,1]); g
|
|
806
|
+
[1 1]
|
|
807
|
+
[0 1]
|
|
808
|
+
sage: g * Cusp(2,5)
|
|
809
|
+
7/5
|
|
810
|
+
sage: Cusp(2,5) * g
|
|
811
|
+
Traceback (most recent call last):
|
|
812
|
+
...
|
|
813
|
+
TypeError: unsupported operand parent(s) for *: 'Set P^1(QQ) of all cusps' and 'Full MatrixSpace of 2 by 2 dense matrices over Integer Ring'
|
|
814
|
+
sage: h = matrix(ZZ, 2, [12,3,-100,7])
|
|
815
|
+
sage: h * Cusp(2,5)
|
|
816
|
+
-13/55
|
|
817
|
+
sage: Cusp(2,5)._acted_upon_(h, False)
|
|
818
|
+
-13/55
|
|
819
|
+
sage: (h*g) * Cusp(3,7) == h * (g * Cusp(3,7))
|
|
820
|
+
True
|
|
821
|
+
|
|
822
|
+
sage: cm = sage.structure.element.get_coercion_model()
|
|
823
|
+
sage: cm.explain(MatrixSpace(ZZ, 2), Cusps)
|
|
824
|
+
Action discovered.
|
|
825
|
+
Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps
|
|
826
|
+
Result lives in Set P^1(QQ) of all cusps
|
|
827
|
+
Set P^1(QQ) of all cusps
|
|
828
|
+
"""
|
|
829
|
+
if not self_on_left:
|
|
830
|
+
if (isinstance(g, Matrix) and g.base_ring() is ZZ
|
|
831
|
+
and g.ncols() == 2 == g.nrows()):
|
|
832
|
+
a, b, c, d = g.list()
|
|
833
|
+
return Cusp(a * self.__a + b * self.__b,
|
|
834
|
+
c * self.__a + d * self.__b)
|
|
835
|
+
|
|
836
|
+
def apply(self, g):
|
|
837
|
+
"""
|
|
838
|
+
Return g(self), where g=[a,b,c,d] is a list of length 4, which we
|
|
839
|
+
view as a linear fractional transformation.
|
|
840
|
+
|
|
841
|
+
EXAMPLES: Apply the identity matrix::
|
|
842
|
+
|
|
843
|
+
sage: Cusp(0).apply([1,0,0,1])
|
|
844
|
+
0
|
|
845
|
+
sage: Cusp(0).apply([0,-1,1,0])
|
|
846
|
+
Infinity
|
|
847
|
+
sage: Cusp(0).apply([1,-3,0,1])
|
|
848
|
+
-3
|
|
849
|
+
"""
|
|
850
|
+
return Cusp(g[0] * self.__a + g[1] * self.__b,
|
|
851
|
+
g[2] * self.__a + g[3] * self.__b)
|
|
852
|
+
|
|
853
|
+
def galois_action(self, t, N):
|
|
854
|
+
r"""
|
|
855
|
+
Suppose this cusp is `\alpha`, `G` a congruence subgroup of level `N`
|
|
856
|
+
and `\sigma` is the automorphism in the Galois group of
|
|
857
|
+
`\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to `\zeta_N^t`. Then this
|
|
858
|
+
function computes a cusp `\beta` such that `\sigma([\alpha]) = [\beta]`,
|
|
859
|
+
where `[\alpha]` is the equivalence class of `\alpha` modulo `G`.
|
|
860
|
+
|
|
861
|
+
This code only needs as input the level and not the group since the
|
|
862
|
+
action of Galois for a congruence group `G` of level `N` is compatible
|
|
863
|
+
with the action of the full congruence group `\Gamma(N)`.
|
|
864
|
+
|
|
865
|
+
INPUT:
|
|
866
|
+
|
|
867
|
+
- ``t`` -- integer that is coprime to N
|
|
868
|
+
|
|
869
|
+
- ``N`` -- positive integer (level)
|
|
870
|
+
|
|
871
|
+
OUTPUT: a cusp
|
|
872
|
+
|
|
873
|
+
.. WARNING::
|
|
874
|
+
|
|
875
|
+
In some cases `N` must fit in a long long, i.e., there
|
|
876
|
+
are cases where this algorithm isn't fully implemented.
|
|
877
|
+
|
|
878
|
+
.. NOTE::
|
|
879
|
+
|
|
880
|
+
Modular curves can have multiple non-isomorphic models over `\QQ`.
|
|
881
|
+
The action of Galois depends on such a model. The model over `\QQ`
|
|
882
|
+
of `X(G)` used here is the model where the function field
|
|
883
|
+
`\QQ(X(G))` is given by the functions whose Fourier expansion at
|
|
884
|
+
`\infty` have their coefficients in `\QQ`. For `X(N):=X(\Gamma(N))`
|
|
885
|
+
the corresponding moduli interpretation over `\ZZ[1/N]` is that
|
|
886
|
+
`X(N)` parametrizes pairs `(E,a)` where `E` is a (generalized)
|
|
887
|
+
elliptic curve and `a: \ZZ / N\ZZ \times \mu_N \to E` is a closed
|
|
888
|
+
immersion such that the Weil pairing of `a(1,1)` and `a(0,\zeta_N)`
|
|
889
|
+
is `\zeta_N`. In this parameterisation the point `z \in H`
|
|
890
|
+
corresponds to the pair `(E_z,a_z)` with `E_z=\CC/(z \ZZ+\ZZ)` and
|
|
891
|
+
`a_z: \ZZ / N\ZZ \times \mu_N \to E` given by `a_z(1,1) = z/N` and
|
|
892
|
+
`a_z(0,\zeta_N) = 1/N`.
|
|
893
|
+
Similarly `X_1(N):=X(\Gamma_1(N))` parametrizes pairs `(E,a)` where
|
|
894
|
+
`a: \mu_N \to E` is a closed immersion.
|
|
895
|
+
|
|
896
|
+
EXAMPLES::
|
|
897
|
+
|
|
898
|
+
sage: Cusp(1/10).galois_action(3, 50)
|
|
899
|
+
1/170
|
|
900
|
+
sage: Cusp(oo).galois_action(3, 50)
|
|
901
|
+
Infinity
|
|
902
|
+
sage: c = Cusp(0).galois_action(3, 50); c
|
|
903
|
+
50/17
|
|
904
|
+
sage: Gamma0(50).reduce_cusp(c)
|
|
905
|
+
0
|
|
906
|
+
|
|
907
|
+
Here we compute the permutations of the action for t=3 on cusps for
|
|
908
|
+
Gamma0(50). ::
|
|
909
|
+
|
|
910
|
+
sage: N = 50; t=3; G = Gamma0(N); C = G.cusps()
|
|
911
|
+
sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1]
|
|
912
|
+
sage: for i in range(5):
|
|
913
|
+
....: print((i, t^i))
|
|
914
|
+
....: print([cl(alpha.galois_action(t^i,N)) for alpha in C])
|
|
915
|
+
(0, 1)
|
|
916
|
+
[0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
|
|
917
|
+
(1, 3)
|
|
918
|
+
[0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity]
|
|
919
|
+
(2, 9)
|
|
920
|
+
[0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity]
|
|
921
|
+
(3, 27)
|
|
922
|
+
[0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity]
|
|
923
|
+
(4, 81)
|
|
924
|
+
[0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
|
|
925
|
+
|
|
926
|
+
TESTS:
|
|
927
|
+
|
|
928
|
+
Here we check that the Galois action is indeed a permutation on the
|
|
929
|
+
cusps of Gamma1(48) and check that :issue:`13253` is fixed. ::
|
|
930
|
+
|
|
931
|
+
sage: # needs sage.libs.pari
|
|
932
|
+
sage: G = Gamma1(48)
|
|
933
|
+
sage: C = G.cusps()
|
|
934
|
+
sage: for i in Integers(48).unit_gens():
|
|
935
|
+
....: C_permuted = [G.reduce_cusp(c.galois_action(i,48)) for c in C]
|
|
936
|
+
....: assert len(set(C_permuted))==len(C)
|
|
937
|
+
|
|
938
|
+
We test that Gamma1(19) has 9 rational cusps and check that :issue:`8998`
|
|
939
|
+
is fixed. ::
|
|
940
|
+
|
|
941
|
+
sage: # needs sage.libs.pari
|
|
942
|
+
sage: G = Gamma1(19)
|
|
943
|
+
sage: [c for c in G.cusps() if c.galois_action(2,19).is_gamma1_equiv(c,19)[0]]
|
|
944
|
+
[2/19, 3/19, 4/19, 5/19, 6/19, 7/19, 8/19, 9/19, Infinity]
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
REFERENCES:
|
|
948
|
+
|
|
949
|
+
- Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves"
|
|
950
|
+
|
|
951
|
+
- There is a long comment about our algorithm in the source code for this function.
|
|
952
|
+
|
|
953
|
+
AUTHORS:
|
|
954
|
+
|
|
955
|
+
- William Stein, 2009-04-18
|
|
956
|
+
"""
|
|
957
|
+
if self.is_infinity():
|
|
958
|
+
return self
|
|
959
|
+
if not isinstance(t, Integer):
|
|
960
|
+
t = Integer(t)
|
|
961
|
+
|
|
962
|
+
# Our algorithm for computing the Galois action works as
|
|
963
|
+
# follows (see Section 1.3 of Glenn Stevens "Arithmetic on
|
|
964
|
+
# Modular Curves" for a proof that the action given below is
|
|
965
|
+
# correct). We alternatively view the set of cusps as the
|
|
966
|
+
# Gamma-equivalence classes of column vectors [a;b] with
|
|
967
|
+
# gcd(a,b,N)=1, and the left action of Gamma by matrix
|
|
968
|
+
# multiplication. The action of t is induced by [a;b] |-->
|
|
969
|
+
# [a;t'*b], where t' is an inverse mod N of t. For [a;t'*b]
|
|
970
|
+
# with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is
|
|
971
|
+
# just the rational number a/(t'*b). Thus in this case, to
|
|
972
|
+
# compute the action of t we just do a/b <--> [a;b] |--->
|
|
973
|
+
# [a;t'*b] <--> a/(t'*b). IN the other case when we get
|
|
974
|
+
# [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen,
|
|
975
|
+
# we have to work a bit harder. We need to find [c;d] such
|
|
976
|
+
# that [c;d] is congruent to [a;t'*b] modulo N, and
|
|
977
|
+
# gcd(c,d)=1. There is a standard lifting algorithm that is
|
|
978
|
+
# implemented for working with P^1(Z/NZ) [it is needed for
|
|
979
|
+
# modular symbols algorithms], so we just apply it to lift
|
|
980
|
+
# [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two
|
|
981
|
+
# entries congruent to [a,t'*b] modulo N. This exactly solves
|
|
982
|
+
# our problem, since gcd(c,d)=1.
|
|
983
|
+
|
|
984
|
+
a = self.__a
|
|
985
|
+
b = self.__b * t.inverse_mod(N)
|
|
986
|
+
if b.gcd(a) != 1:
|
|
987
|
+
_, _, a, b = lift_to_sl2z_llong(a, b, N)
|
|
988
|
+
a = Integer(a)
|
|
989
|
+
b = Integer(b)
|
|
990
|
+
|
|
991
|
+
# Now that we've computed the Galois action, we efficiently
|
|
992
|
+
# construct the corresponding cusp as a Cusp object.
|
|
993
|
+
return Cusp(a, b, check=False)
|
|
994
|
+
|
|
995
|
+
def __pari__(self):
|
|
996
|
+
"""
|
|
997
|
+
Return a PARI representation of ``self``.
|
|
998
|
+
|
|
999
|
+
EXAMPLES::
|
|
1000
|
+
|
|
1001
|
+
sage: Cusp(1, 0).__pari__() # needs sage.libs.pari
|
|
1002
|
+
+oo
|
|
1003
|
+
sage: pari(Cusp(3, 2)) # needs sage.libs.pari
|
|
1004
|
+
3/2
|
|
1005
|
+
"""
|
|
1006
|
+
b = self.__b
|
|
1007
|
+
return pari(self.__a / b) if b else pari.oo()
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
class Cusps_class(Singleton, Parent):
|
|
1011
|
+
"""
|
|
1012
|
+
The set of cusps.
|
|
1013
|
+
|
|
1014
|
+
EXAMPLES::
|
|
1015
|
+
|
|
1016
|
+
sage: C = Cusps; C
|
|
1017
|
+
Set P^1(QQ) of all cusps
|
|
1018
|
+
sage: loads(C.dumps()) == C
|
|
1019
|
+
True
|
|
1020
|
+
"""
|
|
1021
|
+
def __init__(self):
|
|
1022
|
+
r"""
|
|
1023
|
+
The set of cusps, i.e. `\mathbb{P}^1(\QQ)`.
|
|
1024
|
+
|
|
1025
|
+
EXAMPLES::
|
|
1026
|
+
|
|
1027
|
+
sage: C = sage.modular.cusps.Cusps_class() ; C
|
|
1028
|
+
Set P^1(QQ) of all cusps
|
|
1029
|
+
sage: Cusps == C
|
|
1030
|
+
True
|
|
1031
|
+
"""
|
|
1032
|
+
Parent.__init__(self, self)
|
|
1033
|
+
|
|
1034
|
+
Element = Cusp
|
|
1035
|
+
|
|
1036
|
+
def _repr_(self):
|
|
1037
|
+
"""
|
|
1038
|
+
String representation of the set of cusps.
|
|
1039
|
+
|
|
1040
|
+
EXAMPLES::
|
|
1041
|
+
|
|
1042
|
+
sage: Cusps
|
|
1043
|
+
Set P^1(QQ) of all cusps
|
|
1044
|
+
sage: Cusps._repr_()
|
|
1045
|
+
'Set P^1(QQ) of all cusps'
|
|
1046
|
+
sage: Cusps.rename('CUSPS'); Cusps
|
|
1047
|
+
CUSPS
|
|
1048
|
+
sage: Cusps.rename(); Cusps
|
|
1049
|
+
Set P^1(QQ) of all cusps
|
|
1050
|
+
sage: Cusps
|
|
1051
|
+
Set P^1(QQ) of all cusps
|
|
1052
|
+
"""
|
|
1053
|
+
return "Set P^1(QQ) of all cusps"
|
|
1054
|
+
|
|
1055
|
+
def _latex_(self):
|
|
1056
|
+
r"""
|
|
1057
|
+
Return latex representation of ``self``.
|
|
1058
|
+
|
|
1059
|
+
EXAMPLES::
|
|
1060
|
+
|
|
1061
|
+
sage: latex(Cusps)
|
|
1062
|
+
\mathbf{P}^1(\QQ)
|
|
1063
|
+
sage: latex(Cusps) == Cusps._latex_()
|
|
1064
|
+
True
|
|
1065
|
+
"""
|
|
1066
|
+
return r"\mathbf{P}^1(\QQ)"
|
|
1067
|
+
|
|
1068
|
+
def __call__(self, x):
|
|
1069
|
+
"""
|
|
1070
|
+
Coerce x into the set of cusps.
|
|
1071
|
+
|
|
1072
|
+
EXAMPLES::
|
|
1073
|
+
|
|
1074
|
+
sage: a = Cusps(-4/5); a
|
|
1075
|
+
-4/5
|
|
1076
|
+
sage: Cusps(a) is a
|
|
1077
|
+
False
|
|
1078
|
+
sage: Cusps(1.5)
|
|
1079
|
+
3/2
|
|
1080
|
+
sage: Cusps(oo)
|
|
1081
|
+
Infinity
|
|
1082
|
+
sage: Cusps(I)
|
|
1083
|
+
Traceback (most recent call last):
|
|
1084
|
+
...
|
|
1085
|
+
TypeError: unable to convert I to a cusp
|
|
1086
|
+
|
|
1087
|
+
TESTS::
|
|
1088
|
+
|
|
1089
|
+
sage: Cusps.has_coerce_map_from(ZZ)
|
|
1090
|
+
True
|
|
1091
|
+
sage: Cusps.has_coerce_map_from(QQ)
|
|
1092
|
+
True
|
|
1093
|
+
sage: Cusps.has_coerce_map_from(GF(7))
|
|
1094
|
+
False
|
|
1095
|
+
"""
|
|
1096
|
+
return Cusp(x)
|
|
1097
|
+
|
|
1098
|
+
def _coerce_map_from_(self, R):
|
|
1099
|
+
if QQ.has_coerce_map_from(R):
|
|
1100
|
+
return True
|
|
1101
|
+
if R is InfinityRing:
|
|
1102
|
+
return True
|
|
1103
|
+
return False
|
|
1104
|
+
|
|
1105
|
+
def _element_constructor_(self, x):
|
|
1106
|
+
return Cusp(x)
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
Cusps = Cusps_class()
|