passagemath-pari 10.6.32__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-pari might be problematic. Click here for more details.
- PARIKernel/__init__.py +2 -0
- PARIKernel/__main__.py +5 -0
- PARIKernel/io.cpython-314-x86_64-linux-musl.so +0 -0
- PARIKernel/io.pxd +7 -0
- PARIKernel/io.pyx +84 -0
- PARIKernel/kernel.cpython-314-x86_64-linux-musl.so +0 -0
- PARIKernel/kernel.pyx +260 -0
- PARIKernel/paridecl.pxd +95 -0
- PARIKernel/svg.cpython-314-x86_64-linux-musl.so +0 -0
- PARIKernel/svg.pyx +52 -0
- cypari2/__init__.py +8 -0
- cypari2/auto_paridecl.pxd +1070 -0
- cypari2/closure.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/closure.pxd +5 -0
- cypari2/closure.pyx +246 -0
- cypari2/convert.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/convert.pxd +80 -0
- cypari2/convert.pyx +613 -0
- cypari2/custom_block.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/custom_block.pyx +30 -0
- cypari2/cypari.h +13 -0
- cypari2/gen.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/gen.pxd +69 -0
- cypari2/gen.pyx +4819 -0
- cypari2/handle_error.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/handle_error.pxd +7 -0
- cypari2/handle_error.pyx +232 -0
- cypari2/pari_instance.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/pari_instance.pxd +27 -0
- cypari2/pari_instance.pyx +1438 -0
- cypari2/paridecl.pxd +5353 -0
- cypari2/paripriv.pxd +34 -0
- cypari2/pycore_long.h +98 -0
- cypari2/pycore_long.pxd +9 -0
- cypari2/stack.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/stack.pxd +27 -0
- cypari2/stack.pyx +278 -0
- cypari2/string_utils.cpython-314-x86_64-linux-musl.so +0 -0
- cypari2/string_utils.pxd +29 -0
- cypari2/string_utils.pyx +65 -0
- cypari2/types.pxd +147 -0
- passagemath_pari-10.6.32.data/data/etc/jupyter/nbconfig/notebook.d/gp-mode.json +5 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/kernels/pari_jupyter/kernel.js +28 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/kernels/pari_jupyter/kernel.json +6 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/kernels/pari_jupyter/logo-64x64.png +0 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/kernel.json +13 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/logo-32x32.png +0 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/logo-64x64.png +0 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/logo-svg.svg +75 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/nbextensions/gp-mode/gp.js +284 -0
- passagemath_pari-10.6.32.data/data/share/jupyter/nbextensions/gp-mode/main.js +15 -0
- passagemath_pari-10.6.32.dist-info/METADATA +209 -0
- passagemath_pari-10.6.32.dist-info/RECORD +331 -0
- passagemath_pari-10.6.32.dist-info/WHEEL +5 -0
- passagemath_pari-10.6.32.dist-info/top_level.txt +4 -0
- passagemath_pari.libs/libcrypto-f04afe95.so.3 +0 -0
- passagemath_pari.libs/libflint-fd6f12fc.so.21.0.0 +0 -0
- passagemath_pari.libs/libgcc_s-0cd532bd.so.1 +0 -0
- passagemath_pari.libs/libgf2x-9e30c3e3.so.3.0.0 +0 -0
- passagemath_pari.libs/libgfortran-2c33b284.so.5.0.0 +0 -0
- passagemath_pari.libs/libgivaro-9a94c711.so.9.2.1 +0 -0
- passagemath_pari.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_pari.libs/libgmpxx-9e08595c.so.4.7.0 +0 -0
- passagemath_pari.libs/libgsl-42cda06f.so.28.0.0 +0 -0
- passagemath_pari.libs/libmpfr-aaecbfc0.so.6.2.1 +0 -0
- passagemath_pari.libs/libncursesw-9c9e32c3.so.6.5 +0 -0
- passagemath_pari.libs/libntl-26885ca2.so.44.0.1 +0 -0
- passagemath_pari.libs/libopenblasp-r0-905cb27d.3.29.so +0 -0
- passagemath_pari.libs/libpari-gmp-tls-f31f908f.so.2.17.2 +0 -0
- passagemath_pari.libs/libquadmath-bb76a5fc.so.0.0.0 +0 -0
- passagemath_pari.libs/libreadline-06542304.so.8.2 +0 -0
- passagemath_pari.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
- passagemath_pari.libs/libuuid-f3770415.so.1.3.0 +0 -0
- passagemath_pari.libs/libxeus-735780ff.so.13.1.0 +0 -0
- passagemath_pari.libs/libxeus-zmq-c68577b4.so.6.0.1 +0 -0
- passagemath_pari.libs/libzmq-1ba9a3da.so.5.2.5 +0 -0
- sage/all__sagemath_pari.py +26 -0
- sage/databases/all__sagemath_pari.py +7 -0
- sage/databases/conway.py +274 -0
- sage/ext/all__sagemath_pari.py +1 -0
- sage/ext/memory.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/memory.pyx +98 -0
- sage/ext_data/pari/buzzard/DimensionSk.g +286 -0
- sage/ext_data/pari/buzzard/Tpprog.g +179 -0
- sage/ext_data/pari/buzzard/genusn.g +129 -0
- sage/ext_data/pari/dokchitser/computel.gp +740 -0
- sage/ext_data/pari/dokchitser/computel.gp.template +740 -0
- sage/ext_data/pari/dokchitser/ex-bsw +43 -0
- sage/ext_data/pari/dokchitser/ex-chgen +48 -0
- sage/ext_data/pari/dokchitser/ex-chqua +37 -0
- sage/ext_data/pari/dokchitser/ex-delta +35 -0
- sage/ext_data/pari/dokchitser/ex-eisen +30 -0
- sage/ext_data/pari/dokchitser/ex-gen2 +38 -0
- sage/ext_data/pari/dokchitser/ex-gen3 +49 -0
- sage/ext_data/pari/dokchitser/ex-gen4 +54 -0
- sage/ext_data/pari/dokchitser/ex-nf +48 -0
- sage/ext_data/pari/dokchitser/ex-shin +50 -0
- sage/ext_data/pari/dokchitser/ex-tau2 +30 -0
- sage/ext_data/pari/dokchitser/ex-zeta +27 -0
- sage/ext_data/pari/dokchitser/ex-zeta2 +47 -0
- sage/ext_data/pari/dokchitser/testall +13 -0
- sage/ext_data/pari/simon/ell.gp +2129 -0
- sage/ext_data/pari/simon/ellQ.gp +2151 -0
- sage/ext_data/pari/simon/ellcommon.gp +126 -0
- sage/ext_data/pari/simon/qfsolve.gp +722 -0
- sage/ext_data/pari/simon/resultant3.gp +306 -0
- sage/groups/all__sagemath_pari.py +3 -0
- sage/groups/pari_group.py +175 -0
- sage/interfaces/all__sagemath_pari.py +1 -0
- sage/interfaces/genus2reduction.py +464 -0
- sage/interfaces/gp.py +1114 -0
- sage/libs/all__sagemath_pari.py +2 -0
- sage/libs/linkages/__init__.py +1 -0
- sage/libs/linkages/padics/API.pxi +617 -0
- sage/libs/linkages/padics/Polynomial_ram.pxi +388 -0
- sage/libs/linkages/padics/Polynomial_shared.pxi +554 -0
- sage/libs/linkages/padics/__init__.py +1 -0
- sage/libs/linkages/padics/fmpz_poly_unram.pxi +869 -0
- sage/libs/linkages/padics/mpz.pxi +691 -0
- sage/libs/linkages/padics/relaxed/API.pxi +518 -0
- sage/libs/linkages/padics/relaxed/__init__.py +1 -0
- sage/libs/linkages/padics/relaxed/flint.pxi +543 -0
- sage/libs/linkages/padics/unram_shared.pxi +247 -0
- sage/libs/pari/__init__.py +210 -0
- sage/libs/pari/all.py +5 -0
- sage/libs/pari/convert_flint.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/convert_flint.pxd +14 -0
- sage/libs/pari/convert_flint.pyx +159 -0
- sage/libs/pari/convert_gmp.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/convert_gmp.pxd +14 -0
- sage/libs/pari/convert_gmp.pyx +210 -0
- sage/libs/pari/convert_sage.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/convert_sage.pxd +16 -0
- sage/libs/pari/convert_sage.pyx +588 -0
- sage/libs/pari/convert_sage_complex_double.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/convert_sage_complex_double.pxd +14 -0
- sage/libs/pari/convert_sage_complex_double.pyx +132 -0
- sage/libs/pari/convert_sage_matrix.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/convert_sage_matrix.pyx +106 -0
- sage/libs/pari/convert_sage_real_double.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/convert_sage_real_double.pxd +5 -0
- sage/libs/pari/convert_sage_real_double.pyx +14 -0
- sage/libs/pari/convert_sage_real_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/convert_sage_real_mpfr.pxd +7 -0
- sage/libs/pari/convert_sage_real_mpfr.pyx +108 -0
- sage/libs/pari/misc.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/pari/misc.pxd +4 -0
- sage/libs/pari/misc.pyx +26 -0
- sage/libs/pari/tests.py +1848 -0
- sage/matrix/all__sagemath_pari.py +1 -0
- sage/matrix/matrix_integer_pari.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_integer_pari.pyx +187 -0
- sage/matrix/matrix_rational_pari.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_rational_pari.pyx +160 -0
- sage/quadratic_forms/all__sagemath_pari.py +10 -0
- sage/quadratic_forms/genera/all.py +9 -0
- sage/quadratic_forms/genera/genus.py +3506 -0
- sage/quadratic_forms/genera/normal_form.py +1519 -0
- sage/quadratic_forms/genera/spinor_genus.py +243 -0
- sage/quadratic_forms/qfsolve.py +255 -0
- sage/quadratic_forms/quadratic_form__automorphisms.py +427 -0
- sage/quadratic_forms/quadratic_form__genus.py +141 -0
- sage/quadratic_forms/quadratic_form__local_density_interfaces.py +140 -0
- sage/quadratic_forms/quadratic_form__local_normal_form.py +421 -0
- sage/quadratic_forms/quadratic_form__local_representation_conditions.py +889 -0
- sage/quadratic_forms/quadratic_form__mass.py +69 -0
- sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +663 -0
- sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +373 -0
- sage/quadratic_forms/quadratic_form__siegel_product.py +198 -0
- sage/quadratic_forms/special_values.py +323 -0
- sage/rings/all__sagemath_pari.py +15 -0
- sage/rings/factorint_pari.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/factorint_pari.pyx +80 -0
- sage/rings/finite_rings/all__sagemath_pari.py +1 -0
- sage/rings/finite_rings/element_givaro.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_givaro.pxd +91 -0
- sage/rings/finite_rings/element_givaro.pyx +1769 -0
- sage/rings/finite_rings/element_ntl_gf2e.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_ntl_gf2e.pxd +22 -0
- sage/rings/finite_rings/element_ntl_gf2e.pyx +1333 -0
- sage/rings/finite_rings/element_pari_ffelt.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_pari_ffelt.pxd +13 -0
- sage/rings/finite_rings/element_pari_ffelt.pyx +1441 -0
- sage/rings/finite_rings/finite_field_givaro.py +612 -0
- sage/rings/finite_rings/finite_field_pari_ffelt.py +238 -0
- sage/rings/finite_rings/hom_finite_field_givaro.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field_givaro.pxd +28 -0
- sage/rings/finite_rings/hom_finite_field_givaro.pyx +280 -0
- sage/rings/finite_rings/residue_field_givaro.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field_givaro.pyx +133 -0
- sage/rings/finite_rings/residue_field_pari_ffelt.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field_pari_ffelt.pyx +128 -0
- sage/rings/function_field/all__sagemath_pari.py +1 -0
- sage/rings/function_field/valuation.py +1450 -0
- sage/rings/function_field/valuation_ring.py +212 -0
- sage/rings/number_field/all__sagemath_pari.py +14 -0
- sage/rings/number_field/totallyreal.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/number_field/totallyreal.pyx +509 -0
- sage/rings/number_field/totallyreal_data.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/number_field/totallyreal_data.pxd +26 -0
- sage/rings/number_field/totallyreal_data.pyx +928 -0
- sage/rings/number_field/totallyreal_phc.py +144 -0
- sage/rings/number_field/totallyreal_rel.py +1018 -0
- sage/rings/padics/CA_template.pxi +1847 -0
- sage/rings/padics/CA_template_header.pxi +50 -0
- sage/rings/padics/CR_template.pxi +2563 -0
- sage/rings/padics/CR_template_header.pxi +57 -0
- sage/rings/padics/FM_template.pxi +1575 -0
- sage/rings/padics/FM_template_header.pxi +50 -0
- sage/rings/padics/FP_template.pxi +2176 -0
- sage/rings/padics/FP_template_header.pxi +57 -0
- sage/rings/padics/all.py +3 -0
- sage/rings/padics/all__sagemath_pari.py +11 -0
- sage/rings/padics/common_conversion.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/common_conversion.pxd +15 -0
- sage/rings/padics/common_conversion.pyx +508 -0
- sage/rings/padics/eisenstein_extension_generic.py +232 -0
- sage/rings/padics/factory.py +3623 -0
- sage/rings/padics/generic_nodes.py +1615 -0
- sage/rings/padics/lattice_precision.py +2889 -0
- sage/rings/padics/morphism.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/morphism.pxd +11 -0
- sage/rings/padics/morphism.pyx +366 -0
- sage/rings/padics/padic_base_generic.py +467 -0
- sage/rings/padics/padic_base_leaves.py +1235 -0
- sage/rings/padics/padic_capped_absolute_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_capped_absolute_element.pxd +15 -0
- sage/rings/padics/padic_capped_absolute_element.pyx +520 -0
- sage/rings/padics/padic_capped_relative_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_capped_relative_element.pxd +14 -0
- sage/rings/padics/padic_capped_relative_element.pyx +614 -0
- sage/rings/padics/padic_extension_generic.py +990 -0
- sage/rings/padics/padic_extension_leaves.py +738 -0
- sage/rings/padics/padic_fixed_mod_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_fixed_mod_element.pxd +15 -0
- sage/rings/padics/padic_fixed_mod_element.pyx +584 -0
- sage/rings/padics/padic_floating_point_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_floating_point_element.pxd +14 -0
- sage/rings/padics/padic_floating_point_element.pyx +447 -0
- sage/rings/padics/padic_generic_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_generic_element.pxd +48 -0
- sage/rings/padics/padic_generic_element.pyx +4642 -0
- sage/rings/padics/padic_lattice_element.py +1342 -0
- sage/rings/padics/padic_printing.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_printing.pxd +38 -0
- sage/rings/padics/padic_printing.pyx +1505 -0
- sage/rings/padics/padic_relaxed_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_relaxed_element.pxd +56 -0
- sage/rings/padics/padic_relaxed_element.pyx +18 -0
- sage/rings/padics/padic_relaxed_errors.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/padic_relaxed_errors.pxd +11 -0
- sage/rings/padics/padic_relaxed_errors.pyx +71 -0
- sage/rings/padics/padic_template_element.pxi +1212 -0
- sage/rings/padics/padic_template_element_header.pxi +50 -0
- sage/rings/padics/padic_valuation.py +1423 -0
- sage/rings/padics/pow_computer_flint.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer_flint.pxd +38 -0
- sage/rings/padics/pow_computer_flint.pyx +641 -0
- sage/rings/padics/pow_computer_relative.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer_relative.pxd +29 -0
- sage/rings/padics/pow_computer_relative.pyx +415 -0
- sage/rings/padics/qadic_flint_CA.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/qadic_flint_CA.pxd +21 -0
- sage/rings/padics/qadic_flint_CA.pyx +130 -0
- sage/rings/padics/qadic_flint_CR.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/qadic_flint_CR.pxd +13 -0
- sage/rings/padics/qadic_flint_CR.pyx +172 -0
- sage/rings/padics/qadic_flint_FM.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/qadic_flint_FM.pxd +14 -0
- sage/rings/padics/qadic_flint_FM.pyx +111 -0
- sage/rings/padics/qadic_flint_FP.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/qadic_flint_FP.pxd +12 -0
- sage/rings/padics/qadic_flint_FP.pyx +165 -0
- sage/rings/padics/relative_extension_leaves.py +429 -0
- sage/rings/padics/relative_ramified_CA.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/relative_ramified_CA.pxd +9 -0
- sage/rings/padics/relative_ramified_CA.pyx +33 -0
- sage/rings/padics/relative_ramified_CR.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/relative_ramified_CR.pxd +8 -0
- sage/rings/padics/relative_ramified_CR.pyx +33 -0
- sage/rings/padics/relative_ramified_FM.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/relative_ramified_FM.pxd +9 -0
- sage/rings/padics/relative_ramified_FM.pyx +33 -0
- sage/rings/padics/relative_ramified_FP.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/padics/relative_ramified_FP.pxd +8 -0
- sage/rings/padics/relative_ramified_FP.pyx +33 -0
- sage/rings/padics/relaxed_template.pxi +4229 -0
- sage/rings/padics/relaxed_template_header.pxi +160 -0
- sage/rings/padics/tests.py +35 -0
- sage/rings/padics/tutorial.py +341 -0
- sage/rings/padics/unramified_extension_generic.py +335 -0
- sage/rings/padics/witt_vector.py +917 -0
- sage/rings/padics/witt_vector_ring.py +934 -0
- sage/rings/pari_ring.py +235 -0
- sage/rings/polynomial/all__sagemath_pari.py +1 -0
- sage/rings/polynomial/padics/all.py +1 -0
- sage/rings/polynomial/padics/polynomial_padic.py +360 -0
- sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +1324 -0
- sage/rings/polynomial/padics/polynomial_padic_flat.py +72 -0
- sage/rings/power_series_pari.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/power_series_pari.pxd +6 -0
- sage/rings/power_series_pari.pyx +934 -0
- sage/rings/tate_algebra.py +1282 -0
- sage/rings/tate_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/tate_algebra_element.pxd +49 -0
- sage/rings/tate_algebra_element.pyx +3464 -0
- sage/rings/tate_algebra_ideal.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/tate_algebra_ideal.pxd +7 -0
- sage/rings/tate_algebra_ideal.pyx +1307 -0
- sage/rings/valuation/all.py +7 -0
- sage/rings/valuation/augmented_valuation.py +2118 -0
- sage/rings/valuation/developing_valuation.py +362 -0
- sage/rings/valuation/gauss_valuation.py +812 -0
- sage/rings/valuation/inductive_valuation.py +1686 -0
- sage/rings/valuation/limit_valuation.py +946 -0
- sage/rings/valuation/mapped_valuation.py +656 -0
- sage/rings/valuation/scaled_valuation.py +322 -0
- sage/rings/valuation/trivial_valuation.py +382 -0
- sage/rings/valuation/valuation.py +1119 -0
- sage/rings/valuation/valuation_space.py +1615 -0
- sage/rings/valuation/valuations_catalog.py +10 -0
- sage/rings/valuation/value_group.py +697 -0
- sage/schemes/all__sagemath_pari.py +1 -0
- sage/schemes/elliptic_curves/all__sagemath_pari.py +1 -0
- sage/schemes/elliptic_curves/descent_two_isogeny_pari.cpython-314-x86_64-linux-musl.so +0 -0
- sage/schemes/elliptic_curves/descent_two_isogeny_pari.pyx +46 -0
- sage_wheels/bin/gp +0 -0
- sage_wheels/bin/gp2c +0 -0
- sage_wheels/bin/gp2c-run +57 -0
- sage_wheels/bin/xeus-gp +0 -0
- sage_wheels/share/gp2c/func.dsc +18414 -0
|
@@ -0,0 +1,2889 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
r"""
|
|
3
|
+
Lattice precision for the parents ``ZpLC``/``QpLC`` and ``ZpLF``/``QpLF``
|
|
4
|
+
|
|
5
|
+
AUTHOR:
|
|
6
|
+
|
|
7
|
+
- Xavier Caruso (2018-02): initial version
|
|
8
|
+
|
|
9
|
+
TESTS::
|
|
10
|
+
|
|
11
|
+
sage: R = ZpLC(2)
|
|
12
|
+
doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation.
|
|
13
|
+
See https://github.com/sagemath/sage/issues/23505 for details.
|
|
14
|
+
sage: prec = R.precision()
|
|
15
|
+
sage: prec
|
|
16
|
+
Precision lattice on 0 objects
|
|
17
|
+
|
|
18
|
+
sage: S = ZpLF(2)
|
|
19
|
+
sage: prec = S.precision()
|
|
20
|
+
sage: prec
|
|
21
|
+
Precision module on 0 objects
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# ****************************************************************************
|
|
25
|
+
# Copyright (C) 2018 Xavier Caruso <xavier.caruso@normalesup.org>
|
|
26
|
+
#
|
|
27
|
+
# This program is free software: you can redistribute it and/or modify
|
|
28
|
+
# it under the terms of the GNU General Public License as published by
|
|
29
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
30
|
+
# (at your option) any later version.
|
|
31
|
+
# https://www.gnu.org/licenses/
|
|
32
|
+
# ****************************************************************************
|
|
33
|
+
|
|
34
|
+
from collections import defaultdict
|
|
35
|
+
|
|
36
|
+
from sage.misc.timing import walltime
|
|
37
|
+
|
|
38
|
+
from sage.structure.sage_object import SageObject
|
|
39
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
40
|
+
from sage.misc.abstract_method import abstract_method
|
|
41
|
+
from sage.misc.cachefunc import cached_method
|
|
42
|
+
|
|
43
|
+
from sage.rings.integer_ring import ZZ
|
|
44
|
+
from sage.rings.rational_field import QQ
|
|
45
|
+
from sage.rings.infinity import Infinity
|
|
46
|
+
|
|
47
|
+
from sage.rings.padics.precision_error import PrecisionError
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# The default minimal size after which re-echelonization is not performed,
|
|
51
|
+
# i.e., when a variable is not referenced anymore and could be deleted but its
|
|
52
|
+
# corresponding column is further than this threshold from the right end of the
|
|
53
|
+
# matrix representing the precision lattice, then the column is not removed
|
|
54
|
+
# from the matrix because the re-echelonization would be too costly.
|
|
55
|
+
DEFAULT_THRESHOLD_DELETION = 50
|
|
56
|
+
|
|
57
|
+
# The number of additional digits used for internal computations
|
|
58
|
+
STARTING_ADDITIONAL_PREC = 5
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class pRational:
|
|
62
|
+
r"""
|
|
63
|
+
This class implements rational numbers viewed as elements of ``Qp``.
|
|
64
|
+
In particular, it provides additional methods which are specific to
|
|
65
|
+
`p`-adics (as `p`-adic valuation).
|
|
66
|
+
|
|
67
|
+
Only for internal use.
|
|
68
|
+
|
|
69
|
+
INPUT:
|
|
70
|
+
|
|
71
|
+
- ``p`` -- a prime number
|
|
72
|
+
|
|
73
|
+
- ``x`` -- a rational number
|
|
74
|
+
|
|
75
|
+
- ``exponent`` -- integer (default: 0)
|
|
76
|
+
|
|
77
|
+
- ``valuation`` -- integer or ``None`` (default: ``None``);
|
|
78
|
+
the `p`-adic valuation of this element
|
|
79
|
+
|
|
80
|
+
If not ``None``, this method trusts the given value to the
|
|
81
|
+
attribute ``valuation``.
|
|
82
|
+
|
|
83
|
+
TESTS::
|
|
84
|
+
|
|
85
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
86
|
+
sage: x = pRational(2, 5); x
|
|
87
|
+
5
|
|
88
|
+
sage: y = pRational(2, 5/3, 2); y
|
|
89
|
+
2^2 * 5/3
|
|
90
|
+
|
|
91
|
+
sage: x + y
|
|
92
|
+
35/3
|
|
93
|
+
sage: x - y
|
|
94
|
+
-5/3
|
|
95
|
+
sage: x * y
|
|
96
|
+
2^2 * 25/3
|
|
97
|
+
sage: x / y
|
|
98
|
+
2^-2 * 3
|
|
99
|
+
|
|
100
|
+
sage: x.valuation()
|
|
101
|
+
0
|
|
102
|
+
sage: y.valuation()
|
|
103
|
+
2
|
|
104
|
+
|
|
105
|
+
sage: z = pRational(2, 1024, valuation=4)
|
|
106
|
+
sage: z
|
|
107
|
+
1024
|
|
108
|
+
sage: z.valuation()
|
|
109
|
+
4
|
|
110
|
+
"""
|
|
111
|
+
def __init__(self, p, x, exponent=0, valuation=None):
|
|
112
|
+
r"""
|
|
113
|
+
Construct the element ``x * p^exponent``.
|
|
114
|
+
|
|
115
|
+
TESTS::
|
|
116
|
+
|
|
117
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
118
|
+
sage: pRational(2, 5)
|
|
119
|
+
5
|
|
120
|
+
sage: pRational(2, 5/3, 2)
|
|
121
|
+
2^2 * 5/3
|
|
122
|
+
"""
|
|
123
|
+
self.p = p
|
|
124
|
+
if x in ZZ:
|
|
125
|
+
self.x = ZZ(x)
|
|
126
|
+
else:
|
|
127
|
+
self.x = x
|
|
128
|
+
self.exponent = exponent
|
|
129
|
+
self._valuation = valuation
|
|
130
|
+
|
|
131
|
+
def __repr__(self):
|
|
132
|
+
r"""
|
|
133
|
+
Return a string representation of this element.
|
|
134
|
+
|
|
135
|
+
TESTS::
|
|
136
|
+
|
|
137
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
138
|
+
sage: pRational(2, 5, 2) # indirect doctest
|
|
139
|
+
2^2 * 5
|
|
140
|
+
"""
|
|
141
|
+
if self.exponent == 0:
|
|
142
|
+
return repr(self.x)
|
|
143
|
+
else:
|
|
144
|
+
return "%s^%s * %s" % (self.p, self.exponent, self.x)
|
|
145
|
+
|
|
146
|
+
def reduce(self, prec):
|
|
147
|
+
r"""
|
|
148
|
+
Return this element reduced modulo ``p^prec``.
|
|
149
|
+
|
|
150
|
+
INPUT:
|
|
151
|
+
|
|
152
|
+
- ``prec`` -- integer
|
|
153
|
+
|
|
154
|
+
TESTS::
|
|
155
|
+
|
|
156
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
157
|
+
sage: x = pRational(2, 1234567); x
|
|
158
|
+
1234567
|
|
159
|
+
sage: x.reduce(12)
|
|
160
|
+
1671
|
|
161
|
+
|
|
162
|
+
sage: x = pRational(2, 1234/567); x
|
|
163
|
+
1234/567
|
|
164
|
+
sage: x.reduce(12)
|
|
165
|
+
190
|
|
166
|
+
"""
|
|
167
|
+
if prec is Infinity:
|
|
168
|
+
return self
|
|
169
|
+
x = self.x
|
|
170
|
+
exp = self.exponent
|
|
171
|
+
if x.parent() is ZZ:
|
|
172
|
+
if prec > exp:
|
|
173
|
+
x = x % (self.p ** (prec-exp))
|
|
174
|
+
else:
|
|
175
|
+
x = 0
|
|
176
|
+
elif x.parent() is QQ:
|
|
177
|
+
num = x.numerator()
|
|
178
|
+
denom = x.denominator()
|
|
179
|
+
valdenom = denom.valuation(self.p)
|
|
180
|
+
denom //= self.p ** valdenom
|
|
181
|
+
exp -= valdenom
|
|
182
|
+
if prec > exp:
|
|
183
|
+
modulo = self.p ** (prec - exp)
|
|
184
|
+
# probably we should use Newton iteration instead
|
|
185
|
+
# (but it is actually slower for now - Python implementation)
|
|
186
|
+
_, inv, _ = denom.xgcd(modulo)
|
|
187
|
+
x = (num*inv) % modulo
|
|
188
|
+
else:
|
|
189
|
+
x = 0
|
|
190
|
+
if self.x == 0:
|
|
191
|
+
val = Infinity
|
|
192
|
+
else:
|
|
193
|
+
val = self._valuation
|
|
194
|
+
return self.__class__(self.p, x, exp, valuation=val)
|
|
195
|
+
|
|
196
|
+
def reduce_relative(self, prec):
|
|
197
|
+
r"""
|
|
198
|
+
Return this element reduced modulo ``p^n`` where ``n = prec + val(x)``.
|
|
199
|
+
|
|
200
|
+
INPUT:
|
|
201
|
+
|
|
202
|
+
- ``prec`` -- nonnegative integer
|
|
203
|
+
|
|
204
|
+
TESTS::
|
|
205
|
+
|
|
206
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
207
|
+
sage: x = pRational(2, 1234567); x
|
|
208
|
+
1234567
|
|
209
|
+
sage: x.reduce_relative(12)
|
|
210
|
+
1671
|
|
211
|
+
|
|
212
|
+
sage: x = pRational(2, 1234/567); x
|
|
213
|
+
1234/567
|
|
214
|
+
sage: x.reduce_relative(12)
|
|
215
|
+
190
|
|
216
|
+
"""
|
|
217
|
+
v = self.valuation()
|
|
218
|
+
if v is Infinity:
|
|
219
|
+
return self
|
|
220
|
+
return self.reduce(prec+v)
|
|
221
|
+
|
|
222
|
+
def normalize(self):
|
|
223
|
+
r"""
|
|
224
|
+
Normalize this element, i.e. write it as ``p^v * u`` where
|
|
225
|
+
``u`` is coprime to `p`.
|
|
226
|
+
|
|
227
|
+
TESTS::
|
|
228
|
+
|
|
229
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
230
|
+
sage: x = pRational(2, 123456, 7); x
|
|
231
|
+
2^7 * 123456
|
|
232
|
+
sage: x.normalize(); x
|
|
233
|
+
2^13 * 1929
|
|
234
|
+
"""
|
|
235
|
+
if self.x == 0:
|
|
236
|
+
self.exponent = 0
|
|
237
|
+
else:
|
|
238
|
+
val = self.valuation()
|
|
239
|
+
exp = self.exponent
|
|
240
|
+
self.x /= self.p ** (val-exp)
|
|
241
|
+
if self.x in ZZ:
|
|
242
|
+
self.x = ZZ(self.x)
|
|
243
|
+
self.exponent = val
|
|
244
|
+
|
|
245
|
+
def valuation(self):
|
|
246
|
+
r"""
|
|
247
|
+
Return the `p`-adic valuation of this element.
|
|
248
|
+
|
|
249
|
+
TESTS::
|
|
250
|
+
|
|
251
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
252
|
+
sage: x = pRational(2, 123456, 7); x
|
|
253
|
+
2^7 * 123456
|
|
254
|
+
sage: x.valuation()
|
|
255
|
+
13
|
|
256
|
+
"""
|
|
257
|
+
if self._valuation is None:
|
|
258
|
+
valx = self.x.valuation(self.p)
|
|
259
|
+
self._valuation = self.exponent + valx
|
|
260
|
+
return self._valuation
|
|
261
|
+
|
|
262
|
+
def is_p_power(self):
|
|
263
|
+
r"""
|
|
264
|
+
Return ``True`` if this element is a power of `p`.
|
|
265
|
+
|
|
266
|
+
TESTS::
|
|
267
|
+
|
|
268
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
269
|
+
sage: x = pRational(2, 1024, 2); x
|
|
270
|
+
2^2 * 1024
|
|
271
|
+
sage: x.is_p_power()
|
|
272
|
+
True
|
|
273
|
+
|
|
274
|
+
sage: y = pRational(2, 123456, 7); y
|
|
275
|
+
2^7 * 123456
|
|
276
|
+
sage: y.is_p_power()
|
|
277
|
+
False
|
|
278
|
+
"""
|
|
279
|
+
self.normalize()
|
|
280
|
+
return self.x == 1
|
|
281
|
+
|
|
282
|
+
def is_zero(self):
|
|
283
|
+
r"""
|
|
284
|
+
Return ``True`` if this element vanishes.
|
|
285
|
+
|
|
286
|
+
TESTS::
|
|
287
|
+
|
|
288
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
289
|
+
sage: x = pRational(2, 123456, 7); x
|
|
290
|
+
2^7 * 123456
|
|
291
|
+
sage: x.is_zero()
|
|
292
|
+
False
|
|
293
|
+
|
|
294
|
+
sage: (x-x).is_zero()
|
|
295
|
+
True
|
|
296
|
+
"""
|
|
297
|
+
return self.x == 0
|
|
298
|
+
|
|
299
|
+
def __add__(self, other):
|
|
300
|
+
r"""
|
|
301
|
+
Return the sum of ``self`` and ``other``.
|
|
302
|
+
|
|
303
|
+
TESTS::
|
|
304
|
+
|
|
305
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
306
|
+
sage: x = pRational(2, 123456, 7); x
|
|
307
|
+
2^7 * 123456
|
|
308
|
+
sage: y = pRational(2, 891011, 12); y
|
|
309
|
+
2^12 * 891011
|
|
310
|
+
sage: x + y
|
|
311
|
+
2^7 * 28635808
|
|
312
|
+
"""
|
|
313
|
+
p = self.p
|
|
314
|
+
sexp = self.exponent
|
|
315
|
+
oexp = other.exponent
|
|
316
|
+
if sexp is Infinity:
|
|
317
|
+
return other
|
|
318
|
+
if oexp is Infinity:
|
|
319
|
+
return self
|
|
320
|
+
if self._valuation is None or other._valuation is None:
|
|
321
|
+
val = None
|
|
322
|
+
elif self._valuation < other._valuation:
|
|
323
|
+
val = self._valuation
|
|
324
|
+
elif self._valuation > other._valuation:
|
|
325
|
+
val = other._valuation
|
|
326
|
+
else:
|
|
327
|
+
val = None
|
|
328
|
+
if sexp < oexp:
|
|
329
|
+
return self.__class__(p, self.x + other.x * p**(oexp-sexp), sexp, valuation=val)
|
|
330
|
+
else:
|
|
331
|
+
return self.__class__(p, self.x * p**(sexp-oexp) + other.x, oexp, valuation=val)
|
|
332
|
+
|
|
333
|
+
def __sub__(self, other):
|
|
334
|
+
r"""
|
|
335
|
+
Return the subtraction of ``self`` by ``other``.
|
|
336
|
+
|
|
337
|
+
TESTS::
|
|
338
|
+
|
|
339
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
340
|
+
sage: x = pRational(2, 123456, 7); x
|
|
341
|
+
2^7 * 123456
|
|
342
|
+
sage: y = pRational(2, 891011, 12); y
|
|
343
|
+
2^12 * 891011
|
|
344
|
+
sage: x - y
|
|
345
|
+
2^7 * -28388896
|
|
346
|
+
"""
|
|
347
|
+
return self + (-other)
|
|
348
|
+
|
|
349
|
+
def __neg__(self):
|
|
350
|
+
r"""
|
|
351
|
+
Return the opposite of this element.
|
|
352
|
+
|
|
353
|
+
TESTS::
|
|
354
|
+
|
|
355
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
356
|
+
sage: x = pRational(2, 123456, 7); x
|
|
357
|
+
2^7 * 123456
|
|
358
|
+
sage: -x
|
|
359
|
+
2^7 * -123456
|
|
360
|
+
"""
|
|
361
|
+
return self.__class__(self.p, -self.x, self.exponent, valuation=self._valuation)
|
|
362
|
+
|
|
363
|
+
def __mul__(self, other):
|
|
364
|
+
r"""
|
|
365
|
+
Return the product of ``self`` and ``other``.
|
|
366
|
+
|
|
367
|
+
TESTS::
|
|
368
|
+
|
|
369
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
370
|
+
sage: x = pRational(2, 123456, 7); x
|
|
371
|
+
2^7 * 123456
|
|
372
|
+
sage: y = pRational(2, 891011, 12); y
|
|
373
|
+
2^12 * 891011
|
|
374
|
+
sage: x * y
|
|
375
|
+
2^19 * 110000654016
|
|
376
|
+
"""
|
|
377
|
+
if self._valuation is None or other._valuation is None:
|
|
378
|
+
val = None
|
|
379
|
+
else:
|
|
380
|
+
val = self._valuation + other._valuation
|
|
381
|
+
return self.__class__(self.p, self.x * other.x, self.exponent + other.exponent, valuation=val)
|
|
382
|
+
|
|
383
|
+
def __truediv__(self, other):
|
|
384
|
+
r"""
|
|
385
|
+
Return the quotient of ``self`` by ``other``.
|
|
386
|
+
|
|
387
|
+
TESTS::
|
|
388
|
+
|
|
389
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
390
|
+
sage: x = pRational(2, 123456, 7); x
|
|
391
|
+
2^7 * 123456
|
|
392
|
+
sage: y = pRational(2, 891011, 12); y
|
|
393
|
+
2^12 * 891011
|
|
394
|
+
sage: x / y
|
|
395
|
+
2^-5 * 123456/891011
|
|
396
|
+
"""
|
|
397
|
+
if self._valuation is None or other._valuation is None:
|
|
398
|
+
val = None
|
|
399
|
+
else:
|
|
400
|
+
val = self._valuation - other._valuation
|
|
401
|
+
return self.__class__(self.p, self.x / other.x, self.exponent - other.exponent, valuation=val)
|
|
402
|
+
|
|
403
|
+
def _quo_rem(self, other):
|
|
404
|
+
"""
|
|
405
|
+
Quotient with remainder.
|
|
406
|
+
|
|
407
|
+
Returns a pair `q`, `r` where `r` has the `p`-adic expansion of this element,
|
|
408
|
+
truncated at the valuation of other.
|
|
409
|
+
|
|
410
|
+
EXAMPLES::
|
|
411
|
+
|
|
412
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
413
|
+
sage: a = pRational(2, 123456, 3)
|
|
414
|
+
sage: b = pRational(2, 654321, 2)
|
|
415
|
+
sage: q,r = a._quo_rem(b); q, r
|
|
416
|
+
(2^7 * 643/218107, 0)
|
|
417
|
+
sage: q*b+r - a
|
|
418
|
+
0
|
|
419
|
+
sage: q,r = b._quo_rem(a); q, r
|
|
420
|
+
(5111/1929, 2^2 * 113)
|
|
421
|
+
sage: q*a+r - b
|
|
422
|
+
2^2 * 0
|
|
423
|
+
"""
|
|
424
|
+
other.normalize()
|
|
425
|
+
ox = other.x
|
|
426
|
+
if ox == 0:
|
|
427
|
+
raise ZeroDivisionError
|
|
428
|
+
self.normalize()
|
|
429
|
+
oval = other.exponent
|
|
430
|
+
sx = self.x
|
|
431
|
+
sval = self.exponent
|
|
432
|
+
diff = sval - oval
|
|
433
|
+
if sx == 0:
|
|
434
|
+
return (self.__class__(self.p, 0, 0, valuation=Infinity),
|
|
435
|
+
self.__class__(self.p, 0, 0, valuation=Infinity))
|
|
436
|
+
elif sval >= oval:
|
|
437
|
+
return (self.__class__(self.p, sx / ox, diff, valuation=diff),
|
|
438
|
+
self.__class__(self.p, 0, 0, valuation=Infinity))
|
|
439
|
+
else:
|
|
440
|
+
pd = self.p**(-diff)
|
|
441
|
+
sred = sx % pd
|
|
442
|
+
return (self.__class__(self.p, (sx - sred)/(pd*ox), 0),
|
|
443
|
+
self.__class__(self.p, sred, sval, valuation=sval))
|
|
444
|
+
|
|
445
|
+
def __lshift__(self, n):
|
|
446
|
+
r"""
|
|
447
|
+
Return the product of this element by ``p^n``.
|
|
448
|
+
|
|
449
|
+
INPUT:
|
|
450
|
+
|
|
451
|
+
- ``n`` -- relative integer
|
|
452
|
+
|
|
453
|
+
TESTS::
|
|
454
|
+
|
|
455
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
456
|
+
sage: x = pRational(2, 123456, 7); x
|
|
457
|
+
2^7 * 123456
|
|
458
|
+
sage: x << 10
|
|
459
|
+
2^17 * 123456
|
|
460
|
+
"""
|
|
461
|
+
if self._valuation is None:
|
|
462
|
+
val = None
|
|
463
|
+
else:
|
|
464
|
+
val = self._valuation + n
|
|
465
|
+
return self.__class__(self.p, self.x, self.exponent + n, valuation=val)
|
|
466
|
+
|
|
467
|
+
def __rshift__(self, n):
|
|
468
|
+
r"""
|
|
469
|
+
Return the quotient of this element by ``p^n``.
|
|
470
|
+
|
|
471
|
+
INPUT:
|
|
472
|
+
|
|
473
|
+
- ``n`` -- relative integer
|
|
474
|
+
|
|
475
|
+
TESTS::
|
|
476
|
+
|
|
477
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
478
|
+
sage: x = pRational(2, 123456, 7); x
|
|
479
|
+
2^7 * 123456
|
|
480
|
+
sage: x >> 10
|
|
481
|
+
2^-3 * 123456
|
|
482
|
+
"""
|
|
483
|
+
return self << (-n)
|
|
484
|
+
|
|
485
|
+
def unit_part(self):
|
|
486
|
+
r"""
|
|
487
|
+
Return the unit part of this element, that is the part ``u``
|
|
488
|
+
in the writing ``u * p^v`` with ``u`` coprime to `p`.
|
|
489
|
+
|
|
490
|
+
TESTS::
|
|
491
|
+
|
|
492
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
493
|
+
sage: x = pRational(2, 123456, 7); x
|
|
494
|
+
2^7 * 123456
|
|
495
|
+
sage: x.unit_part()
|
|
496
|
+
1929
|
|
497
|
+
"""
|
|
498
|
+
if self.is_zero():
|
|
499
|
+
raise ValueError("the unit part of zero is not defined")
|
|
500
|
+
p = self.p
|
|
501
|
+
val = self.valuation()
|
|
502
|
+
x = self.x / (p ** (val-self.exponent))
|
|
503
|
+
return self.__class__(p, x, 0, valuation=0)
|
|
504
|
+
|
|
505
|
+
def xgcd(self, other):
|
|
506
|
+
r"""
|
|
507
|
+
Return the gcd of ``self`` and ``other`` together with two
|
|
508
|
+
elements ``u`` and ``v`` such that ``u*self + v*other = gcd``.
|
|
509
|
+
|
|
510
|
+
The ``gcd`` is normalized so that it is a power of `p`.
|
|
511
|
+
|
|
512
|
+
TESTS::
|
|
513
|
+
|
|
514
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
515
|
+
sage: x = pRational(2, 123456, 7); x
|
|
516
|
+
2^7 * 123456
|
|
517
|
+
sage: y = pRational(2, 891011, 12); y
|
|
518
|
+
2^12 * 891011
|
|
519
|
+
|
|
520
|
+
sage: d, u, v = x.xgcd(y)
|
|
521
|
+
sage: d
|
|
522
|
+
2^7 * 32
|
|
523
|
+
sage: d.normalize(); d
|
|
524
|
+
2^12 * 1
|
|
525
|
+
|
|
526
|
+
sage: u*x + v*y
|
|
527
|
+
2^7 * 32
|
|
528
|
+
"""
|
|
529
|
+
p = self.p
|
|
530
|
+
sexp = self.exponent
|
|
531
|
+
oexp = other.exponent
|
|
532
|
+
if sexp < oexp:
|
|
533
|
+
a = ZZ(self.x)
|
|
534
|
+
b = ZZ(other.x * (p ** (oexp-sexp)))
|
|
535
|
+
exp = sexp
|
|
536
|
+
else:
|
|
537
|
+
a = ZZ(self.x * (p ** (sexp-oexp)))
|
|
538
|
+
b = ZZ(other.x)
|
|
539
|
+
exp = oexp
|
|
540
|
+
d, u, v = a.xgcd(b)
|
|
541
|
+
if self._valuation is None or other._valuation is None:
|
|
542
|
+
val = None
|
|
543
|
+
else:
|
|
544
|
+
val = min(self._valuation, other._valuation)
|
|
545
|
+
d = self.__class__(p, d, exp, valuation=val)
|
|
546
|
+
u = self.__class__(p, u)
|
|
547
|
+
v = self.__class__(p, v)
|
|
548
|
+
return d, u, v
|
|
549
|
+
|
|
550
|
+
def value(self):
|
|
551
|
+
r"""
|
|
552
|
+
Return this element as a rational number.
|
|
553
|
+
|
|
554
|
+
TESTS::
|
|
555
|
+
|
|
556
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
557
|
+
sage: x = pRational(2, 123456, 7); x
|
|
558
|
+
2^7 * 123456
|
|
559
|
+
sage: x.value()
|
|
560
|
+
15802368
|
|
561
|
+
"""
|
|
562
|
+
return (self.p ** self.exponent) * self.x
|
|
563
|
+
|
|
564
|
+
def list(self, prec):
|
|
565
|
+
r"""
|
|
566
|
+
Return the list of the digits of this element (written in radix
|
|
567
|
+
`p`) up to position ``prec``.
|
|
568
|
+
|
|
569
|
+
The first zeros are omitted.
|
|
570
|
+
|
|
571
|
+
TESTS::
|
|
572
|
+
|
|
573
|
+
sage: from sage.rings.padics.lattice_precision import pRational
|
|
574
|
+
sage: x = pRational(2, 123456); x
|
|
575
|
+
123456
|
|
576
|
+
sage: x.list(5)
|
|
577
|
+
[]
|
|
578
|
+
sage: x.list(20)
|
|
579
|
+
[1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0]
|
|
580
|
+
|
|
581
|
+
sage: y = pRational(2, 123/456); y
|
|
582
|
+
41/152
|
|
583
|
+
sage: y.list(10)
|
|
584
|
+
[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1]
|
|
585
|
+
|
|
586
|
+
sage: z = pRational(2, 0)
|
|
587
|
+
sage: z.list(10)
|
|
588
|
+
[]
|
|
589
|
+
sage: z.list(100)
|
|
590
|
+
[]
|
|
591
|
+
"""
|
|
592
|
+
if self.x not in ZZ:
|
|
593
|
+
self = self.reduce(prec)
|
|
594
|
+
val = self.valuation()
|
|
595
|
+
if val is Infinity:
|
|
596
|
+
return []
|
|
597
|
+
p = self.p
|
|
598
|
+
x = ZZ(self.x * p**(self.exponent - val))
|
|
599
|
+
l = []
|
|
600
|
+
for _ in range(val, prec):
|
|
601
|
+
x, digit = x.quo_rem(p)
|
|
602
|
+
l.append(digit)
|
|
603
|
+
return l
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class DifferentialPrecisionGeneric(SageObject):
|
|
607
|
+
r"""
|
|
608
|
+
A generic class for precision objects obtained by automatic
|
|
609
|
+
differentiation.
|
|
610
|
+
|
|
611
|
+
INPUT:
|
|
612
|
+
|
|
613
|
+
- ``p`` -- a prime number
|
|
614
|
+
|
|
615
|
+
- ``label`` -- string; the label of the parents to which the elements
|
|
616
|
+
belong that are tracked by this precision module
|
|
617
|
+
|
|
618
|
+
.. NOTE::
|
|
619
|
+
|
|
620
|
+
This object is used internally by the parent ring. You should not
|
|
621
|
+
create instances of this class on your own.
|
|
622
|
+
|
|
623
|
+
EXAMPLES::
|
|
624
|
+
|
|
625
|
+
sage: R = ZpLC(2, label='init')
|
|
626
|
+
sage: R.precision()
|
|
627
|
+
Precision lattice on 0 objects (label: init)
|
|
628
|
+
"""
|
|
629
|
+
def __init__(self, p, label):
|
|
630
|
+
r"""
|
|
631
|
+
TESTS::
|
|
632
|
+
|
|
633
|
+
sage: prec = ZpLC(2, label='init').precision()
|
|
634
|
+
sage: from sage.rings.padics.lattice_precision import DifferentialPrecisionGeneric
|
|
635
|
+
sage: isinstance(prec, DifferentialPrecisionGeneric)
|
|
636
|
+
True
|
|
637
|
+
"""
|
|
638
|
+
self._p = p
|
|
639
|
+
self._label = label
|
|
640
|
+
self._elements = []
|
|
641
|
+
|
|
642
|
+
self._matrix = {}
|
|
643
|
+
# A dictionary whose keys are weak references to tracked
|
|
644
|
+
# elements and values corresponding columns in the matrix
|
|
645
|
+
# representing the precision lattice
|
|
646
|
+
|
|
647
|
+
self._collected_references = []
|
|
648
|
+
self._marked_for_deletion = []
|
|
649
|
+
self._approx_zero = pRational(p, ZZ.zero())
|
|
650
|
+
self._threshold_deletion = DEFAULT_THRESHOLD_DELETION
|
|
651
|
+
self._history_init = None
|
|
652
|
+
self._history = None
|
|
653
|
+
|
|
654
|
+
def __reduce__(self):
|
|
655
|
+
r"""
|
|
656
|
+
TESTS::
|
|
657
|
+
|
|
658
|
+
sage: R = ZpLF(2)
|
|
659
|
+
sage: prec = R.precision()
|
|
660
|
+
sage: dumps(prec)
|
|
661
|
+
Traceback (most recent call last):
|
|
662
|
+
...
|
|
663
|
+
NotImplementedError: pickling/unpickling precision modules is not implemented yet
|
|
664
|
+
"""
|
|
665
|
+
raise NotImplementedError("pickling/unpickling precision modules is not implemented yet")
|
|
666
|
+
|
|
667
|
+
def _repr_(self):
|
|
668
|
+
r"""
|
|
669
|
+
Return a string representation of this precision object.
|
|
670
|
+
|
|
671
|
+
EXAMPLES::
|
|
672
|
+
|
|
673
|
+
sage: R = ZpLC(2)
|
|
674
|
+
sage: R.precision()
|
|
675
|
+
Precision lattice on ... objects
|
|
676
|
+
|
|
677
|
+
If a label has been specified, it is included in the representation::
|
|
678
|
+
|
|
679
|
+
sage: R = ZpLC(2, label='mylabel')
|
|
680
|
+
sage: R.precision()
|
|
681
|
+
Precision lattice on 0 objects (label: mylabel)
|
|
682
|
+
"""
|
|
683
|
+
label = "" if self._label is None else " (label: %s)" % (self._label,)
|
|
684
|
+
count = "1 object" if len(self._elements) == 1 else "%s objects" % len(self._elements)
|
|
685
|
+
return "%s on %s%s" % (self._repr_type, count, label)
|
|
686
|
+
|
|
687
|
+
def threshold_deletion(self, threshold=None):
|
|
688
|
+
r"""
|
|
689
|
+
Return (and set) the threshold for column deletion.
|
|
690
|
+
|
|
691
|
+
When a variable dies, i.e., goes out of scope, the ambient space in
|
|
692
|
+
which the precision module lives can be reduced (by projection onto the
|
|
693
|
+
hyperplane defined by the dead variable).
|
|
694
|
+
This reduction has a cost because it leads to re-echelonization
|
|
695
|
+
of a part of the matrix that encodes the precision. The size of this
|
|
696
|
+
part is roughly measured by the number of columns between the last
|
|
697
|
+
column and the one corresponding to the dead variable.
|
|
698
|
+
|
|
699
|
+
This threshold returned by this method is the maximal distance until
|
|
700
|
+
which a column of a dead variable is removed and the matrix
|
|
701
|
+
re-echelonized. Beyond the threshold, the column of the dead variable
|
|
702
|
+
is kept in this matrix as if the variable were not destroyed.
|
|
703
|
+
|
|
704
|
+
INPUT:
|
|
705
|
+
|
|
706
|
+
- ``threshold`` -- nonnegative integer, ``Infinity`` or ``None``
|
|
707
|
+
(default: ``None``); if not ``None`` set the threshold to the given
|
|
708
|
+
value.
|
|
709
|
+
|
|
710
|
+
.. NOTE::
|
|
711
|
+
|
|
712
|
+
Setting the threshold to ``0`` disables the dimension reduction.
|
|
713
|
+
|
|
714
|
+
Setting the threshold to ``Infinity`` forces the dimension reduction
|
|
715
|
+
after each deletion.
|
|
716
|
+
|
|
717
|
+
EXAMPLES::
|
|
718
|
+
|
|
719
|
+
sage: R = ZpLC(2, label='threshold_deletion')
|
|
720
|
+
sage: prec = R.precision()
|
|
721
|
+
sage: prec.threshold_deletion()
|
|
722
|
+
50
|
|
723
|
+
|
|
724
|
+
sage: prec.threshold_deletion(20)
|
|
725
|
+
20
|
|
726
|
+
sage: prec.threshold_deletion()
|
|
727
|
+
20
|
|
728
|
+
|
|
729
|
+
sage: prec.threshold_deletion(-2)
|
|
730
|
+
Traceback (most recent call last):
|
|
731
|
+
...
|
|
732
|
+
ValueError: The threshold must be a nonnegative integer or Infinity
|
|
733
|
+
"""
|
|
734
|
+
if threshold is not None:
|
|
735
|
+
if threshold is Infinity or (threshold in ZZ and threshold >= 0):
|
|
736
|
+
self._threshold_deletion = threshold
|
|
737
|
+
else:
|
|
738
|
+
raise ValueError("The threshold must be a nonnegative integer or Infinity")
|
|
739
|
+
return self._threshold_deletion
|
|
740
|
+
|
|
741
|
+
def prime(self):
|
|
742
|
+
r"""
|
|
743
|
+
Return the underlying prime number attached to this precision lattice.
|
|
744
|
+
|
|
745
|
+
EXAMPLES::
|
|
746
|
+
|
|
747
|
+
sage: R = ZpLC(2, label='mylabel')
|
|
748
|
+
sage: R.precision().prime()
|
|
749
|
+
2
|
|
750
|
+
"""
|
|
751
|
+
return self._p
|
|
752
|
+
|
|
753
|
+
def _index(self, ref):
|
|
754
|
+
r"""
|
|
755
|
+
Return the index of the column in the precision matrix that
|
|
756
|
+
corresponds to ``ref``.
|
|
757
|
+
|
|
758
|
+
Only for internal use.
|
|
759
|
+
|
|
760
|
+
TESTS::
|
|
761
|
+
|
|
762
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
763
|
+
sage: R = ZpLC(2, label='index')
|
|
764
|
+
sage: prec = R.precision()
|
|
765
|
+
sage: x = R(1, 10)
|
|
766
|
+
sage: y = R(1, 5)
|
|
767
|
+
|
|
768
|
+
sage: prec._index(pAdicLatticeElementWeakProxy(x))
|
|
769
|
+
0
|
|
770
|
+
sage: prec._index(pAdicLatticeElementWeakProxy(y))
|
|
771
|
+
1
|
|
772
|
+
|
|
773
|
+
sage: del x
|
|
774
|
+
sage: prec.del_elements()
|
|
775
|
+
sage: prec._index(pAdicLatticeElementWeakProxy(y))
|
|
776
|
+
0
|
|
777
|
+
"""
|
|
778
|
+
return self._elements.index(ref)
|
|
779
|
+
|
|
780
|
+
def ambient_dimension(self):
|
|
781
|
+
r"""
|
|
782
|
+
Return the dimension of the vector space in which the precision
|
|
783
|
+
module/lattice lives.
|
|
784
|
+
|
|
785
|
+
EXAMPLES::
|
|
786
|
+
|
|
787
|
+
sage: R = ZpLC(2, label='ambient_dim')
|
|
788
|
+
sage: prec = R.precision()
|
|
789
|
+
|
|
790
|
+
sage: x, y = R(1, 10), R(1, 5)
|
|
791
|
+
sage: prec.ambient_dimension()
|
|
792
|
+
2
|
|
793
|
+
sage: prec.dimension()
|
|
794
|
+
2
|
|
795
|
+
|
|
796
|
+
sage: u = x + y
|
|
797
|
+
sage: prec.ambient_dimension()
|
|
798
|
+
3
|
|
799
|
+
sage: prec.dimension()
|
|
800
|
+
3
|
|
801
|
+
|
|
802
|
+
In the case of ``ZpLC`` (lattice-cap precision), it is always
|
|
803
|
+
equal to the dimension of the lattice.
|
|
804
|
+
|
|
805
|
+
In the case of ``ZpLF`` (lattice-float precision), the precision
|
|
806
|
+
object is not necessarily a lattice and then may have smaller
|
|
807
|
+
dimension::
|
|
808
|
+
|
|
809
|
+
sage: R = ZpLF(2, label='ambient_dim')
|
|
810
|
+
sage: prec = R.precision()
|
|
811
|
+
|
|
812
|
+
sage: x, y = R(1, 10), R(1, 5)
|
|
813
|
+
sage: prec.ambient_dimension()
|
|
814
|
+
2
|
|
815
|
+
sage: prec.dimension()
|
|
816
|
+
2
|
|
817
|
+
|
|
818
|
+
sage: u = x + y
|
|
819
|
+
sage: prec.ambient_dimension()
|
|
820
|
+
3
|
|
821
|
+
sage: prec.dimension()
|
|
822
|
+
2
|
|
823
|
+
"""
|
|
824
|
+
return len(self._matrix)
|
|
825
|
+
|
|
826
|
+
@abstract_method
|
|
827
|
+
def dimension(self):
|
|
828
|
+
r"""
|
|
829
|
+
Return the dimension of this precision module.
|
|
830
|
+
|
|
831
|
+
EXAMPLES::
|
|
832
|
+
|
|
833
|
+
sage: R = ZpLC(5, label='dim')
|
|
834
|
+
sage: prec = R.precision()
|
|
835
|
+
sage: prec.dimension()
|
|
836
|
+
0
|
|
837
|
+
|
|
838
|
+
sage: x = R(1, 10)
|
|
839
|
+
sage: prec.dimension()
|
|
840
|
+
1
|
|
841
|
+
"""
|
|
842
|
+
pass
|
|
843
|
+
|
|
844
|
+
@abstract_method
|
|
845
|
+
def _new_element(self, *args, **kwargs):
|
|
846
|
+
r"""
|
|
847
|
+
Insert a new element in this precision module.
|
|
848
|
+
|
|
849
|
+
TESTS::
|
|
850
|
+
|
|
851
|
+
sage: R = ZpLC(2)
|
|
852
|
+
sage: x = R.random_element()
|
|
853
|
+
sage: y = R.random_element()
|
|
854
|
+
sage: z = x*y # indirect doctest
|
|
855
|
+
"""
|
|
856
|
+
pass
|
|
857
|
+
|
|
858
|
+
def _record_collected_element(self, ref):
|
|
859
|
+
r"""
|
|
860
|
+
Record that the element with weak reference ``ref``
|
|
861
|
+
has been collected by the garbage collector.
|
|
862
|
+
|
|
863
|
+
INPUT:
|
|
864
|
+
|
|
865
|
+
- ``ref`` -- the weak reference of the collected element
|
|
866
|
+
|
|
867
|
+
TESTS::
|
|
868
|
+
|
|
869
|
+
sage: R = ZpLC(2, label='gc')
|
|
870
|
+
sage: prec = R.precision()
|
|
871
|
+
|
|
872
|
+
sage: x = R.random_element()
|
|
873
|
+
sage: prec._collected_references
|
|
874
|
+
[]
|
|
875
|
+
|
|
876
|
+
sage: del x
|
|
877
|
+
sage: prec._collected_references
|
|
878
|
+
[WeakProxy#...]
|
|
879
|
+
"""
|
|
880
|
+
self._collected_references.append(ref)
|
|
881
|
+
|
|
882
|
+
@abstract_method
|
|
883
|
+
def del_elements(self, threshold=None):
|
|
884
|
+
r"""
|
|
885
|
+
Delete (or mark for future deletion) the columns of precision
|
|
886
|
+
matrix corresponding to elements that were collected by the
|
|
887
|
+
garbage collector.
|
|
888
|
+
|
|
889
|
+
INPUT:
|
|
890
|
+
|
|
891
|
+
- ``threshold`` -- integer or ``None`` (default: ``None``);
|
|
892
|
+
a column whose distance to the right is greater than the
|
|
893
|
+
threshold is not erased but marked for deletion.
|
|
894
|
+
If ``None``, always erase (never mark for deletion).
|
|
895
|
+
|
|
896
|
+
EXAMPLES::
|
|
897
|
+
|
|
898
|
+
sage: R = ZpLC(2, label='del_elements')
|
|
899
|
+
sage: prec = R.precision()
|
|
900
|
+
|
|
901
|
+
sage: x = R(1, 10)
|
|
902
|
+
sage: prec
|
|
903
|
+
Precision lattice on 1 object (label: del_elements)
|
|
904
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
905
|
+
[1024]
|
|
906
|
+
|
|
907
|
+
sage: del x
|
|
908
|
+
sage: prec
|
|
909
|
+
Precision lattice on 1 object (label: del_elements)
|
|
910
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
911
|
+
[1024]
|
|
912
|
+
|
|
913
|
+
sage: prec.del_elements()
|
|
914
|
+
sage: prec
|
|
915
|
+
Precision lattice on 0 objects (label: del_elements)
|
|
916
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
917
|
+
[]
|
|
918
|
+
"""
|
|
919
|
+
pass
|
|
920
|
+
|
|
921
|
+
@abstract_method
|
|
922
|
+
def _precision_absolute(self, x):
|
|
923
|
+
r"""
|
|
924
|
+
Return the absolute precision of the given element.
|
|
925
|
+
|
|
926
|
+
INPUT:
|
|
927
|
+
|
|
928
|
+
- ``x`` -- the element whose absolute precision is requested
|
|
929
|
+
|
|
930
|
+
.. NOTE::
|
|
931
|
+
|
|
932
|
+
The absolute precision is obtained by projecting the precision
|
|
933
|
+
lattice onto the line of coordinate ``dx``.
|
|
934
|
+
|
|
935
|
+
This function is not meant to be called directly. Call
|
|
936
|
+
``x.precision_absolute()`` instead.
|
|
937
|
+
|
|
938
|
+
EXAMPLES::
|
|
939
|
+
|
|
940
|
+
sage: R = ZpLC(2)
|
|
941
|
+
sage: x = R(1, 10); x
|
|
942
|
+
1 + O(2^10)
|
|
943
|
+
sage: y = R(1, 5); y
|
|
944
|
+
1 + O(2^5)
|
|
945
|
+
sage: z = x + y; z
|
|
946
|
+
2 + O(2^5)
|
|
947
|
+
sage: z.precision_absolute() # indirect doctest
|
|
948
|
+
5
|
|
949
|
+
"""
|
|
950
|
+
pass
|
|
951
|
+
|
|
952
|
+
@abstract_method
|
|
953
|
+
def precision_lattice(self, elements=None):
|
|
954
|
+
r"""
|
|
955
|
+
Return a lattice modeling the precision on the given set of elements
|
|
956
|
+
or, if not given, on the whole set of elements tracked by the precision
|
|
957
|
+
module.
|
|
958
|
+
|
|
959
|
+
INPUT:
|
|
960
|
+
|
|
961
|
+
- ``elements`` -- list of elements or ``None`` (default: ``None``)
|
|
962
|
+
|
|
963
|
+
EXAMPLES::
|
|
964
|
+
|
|
965
|
+
sage: R = ZpLC(2, label='precision_lattice')
|
|
966
|
+
sage: prec = R.precision()
|
|
967
|
+
sage: x = R(1, 10); y = R(1, 5)
|
|
968
|
+
sage: u = x + y
|
|
969
|
+
sage: v = x - y
|
|
970
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
971
|
+
[ 1024 0 1024 1024]
|
|
972
|
+
[ 0 32 32 1099511627744]
|
|
973
|
+
[ 0 0 2097152 0]
|
|
974
|
+
[ 0 0 0 1099511627776]
|
|
975
|
+
sage: prec.precision_lattice([u, v]) # needs sage.geometry.polyhedron
|
|
976
|
+
[ 32 2016]
|
|
977
|
+
[ 0 2048]
|
|
978
|
+
|
|
979
|
+
If the precision module does not project to a lattice,
|
|
980
|
+
an error is raised. ::
|
|
981
|
+
|
|
982
|
+
sage: R = ZpLF(2, label='precision_lattice')
|
|
983
|
+
sage: prec = R.precision()
|
|
984
|
+
sage: x = R(1, 10); y = R(1, 5)
|
|
985
|
+
sage: u = x + y
|
|
986
|
+
sage: v = x - y
|
|
987
|
+
sage: prec.precision_lattice([x,y,u,v]) # needs sage.geometry.polyhedron
|
|
988
|
+
Traceback (most recent call last):
|
|
989
|
+
...
|
|
990
|
+
PrecisionError: the differential is not surjective
|
|
991
|
+
"""
|
|
992
|
+
pass
|
|
993
|
+
|
|
994
|
+
def diffused_digits(self, elements=None):
|
|
995
|
+
r"""
|
|
996
|
+
Return the number of diffused digits of precision within a
|
|
997
|
+
subset of elements.
|
|
998
|
+
|
|
999
|
+
A diffused digit of precision is a known digit which is not
|
|
1000
|
+
located on a single variable but only appears on a suitable
|
|
1001
|
+
linear combination of variables.
|
|
1002
|
+
|
|
1003
|
+
The number of diffused digits of precision quantifies the
|
|
1004
|
+
quality of the approximation of the lattice precision by a
|
|
1005
|
+
jagged precision (that is a precision which is split over
|
|
1006
|
+
all variables).
|
|
1007
|
+
|
|
1008
|
+
We refer to [CRV2018]_ for a detail exposition of the notion of
|
|
1009
|
+
diffused digits.
|
|
1010
|
+
|
|
1011
|
+
EXAMPLES::
|
|
1012
|
+
|
|
1013
|
+
sage: R = ZpLC(2)
|
|
1014
|
+
sage: prec = R.precision()
|
|
1015
|
+
sage: x = R(1, 10); y = R(1, 5)
|
|
1016
|
+
sage: u = x + y
|
|
1017
|
+
sage: v = x - y
|
|
1018
|
+
|
|
1019
|
+
sage: prec.diffused_digits([x, y]) # needs sage.geometry.polyhedron
|
|
1020
|
+
0
|
|
1021
|
+
sage: prec.diffused_digits([u, v]) # needs sage.geometry.polyhedron
|
|
1022
|
+
6
|
|
1023
|
+
|
|
1024
|
+
The elements `u` and `v` are known at absolute precision `O(2^5)`.
|
|
1025
|
+
However, the sum `u + v = 2x` is known at precision `O(2^11)`, that
|
|
1026
|
+
is with `6` more digits.
|
|
1027
|
+
That is where the `6` diffused digits of precision comes from.
|
|
1028
|
+
|
|
1029
|
+
Here is another example with matrices::
|
|
1030
|
+
|
|
1031
|
+
sage: M = matrix(R, 2, 2, [R(3, 5), R(7, 5), R(1, 5), R(11, 1)]) # needs sage.modules
|
|
1032
|
+
sage: N = M^10 # needs sage.modules
|
|
1033
|
+
|
|
1034
|
+
The next syntax provides as easy way to select an interesting
|
|
1035
|
+
subset of variables (the selected subset consists of the four
|
|
1036
|
+
entries of the matrix ``N``)::
|
|
1037
|
+
|
|
1038
|
+
sage: prec.diffused_digits(N) # needs sage.geometry.polyhedron sage.modules
|
|
1039
|
+
17
|
|
1040
|
+
|
|
1041
|
+
Note that, in some cases, the number of diffused digits can be
|
|
1042
|
+
infinite::
|
|
1043
|
+
|
|
1044
|
+
sage: R = ZpLF(2)
|
|
1045
|
+
sage: prec = R.precision()
|
|
1046
|
+
sage: x = R(1, 10)
|
|
1047
|
+
sage: y = x
|
|
1048
|
+
sage: prec.diffused_digits([x, y]) # needs sage.geometry.polyhedron
|
|
1049
|
+
+Infinity
|
|
1050
|
+
"""
|
|
1051
|
+
try:
|
|
1052
|
+
M = self.precision_lattice(elements)
|
|
1053
|
+
except PrecisionError:
|
|
1054
|
+
return Infinity
|
|
1055
|
+
n = M.nrows()
|
|
1056
|
+
p = self._p
|
|
1057
|
+
return sum(M[i, i].valuation(p) - min(M[j, i].valuation(p) for j in range(i + 1)) for i in range(n))
|
|
1058
|
+
|
|
1059
|
+
def tracked_elements(self, values=True, dead=True):
|
|
1060
|
+
r"""
|
|
1061
|
+
Return the list of tracked elements.
|
|
1062
|
+
|
|
1063
|
+
INPUT:
|
|
1064
|
+
|
|
1065
|
+
- ``values`` -- boolean (default: ``True``); if ``False``,
|
|
1066
|
+
the method returns a list of weak references on tracked
|
|
1067
|
+
elements instead
|
|
1068
|
+
|
|
1069
|
+
- ``dead`` -- boolean (default: ``True``); whether dead
|
|
1070
|
+
elements for which the corresponding column is still not
|
|
1071
|
+
erased should be listed or not
|
|
1072
|
+
|
|
1073
|
+
EXAMPLES::
|
|
1074
|
+
|
|
1075
|
+
sage: R = ZpLC(2, label='tracked')
|
|
1076
|
+
sage: prec = R.precision()
|
|
1077
|
+
sage: x = R(1, 10); y = R(1, 5)
|
|
1078
|
+
sage: prec.tracked_elements()
|
|
1079
|
+
[1 + O(2^10), 1 + O(2^5)]
|
|
1080
|
+
sage: prec.tracked_elements(values=False)
|
|
1081
|
+
[WeakProxy#...,
|
|
1082
|
+
WeakProxy#...,
|
|
1083
|
+
WeakProxy#...]
|
|
1084
|
+
sage: prec.tracked_elements(values=False, dead=False)
|
|
1085
|
+
[WeakProxy#...,
|
|
1086
|
+
WeakProxy#...]
|
|
1087
|
+
|
|
1088
|
+
sage: # needs sage.rings.padics
|
|
1089
|
+
sage: u = x + y
|
|
1090
|
+
sage: v = x - y
|
|
1091
|
+
sage: prec.tracked_elements()
|
|
1092
|
+
[1 + O(2^10), 1 + O(2^5), 2 + O(2^5), O(2^5)]
|
|
1093
|
+
sage: prec.tracked_elements(values=False)
|
|
1094
|
+
[WeakProxy#...,
|
|
1095
|
+
WeakProxy#...,
|
|
1096
|
+
WeakProxy#...,
|
|
1097
|
+
WeakProxy#...,
|
|
1098
|
+
WeakProxy#...]
|
|
1099
|
+
sage: del x; del y
|
|
1100
|
+
sage: prec.tracked_elements()
|
|
1101
|
+
[None, None, 2 + O(2^5), O(2^5), None]
|
|
1102
|
+
sage: prec.tracked_elements(values=False)
|
|
1103
|
+
[WeakProxy#...,
|
|
1104
|
+
WeakProxy#...,
|
|
1105
|
+
WeakProxy#...]
|
|
1106
|
+
"""
|
|
1107
|
+
ret = [ ref for ref in self._elements if dead or ref() is not None]
|
|
1108
|
+
if values:
|
|
1109
|
+
ret = [ ref() for ref in ret ]
|
|
1110
|
+
return ret
|
|
1111
|
+
|
|
1112
|
+
# History
|
|
1113
|
+
|
|
1114
|
+
def history_enable(self):
|
|
1115
|
+
r"""
|
|
1116
|
+
Enable history.
|
|
1117
|
+
|
|
1118
|
+
We refer to the documentation of the method :meth:`history` for
|
|
1119
|
+
a complete documentation (including examples) about history.
|
|
1120
|
+
|
|
1121
|
+
TESTS::
|
|
1122
|
+
|
|
1123
|
+
sage: R = ZpLC(2, label='history_en')
|
|
1124
|
+
sage: prec = R.precision()
|
|
1125
|
+
|
|
1126
|
+
sage: print(prec.history()) # history is disabled by default
|
|
1127
|
+
Traceback (most recent call last):
|
|
1128
|
+
...
|
|
1129
|
+
ValueError: History is not tracked
|
|
1130
|
+
|
|
1131
|
+
sage: prec.history_enable()
|
|
1132
|
+
sage: print(prec.history())
|
|
1133
|
+
Timings
|
|
1134
|
+
---
|
|
1135
|
+
|
|
1136
|
+
.. SEEALSO::
|
|
1137
|
+
|
|
1138
|
+
:meth:`history`, :meth:`history_disable`, :meth:`history_clear`
|
|
1139
|
+
"""
|
|
1140
|
+
if self._history is None:
|
|
1141
|
+
self._history_init = ( len(self._elements), list(self._marked_for_deletion) )
|
|
1142
|
+
self._history = [ ]
|
|
1143
|
+
|
|
1144
|
+
def history_disable(self):
|
|
1145
|
+
r"""
|
|
1146
|
+
Disable history.
|
|
1147
|
+
|
|
1148
|
+
We refer to the documentation of the method :meth:`history` for
|
|
1149
|
+
a complete documentation (including examples) about history.
|
|
1150
|
+
|
|
1151
|
+
TESTS::
|
|
1152
|
+
|
|
1153
|
+
sage: R = ZpLC(2, label='history_dis')
|
|
1154
|
+
sage: prec = R.precision()
|
|
1155
|
+
|
|
1156
|
+
sage: print(prec.history()) # history is disabled by default
|
|
1157
|
+
Traceback (most recent call last):
|
|
1158
|
+
...
|
|
1159
|
+
ValueError: History is not tracked
|
|
1160
|
+
|
|
1161
|
+
sage: prec.history_enable()
|
|
1162
|
+
sage: print(prec.history())
|
|
1163
|
+
Timings
|
|
1164
|
+
---
|
|
1165
|
+
|
|
1166
|
+
sage: prec.history_disable()
|
|
1167
|
+
sage: print(prec.history())
|
|
1168
|
+
Traceback (most recent call last):
|
|
1169
|
+
...
|
|
1170
|
+
ValueError: History is not tracked
|
|
1171
|
+
|
|
1172
|
+
.. SEEALSO::
|
|
1173
|
+
|
|
1174
|
+
:meth:`history`, :meth:`history_enable`, :meth:`history_clear`
|
|
1175
|
+
"""
|
|
1176
|
+
self._history = self._history_init = None
|
|
1177
|
+
|
|
1178
|
+
def history_clear(self):
|
|
1179
|
+
r"""
|
|
1180
|
+
Clear history.
|
|
1181
|
+
|
|
1182
|
+
We refer to the documentation of the method :meth:`history` for
|
|
1183
|
+
a complete documentation (including examples) about history.
|
|
1184
|
+
|
|
1185
|
+
TESTS::
|
|
1186
|
+
|
|
1187
|
+
sage: R = ZpLC(2, label='history_clear')
|
|
1188
|
+
sage: prec = R.precision()
|
|
1189
|
+
sage: prec.history_enable()
|
|
1190
|
+
|
|
1191
|
+
sage: x = R(1, 10); y = R(1, 5)
|
|
1192
|
+
sage: x, y = x+y, x-y
|
|
1193
|
+
sage: print(prec.history()) # somewhat random
|
|
1194
|
+
Timings
|
|
1195
|
+
0.000213s oooo
|
|
1196
|
+
|
|
1197
|
+
When we clear history, only the last line is kept::
|
|
1198
|
+
|
|
1199
|
+
sage: prec.history_clear()
|
|
1200
|
+
sage: print(prec.history())
|
|
1201
|
+
Timings oooo
|
|
1202
|
+
--- oooo
|
|
1203
|
+
|
|
1204
|
+
sage: prec.del_elements()
|
|
1205
|
+
|
|
1206
|
+
sage: print(prec.history()) # somewhat random
|
|
1207
|
+
Timings oooo
|
|
1208
|
+
0.000005s ~~oo
|
|
1209
|
+
0.000285s oo
|
|
1210
|
+
|
|
1211
|
+
.. SEEALSO::
|
|
1212
|
+
|
|
1213
|
+
:meth:`history`, :meth:`history_enable`, :meth:`history_disable`
|
|
1214
|
+
"""
|
|
1215
|
+
if self._history is None:
|
|
1216
|
+
raise ValueError("History is not tracked")
|
|
1217
|
+
self._history_init = ( len(self._elements), list(self._marked_for_deletion) )
|
|
1218
|
+
self._history = [ ]
|
|
1219
|
+
|
|
1220
|
+
def _format_history(self, time, status, timings):
|
|
1221
|
+
r"""
|
|
1222
|
+
Return a formatted output for the history.
|
|
1223
|
+
|
|
1224
|
+
This is a helper function for the method :meth:`history`.
|
|
1225
|
+
|
|
1226
|
+
TESTS::
|
|
1227
|
+
|
|
1228
|
+
sage: R = ZpLC(2, label='history_en')
|
|
1229
|
+
sage: prec = R.precision()
|
|
1230
|
+
sage: prec._format_history(1.23456789, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
|
|
1231
|
+
'1.234568s oooooo~oo'
|
|
1232
|
+
sage: prec._format_history(1.23456789, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], false)
|
|
1233
|
+
'oooooo~oo'
|
|
1234
|
+
|
|
1235
|
+
sage: prec._format_history(12.3456789, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
|
|
1236
|
+
' >= 10s oooooo~oo'
|
|
1237
|
+
sage: prec._format_history(10^(-10), ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
|
|
1238
|
+
' --- oooooo~oo'
|
|
1239
|
+
sage: prec._format_history(-1, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
|
|
1240
|
+
' Timings oooooo~oo'
|
|
1241
|
+
"""
|
|
1242
|
+
status = ''.join(status)
|
|
1243
|
+
if timings:
|
|
1244
|
+
if time < 0:
|
|
1245
|
+
s = " Timings "
|
|
1246
|
+
elif time < 0.000001:
|
|
1247
|
+
s = " --- "
|
|
1248
|
+
elif time >= 10:
|
|
1249
|
+
s = " >= 10s "
|
|
1250
|
+
else:
|
|
1251
|
+
s = "%.6fs" % time
|
|
1252
|
+
return s + " " + status
|
|
1253
|
+
else:
|
|
1254
|
+
return status
|
|
1255
|
+
|
|
1256
|
+
def history(self, compact=True, separate_reduce=False, timings=True, output_type='asciiart'):
|
|
1257
|
+
r"""
|
|
1258
|
+
Show history.
|
|
1259
|
+
|
|
1260
|
+
The history records creations and deletions of elements attached
|
|
1261
|
+
to this precision lattice, together with many timings.
|
|
1262
|
+
|
|
1263
|
+
INPUT:
|
|
1264
|
+
|
|
1265
|
+
- ``compact`` -- boolean (default: ``True``); if ``True``, all
|
|
1266
|
+
consecutive operations of the same type appear on a single row
|
|
1267
|
+
|
|
1268
|
+
- ``separate_reduce`` -- boolean (default: ``False``); specify
|
|
1269
|
+
whether partial/full Hermite reduction should be displayed
|
|
1270
|
+
separately
|
|
1271
|
+
|
|
1272
|
+
- ``timings`` -- boolean (default: ``True``); specify whether
|
|
1273
|
+
timings should be displayed
|
|
1274
|
+
|
|
1275
|
+
- ``output_type`` -- only ``asciiart`` is implemented for now
|
|
1276
|
+
|
|
1277
|
+
IMPORTANT NOTE:
|
|
1278
|
+
|
|
1279
|
+
History is disabled by default.
|
|
1280
|
+
It should then be enabled (through a call to the method :meth:`history_enable`)
|
|
1281
|
+
before use.
|
|
1282
|
+
|
|
1283
|
+
EXAMPLES::
|
|
1284
|
+
|
|
1285
|
+
sage: R = ZpLC(2, label='history_en')
|
|
1286
|
+
sage: prec = R.precision()
|
|
1287
|
+
|
|
1288
|
+
We first enable history::
|
|
1289
|
+
|
|
1290
|
+
sage: prec.history_enable()
|
|
1291
|
+
|
|
1292
|
+
At the beginning, the history is of course empty::
|
|
1293
|
+
|
|
1294
|
+
sage: print(prec.history())
|
|
1295
|
+
Timings
|
|
1296
|
+
---
|
|
1297
|
+
|
|
1298
|
+
Now we start creating and deleting elements::
|
|
1299
|
+
|
|
1300
|
+
sage: L = [ R.random_element() for _ in range(20) ]
|
|
1301
|
+
sage: for p in range(20):
|
|
1302
|
+
....: if is_prime(p): L[p] = None
|
|
1303
|
+
sage: prec.del_elements()
|
|
1304
|
+
|
|
1305
|
+
sage: print(prec.history()) # somewhat random
|
|
1306
|
+
Timings
|
|
1307
|
+
0.001108s oooooooooooooooooooo
|
|
1308
|
+
0.000009s oo~~o~o~ooo~o~ooo~o~
|
|
1309
|
+
0.014250s oooooooooooo
|
|
1310
|
+
|
|
1311
|
+
The legend is the following:
|
|
1312
|
+
|
|
1313
|
+
- the symbol ``o`` represents a tracked element,
|
|
1314
|
+
- the symbol ``~`` represents an element which is marked for deletion.
|
|
1315
|
+
|
|
1316
|
+
On the history, we see:
|
|
1317
|
+
|
|
1318
|
+
- 1st line: twenty new elements were created
|
|
1319
|
+
(this corresponds to the affectation of the list ``L``);
|
|
1320
|
+
- 2nd line: elements at prime positions were marked for deletion
|
|
1321
|
+
(this corresponds to the ``for`` loop);
|
|
1322
|
+
- 3rd line: the above elements are indeed deleted
|
|
1323
|
+
(this corresponds to the call of the method :meth:`del_elements`.
|
|
1324
|
+
|
|
1325
|
+
Here are some variants::
|
|
1326
|
+
|
|
1327
|
+
sage: print(prec.history(timings=False))
|
|
1328
|
+
oooooooooooooooooooo
|
|
1329
|
+
oo~~o~o~ooo~o~ooo~o~
|
|
1330
|
+
oooooooooooo
|
|
1331
|
+
|
|
1332
|
+
sage: print(prec.history(separate_reduce=True)) # somewhat random
|
|
1333
|
+
Timings
|
|
1334
|
+
0.001063s oooooooooooooooooooo
|
|
1335
|
+
0.000014s oo~~o~o~ooo~o~ooo~o~
|
|
1336
|
+
0.000798s oo~~o~o~ooo~ooooo
|
|
1337
|
+
0.000233s oo~~o~o~ooo~orrrr
|
|
1338
|
+
0.000824s oo~~o~o~oooooooo
|
|
1339
|
+
0.000375s oo~~o~o~ooorrrrr
|
|
1340
|
+
0.001724s oo~~o~ooooooooo
|
|
1341
|
+
0.001020s oo~~o~orrrrrrrr
|
|
1342
|
+
0.001989s oo~~oooooooooo
|
|
1343
|
+
0.001303s oo~~orrrrrrrrr
|
|
1344
|
+
0.002352s oo~oooooooooo
|
|
1345
|
+
0.001632s oo~rrrrrrrrrr
|
|
1346
|
+
0.002265s oooooooooooo
|
|
1347
|
+
0.001630s oorrrrrrrrrr
|
|
1348
|
+
--- oooooooooooo
|
|
1349
|
+
|
|
1350
|
+
The symbol ``r`` represents a column of the precision matrix which is
|
|
1351
|
+
currently under partial Hermite reduction.
|
|
1352
|
+
|
|
1353
|
+
Timings for automatic reduction do not appear because they are included
|
|
1354
|
+
in the timings for deletion.
|
|
1355
|
+
|
|
1356
|
+
The symbol ``R`` is used to symbolize a column which is under full
|
|
1357
|
+
Hermite reduction. Note that full Hermite reduction are never performed
|
|
1358
|
+
automatically but needs to be called by hand::
|
|
1359
|
+
|
|
1360
|
+
sage: prec.reduce()
|
|
1361
|
+
sage: print(prec.history(separate_reduce=True)) # somewhat random
|
|
1362
|
+
Timings
|
|
1363
|
+
0.001063s oooooooooooooooooooo
|
|
1364
|
+
0.000014s oo~~o~o~ooo~o~ooo~o~
|
|
1365
|
+
0.000798s oo~~o~o~ooo~ooooo
|
|
1366
|
+
0.000233s oo~~o~o~ooo~orrrr
|
|
1367
|
+
0.000824s oo~~o~o~oooooooo
|
|
1368
|
+
0.000375s oo~~o~o~ooorrrrr
|
|
1369
|
+
0.001724s oo~~o~ooooooooo
|
|
1370
|
+
0.001020s oo~~o~orrrrrrrr
|
|
1371
|
+
0.001989s oo~~oooooooooo
|
|
1372
|
+
0.001303s oo~~orrrrrrrrr
|
|
1373
|
+
0.002352s oo~oooooooooo
|
|
1374
|
+
0.001632s oo~rrrrrrrrrr
|
|
1375
|
+
0.002265s oooooooooooo
|
|
1376
|
+
0.001630s oorrrrrrrrrr
|
|
1377
|
+
0.001486s RRRRRRRRRRRR
|
|
1378
|
+
--- oooooooooooo
|
|
1379
|
+
|
|
1380
|
+
Here is a more common example with matrices::
|
|
1381
|
+
|
|
1382
|
+
sage: R = ZpLC(3)
|
|
1383
|
+
sage: prec = R.precision()
|
|
1384
|
+
sage: prec.history_enable()
|
|
1385
|
+
sage: M = random_matrix(R, 5) # needs sage.geometry.polyhedron
|
|
1386
|
+
sage: d = M.determinant() # needs sage.geometry.polyhedron
|
|
1387
|
+
sage: print(prec.history()) # somewhat random
|
|
1388
|
+
---
|
|
1389
|
+
0.004212s oooooooooooooooooooooooooooooooooooo
|
|
1390
|
+
0.000003s oooooooooooooooooooooooooooooooooo~~
|
|
1391
|
+
0.000010s oooooooooooooooooooooooooooooooooo
|
|
1392
|
+
0.001560s ooooooooooooooooooooooooooooooooooooooooo
|
|
1393
|
+
0.000004s ooooooooooooooooooooooooooooo~oooo~oooo~o
|
|
1394
|
+
0.002168s oooooooooooooooooooooooooooooooooooooo
|
|
1395
|
+
0.001787s ooooooooooooooooooooooooooooooooooooooooo
|
|
1396
|
+
0.000004s oooooooooooooooooooooooooooooooooooooo~~o
|
|
1397
|
+
0.000198s ooooooooooooooooooooooooooooooooooooooo
|
|
1398
|
+
0.001152s ooooooooooooooooooooooooooooooooooooooooo
|
|
1399
|
+
0.000005s ooooooooooooooooooooooooooooooooo~oooo~~o
|
|
1400
|
+
0.000853s oooooooooooooooooooooooooooooooooooooo
|
|
1401
|
+
0.000610s ooooooooooooooooooooooooooooooooooooooo
|
|
1402
|
+
[...]
|
|
1403
|
+
0.003879s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1404
|
+
0.000006s oooooooooooooooooooooooooooooooooooooooooooooooooooo~~~~~
|
|
1405
|
+
0.000036s oooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1406
|
+
0.006737s oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1407
|
+
0.000005s oooooooooooooooooooooooooooooooooooooooooooooooooooo~~~~~ooooo
|
|
1408
|
+
0.002637s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1409
|
+
0.007118s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1410
|
+
0.000008s oooooooooooooooooooooooooooooooooooooooooooooooooooo~~~~o~~~~oooo
|
|
1411
|
+
0.003504s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1412
|
+
0.005371s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1413
|
+
0.000006s ooooooooooooooooooooooooooooooooooooooooooooooooooooo~~~o~~~ooo
|
|
1414
|
+
0.001858s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1415
|
+
0.003584s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1416
|
+
0.000004s oooooooooooooooooooooooooooooooooooooooooooooooooooooo~~o~~oo
|
|
1417
|
+
0.000801s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1418
|
+
0.001916s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
|
|
1419
|
+
0.000022s ooooooooooooooooooooooooooooo~~~~~~~~~~~~~~~~~~~~~~oooo~o~o
|
|
1420
|
+
0.014705s ooooooooooooooooooooooooooooooooooo
|
|
1421
|
+
0.001292s ooooooooooooooooooooooooooooooooooooo
|
|
1422
|
+
|
|
1423
|
+
We observe that deleted variables appear mostly on the right.
|
|
1424
|
+
This is the so-called principal of temporal locality.
|
|
1425
|
+
|
|
1426
|
+
.. SEEALSO::
|
|
1427
|
+
|
|
1428
|
+
:meth:`history_enable`, :meth:`history_disable`, :meth:`history_clear`
|
|
1429
|
+
"""
|
|
1430
|
+
if self._history is None:
|
|
1431
|
+
raise ValueError("History is not tracked")
|
|
1432
|
+
total_time = 0
|
|
1433
|
+
if output_type == 'asciiart':
|
|
1434
|
+
# Legend:
|
|
1435
|
+
# o : tracked element
|
|
1436
|
+
# ~ : element marked for deletion
|
|
1437
|
+
# r : partial reduction
|
|
1438
|
+
# R : full Hermite reduction
|
|
1439
|
+
(n, mark) = self._history_init
|
|
1440
|
+
status = n*['o']
|
|
1441
|
+
for index in mark:
|
|
1442
|
+
status[index] = '~'
|
|
1443
|
+
hist = [ self._format_history(-1, status, timings) ]
|
|
1444
|
+
oldevent = ''
|
|
1445
|
+
total_time = 0
|
|
1446
|
+
for (event, index, tme) in self._history:
|
|
1447
|
+
if event == 'partial reduce' or event == 'full reduce':
|
|
1448
|
+
if separate_reduce:
|
|
1449
|
+
if status:
|
|
1450
|
+
hist.append(self._format_history(total_time, status, timings))
|
|
1451
|
+
if event == 'partial reduce':
|
|
1452
|
+
code = 'r'
|
|
1453
|
+
else:
|
|
1454
|
+
code = 'R'
|
|
1455
|
+
status_red = status[:index] + (len(status) - index) * [code]
|
|
1456
|
+
hist.append(self._format_history(tme, status_red, timings))
|
|
1457
|
+
total_time = 0
|
|
1458
|
+
oldevent = ''
|
|
1459
|
+
else:
|
|
1460
|
+
total_time += tme
|
|
1461
|
+
continue
|
|
1462
|
+
if not compact or event != oldevent:
|
|
1463
|
+
if status:
|
|
1464
|
+
hist.append(self._format_history(total_time, status, timings))
|
|
1465
|
+
total_time = 0
|
|
1466
|
+
oldevent = event
|
|
1467
|
+
total_time += tme
|
|
1468
|
+
if event == 'add':
|
|
1469
|
+
if index is None:
|
|
1470
|
+
status.append('o')
|
|
1471
|
+
else:
|
|
1472
|
+
status = status[:index] + ['o'] + status[index:]
|
|
1473
|
+
elif event == 'mark':
|
|
1474
|
+
status[index] = '~'
|
|
1475
|
+
elif event == 'del':
|
|
1476
|
+
del status[index]
|
|
1477
|
+
if status or oldevent == '':
|
|
1478
|
+
hist.append(self._format_history(total_time, status, timings))
|
|
1479
|
+
return '\n'.join(hist)
|
|
1480
|
+
else:
|
|
1481
|
+
raise NotImplementedError
|
|
1482
|
+
|
|
1483
|
+
def timings(self, action=None):
|
|
1484
|
+
r"""
|
|
1485
|
+
Return cumulated timings (grouped by actions) since the last
|
|
1486
|
+
time history has been cleared.
|
|
1487
|
+
|
|
1488
|
+
INPUT:
|
|
1489
|
+
|
|
1490
|
+
- ``action`` -- ``None`` (default), ``'add'``, ``'mark'``, ``'del'``,
|
|
1491
|
+
``'partial reduce'`` or ``'full reduce'``; if not ``None``, return the
|
|
1492
|
+
cumulated timing corresponding to this action; otherwise, return
|
|
1493
|
+
a dictionary
|
|
1494
|
+
|
|
1495
|
+
Here are the meanings of the keywords above:
|
|
1496
|
+
|
|
1497
|
+
- ``'add'``: time spent in adding new columns to the precision matrix
|
|
1498
|
+
(corresponding to the creation of new elements)
|
|
1499
|
+
- ``'mark'``: time spent in marking elements for deletion
|
|
1500
|
+
- ``'del'``: time spent in deleting columns of the precision matrix
|
|
1501
|
+
and re-echelonizing the matrix
|
|
1502
|
+
- ``'partial reduce'``: time spent in partial Hermite reduction
|
|
1503
|
+
- ``'full reduce'``: time spent in full Hermite reduction.
|
|
1504
|
+
|
|
1505
|
+
EXAMPLES::
|
|
1506
|
+
|
|
1507
|
+
sage: R = ZpLC(2, label='timings')
|
|
1508
|
+
sage: prec = R.precision()
|
|
1509
|
+
sage: prec.history_enable()
|
|
1510
|
+
sage: M = random_matrix(R, 5, 5) # needs sage.geometry.polyhedron
|
|
1511
|
+
sage: N = M^10 # needs sage.geometry.polyhedron
|
|
1512
|
+
sage: prec.timings() # somewhat random
|
|
1513
|
+
{'add': 1.0530245304107666,
|
|
1514
|
+
'del': 0.24358701705932617,
|
|
1515
|
+
'mark': 0.0013289451599121094,
|
|
1516
|
+
'partial reduce': 0.21604204177856445
|
|
1517
|
+
'full reduce': 0}
|
|
1518
|
+
|
|
1519
|
+
TESTS::
|
|
1520
|
+
|
|
1521
|
+
sage: prec.history_clear()
|
|
1522
|
+
sage: prec.timings()
|
|
1523
|
+
{'add': 0, 'del': 0, 'full reduce': 0, 'mark': 0, 'partial reduce': 0}
|
|
1524
|
+
"""
|
|
1525
|
+
if self._history is None:
|
|
1526
|
+
raise ValueError("History is not tracked")
|
|
1527
|
+
tme_by_event = { 'add': 0, 'del': 0, 'mark': 0, 'partial reduce': 0, 'full reduce': 0 }
|
|
1528
|
+
for (event, _, tme) in self._history:
|
|
1529
|
+
tme_by_event[event] += tme
|
|
1530
|
+
if action is None:
|
|
1531
|
+
return tme_by_event
|
|
1532
|
+
if action in tme_by_event:
|
|
1533
|
+
return tme_by_event[action]
|
|
1534
|
+
else:
|
|
1535
|
+
raise ValueError("invalid event")
|
|
1536
|
+
|
|
1537
|
+
|
|
1538
|
+
class PrecisionLattice(UniqueRepresentation, DifferentialPrecisionGeneric):
|
|
1539
|
+
r"""
|
|
1540
|
+
A class for handling precision lattices which are used to
|
|
1541
|
+
track precision in the ZpLC model.
|
|
1542
|
+
|
|
1543
|
+
The precision lattice is stored as a triangular matrix whose
|
|
1544
|
+
rows are generators of the lattice.
|
|
1545
|
+
|
|
1546
|
+
INPUT:
|
|
1547
|
+
|
|
1548
|
+
- ``p`` -- a prime number
|
|
1549
|
+
|
|
1550
|
+
- ``label`` -- string; the label of the parents to which the elements
|
|
1551
|
+
tracked by this lattice belong
|
|
1552
|
+
|
|
1553
|
+
.. NOTE::
|
|
1554
|
+
|
|
1555
|
+
You should not create instances of this class directly. The precision
|
|
1556
|
+
lattice is automatically initialized at the creation of the parent.
|
|
1557
|
+
|
|
1558
|
+
EXAMPLES::
|
|
1559
|
+
|
|
1560
|
+
sage: R = ZpLC(2, label='init')
|
|
1561
|
+
sage: R.precision()
|
|
1562
|
+
Precision lattice on 0 objects (label: init)
|
|
1563
|
+
"""
|
|
1564
|
+
def __init__(self, p, label):
|
|
1565
|
+
r"""
|
|
1566
|
+
TESTS::
|
|
1567
|
+
|
|
1568
|
+
sage: from sage.rings.padics.lattice_precision import PrecisionLattice
|
|
1569
|
+
sage: R = ZpLC(2)
|
|
1570
|
+
sage: isinstance(R.precision(), PrecisionLattice)
|
|
1571
|
+
True
|
|
1572
|
+
"""
|
|
1573
|
+
DifferentialPrecisionGeneric.__init__(self, p, label)
|
|
1574
|
+
self._repr_type = "Precision lattice"
|
|
1575
|
+
self._capped = { }
|
|
1576
|
+
|
|
1577
|
+
# We need to copy this method.
|
|
1578
|
+
# Indeed otherwise it is inherited from UniqueRepresentation
|
|
1579
|
+
def __reduce__(self):
|
|
1580
|
+
r"""
|
|
1581
|
+
TESTS::
|
|
1582
|
+
|
|
1583
|
+
sage: R = ZpLC(2)
|
|
1584
|
+
sage: prec = R.precision()
|
|
1585
|
+
sage: dumps(prec)
|
|
1586
|
+
Traceback (most recent call last):
|
|
1587
|
+
...
|
|
1588
|
+
NotImplementedError: pickling/unpickling precision modules is not implemented yet
|
|
1589
|
+
"""
|
|
1590
|
+
raise NotImplementedError("pickling/unpickling precision modules is not implemented yet")
|
|
1591
|
+
|
|
1592
|
+
def _index(self, ref):
|
|
1593
|
+
r"""
|
|
1594
|
+
Return the index of the element whose reference is ``ref``.
|
|
1595
|
+
|
|
1596
|
+
TESTS::
|
|
1597
|
+
|
|
1598
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
1599
|
+
sage: R = ZpLC(2, label='index')
|
|
1600
|
+
sage: prec = R.precision()
|
|
1601
|
+
sage: x = R(1, 10)
|
|
1602
|
+
sage: y = R(1, 5)
|
|
1603
|
+
|
|
1604
|
+
sage: prec._index(pAdicLatticeElementWeakProxy(x))
|
|
1605
|
+
0
|
|
1606
|
+
sage: prec._index(pAdicLatticeElementWeakProxy(y))
|
|
1607
|
+
1
|
|
1608
|
+
|
|
1609
|
+
sage: del x
|
|
1610
|
+
sage: prec.del_elements()
|
|
1611
|
+
sage: prec._index(pAdicLatticeElementWeakProxy(y))
|
|
1612
|
+
0
|
|
1613
|
+
"""
|
|
1614
|
+
return len(self._matrix[ref]) - 1
|
|
1615
|
+
|
|
1616
|
+
def dimension(self):
|
|
1617
|
+
r"""
|
|
1618
|
+
Return the dimension of this lattice.
|
|
1619
|
+
|
|
1620
|
+
EXAMPLES::
|
|
1621
|
+
|
|
1622
|
+
sage: R = ZpLC(5, label='dimension')
|
|
1623
|
+
sage: prec = R.precision()
|
|
1624
|
+
sage: prec.dimension()
|
|
1625
|
+
0
|
|
1626
|
+
|
|
1627
|
+
sage: x = R(1, 10)
|
|
1628
|
+
sage: prec.dimension()
|
|
1629
|
+
1
|
|
1630
|
+
"""
|
|
1631
|
+
return len(self._matrix)
|
|
1632
|
+
|
|
1633
|
+
def reduce(self, index=0, partial=False):
|
|
1634
|
+
r"""
|
|
1635
|
+
Reduce the size of the entries above the diagonal of the precision matrix.
|
|
1636
|
+
|
|
1637
|
+
INPUT:
|
|
1638
|
+
|
|
1639
|
+
- ``index`` -- integer; the starting row for which the reduction
|
|
1640
|
+
is performed
|
|
1641
|
+
|
|
1642
|
+
- ``partial`` -- boolean (default: ``False``); specifying whether a
|
|
1643
|
+
partial or a full Hermite reduction should be performed
|
|
1644
|
+
|
|
1645
|
+
NOTE:
|
|
1646
|
+
|
|
1647
|
+
The partial reduction has cost `O(m^2)` where `m` is the number of
|
|
1648
|
+
rows that need to be reduced (that is the difference between the
|
|
1649
|
+
total number of rows and ``index``).
|
|
1650
|
+
|
|
1651
|
+
The full Hermite reduction has cost `O(m^3)`.
|
|
1652
|
+
|
|
1653
|
+
.. NOTE::
|
|
1654
|
+
|
|
1655
|
+
The software ensures that the precision lattice is always partially
|
|
1656
|
+
reduced. Calling the function manually with the argument
|
|
1657
|
+
``partial=True`` should then just do nothing.
|
|
1658
|
+
|
|
1659
|
+
TESTS::
|
|
1660
|
+
|
|
1661
|
+
sage: R = ZpLC(2)
|
|
1662
|
+
sage: x = R.random_element()
|
|
1663
|
+
sage: del x
|
|
1664
|
+
sage: R.precision().del_elements() # indirect doctest
|
|
1665
|
+
"""
|
|
1666
|
+
n = len(self._elements)
|
|
1667
|
+
if index >= n-1:
|
|
1668
|
+
return
|
|
1669
|
+
if partial:
|
|
1670
|
+
# Partial reduction
|
|
1671
|
+
# Cost: O(m^2) with m = n-index
|
|
1672
|
+
tme = walltime()
|
|
1673
|
+
diffval = (n-index) * [0]
|
|
1674
|
+
for j in range(n-1, index, -1):
|
|
1675
|
+
col = self._matrix[self._elements[j]]
|
|
1676
|
+
prec = col[j].valuation() - diffval[j-index]
|
|
1677
|
+
for i in range(index, j):
|
|
1678
|
+
col[i] = col[i].reduce(prec)
|
|
1679
|
+
col[i].normalize()
|
|
1680
|
+
dval = col[i].valuation() - prec
|
|
1681
|
+
diffval[i-index] = min(dval, diffval[i-index])
|
|
1682
|
+
# We update history
|
|
1683
|
+
if self._history is not None:
|
|
1684
|
+
self._history.append(('partial reduce', index, walltime(tme)))
|
|
1685
|
+
else:
|
|
1686
|
+
# Full Hermite reduction
|
|
1687
|
+
# Cost: O(m^3) with m = n-index
|
|
1688
|
+
tme = walltime()
|
|
1689
|
+
for j in range(index+1, n):
|
|
1690
|
+
# In what follows, we assume that col[j] is a power of p
|
|
1691
|
+
col = self._matrix[self._elements[j]]
|
|
1692
|
+
valpivot = col[j].valuation()
|
|
1693
|
+
for i in range(index, j):
|
|
1694
|
+
reduced = col[i].reduce(valpivot)
|
|
1695
|
+
scalar = (col[i] - reduced) >> valpivot
|
|
1696
|
+
if scalar.is_zero():
|
|
1697
|
+
continue
|
|
1698
|
+
col[i] = reduced
|
|
1699
|
+
col[i].normalize()
|
|
1700
|
+
for j2 in range(j+1, n):
|
|
1701
|
+
col2 = self._matrix[self._elements[j2]]
|
|
1702
|
+
col2[i] -= scalar*col2[i]
|
|
1703
|
+
col2[i].normalize()
|
|
1704
|
+
# We update history
|
|
1705
|
+
if self._history is not None:
|
|
1706
|
+
self._history.append(('full reduce', index, walltime(tme)))
|
|
1707
|
+
|
|
1708
|
+
def _new_element(self, x, dx, bigoh, dx_mode='linear_combination', capped=False):
|
|
1709
|
+
r"""
|
|
1710
|
+
Update the lattice when a new element is created.
|
|
1711
|
+
|
|
1712
|
+
This function is not meant to be called manually.
|
|
1713
|
+
It is automatically called by the parent when a new
|
|
1714
|
+
element is created.
|
|
1715
|
+
|
|
1716
|
+
INPUT:
|
|
1717
|
+
|
|
1718
|
+
- ``x`` -- the newly created element
|
|
1719
|
+
|
|
1720
|
+
- ``dx`` -- dictionary representing the differential of ``x``
|
|
1721
|
+
|
|
1722
|
+
- ``bigoh`` -- integer or ``None`` (default: ``None``); the
|
|
1723
|
+
bigoh to be added to the precision of ``x``; if ``None``, the
|
|
1724
|
+
default cap is used.
|
|
1725
|
+
|
|
1726
|
+
- ``dx_mode`` -- string; either ``linear_combination`` (the default)
|
|
1727
|
+
or ``values``
|
|
1728
|
+
|
|
1729
|
+
- ``capped`` -- boolean; whether this element has been capped
|
|
1730
|
+
according to the parent's cap
|
|
1731
|
+
|
|
1732
|
+
If ``dx_mode`` is ``linear_combination``, the dictionary ``dx``
|
|
1733
|
+
encodes the expression of the differential of ``x``.
|
|
1734
|
+
For example, if ``x`` was defined as ``x = y*z`` then:
|
|
1735
|
+
|
|
1736
|
+
.. MATH::
|
|
1737
|
+
|
|
1738
|
+
dx = y dz + z dy
|
|
1739
|
+
|
|
1740
|
+
and the corresponding dictionary is ``{z: y, y: z}`` (except
|
|
1741
|
+
that the keys are not the elements themselves but weak references
|
|
1742
|
+
to them).
|
|
1743
|
+
|
|
1744
|
+
If ``dx_mode`` is ``values``, the dictionary ``dx`` directly
|
|
1745
|
+
specifies the entries that have to be stored in the precision lattice.
|
|
1746
|
+
This mode is only used for multiple conversion between different
|
|
1747
|
+
parents (see :meth:`multiple_conversion`).
|
|
1748
|
+
|
|
1749
|
+
TESTS::
|
|
1750
|
+
|
|
1751
|
+
sage: R = ZpLC(2)
|
|
1752
|
+
sage: x = R.random_element()
|
|
1753
|
+
sage: y = R.random_element()
|
|
1754
|
+
sage: z = x*y # indirect doctest
|
|
1755
|
+
"""
|
|
1756
|
+
# First we delete some elements marked for deletion
|
|
1757
|
+
self.del_elements(threshold=self._threshold_deletion)
|
|
1758
|
+
|
|
1759
|
+
# Then we add the new element
|
|
1760
|
+
tme = walltime()
|
|
1761
|
+
p = self._p
|
|
1762
|
+
n = len(self._elements)
|
|
1763
|
+
x_ref = pAdicLatticeElementWeakProxy(x, self._record_collected_element)
|
|
1764
|
+
self._elements.append(x_ref)
|
|
1765
|
+
col = n * [self._approx_zero]
|
|
1766
|
+
if dx_mode == 'linear_combination':
|
|
1767
|
+
for elt, scalar in dx:
|
|
1768
|
+
ref = pAdicLatticeElementWeakProxy(elt)
|
|
1769
|
+
if not isinstance(scalar, pRational):
|
|
1770
|
+
scalar = pRational(p, scalar)
|
|
1771
|
+
c = self._matrix[ref]
|
|
1772
|
+
for i in range(len(c)):
|
|
1773
|
+
col[i] += scalar * c[i]
|
|
1774
|
+
elif dx_mode == 'values':
|
|
1775
|
+
for elt, scalar in dx:
|
|
1776
|
+
ref = pAdicLatticeElementWeakProxy(elt)
|
|
1777
|
+
if not isinstance(scalar, pRational):
|
|
1778
|
+
scalar = pRational(p, scalar)
|
|
1779
|
+
i = self._index(ref)
|
|
1780
|
+
col[i] = scalar
|
|
1781
|
+
else:
|
|
1782
|
+
raise ValueError("dx_mode must be either 'linear_combination' or 'values'")
|
|
1783
|
+
for i in range(n):
|
|
1784
|
+
col[i] = col[i].reduce(bigoh)
|
|
1785
|
+
col.append(pRational(p, ZZ(1), bigoh))
|
|
1786
|
+
self._matrix[x_ref] = col
|
|
1787
|
+
self._capped[x_ref] = capped
|
|
1788
|
+
|
|
1789
|
+
# We update history
|
|
1790
|
+
if self._history is not None:
|
|
1791
|
+
self._history.append(('add', None, walltime(tme)))
|
|
1792
|
+
|
|
1793
|
+
def del_elements(self, threshold=None):
|
|
1794
|
+
r"""
|
|
1795
|
+
Erase columns of the lattice precision matrix corresponding to
|
|
1796
|
+
elements which are marked for deletion and echelonize the matrix
|
|
1797
|
+
in order to keep it upper triangular.
|
|
1798
|
+
|
|
1799
|
+
INPUT:
|
|
1800
|
+
|
|
1801
|
+
- ``threshold`` -- integer or ``None`` (default: ``None``);
|
|
1802
|
+
a column whose distance to the right is greater than the
|
|
1803
|
+
threshold is not erased
|
|
1804
|
+
|
|
1805
|
+
EXAMPLES::
|
|
1806
|
+
|
|
1807
|
+
sage: R = ZpLC(2, label='delelts')
|
|
1808
|
+
sage: prec = R.precision()
|
|
1809
|
+
|
|
1810
|
+
sage: x = R(1, 10)
|
|
1811
|
+
sage: prec
|
|
1812
|
+
Precision lattice on 1 object (label: delelts)
|
|
1813
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
1814
|
+
[1024]
|
|
1815
|
+
|
|
1816
|
+
sage: del x
|
|
1817
|
+
sage: prec
|
|
1818
|
+
Precision lattice on 1 object (label: delelts)
|
|
1819
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
1820
|
+
[1024]
|
|
1821
|
+
|
|
1822
|
+
sage: prec.del_elements()
|
|
1823
|
+
sage: prec
|
|
1824
|
+
Precision lattice on 0 objects (label: delelts)
|
|
1825
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
1826
|
+
[]
|
|
1827
|
+
"""
|
|
1828
|
+
n = len(self._elements)
|
|
1829
|
+
|
|
1830
|
+
# We mark new collected elements for deletion
|
|
1831
|
+
# The list self._collected_references can be updated while
|
|
1832
|
+
# the loop runs.
|
|
1833
|
+
# However, we do not need to copy it because Python supports
|
|
1834
|
+
# iteration over a list to which elements are added.
|
|
1835
|
+
count = 0
|
|
1836
|
+
for ref in self._collected_references:
|
|
1837
|
+
count += 1
|
|
1838
|
+
tme = walltime()
|
|
1839
|
+
index = self._index(ref)
|
|
1840
|
+
self._marked_for_deletion.append(index)
|
|
1841
|
+
if self._history is not None:
|
|
1842
|
+
self._history.append(('mark', index, walltime(tme)))
|
|
1843
|
+
del self._collected_references[:count]
|
|
1844
|
+
|
|
1845
|
+
# We erase corresponding columns and echelonize
|
|
1846
|
+
self._marked_for_deletion.sort(reverse=True)
|
|
1847
|
+
count = 0
|
|
1848
|
+
for index in self._marked_for_deletion:
|
|
1849
|
+
if threshold is not None and index < n - threshold:
|
|
1850
|
+
break
|
|
1851
|
+
n -= 1
|
|
1852
|
+
count += 1
|
|
1853
|
+
|
|
1854
|
+
tme = walltime()
|
|
1855
|
+
ref = self._elements[index]
|
|
1856
|
+
del self._elements[index]
|
|
1857
|
+
del self._matrix[ref]
|
|
1858
|
+
capped = self._capped[ref]
|
|
1859
|
+
del self._capped[ref]
|
|
1860
|
+
|
|
1861
|
+
# Now, we echelonize
|
|
1862
|
+
for i in range(index, n):
|
|
1863
|
+
ref = self._elements[i]
|
|
1864
|
+
col = self._matrix[ref]
|
|
1865
|
+
if col[i].valuation() < col[i+1].valuation():
|
|
1866
|
+
self._capped[ref], capped = capped, capped or self._capped[ref]
|
|
1867
|
+
else:
|
|
1868
|
+
capped = capped or self._capped[ref]
|
|
1869
|
+
|
|
1870
|
+
d, u, v = col[i].xgcd(col[i+1])
|
|
1871
|
+
up, vp = col[i+1]/d, col[i]/d
|
|
1872
|
+
col[i] = d
|
|
1873
|
+
del col[i+1]
|
|
1874
|
+
for j in range(i+1, n):
|
|
1875
|
+
col = self._matrix[self._elements[j]]
|
|
1876
|
+
col[i], col[i+1] = u*col[i] + v*col[i+1], up*col[i] - vp*col[i+1]
|
|
1877
|
+
|
|
1878
|
+
# We update history
|
|
1879
|
+
if self._history is not None:
|
|
1880
|
+
self._history.append(('del', index, walltime(tme)))
|
|
1881
|
+
|
|
1882
|
+
# And we reduce a bit
|
|
1883
|
+
# (we do not perform a complete reduction because it is costly)
|
|
1884
|
+
self.reduce(index, partial=True)
|
|
1885
|
+
|
|
1886
|
+
del self._marked_for_deletion[:count]
|
|
1887
|
+
|
|
1888
|
+
def _lift_to_precision(self, x, prec):
|
|
1889
|
+
r"""
|
|
1890
|
+
Lift the specified element to the specified precision.
|
|
1891
|
+
|
|
1892
|
+
INPUT:
|
|
1893
|
+
|
|
1894
|
+
- ``x`` -- the element whose precision has to be lifted
|
|
1895
|
+
|
|
1896
|
+
- ``prec`` -- the new precision
|
|
1897
|
+
|
|
1898
|
+
NOTE:
|
|
1899
|
+
|
|
1900
|
+
The new precision lattice is computed as the intersection
|
|
1901
|
+
of the current precision lattice with the subspace
|
|
1902
|
+
|
|
1903
|
+
.. MATH::
|
|
1904
|
+
|
|
1905
|
+
p^{prec} \Z_p dx \oplus \bigoplus_{y \neq x} \Q_p dy
|
|
1906
|
+
|
|
1907
|
+
This function may change at the same time the precision of
|
|
1908
|
+
other elements having the same parent.
|
|
1909
|
+
|
|
1910
|
+
.. NOTE::
|
|
1911
|
+
|
|
1912
|
+
This function is not meant to be called directly. Use
|
|
1913
|
+
``x.lift_to_precision`` instead.
|
|
1914
|
+
|
|
1915
|
+
EXAMPLES::
|
|
1916
|
+
|
|
1917
|
+
sage: R = ZpLC(2)
|
|
1918
|
+
sage: x = R(1, 10); x
|
|
1919
|
+
1 + O(2^10)
|
|
1920
|
+
sage: y = R(1, 5); y
|
|
1921
|
+
1 + O(2^5)
|
|
1922
|
+
sage: z = x + y; z
|
|
1923
|
+
2 + O(2^5)
|
|
1924
|
+
|
|
1925
|
+
sage: prec = R.precision()
|
|
1926
|
+
sage: prec._lift_to_precision(z, 12)
|
|
1927
|
+
sage: z
|
|
1928
|
+
2 + O(2^12)
|
|
1929
|
+
sage: y
|
|
1930
|
+
1 + O(2^10)
|
|
1931
|
+
"""
|
|
1932
|
+
ref = pAdicLatticeElementWeakProxy(x)
|
|
1933
|
+
col = self._matrix[ref]
|
|
1934
|
+
n = len(self._elements)
|
|
1935
|
+
|
|
1936
|
+
rows_by_val = defaultdict(list)
|
|
1937
|
+
for i in range(len(col)):
|
|
1938
|
+
v = col[i].valuation()
|
|
1939
|
+
if v >= prec:
|
|
1940
|
+
continue
|
|
1941
|
+
rows_by_val[v].append(i)
|
|
1942
|
+
vals = sorted(rows_by_val)
|
|
1943
|
+
vals.append(prec)
|
|
1944
|
+
|
|
1945
|
+
for t in range(len(vals)-1):
|
|
1946
|
+
v, w = vals[t], vals[t+1]
|
|
1947
|
+
rows = rows_by_val[v]
|
|
1948
|
+
piv = max(rows)
|
|
1949
|
+
for i in rows:
|
|
1950
|
+
if i == piv:
|
|
1951
|
+
continue
|
|
1952
|
+
# We clear the entry on the i-th row
|
|
1953
|
+
scalar = (col[i]/col[piv]).reduce(prec-v)
|
|
1954
|
+
for j in range(piv,n):
|
|
1955
|
+
col_cur = self._matrix[self._elements[j]]
|
|
1956
|
+
col_cur[i] -= scalar*col_cur[piv]
|
|
1957
|
+
# We rescale the piv-th row
|
|
1958
|
+
for j in range(piv,n):
|
|
1959
|
+
col_cur = self._matrix[self._elements[j]]
|
|
1960
|
+
col_cur[piv] <<= w - v
|
|
1961
|
+
# Now the entry on the piv-th row has valuation w
|
|
1962
|
+
# We update the dictionary accordingly
|
|
1963
|
+
if w < prec:
|
|
1964
|
+
rows_by_val[w].append(piv)
|
|
1965
|
+
|
|
1966
|
+
self._precision_absolute_data.clear_cache()
|
|
1967
|
+
|
|
1968
|
+
@cached_method(key=lambda self, x: pAdicLatticeElementWeakProxy(x))
|
|
1969
|
+
def _precision_absolute_data(self, x):
|
|
1970
|
+
r"""
|
|
1971
|
+
Return absolute precision data for ``x``.
|
|
1972
|
+
|
|
1973
|
+
.. NOTE::
|
|
1974
|
+
|
|
1975
|
+
Helper method for :meth:`_precision_absolute` and
|
|
1976
|
+
:meth:`_is_precision_capped`.
|
|
1977
|
+
|
|
1978
|
+
TESTS::
|
|
1979
|
+
|
|
1980
|
+
sage: R = ZpLC(2)
|
|
1981
|
+
sage: x = R(1, 10); x
|
|
1982
|
+
1 + O(2^10)
|
|
1983
|
+
sage: y = R(1, 5); y
|
|
1984
|
+
1 + O(2^5)
|
|
1985
|
+
sage: z = x + y; z
|
|
1986
|
+
2 + O(2^5)
|
|
1987
|
+
sage: z.precision_absolute() # indirect doctest
|
|
1988
|
+
5
|
|
1989
|
+
"""
|
|
1990
|
+
ref = pAdicLatticeElementWeakProxy(x)
|
|
1991
|
+
col = self._matrix[ref]
|
|
1992
|
+
absprec = Infinity
|
|
1993
|
+
capped = False
|
|
1994
|
+
for i in range(len(col)):
|
|
1995
|
+
v = col[i].valuation()
|
|
1996
|
+
if v < absprec:
|
|
1997
|
+
absprec = v
|
|
1998
|
+
capped = self._capped[self._elements[i]]
|
|
1999
|
+
elif v == absprec:
|
|
2000
|
+
capped = capped and self._capped[self._elements[i]]
|
|
2001
|
+
return (absprec, capped)
|
|
2002
|
+
|
|
2003
|
+
def _precision_absolute(self, x):
|
|
2004
|
+
r"""
|
|
2005
|
+
Return the absolute precision of the given element.
|
|
2006
|
+
|
|
2007
|
+
INPUT:
|
|
2008
|
+
|
|
2009
|
+
- ``x`` -- an element in the parent corresponding to this lattice
|
|
2010
|
+
|
|
2011
|
+
.. NOTE::
|
|
2012
|
+
|
|
2013
|
+
The absolute precision is obtained by projecting the precision
|
|
2014
|
+
lattice onto the line of coordinate ``dx``.
|
|
2015
|
+
|
|
2016
|
+
This function is not meant to be called directly. Call
|
|
2017
|
+
``x.precision_absolute()`` instead.
|
|
2018
|
+
|
|
2019
|
+
EXAMPLES::
|
|
2020
|
+
|
|
2021
|
+
sage: R = ZpLC(2)
|
|
2022
|
+
sage: x = R(1, 10); x
|
|
2023
|
+
1 + O(2^10)
|
|
2024
|
+
sage: y = R(1, 5); y
|
|
2025
|
+
1 + O(2^5)
|
|
2026
|
+
sage: z = x + y; z
|
|
2027
|
+
2 + O(2^5)
|
|
2028
|
+
sage: z.precision_absolute() # indirect doctest
|
|
2029
|
+
5
|
|
2030
|
+
"""
|
|
2031
|
+
return self._precision_absolute_data(x)[0]
|
|
2032
|
+
|
|
2033
|
+
def _is_precision_capped(self, x):
|
|
2034
|
+
r"""
|
|
2035
|
+
Return whether the absolute precision of ``x`` results from a cap
|
|
2036
|
+
coming from the parent.
|
|
2037
|
+
|
|
2038
|
+
INPUT:
|
|
2039
|
+
|
|
2040
|
+
- ``x`` -- an element in the parent corresponding to this lattice
|
|
2041
|
+
|
|
2042
|
+
.. NOTE::
|
|
2043
|
+
|
|
2044
|
+
This function is not meant to be called directly. Call
|
|
2045
|
+
``x.is_precision_capped`` instead.
|
|
2046
|
+
|
|
2047
|
+
EXAMPLES::
|
|
2048
|
+
|
|
2049
|
+
sage: R = ZpLC(2)
|
|
2050
|
+
sage: x = R(1, 10); x
|
|
2051
|
+
1 + O(2^10)
|
|
2052
|
+
sage: x.is_precision_capped() # indirect doctest
|
|
2053
|
+
False
|
|
2054
|
+
|
|
2055
|
+
sage: y = x-x; y
|
|
2056
|
+
O(2^40)
|
|
2057
|
+
sage: y.is_precision_capped() # indirect doctest
|
|
2058
|
+
True
|
|
2059
|
+
"""
|
|
2060
|
+
return self._precision_absolute_data(x)[1]
|
|
2061
|
+
|
|
2062
|
+
def precision_lattice(self, elements=None):
|
|
2063
|
+
r"""
|
|
2064
|
+
Return a matrix representing the precision lattice on a
|
|
2065
|
+
subset of elements.
|
|
2066
|
+
|
|
2067
|
+
INPUT:
|
|
2068
|
+
|
|
2069
|
+
- ``elements`` -- list of elements or ``None`` (default: ``None``)
|
|
2070
|
+
|
|
2071
|
+
- ``echelon`` -- boolean (default: ``True``); whether the result
|
|
2072
|
+
should be in echelon form
|
|
2073
|
+
|
|
2074
|
+
EXAMPLES::
|
|
2075
|
+
|
|
2076
|
+
sage: R = ZpLC(2, label='preclattice')
|
|
2077
|
+
sage: prec = R.precision()
|
|
2078
|
+
sage: x = R(1, 10); y = R(1, 5)
|
|
2079
|
+
sage: u = x + y
|
|
2080
|
+
sage: v = x - y
|
|
2081
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
2082
|
+
[ 1024 0 1024 1024]
|
|
2083
|
+
[ 0 32 32 1099511627744]
|
|
2084
|
+
[ 0 0 2097152 0]
|
|
2085
|
+
[ 0 0 0 1099511627776]
|
|
2086
|
+
sage: prec.precision_lattice([u, v]) # needs sage.geometry.polyhedron
|
|
2087
|
+
[ 32 2016]
|
|
2088
|
+
[ 0 2048]
|
|
2089
|
+
|
|
2090
|
+
Here is another example with matrices::
|
|
2091
|
+
|
|
2092
|
+
sage: M = matrix(R, 2, 2, [R(3, 5), R(7, 5), R(1, 5), R(11, 1)]) # needs sage.modules
|
|
2093
|
+
sage: N = M^10 # needs sage.modules
|
|
2094
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron sage.modules
|
|
2095
|
+
23 x 23 dense matrix over Integer Ring (use the '.str()' method to see the entries)
|
|
2096
|
+
|
|
2097
|
+
The next syntax provides as easy way to select an interesting
|
|
2098
|
+
subset of variables (the selected subset consists of the four
|
|
2099
|
+
entries of the matrix ``N``)::
|
|
2100
|
+
|
|
2101
|
+
sage: prec.precision_lattice(N) # needs sage.modules
|
|
2102
|
+
[ 2048 512 28160 230400]
|
|
2103
|
+
[ 0 2048 14336 258048]
|
|
2104
|
+
[ 0 0 65536 65536]
|
|
2105
|
+
[ 0 0 0 262144]
|
|
2106
|
+
|
|
2107
|
+
We can give a list of matrices as well::
|
|
2108
|
+
|
|
2109
|
+
sage: prec.precision_lattice([M, N]) # needs sage.modules
|
|
2110
|
+
[ 32 0 0 0 226115584 96788480 52174848 82804736]
|
|
2111
|
+
[ 0 32 0 0 52174848 121765888 11829248 28516352]
|
|
2112
|
+
[ 0 0 32 0 96788480 42762240 121765888 199614464]
|
|
2113
|
+
[ 0 0 0 2 5175296 12475904 1782272 4045824]
|
|
2114
|
+
[ 0 0 0 0 268435456 0 0 0]
|
|
2115
|
+
[ 0 0 0 0 0 268435456 0 0]
|
|
2116
|
+
[ 0 0 0 0 0 0 268435456 0]
|
|
2117
|
+
[ 0 0 0 0 0 0 0 268435456]
|
|
2118
|
+
"""
|
|
2119
|
+
if elements is None:
|
|
2120
|
+
elements = self._elements
|
|
2121
|
+
else:
|
|
2122
|
+
elements = list_of_padics(elements)
|
|
2123
|
+
n = len(self._elements)
|
|
2124
|
+
rows = []
|
|
2125
|
+
val = 0
|
|
2126
|
+
for ref in elements:
|
|
2127
|
+
col = self._matrix[ref]
|
|
2128
|
+
row = [ x.value() for x in col ]
|
|
2129
|
+
valcol = min([ x.valuation() for x in col ])
|
|
2130
|
+
val = min(valcol, val)
|
|
2131
|
+
row += (n-len(row)) * [ZZ(0)]
|
|
2132
|
+
rows.append(row)
|
|
2133
|
+
from sage.matrix.constructor import matrix
|
|
2134
|
+
M = matrix(rows).transpose()
|
|
2135
|
+
if val < 0:
|
|
2136
|
+
M *= self._p ** (-val)
|
|
2137
|
+
M = M.change_ring(ZZ)
|
|
2138
|
+
M.echelonize()
|
|
2139
|
+
n = len(elements)
|
|
2140
|
+
M = M.submatrix(0, 0, n, n)
|
|
2141
|
+
if val < 0:
|
|
2142
|
+
M *= self._p ** val
|
|
2143
|
+
return M
|
|
2144
|
+
|
|
2145
|
+
|
|
2146
|
+
class PrecisionModule(UniqueRepresentation, DifferentialPrecisionGeneric):
|
|
2147
|
+
r"""
|
|
2148
|
+
A class for handling precision modules which are used to
|
|
2149
|
+
track precision in the ZpLF model.
|
|
2150
|
+
|
|
2151
|
+
The precision module (which is not necessarily a lattice)
|
|
2152
|
+
is stored as a matrix whose rows are generators.
|
|
2153
|
+
"""
|
|
2154
|
+
def __init__(self, p, label, prec):
|
|
2155
|
+
r"""
|
|
2156
|
+
Initialize this precision module.
|
|
2157
|
+
|
|
2158
|
+
INPUT:
|
|
2159
|
+
|
|
2160
|
+
- ``p`` -- a prime number
|
|
2161
|
+
|
|
2162
|
+
- ``label`` -- string; the label of the parents to which belong
|
|
2163
|
+
the elements tracked by this precision module
|
|
2164
|
+
|
|
2165
|
+
NOTE:
|
|
2166
|
+
|
|
2167
|
+
The precision module is automatically initialized at the
|
|
2168
|
+
creation of the parent.
|
|
2169
|
+
|
|
2170
|
+
TESTS::
|
|
2171
|
+
|
|
2172
|
+
sage: R = ZpLF(2, label='init')
|
|
2173
|
+
sage: R.precision()
|
|
2174
|
+
Precision module on 0 objects (label: init)
|
|
2175
|
+
"""
|
|
2176
|
+
DifferentialPrecisionGeneric.__init__(self, p, label)
|
|
2177
|
+
# elements whose valuation are not less than self._zero_cap are assumed to vanish
|
|
2178
|
+
self._zero_cap = prec
|
|
2179
|
+
self._internal_prec = prec + STARTING_ADDITIONAL_PREC
|
|
2180
|
+
self._count = 0
|
|
2181
|
+
self._threshold = 1
|
|
2182
|
+
self._repr_type = "Precision module"
|
|
2183
|
+
|
|
2184
|
+
# We need to copy this method.
|
|
2185
|
+
# Indeed otherwise it is inherited from UniqueRepresentation
|
|
2186
|
+
def __reduce__(self):
|
|
2187
|
+
r"""
|
|
2188
|
+
TESTS::
|
|
2189
|
+
|
|
2190
|
+
sage: R = ZpLF(2)
|
|
2191
|
+
sage: prec = R.precision()
|
|
2192
|
+
sage: dumps(prec)
|
|
2193
|
+
Traceback (most recent call last):
|
|
2194
|
+
...
|
|
2195
|
+
NotImplementedError: pickling/unpickling precision modules is not implemented yet
|
|
2196
|
+
"""
|
|
2197
|
+
raise NotImplementedError("pickling/unpickling precision modules is not implemented yet")
|
|
2198
|
+
|
|
2199
|
+
def internal_prec(self):
|
|
2200
|
+
r"""
|
|
2201
|
+
Return the relative precision at which computations is handled
|
|
2202
|
+
internally.
|
|
2203
|
+
|
|
2204
|
+
It is slightly greater than the actual precision and increases
|
|
2205
|
+
a bit (at a logarithmic rate) when new elements are created
|
|
2206
|
+
and/or computed.
|
|
2207
|
+
|
|
2208
|
+
EXAMPLES::
|
|
2209
|
+
|
|
2210
|
+
sage: R = ZpLF(5, prec=20, label='internal_prec')
|
|
2211
|
+
sage: prec = R.precision()
|
|
2212
|
+
|
|
2213
|
+
sage: prec.internal_prec()
|
|
2214
|
+
25
|
|
2215
|
+
|
|
2216
|
+
sage: L = [ R.random_element() for _ in range(50) ]
|
|
2217
|
+
sage: prec.internal_prec()
|
|
2218
|
+
28
|
|
2219
|
+
"""
|
|
2220
|
+
return self._internal_prec
|
|
2221
|
+
|
|
2222
|
+
def dimension(self):
|
|
2223
|
+
r"""
|
|
2224
|
+
Return the dimension of this precision module.
|
|
2225
|
+
|
|
2226
|
+
EXAMPLES:
|
|
2227
|
+
|
|
2228
|
+
In general, the dimension increases by 1 when a new
|
|
2229
|
+
element with a given precision is created::
|
|
2230
|
+
|
|
2231
|
+
sage: R = ZpLF(2, label='dimension')
|
|
2232
|
+
sage: prec = R.precision()
|
|
2233
|
+
|
|
2234
|
+
sage: prec.dimension()
|
|
2235
|
+
0
|
|
2236
|
+
sage: x = R.random_element(prec=10)
|
|
2237
|
+
sage: prec.dimension()
|
|
2238
|
+
1
|
|
2239
|
+
sage: y = R.random_element(prec=10)
|
|
2240
|
+
sage: prec.dimension()
|
|
2241
|
+
2
|
|
2242
|
+
|
|
2243
|
+
However in general it does not increase while
|
|
2244
|
+
doing computations::
|
|
2245
|
+
|
|
2246
|
+
sage: u = x + y
|
|
2247
|
+
sage: v = x^2 + 3*y + x*y + y^3
|
|
2248
|
+
sage: prec.dimension()
|
|
2249
|
+
2
|
|
2250
|
+
|
|
2251
|
+
Of course, it may also decrease when a sufficient
|
|
2252
|
+
number of variables are collected::
|
|
2253
|
+
|
|
2254
|
+
sage: del x, y, u
|
|
2255
|
+
sage: prec.del_elements()
|
|
2256
|
+
sage: prec.dimension()
|
|
2257
|
+
1
|
|
2258
|
+
|
|
2259
|
+
sage: del v
|
|
2260
|
+
sage: prec.del_elements()
|
|
2261
|
+
sage: prec.dimension()
|
|
2262
|
+
0
|
|
2263
|
+
"""
|
|
2264
|
+
if len(self._elements) == 0:
|
|
2265
|
+
return 0
|
|
2266
|
+
return len(self._matrix[self._elements[-1]])
|
|
2267
|
+
|
|
2268
|
+
def is_lattice(self):
|
|
2269
|
+
r"""
|
|
2270
|
+
Return ``True`` if this precision module is a lattice
|
|
2271
|
+
(i.e. has maximal dimension).
|
|
2272
|
+
|
|
2273
|
+
EXAMPLES::
|
|
2274
|
+
|
|
2275
|
+
sage: R = ZpLF(2, label='is_lattice')
|
|
2276
|
+
sage: prec = R.precision()
|
|
2277
|
+
|
|
2278
|
+
sage: x = R(1, 10)
|
|
2279
|
+
sage: y = R(1, 5)
|
|
2280
|
+
sage: prec.is_lattice()
|
|
2281
|
+
True
|
|
2282
|
+
|
|
2283
|
+
sage: u = x + y
|
|
2284
|
+
sage: prec.is_lattice()
|
|
2285
|
+
False
|
|
2286
|
+
|
|
2287
|
+
.. SEEALSO::
|
|
2288
|
+
|
|
2289
|
+
:meth:`dimension`
|
|
2290
|
+
"""
|
|
2291
|
+
return self.dimension() == len(self._elements)
|
|
2292
|
+
|
|
2293
|
+
def _new_element(self, x, dx, bigoh, dx_mode='linear_combination'):
|
|
2294
|
+
r"""
|
|
2295
|
+
Update the lattice when a new element is created.
|
|
2296
|
+
|
|
2297
|
+
This function is not meant to be called manually.
|
|
2298
|
+
It is automatically called by the parent when a new
|
|
2299
|
+
element is created.
|
|
2300
|
+
|
|
2301
|
+
INPUT:
|
|
2302
|
+
|
|
2303
|
+
- ``x`` -- the newly created element
|
|
2304
|
+
|
|
2305
|
+
- ``dx`` -- dictionary representing the differential of ``x``
|
|
2306
|
+
|
|
2307
|
+
- ``bigoh`` -- integer or ``None`` (default: ``None``); the
|
|
2308
|
+
bigoh to be added to the precision of ``x``. If ``None``, the
|
|
2309
|
+
default cap is used.
|
|
2310
|
+
|
|
2311
|
+
- ``dx_mode`` -- string; either ``'linear_combination'`` (the
|
|
2312
|
+
default) or ``'values'``
|
|
2313
|
+
|
|
2314
|
+
If ``dx_mode`` is ``'linear_combination'``, the dictionary ``dx``
|
|
2315
|
+
encodes the expression of the differential of ``x``. For example, if
|
|
2316
|
+
``x`` was defined as ``x = y*z`` then:
|
|
2317
|
+
|
|
2318
|
+
.. MATH::
|
|
2319
|
+
|
|
2320
|
+
dx = y dz + z dy
|
|
2321
|
+
|
|
2322
|
+
and the corresponding dictionary is ``{z: y, y: z}`` (except
|
|
2323
|
+
that the keys are not the elements themselves but weak references
|
|
2324
|
+
to them).
|
|
2325
|
+
|
|
2326
|
+
If ``dx_mode`` is ``'values'``, the dictionary ``dx`` directly
|
|
2327
|
+
specifies the entries that have to stored in the precision module.
|
|
2328
|
+
This mode is only used for multiple conversion between different
|
|
2329
|
+
parents (see :meth:`multiple_conversion`).
|
|
2330
|
+
|
|
2331
|
+
TESTS::
|
|
2332
|
+
|
|
2333
|
+
sage: R = ZpLF(2)
|
|
2334
|
+
sage: x = R.random_element()
|
|
2335
|
+
sage: y = R.random_element()
|
|
2336
|
+
sage: z = x*y # indirect doctest
|
|
2337
|
+
"""
|
|
2338
|
+
# First we delete some elements marked for deletion
|
|
2339
|
+
if self._marked_for_deletion:
|
|
2340
|
+
self.del_elements(threshold=self._threshold_deletion)
|
|
2341
|
+
|
|
2342
|
+
# We increase the internal prec
|
|
2343
|
+
# The heuristic behind this is the following: when computing
|
|
2344
|
+
# with N digits of precision, we except that about N-log_p(c)
|
|
2345
|
+
# of them are correct after c elementary operations.
|
|
2346
|
+
self._count += 1
|
|
2347
|
+
if self._count > self._threshold:
|
|
2348
|
+
self._internal_prec += 1
|
|
2349
|
+
self._threshold *= self._p
|
|
2350
|
+
|
|
2351
|
+
tme = walltime()
|
|
2352
|
+
p = self._p
|
|
2353
|
+
n = self.dimension()
|
|
2354
|
+
x_ref = pAdicLatticeElementWeakProxy(x, self._record_collected_element)
|
|
2355
|
+
col = n * [self._approx_zero]
|
|
2356
|
+
if dx_mode == 'linear_combination':
|
|
2357
|
+
expected_vals = n * [ Infinity ]
|
|
2358
|
+
for elt, scalar in dx:
|
|
2359
|
+
ref = pAdicLatticeElementWeakProxy(elt)
|
|
2360
|
+
if not isinstance(scalar, pRational):
|
|
2361
|
+
scalar = pRational(p, scalar)
|
|
2362
|
+
c = self._matrix[ref]
|
|
2363
|
+
for i in range(len(c)):
|
|
2364
|
+
summand = scalar * c[i]
|
|
2365
|
+
expected_vals[i] = min(expected_vals[i], summand.valuation())
|
|
2366
|
+
col[i] += summand
|
|
2367
|
+
for i in range(n):
|
|
2368
|
+
if col[i].valuation() >= expected_vals[i] + self._zero_cap:
|
|
2369
|
+
col[i] = self._approx_zero
|
|
2370
|
+
elif dx_mode == 'values':
|
|
2371
|
+
for elt, scalar in dx:
|
|
2372
|
+
ref = pAdicLatticeElementWeakProxy(elt)
|
|
2373
|
+
if not isinstance(scalar, pRational):
|
|
2374
|
+
scalar = pRational(p, scalar)
|
|
2375
|
+
i = self._index(ref)
|
|
2376
|
+
col[i] = scalar
|
|
2377
|
+
else:
|
|
2378
|
+
raise ValueError("dx_mode must be either 'linear_combination' or 'values'")
|
|
2379
|
+
|
|
2380
|
+
for i in range(n):
|
|
2381
|
+
col[i] = col[i].reduce_relative(self._internal_prec)
|
|
2382
|
+
if bigoh is not None:
|
|
2383
|
+
col.append(pRational(p, ZZ(1), bigoh))
|
|
2384
|
+
|
|
2385
|
+
self._elements.append(x_ref)
|
|
2386
|
+
self._matrix[x_ref] = col
|
|
2387
|
+
|
|
2388
|
+
# We update history
|
|
2389
|
+
if self._history is not None:
|
|
2390
|
+
self._history.append(('add', None, walltime(tme)))
|
|
2391
|
+
|
|
2392
|
+
def del_elements(self, threshold=None):
|
|
2393
|
+
r"""
|
|
2394
|
+
Erase columns of the lattice precision matrix corresponding to
|
|
2395
|
+
elements which were collected by the garbage collector.
|
|
2396
|
+
Then reduce the matrix in order to keep it in echelon form.
|
|
2397
|
+
|
|
2398
|
+
INPUT:
|
|
2399
|
+
|
|
2400
|
+
- ``threshold`` -- integer or ``None`` (default: ``None``);
|
|
2401
|
+
a non-pivot column whose distance to the right is greater than
|
|
2402
|
+
the threshold is not erased but only marked for future deletion
|
|
2403
|
+
|
|
2404
|
+
EXAMPLES::
|
|
2405
|
+
|
|
2406
|
+
sage: R = ZpLF(2, label='delelts')
|
|
2407
|
+
sage: prec = R.precision()
|
|
2408
|
+
|
|
2409
|
+
sage: x = R(1, 10)
|
|
2410
|
+
sage: prec
|
|
2411
|
+
Precision module on 1 object (label: delelts)
|
|
2412
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
2413
|
+
[1024]
|
|
2414
|
+
|
|
2415
|
+
sage: del x
|
|
2416
|
+
sage: prec
|
|
2417
|
+
Precision module on 1 object (label: delelts)
|
|
2418
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
2419
|
+
[1024]
|
|
2420
|
+
|
|
2421
|
+
sage: prec.del_elements()
|
|
2422
|
+
sage: prec
|
|
2423
|
+
Precision module on 0 objects (label: delelts)
|
|
2424
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
2425
|
+
[]
|
|
2426
|
+
"""
|
|
2427
|
+
# We mark new collected elements for deletion
|
|
2428
|
+
# The list self._collected_references can be updated while
|
|
2429
|
+
# the loop runs.
|
|
2430
|
+
# However, we do not need to copy it because Python supports
|
|
2431
|
+
# iteration over a list to which elements are added.
|
|
2432
|
+
count = 0
|
|
2433
|
+
for ref in self._collected_references:
|
|
2434
|
+
count += 1
|
|
2435
|
+
tme = walltime()
|
|
2436
|
+
index = self._index(ref)
|
|
2437
|
+
if index == 0:
|
|
2438
|
+
length_before = 0
|
|
2439
|
+
else:
|
|
2440
|
+
length_before = len(self._matrix[self._elements[index-1]])
|
|
2441
|
+
length = len(self._matrix[ref])
|
|
2442
|
+
if length > length_before:
|
|
2443
|
+
self._marked_for_deletion.append(index)
|
|
2444
|
+
if self._history is not None:
|
|
2445
|
+
self._history.append(('mark', index, walltime(tme)))
|
|
2446
|
+
else:
|
|
2447
|
+
# if the column is not a pivot, we erase it without delay
|
|
2448
|
+
# (btw, is it a good idea?)
|
|
2449
|
+
del self._elements[index]
|
|
2450
|
+
self._marked_for_deletion = [i if i < index else i - 1
|
|
2451
|
+
for i in self._marked_for_deletion]
|
|
2452
|
+
if self._history is not None:
|
|
2453
|
+
self._history.append(('del', index, walltime(tme)))
|
|
2454
|
+
del self._collected_references[:count]
|
|
2455
|
+
|
|
2456
|
+
# We erase corresponding columns and echelonize
|
|
2457
|
+
n = len(self._elements)
|
|
2458
|
+
self._marked_for_deletion.sort(reverse=True)
|
|
2459
|
+
count = 0
|
|
2460
|
+
for index in self._marked_for_deletion:
|
|
2461
|
+
if threshold is not None and index < n - threshold:
|
|
2462
|
+
break
|
|
2463
|
+
n -= 1
|
|
2464
|
+
count += 1
|
|
2465
|
+
|
|
2466
|
+
tme = walltime()
|
|
2467
|
+
|
|
2468
|
+
length = len(self._matrix[self._elements[index]])
|
|
2469
|
+
del self._matrix[self._elements[index]]
|
|
2470
|
+
del self._elements[index]
|
|
2471
|
+
start = index
|
|
2472
|
+
while start < n:
|
|
2473
|
+
i = start
|
|
2474
|
+
val = Infinity
|
|
2475
|
+
end = n
|
|
2476
|
+
while i < n:
|
|
2477
|
+
col = self._matrix[self._elements[i]]
|
|
2478
|
+
if len(col) > length:
|
|
2479
|
+
end = i
|
|
2480
|
+
break
|
|
2481
|
+
v = col[-1].valuation()
|
|
2482
|
+
if v < val:
|
|
2483
|
+
val = v
|
|
2484
|
+
piv = i
|
|
2485
|
+
i += 1
|
|
2486
|
+
if val < Infinity:
|
|
2487
|
+
# another pivot has been found, we place it in front
|
|
2488
|
+
self._elements[start], self._elements[piv] = self._elements[piv], self._elements[start]
|
|
2489
|
+
break
|
|
2490
|
+
|
|
2491
|
+
# No pivot was found. We re-echelonize
|
|
2492
|
+
for i in range(start, end):
|
|
2493
|
+
del self._matrix[self._elements[i]][-1]
|
|
2494
|
+
if end == n:
|
|
2495
|
+
break
|
|
2496
|
+
# col is the column of index "end"
|
|
2497
|
+
# its size is (length + 1)
|
|
2498
|
+
d, u, v = col[length-1].xgcd(col[length])
|
|
2499
|
+
up, vp = col[length]/d, col[length-1]/d
|
|
2500
|
+
col[length-1] = d.reduce_relative(self._internal_prec)
|
|
2501
|
+
del col[length]
|
|
2502
|
+
start = end + 1
|
|
2503
|
+
for j in range(start, n):
|
|
2504
|
+
col = self._matrix[self._elements[j]]
|
|
2505
|
+
a1 = u*col[length-1]
|
|
2506
|
+
a2 = v*col[length]
|
|
2507
|
+
a = a1 + a2
|
|
2508
|
+
b1 = up*col[length-1]
|
|
2509
|
+
b2 = vp * col[length]
|
|
2510
|
+
b = b1 + b2
|
|
2511
|
+
if a.valuation() > min(a1.valuation(), a2.valuation()) + self._zero_cap:
|
|
2512
|
+
col[length-1] = self._approx_zero
|
|
2513
|
+
else:
|
|
2514
|
+
col[length-1] = a.reduce_relative(self._internal_prec)
|
|
2515
|
+
if b.valuation() > min(b1.valuation(), b2.valuation()) + self._zero_cap:
|
|
2516
|
+
col[length] = self._approx_zero
|
|
2517
|
+
else:
|
|
2518
|
+
col[length] = b.reduce_relative(self._internal_prec)
|
|
2519
|
+
length += 1
|
|
2520
|
+
|
|
2521
|
+
# We update history
|
|
2522
|
+
if self._history is not None:
|
|
2523
|
+
self._history.append(('del', index, walltime(tme)))
|
|
2524
|
+
|
|
2525
|
+
del self._marked_for_deletion[:count]
|
|
2526
|
+
|
|
2527
|
+
def _lift_to_precision(self, x, prec):
|
|
2528
|
+
r"""
|
|
2529
|
+
Lift the specified element to the specified precision.
|
|
2530
|
+
|
|
2531
|
+
INPUT:
|
|
2532
|
+
|
|
2533
|
+
- ``x`` -- the element whose precision has to be lifted
|
|
2534
|
+
|
|
2535
|
+
- ``prec`` -- the new precision
|
|
2536
|
+
|
|
2537
|
+
.. NOTE::
|
|
2538
|
+
|
|
2539
|
+
The new precision lattice is computed as the intersection
|
|
2540
|
+
of the current precision lattice with the subspace.
|
|
2541
|
+
|
|
2542
|
+
.. MATH::
|
|
2543
|
+
|
|
2544
|
+
p^{prec} \Z_p dx \oplus \bigoplus_{y \neq x} \Q_p dy
|
|
2545
|
+
|
|
2546
|
+
This function may change at the same time the precision of
|
|
2547
|
+
other elements having the same parent.
|
|
2548
|
+
|
|
2549
|
+
.. NOTE::
|
|
2550
|
+
|
|
2551
|
+
This function is not meant to be called directly. Use
|
|
2552
|
+
``x.lift_to_precision`` instead.
|
|
2553
|
+
|
|
2554
|
+
EXAMPLES::
|
|
2555
|
+
|
|
2556
|
+
sage: R = ZpLF(2)
|
|
2557
|
+
sage: x = R(1, 10); x
|
|
2558
|
+
1 + O(2^10)
|
|
2559
|
+
sage: y = R(1, 5); y
|
|
2560
|
+
1 + O(2^5)
|
|
2561
|
+
sage: u = x^2 + x*y
|
|
2562
|
+
sage: v = y^2 + x*y
|
|
2563
|
+
sage: w = u + v
|
|
2564
|
+
|
|
2565
|
+
sage: prec = R.precision()
|
|
2566
|
+
sage: prec._lift_to_precision(w, 11)
|
|
2567
|
+
sage: w
|
|
2568
|
+
2^2 + O(2^11)
|
|
2569
|
+
sage: y
|
|
2570
|
+
1 + O(2^9)
|
|
2571
|
+
"""
|
|
2572
|
+
ref = pAdicLatticeElementWeakProxy(x)
|
|
2573
|
+
col = self._matrix[ref]
|
|
2574
|
+
n = len(self._elements)
|
|
2575
|
+
|
|
2576
|
+
rows_by_val = defaultdict(list)
|
|
2577
|
+
for i in range(len(col)):
|
|
2578
|
+
v = col[i].valuation()
|
|
2579
|
+
if v >= prec:
|
|
2580
|
+
continue
|
|
2581
|
+
rows_by_val[v].append(i)
|
|
2582
|
+
vals = sorted(rows_by_val)
|
|
2583
|
+
vals.append(prec)
|
|
2584
|
+
|
|
2585
|
+
for t in range(len(vals)-1):
|
|
2586
|
+
v, w = vals[t], vals[t+1]
|
|
2587
|
+
rows = rows_by_val[v]
|
|
2588
|
+
piv = max(rows)
|
|
2589
|
+
for i in rows:
|
|
2590
|
+
if i == piv:
|
|
2591
|
+
continue
|
|
2592
|
+
# We clear the entry on the i-th row
|
|
2593
|
+
scalar = (col[i]/col[piv]).reduce(prec-v)
|
|
2594
|
+
for j in range(n):
|
|
2595
|
+
col_cur = self._matrix[self._elements[j]]
|
|
2596
|
+
if len(col_cur) > piv:
|
|
2597
|
+
col_cur[i] -= scalar*col_cur[piv]
|
|
2598
|
+
col_cur[i] = col_cur[i].reduce_relative(self._internal_prec)
|
|
2599
|
+
# We rescale the piv-th row
|
|
2600
|
+
# (if w is Infinity, we delete it)
|
|
2601
|
+
for j in range(n):
|
|
2602
|
+
col_cur = self._matrix[self._elements[j]]
|
|
2603
|
+
if len(col_cur) > piv:
|
|
2604
|
+
if w is Infinity:
|
|
2605
|
+
del col_cur[piv]
|
|
2606
|
+
else:
|
|
2607
|
+
col_cur[piv] <<= w - v
|
|
2608
|
+
# Now the entry on the piv-th row has valuation w
|
|
2609
|
+
# We update the dictionary accordingly
|
|
2610
|
+
if w < prec:
|
|
2611
|
+
rows_by_val[w].append(piv)
|
|
2612
|
+
|
|
2613
|
+
self._precision_absolute.clear_cache()
|
|
2614
|
+
|
|
2615
|
+
@cached_method(key=lambda self, x: pAdicLatticeElementWeakProxy(x))
|
|
2616
|
+
def _precision_absolute(self, x):
|
|
2617
|
+
r"""
|
|
2618
|
+
Return the absolute precision of the given element.
|
|
2619
|
+
|
|
2620
|
+
INPUT:
|
|
2621
|
+
|
|
2622
|
+
- ``x`` -- the element whose absolute precision is requested
|
|
2623
|
+
|
|
2624
|
+
.. NOTE::
|
|
2625
|
+
|
|
2626
|
+
The absolute precision is obtained by projecting the precision
|
|
2627
|
+
module onto the line of coordinate ``dx``.
|
|
2628
|
+
|
|
2629
|
+
This function is not meant to be called directly. Call
|
|
2630
|
+
``x.precision_absolute()`` instead.
|
|
2631
|
+
|
|
2632
|
+
EXAMPLES::
|
|
2633
|
+
|
|
2634
|
+
sage: R = ZpLF(2)
|
|
2635
|
+
sage: prec = R.precision()
|
|
2636
|
+
|
|
2637
|
+
sage: x = R(1, 10); x
|
|
2638
|
+
1 + O(2^10)
|
|
2639
|
+
sage: y = R(1, 5); y
|
|
2640
|
+
1 + O(2^5)
|
|
2641
|
+
sage: z = x + y; z
|
|
2642
|
+
2 + O(2^5)
|
|
2643
|
+
sage: z.precision_absolute() # indirect doctest
|
|
2644
|
+
5
|
|
2645
|
+
|
|
2646
|
+
In some cases, the absolute precision returned by this function
|
|
2647
|
+
may be infinite::
|
|
2648
|
+
|
|
2649
|
+
sage: y = R(1)
|
|
2650
|
+
sage: prec._precision_absolute(y)
|
|
2651
|
+
+Infinity
|
|
2652
|
+
|
|
2653
|
+
However calling the method :meth:`absolute_precision` of the
|
|
2654
|
+
element itself reintroduces a cap::
|
|
2655
|
+
|
|
2656
|
+
sage: y.precision_absolute()
|
|
2657
|
+
20
|
|
2658
|
+
"""
|
|
2659
|
+
ref = pAdicLatticeElementWeakProxy(x)
|
|
2660
|
+
col = self._matrix[ref]
|
|
2661
|
+
if len(col) == 0:
|
|
2662
|
+
return Infinity
|
|
2663
|
+
else:
|
|
2664
|
+
return min( [ c.valuation() for c in col ] )
|
|
2665
|
+
|
|
2666
|
+
def precision_lattice(self, elements=None):
|
|
2667
|
+
r"""
|
|
2668
|
+
Return a matrix representing the precision lattice on a
|
|
2669
|
+
subset of elements.
|
|
2670
|
+
|
|
2671
|
+
INPUT:
|
|
2672
|
+
|
|
2673
|
+
- ``elements`` -- list of elements or ``None`` (default: ``None``)
|
|
2674
|
+
|
|
2675
|
+
EXAMPLES::
|
|
2676
|
+
|
|
2677
|
+
sage: R = ZpLF(2, label='preclattice')
|
|
2678
|
+
sage: prec = R.precision()
|
|
2679
|
+
sage: x = R(1, 10); y = R(1, 5)
|
|
2680
|
+
sage: prec.precision_lattice() # needs sage.geometry.polyhedron
|
|
2681
|
+
[1024 0]
|
|
2682
|
+
[ 0 32]
|
|
2683
|
+
|
|
2684
|
+
sage: u = x + y
|
|
2685
|
+
sage: v = x - y
|
|
2686
|
+
sage: prec.precision_lattice([u, v]) # needs sage.geometry.polyhedron
|
|
2687
|
+
[ 32 2016]
|
|
2688
|
+
[ 0 2048]
|
|
2689
|
+
|
|
2690
|
+
If the precision module does not project to a lattice,
|
|
2691
|
+
an error is raised. ::
|
|
2692
|
+
|
|
2693
|
+
sage: prec.precision_lattice([x, y, u, v]) # needs sage.geometry.polyhedron
|
|
2694
|
+
Traceback (most recent call last):
|
|
2695
|
+
...
|
|
2696
|
+
PrecisionError: the differential is not surjective
|
|
2697
|
+
|
|
2698
|
+
Here is another example with matrices::
|
|
2699
|
+
|
|
2700
|
+
sage: M = matrix(R, 2, 2, [R(3, 5), R(7, 5), R(1, 5), R(11, 1)]) # needs sage.modules
|
|
2701
|
+
sage: N = M^10 # needs sage.modules
|
|
2702
|
+
|
|
2703
|
+
The next syntax provides as easy way to select an interesting
|
|
2704
|
+
subset of variables (the selected subset consists of the four
|
|
2705
|
+
entries of the matrix ``N``)::
|
|
2706
|
+
|
|
2707
|
+
sage: prec.precision_lattice(N) # needs sage.geometry.polyhedron sage.modules
|
|
2708
|
+
[ 2048 512 28160 230400]
|
|
2709
|
+
[ 0 2048 14336 258048]
|
|
2710
|
+
[ 0 0 65536 65536]
|
|
2711
|
+
[ 0 0 0 262144]
|
|
2712
|
+
"""
|
|
2713
|
+
if elements is None:
|
|
2714
|
+
elements = self._elements
|
|
2715
|
+
else:
|
|
2716
|
+
elements = list_of_padics(elements)
|
|
2717
|
+
n = len(self._elements)
|
|
2718
|
+
rows = [ ]
|
|
2719
|
+
val = 0
|
|
2720
|
+
for ref in elements:
|
|
2721
|
+
col = self._matrix[ref]
|
|
2722
|
+
row = [ x.value() for x in col ]
|
|
2723
|
+
valcol = min([ x.valuation() for x in col ])
|
|
2724
|
+
val = min(valcol, val)
|
|
2725
|
+
row += (n-len(row)) * [ZZ(0)]
|
|
2726
|
+
rows.append(row)
|
|
2727
|
+
from sage.matrix.constructor import matrix
|
|
2728
|
+
M = matrix(rows).transpose()
|
|
2729
|
+
if val < 0:
|
|
2730
|
+
M *= self._p ** (-val)
|
|
2731
|
+
M = M.change_ring(ZZ)
|
|
2732
|
+
M.echelonize()
|
|
2733
|
+
n = len(elements)
|
|
2734
|
+
if len(M.pivots()) < n:
|
|
2735
|
+
raise PrecisionError("the differential is not surjective")
|
|
2736
|
+
for i in range(n):
|
|
2737
|
+
v = M[i, i].valuation(self._p)
|
|
2738
|
+
M[i, i] = self._p ** v
|
|
2739
|
+
M.echelonize()
|
|
2740
|
+
M = M.submatrix(0, 0, n, n)
|
|
2741
|
+
if val < 0:
|
|
2742
|
+
M *= self._p ** val
|
|
2743
|
+
return M
|
|
2744
|
+
|
|
2745
|
+
|
|
2746
|
+
class pAdicLatticeElementWeakProxy:
|
|
2747
|
+
r"""
|
|
2748
|
+
The implementations of :class:`DifferentialPrecisionGeneric` hold
|
|
2749
|
+
weak references to :class:`pAdicLatticeElement`. They are stored in
|
|
2750
|
+
dictionaries, e.g., a dictionary that maps an element to the corresponding
|
|
2751
|
+
column in the precision lattice matrix.
|
|
2752
|
+
However, weak references as implemented by Python are tricky to use as
|
|
2753
|
+
dictionary keys. Their equality depends on the equality of the element they
|
|
2754
|
+
point to (as long as that element is alive) and then on the equality by
|
|
2755
|
+
``id``. This means that statements such as: ``ref in D == ref in D`` could
|
|
2756
|
+
be false if the garbage collector kicks in between the two invocations.
|
|
2757
|
+
To prevent very subtle and hardly reproducible bugs, we wrap weak
|
|
2758
|
+
references in a proxy that gives every lattice element a unique increasing
|
|
2759
|
+
id and uses that id for comparisons.
|
|
2760
|
+
|
|
2761
|
+
EXAMPLES:
|
|
2762
|
+
|
|
2763
|
+
Proxy elements exist only internally and are not usually exposed to the user::
|
|
2764
|
+
|
|
2765
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
2766
|
+
sage: R = ZpLF(2, label='proxy')
|
|
2767
|
+
sage: p = R(2)
|
|
2768
|
+
sage: prec = R.precision()
|
|
2769
|
+
sage: proxy = prec._elements[0]
|
|
2770
|
+
sage: isinstance(proxy, pAdicLatticeElementWeakProxy)
|
|
2771
|
+
True
|
|
2772
|
+
"""
|
|
2773
|
+
_next_id = 0
|
|
2774
|
+
|
|
2775
|
+
def __init__(self, element, callback=None):
|
|
2776
|
+
r"""
|
|
2777
|
+
TESTS::
|
|
2778
|
+
|
|
2779
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
2780
|
+
sage: R = ZpLF(2, label='proxy')
|
|
2781
|
+
sage: p = R(2)
|
|
2782
|
+
sage: pAdicLatticeElementWeakProxy(p) == pAdicLatticeElementWeakProxy(p)
|
|
2783
|
+
True
|
|
2784
|
+
sage: pAdicLatticeElementWeakProxy(p) is pAdicLatticeElementWeakProxy(p)
|
|
2785
|
+
False
|
|
2786
|
+
"""
|
|
2787
|
+
if not hasattr(element, '_proxy_id'):
|
|
2788
|
+
element._proxy_id = pAdicLatticeElementWeakProxy._next_id
|
|
2789
|
+
pAdicLatticeElementWeakProxy._next_id += 1
|
|
2790
|
+
self._id = element._proxy_id
|
|
2791
|
+
from weakref import ref
|
|
2792
|
+
proxy_callback = callback
|
|
2793
|
+
if callback is not None:
|
|
2794
|
+
proxy_callback = lambda _: callback(self)
|
|
2795
|
+
self._weakref = ref(element, proxy_callback)
|
|
2796
|
+
|
|
2797
|
+
def __hash__(self):
|
|
2798
|
+
r"""
|
|
2799
|
+
Return a hash value for this proxy.
|
|
2800
|
+
|
|
2801
|
+
EXAMPLES::
|
|
2802
|
+
|
|
2803
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
2804
|
+
sage: R = ZpLF(2, label='proxy')
|
|
2805
|
+
sage: p = R(2)
|
|
2806
|
+
sage: hash(pAdicLatticeElementWeakProxy(p)) == hash(pAdicLatticeElementWeakProxy(p))
|
|
2807
|
+
True
|
|
2808
|
+
"""
|
|
2809
|
+
return self._id
|
|
2810
|
+
|
|
2811
|
+
def __eq__(self, other):
|
|
2812
|
+
r"""
|
|
2813
|
+
Return whether this proxy is undistinguishable from ``other``.
|
|
2814
|
+
|
|
2815
|
+
EXAMPLES::
|
|
2816
|
+
|
|
2817
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
2818
|
+
sage: R = ZpLF(2, label='proxy')
|
|
2819
|
+
sage: p = R(2)
|
|
2820
|
+
sage: q = R(2)
|
|
2821
|
+
sage: pAdicLatticeElementWeakProxy(p) == pAdicLatticeElementWeakProxy(p)
|
|
2822
|
+
True
|
|
2823
|
+
sage: pAdicLatticeElementWeakProxy(q) == pAdicLatticeElementWeakProxy(p)
|
|
2824
|
+
False
|
|
2825
|
+
"""
|
|
2826
|
+
return isinstance(other, pAdicLatticeElementWeakProxy) and self._id == other._id
|
|
2827
|
+
|
|
2828
|
+
def __call__(self):
|
|
2829
|
+
r"""
|
|
2830
|
+
Return the lattice element this proxy points to, or ``None`` if the
|
|
2831
|
+
target has already been finalized.
|
|
2832
|
+
|
|
2833
|
+
EXAMPLES::
|
|
2834
|
+
|
|
2835
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
2836
|
+
sage: R = ZpLF(2, label='proxy')
|
|
2837
|
+
sage: p = R(2)
|
|
2838
|
+
sage: pAdicLatticeElementWeakProxy(p)()
|
|
2839
|
+
2 + O(2^21)
|
|
2840
|
+
"""
|
|
2841
|
+
return self._weakref()
|
|
2842
|
+
|
|
2843
|
+
def __repr__(self):
|
|
2844
|
+
r"""
|
|
2845
|
+
Return a printable representation of this proxy.
|
|
2846
|
+
|
|
2847
|
+
EXAMPLES::
|
|
2848
|
+
|
|
2849
|
+
sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
|
|
2850
|
+
sage: R = ZpLF(2, label='proxy_repr')
|
|
2851
|
+
sage: p = R(2)
|
|
2852
|
+
sage: R.precision()._elements # indirect doctest
|
|
2853
|
+
[WeakProxy#...]
|
|
2854
|
+
"""
|
|
2855
|
+
return "WeakProxy#%s" % (self._id,)
|
|
2856
|
+
|
|
2857
|
+
|
|
2858
|
+
def list_of_padics(elements):
|
|
2859
|
+
r"""
|
|
2860
|
+
Convert a list of `p`-adic composed elements (such as polynomials, matrices)
|
|
2861
|
+
to a list of weak references of their `p`-adic coefficients.
|
|
2862
|
+
|
|
2863
|
+
This is a helper function for the method :meth:`precision_lattice`.
|
|
2864
|
+
|
|
2865
|
+
TESTS::
|
|
2866
|
+
|
|
2867
|
+
sage: from sage.rings.padics.lattice_precision import list_of_padics
|
|
2868
|
+
sage: R = ZpLC(2)
|
|
2869
|
+
sage: M = random_matrix(R, 2, 2) # needs sage.geometry.polyhedron
|
|
2870
|
+
sage: list_of_padics(M) # needs sage.geometry.polyhedron
|
|
2871
|
+
[WeakProxy#...,
|
|
2872
|
+
WeakProxy#...,
|
|
2873
|
+
WeakProxy#...,
|
|
2874
|
+
WeakProxy#...]
|
|
2875
|
+
"""
|
|
2876
|
+
from sage.rings.padics.padic_lattice_element import pAdicLatticeElement
|
|
2877
|
+
if isinstance(elements, pAdicLatticeElement):
|
|
2878
|
+
return [ pAdicLatticeElementWeakProxy(elements) ]
|
|
2879
|
+
try:
|
|
2880
|
+
if elements.parent().is_sparse():
|
|
2881
|
+
elements = elements.coefficients()
|
|
2882
|
+
except AttributeError:
|
|
2883
|
+
pass
|
|
2884
|
+
if not isinstance(elements, list):
|
|
2885
|
+
elements = list(elements)
|
|
2886
|
+
ans = [ ]
|
|
2887
|
+
for x in elements:
|
|
2888
|
+
ans += list_of_padics(x)
|
|
2889
|
+
return ans
|