passagemath-schemes 10.8.1a4__cp314-cp314t-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.
Files changed (312) 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.8.1a4.dist-info/METADATA +203 -0
  7. passagemath_schemes-10.8.1a4.dist-info/METADATA.bak +204 -0
  8. passagemath_schemes-10.8.1a4.dist-info/RECORD +312 -0
  9. passagemath_schemes-10.8.1a4.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.8.1a4.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 +9556 -0
  24. sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
  25. sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
  26. sage/dynamics/arithmetic_dynamics/wehlerK3.py +2578 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +727 -0
  29. sage/lfunctions/pari.py +971 -0
  30. sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
  31. sage/lfunctions/zero_sums.pyx +1847 -0
  32. sage/modular/abvar/abvar.py +5132 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +414 -0
  34. sage/modular/abvar/abvar_newform.py +246 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +187 -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 +721 -0
  40. sage/modular/abvar/homspace.py +989 -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 +741 -0
  45. sage/modular/all.py +43 -0
  46. sage/modular/arithgroup/all.py +20 -0
  47. sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
  48. sage/modular/arithgroup/arithgroup_element.pyx +474 -0
  49. sage/modular/arithgroup/arithgroup_generic.py +1406 -0
  50. sage/modular/arithgroup/arithgroup_perm.py +2692 -0
  51. sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
  52. sage/modular/arithgroup/congroup.pyx +334 -0
  53. sage/modular/arithgroup/congroup_gamma.py +361 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +659 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1491 -0
  57. sage/modular/arithgroup/congroup_generic.py +630 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +266 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1067 -0
  61. sage/modular/arithgroup/tests.py +425 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3736 -0
  64. sage/modular/btquotients/pautomorphicform.py +2564 -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 +1107 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +571 -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 +1076 -0
  77. sage/modular/hecke/algebra.py +725 -0
  78. sage/modular/hecke/all.py +19 -0
  79. sage/modular/hecke/ambient_module.py +994 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +302 -0
  82. sage/modular/hecke/hecke_operator.py +736 -0
  83. sage/modular/hecke/homspace.py +185 -0
  84. sage/modular/hecke/module.py +1744 -0
  85. sage/modular/hecke/morphism.py +139 -0
  86. sage/modular/hecke/submodule.py +970 -0
  87. sage/modular/hypergeometric_misc.cpython-314t-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 +2020 -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 +1070 -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 +817 -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 +120 -0
  101. sage/modular/modform/ambient_g1.py +199 -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 +487 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4105 -0
  108. sage/modular/modform/half_integral.py +154 -0
  109. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  110. sage/modular/modform/j_invariant.py +47 -0
  111. sage/modular/modform/l_series_gross_zagier.py +127 -0
  112. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  114. sage/modular/modform/notes.py +45 -0
  115. sage/modular/modform/numerical.py +514 -0
  116. sage/modular/modform/periods.py +14 -0
  117. sage/modular/modform/ring.py +1257 -0
  118. sage/modular/modform/space.py +1859 -0
  119. sage/modular/modform/submodule.py +118 -0
  120. sage/modular/modform/tests.py +64 -0
  121. sage/modular/modform/theta.py +110 -0
  122. sage/modular/modform/vm_basis.py +380 -0
  123. sage/modular/modform/weight1.py +221 -0
  124. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  125. sage/modular/modform_hecketriangle/abstract_space.py +2527 -0
  126. sage/modular/modform_hecketriangle/all.py +30 -0
  127. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  128. sage/modular/modform_hecketriangle/constructor.py +416 -0
  129. sage/modular/modform_hecketriangle/element.py +351 -0
  130. sage/modular/modform_hecketriangle/functors.py +752 -0
  131. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  132. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  133. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3349 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1426 -0
  135. sage/modular/modform_hecketriangle/readme.py +1214 -0
  136. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  137. sage/modular/modform_hecketriangle/space.py +1037 -0
  138. sage/modular/modform_hecketriangle/subspace.py +423 -0
  139. sage/modular/modsym/all.py +17 -0
  140. sage/modular/modsym/ambient.py +3844 -0
  141. sage/modular/modsym/boundary.py +1420 -0
  142. sage/modular/modsym/element.py +336 -0
  143. sage/modular/modsym/g1list.py +178 -0
  144. sage/modular/modsym/ghlist.py +182 -0
  145. sage/modular/modsym/hecke_operator.py +73 -0
  146. sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
  147. sage/modular/modsym/manin_symbol.pxd +5 -0
  148. sage/modular/modsym/manin_symbol.pyx +497 -0
  149. sage/modular/modsym/manin_symbol_list.py +1291 -0
  150. sage/modular/modsym/modsym.py +400 -0
  151. sage/modular/modsym/modular_symbols.py +384 -0
  152. sage/modular/modsym/p1list_nf.py +1241 -0
  153. sage/modular/modsym/relation_matrix.py +591 -0
  154. sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
  155. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  156. sage/modular/modsym/space.py +2468 -0
  157. sage/modular/modsym/subspace.py +455 -0
  158. sage/modular/modsym/tests.py +376 -0
  159. sage/modular/multiple_zeta.py +2635 -0
  160. sage/modular/multiple_zeta_F_algebra.py +789 -0
  161. sage/modular/overconvergent/all.py +6 -0
  162. sage/modular/overconvergent/genus0.py +1879 -0
  163. sage/modular/overconvergent/hecke_series.py +1187 -0
  164. sage/modular/overconvergent/weightspace.py +776 -0
  165. sage/modular/pollack_stevens/all.py +4 -0
  166. sage/modular/pollack_stevens/distributions.py +874 -0
  167. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  168. sage/modular/pollack_stevens/manin_map.py +856 -0
  169. sage/modular/pollack_stevens/modsym.py +1590 -0
  170. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  171. sage/modular/pollack_stevens/sigma0.py +534 -0
  172. sage/modular/pollack_stevens/space.py +1078 -0
  173. sage/modular/quasimodform/all.py +3 -0
  174. sage/modular/quasimodform/element.py +846 -0
  175. sage/modular/quasimodform/ring.py +826 -0
  176. sage/modular/quatalg/all.py +3 -0
  177. sage/modular/quatalg/brandt.py +1642 -0
  178. sage/modular/ssmod/all.py +8 -0
  179. sage/modular/ssmod/ssmod.py +827 -0
  180. sage/rings/all__sagemath_schemes.py +1 -0
  181. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  182. sage/rings/polynomial/binary_form_reduce.py +585 -0
  183. sage/schemes/all.py +41 -0
  184. sage/schemes/berkovich/all.py +6 -0
  185. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  186. sage/schemes/berkovich/berkovich_space.py +700 -0
  187. sage/schemes/curves/affine_curve.py +2924 -0
  188. sage/schemes/curves/all.py +33 -0
  189. sage/schemes/curves/closed_point.py +434 -0
  190. sage/schemes/curves/constructor.py +397 -0
  191. sage/schemes/curves/curve.py +542 -0
  192. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  193. sage/schemes/curves/point.py +463 -0
  194. sage/schemes/curves/projective_curve.py +3203 -0
  195. sage/schemes/curves/weighted_projective_curve.py +106 -0
  196. sage/schemes/curves/zariski_vankampen.py +1931 -0
  197. sage/schemes/cyclic_covers/all.py +2 -0
  198. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  199. sage/schemes/cyclic_covers/constructor.py +137 -0
  200. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  201. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  202. sage/schemes/elliptic_curves/BSD.py +991 -0
  203. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  204. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  205. sage/schemes/elliptic_curves/all.py +49 -0
  206. sage/schemes/elliptic_curves/cardinality.py +609 -0
  207. sage/schemes/elliptic_curves/cm.py +1103 -0
  208. sage/schemes/elliptic_curves/constructor.py +1530 -0
  209. sage/schemes/elliptic_curves/ec_database.py +175 -0
  210. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3971 -0
  211. sage/schemes/elliptic_curves/ell_egros.py +457 -0
  212. sage/schemes/elliptic_curves/ell_field.py +2837 -0
  213. sage/schemes/elliptic_curves/ell_finite_field.py +3249 -0
  214. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  215. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  216. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  217. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  218. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  219. sage/schemes/elliptic_curves/ell_point.py +4944 -0
  220. sage/schemes/elliptic_curves/ell_rational_field.py +7184 -0
  221. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  222. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  223. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  224. sage/schemes/elliptic_curves/formal_group.py +760 -0
  225. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  226. sage/schemes/elliptic_curves/gal_reps_number_field.py +1663 -0
  227. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  228. sage/schemes/elliptic_curves/heegner.py +7328 -0
  229. sage/schemes/elliptic_curves/height.py +2108 -0
  230. sage/schemes/elliptic_curves/hom.py +1788 -0
  231. sage/schemes/elliptic_curves/hom_composite.py +1084 -0
  232. sage/schemes/elliptic_curves/hom_fractional.py +544 -0
  233. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  234. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  235. sage/schemes/elliptic_curves/hom_sum.py +681 -0
  236. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  237. sage/schemes/elliptic_curves/homset.py +271 -0
  238. sage/schemes/elliptic_curves/isogeny_class.py +1523 -0
  239. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  240. sage/schemes/elliptic_curves/jacobian.py +247 -0
  241. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  242. sage/schemes/elliptic_curves/kraus.py +1014 -0
  243. sage/schemes/elliptic_curves/lseries_ell.py +915 -0
  244. sage/schemes/elliptic_curves/mod5family.py +105 -0
  245. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  246. sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
  247. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  248. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  249. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  250. sage/schemes/elliptic_curves/padics.py +1816 -0
  251. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  252. sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
  253. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  254. sage/schemes/elliptic_curves/saturation.py +716 -0
  255. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  256. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  257. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  258. sage/schemes/hyperelliptic_curves/all.py +6 -0
  259. sage/schemes/hyperelliptic_curves/constructor.py +369 -0
  260. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1948 -0
  261. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +936 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  265. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  266. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +312 -0
  267. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_generic.py +437 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +878 -0
  271. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  272. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  273. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3863 -0
  274. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  275. sage/schemes/jacobians/all.py +2 -0
  276. sage/schemes/overview.py +161 -0
  277. sage/schemes/plane_conics/all.py +22 -0
  278. sage/schemes/plane_conics/con_field.py +1296 -0
  279. sage/schemes/plane_conics/con_finite_field.py +158 -0
  280. sage/schemes/plane_conics/con_number_field.py +456 -0
  281. sage/schemes/plane_conics/con_rational_field.py +406 -0
  282. sage/schemes/plane_conics/con_rational_function_field.py +581 -0
  283. sage/schemes/plane_conics/constructor.py +249 -0
  284. sage/schemes/plane_quartics/all.py +2 -0
  285. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  286. sage/schemes/plane_quartics/quartic_generic.py +53 -0
  287. sage/schemes/riemann_surfaces/all.py +1 -0
  288. sage/schemes/riemann_surfaces/riemann_surface.py +4177 -0
  289. sage_wheels/share/cremona/cremona_mini.db +0 -0
  290. sage_wheels/share/ellcurves/rank0 +30427 -0
  291. sage_wheels/share/ellcurves/rank1 +31871 -0
  292. sage_wheels/share/ellcurves/rank10 +6 -0
  293. sage_wheels/share/ellcurves/rank11 +6 -0
  294. sage_wheels/share/ellcurves/rank12 +1 -0
  295. sage_wheels/share/ellcurves/rank14 +1 -0
  296. sage_wheels/share/ellcurves/rank15 +1 -0
  297. sage_wheels/share/ellcurves/rank17 +1 -0
  298. sage_wheels/share/ellcurves/rank19 +1 -0
  299. sage_wheels/share/ellcurves/rank2 +2388 -0
  300. sage_wheels/share/ellcurves/rank20 +1 -0
  301. sage_wheels/share/ellcurves/rank21 +1 -0
  302. sage_wheels/share/ellcurves/rank22 +1 -0
  303. sage_wheels/share/ellcurves/rank23 +1 -0
  304. sage_wheels/share/ellcurves/rank24 +1 -0
  305. sage_wheels/share/ellcurves/rank28 +1 -0
  306. sage_wheels/share/ellcurves/rank3 +836 -0
  307. sage_wheels/share/ellcurves/rank4 +10 -0
  308. sage_wheels/share/ellcurves/rank5 +5 -0
  309. sage_wheels/share/ellcurves/rank6 +5 -0
  310. sage_wheels/share/ellcurves/rank7 +5 -0
  311. sage_wheels/share/ellcurves/rank8 +6 -0
  312. sage_wheels/share/ellcurves/rank9 +7 -0
