passagemath-flint 10.6.1rc10__cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.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.
- passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
- passagemath_flint-10.6.1rc10.dist-info/RECORD +360 -0
- passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
- passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
- passagemath_flint.libs/libflint-3701249d.so.21.0.0 +0 -0
- passagemath_flint.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
- passagemath_flint.libs/libgfortran-8a9a71bc.so.5.0.0 +0 -0
- passagemath_flint.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_flint.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_flint.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
- passagemath_flint.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
- passagemath_flint.libs/libntl-1004113e.so.44.0.1 +0 -0
- passagemath_flint.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
- sage/all__sagemath_flint.py +29 -0
- sage/combinat/all__sagemath_flint.py +1 -0
- sage/combinat/posets/all__sagemath_flint.py +1 -0
- sage/combinat/posets/hasse_cython_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython_flint.pyx +194 -0
- sage/data_structures/all__sagemath_flint.py +1 -0
- sage/data_structures/bounded_integer_sequences.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/data_structures/bounded_integer_sequences.pxd +62 -0
- sage/data_structures/bounded_integer_sequences.pyx +1418 -0
- sage/graphs/all__sagemath_flint.py +1 -0
- sage/graphs/chrompoly.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/chrompoly.pyx +555 -0
- sage/graphs/matchpoly.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/matchpoly.pyx +412 -0
- sage/libs/all__sagemath_flint.py +17 -0
- sage/libs/arb/__init__.py +1 -0
- sage/libs/arb/acb.pxd +154 -0
- sage/libs/arb/acb_calc.pxd +9 -0
- sage/libs/arb/acb_elliptic.pxd +25 -0
- sage/libs/arb/acb_hypgeom.pxd +74 -0
- sage/libs/arb/acb_mat.pxd +62 -0
- sage/libs/arb/acb_modular.pxd +17 -0
- sage/libs/arb/acb_poly.pxd +216 -0
- sage/libs/arb/arb.pxd +240 -0
- sage/libs/arb/arb_fmpz_poly.pxd +21 -0
- sage/libs/arb/arb_hypgeom.pxd +83 -0
- sage/libs/arb/arb_wrap.h +34 -0
- sage/libs/arb/arf.pxd +131 -0
- sage/libs/arb/arith.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/arb/arith.pyx +87 -0
- sage/libs/arb/bernoulli.pxd +6 -0
- sage/libs/arb/mag.pxd +77 -0
- sage/libs/arb/types.pxd +37 -0
- sage/libs/flint/__init__.py +1 -0
- sage/libs/flint/acb.pxd +270 -0
- sage/libs/flint/acb_calc.pxd +22 -0
- sage/libs/flint/acb_dft.pxd +51 -0
- sage/libs/flint/acb_dirichlet.pxd +112 -0
- sage/libs/flint/acb_elliptic.pxd +42 -0
- sage/libs/flint/acb_hypgeom.pxd +169 -0
- sage/libs/flint/acb_macros.pxd +9 -0
- sage/libs/flint/acb_mat.pxd +136 -0
- sage/libs/flint/acb_mat_macros.pxd +10 -0
- sage/libs/flint/acb_modular.pxd +62 -0
- sage/libs/flint/acb_poly.pxd +251 -0
- sage/libs/flint/acb_poly_macros.pxd +8 -0
- sage/libs/flint/acb_theta.pxd +124 -0
- sage/libs/flint/acf.pxd +32 -0
- sage/libs/flint/aprcl.pxd +84 -0
- sage/libs/flint/arb.pxd +382 -0
- sage/libs/flint/arb_calc.pxd +31 -0
- sage/libs/flint/arb_fmpz_poly.pxd +34 -0
- sage/libs/flint/arb_fpwrap.pxd +215 -0
- sage/libs/flint/arb_hypgeom.pxd +147 -0
- sage/libs/flint/arb_macros.pxd +9 -0
- sage/libs/flint/arb_mat.pxd +140 -0
- sage/libs/flint/arb_mat_macros.pxd +10 -0
- sage/libs/flint/arb_poly.pxd +237 -0
- sage/libs/flint/arf.pxd +167 -0
- sage/libs/flint/arith.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith.pxd +76 -0
- sage/libs/flint/arith.pyx +77 -0
- sage/libs/flint/arith_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith_sage.pyx +308 -0
- sage/libs/flint/bernoulli.pxd +28 -0
- sage/libs/flint/bool_mat.pxd +52 -0
- sage/libs/flint/ca.pxd +203 -0
- sage/libs/flint/ca_ext.pxd +34 -0
- sage/libs/flint/ca_field.pxd +32 -0
- sage/libs/flint/ca_mat.pxd +117 -0
- sage/libs/flint/ca_poly.pxd +104 -0
- sage/libs/flint/ca_vec.pxd +46 -0
- sage/libs/flint/calcium.pxd +27 -0
- sage/libs/flint/d_mat.pxd +39 -0
- sage/libs/flint/d_vec.pxd +32 -0
- sage/libs/flint/dirichlet.pxd +57 -0
- sage/libs/flint/dlog.pxd +53 -0
- sage/libs/flint/double_extras.pxd +24 -0
- sage/libs/flint/double_interval.pxd +36 -0
- sage/libs/flint/fexpr.pxd +104 -0
- sage/libs/flint/fexpr_builtin.pxd +20 -0
- sage/libs/flint/fft.pxd +66 -0
- sage/libs/flint/flint.pxd +36 -0
- sage/libs/flint/flint_ntl_wrap.h +35 -0
- sage/libs/flint/flint_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/flint_sage.pyx +163 -0
- sage/libs/flint/flint_wrap.h +190 -0
- sage/libs/flint/fmpq.pxd +137 -0
- sage/libs/flint/fmpq_mat.pxd +105 -0
- sage/libs/flint/fmpq_mat_macros.pxd +10 -0
- sage/libs/flint/fmpq_mpoly.pxd +165 -0
- sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
- sage/libs/flint/fmpq_poly.pxd +241 -0
- sage/libs/flint/fmpq_poly_macros.pxd +9 -0
- sage/libs/flint/fmpq_poly_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpq_poly_sage.pxd +31 -0
- sage/libs/flint/fmpq_poly_sage.pyx +48 -0
- sage/libs/flint/fmpq_vec.pxd +27 -0
- sage/libs/flint/fmpz.pxd +256 -0
- sage/libs/flint/fmpz_extras.pxd +32 -0
- sage/libs/flint/fmpz_factor.pxd +42 -0
- sage/libs/flint/fmpz_factor_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_factor_sage.pxd +4 -0
- sage/libs/flint/fmpz_factor_sage.pyx +29 -0
- sage/libs/flint/fmpz_lll.pxd +49 -0
- sage/libs/flint/fmpz_macros.pxd +8 -0
- sage/libs/flint/fmpz_mat.pxd +184 -0
- sage/libs/flint/fmpz_mat_macros.pxd +10 -0
- sage/libs/flint/fmpz_mod.pxd +46 -0
- sage/libs/flint/fmpz_mod_mat.pxd +71 -0
- sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
- sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fmpz_mod_poly.pxd +249 -0
- sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
- sage/libs/flint/fmpz_mod_vec.pxd +27 -0
- sage/libs/flint/fmpz_mpoly.pxd +224 -0
- sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
- sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
- sage/libs/flint/fmpz_poly.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly.pxd +407 -0
- sage/libs/flint/fmpz_poly.pyx +19 -0
- sage/libs/flint/fmpz_poly_factor.pxd +33 -0
- sage/libs/flint/fmpz_poly_macros.pxd +8 -0
- sage/libs/flint/fmpz_poly_mat.pxd +71 -0
- sage/libs/flint/fmpz_poly_q.pxd +55 -0
- sage/libs/flint/fmpz_poly_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly_sage.pxd +20 -0
- sage/libs/flint/fmpz_poly_sage.pyx +500 -0
- sage/libs/flint/fmpz_vec.pxd +80 -0
- sage/libs/flint/fmpzi.pxd +52 -0
- sage/libs/flint/fq.pxd +97 -0
- sage/libs/flint/fq_default.pxd +84 -0
- sage/libs/flint/fq_default_mat.pxd +70 -0
- sage/libs/flint/fq_default_poly.pxd +97 -0
- sage/libs/flint/fq_default_poly_factor.pxd +39 -0
- sage/libs/flint/fq_embed.pxd +28 -0
- sage/libs/flint/fq_mat.pxd +83 -0
- sage/libs/flint/fq_nmod.pxd +95 -0
- sage/libs/flint/fq_nmod_embed.pxd +28 -0
- sage/libs/flint/fq_nmod_mat.pxd +83 -0
- sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
- sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fq_nmod_poly.pxd +202 -0
- sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
- sage/libs/flint/fq_nmod_vec.pxd +33 -0
- sage/libs/flint/fq_poly.pxd +204 -0
- sage/libs/flint/fq_poly_factor.pxd +47 -0
- sage/libs/flint/fq_vec.pxd +33 -0
- sage/libs/flint/fq_zech.pxd +99 -0
- sage/libs/flint/fq_zech_embed.pxd +28 -0
- sage/libs/flint/fq_zech_mat.pxd +78 -0
- sage/libs/flint/fq_zech_poly.pxd +198 -0
- sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
- sage/libs/flint/fq_zech_vec.pxd +33 -0
- sage/libs/flint/gr.pxd +174 -0
- sage/libs/flint/gr_generic.pxd +215 -0
- sage/libs/flint/gr_mat.pxd +161 -0
- sage/libs/flint/gr_mpoly.pxd +68 -0
- sage/libs/flint/gr_poly.pxd +276 -0
- sage/libs/flint/gr_special.pxd +237 -0
- sage/libs/flint/gr_vec.pxd +120 -0
- sage/libs/flint/hypgeom.pxd +24 -0
- sage/libs/flint/long_extras.pxd +23 -0
- sage/libs/flint/mag.pxd +131 -0
- sage/libs/flint/mag_macros.pxd +8 -0
- sage/libs/flint/mpf_mat.pxd +36 -0
- sage/libs/flint/mpf_vec.pxd +34 -0
- sage/libs/flint/mpfr_mat.pxd +27 -0
- sage/libs/flint/mpfr_vec.pxd +25 -0
- sage/libs/flint/mpn_extras.pxd +41 -0
- sage/libs/flint/mpoly.pxd +72 -0
- sage/libs/flint/nf.pxd +19 -0
- sage/libs/flint/nf_elem.pxd +74 -0
- sage/libs/flint/nmod.pxd +35 -0
- sage/libs/flint/nmod_mat.pxd +104 -0
- sage/libs/flint/nmod_mpoly.pxd +144 -0
- sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/nmod_poly.pxd +339 -0
- sage/libs/flint/nmod_poly_factor.pxd +44 -0
- sage/libs/flint/nmod_poly_linkage.pxi +710 -0
- sage/libs/flint/nmod_poly_mat.pxd +76 -0
- sage/libs/flint/nmod_vec.pxd +40 -0
- sage/libs/flint/ntl_interface.pxd +17 -0
- sage/libs/flint/padic.pxd +93 -0
- sage/libs/flint/padic_mat.pxd +64 -0
- sage/libs/flint/padic_poly.pxd +88 -0
- sage/libs/flint/partitions.pxd +23 -0
- sage/libs/flint/perm.pxd +26 -0
- sage/libs/flint/profiler.pxd +24 -0
- sage/libs/flint/qadic.pxd +77 -0
- sage/libs/flint/qfb.pxd +44 -0
- sage/libs/flint/qqbar.pxd +172 -0
- sage/libs/flint/qsieve.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve.pxd +41 -0
- sage/libs/flint/qsieve.pyx +21 -0
- sage/libs/flint/qsieve_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve_sage.pyx +67 -0
- sage/libs/flint/thread_pool.pxd +25 -0
- sage/libs/flint/types.pxd +2076 -0
- sage/libs/flint/ulong_extras.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras.pxd +141 -0
- sage/libs/flint/ulong_extras.pyx +21 -0
- sage/libs/flint/ulong_extras_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras_sage.pyx +21 -0
- sage/matrix/all__sagemath_flint.py +1 -0
- sage/matrix/change_ring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/change_ring.pyx +43 -0
- sage/matrix/matrix_complex_ball_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_complex_ball_dense.pxd +14 -0
- sage/matrix/matrix_complex_ball_dense.pyx +973 -0
- sage/matrix/matrix_cyclo_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_cyclo_dense.pxd +16 -0
- sage/matrix/matrix_cyclo_dense.pyx +1761 -0
- sage/matrix/matrix_integer_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_dense.pxd +32 -0
- sage/matrix/matrix_integer_dense.pyx +5801 -0
- sage/matrix/matrix_integer_dense_hnf.py +1294 -0
- sage/matrix/matrix_integer_dense_saturation.py +346 -0
- sage/matrix/matrix_integer_sparse.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_sparse.pxd +9 -0
- sage/matrix/matrix_integer_sparse.pyx +1090 -0
- sage/matrix/matrix_rational_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_dense.pxd +23 -0
- sage/matrix/matrix_rational_dense.pyx +2995 -0
- sage/matrix/matrix_rational_sparse.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_sparse.pxd +11 -0
- sage/matrix/matrix_rational_sparse.pyx +789 -0
- sage/matrix/misc_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/misc_flint.pyx +109 -0
- sage/modular/all__sagemath_flint.py +1 -0
- sage/modular/modform/all__sagemath_flint.py +1 -0
- sage/modular/modform/eis_series_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/modform/eis_series_cython.pyx +226 -0
- sage/modular/modsym/all__sagemath_flint.py +1 -0
- sage/modular/modsym/apply.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/apply.pxd +6 -0
- sage/modular/modsym/apply.pyx +113 -0
- sage/modular/modsym/heilbronn.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/heilbronn.pyx +966 -0
- sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
- sage/modular/pollack_stevens/dist.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/pollack_stevens/dist.pxd +38 -0
- sage/modular/pollack_stevens/dist.pyx +1439 -0
- sage/quivers/algebra.py +691 -0
- sage/quivers/algebra_elements.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/quivers/algebra_elements.pxd +97 -0
- sage/quivers/algebra_elements.pxi +1324 -0
- sage/quivers/algebra_elements.pyx +1424 -0
- sage/quivers/all.py +1 -0
- sage/quivers/ar_quiver.py +917 -0
- sage/quivers/homspace.py +640 -0
- sage/quivers/morphism.py +1282 -0
- sage/quivers/path_semigroup.py +1155 -0
- sage/quivers/paths.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/quivers/paths.pxd +13 -0
- sage/quivers/paths.pyx +809 -0
- sage/quivers/representation.py +2975 -0
- sage/rings/all__sagemath_flint.py +37 -0
- sage/rings/cif.py +4 -0
- sage/rings/complex_arb.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_arb.pxd +29 -0
- sage/rings/complex_arb.pyx +5176 -0
- sage/rings/complex_interval.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_interval.pxd +30 -0
- sage/rings/complex_interval.pyx +2475 -0
- sage/rings/complex_interval_field.py +711 -0
- sage/rings/convert/all.py +1 -0
- sage/rings/convert/mpfi.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/convert/mpfi.pxd +6 -0
- sage/rings/convert/mpfi.pyx +576 -0
- sage/rings/factorint_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/factorint_flint.pyx +99 -0
- sage/rings/fraction_field_FpT.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/fraction_field_FpT.pxd +28 -0
- sage/rings/fraction_field_FpT.pyx +2043 -0
- sage/rings/imaginary_unit.py +5 -0
- sage/rings/monomials.py +73 -0
- sage/rings/number_field/S_unit_solver.py +2870 -0
- sage/rings/number_field/all__sagemath_flint.py +7 -0
- sage/rings/number_field/bdd_height.py +664 -0
- sage/rings/number_field/class_group.py +762 -0
- sage/rings/number_field/galois_group.py +1307 -0
- sage/rings/number_field/homset.py +612 -0
- sage/rings/number_field/maps.py +687 -0
- sage/rings/number_field/morphism.py +272 -0
- sage/rings/number_field/number_field.py +12820 -0
- sage/rings/number_field/number_field_element.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element.pxd +59 -0
- sage/rings/number_field/number_field_element.pyx +5735 -0
- sage/rings/number_field/number_field_element_quadratic.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
- sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
- sage/rings/number_field/number_field_ideal_rel.py +925 -0
- sage/rings/number_field/number_field_morphisms.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_morphisms.pyx +781 -0
- sage/rings/number_field/number_field_rel.py +2734 -0
- sage/rings/number_field/order.py +2981 -0
- sage/rings/number_field/order_ideal.py +804 -0
- sage/rings/number_field/selmer_group.py +715 -0
- sage/rings/number_field/small_primes_of_degree_one.py +242 -0
- sage/rings/number_field/splitting_field.py +606 -0
- sage/rings/number_field/structure.py +380 -0
- sage/rings/number_field/unit_group.py +721 -0
- sage/rings/padics/all__sagemath_flint.py +3 -0
- sage/rings/polynomial/all__sagemath_flint.py +1 -0
- sage/rings/polynomial/complex_roots.py +312 -0
- sage/rings/polynomial/evaluation_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/evaluation_flint.pxd +7 -0
- sage/rings/polynomial/evaluation_flint.pyx +68 -0
- sage/rings/polynomial/hilbert.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/hilbert.pyx +602 -0
- sage/rings/polynomial/polynomial_complex_arb.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
- sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
- sage/rings/polynomial/polynomial_number_field.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_number_field.pyx +345 -0
- sage/rings/polynomial/polynomial_rational_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
- sage/rings/polynomial/polynomial_zmod_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
- sage/rings/polynomial/real_roots.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/real_roots.pxd +81 -0
- sage/rings/polynomial/real_roots.pyx +4704 -0
- sage/rings/polynomial/refine_root.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/refine_root.pyx +142 -0
- sage/rings/polynomial/weil/all.py +4 -0
- sage/rings/polynomial/weil/power_sums.h +46 -0
- sage/rings/polynomial/weil/weil_polynomials.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
- sage/rings/qqbar.py +9025 -0
- sage/rings/real_arb.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/real_arb.pxd +21 -0
- sage/rings/real_arb.pyx +4065 -0
- sage/rings/real_interval_absolute.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/real_interval_absolute.pyx +1073 -0
- sage/rings/real_mpfi.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/real_mpfi.pyx +5428 -0
- sage/schemes/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
- sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,1439 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-flint
|
2
|
+
# distutils: libraries = gmp
|
3
|
+
# distutils: extra_compile_args = -D_XPG6
|
4
|
+
# sage.doctest: needs sage.schemes
|
5
|
+
"""
|
6
|
+
`p`-adic distributions spaces
|
7
|
+
|
8
|
+
This module implements `p`-adic distributions, a `p`-adic Banach
|
9
|
+
space dual to locally analytic functions on a disc.
|
10
|
+
|
11
|
+
EXAMPLES::
|
12
|
+
|
13
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
14
|
+
sage: v = D([7,14,21,28,35]); v
|
15
|
+
(7 + O(7^5), 2*7 + O(7^4), 3*7 + O(7^3), 4*7 + O(7^2), O(7))
|
16
|
+
|
17
|
+
REFERENCES:
|
18
|
+
|
19
|
+
- [PS2011]_
|
20
|
+
"""
|
21
|
+
|
22
|
+
# ****************************************************************************
|
23
|
+
# Copyright (C) 2012 Robert Pollack <rpollack@math.bu.edu>
|
24
|
+
#
|
25
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
26
|
+
# as published by the Free Software Foundation; either version 2 of
|
27
|
+
# the License, or (at your option) any later version.
|
28
|
+
# https://www.gnu.org/licenses/
|
29
|
+
# ****************************************************************************
|
30
|
+
import operator
|
31
|
+
|
32
|
+
from sage.arith.misc import bernoulli
|
33
|
+
from sage.categories.fields import Fields
|
34
|
+
from sage.matrix.constructor import matrix
|
35
|
+
from sage.matrix.matrix cimport Matrix
|
36
|
+
from sage.misc.verbose import verbose
|
37
|
+
from sage.modular.pollack_stevens.sigma0 import Sigma0
|
38
|
+
from sage.rings.finite_rings.integer_mod_ring import Zmod
|
39
|
+
from sage.rings.infinity import Infinity
|
40
|
+
from sage.rings.integer cimport Integer
|
41
|
+
from sage.rings.integer_ring import ZZ
|
42
|
+
from sage.rings.padics.padic_generic import pAdicGeneric
|
43
|
+
from sage.rings.power_series_ring import PowerSeriesRing
|
44
|
+
from sage.rings.rational_field import QQ
|
45
|
+
from sage.structure.element cimport Element
|
46
|
+
from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool
|
47
|
+
|
48
|
+
# from sage.libs.flint.ulong_extras cimport *
|
49
|
+
|
50
|
+
cdef long overflow = 1 << (4 * sizeof(long) - 1)
|
51
|
+
cdef long underflow = -overflow
|
52
|
+
cdef long maxordp = (1L << (sizeof(long) * 8 - 2)) - 1
|
53
|
+
|
54
|
+
|
55
|
+
def get_dist_classes(p, prec_cap, base, symk, implementation):
|
56
|
+
r"""
|
57
|
+
Determine the element and action classes to be used for given inputs.
|
58
|
+
|
59
|
+
INPUT:
|
60
|
+
|
61
|
+
- ``p`` -- prime
|
62
|
+
|
63
|
+
- ``prec_cap`` -- the `p`-adic precision cap
|
64
|
+
|
65
|
+
- ``base`` -- the base ring
|
66
|
+
|
67
|
+
- ``symk`` -- an element of Symk
|
68
|
+
|
69
|
+
- ``implementation`` -- string; if not ``None``, override the
|
70
|
+
automatic choice of implementation. May be 'long' or 'vector',
|
71
|
+
otherwise raise a :exc:`NotImplementedError`.
|
72
|
+
|
73
|
+
OUTPUT:
|
74
|
+
|
75
|
+
- Either a Dist_vector and WeightKAction_vector, or a Dist_vector_long
|
76
|
+
and WeightKAction_vector_long
|
77
|
+
|
78
|
+
EXAMPLES::
|
79
|
+
|
80
|
+
sage: D = OverconvergentDistributions(2, 3, 5); D # indirect doctest
|
81
|
+
Space of 3-adic distributions with k=2 action and precision cap 5
|
82
|
+
"""
|
83
|
+
if implementation is not None:
|
84
|
+
if implementation == 'long':
|
85
|
+
raise NotImplementedError('The optimized implementation -using longs- has been disabled and may return wrong results.')
|
86
|
+
elif implementation == 'vector':
|
87
|
+
return Dist_vector, WeightKAction_vector
|
88
|
+
else:
|
89
|
+
raise NotImplementedError('The implementation "%s" does not exist yet' % (implementation))
|
90
|
+
|
91
|
+
return Dist_vector, WeightKAction_vector
|
92
|
+
|
93
|
+
|
94
|
+
cdef class Dist(ModuleElement):
|
95
|
+
r"""
|
96
|
+
The main `p`-adic distribution class, implemented as per the paper [PS2011]__.
|
97
|
+
"""
|
98
|
+
def moment(self, n):
|
99
|
+
r"""
|
100
|
+
Return the `n`-th moment.
|
101
|
+
|
102
|
+
INPUT:
|
103
|
+
|
104
|
+
- ``n`` -- integer or slice, to be passed on to moments
|
105
|
+
|
106
|
+
OUTPUT:
|
107
|
+
|
108
|
+
- the `n`-th moment, or a list of moments in the case that `n`
|
109
|
+
is a slice.
|
110
|
+
|
111
|
+
EXAMPLES::
|
112
|
+
|
113
|
+
sage: D = OverconvergentDistributions(4, 7, 10)
|
114
|
+
sage: v = D([7,14,21,28,35])
|
115
|
+
sage: v.moment(3)
|
116
|
+
4*7 + O(7^2)
|
117
|
+
sage: v.moment(0)
|
118
|
+
7 + O(7^5)
|
119
|
+
"""
|
120
|
+
return self.parent().prime() ** (self.ordp) * self._unscaled_moment(n)
|
121
|
+
|
122
|
+
def moments(self):
|
123
|
+
r"""
|
124
|
+
Return the vector of moments.
|
125
|
+
|
126
|
+
OUTPUT: the vector of moments
|
127
|
+
|
128
|
+
EXAMPLES::
|
129
|
+
|
130
|
+
sage: D = OverconvergentDistributions(4, 5, 10, base = Qp(5))
|
131
|
+
sage: v = D([1,7,4,2,-1])
|
132
|
+
sage: v = 1/5^3 * v
|
133
|
+
sage: v
|
134
|
+
5^-3 * (1 + O(5^5), 2 + 5 + O(5^4), 4 + O(5^3), 2 + O(5^2), 4 + O(5))
|
135
|
+
sage: v.moments()
|
136
|
+
(5^-3 + O(5^2), 2*5^-3 + 5^-2 + O(5), 4*5^-3 + O(5^0), 2*5^-3 + O(5^-1), 4*5^-3 + O(5^-2))
|
137
|
+
"""
|
138
|
+
return self.parent().prime() ** (self.ordp) * self._moments
|
139
|
+
|
140
|
+
cpdef normalize(self, include_zeroth_moment=True):
|
141
|
+
r"""
|
142
|
+
Normalize so that the precision of the `i`-th moment is `n-i`,
|
143
|
+
where `n` is the number of moments.
|
144
|
+
|
145
|
+
OUTPUT: normalized entries of the distribution
|
146
|
+
|
147
|
+
EXAMPLES::
|
148
|
+
|
149
|
+
sage: D = OverconvergentDistributions(5, 7, 15); D
|
150
|
+
Space of 7-adic distributions with k=5 action and precision cap 15
|
151
|
+
sage: v = D([1,2,3,4,5]); v
|
152
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
153
|
+
sage: v.normalize()
|
154
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
155
|
+
"""
|
156
|
+
raise NotImplementedError
|
157
|
+
|
158
|
+
cdef long _relprec(self) noexcept:
|
159
|
+
raise NotImplementedError
|
160
|
+
|
161
|
+
cdef _unscaled_moment(self, long i):
|
162
|
+
raise NotImplementedError
|
163
|
+
|
164
|
+
cpdef long _ord_p(self) noexcept:
|
165
|
+
r"""
|
166
|
+
Return power of `p` by which the moments are shifted.
|
167
|
+
|
168
|
+
.. NOTE::
|
169
|
+
|
170
|
+
This is not necessarily the same as the valuation,
|
171
|
+
since the moments could all be divisible by `p`.
|
172
|
+
|
173
|
+
EXAMPLES::
|
174
|
+
|
175
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
176
|
+
sage: v = D([7,14,21,28,35]); v
|
177
|
+
(7 + O(7^5), 2*7 + O(7^4), 3*7 + O(7^3), 4*7 + O(7^2), O(7))
|
178
|
+
sage: v._ord_p()
|
179
|
+
0
|
180
|
+
"""
|
181
|
+
return self.ordp
|
182
|
+
|
183
|
+
def scale(self, left):
|
184
|
+
r"""
|
185
|
+
Scale the moments of the distribution by ``left``.
|
186
|
+
|
187
|
+
INPUT:
|
188
|
+
|
189
|
+
- ``left`` -- scalar
|
190
|
+
|
191
|
+
OUTPUT: scales the moments by ``left``
|
192
|
+
|
193
|
+
EXAMPLES::
|
194
|
+
|
195
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
196
|
+
sage: v = D([1,2,3,4,5]); v
|
197
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
198
|
+
sage: v.scale(2)
|
199
|
+
(2 + O(7^5), 4 + O(7^4), 6 + O(7^3), 1 + 7 + O(7^2), 3 + O(7))
|
200
|
+
"""
|
201
|
+
# if isinstance(self, Dist_long) and isinstance(left, (Integer, pAdicCappedRelativeElement, pAdicCappedAbsoluteElement, pAdicFixedModElement)):
|
202
|
+
# return self._lmul_(left)
|
203
|
+
R = left.parent()
|
204
|
+
base = self.parent().base_ring()
|
205
|
+
if base is R:
|
206
|
+
return self._lmul_(left)
|
207
|
+
elif base.has_coerce_map_from(R):
|
208
|
+
return self._lmul_(base(left))
|
209
|
+
else:
|
210
|
+
from sage.categories.pushout import pushout
|
211
|
+
new_base = pushout(base, R)
|
212
|
+
V = self.parent().change_ring(new_base)
|
213
|
+
scalar = new_base(left)
|
214
|
+
return V([scalar * new_base(self.moment(i)) for i in range(self.precision_absolute())])
|
215
|
+
|
216
|
+
def is_zero(self, p=None, M=None) -> bool:
|
217
|
+
r"""
|
218
|
+
Return ``True`` if the `i`-th moment is zero for all `i` (case ``M`` is
|
219
|
+
``None``) or zero modulo `p^{M-i}` for all `i` (when ``M`` is not
|
220
|
+
``None``).
|
221
|
+
|
222
|
+
Note that some moments are not known to precision ``M``, in which
|
223
|
+
case they are only checked to be equal to zero modulo the
|
224
|
+
precision to which they are defined.
|
225
|
+
|
226
|
+
INPUT:
|
227
|
+
|
228
|
+
- ``p`` -- prime
|
229
|
+
|
230
|
+
- ``M`` -- precision
|
231
|
+
|
232
|
+
OUTPUT: boolean
|
233
|
+
|
234
|
+
EXAMPLES::
|
235
|
+
|
236
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
237
|
+
sage: v = D([1,2,3,4,5]); v
|
238
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
239
|
+
sage: v.is_zero()
|
240
|
+
False
|
241
|
+
sage: v = D(5*[0])
|
242
|
+
sage: v.is_zero()
|
243
|
+
True
|
244
|
+
|
245
|
+
::
|
246
|
+
|
247
|
+
sage: D = Symk(0)
|
248
|
+
sage: v = D([0])
|
249
|
+
sage: v.is_zero(5,3)
|
250
|
+
True
|
251
|
+
"""
|
252
|
+
n = self.precision_relative()
|
253
|
+
aprec = self.precision_absolute()
|
254
|
+
if M is None:
|
255
|
+
M = n
|
256
|
+
# elif M > aprec: # DEBUG
|
257
|
+
# return False
|
258
|
+
elif M < aprec:
|
259
|
+
n -= (aprec - M)
|
260
|
+
M -= self.ordp
|
261
|
+
if p is None:
|
262
|
+
p = self.parent().prime()
|
263
|
+
cdef bint usearg = True
|
264
|
+
if n == 0:
|
265
|
+
return True
|
266
|
+
else:
|
267
|
+
try:
|
268
|
+
z = self._unscaled_moment(0).is_zero(M)
|
269
|
+
except TypeError:
|
270
|
+
z = self._unscaled_moment(0).is_zero()
|
271
|
+
use_arg = False
|
272
|
+
if not z:
|
273
|
+
return False
|
274
|
+
for a in range(1, n):
|
275
|
+
if usearg:
|
276
|
+
try:
|
277
|
+
z = self._unscaled_moment(a).is_zero(M - a)
|
278
|
+
except TypeError:
|
279
|
+
z = self._unscaled_moment(a).is_zero()
|
280
|
+
use_arg = False
|
281
|
+
else:
|
282
|
+
z = self._unscaled_moment(a).is_zero()
|
283
|
+
if not z:
|
284
|
+
return False
|
285
|
+
return True
|
286
|
+
|
287
|
+
def find_scalar(self, _other, p, M=None, check=True):
|
288
|
+
r"""
|
289
|
+
Return an ``alpha`` with ``other = self * alpha``, or raises
|
290
|
+
a :exc:`ValueError`.
|
291
|
+
|
292
|
+
It will also raise a :exc:`ValueError` if this distribution is zero.
|
293
|
+
|
294
|
+
INPUT:
|
295
|
+
|
296
|
+
- ``other`` -- another distribution
|
297
|
+
|
298
|
+
- ``p`` -- an integral prime (only used if the parent is not a Symk)
|
299
|
+
|
300
|
+
- ``M`` -- (default: ``None``) an integer, the relative precision
|
301
|
+
to which the scalar must be determined
|
302
|
+
|
303
|
+
- ``check`` -- boolean (default: ``True``); whether to validate
|
304
|
+
that ``other`` is actually a multiple of this element
|
305
|
+
|
306
|
+
OUTPUT: a scalar ``alpha`` with ``other = self * alpha``
|
307
|
+
|
308
|
+
EXAMPLES::
|
309
|
+
|
310
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
311
|
+
sage: v = D([1,2,3,4,5])
|
312
|
+
sage: w = D([3,6,9,12,15])
|
313
|
+
sage: v.find_scalar(w,p=7)
|
314
|
+
3 + O(7^5)
|
315
|
+
sage: v.find_scalar(w,p=7,M=4)
|
316
|
+
3 + O(7^4)
|
317
|
+
|
318
|
+
sage: u = D([1,4,9,16,25])
|
319
|
+
sage: v.find_scalar(u,p=7)
|
320
|
+
Traceback (most recent call last):
|
321
|
+
...
|
322
|
+
ValueError: not a scalar multiple
|
323
|
+
"""
|
324
|
+
cdef Dist other = _other
|
325
|
+
i = 0
|
326
|
+
n = self.precision_relative()
|
327
|
+
other_pr = other.precision_relative()
|
328
|
+
if n == 0:
|
329
|
+
raise ValueError("self is zero")
|
330
|
+
verbose("n = %s" % n, level=2)
|
331
|
+
verbose("moment 0", level=2)
|
332
|
+
a = self._unscaled_moment(i)
|
333
|
+
verbose("a = %s" % a, level = 2)
|
334
|
+
padic = isinstance(a.parent(), pAdicGeneric)
|
335
|
+
if self.parent().is_symk():
|
336
|
+
while a == 0:
|
337
|
+
if other._unscaled_moment(i) != 0:
|
338
|
+
raise ValueError("not a scalar multiple")
|
339
|
+
i += 1
|
340
|
+
verbose("moment %s" % i, level = 2)
|
341
|
+
try:
|
342
|
+
a = self._unscaled_moment(i)
|
343
|
+
except IndexError:
|
344
|
+
raise ValueError("self is zero")
|
345
|
+
alpha = other._unscaled_moment(i) / a
|
346
|
+
if check:
|
347
|
+
i += 1
|
348
|
+
while i < n:
|
349
|
+
verbose("comparing moment %s" % i, level = 2)
|
350
|
+
if alpha * self._unscaled_moment(i) != other._unscaled_moment(i):
|
351
|
+
raise ValueError("not a scalar multiple")
|
352
|
+
i += 1
|
353
|
+
else:
|
354
|
+
p = self.parent().prime()
|
355
|
+
v = a.valuation(p)
|
356
|
+
while v >= n - i:
|
357
|
+
i += 1
|
358
|
+
verbose("p moment %s" % i, level = 2)
|
359
|
+
try:
|
360
|
+
a = self._unscaled_moment(i)
|
361
|
+
except IndexError:
|
362
|
+
raise ValueError("self is zero")
|
363
|
+
v = a.valuation(p)
|
364
|
+
relprec = n - i - v
|
365
|
+
# verbose("p=%s, n-i=%s\nself.moment=%s, other.moment=%s" % (p, n-i, a, other._unscaled_moment(i)),level=2)
|
366
|
+
# RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision
|
367
|
+
if padic:
|
368
|
+
if i < other_pr:
|
369
|
+
alpha = (other._unscaled_moment(i) / a).add_bigoh(n - i)
|
370
|
+
else:
|
371
|
+
alpha = (0 * a).add_bigoh(other_pr - i)
|
372
|
+
else:
|
373
|
+
if i < other_pr:
|
374
|
+
alpha = (other._unscaled_moment(i) / a) % p ** (n - i)
|
375
|
+
else:
|
376
|
+
alpha = 0
|
377
|
+
verbose("alpha = %s" % alpha, level = 2)
|
378
|
+
# RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision
|
379
|
+
while i < other_pr - 1:
|
380
|
+
i += 1
|
381
|
+
verbose("comparing p moment %s" % i, level = 2)
|
382
|
+
a = self._unscaled_moment(i)
|
383
|
+
if check:
|
384
|
+
# verbose("self.moment=%s, other.moment=%s" % (a, other._unscaled_moment(i)))
|
385
|
+
if (padic and other._unscaled_moment(i) != alpha * a) or \
|
386
|
+
(not padic and other._unscaled_moment(i) % p ** (n - i) != alpha * a % p ** (n - i)):
|
387
|
+
raise ValueError("not a scalar multiple")
|
388
|
+
v = a.valuation(p)
|
389
|
+
if n - i - v > relprec:
|
390
|
+
verbose("Resetting alpha: relprec=%s, n-i=%s, v=%s" % (relprec, n - i, v), level = 2)
|
391
|
+
relprec = n - i - v
|
392
|
+
if padic:
|
393
|
+
alpha = (other._unscaled_moment(i) / a).add_bigoh(n - i)
|
394
|
+
else:
|
395
|
+
alpha = (other._unscaled_moment(i) / a) % p ** (n - i)
|
396
|
+
verbose("alpha=%s" % alpha, level = 2)
|
397
|
+
if relprec < M:
|
398
|
+
raise ValueError("result not determined to high enough precision")
|
399
|
+
alpha = alpha * self.parent().prime() ** (other.ordp - self.ordp)
|
400
|
+
verbose("alpha=%s" % alpha, level = 2)
|
401
|
+
try:
|
402
|
+
alpha = self.parent().base_ring()(alpha)
|
403
|
+
if M is not None:
|
404
|
+
alpha = alpha.add_bigoh(M)
|
405
|
+
except (ValueError, AttributeError):
|
406
|
+
pass
|
407
|
+
return alpha
|
408
|
+
|
409
|
+
def find_scalar_from_zeroth_moment(self, _other, p, M=None, check=True):
|
410
|
+
r"""
|
411
|
+
Return an ``alpha`` with ``other = self * alpha`` using only
|
412
|
+
the zeroth moment, or raises a :exc:`ValueError`.
|
413
|
+
|
414
|
+
It will also raise a :exc:`ValueError` if the zeroth moment of the
|
415
|
+
distribution is zero.
|
416
|
+
|
417
|
+
INPUT:
|
418
|
+
|
419
|
+
- ``other`` -- another distribution
|
420
|
+
|
421
|
+
- ``p`` -- an integral prime (only used if the parent is not a Symk)
|
422
|
+
|
423
|
+
- ``M`` -- (default: ``None``) an integer, the relative precision
|
424
|
+
to which the scalar must be determined
|
425
|
+
|
426
|
+
- ``check`` -- boolean (default: ``True``); whether to validate
|
427
|
+
that ``other`` is actually a multiple of this element
|
428
|
+
|
429
|
+
OUTPUT: a scalar ``alpha`` with ``other = self * alpha``
|
430
|
+
|
431
|
+
EXAMPLES::
|
432
|
+
|
433
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
434
|
+
sage: v = D([1,2,3,4,5])
|
435
|
+
sage: w = D([3,6,9,12,15])
|
436
|
+
sage: v.find_scalar_from_zeroth_moment(w,p=7)
|
437
|
+
3 + O(7^5)
|
438
|
+
sage: v.find_scalar_from_zeroth_moment(w,p=7,M=4)
|
439
|
+
3 + O(7^4)
|
440
|
+
|
441
|
+
sage: u = D([1,4,9,16,25])
|
442
|
+
sage: v.find_scalar_from_zeroth_moment(u,p=7)
|
443
|
+
Traceback (most recent call last):
|
444
|
+
...
|
445
|
+
ValueError: not a scalar multiple
|
446
|
+
"""
|
447
|
+
cdef Dist other = _other
|
448
|
+
n = self.precision_relative()
|
449
|
+
if n == 0:
|
450
|
+
raise ValueError("zeroth moment is zero")
|
451
|
+
verbose("n = %s" % n, level = 2)
|
452
|
+
a = self.moment(0)
|
453
|
+
if a.is_zero():
|
454
|
+
raise ValueError("zeroth moment is zero")
|
455
|
+
alpha = other.moment(0) / a
|
456
|
+
if check:
|
457
|
+
for i in range(1, n):
|
458
|
+
verbose("comparing moment %s" % i, level = 2)
|
459
|
+
if alpha * self.moment(i) != other.moment(i):
|
460
|
+
raise ValueError("not a scalar multiple")
|
461
|
+
alpha = self.parent().base_ring()(alpha)
|
462
|
+
if M is not None:
|
463
|
+
try:
|
464
|
+
absprec = alpha.precision_absolute()
|
465
|
+
if absprec < M:
|
466
|
+
raise ValueError("result not determined to high "
|
467
|
+
"enough precision")
|
468
|
+
verbose("alpha=%s" % (alpha), level = 2)
|
469
|
+
alpha = alpha.add_bigoh(M)
|
470
|
+
except AttributeError:
|
471
|
+
pass
|
472
|
+
return alpha
|
473
|
+
|
474
|
+
cpdef _richcmp_(_left, _right, int op):
|
475
|
+
r"""
|
476
|
+
Comparison.
|
477
|
+
|
478
|
+
EXAMPLES:
|
479
|
+
|
480
|
+
Equality of two distributions::
|
481
|
+
|
482
|
+
sage: D = OverconvergentDistributions(0, 5, 10)
|
483
|
+
sage: D([1, 2]) == D([1])
|
484
|
+
True
|
485
|
+
sage: D([1]) == D([1, 2])
|
486
|
+
True
|
487
|
+
sage: v = D([1+O(5^3),2+O(5^2),3+O(5)])
|
488
|
+
sage: w = D([1+O(5^2),2+O(5)])
|
489
|
+
sage: v == w
|
490
|
+
True
|
491
|
+
sage: D = Symk(0,Qp(5,5))
|
492
|
+
sage: v = 5 * D([4*5^-1+3+O(5^2)])
|
493
|
+
sage: w = D([4+3*5+O(5^2)])
|
494
|
+
sage: v == w
|
495
|
+
True
|
496
|
+
"""
|
497
|
+
cdef Dist left = _left
|
498
|
+
cdef Dist right = _right
|
499
|
+
left.normalize()
|
500
|
+
right.normalize()
|
501
|
+
cdef long rprec = min(left._relprec(), right._relprec())
|
502
|
+
cdef long i
|
503
|
+
p = left.parent().prime()
|
504
|
+
if left.ordp > right.ordp:
|
505
|
+
shift = p ** (left.ordp - right.ordp)
|
506
|
+
for i in range(rprec):
|
507
|
+
lx = shift * left._unscaled_moment(i)
|
508
|
+
rx = right._unscaled_moment(i)
|
509
|
+
if lx != rx:
|
510
|
+
return richcmp_not_equal(lx, rx, op)
|
511
|
+
elif left.ordp < right.ordp:
|
512
|
+
shift = p ** (right.ordp - left.ordp)
|
513
|
+
for i in range(rprec):
|
514
|
+
lx = left._unscaled_moment(i)
|
515
|
+
rx = shift * right._unscaled_moment(i)
|
516
|
+
if lx != rx:
|
517
|
+
return richcmp_not_equal(lx, rx, op)
|
518
|
+
else:
|
519
|
+
for i in range(rprec):
|
520
|
+
lx = left.moment(i)
|
521
|
+
rx = right.moment(i)
|
522
|
+
if lx != rx:
|
523
|
+
return richcmp_not_equal(lx, rx, op)
|
524
|
+
return rich_to_bool(op, 0)
|
525
|
+
|
526
|
+
def diagonal_valuation(self, p=None):
|
527
|
+
"""
|
528
|
+
Return the largest `m` so that this distribution lies in `Fil^m`.
|
529
|
+
|
530
|
+
INPUT:
|
531
|
+
|
532
|
+
- ``p`` -- (default: ``None``) a positive integral prime
|
533
|
+
|
534
|
+
OUTPUT:
|
535
|
+
|
536
|
+
The largest integer `m` so that `p^m` divides the `0`-th
|
537
|
+
moment, `p^{m-1}` divides the first moment, etc.
|
538
|
+
|
539
|
+
EXAMPLES::
|
540
|
+
|
541
|
+
sage: D = OverconvergentDistributions(8, 7, 15)
|
542
|
+
sage: v = D([7^(5-i) for i in range(1,5)])
|
543
|
+
sage: v
|
544
|
+
(O(7^4), O(7^3), O(7^2), O(7))
|
545
|
+
sage: v.diagonal_valuation(7)
|
546
|
+
4
|
547
|
+
"""
|
548
|
+
if p is None:
|
549
|
+
p = self.parent()._p
|
550
|
+
n = self.precision_relative()
|
551
|
+
return self.ordp + min([n] + [a + self._unscaled_moment(a).valuation(p) for a in range(n)])
|
552
|
+
|
553
|
+
def valuation(self, p=None):
|
554
|
+
"""
|
555
|
+
Return the minimum valuation of any moment.
|
556
|
+
|
557
|
+
INPUT:
|
558
|
+
|
559
|
+
- ``p`` -- (default: ``None``) a positive integral prime
|
560
|
+
|
561
|
+
OUTPUT: integer
|
562
|
+
|
563
|
+
.. WARNING::
|
564
|
+
|
565
|
+
Since only finitely many moments are computed, this valuation may
|
566
|
+
be larger than the actual valuation of this distribution.
|
567
|
+
Moreover, this valuation may be smaller than the actual
|
568
|
+
valuation if all entries are zero to the known precision.
|
569
|
+
|
570
|
+
EXAMPLES::
|
571
|
+
|
572
|
+
sage: D = OverconvergentDistributions(8, 7, 15)
|
573
|
+
sage: v = D([7^(5-i) for i in range(1,5)])
|
574
|
+
sage: v
|
575
|
+
(O(7^4), O(7^3), O(7^2), O(7))
|
576
|
+
sage: v.valuation(7)
|
577
|
+
4
|
578
|
+
"""
|
579
|
+
if p is None:
|
580
|
+
p = self.parent()._p
|
581
|
+
n = self.precision_relative()
|
582
|
+
if self.parent().is_symk():
|
583
|
+
return self.ordp + min([self._unscaled_moment(a).valuation(p) for a in range(n)])
|
584
|
+
else:
|
585
|
+
return self.ordp + min([n] + [self._unscaled_moment(a).valuation(p) for a in range(n) if not self._unscaled_moment(a).is_zero()])
|
586
|
+
|
587
|
+
def specialize(self, new_base_ring=None):
|
588
|
+
"""
|
589
|
+
Return the image of this overconvergent distribution under
|
590
|
+
the canonical projection from distributions of weight `k` to
|
591
|
+
`Sym^k`.
|
592
|
+
|
593
|
+
INPUT:
|
594
|
+
|
595
|
+
- ``new_base_ring`` -- (default: ``None``) a ring giving the
|
596
|
+
desired base ring of the result
|
597
|
+
|
598
|
+
OUTPUT:
|
599
|
+
|
600
|
+
An element of `Sym^k(K)`, where `K` is the specified base ring.
|
601
|
+
|
602
|
+
EXAMPLES::
|
603
|
+
|
604
|
+
sage: D = OverconvergentDistributions(4, 13)
|
605
|
+
sage: d = D([0,2,4,6,8,10,12])
|
606
|
+
sage: d.specialize()
|
607
|
+
(O(13^7), 2 + O(13^6), 4 + O(13^5), 6 + O(13^4), 8 + O(13^3))
|
608
|
+
"""
|
609
|
+
# self.normalize() # This method should not change self
|
610
|
+
k = self.parent()._k
|
611
|
+
if k < 0:
|
612
|
+
raise ValueError("negative weight")
|
613
|
+
if self.precision_absolute() < k + 1:
|
614
|
+
raise ValueError("not enough moments")
|
615
|
+
V = self.parent().specialize(new_base_ring)
|
616
|
+
new_base_ring = V.base_ring()
|
617
|
+
if self.precision_relative() == 0:
|
618
|
+
return V.zero()
|
619
|
+
return V([new_base_ring.coerce(self.moment(j)) for j in range(k + 1)])
|
620
|
+
|
621
|
+
def lift(self, p=None, M=None, new_base_ring=None):
|
622
|
+
r"""
|
623
|
+
Lift a distribution or element of `Sym^k` to an overconvergent distribution.
|
624
|
+
|
625
|
+
INPUT:
|
626
|
+
|
627
|
+
- ``p`` -- (default: ``None``) a positive integral prime. If ``None``
|
628
|
+
then ``p`` must be available in the parent
|
629
|
+
|
630
|
+
- ``M`` -- (default: ``None``) a positive integer giving the
|
631
|
+
desired number of moments. If ``None``, returns a distribution having one
|
632
|
+
more moment than this one.
|
633
|
+
|
634
|
+
- ``new_base_ring`` -- (default: ``None``) a ring giving the desired base
|
635
|
+
ring of the result. If ``None``, a base ring is chosen automatically.
|
636
|
+
|
637
|
+
OUTPUT:
|
638
|
+
|
639
|
+
- An overconvergent distribution with `M` moments whose image
|
640
|
+
under the specialization map is this element.
|
641
|
+
|
642
|
+
EXAMPLES::
|
643
|
+
|
644
|
+
sage: V = Symk(0)
|
645
|
+
sage: x = V(1/4)
|
646
|
+
sage: y = x.lift(17, 5)
|
647
|
+
sage: y
|
648
|
+
(13 + 12*17 + 12*17^2 + 12*17^3 + 12*17^4 + O(17^5), O(17^4), O(17^3), O(17^2), O(17))
|
649
|
+
sage: y.specialize()._moments == x._moments
|
650
|
+
True
|
651
|
+
"""
|
652
|
+
V = self.parent().lift(p, M, new_base_ring)
|
653
|
+
k = V._k
|
654
|
+
p = V.prime()
|
655
|
+
M = V.precision_cap()
|
656
|
+
R = V.base_ring()
|
657
|
+
moments = [R(self.moment(j)) for j in range(k + 1)]
|
658
|
+
zero = R(0)
|
659
|
+
moments.extend([zero] * (M - k - 1))
|
660
|
+
mu = V(moments)
|
661
|
+
# val = mu.valuation()
|
662
|
+
# if val < 0:
|
663
|
+
# # This seems unnatural
|
664
|
+
# print("scaling by ", p, "^", -val, " to keep things integral")
|
665
|
+
# mu *= p**(-val)
|
666
|
+
return mu
|
667
|
+
|
668
|
+
def _is_malformed(self):
|
669
|
+
r"""
|
670
|
+
Check that the precision of ``self`` is sensible.
|
671
|
+
|
672
|
+
EXAMPLES::
|
673
|
+
|
674
|
+
sage: D = sage.modular.pollack_stevens.distributions.Symk(2, base=Qp(5))
|
675
|
+
sage: v = D([1, 2, 3])
|
676
|
+
sage: v._is_malformed()
|
677
|
+
False
|
678
|
+
sage: v = D([1 + O(5), 2, 3])
|
679
|
+
sage: v._is_malformed()
|
680
|
+
True
|
681
|
+
"""
|
682
|
+
n = self.precision_absolute()
|
683
|
+
for i in range(n):
|
684
|
+
if self.moment(i).precision_absolute() < n - i:
|
685
|
+
return True
|
686
|
+
return False
|
687
|
+
|
688
|
+
def act_right(self, gamma):
|
689
|
+
r"""
|
690
|
+
The image of this element under the right action by a
|
691
|
+
`2 \times 2` matrix.
|
692
|
+
|
693
|
+
INPUT:
|
694
|
+
|
695
|
+
- ``gamma`` -- the matrix by which to act
|
696
|
+
|
697
|
+
OUTPUT:
|
698
|
+
|
699
|
+
- ``self | gamma``
|
700
|
+
|
701
|
+
.. NOTE::
|
702
|
+
|
703
|
+
You may also just use multiplication ``self * gamma``.
|
704
|
+
|
705
|
+
EXAMPLES::
|
706
|
+
|
707
|
+
sage: D = OverconvergentDistributions(4, 7, 10)
|
708
|
+
sage: v = D([98,49,21,28,35])
|
709
|
+
sage: M = matrix([[1,0], [7,1]])
|
710
|
+
sage: v.act_right(M)
|
711
|
+
(2*7^2 + 7^3 + 5*7^4 + O(7^5), 3*7^2 + 6*7^3 + O(7^4), 3*7 + 7^2 + O(7^3), 4*7 + O(7^2), O(7))
|
712
|
+
"""
|
713
|
+
return self.parent()._act(self, gamma)
|
714
|
+
|
715
|
+
cdef class Dist_vector(Dist):
|
716
|
+
r"""
|
717
|
+
A distribution is stored as a vector whose `j`-th entry is the `j`-th moment of the distribution.
|
718
|
+
|
719
|
+
The `j`-th entry is stored modulo `p^{N-j}` where `N` is the total number of moments.
|
720
|
+
(This is the accuracy that is maintained after acting by `\Gamma_0(p)`.)
|
721
|
+
|
722
|
+
INPUT:
|
723
|
+
|
724
|
+
- ``moments`` -- the list of moments. If ``check == False`` it
|
725
|
+
must be a vector in the appropriate approximation module.
|
726
|
+
|
727
|
+
- ``parent`` -- a :class:`distributions.OverconvergentDistributions_class` or
|
728
|
+
:class:`distributions.Symk_class` instance
|
729
|
+
|
730
|
+
- ``ordp`` -- integer; this *must* be zero in the case of Symk
|
731
|
+
of an exact ring
|
732
|
+
|
733
|
+
- ``check`` -- boolean (default: ``True``); whether to validate input
|
734
|
+
|
735
|
+
EXAMPLES::
|
736
|
+
|
737
|
+
sage: D = OverconvergentDistributions(3,5,6) # indirect doctest
|
738
|
+
sage: v = D([1,1,1])
|
739
|
+
"""
|
740
|
+
def __init__(self, moments, parent, ordp=0, check=True, normalize=True):
|
741
|
+
"""
|
742
|
+
Initialization.
|
743
|
+
|
744
|
+
TESTS::
|
745
|
+
|
746
|
+
sage: Symk(4)(0)
|
747
|
+
(0, 0, 0, 0, 0)
|
748
|
+
"""
|
749
|
+
# if not hasattr(parent,'Element'):
|
750
|
+
# parent, moments = moments, parent
|
751
|
+
|
752
|
+
Dist.__init__(self, parent)
|
753
|
+
if check:
|
754
|
+
# case 1: input is a distribution already
|
755
|
+
if isinstance(moments, Dist):
|
756
|
+
ordp = moments._ord_p()
|
757
|
+
moments = moments._moments.change_ring(parent.base_ring())
|
758
|
+
# case 2: input is a vector, or something with a len
|
759
|
+
elif hasattr(moments, '__len__'):
|
760
|
+
M = len(moments)
|
761
|
+
moments = parent.approx_module(M)(moments)
|
762
|
+
# case 3: input is zero
|
763
|
+
elif moments == 0:
|
764
|
+
moments = parent.approx_module(parent.precision_cap())(moments)
|
765
|
+
# case 4: everything else
|
766
|
+
else:
|
767
|
+
moments = parent.approx_module(1)([moments])
|
768
|
+
# TODO: This is not quite right if the input is an inexact zero.
|
769
|
+
if ordp != 0 and parent.prime() == 0:
|
770
|
+
raise ValueError("cannot specify a valuation shift for an exact ring")
|
771
|
+
|
772
|
+
self._moments = moments
|
773
|
+
self.ordp = ordp
|
774
|
+
if normalize:
|
775
|
+
self.normalize()
|
776
|
+
|
777
|
+
def __reduce__(self):
|
778
|
+
r"""
|
779
|
+
Used for pickling.
|
780
|
+
|
781
|
+
EXAMPLES::
|
782
|
+
|
783
|
+
sage: D = sage.modular.pollack_stevens.distributions.Symk(2)
|
784
|
+
sage: x = D([2,3,4])
|
785
|
+
sage: x.__reduce__()
|
786
|
+
(<class 'sage.modular.pollack_stevens.dist.Dist_vector'>, ((2, 3, 4), Sym^2 Q^2, 0, False))
|
787
|
+
"""
|
788
|
+
return (self.__class__, (self._moments, self.parent(), self.ordp, False))
|
789
|
+
|
790
|
+
cdef Dist_vector _new_c(self):
|
791
|
+
r"""
|
792
|
+
Create an empty distribution.
|
793
|
+
|
794
|
+
Note that you MUST fill in the ordp attribute on the resulting distribution.
|
795
|
+
|
796
|
+
OUTPUT:
|
797
|
+
|
798
|
+
- A distribution with no moments. The moments are then filled
|
799
|
+
in by the calling function.
|
800
|
+
|
801
|
+
EXAMPLES::
|
802
|
+
|
803
|
+
sage: D = OverconvergentDistributions(3,5,4) # indirect doctest
|
804
|
+
sage: v = D([1,1,1])
|
805
|
+
"""
|
806
|
+
cdef Dist_vector ans = Dist_vector.__new__(Dist_vector)
|
807
|
+
ans._parent = self._parent
|
808
|
+
return ans
|
809
|
+
|
810
|
+
def _repr_(self):
|
811
|
+
r"""
|
812
|
+
String representation.
|
813
|
+
|
814
|
+
EXAMPLES::
|
815
|
+
|
816
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
817
|
+
sage: v = D([1,2,3,4,5]); v
|
818
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
819
|
+
sage: repr(v)
|
820
|
+
'(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))'
|
821
|
+
"""
|
822
|
+
valstr = ""
|
823
|
+
if self.ordp == 1:
|
824
|
+
valstr = "%s * " % (self.parent().prime())
|
825
|
+
elif self.ordp != 0:
|
826
|
+
valstr = "%s^%s * " % (self.parent().prime(), self.ordp)
|
827
|
+
if len(self._moments) == 1:
|
828
|
+
return valstr + repr(self._moments[0])
|
829
|
+
else:
|
830
|
+
return valstr + repr(self._moments)
|
831
|
+
|
832
|
+
def _rational_(self):
|
833
|
+
"""
|
834
|
+
Convert to a rational number.
|
835
|
+
|
836
|
+
EXAMPLES::
|
837
|
+
|
838
|
+
sage: D = Symk(0); d = D(4/3); d
|
839
|
+
4/3
|
840
|
+
sage: QQ(d)
|
841
|
+
4/3
|
842
|
+
|
843
|
+
We get a :exc:`TypeError` if there is more than 1 moment::
|
844
|
+
|
845
|
+
sage: D = Symk(1); d = D([1,2]); d
|
846
|
+
(1, 2)
|
847
|
+
sage: QQ(d)
|
848
|
+
Traceback (most recent call last):
|
849
|
+
...
|
850
|
+
TypeError: k must be 0
|
851
|
+
"""
|
852
|
+
if len(self._moments) == 1:
|
853
|
+
return QQ(self.moment(0))
|
854
|
+
raise TypeError("k must be 0")
|
855
|
+
|
856
|
+
cdef long _relprec(self) noexcept:
|
857
|
+
"""
|
858
|
+
Return the number of moments.
|
859
|
+
|
860
|
+
EXAMPLES::
|
861
|
+
|
862
|
+
sage: D = Symk(4)
|
863
|
+
sage: d = D([1,2,3,4,5]); e = D([2,3,4,5,6])
|
864
|
+
sage: d == e # indirect doctest
|
865
|
+
False
|
866
|
+
"""
|
867
|
+
return len(self._moments)
|
868
|
+
|
869
|
+
cdef _unscaled_moment(self, long n):
|
870
|
+
r"""
|
871
|
+
Return the `n`-th moment, unscaled by the overall power of `p`
|
872
|
+
stored in ``self.ordp``.
|
873
|
+
|
874
|
+
EXAMPLES::
|
875
|
+
|
876
|
+
sage: D = OverconvergentDistributions(4,3,5)
|
877
|
+
sage: d = D([3,3,3,3,3])
|
878
|
+
sage: d.moment(2) # indirect doctest
|
879
|
+
3 + O(3^3)
|
880
|
+
"""
|
881
|
+
return self._moments[n]
|
882
|
+
|
883
|
+
cdef Dist_vector _addsub(self, Dist_vector right, bint negate):
|
884
|
+
r"""
|
885
|
+
Common code for the sum and the difference of two distributions.
|
886
|
+
|
887
|
+
EXAMPLES::
|
888
|
+
|
889
|
+
sage: D = Symk(2)
|
890
|
+
sage: u = D([1,2,3]); v = D([4,5,6])
|
891
|
+
sage: u + v # indirect doctest
|
892
|
+
(5, 7, 9)
|
893
|
+
sage: u - v # indirect doctest
|
894
|
+
(-3, -3, -3)
|
895
|
+
"""
|
896
|
+
cdef Dist_vector ans = self._new_c()
|
897
|
+
cdef long aprec = min(self.ordp + len(self._moments), right.ordp + len(right._moments))
|
898
|
+
ans.ordp = min(self.ordp, right.ordp)
|
899
|
+
cdef long rprec = aprec - ans.ordp
|
900
|
+
# In the case of symk, rprec will always be k
|
901
|
+
V = ans.parent().approx_module(rprec)
|
902
|
+
R = V.base_ring()
|
903
|
+
smoments = self._moments
|
904
|
+
rmoments = right._moments
|
905
|
+
# We truncate if the moments are too long; extend by zero if too short
|
906
|
+
if smoments.parent() is not V:
|
907
|
+
vec = smoments.list(copy=False)[:rprec] + ([R(0)] * (rprec - len(smoments)) if rprec > len(smoments) else [])
|
908
|
+
smoments = V(vec)
|
909
|
+
if rmoments.parent() is not V:
|
910
|
+
vec = rmoments.list(copy=False)[:rprec] + ([R(0)] * (rprec - len(rmoments)) if rprec > len(rmoments) else [])
|
911
|
+
rmoments = V(vec)
|
912
|
+
# We multiply by the relative power of p
|
913
|
+
if self.ordp > right.ordp:
|
914
|
+
smoments *= self.parent().prime() ** (self.ordp - right.ordp)
|
915
|
+
elif self.ordp < right.ordp:
|
916
|
+
rmoments *= self.parent().prime() ** (right.ordp - self.ordp)
|
917
|
+
if negate:
|
918
|
+
rmoments = -rmoments
|
919
|
+
ans._moments = smoments + rmoments
|
920
|
+
return ans
|
921
|
+
|
922
|
+
cpdef _add_(self, _right):
|
923
|
+
r"""
|
924
|
+
Sum of two distributions.
|
925
|
+
|
926
|
+
EXAMPLES::
|
927
|
+
|
928
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
929
|
+
sage: v = D([1,2,3,4,5]); w = D([3,6,9,12,15])
|
930
|
+
sage: v+w
|
931
|
+
(4 + O(7^5), 1 + 7 + O(7^4), 5 + 7 + O(7^3), 2 + 2*7 + O(7^2), 6 + O(7))
|
932
|
+
"""
|
933
|
+
return self._addsub(<Dist_vector>_right, False)
|
934
|
+
|
935
|
+
cpdef _sub_(self, _right):
|
936
|
+
r"""
|
937
|
+
Difference of two distributions.
|
938
|
+
|
939
|
+
EXAMPLES::
|
940
|
+
|
941
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
942
|
+
sage: v = D([1,2,3,4,5]); w = D([1,1,1,8,8])
|
943
|
+
sage: v-w
|
944
|
+
(O(7^5), 1 + O(7^4), 2 + O(7^3), 3 + 6*7 + O(7^2), 4 + O(7))
|
945
|
+
"""
|
946
|
+
return self._addsub(<Dist_vector>_right, True)
|
947
|
+
|
948
|
+
cpdef _lmul_(self, Element right):
|
949
|
+
r"""
|
950
|
+
Scalar product of a distribution with a ring element that coerces into the base ring.
|
951
|
+
|
952
|
+
EXAMPLES::
|
953
|
+
|
954
|
+
sage: D = OverconvergentDistributions(5, 7, 15)
|
955
|
+
sage: v = D([1,2,3,4,5]); v
|
956
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
957
|
+
sage: 3*v; 7*v
|
958
|
+
(3 + O(7^5), 6 + O(7^4), 2 + 7 + O(7^3), 5 + 7 + O(7^2), 1 + O(7))
|
959
|
+
7 * (1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
960
|
+
sage: v*3; v*7
|
961
|
+
(3 + O(7^5), 6 + O(7^4), 2 + 7 + O(7^3), 5 + 7 + O(7^2), 1 + O(7))
|
962
|
+
7 * (1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
963
|
+
"""
|
964
|
+
cdef Dist_vector ans = self._new_c()
|
965
|
+
p = self.parent().prime()
|
966
|
+
if p == 0:
|
967
|
+
ans._moments = self._moments * right
|
968
|
+
ans.ordp = self.ordp
|
969
|
+
elif right.valuation(p) == Infinity:
|
970
|
+
ans._moments = self.parent().approx_module(0)([])
|
971
|
+
ans.ordp += self.precision_relative()
|
972
|
+
else:
|
973
|
+
try:
|
974
|
+
v, u = right.val_unit(p)
|
975
|
+
except TypeError: # bug in p-adics: they should accept p here
|
976
|
+
v, u = right.val_unit()
|
977
|
+
ans._moments = self._moments * u
|
978
|
+
ans.ordp = self.ordp + v
|
979
|
+
# if the relative precision of u is less than that of self, ans may not be normalized.
|
980
|
+
return ans
|
981
|
+
|
982
|
+
def precision_relative(self):
|
983
|
+
r"""
|
984
|
+
Return the relative precision of this distribution.
|
985
|
+
|
986
|
+
The precision is just the number of moments stored, which is
|
987
|
+
also `k+1` in the case of `Sym^k(R)`. For overconvergent
|
988
|
+
distributions, the precision is the integer `m` so that the
|
989
|
+
sequence of moments is known modulo `Fil^m`.
|
990
|
+
|
991
|
+
OUTPUT: integer giving the number of moments
|
992
|
+
|
993
|
+
EXAMPLES::
|
994
|
+
|
995
|
+
sage: D = OverconvergentDistributions(2, 11, 15)
|
996
|
+
sage: v = D([1,1,10,9,6,15])
|
997
|
+
sage: v.precision_relative()
|
998
|
+
6
|
999
|
+
sage: v = v.reduce_precision(4); v.precision_relative()
|
1000
|
+
4
|
1001
|
+
sage: D = Symk(10)
|
1002
|
+
sage: v = D.random_element()
|
1003
|
+
sage: v.precision_relative()
|
1004
|
+
11
|
1005
|
+
"""
|
1006
|
+
return Integer(len(self._moments))
|
1007
|
+
|
1008
|
+
def precision_absolute(self):
|
1009
|
+
r"""
|
1010
|
+
Return the absolute precision of this distribution.
|
1011
|
+
|
1012
|
+
The absolute precision is the sum of the relative precision
|
1013
|
+
(number of moments) and the valuation.
|
1014
|
+
|
1015
|
+
EXAMPLES::
|
1016
|
+
|
1017
|
+
sage: D = OverconvergentDistributions(3, 7, base = Qp(7))
|
1018
|
+
sage: v = D([3,1,10,0])
|
1019
|
+
sage: v.precision_absolute()
|
1020
|
+
4
|
1021
|
+
sage: v *= 7
|
1022
|
+
sage: v.precision_absolute()
|
1023
|
+
5
|
1024
|
+
sage: v = 1/7^10 * v
|
1025
|
+
sage: v.precision_absolute()
|
1026
|
+
-5
|
1027
|
+
"""
|
1028
|
+
return Integer(len(self._moments) + self.ordp)
|
1029
|
+
|
1030
|
+
cpdef normalize(self, include_zeroth_moment=True):
|
1031
|
+
r"""
|
1032
|
+
Normalize by reducing modulo `Fil^N`, where `N` is the number of moments.
|
1033
|
+
|
1034
|
+
If the parent is Symk, then normalize has no effect. If the
|
1035
|
+
parent is a space of distributions, then normalize reduces the
|
1036
|
+
`i`-th moment modulo `p^{N-i}`.
|
1037
|
+
|
1038
|
+
OUTPUT: this distribution, after normalizing
|
1039
|
+
|
1040
|
+
.. WARNING::
|
1041
|
+
|
1042
|
+
This function modifies the distribution in place as well as returning it.
|
1043
|
+
|
1044
|
+
EXAMPLES::
|
1045
|
+
|
1046
|
+
sage: D = OverconvergentDistributions(3,7,10)
|
1047
|
+
sage: v = D([1,2,3,4,5]) ; v
|
1048
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
1049
|
+
sage: w = v.reduce_precision(3) ; w
|
1050
|
+
(1 + O(7^5), 2 + O(7^4), 3 + O(7^3))
|
1051
|
+
sage: w.normalize()
|
1052
|
+
(1 + O(7^3), 2 + O(7^2), 3 + O(7))
|
1053
|
+
sage: w
|
1054
|
+
(1 + O(7^3), 2 + O(7^2), 3 + O(7))
|
1055
|
+
sage: v.reduce_precision(3).normalize(include_zeroth_moment=False)
|
1056
|
+
(1 + O(7^5), 2 + O(7^2), 3 + O(7))
|
1057
|
+
"""
|
1058
|
+
if not self.parent().is_symk() and self._moments != 0: # non-classical
|
1059
|
+
if not self._moments:
|
1060
|
+
return self
|
1061
|
+
V = self._moments.parent()
|
1062
|
+
R = V.base_ring()
|
1063
|
+
n = self.precision_relative()
|
1064
|
+
p = self.parent()._p
|
1065
|
+
shift = self.ordp
|
1066
|
+
if include_zeroth_moment:
|
1067
|
+
if isinstance(R, pAdicGeneric):
|
1068
|
+
self._moments = V([self._moments[i].add_bigoh(n -shift - i) for i in range(n)])
|
1069
|
+
else:
|
1070
|
+
self._moments = V([self._moments[i] % (p ** (n -shift - i)) for i in range(n)])
|
1071
|
+
else:
|
1072
|
+
if isinstance(R, pAdicGeneric):
|
1073
|
+
self._moments = V([self._moments[0]] + [self._moments[i].add_bigoh(n -shift - i) for i in range(1, n)]) # Don't normalize the zeroth moment
|
1074
|
+
else:
|
1075
|
+
self._moments = V([self._moments[0]] + [self._moments[i] % (p ** (n -shift- i)) for i in range(1, n)]) # Don't normalize the zeroth moment
|
1076
|
+
return self
|
1077
|
+
|
1078
|
+
def reduce_precision(self, M):
|
1079
|
+
r"""
|
1080
|
+
Only hold on to `M` moments.
|
1081
|
+
|
1082
|
+
INPUT:
|
1083
|
+
|
1084
|
+
- ``M`` -- positive integer less than the precision of this
|
1085
|
+
distribution
|
1086
|
+
|
1087
|
+
OUTPUT:
|
1088
|
+
|
1089
|
+
- a new distribution with `M` moments equal to the first `M`
|
1090
|
+
moments of this distribution.
|
1091
|
+
|
1092
|
+
EXAMPLES::
|
1093
|
+
|
1094
|
+
sage: D = OverconvergentDistributions(3,7,10)
|
1095
|
+
sage: v = D([3,4,5])
|
1096
|
+
sage: v
|
1097
|
+
(3 + O(7^3), 4 + O(7^2), 5 + O(7))
|
1098
|
+
sage: v.reduce_precision(2)
|
1099
|
+
(3 + O(7^3), 4 + O(7^2))
|
1100
|
+
"""
|
1101
|
+
assert M <= self.precision_relative(), "not enough moments"
|
1102
|
+
|
1103
|
+
cdef Dist_vector ans = self._new_c()
|
1104
|
+
ans._moments = self._moments[:M]
|
1105
|
+
ans.ordp = self.ordp
|
1106
|
+
return ans
|
1107
|
+
|
1108
|
+
def solve_difference_equation(self):
|
1109
|
+
r"""
|
1110
|
+
Solve the difference equation. `self = v | \Delta`, where `\Delta = [1, 1; 0, 1] - 1`.
|
1111
|
+
|
1112
|
+
See Theorem 4.5 and Lemma 4.4 of [PS2011]_.
|
1113
|
+
|
1114
|
+
OUTPUT:
|
1115
|
+
|
1116
|
+
- a distribution `v` so that `self = v | Delta` , assuming ``self.moment(0) == 0``.
|
1117
|
+
Otherwise solves the difference equation for ``self - (self.moment(0),0,...,0)``.
|
1118
|
+
|
1119
|
+
EXAMPLES::
|
1120
|
+
|
1121
|
+
sage: D = OverconvergentDistributions(5,7,15)
|
1122
|
+
sage: v = D(([0,2,3,4,5]))
|
1123
|
+
sage: g = D._act.actor()(Matrix(ZZ,2,2,[1,1,0,1]))
|
1124
|
+
sage: w = v.solve_difference_equation()
|
1125
|
+
sage: v - (w*g - w)
|
1126
|
+
(O(7^4), O(7^3), O(7^2), O(7))
|
1127
|
+
sage: v = D(([7,2,3,4,5]))
|
1128
|
+
sage: w = v.solve_difference_equation()
|
1129
|
+
sage: v - (w*g - w)
|
1130
|
+
(7 + O(7^4), O(7^3), O(7^2), O(7))
|
1131
|
+
"""
|
1132
|
+
# assert self._moments[0][0]==0, "not total measure zero"
|
1133
|
+
# print("result accurate modulo p^",self.moment(0).valuation(self.p) )
|
1134
|
+
# v=[0 for j in range(i)]+[binomial(j,i)*bernoulli(j-i) for j in range(i,M)]
|
1135
|
+
M = self.precision_relative()
|
1136
|
+
R = self.parent().base_ring()
|
1137
|
+
K = R.fraction_field()
|
1138
|
+
V = self._moments.parent()
|
1139
|
+
v = [K(0) for i in range(M)]
|
1140
|
+
bern = [bernoulli(i) for i in range(0, M, 2)]
|
1141
|
+
minhalf = ~K(-2)
|
1142
|
+
for m in range(1, M):
|
1143
|
+
scalar = K(self.moment(m) / m)
|
1144
|
+
# bernoulli(1) = -1/2; the only nonzero odd Bernoulli number
|
1145
|
+
v[m] += m * minhalf * scalar
|
1146
|
+
for j in range(m - 1, M, 2):
|
1147
|
+
v[j] += ZZ(j).binomial(m - 1) * bern[(j - m + 1) // 2] * scalar
|
1148
|
+
p = self.parent().prime()
|
1149
|
+
cdef Dist_vector ans
|
1150
|
+
if p == 0:
|
1151
|
+
if R in Fields():
|
1152
|
+
ans = self._new_c()
|
1153
|
+
ans.ordp = 0
|
1154
|
+
ans._moments = V(v)
|
1155
|
+
else:
|
1156
|
+
newparent = self.parent().change_ring(K)
|
1157
|
+
ans = newparent(v)
|
1158
|
+
else:
|
1159
|
+
ans = self._new_c()
|
1160
|
+
try:
|
1161
|
+
ans.ordp = min(a.valuation(p) for a in v)
|
1162
|
+
except TypeError:
|
1163
|
+
ans.ordp = 0
|
1164
|
+
if ans.ordp < 0:
|
1165
|
+
scalar = K(p) ** (-ans.ordp)
|
1166
|
+
ans._moments = V([R(a * scalar) for a in v])
|
1167
|
+
elif ans.ordp > 0:
|
1168
|
+
scalar = K(p) ** ans.ordp
|
1169
|
+
ans._moments = V([R(a // scalar) for a in v])
|
1170
|
+
else:
|
1171
|
+
ans._moments = V([R(a) for a in v])
|
1172
|
+
v = ans._moments
|
1173
|
+
N = len(ans._moments)
|
1174
|
+
prec_loss = max([N - j - v[j].precision_absolute()
|
1175
|
+
for j in range(N)])
|
1176
|
+
# print("precision loss = ", prec_loss)
|
1177
|
+
if prec_loss > 0:
|
1178
|
+
ans._moments = ans._moments[:(N - prec_loss)]
|
1179
|
+
return ans
|
1180
|
+
|
1181
|
+
|
1182
|
+
cdef class WeightKAction(Action):
|
1183
|
+
r"""
|
1184
|
+
Encode the action of the monoid `\Sigma_0(N)` on the space of distributions.
|
1185
|
+
|
1186
|
+
INPUT:
|
1187
|
+
|
1188
|
+
- ``Dk`` -- a space of distributions
|
1189
|
+
- ``character`` -- data specifying a Dirichlet character to apply to
|
1190
|
+
the top right corner, and a power of the determinant by which to scale.
|
1191
|
+
See the documentation of
|
1192
|
+
:class:`sage.modular.pollack_stevens.distributions.OverconvergentDistributions_factory`
|
1193
|
+
for more details.
|
1194
|
+
- ``adjuster`` -- a callable object that turns matrices into 4-tuples
|
1195
|
+
- ``on_left`` -- whether this action should be on the left
|
1196
|
+
- ``dettwist`` -- a power of the determinant to twist by
|
1197
|
+
- ``padic`` -- if ``True``, define an action of `p`-adic matrices (not just integer ones)
|
1198
|
+
|
1199
|
+
EXAMPLES::
|
1200
|
+
|
1201
|
+
sage: D = OverconvergentDistributions(4,5,10,base = Qp(5,20)); D
|
1202
|
+
Space of 5-adic distributions with k=4 action and precision cap 10
|
1203
|
+
sage: D._act
|
1204
|
+
Right action by Monoid Sigma0(5) with coefficients in 5-adic Field with capped relative precision 20 on Space of 5-adic distributions with k=4 action and precision cap 10
|
1205
|
+
"""
|
1206
|
+
def __init__(self, Dk, character, adjuster, on_left, dettwist, padic=False):
|
1207
|
+
r"""
|
1208
|
+
Initialization.
|
1209
|
+
|
1210
|
+
TESTS::
|
1211
|
+
|
1212
|
+
sage: D = OverconvergentDistributions(4,5,10,base = Qp(5,20)); D # indirect doctest
|
1213
|
+
Space of 5-adic distributions with k=4 action and precision cap 10
|
1214
|
+
sage: D = Symk(10) # indirect doctest
|
1215
|
+
"""
|
1216
|
+
self._k = Dk._k
|
1217
|
+
# if self._k < 0: raise ValueError("k must not be negative")
|
1218
|
+
self._adjuster = adjuster
|
1219
|
+
self._character = character
|
1220
|
+
self._dettwist = dettwist
|
1221
|
+
self._p = Dk._p
|
1222
|
+
self._symk = Dk.is_symk()
|
1223
|
+
self._actmat = {}
|
1224
|
+
self._maxprecs = {}
|
1225
|
+
if character is None:
|
1226
|
+
self._Np = ZZ(1) # all of M2Z acts
|
1227
|
+
else:
|
1228
|
+
self._Np = character.modulus()
|
1229
|
+
if not self._symk:
|
1230
|
+
self._Np = self._Np.lcm(self._p)
|
1231
|
+
|
1232
|
+
if padic:
|
1233
|
+
self._Sigma0 = Sigma0(self._Np, base_ring=Dk.base_ring(), adjuster=self._adjuster)
|
1234
|
+
else:
|
1235
|
+
self._Sigma0 = Sigma0(self._Np, base_ring=ZZ, adjuster=self._adjuster)
|
1236
|
+
Action.__init__(self, self._Sigma0, Dk, on_left, operator.mul)
|
1237
|
+
|
1238
|
+
def clear_cache(self):
|
1239
|
+
r"""
|
1240
|
+
Clear the cached matrices which define the action of `U_p`
|
1241
|
+
(these depend on the desired precision) and the
|
1242
|
+
dictionary that stores the maximum precisions computed so far.
|
1243
|
+
|
1244
|
+
EXAMPLES::
|
1245
|
+
|
1246
|
+
sage: D = OverconvergentDistributions(4,5,4)
|
1247
|
+
sage: D([1,2,5,3]) * D._act.actor()(Matrix(ZZ,2,2,[1,1,0,1]))
|
1248
|
+
(1 + O(5^4), 3 + O(5^3), 2*5 + O(5^2), O(5))
|
1249
|
+
sage: D._act.clear_cache()
|
1250
|
+
"""
|
1251
|
+
self._actmat = {}
|
1252
|
+
self._maxprecs = {}
|
1253
|
+
|
1254
|
+
cpdef acting_matrix(self, g, M):
|
1255
|
+
r"""
|
1256
|
+
The matrix defining the action of ``g`` at precision ``M``.
|
1257
|
+
|
1258
|
+
INPUT:
|
1259
|
+
|
1260
|
+
- ``g`` -- an instance of
|
1261
|
+
:class:`sage.matrix.matrix_generic_dense.Matrix_generic_dense`
|
1262
|
+
|
1263
|
+
- ``M`` -- positive integer giving the precision at which
|
1264
|
+
``g`` should act
|
1265
|
+
|
1266
|
+
OUTPUT:
|
1267
|
+
|
1268
|
+
- An `M \times M` matrix so that the action of `g` on a
|
1269
|
+
distribution with `M` moments is given by a vector-matrix
|
1270
|
+
multiplication.
|
1271
|
+
|
1272
|
+
.. NOTE::
|
1273
|
+
|
1274
|
+
This function caches its results. To clear the cache use
|
1275
|
+
:meth:`clear_cache`.
|
1276
|
+
|
1277
|
+
EXAMPLES::
|
1278
|
+
|
1279
|
+
sage: D = Symk(3)
|
1280
|
+
sage: v = D([5,2,7,1])
|
1281
|
+
sage: g = Matrix(ZZ,2,2,[1,3,0,1])
|
1282
|
+
sage: v * D._act.actor()(g) # indirect doctest
|
1283
|
+
(5, 17, 64, 253)
|
1284
|
+
"""
|
1285
|
+
g = g.matrix()
|
1286
|
+
if g not in self._maxprecs:
|
1287
|
+
A = self._compute_acting_matrix(g, M)
|
1288
|
+
self._actmat[g] = {M: A}
|
1289
|
+
self._maxprecs[g] = M
|
1290
|
+
return A
|
1291
|
+
else:
|
1292
|
+
mats = self._actmat[g]
|
1293
|
+
if M in mats:
|
1294
|
+
return mats[M]
|
1295
|
+
maxprec = self._maxprecs[g]
|
1296
|
+
if M < maxprec:
|
1297
|
+
A = mats[maxprec][:M, :M] # submatrix; might want to reduce precisions
|
1298
|
+
mats[M] = A
|
1299
|
+
return A
|
1300
|
+
if M < 30: # This should not be hard-coded
|
1301
|
+
maxprec = max([M, 2 * maxprec]) # This may be wasting memory
|
1302
|
+
else:
|
1303
|
+
maxprec = M
|
1304
|
+
self._maxprecs[g] = maxprec
|
1305
|
+
mats[maxprec] = self._compute_acting_matrix(g, maxprec) # could lift from current maxprec
|
1306
|
+
if M == maxprec:
|
1307
|
+
return mats[maxprec]
|
1308
|
+
A = mats[maxprec][:M, :M] # submatrix; might want to reduce precisions
|
1309
|
+
mats[M] = A
|
1310
|
+
return A
|
1311
|
+
|
1312
|
+
cpdef _compute_acting_matrix(self, g, M):
|
1313
|
+
r"""
|
1314
|
+
Compute the matrix defining the action of ``g`` at precision ``M``.
|
1315
|
+
|
1316
|
+
INPUT:
|
1317
|
+
|
1318
|
+
- ``g`` -- a `2 \times 2` instance of
|
1319
|
+
:class:`sage.matrices.matrix_integer_dense.Matrix_integer_dense`
|
1320
|
+
|
1321
|
+
- ``M`` -- positive integer giving the precision at which
|
1322
|
+
``g`` should act
|
1323
|
+
|
1324
|
+
OUTPUT:
|
1325
|
+
|
1326
|
+
- ``G`` -- an `M \times M` matrix. If `v `is the vector of moments of a
|
1327
|
+
distribution `\mu`, then `v*G` is the vector of moments of `\mu|[a,b;c,d]`
|
1328
|
+
|
1329
|
+
EXAMPLES::
|
1330
|
+
|
1331
|
+
sage: D = Symk(3)
|
1332
|
+
sage: v = D([5,2,7,1])
|
1333
|
+
sage: g = Matrix(ZZ,2,2,[-2,1,-1,0])
|
1334
|
+
sage: v * D._act.actor()(g) # indirect doctest
|
1335
|
+
(-107, 35, -12, 5)
|
1336
|
+
"""
|
1337
|
+
raise NotImplementedError
|
1338
|
+
|
1339
|
+
|
1340
|
+
cdef class WeightKAction_vector(WeightKAction):
|
1341
|
+
cpdef _compute_acting_matrix(self, g, M):
|
1342
|
+
r"""
|
1343
|
+
Compute the matrix defining the action of ``g`` at precision ``M``.
|
1344
|
+
|
1345
|
+
INPUT:
|
1346
|
+
|
1347
|
+
- ``g`` -- a `2 \times 2` instance of
|
1348
|
+
:class:`sage.matrix.matrix_generic_dense.Matrix_generic_dense`
|
1349
|
+
|
1350
|
+
- ``M`` -- positive integer giving the precision at which
|
1351
|
+
``g`` should act
|
1352
|
+
|
1353
|
+
OUTPUT:
|
1354
|
+
|
1355
|
+
- ``G`` -- an `M \times M` matrix. If `v` is the vector of moments of a
|
1356
|
+
distribution `\mu`, then `v*G` is the vector of moments of `\mu|[a,b;c,d]`
|
1357
|
+
|
1358
|
+
EXAMPLES::
|
1359
|
+
|
1360
|
+
sage: D = Symk(3)
|
1361
|
+
sage: v = D([5,2,7,1])
|
1362
|
+
sage: g = Matrix(ZZ,2,2,[-2,1,-1,0])
|
1363
|
+
sage: v * D._act.actor()(g) # indirect doctest
|
1364
|
+
(-107, 35, -12, 5)
|
1365
|
+
"""
|
1366
|
+
# tim = verbose("Starting")
|
1367
|
+
a, b, c, d = self._adjuster(g)
|
1368
|
+
# if g.parent().base_ring().is_exact():
|
1369
|
+
# self._check_mat(a, b, c, d)
|
1370
|
+
k = self._k
|
1371
|
+
if g.parent().base_ring() is ZZ:
|
1372
|
+
if self._symk:
|
1373
|
+
base_ring = QQ
|
1374
|
+
else:
|
1375
|
+
base_ring = Zmod(self._p ** M)
|
1376
|
+
else:
|
1377
|
+
base_ring = self.underlying_set().base_ring()
|
1378
|
+
cdef Matrix B = matrix(base_ring, M, M)
|
1379
|
+
if M == 0:
|
1380
|
+
return B.change_ring(self.codomain().base_ring())
|
1381
|
+
R = PowerSeriesRing(base_ring, 'y', default_prec=M)
|
1382
|
+
y = R.gen()
|
1383
|
+
# tim = verbose("Checked, made R",tim)
|
1384
|
+
# special case for small precision, large weight
|
1385
|
+
scale = (b + d * y) / (a + c * y)
|
1386
|
+
t = (a + c * y) ** k # will already have precision M
|
1387
|
+
cdef long row, col
|
1388
|
+
# tim = verbose("Made matrix",tim)
|
1389
|
+
for col in range(M):
|
1390
|
+
for row in range(M):
|
1391
|
+
B.set_unsafe(row, col, t[row])
|
1392
|
+
t *= scale
|
1393
|
+
# verbose("Finished loop",tim)
|
1394
|
+
# the changering here is annoying, but otherwise we have to
|
1395
|
+
# change ring each time we multiply
|
1396
|
+
B = B.change_ring(self.codomain().base_ring())
|
1397
|
+
if self._character is not None:
|
1398
|
+
B *= self._character(a)
|
1399
|
+
if self._dettwist is not None:
|
1400
|
+
B *= (a * d - b * c) ** (self._dettwist)
|
1401
|
+
return B
|
1402
|
+
|
1403
|
+
cpdef _act_(self, g, _v):
|
1404
|
+
r"""
|
1405
|
+
The right action of ``g`` on a distribution.
|
1406
|
+
|
1407
|
+
INPUT:
|
1408
|
+
|
1409
|
+
- ``_v`` -- a :class:`Dist_vector` instance, the distribution
|
1410
|
+
on which to act
|
1411
|
+
|
1412
|
+
- ``g`` -- a `2 \times 2` instance of
|
1413
|
+
:class:`sage.matrix.matrix_integer_dense.Matrix_integer_dense`
|
1414
|
+
|
1415
|
+
OUTPUT: the distribution ``_v * g``
|
1416
|
+
|
1417
|
+
EXAMPLES::
|
1418
|
+
|
1419
|
+
sage: D = sage.modular.pollack_stevens.distributions.Symk(2)
|
1420
|
+
sage: v = D([2,3,4])
|
1421
|
+
sage: g = Matrix(ZZ,2,2,[3,-1,1,0])
|
1422
|
+
sage: v * D._act.actor()(g) # indirect doctest
|
1423
|
+
(40, -9, 2)
|
1424
|
+
"""
|
1425
|
+
# if g is a matrix it needs to be immutable
|
1426
|
+
# hashing on arithmetic_subgroup_elements is by str
|
1427
|
+
if g == 1:
|
1428
|
+
return _v
|
1429
|
+
cdef Dist_vector v = <Dist_vector?>_v
|
1430
|
+
cdef Dist_vector ans = v._new_c()
|
1431
|
+
|
1432
|
+
try:
|
1433
|
+
g.set_immutable()
|
1434
|
+
except AttributeError:
|
1435
|
+
pass
|
1436
|
+
v_moments = v._moments
|
1437
|
+
ans._moments = v_moments * self.acting_matrix(g, len(v_moments))
|
1438
|
+
ans.ordp = v.ordp
|
1439
|
+
return ans
|