@@ -0,0 +1,1642 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ r"""
3
+ Brandt modules
4
+
5
+ Introduction
6
+ ------------
7
+
8
+ The construction of Brandt modules provides us with a method to
9
+ compute modular forms, as outlined in Pizer's paper [Piz1980]_.
10
+
11
+ Given a prime number `p` and a positive integer `M` with `p\nmid M`,
12
+ the *Brandt module* `B(p, M)` is the free abelian group on right ideal
13
+ classes of a quaternion order of level `pM` in the quaternion algebra
14
+ ramified precisely at the places `p` and `\infty`. This Brandt module
15
+ carries a natural Hecke action given by Brandt matrices. There exists
16
+ a non-canonical Hecke algebra isomorphism between `B(p, M)` and a
17
+ certain subspace of `S_{2}(\Gamma_0(pM))` containing the newforms.
18
+
19
+ Quaternion Algebras
20
+ -------------------
21
+
22
+ A quaternion algebra over `\QQ` is a central simple algebra of
23
+ dimension 4 over `\QQ`. Such an algebra `A` is said to be ramified at
24
+ a place `v` of `\QQ` if and only if `A \otimes \QQ_v` is a division
25
+ algebra. Otherwise `A` is said to be split at `v`.
26
+
27
+ ``A = QuaternionAlgebra(p)`` returns the quaternion algebra `A` over
28
+ `\QQ` ramified precisely at the places `p` and `\infty`.
29
+
30
+ ``A = QuaternionAlgebra(a, b)`` returns the quaternion algebra `A`
31
+ over `\QQ` with basis `\{1, i, j, k\}` such that `i^2 = a`, `j^2 = b`
32
+ and `ij = -ji = k.`
33
+
34
+ An order `R` in a quaternion algebra `A` over `\QQ` is a 4-dimensional
35
+ lattice in `A` which is also a subring containing the identity. A
36
+ maximal order is one that is not properly contained in another order.
37
+
38
+ A particularly important kind of orders are those that have a level;
39
+ see Definition 1.2 in [Piz1980]_. This is a positive integer `N` such
40
+ that every prime that ramifies in `A` divides `N` to an odd power.
41
+ The maximal orders are those that have level equal to the discriminant
42
+ of `A`.
43
+
44
+ ``R = A.maximal_order()`` returns a maximal order `R` in the quaternion
45
+ algebra `A.`
46
+
47
+ A right `\mathcal{O}`-ideal `I` is a lattice in `A` such that for
48
+ every prime `p` there exists `a_p\in A_p^*` with `I_p =
49
+ a_p\mathcal{O}_p`. Two right `\mathcal{O}`-ideals `I` and `J` are said
50
+ to belong to the same class if `I=aJ` for some `a \in A^*`. Left
51
+ `\mathcal{O}`-ideals are defined in a similar fashion.
52
+
53
+ The right order of `I` is the subring of `A` consisting of elements
54
+ `a` with `Ia \subseteq I`.
55
+
56
+ Brandt Modules
57
+ --------------
58
+
59
+ ``B = BrandtModule(p, M=1)`` returns the Brandt module associated to
60
+ the prime number `p` and the integer `M`, with `p` not dividing `M`.
61
+
62
+ ``A = B.quaternion_algebra()`` returns the quaternion algebra attached
63
+ to `B`; this is the quaternion algebra over `\QQ` ramified exactly at
64
+ `p` and `\infty`.
65
+
66
+ ``O = B.order_of_level_N()`` returns an order `\mathcal{O}` of level
67
+ `N = pM` in `A`.
68
+
69
+ ``B.right_ideals()`` returns a tuple of representatives for all right
70
+ ideal classes of `\mathcal{O}`.
71
+
72
+ The implementation of this method is especially interesting. It
73
+ depends on the construction of a Hecke module defined as a free
74
+ abelian group on right ideal classes of a quaternion algebra with the
75
+ following action:
76
+
77
+ .. MATH::
78
+
79
+ T_n[I] = \sum_{\phi} [J]
80
+
81
+ where `(n,pM)=1` and the sum is over cyclic `\mathcal{O}`-module
82
+ homomorphisms `\phi\colon I\rightarrow J` of degree `n` up to
83
+ isomorphism of `J`. Equivalently one can sum over the inclusions of
84
+ the submodules `J \rightarrow n^{-1}I`. The rough idea is to start
85
+ with the trivial ideal class containing the order `\mathcal{O}`
86
+ itself. Using the method ``cyclic_submodules(self, I, q)`` one then
87
+ repeatedly computes `T_q([\mathcal{O}])` for some prime `q` not
88
+ dividing the level of `\mathcal{O}` and tests for equivalence among
89
+ the resulting ideals. A theorem of Serre asserts that one gets a
90
+ complete set of ideal class representatives after a finite number of
91
+ repetitions.
92
+
93
+ One can prove that two ideals `I` and `J` are equivalent if and only
94
+ if there exists an element `\alpha \in I \overline{J}` such
95
+ `N(\alpha)=N(I)N(J)`.
96
+
97
+ ``is_right_equivalent(I,J)`` returns true if `I` and `J` are equivalent. This
98
+ method first compares the theta series of `I` and `J`. If they are the
99
+ same, it computes the theta series of the lattice `I\overline(J)`. It
100
+ returns true if the `n`-th coefficient of this series is nonzero
101
+ where `n=N(J)N(I)`.
102
+
103
+ The theta series of a lattice `L` over the quaternion algebra `A` is
104
+ defined as
105
+
106
+ .. MATH::
107
+
108
+ \theta_L(q)=\sum_{x \in L} q^{\frac{N(x)}{N(L)}}
109
+
110
+ ``L.theta_series(T,q)`` returns a power series representing `\theta_L(q)`
111
+ up to a precision of `\mathcal{O}(q^{T+1})`.
112
+
113
+
114
+ Hecke Structure
115
+ ---------------
116
+
117
+ The Hecke structure defined on the Brandt module is given by the
118
+ Brandt matrices which can be computed using the definition of the
119
+ Hecke operators given earlier.
120
+
121
+ ``hecke_matrix_from_defn(self,n)`` returns the matrix of the `n`-th Hecke
122
+ operator `B_{0}(n)` acting on self, computed directly from the
123
+ definition.
124
+
125
+ However, one can efficiently compute Brandt matrices using theta
126
+ series. In fact, let `\{I_{1},.....,I_{h}\}` be a set of right
127
+ `\mathcal{O}`-ideal class representatives. The (i,j) entry in the
128
+ Brandt matrix `B_{0}(n)` is the product of the `n`-th coefficient in
129
+ the theta series of the lattice `I_{i}\overline{I_{j}}` and the first
130
+ coefficient in the theta series of the lattice
131
+ `I_{i}\overline{I_{i}}`.
132
+
133
+ ``compute_hecke_matrix_brandt(self,n)`` returns the `n`-th Hecke matrix,
134
+ computed using theta series.
135
+
136
+ EXAMPLES::
137
+
138
+ sage: B = BrandtModule(23)
139
+
140
+ sage: B.maximal_order()
141
+ Order of Quaternion Algebra (-1, -23) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k)
142
+
143
+ sage: B.right_ideals()
144
+ (Fractional ideal (4, 4*i, 2 + 2*j, 2*i + 2*k),
145
+ Fractional ideal (8, 8*i, 2 + 2*j, 6*i + 2*k),
146
+ Fractional ideal (16, 16*i, 10 + 8*i + 2*j, 8 + 6*i + 2*k))
147
+
148
+ sage: B.hecke_matrix(2)
149
+ [1 2 0]
150
+ [1 1 1]
151
+ [0 3 0]
152
+
153
+ sage: B.brandt_series(3)
154
+ [1/4 + q + q^2 + O(q^3) 1/4 + q^2 + O(q^3) 1/4 + O(q^3)]
155
+ [ 1/2 + 2*q^2 + O(q^3) 1/2 + q + q^2 + O(q^3) 1/2 + 3*q^2 + O(q^3)]
156
+ [ 1/6 + O(q^3) 1/6 + q^2 + O(q^3) 1/6 + q + O(q^3)]
157
+
158
+
159
+ REFERENCES:
160
+
161
+ - [Piz1980]_
162
+ - [Koh2000]_
163
+
164
+ Further Examples
165
+ ----------------
166
+
167
+ We decompose a Brandt module over both `\ZZ` and `\QQ`. ::
168
+
169
+ sage: B = BrandtModule(43, base_ring=ZZ); B
170
+ Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring
171
+ sage: D = B.decomposition()
172
+ sage: D
173
+ [Subspace of dimension 1 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring,
174
+ Subspace of dimension 1 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring,
175
+ Subspace of dimension 2 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring]
176
+ sage: D[0].basis()
177
+ ((0, 0, 1, -1),)
178
+ sage: D[1].basis()
179
+ ((1, 2, 2, 2),)
180
+ sage: D[2].basis()
181
+ ((1, 1, -1, -1), (0, 2, -1, -1))
182
+ sage: B = BrandtModule(43, base_ring=QQ); B
183
+ Brandt module of dimension 4 of level 43 of weight 2 over Rational Field
184
+ sage: B.decomposition()[2].basis()
185
+ ((1, 0, -1/2, -1/2), (0, 1, -1/2, -1/2))
186
+
187
+ AUTHORS:
188
+
189
+ - Jon Bober
190
+ - Alia Hamieh
191
+ - Victoria de Quehen
192
+ - William Stein
193
+ - Gonzalo Tornaria
194
+ """
195
+
196
+ # ****************************************************************************
197
+ # Copyright (C) 2009 William Stein <wstein@gmail.com>
198
+ #
199
+ # This program is free software: you can redistribute it and/or modify
200
+ # it under the terms of the GNU General Public License as published by
201
+ # the Free Software Foundation, either version 2 of the License, or
202
+ # (at your option) any later version.
203
+ # https://www.gnu.org/licenses/
204
+ # ****************************************************************************
205
+
206
+ from sage.arith.misc import gcd, prime_divisors, kronecker, next_prime
207
+ from sage.categories.commutative_rings import CommutativeRings
208
+ from sage.matrix.constructor import matrix
209
+ from sage.matrix.matrix_space import MatrixSpace
210
+ from sage.misc.cachefunc import cached_method
211
+ from sage.misc.lazy_import import lazy_import
212
+ from sage.misc.misc_c import prod
213
+ from sage.misc.verbose import verbose
214
+ from sage.modular.dirichlet import TrivialCharacter
215
+ from sage.modular.hecke.ambient_module import AmbientHeckeModule
216
+ from sage.modular.hecke.element import HeckeModuleElement
217
+ from sage.modular.hecke.submodule import HeckeSubmodule
218
+ from sage.rings.finite_rings.finite_field_constructor import GF
219
+ from sage.rings.integer import Integer
220
+ from sage.rings.integer_ring import ZZ
221
+ from sage.rings.power_series_ring import PowerSeriesRing
222
+ from sage.rings.rational_field import QQ
223
+ from sage.structure.richcmp import richcmp, richcmp_method
224
+
225
+ lazy_import('sage.algebras.quatalg.quaternion_algebra', ['QuaternionAlgebra', 'basis_for_quaternion_lattice'])
226
+ lazy_import('sage.algebras.quatalg.quaternion_algebra_cython', 'rational_matrix_from_rational_quaternions')
227
+
228
+
229
+ cache = {}
230
+
231
+
232
+ def BrandtModule(N, M=1, weight=2, base_ring=QQ, use_cache=True):
233
+ """
234
+ Return the Brandt module of given weight associated to the prime
235
+ power `p^r` and integer `M`, where `p` and `M` are coprime.
236
+
237
+ INPUT:
238
+
239
+ - ``N`` -- a product of primes with odd exponents
240
+ - ``M`` -- integer coprime to `q` (default: 1)
241
+ - ``weight`` -- integer that is at least 2 (default: 2)
242
+ - ``base_ring`` -- the base ring (default: ``QQ``)
243
+ - ``use_cache`` -- whether to use the cache (default: ``True``)
244
+
245
+ OUTPUT: a Brandt module
246
+
247
+ EXAMPLES::
248
+
249
+ sage: BrandtModule(17)
250
+ Brandt module of dimension 2 of level 17 of weight 2 over Rational Field
251
+ sage: BrandtModule(17,15)
252
+ Brandt module of dimension 32 of level 17*15 of weight 2 over Rational Field
253
+ sage: BrandtModule(3,7)
254
+ Brandt module of dimension 2 of level 3*7 of weight 2 over Rational Field
255
+ sage: BrandtModule(3,weight=2)
256
+ Brandt module of dimension 1 of level 3 of weight 2 over Rational Field
257
+ sage: BrandtModule(11, base_ring=ZZ)
258
+ Brandt module of dimension 2 of level 11 of weight 2 over Integer Ring
259
+ sage: BrandtModule(11, base_ring=QQbar)
260
+ Brandt module of dimension 2 of level 11 of weight 2 over Algebraic Field
261
+
262
+ The ``use_cache`` option determines whether the Brandt module returned
263
+ by this function is cached::
264
+
265
+ sage: BrandtModule(37) is BrandtModule(37)
266
+ True
267
+ sage: BrandtModule(37,use_cache=False) is BrandtModule(37,use_cache=False)
268
+ False
269
+
270
+ TESTS:
271
+
272
+ Note that `N` and `M` must be coprime::
273
+
274
+ sage: BrandtModule(3,15)
275
+ Traceback (most recent call last):
276
+ ...
277
+ ValueError: M must be coprime to N
278
+
279
+ Only weight 2 is currently implemented::
280
+
281
+ sage: BrandtModule(3,weight=4)
282
+ Traceback (most recent call last):
283
+ ...
284
+ NotImplementedError: weight != 2 not yet implemented
285
+
286
+ Brandt modules are cached::
287
+
288
+ sage: B = BrandtModule(3,5,2,ZZ)
289
+ sage: B is BrandtModule(3,5,2,ZZ)
290
+ True
291
+ """
292
+ N, M, weight = Integer(N), Integer(M), Integer(weight)
293
+ if not N.is_prime():
294
+ raise NotImplementedError("Brandt modules currently only implemented when N is a prime")
295
+ if M < 1:
296
+ raise ValueError("M must be positive")
297
+ if M.gcd(N) != 1:
298
+ raise ValueError("M must be coprime to N")
299
+ if weight < 2:
300
+ raise ValueError("weight must be at least 2")
301
+ if base_ring not in CommutativeRings():
302
+ raise TypeError("base_ring must be a commutative ring")
303
+ key = (N, M, weight, base_ring)
304
+ if use_cache:
305
+ if key in cache: # TODO: re-enable caching!
306
+ return cache[key]
307
+ if weight != 2:
308
+ raise NotImplementedError("weight != 2 not yet implemented")
309
+ B = BrandtModule_class(*key)
310
+ if use_cache:
311
+ cache[key] = B
312
+ return B
313
+
314
+
315
+ def class_number(p, r, M):
316
+ r"""
317
+ Return the class number of an order of level `N = p^r M` in the
318
+ quaternion algebra over `\QQ` ramified precisely at `p` and infinity.
319
+
320
+ This is an implementation of Theorem 1.12 of [Piz1980]_.
321
+
322
+ INPUT:
323
+
324
+ - ``p`` -- a prime
325
+ - ``r`` -- an odd positive integer (default: 1)
326
+ - ``M`` -- integer coprime to `q` (default: 1)
327
+
328
+ OUTPUT: integer
329
+
330
+ EXAMPLES::
331
+
332
+ sage: sage.modular.quatalg.brandt.class_number(389,1,1)
333
+ 33
334
+ sage: sage.modular.quatalg.brandt.class_number(389,1,2) # TODO -- right?
335
+ 97
336
+ sage: sage.modular.quatalg.brandt.class_number(389,3,1) # TODO -- right?
337
+ 4892713
338
+ """
339
+ N = M * p**r
340
+ D = prime_divisors(M)
341
+ s = 0
342
+ t = 0
343
+ if N % 4:
344
+ s = (1 - kronecker(-4, p)) / 4 * prod(1 + kronecker(-4, q) for q in D)
345
+ if N % 9:
346
+ t = (1 - kronecker(-3, p)) / 3 * prod(1 + kronecker(-3, q) for q in D)
347
+ h = (N / Integer(12)) * (1 - 1 / p) * prod(1 + 1 / q for q in D) + s + t
348
+ return Integer(h)
349
+
350
+
351
+ def maximal_order(A):
352
+ """
353
+ Return a maximal order in the quaternion algebra ramified
354
+ at `p` and infinity.
355
+
356
+ This is an implementation of Proposition 5.2 of [Piz1980]_.
357
+
358
+ INPUT:
359
+
360
+ - ``A`` -- quaternion algebra ramified precisely at `p` and infinity
361
+
362
+ OUTPUT: a maximal order in `A`
363
+
364
+ EXAMPLES::
365
+
366
+ sage: A = BrandtModule(17).quaternion_algebra()
367
+
368
+ sage: sage.modular.quatalg.brandt.maximal_order(A)
369
+ doctest:...: DeprecationWarning: The function maximal_order() is deprecated, use the maximal_order() method of quaternion algebras
370
+ See https://github.com/sagemath/sage/issues/37090 for details.
371
+ Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/2*i, 1/2*j - 1/2*k, -1/3*i + 1/3*k, -k)
372
+
373
+ sage: A = QuaternionAlgebra(17,names='i,j,k')
374
+ sage: A.maximal_order()
375
+ Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/2*i, 1/2*j - 1/2*k, -1/3*i + 1/3*k, -k)
376
+ """
377
+ from sage.misc.superseded import deprecation
378
+ deprecation(37090, "The function maximal_order() is deprecated, use the maximal_order() method of quaternion algebras")
379
+ return A.maximal_order()
380
+
381
+
382
+ def basis_for_left_ideal(R, gens):
383
+ """
384
+ Return a basis for the left ideal of `R` with given generators.
385
+
386
+ INPUT:
387
+
388
+ - ``R`` -- quaternion order
389
+ - ``gens`` -- list of elements of `R`
390
+
391
+ OUTPUT: list of four elements of `R`
392
+
393
+ EXAMPLES::
394
+
395
+ sage: B = BrandtModule(17); A = B.quaternion_algebra(); i,j,k = A.gens()
396
+ sage: sage.modular.quatalg.brandt.basis_for_left_ideal(B.maximal_order(), [i+j,i-j,2*k,A(3)])
397
+ doctest:...: DeprecationWarning: The function basis_for_left_ideal() is deprecated, use the _left_ideal_basis() method of quaternion algebras
398
+ See https://github.com/sagemath/sage/issues/37090 for details.
399
+ [1, 1/2 + 1/2*i, j, 1/3*i + 1/2*j + 1/6*k]
400
+ sage: sage.modular.quatalg.brandt.basis_for_left_ideal(B.maximal_order(), [3*(i+j),3*(i-j),6*k,A(3)])
401
+ [3, 3/2 + 3/2*i, 3*j, i + 3/2*j + 1/2*k]
402
+ """
403
+ from sage.misc.superseded import deprecation
404
+ deprecation(37090, "The function basis_for_left_ideal() is deprecated, use the _left_ideal_basis() method of quaternion algebras")
405
+ return R._left_ideal_basis(gens)
406
+
407
+
408
+ def right_order(R, basis):
409
+ """
410
+ Given a basis for a left ideal `I`, return the right order in the
411
+ quaternion order `R` of elements `x` such that `I x` is contained in `I`.
412
+
413
+ INPUT:
414
+
415
+ - ``R`` -- order in quaternion algebra
416
+ - ``basis`` -- basis for an ideal `I`
417
+
418
+ OUTPUT: order in quaternion algebra
419
+
420
+ EXAMPLES:
421
+
422
+ We do a consistency check with the ideal equal to a maximal order::
423
+
424
+ sage: B = BrandtModule(17); basis = B.maximal_order()._left_ideal_basis([1])
425
+ sage: sage.modular.quatalg.brandt.right_order(B.maximal_order(), basis)
426
+ doctest:...: DeprecationWarning: The function right_order() is deprecated, use the _right_order_from_ideal_basis() method of quaternion algebras
427
+ See https://github.com/sagemath/sage/issues/37090 for details.
428
+ Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k)
429
+ sage: basis
430
+ [1, 1/2 + 1/2*i, j, 1/3*i + 1/2*j + 1/6*k]
431
+
432
+ sage: B = BrandtModule(17); A = B.quaternion_algebra(); i,j,k = A.gens()
433
+ sage: basis = B.maximal_order()._left_ideal_basis([i*j - j])
434
+ sage: sage.modular.quatalg.brandt.right_order(B.maximal_order(), basis)
435
+ Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k)
436
+ """
437
+ from sage.misc.superseded import deprecation
438
+ deprecation(37090, "The function right_order() is deprecated, use the _right_order_from_ideal_basis() method of quaternion algebras")
439
+ return R._right_order_from_ideal_basis(basis)
440
+
441
+
442
+ def quaternion_order_with_given_level(A, level):
443
+ """
444
+ Return an order in the quaternion algebra A with given level.
445
+
446
+ This is implemented only when the base field is the rational numbers.
447
+
448
+ INPUT:
449
+
450
+ - ``level`` -- the level of the order to be returned. Currently this
451
+ is only implemented when the level is divisible by at
452
+ most one power of a prime that ramifies in this quaternion algebra.
453
+
454
+ EXAMPLES::
455
+
456
+ sage: from sage.modular.quatalg.brandt import quaternion_order_with_given_level, maximal_order
457
+ sage: A.<i,j,k> = QuaternionAlgebra(5)
458
+ sage: level = 2 * 5 * 17
459
+ sage: O = quaternion_order_with_given_level(A, level)
460
+ doctest:...: DeprecationWarning: The function quaternion_order_with_given_level() is deprecated, use the order_with_level() method of quaternion algebras
461
+ See https://github.com/sagemath/sage/issues/37090 for details.
462
+ sage: M = A.maximal_order()
463
+ sage: L = O.free_module()
464
+ sage: N = M.free_module()
465
+ sage: L.index_in(N) == level/5 #check that the order has the right index in the maximal order
466
+ True
467
+ """
468
+ from sage.misc.superseded import deprecation
469
+ deprecation(37090, "The function quaternion_order_with_given_level() is deprecated, use the order_with_level() method of quaternion algebras")
470
+ return A.order_with_level(level)
471
+
472
+
473
+ class BrandtSubmodule(HeckeSubmodule):
474
+ def _repr_(self):
475
+ """
476
+ Return string representation of this Brandt submodule.
477
+
478
+ EXAMPLES::
479
+
480
+ sage: BrandtModule(11)[0]._repr_()
481
+ 'Subspace of dimension 1 of Brandt module of dimension 2 of level 11 of weight 2 over Rational Field'
482
+ """
483
+ return "Subspace of dimension %s of %s" % (self.dimension(), self.ambient_module())
484
+
485
+
486
+ class BrandtModuleElement(HeckeModuleElement):
487
+ def __init__(self, parent, x):
488
+ """
489
+ EXAMPLES::
490
+
491
+ sage: B = BrandtModule(37)
492
+ sage: x = B([1,2,3]); x
493
+ (1, 2, 3)
494
+ sage: parent(x)
495
+ Brandt module of dimension 3 of level 37 of weight 2 over Rational Field
496
+ """
497
+ if isinstance(x, HeckeModuleElement):
498
+ x = x.element()
499
+ HeckeModuleElement.__init__(self, parent, parent.free_module()(x))
500
+
501
+ def _richcmp_(self, other, op):
502
+ """
503
+ EXAMPLES::
504
+
505
+ sage: B = BrandtModule(13,5)
506
+ sage: B.0
507
+ (1, 0, 0, 0, 0, 0)
508
+ sage: B.0 == B.1
509
+ False
510
+ sage: B.0 == 0
511
+ False
512
+ sage: B(0) == 0
513
+ True
514
+ sage: B.0 + 2*B.1 == 2*B.1 + B.0
515
+ True
516
+ sage: loads(dumps(B.0)) == B.0
517
+ True
518
+ """
519
+ return richcmp(self.element(), other.element(), op)
520
+
521
+ def monodromy_pairing(self, x):
522
+ """
523
+ Return the monodromy pairing of ``self`` and ``x``.
524
+
525
+ EXAMPLES::
526
+
527
+ sage: B = BrandtModule(5,13)
528
+ sage: B.monodromy_weights()
529
+ (1, 3, 1, 1, 1, 3)
530
+ sage: (B.0 + B.1).monodromy_pairing(B.0 + B.1)
531
+ 4
532
+
533
+ TESTS:
534
+
535
+ One check for :issue:`12866`::
536
+
537
+ sage: Br = BrandtModule(2,7)
538
+ sage: g1, g2 = Br.basis()
539
+ sage: g = g1 - g2
540
+ sage: g.monodromy_pairing(g)
541
+ 6
542
+ """
543
+ B = self.parent()
544
+ w = B.monodromy_weights()
545
+ x = B(x).element()
546
+ v = self.element()
547
+ return sum(x[i] * v[i] * w[i] for i in range(len(v)))
548
+
549
+ def __mul__(self, right):
550
+ """
551
+ Return the monodromy pairing of ``self`` and ``right``.
552
+
553
+ EXAMPLES::
554
+
555
+ sage: B = BrandtModule(7,10)
556
+ sage: B.monodromy_weights()
557
+ (1, 1, 1, 2, 1, 1, 2, 1, 1, 1)
558
+ sage: B.0 * B.0
559
+ 1
560
+ sage: B.3 * B.3
561
+ 2
562
+ sage: (B.0+B.3) * (B.0 + B.1 + 2*B.3)
563
+ 5
564
+ """
565
+ return self.monodromy_pairing(right)
566
+
567
+ def _add_(self, right):
568
+ """
569
+ Return the sum of ``self`` and ``right``.
570
+
571
+ EXAMPLES::
572
+
573
+ sage: B = BrandtModule(11)
574
+ sage: B.0 + B.1 # indirect doctest
575
+ (1, 1)
576
+ """
577
+ return BrandtModuleElement(self.parent(), self.element() + right.element())
578
+
579
+ def _sub_(self, right):
580
+ """
581
+ Return the difference of ``self`` and ``right``.
582
+
583
+ EXAMPLES::
584
+
585
+ sage: B = BrandtModule(11)
586
+ sage: B.0 - B.1 # indirect doctest
587
+ (1, -1)
588
+ """
589
+ return BrandtModuleElement(self.parent(), self.element() - right.element())
590
+
591
+ def _neg_(self):
592
+ """
593
+ Return the opposite of ``self``.
594
+
595
+ EXAMPLES::
596
+
597
+ sage: B = BrandtModule(11)
598
+ sage: -B.0 # indirect doctest
599
+ (-1, 0)
600
+ """
601
+ return BrandtModuleElement(self.parent(), -self.element())
602
+
603
+
604
+ @richcmp_method
605
+ class BrandtModule_class(AmbientHeckeModule):
606
+ """
607
+ A Brandt module.
608
+
609
+ EXAMPLES::
610
+
611
+ sage: BrandtModule(3, 10)
612
+ Brandt module of dimension 4 of level 3*10 of weight 2 over Rational Field
613
+ """
614
+ def __init__(self, N, M, weight, base_ring):
615
+ """
616
+ INPUT:
617
+
618
+ - ``N`` -- ramification number (coprime to M)
619
+ - ``M`` -- auxiliary level
620
+ - ``weight`` -- integer 2
621
+ - ``base_ring`` -- the base ring
622
+
623
+ EXAMPLES::
624
+
625
+ sage: BrandtModule(3, 5, weight=2, base_ring=ZZ)
626
+ Brandt module of dimension 2 of level 3*5 of weight 2 over Integer Ring
627
+ """
628
+ assert weight == 2
629
+ self.__N = N
630
+ self.__M = M
631
+ if not N.is_prime():
632
+ raise NotImplementedError("right now N must be prime")
633
+ rank = class_number(N, 1, M)
634
+ self.__key = (N, M, weight, base_ring)
635
+ AmbientHeckeModule.__init__(self, base_ring, rank, N * M, weight=2)
636
+ self._populate_coercion_lists_(coerce_list=[self.free_module()])
637
+
638
+ Element = BrandtModuleElement
639
+
640
+ def _submodule_class(self):
641
+ """
642
+ Return the Python class of submodules of this ambient Brandt module.
643
+
644
+ EXAMPLES::
645
+
646
+ sage: BrandtModule(37)._submodule_class()
647
+ <class 'sage.modular.quatalg.brandt.BrandtSubmodule'>
648
+ """
649
+ return BrandtSubmodule
650
+
651
+ @cached_method
652
+ def free_module(self):
653
+ """
654
+ Return the underlying free module of the Brandt module.
655
+
656
+ EXAMPLES::
657
+
658
+ sage: B = BrandtModule(10007,389)
659
+ sage: B.free_module()
660
+ Vector space of dimension 325196 over Rational Field
661
+ """
662
+ return self.base_ring() ** self.dimension()
663
+
664
+ def N(self):
665
+ """
666
+ Return ramification level `N`.
667
+
668
+ EXAMPLES::
669
+
670
+ sage: BrandtModule(7,5,2,ZZ).N()
671
+ 7
672
+ """
673
+ return self.__N
674
+
675
+ def M(self):
676
+ """
677
+ Return the auxiliary level (prime to `p` part) of the quaternion
678
+ order used to compute this Brandt module.
679
+
680
+ EXAMPLES::
681
+
682
+ sage: BrandtModule(7,5,2,ZZ).M()
683
+ 5
684
+ """
685
+ return self.__M
686
+
687
+ def character(self):
688
+ r"""
689
+ The character of this space.
690
+
691
+ Always trivial.
692
+
693
+ EXAMPLES::
694
+
695
+ sage: BrandtModule(11,5).character()
696
+ Dirichlet character modulo 55 of conductor 1 mapping 12 |--> 1, 46 |--> 1
697
+ """
698
+ return TrivialCharacter(self.__N * self.__M)
699
+
700
+ def _repr_(self):
701
+ """
702
+ Return string representation of this Brandt module.
703
+
704
+ EXAMPLES::
705
+
706
+ sage: BrandtModule(7,5,2,ZZ)._repr_()
707
+ 'Brandt module of dimension 4 of level 7*5 of weight 2 over Integer Ring'
708
+ """
709
+ aux = '' if self.__M == 1 else '*%s' % self.__M
710
+ txt = "Brandt module of dimension %s of level %s%s of weight %s over %s"
711
+ return txt % (self.rank(), self.__N, aux, self.weight(), self.base_ring())
712
+
713
+ def __richcmp__(self, other, op):
714
+ r"""
715
+ Compare ``self`` to ``other``.
716
+
717
+ EXAMPLES::
718
+
719
+ sage: BrandtModule(37, 5, 2, ZZ) == BrandtModule(37, 5, 2, QQ)
720
+ False
721
+ sage: BrandtModule(37, 5, 2, ZZ) == BrandtModule(37, 5, 2, ZZ)
722
+ True
723
+ sage: BrandtModule(37, 5, 2, ZZ) == loads(dumps(BrandtModule(37, 5, 2, ZZ)))
724
+ True
725
+ """
726
+ if not isinstance(other, BrandtModule_class):
727
+ return NotImplemented
728
+
729
+ return richcmp((self.__M, self.__N, self.weight(), self.base_ring()),
730
+ (other.__M, other.__N, other.weight(), other.base_ring()),
731
+ op)
732
+
733
+ @cached_method
734
+ def quaternion_algebra(self):
735
+ r"""
736
+ Return the quaternion algebra `A` over `\QQ` ramified precisely at
737
+ `p` and infinity used to compute this Brandt module.
738
+
739
+ EXAMPLES::
740
+
741
+ sage: BrandtModule(997).quaternion_algebra()
742
+ Quaternion Algebra (-2, -997) with base ring Rational Field
743
+ sage: BrandtModule(2).quaternion_algebra()
744
+ Quaternion Algebra (-1, -1) with base ring Rational Field
745
+ sage: BrandtModule(3).quaternion_algebra()
746
+ Quaternion Algebra (-1, -3) with base ring Rational Field
747
+ sage: BrandtModule(5).quaternion_algebra()
748
+ Quaternion Algebra (-2, -5) with base ring Rational Field
749
+ sage: BrandtModule(17).quaternion_algebra()
750
+ Quaternion Algebra (-3, -17) with base ring Rational Field
751
+ """
752
+ return QuaternionAlgebra(self.N())
753
+
754
+ def maximal_order(self):
755
+ """
756
+ Return a maximal order in the quaternion algebra associated to this Brandt module.
757
+
758
+ EXAMPLES::
759
+
760
+ sage: BrandtModule(17).maximal_order()
761
+ Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/2*i, 1/2*j - 1/2*k, -1/3*i + 1/3*k, -k)
762
+ sage: BrandtModule(17).maximal_order() is BrandtModule(17).maximal_order()
763
+ True
764
+ """
765
+ return self.quaternion_algebra().maximal_order()
766
+
767
+ @cached_method
768
+ def order_of_level_N(self):
769
+ """
770
+ Return an order of level `N = p^{2 r + 1} M` in the
771
+ quaternion algebra.
772
+
773
+ EXAMPLES::
774
+
775
+ sage: BrandtModule(7).order_of_level_N()
776
+ Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k)
777
+ sage: BrandtModule(7,13).order_of_level_N()
778
+ Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j + 12*k, 1/2*i + 9/2*k, j + 11*k, 13*k)
779
+ sage: BrandtModule(7,3*17).order_of_level_N()
780
+ Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j + 35*k, 1/2*i + 65/2*k, j + 19*k, 51*k)
781
+ """
782
+ return self.quaternion_algebra().order_with_level(self.level())
783
+
784
+ def cyclic_submodules(self, I, p):
785
+ """
786
+ Return a list of rescaled versions of the fractional right
787
+ ideals `J` such that `J` contains `I` and the quotient has
788
+ group structure the product of two cyclic groups of order `p`.
789
+
790
+ We emphasize again that `J` is rescaled to be integral.
791
+
792
+ INPUT:
793
+
794
+ - ``I`` -- ideal `I` in ``R = self.order_of_level_N()``
795
+ - ``p`` -- prime `p` coprime to ``self.level()``
796
+
797
+ OUTPUT:
798
+
799
+ list of the `p+1` fractional right R-ideals that contain I
800
+ such that J/I is GF(p) x GF(p).
801
+
802
+ EXAMPLES::
803
+
804
+ sage: B = BrandtModule(11)
805
+ sage: I = B.order_of_level_N().unit_ideal()
806
+ sage: B.cyclic_submodules(I, 2)
807
+ [Fractional ideal (2, 2*i, 3/2 + i + 1/2*j, 1 + 1/2*i + 1/2*k),
808
+ Fractional ideal (2, 1 + i, 1 + j, 1/2 + 1/2*i + 1/2*j + 1/2*k),
809
+ Fractional ideal (2, 2*i, 1/2 + i + 1/2*j, 1 + 3/2*i + 1/2*k)]
810
+ sage: B.cyclic_submodules(I, 3)
811
+ [Fractional ideal (3, 3*i, 1/2 + 1/2*j, 5/2*i + 1/2*k),
812
+ Fractional ideal (3, 3*i, 3/2 + 2*i + 1/2*j, 2 + 3/2*i + 1/2*k),
813
+ Fractional ideal (3, 3*i, 3/2 + i + 1/2*j, 1 + 3/2*i + 1/2*k),
814
+ Fractional ideal (3, 3*i, 5/2 + 1/2*j, 1/2*i + 1/2*k)]
815
+ sage: B.cyclic_submodules(I, 11)
816
+ Traceback (most recent call last):
817
+ ...
818
+ ValueError: p must be coprime to the level
819
+ """
820
+ if not Integer(p).is_prime():
821
+ raise ValueError("p must be a prime")
822
+ if not self.level() % p:
823
+ raise ValueError("p must be coprime to the level")
824
+
825
+ R = self.order_of_level_N()
826
+ A = R.quaternion_algebra()
827
+ B = R.basis()
828
+ V = GF(p)**4
829
+
830
+ # step 1: Compute alpha, beta, and the matrix of their action on I/pI.
831
+ # NOTE: Move this code to orders once we have it all working...
832
+ try:
833
+ alpha, beta = self.__cyclic_submodules[p]
834
+ compute = False
835
+ except AttributeError:
836
+ self.__cyclic_submodules = {}
837
+ compute = True
838
+ except KeyError:
839
+ compute = True
840
+
841
+ if compute:
842
+ d = R.free_module().basis_matrix().determinant()
843
+ S = None
844
+ for v in V:
845
+ if not v:
846
+ continue
847
+ alpha = sum(Integer(v[i]) * B[i] for i in range(4))
848
+ # If the quadratic polynomial over GF(p) given by
849
+ # X^2 - alpha.reduced_trace() * X + alpha.reduced_norm()
850
+ # is not irreducible, we try again with a new element.
851
+ if p == 2:
852
+ # special case p == 2, since there is a unique quadratic irreducible poly.
853
+ if alpha.reduced_trace() % 2 == 0 or alpha.reduced_norm() % 2 == 0:
854
+ continue
855
+ else:
856
+ # check if the discriminant is a square -- if so, poly is reducible
857
+ b = alpha.reduced_trace()
858
+ c = alpha.reduced_norm()
859
+ if kronecker(b * b - 4 * c, p) != -1:
860
+ continue
861
+ for w in V:
862
+ if not w:
863
+ continue
864
+ beta = sum(Integer(w[i]) * B[i] for i in range(4))
865
+ v = [A(1), alpha, beta, alpha * beta]
866
+ M = rational_matrix_from_rational_quaternions(v)
867
+ e = M.determinant()
868
+ if e and not (d / e).valuation(p):
869
+ S = A.quaternion_order(v)
870
+ break
871
+ if S is not None:
872
+ break
873
+ self.__cyclic_submodules[p] = (alpha, beta)
874
+
875
+ # right multiplication by X changes something to be written
876
+ # in terms of the basis for I.
877
+ basis = basis_for_quaternion_lattice(I.basis(), reverse=False)
878
+ Y = matrix(map(list, basis))
879
+ X = ~Y
880
+
881
+ # Compute the matrix of right multiplication by alpha acting on
882
+ # our fixed choice of basis for this ideal.
883
+
884
+ M_alpha = (matrix([(i * alpha).coefficient_tuple()
885
+ for i in basis]) * X).change_ring(GF(p))
886
+ M_beta = (matrix([(i * beta).coefficient_tuple()
887
+ for i in basis]) * X).change_ring(GF(p))
888
+
889
+ # step 2: Find j such that if f=I[j], then mod 2 we have span(I[0],alpha*I[i])
890
+ # has trivial intersection with span(I[j],alpha*I[j]).
891
+ #
892
+ # In terms of our matrices alpha, beta, we can now think of I/p*I
893
+ # as being the GF(p)^4 that M_alpha and M_beta naturally act on,
894
+ # and I[0], I[1], I[2], I[3] correspond to the standard basis.
895
+ #
896
+ # We try each of the standard basis vectors.
897
+ W0 = V.span([V.gen(0), V.gen(0) * M_alpha])
898
+ assert W0.dimension() == 2
899
+ j = None
900
+ for i in range(1, 4):
901
+ Wi = V.span([V.gen(i), V.gen(i) * M_alpha])
902
+ if Wi.dimension() == 2 and W0.intersection(Wi).dimension() == 0:
903
+ j = i
904
+ break
905
+ assert j is not None, "bug -- couldn't find basis"
906
+
907
+ # step 3: Enumerate the elements of P^1(GF(p^2)), recording each
908
+ # cyclic submodule of degree p.
909
+ answer = []
910
+ f = V.gen(0)
911
+ g = V.gen(j)
912
+ M2_4 = MatrixSpace(GF(p), 4)
913
+ M2_2 = MatrixSpace(QQ, 2, 4)
914
+ Yp = p * Y
915
+ from sage.algebras.quatalg.quaternion_algebra_cython import \
916
+ rational_quaternions_from_integral_matrix_and_denom
917
+ for v in [f + g * (a + b * M_alpha)
918
+ for a in GF(p) for b in GF(p)] + [g]:
919
+ v0 = v
920
+ v1 = v * M_alpha
921
+ v2 = v * M_beta
922
+ v3 = v1 * M_beta
923
+ W = M2_4([v0, v1, v2, v3], coerce=False)
924
+ if W.rank() == 2:
925
+ gen_mat = Yp.stack(M2_2([v0.lift() * Y, v1.lift() * Y],
926
+ coerce=False))
927
+ gen_mat, d = gen_mat._clear_denom()
928
+ H = gen_mat._hnf_pari(0, include_zero_rows=False)
929
+ gens = tuple(rational_quaternions_from_integral_matrix_and_denom(A, H, d))
930
+ answer.append(R.right_ideal(gens, check=False))
931
+ if len(answer) == p + 1:
932
+ break
933
+ return answer
934
+
935
+ def hecke_matrix(self, n, algorithm='default', sparse=False, B=None):
936
+ """
937
+ Return the matrix of the `n`-th Hecke operator.
938
+
939
+ INPUT:
940
+
941
+ - ``n`` -- integer
942
+
943
+ - ``algorithm`` -- string (default: ``'default'``)
944
+
945
+ - ``'default'`` -- let Sage guess which algorithm is best
946
+
947
+ - ``'direct'`` -- use cyclic subideals (generally much
948
+ better when you want few Hecke operators and the
949
+ dimension is very large); uses 'theta' if n divides
950
+ the level.
951
+
952
+ - ``'brandt'`` -- use Brandt matrices (generally much
953
+ better when you want many Hecke operators and the
954
+ dimension is very small; bad when the dimension
955
+ is large)
956
+
957
+ - ``sparse`` -- boolean (default: ``False``)
958
+
959
+ - ``B`` -- integer or ``None`` (default: ``None``); in direct
960
+ algorithm, use theta series to this precision as an initial
961
+ check for equality of ideal classes.
962
+
963
+ EXAMPLES::
964
+
965
+ sage: B = BrandtModule(3,7); B.hecke_matrix(2)
966
+ [0 3]
967
+ [1 2]
968
+ sage: B.hecke_matrix(5, algorithm='brandt')
969
+ [0 6]
970
+ [2 4]
971
+ sage: t = B.hecke_matrix(11, algorithm='brandt', sparse=True); t
972
+ [ 6 6]
973
+ [ 2 10]
974
+ sage: type(t)
975
+ <class 'sage.matrix.matrix_rational_sparse.Matrix_rational_sparse'>
976
+ sage: B.hecke_matrix(19, algorithm='direct', B=2)
977
+ [ 8 12]
978
+ [ 4 16]
979
+ """
980
+ n = ZZ(n)
981
+ if n <= 0:
982
+ raise IndexError("n must be positive")
983
+ if n not in self._hecke_matrices:
984
+ if algorithm == 'default':
985
+ try:
986
+ pr = len(self.__brandt_series_vectors[0][0])
987
+ except (AttributeError, IndexError):
988
+ pr = 0
989
+ if n <= pr:
990
+ # already trivially know the Hecke operator in this case
991
+ algorithm = 'brandt'
992
+ if algorithm == 'default': # still don't know
993
+ algorithm = 'direct'
994
+
995
+ if self.level().gcd(n) != 1:
996
+ algorithm = 'brandt'
997
+
998
+ if algorithm == 'direct':
999
+ T = self._compute_hecke_matrix(n, sparse=sparse, B=B)
1000
+ elif algorithm == 'brandt':
1001
+ T = self._compute_hecke_matrix_brandt(n, sparse=sparse)
1002
+ else:
1003
+ raise ValueError(f"unknown algorithm '{algorithm}'")
1004
+ T.set_immutable()
1005
+ self._hecke_matrices[n] = T
1006
+ return self._hecke_matrices[n]
1007
+
1008
+ def _compute_hecke_matrix_prime(self, p, sparse=False, B=None):
1009
+ """
1010
+ Return matrix of the `p`-th Hecke operator on ``self``. The matrix
1011
+ is always computed using the direct algorithm.
1012
+
1013
+ INPUT:
1014
+
1015
+ - ``p`` -- prime number
1016
+
1017
+ - ``B`` -- integer or ``None`` (default: ``None``); in direct algorithm,
1018
+ use theta series to this precision as an initial check for
1019
+ equality of ideal classes.
1020
+
1021
+ - ``sparse`` -- boolean (default: ``False``); whether matrix should be sparse
1022
+
1023
+ EXAMPLES::
1024
+
1025
+ sage: B = BrandtModule(37)
1026
+ sage: t = B._compute_hecke_matrix_prime(2); t
1027
+ [1 1 1]
1028
+ [1 0 2]
1029
+ [1 2 0]
1030
+ sage: type(t)
1031
+ <class 'sage.matrix.matrix_rational_dense.Matrix_rational_dense'>
1032
+ sage: type(B._compute_hecke_matrix_prime(2,sparse=True))
1033
+ <class 'sage.matrix.matrix_rational_sparse.Matrix_rational_sparse'>
1034
+ """
1035
+ return self._compute_hecke_matrix_directly(n=p, B=B, sparse=sparse)
1036
+
1037
+ def _compute_hecke_matrix_directly(self, n, B=None, sparse=False):
1038
+ """
1039
+ Given an integer `n` coprime to the level, return the matrix of
1040
+ the `n`-th Hecke operator on ``self``, computed on our fixed basis
1041
+ by directly using the definition of the Hecke action in terms
1042
+ of fractional ideals.
1043
+
1044
+ INPUT:
1045
+
1046
+ - ``n`` -- integer, coprime to level
1047
+
1048
+ - ``sparse`` -- boolean (default: ``False``); whether matrix should be sparse
1049
+
1050
+ EXAMPLES::
1051
+
1052
+ sage: B = BrandtModule(37)
1053
+ sage: t = B._compute_hecke_matrix_directly(2); t
1054
+ [1 1 1]
1055
+ [1 0 2]
1056
+ [1 2 0]
1057
+ sage: type(t)
1058
+ <class 'sage.matrix.matrix_rational_dense.Matrix_rational_dense'>
1059
+ sage: type(B._compute_hecke_matrix_directly(2,sparse=True))
1060
+ <class 'sage.matrix.matrix_rational_sparse.Matrix_rational_sparse'>
1061
+
1062
+ You can't compute the Hecke operator for n not coprime to the level using this function::
1063
+
1064
+ sage: B._compute_hecke_matrix_directly(37)
1065
+ Traceback (most recent call last):
1066
+ ...
1067
+ ValueError: n must be coprime to the level
1068
+
1069
+ The generic function (which uses theta series) does work, though::
1070
+
1071
+ sage: B.hecke_matrix(37)
1072
+ [1 0 0]
1073
+ [0 0 1]
1074
+ [0 1 0]
1075
+
1076
+ An example where the Hecke operator isn't symmetric::
1077
+
1078
+ sage: B = BrandtModule(43)
1079
+ sage: B._compute_hecke_matrix_directly(2)
1080
+ [1 2 0 0]
1081
+ [1 0 1 1]
1082
+ [0 1 0 2]
1083
+ [0 1 2 0]
1084
+ sage: B._compute_hecke_matrix_brandt(2)
1085
+ [1 2 0 0]
1086
+ [1 0 1 1]
1087
+ [0 1 0 2]
1088
+ [0 1 2 0]
1089
+ """
1090
+ level = self.level()
1091
+ if gcd(n, level) != 1:
1092
+ raise ValueError("n must be coprime to the level")
1093
+
1094
+ # For rigor it does not matter at all what bound we chose.
1095
+ # This B is used only for the first phase of checking equality
1096
+ # of ideals modulo equivalence -- we always provably check
1097
+ # equivalence if the theta series are the same up to this
1098
+ # bound.
1099
+ if B is None:
1100
+ B = self.dimension() // 2 + 5
1101
+
1102
+ T = matrix(self.base_ring(), self.dimension(), sparse=sparse)
1103
+ C = self.right_ideals()
1104
+ theta_dict = self._theta_dict(B)
1105
+ # I think the runtime of this algorithm is now dominated by
1106
+ # computing theta series of ideals. The computation of
1107
+ # cyclic submodules is a lower order term.
1108
+
1109
+ # TODO: temporary!! -- it's not sufficiently *optimized* to be
1110
+ # sure this is best in these cases.
1111
+ # d = lcm([a.denominator() for a in self.order_of_level_N().basis()])
1112
+ # q = self._smallest_good_prime()
1113
+ # if gcd(2*d*q,n) == 1:
1114
+ # use_fast_alg = True
1115
+ # else:
1116
+ # use_fast_alg = False
1117
+
1118
+ use_fast_alg = False
1119
+
1120
+ last_percent = 0
1121
+ for r in range(len(C)):
1122
+ percent_done = 100 * r // len(C)
1123
+ if percent_done != last_percent:
1124
+ if not percent_done % 5:
1125
+ verbose("percent done: %s" % percent_done)
1126
+ last_percent = percent_done
1127
+ if use_fast_alg:
1128
+ v = C[r].cyclic_right_subideals(n)
1129
+ else:
1130
+ v = self.cyclic_submodules(C[r], n)
1131
+ for J in v:
1132
+ J_theta = tuple(J.theta_series_vector(B))
1133
+ v = theta_dict[J_theta]
1134
+ if len(v) == 1:
1135
+ T[r, v[0]] += 1
1136
+ else:
1137
+ for i in v:
1138
+ if C[i].is_right_equivalent(J, 0):
1139
+ T[r, i] += 1
1140
+ break
1141
+ return T
1142
+
1143
+ @cached_method
1144
+ def _theta_dict(self, B):
1145
+ """
1146
+ Return a dictionary from theta series vectors of degree `B` to
1147
+ list of integers `i`, where the key is the vector of
1148
+ coefficients of the normalized theta series of the `i`-th right
1149
+ ideal, as indexed by ``self.right_ideals()``.
1150
+
1151
+ INPUT:
1152
+
1153
+ - ``B`` -- positive integer, precision of theta series vectors
1154
+
1155
+ OUTPUT: dictionary
1156
+
1157
+ EXAMPLES:
1158
+
1159
+ In this example the theta series determine the ideal classes::
1160
+
1161
+ sage: B = BrandtModule(5,11); B
1162
+ Brandt module of dimension 4 of level 5*11 of weight 2 over Rational Field
1163
+ sage: sorted(list(B._theta_dict(5).items()))
1164
+ [((1, 0, 0, 4, 0), [3]),
1165
+ ((1, 0, 0, 4, 2), [2]),
1166
+ ((1, 0, 2, 0, 6), [1]),
1167
+ ((1, 2, 4, 0, 6), [0])]
1168
+
1169
+ In this example, the theta series does not determine the ideal class::
1170
+
1171
+ sage: sorted(list(BrandtModule(37)._theta_dict(6).items()))
1172
+ [((1, 0, 2, 2, 6, 4), [1, 2]), ((1, 2, 2, 4, 2, 4), [0])]
1173
+ """
1174
+ C = self.right_ideals()
1175
+ theta_dict = {}
1176
+ for i in range(len(C)):
1177
+ I_theta = tuple(C[i].theta_series_vector(B))
1178
+ if I_theta in theta_dict:
1179
+ theta_dict[I_theta].append(i)
1180
+ else:
1181
+ theta_dict[I_theta] = [i]
1182
+ return theta_dict
1183
+
1184
+ def _compute_hecke_matrix_brandt(self, n, sparse=False):
1185
+ """
1186
+ Return the `n`-th Hecke matrix, computed using Brandt matrices
1187
+ (theta series).
1188
+
1189
+ When the `n`-th Hecke operator is requested, we computed theta
1190
+ series to precision `2n+20`, since it only takes slightly
1191
+ longer, and this means that any Hecke operator `T_m` can
1192
+ quickly be computed, for `m<2n+20`.
1193
+
1194
+ INPUT:
1195
+
1196
+ - ``n`` -- integer, coprime to level
1197
+ - ``sparse`` -- boolean (default: ``False``); whether matrix should be sparse
1198
+
1199
+ EXAMPLES::
1200
+
1201
+ sage: B = BrandtModule(3,17)
1202
+ sage: B._compute_hecke_matrix_brandt(3)
1203
+ [0 1 0 0]
1204
+ [1 0 0 0]
1205
+ [0 0 0 1]
1206
+ [0 0 1 0]
1207
+ sage: B._compute_hecke_matrix_brandt(5)
1208
+ [4 1 1 0]
1209
+ [1 4 0 1]
1210
+ [2 0 2 2]
1211
+ [0 2 2 2]
1212
+ sage: B._compute_hecke_matrix_brandt(5).fcp()
1213
+ (x - 6) * (x - 3) * (x^2 - 3*x - 2)
1214
+ """
1215
+ # we go out to 2*n+20 for efficiency, since it takes only a
1216
+ # little longer, but saves a lot of time if one computes
1217
+ # successive Hecke operators, which is a very common thing to
1218
+ # do.
1219
+ B = self._brandt_series_vectors()
1220
+ if len(B[0][0]) <= n:
1221
+ B = self._brandt_series_vectors(2 * n + 10)
1222
+ m = len(B)
1223
+ K = self.base_ring()
1224
+ return matrix(K, m, m, {(i, j): K(B[j][i][n])
1225
+ for i in range(m)
1226
+ for j in range(m)}, sparse=sparse)
1227
+
1228
+ @cached_method
1229
+ def _smallest_good_prime(self):
1230
+ """
1231
+ Return the smallest prime number that does not divide the level.
1232
+
1233
+ EXAMPLES::
1234
+
1235
+ sage: BrandtModule(17,6)._smallest_good_prime()
1236
+ 5
1237
+ """
1238
+ level = self.level()
1239
+ p = ZZ(2)
1240
+ while not level % p:
1241
+ p = next_prime(p)
1242
+ return p
1243
+
1244
+ @cached_method
1245
+ def right_ideals(self, B=None):
1246
+ """
1247
+ Return sorted tuple of representatives for the equivalence
1248
+ classes of right ideals in ``self``.
1249
+
1250
+ OUTPUT: sorted tuple of fractional ideals
1251
+
1252
+ EXAMPLES::
1253
+
1254
+ sage: B = BrandtModule(23)
1255
+ sage: B.right_ideals()
1256
+ (Fractional ideal (4, 4*i, 2 + 2*j, 2*i + 2*k),
1257
+ Fractional ideal (8, 8*i, 2 + 2*j, 6*i + 2*k),
1258
+ Fractional ideal (16, 16*i, 10 + 8*i + 2*j, 8 + 6*i + 2*k))
1259
+
1260
+ TESTS::
1261
+
1262
+ sage: B = BrandtModule(1009)
1263
+ sage: Is = B.right_ideals()
1264
+ sage: n = len(Is)
1265
+ sage: prod(not Is[i].is_right_equivalent(Is[j]) for i in range(n) for j in range(i))
1266
+ 1
1267
+ """
1268
+ # TODO: move this code to orders, along with cyclic_submodules()
1269
+ p = self._smallest_good_prime()
1270
+ R = self.order_of_level_N()
1271
+ I = R.unit_ideal()
1272
+ I = R.right_ideal([4 * x for x in I.basis()])
1273
+
1274
+ if B is None:
1275
+ B = self.dimension() // 2 + 5
1276
+
1277
+ ideals = [I]
1278
+ ideals_theta = {tuple(I.theta_series_vector(B)): [I]}
1279
+ new_ideals = [I]
1280
+
1281
+ newly_computed_ideals = []
1282
+ got_something_new = True
1283
+
1284
+ while got_something_new:
1285
+ got_something_new = False
1286
+ newly_computed_ideals = []
1287
+ for I in new_ideals:
1288
+ L = self.cyclic_submodules(I, p)
1289
+ for J in L:
1290
+ is_new = True
1291
+ J_theta = tuple(J.theta_series_vector(B))
1292
+ if J_theta in ideals_theta:
1293
+ for K in ideals_theta[J_theta]:
1294
+ if J.is_right_equivalent(K, 0):
1295
+ is_new = False
1296
+ break
1297
+ if is_new:
1298
+ newly_computed_ideals.append(J)
1299
+ ideals.append(J)
1300
+ if J_theta in ideals_theta:
1301
+ ideals_theta[J_theta].append(J)
1302
+ else:
1303
+ ideals_theta[J_theta] = [J]
1304
+ verbose("found %s of %s ideals" % (len(ideals), self.dimension()), level=2)
1305
+ if len(ideals) >= self.dimension():
1306
+ # order by basis matrix (as ideals were previously
1307
+ # ordered) for backward compatibility and
1308
+ # deterministic order of the output
1309
+ ideals = tuple(sorted(ideals, key=lambda x: x.basis_matrix()))
1310
+ self.__right_ideals = ideals
1311
+ return ideals
1312
+ got_something_new = True
1313
+ new_ideals = list(newly_computed_ideals)
1314
+
1315
+ return tuple(sorted(ideals))
1316
+
1317
+ @cached_method
1318
+ def _ideal_products(self, diagonal_only=False):
1319
+ """
1320
+ Return all products of right ideals, which are used in computing
1321
+ the Brandt matrices.
1322
+
1323
+ This function is used internally by the Brandt matrices
1324
+ algorithms.
1325
+
1326
+ INPUT:
1327
+
1328
+ - ``diagonal_only`` -- boolean (default: ``False``); if ``True`` returns
1329
+ only the diagonal ideal products
1330
+
1331
+ OUTPUT: list of ideals
1332
+
1333
+ EXAMPLES::
1334
+
1335
+ sage: B = BrandtModule(37)
1336
+ sage: B._ideal_products()
1337
+ [[Fractional ideal (16, 16*i, 8 + 8*i + 8*j, 8 + 12*i + 4*k)],
1338
+ [Fractional ideal (32, 32*i, 8 + 24*i + 8*j, 24 + 12*i + 4*k),
1339
+ Fractional ideal (32, 64*i, 16 + 48*i + 16*j, 36*i + 8*j + 4*k)],
1340
+ [Fractional ideal (32, 32*i, 8 + 8*i + 8*j, 8 + 12*i + 4*k),
1341
+ Fractional ideal (64, 32 + 32*i, 16 + 16*i + 16*j, 40 + 12*i + 4*k),
1342
+ Fractional ideal (32, 64*i, 16 + 16*i + 16*j, 16 + 52*i + 8*j + 4*k)]]
1343
+ sage: B._ideal_products(diagonal_only=True)
1344
+ [Fractional ideal (16, 16*i, 8 + 8*i + 8*j, 8 + 12*i + 4*k),
1345
+ Fractional ideal (32, 64*i, 16 + 48*i + 16*j, 36*i + 8*j + 4*k),
1346
+ Fractional ideal (32, 64*i, 16 + 16*i + 16*j, 16 + 52*i + 8*j + 4*k)]
1347
+ """
1348
+ L = self.right_ideals()
1349
+ n = len(L)
1350
+ if not n:
1351
+ return matrix(self.base_ring()[['q']], 0)
1352
+
1353
+ # 1. Compute the diagonal
1354
+ D = [I.multiply_by_conjugate(I) for I in L]
1355
+
1356
+ if diagonal_only:
1357
+ return D
1358
+
1359
+ # 2. Compute the rest of the products
1360
+ P = []
1361
+ for i in range(n):
1362
+ v = [L[i].multiply_by_conjugate(L[j]) for j in range(i)]
1363
+ v.append(D[i])
1364
+ P.append(v)
1365
+ return P
1366
+
1367
+ def _brandt_series_vectors(self, prec=None):
1368
+ """
1369
+ Return Brandt series coefficient vectors out to precision *at least* prec.
1370
+
1371
+ EXAMPLES::
1372
+
1373
+ sage: B = BrandtModule(37, use_cache=False)
1374
+ sage: B._brandt_series_vectors(5)
1375
+ [[(1/2, 1, 1, 2, 1), (1/2, 0, 1, 1, 3), (1/2, 0, 1, 1, 3)],
1376
+ [(1/2, 0, 1, 1, 3), (1/2, 1, 0, 0, 3), (1/2, 0, 2, 3, 1)],
1377
+ [(1/2, 0, 1, 1, 3), (1/2, 0, 2, 3, 1), (1/2, 1, 0, 0, 3)]]
1378
+
1379
+ If you have computed to higher precision and ask for a lower
1380
+ precision, the higher precision is still returned::
1381
+
1382
+ sage: B._brandt_series_vectors(2)
1383
+ [[(1/2, 1, 1, 2, 1), (1/2, 0, 1, 1, 3), (1/2, 0, 1, 1, 3)],
1384
+ [(1/2, 0, 1, 1, 3), (1/2, 1, 0, 0, 3), (1/2, 0, 2, 3, 1)],
1385
+ [(1/2, 0, 1, 1, 3), (1/2, 0, 2, 3, 1), (1/2, 1, 0, 0, 3)]]
1386
+ """
1387
+ if prec is None:
1388
+ try:
1389
+ return self.__brandt_series_vectors
1390
+ except AttributeError:
1391
+ prec = 2
1392
+ elif prec < 2:
1393
+ raise ValueError("prec must be at least 2")
1394
+ L = self.right_ideals()
1395
+ if not L:
1396
+ return [[]]
1397
+ try:
1398
+ if len(self.__brandt_series_vectors[0][0]) >= prec:
1399
+ return self.__brandt_series_vectors
1400
+ except AttributeError:
1401
+ pass
1402
+
1403
+ n = len(L)
1404
+ # 1. Compute the theta series
1405
+ theta = [[I.theta_series_vector(prec) for I in x]
1406
+ for x in self._ideal_products()]
1407
+
1408
+ # 2. Compute the number e_j
1409
+ e = [theta[j][j][1] for j in range(n)]
1410
+
1411
+ B = [[0 for _ in range(n)] for _ in range(n)]
1412
+
1413
+ # 3. Make the Brandt matrix series
1414
+ for i in range(n):
1415
+ B[i][i] = theta[i][i] / e[i]
1416
+ for j in range(i):
1417
+ B[j][i] = theta[i][j] / e[j]
1418
+ B[i][j] = theta[i][j] / e[i]
1419
+
1420
+ self.__brandt_series_vectors = B
1421
+ return B
1422
+
1423
+ def brandt_series(self, prec, var='q'):
1424
+ r"""
1425
+ Return matrix of power series `\sum T_n q^n` to the given
1426
+ precision.
1427
+
1428
+ Note that the Hecke operators in this series are
1429
+ always over `\QQ`, even if the base ring of this Brandt module
1430
+ is not `\QQ`.
1431
+
1432
+ INPUT:
1433
+
1434
+ - ``prec`` -- positive integer
1435
+ - ``var`` -- string (default: `q`)
1436
+
1437
+ OUTPUT: matrix of power series with coefficients in `\QQ`
1438
+
1439
+ EXAMPLES::
1440
+
1441
+ sage: B = BrandtModule(11)
1442
+ sage: B.brandt_series(2)
1443
+ [1/4 + q + O(q^2) 1/4 + O(q^2)]
1444
+ [ 1/6 + O(q^2) 1/6 + q + O(q^2)]
1445
+ sage: B.brandt_series(5)
1446
+ [1/4 + q + q^2 + 2*q^3 + 5*q^4 + O(q^5) 1/4 + 3*q^2 + 3*q^3 + 3*q^4 + O(q^5)]
1447
+ [ 1/6 + 2*q^2 + 2*q^3 + 2*q^4 + O(q^5) 1/6 + q + q^3 + 4*q^4 + O(q^5)]
1448
+
1449
+
1450
+ Asking for a smaller precision works::
1451
+
1452
+ sage: B.brandt_series(3)
1453
+ [1/4 + q + q^2 + O(q^3) 1/4 + 3*q^2 + O(q^3)]
1454
+ [ 1/6 + 2*q^2 + O(q^3) 1/6 + q + O(q^3)]
1455
+ sage: B.brandt_series(3,var='t')
1456
+ [1/4 + t + t^2 + O(t^3) 1/4 + 3*t^2 + O(t^3)]
1457
+ [ 1/6 + 2*t^2 + O(t^3) 1/6 + t + O(t^3)]
1458
+ """
1459
+ A = self._brandt_series_vectors(prec)
1460
+ R = PowerSeriesRing(QQ, var)
1461
+ n = len(A[0])
1462
+ return matrix(R, n, n,
1463
+ [[R(x.list()[:prec], prec) for x in Y] for Y in A])
1464
+
1465
+ @cached_method
1466
+ def eisenstein_subspace(self):
1467
+ """
1468
+ Return the 1-dimensional subspace of ``self`` on which the Hecke
1469
+ operators `T_p` act as `p+1` for `p` coprime to the level.
1470
+
1471
+ .. NOTE::
1472
+
1473
+ This function assumes that the base field has
1474
+ characteristic 0.
1475
+
1476
+ EXAMPLES::
1477
+
1478
+ sage: B = BrandtModule(11); B.eisenstein_subspace()
1479
+ Subspace of dimension 1 of Brandt module of dimension 2 of level 11 of weight 2 over Rational Field
1480
+ sage: B.eisenstein_subspace() is B.eisenstein_subspace()
1481
+ True
1482
+ sage: BrandtModule(3,11).eisenstein_subspace().basis()
1483
+ ((1, 1),)
1484
+ sage: BrandtModule(7,10).eisenstein_subspace().basis()
1485
+ ((1, 1, 1, 1/2, 1, 1, 1/2, 1, 1, 1),)
1486
+ sage: BrandtModule(7,10,base_ring=ZZ).eisenstein_subspace().basis()
1487
+ ((2, 2, 2, 1, 2, 2, 1, 2, 2, 2),)
1488
+ """
1489
+ if self.base_ring().characteristic():
1490
+ raise ValueError("characteristic must be 0")
1491
+ # cut down until we get a 1-d space using Hecke operators T_p
1492
+ # with p coprime to the level.
1493
+ V = self
1494
+ p = Integer(2)
1495
+ N = self.level()
1496
+ while V.dimension() >= 2:
1497
+ while not N % p:
1498
+ p = p.next_prime()
1499
+ A = V.T(p) - (p + 1)
1500
+ V = A.kernel()
1501
+ return V
1502
+
1503
+ def is_cuspidal(self) -> bool:
1504
+ r"""
1505
+ Return whether ``self`` is cuspidal, i.e. has no Eisenstein part.
1506
+
1507
+ EXAMPLES::
1508
+
1509
+ sage: B = BrandtModule(3, 4)
1510
+ sage: B.is_cuspidal()
1511
+ False
1512
+ sage: B.eisenstein_subspace()
1513
+ Brandt module of dimension 1 of level 3*4 of weight 2 over Rational Field
1514
+ """
1515
+ return not self.eisenstein_subspace().dimension()
1516
+
1517
+ @cached_method
1518
+ def monodromy_weights(self):
1519
+ r"""
1520
+ Return the weights for the monodromy pairing on this Brandt
1521
+ module.
1522
+
1523
+ The weights are associated to each ideal class in our
1524
+ fixed choice of basis. The weight of an ideal class `[I]` is
1525
+ half the number of units of the right order `I`.
1526
+
1527
+ .. NOTE:: The base ring must be `\QQ` or `\ZZ`.
1528
+
1529
+ EXAMPLES::
1530
+
1531
+ sage: BrandtModule(11).monodromy_weights()
1532
+ (2, 3)
1533
+ sage: BrandtModule(37).monodromy_weights()
1534
+ (1, 1, 1)
1535
+ sage: BrandtModule(43).monodromy_weights()
1536
+ (2, 1, 1, 1)
1537
+ sage: BrandtModule(7,10).monodromy_weights()
1538
+ (1, 1, 1, 2, 1, 1, 2, 1, 1, 1)
1539
+ sage: BrandtModule(5,13).monodromy_weights()
1540
+ (1, 3, 1, 1, 1, 3)
1541
+ sage: BrandtModule(2).monodromy_weights()
1542
+ (12,)
1543
+ sage: BrandtModule(2,7).monodromy_weights()
1544
+ (3, 3)
1545
+ """
1546
+ # Before normalization,
1547
+ #
1548
+ # theta(R) = 1 + e*q + ....
1549
+ #
1550
+ # where e is the number of units in the order R.
1551
+ #
1552
+ # Since the theta series may be normalized as
1553
+ #
1554
+ # c * theta(R) = a[0] + a[1]*q + ...
1555
+ #
1556
+ # we recover e = a[1]/a[0] regardless of normalization.
1557
+ orders = self._ideal_products(diagonal_only=True)
1558
+ thetas = (R.theta_series_vector(2) for R in orders)
1559
+ return tuple(a[1] / a[0] / 2 for a in thetas)
1560
+
1561
+
1562
+ # ====================
1563
+ # Benchmarking
1564
+ # ====================
1565
+ def benchmark_magma(levels, silent=False):
1566
+ """
1567
+ INPUT:
1568
+
1569
+ - ``levels`` -- list of pairs `(p,M)` where `p` is a prime not
1570
+ dividing `M`
1571
+ - ``silent`` -- boolean (default: ``False``); if ``True`` suppress
1572
+ printing during computation
1573
+
1574
+ OUTPUT:
1575
+
1576
+ list of 4-tuples ('magma', p, M, tm), where tm is the
1577
+ CPU time in seconds to compute T2 using Magma
1578
+
1579
+ EXAMPLES::
1580
+
1581
+ sage: a = sage.modular.quatalg.brandt.benchmark_magma([(11,1), (37,1), (43,1), (97,1)]) # optional - magma
1582
+ ('magma', 11, 1, ...)
1583
+ ('magma', 37, 1, ...)
1584
+ ('magma', 43, 1, ...)
1585
+ ('magma', 97, 1, ...)
1586
+ sage: a = sage.modular.quatalg.brandt.benchmark_magma([(11,2), (37,2), (43,2), (97,2)]) # optional - magma
1587
+ ('magma', 11, 2, ...)
1588
+ ('magma', 37, 2, ...)
1589
+ ('magma', 43, 2, ...)
1590
+ ('magma', 97, 2, ...)
1591
+ """
1592
+ ans = []
1593
+ from sage.interfaces.magma import magma
1594
+ for p, M in levels:
1595
+ t = magma.cputime()
1596
+ magma.eval('HeckeOperator(BrandtModule(%s, %s),2)' % (p, M))
1597
+ tm = magma.cputime(t)
1598
+ v = ('magma', p, M, tm)
1599
+ if not silent:
1600
+ print(v)
1601
+ ans.append(v)
1602
+ return ans
1603
+
1604
+
1605
+ def benchmark_sage(levels, silent=False):
1606
+ """
1607
+ INPUT:
1608
+
1609
+ - ``levels`` -- list of pairs `(p,M)` where `p` is a prime
1610
+ not dividing `M`
1611
+ - ``silent`` -- boolean (default: ``False``); if ``True`` suppress
1612
+ printing during computation
1613
+
1614
+ OUTPUT:
1615
+
1616
+ list of 4-tuples ('sage', p, M, tm), where tm is the
1617
+ CPU time in seconds to compute T2 using Sage
1618
+
1619
+ EXAMPLES::
1620
+
1621
+ sage: a = sage.modular.quatalg.brandt.benchmark_sage([(11,1), (37,1), (43,1), (97,1)])
1622
+ ('sage', 11, 1, ...)
1623
+ ('sage', 37, 1, ...)
1624
+ ('sage', 43, 1, ...)
1625
+ ('sage', 97, 1, ...)
1626
+ sage: a = sage.modular.quatalg.brandt.benchmark_sage([(11,2), (37,2), (43,2), (97,2)])
1627
+ ('sage', 11, 2, ...)
1628
+ ('sage', 37, 2, ...)
1629
+ ('sage', 43, 2, ...)
1630
+ ('sage', 97, 2, ...)
1631
+ """
1632
+ from sage.misc.timing import cputime
1633
+ ans = []
1634
+ for p, M in levels:
1635
+ t = cputime()
1636
+ BrandtModule(p, M, use_cache=False).hecke_matrix(2)
1637
+ tm = cputime(t)
1638
+ v = ('sage', p, M, tm)
1639
+ if not silent:
1640
+ print(v)
1641
+ ans.append(v)
1642
+ return ans