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,1615 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
r"""
|
|
3
|
+
Spaces of valuations
|
|
4
|
+
|
|
5
|
+
This module provides spaces of exponential pseudo-valuations on integral
|
|
6
|
+
domains. It currently only provides support for such valuations if they are
|
|
7
|
+
discrete, i.e., their image is a discrete additive subgroup of the rational
|
|
8
|
+
numbers extended by `\infty`.
|
|
9
|
+
|
|
10
|
+
AUTHORS:
|
|
11
|
+
|
|
12
|
+
- Julian Rüth (2016-10-14): initial version
|
|
13
|
+
|
|
14
|
+
EXAMPLES::
|
|
15
|
+
|
|
16
|
+
sage: QQ.valuation(2).parent()
|
|
17
|
+
Discrete pseudo-valuations on Rational Field
|
|
18
|
+
|
|
19
|
+
.. NOTE::
|
|
20
|
+
|
|
21
|
+
Note that many tests not only in this module do not create instances of
|
|
22
|
+
valuations directly since this gives the wrong inheritance structure on
|
|
23
|
+
the resulting objects::
|
|
24
|
+
|
|
25
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
26
|
+
sage: from sage.rings.valuation.trivial_valuation import TrivialDiscretePseudoValuation
|
|
27
|
+
sage: H = DiscretePseudoValuationSpace(QQ)
|
|
28
|
+
sage: v = TrivialDiscretePseudoValuation(H)
|
|
29
|
+
sage: v._test_category()
|
|
30
|
+
Traceback (most recent call last):
|
|
31
|
+
...
|
|
32
|
+
AssertionError: False is not true
|
|
33
|
+
|
|
34
|
+
Instead, the valuations need to be created through the
|
|
35
|
+
``__make_element_class__`` of the containing space::
|
|
36
|
+
|
|
37
|
+
sage: from sage.rings.valuation.trivial_valuation import TrivialDiscretePseudoValuation
|
|
38
|
+
sage: v = H.__make_element_class__(TrivialDiscretePseudoValuation)(H)
|
|
39
|
+
sage: v._test_category()
|
|
40
|
+
|
|
41
|
+
The factories such as ``TrivialPseudoValuation`` provide the right
|
|
42
|
+
inheritance structure::
|
|
43
|
+
|
|
44
|
+
sage: v = valuations.TrivialPseudoValuation(QQ)
|
|
45
|
+
sage: v._test_category()
|
|
46
|
+
"""
|
|
47
|
+
# ****************************************************************************
|
|
48
|
+
# Copyright (C) 2016-2017 Julian Rüth <julian.rueth@fsfe.org>
|
|
49
|
+
#
|
|
50
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
51
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
52
|
+
# the License, or (at your option) any later version.
|
|
53
|
+
# https://www.gnu.org/licenses/
|
|
54
|
+
# ****************************************************************************
|
|
55
|
+
|
|
56
|
+
from sage.categories.homset import Homset
|
|
57
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
58
|
+
from sage.misc.abstract_method import abstract_method
|
|
59
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
60
|
+
from sage.misc.cachefunc import cached_method
|
|
61
|
+
from sage.categories.action import Action
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class DiscretePseudoValuationSpace(UniqueRepresentation, Homset):
|
|
65
|
+
r"""
|
|
66
|
+
The space of discrete pseudo-valuations on ``domain``.
|
|
67
|
+
|
|
68
|
+
EXAMPLES::
|
|
69
|
+
|
|
70
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
71
|
+
sage: H = DiscretePseudoValuationSpace(QQ)
|
|
72
|
+
sage: QQ.valuation(2) in H
|
|
73
|
+
True
|
|
74
|
+
|
|
75
|
+
.. NOTE::
|
|
76
|
+
|
|
77
|
+
We do not distinguish between the space of discrete valuations and the
|
|
78
|
+
space of discrete pseudo-valuations. This is entirely for practical
|
|
79
|
+
reasons: We would like to model the fact that every discrete valuation
|
|
80
|
+
is also a discrete pseudo-valuation. At first, it seems to be
|
|
81
|
+
sufficient to make sure that the ``in`` operator works which can
|
|
82
|
+
essentially be achieved by overriding ``_element_constructor_`` of
|
|
83
|
+
the space of discrete pseudo-valuations to accept discrete valuations
|
|
84
|
+
by just returning them. Currently, however, if one does not change the
|
|
85
|
+
parent of an element in ``_element_constructor_`` to ``self``, then
|
|
86
|
+
one cannot register that conversion as a coercion. Consequently, the
|
|
87
|
+
operators ``<=`` and ``>=`` cannot be made to work between discrete
|
|
88
|
+
valuations and discrete pseudo-valuations on the same domain (because
|
|
89
|
+
the implementation only calls ``_richcmp`` if both operands have the
|
|
90
|
+
same parent.) Of course, we could override ``__ge__`` and ``__le__``
|
|
91
|
+
but then we would likely run into other surprises.
|
|
92
|
+
So in the end, we went for a single homspace for all discrete
|
|
93
|
+
valuations (pseudo or not) as this makes the implementation much
|
|
94
|
+
easier.
|
|
95
|
+
|
|
96
|
+
.. TODO::
|
|
97
|
+
|
|
98
|
+
The comparison problem might be fixed by :issue:`22029` or similar.
|
|
99
|
+
|
|
100
|
+
TESTS::
|
|
101
|
+
|
|
102
|
+
sage: TestSuite(H).run() # long time
|
|
103
|
+
"""
|
|
104
|
+
def __init__(self, domain):
|
|
105
|
+
r"""
|
|
106
|
+
TESTS::
|
|
107
|
+
|
|
108
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
109
|
+
sage: isinstance(QQ.valuation(2).parent(), DiscretePseudoValuationSpace)
|
|
110
|
+
True
|
|
111
|
+
"""
|
|
112
|
+
from .value_group import DiscreteValuationCodomain
|
|
113
|
+
# A valuation is a map from an additive semigroup to an additive semigroup, however, it
|
|
114
|
+
# does not preserve that structure. It is therefore only a morphism in the category of sets.
|
|
115
|
+
from sage.categories.sets_cat import Sets
|
|
116
|
+
|
|
117
|
+
UniqueRepresentation.__init__(self)
|
|
118
|
+
Homset.__init__(self, domain, DiscreteValuationCodomain(), category=Sets())
|
|
119
|
+
|
|
120
|
+
from sage.categories.domains import Domains
|
|
121
|
+
if domain not in Domains():
|
|
122
|
+
raise ValueError("domain must be an integral domain")
|
|
123
|
+
|
|
124
|
+
@lazy_attribute
|
|
125
|
+
def _abstract_element_class(self):
|
|
126
|
+
r"""
|
|
127
|
+
Return an abstract base class for all valuations in this space.
|
|
128
|
+
|
|
129
|
+
This is used to extend every valuation with a number of generic methods
|
|
130
|
+
that are independent of implementation details.
|
|
131
|
+
|
|
132
|
+
Usually, extensions of this kind would be done by implementing an
|
|
133
|
+
appropriate class ``MorphismMethods`` in the category of this homset.
|
|
134
|
+
However, there is no category whose arrows are the valuations, so we
|
|
135
|
+
need to move this magic down to the level of the actual homset.
|
|
136
|
+
|
|
137
|
+
EXAMPLES::
|
|
138
|
+
|
|
139
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
140
|
+
sage: isinstance(QQ.valuation(2), DiscretePseudoValuationSpace.ElementMethods) # indirect doctest
|
|
141
|
+
True
|
|
142
|
+
"""
|
|
143
|
+
class_name = "%s._abstract_element_class" % self.__class__.__name__
|
|
144
|
+
from sage.structure.dynamic_class import dynamic_class
|
|
145
|
+
return dynamic_class(class_name, (super()._abstract_element_class, self.__class__.ElementMethods))
|
|
146
|
+
|
|
147
|
+
def _get_action_(self, S, op, self_on_left):
|
|
148
|
+
r"""
|
|
149
|
+
Return the ``op`` action of ``S`` on elements in this space.
|
|
150
|
+
|
|
151
|
+
EXAMPLES::
|
|
152
|
+
|
|
153
|
+
sage: v = QQ.valuation(2)
|
|
154
|
+
sage: from operator import mul
|
|
155
|
+
sage: v.parent().get_action(ZZ, mul) # indirect doctest
|
|
156
|
+
Right action by Integer Ring on Discrete pseudo-valuations on Rational Field
|
|
157
|
+
"""
|
|
158
|
+
from operator import mul
|
|
159
|
+
from sage.rings.infinity import InfinityRing
|
|
160
|
+
from sage.rings.rational_field import QQ
|
|
161
|
+
from sage.rings.integer_ring import ZZ
|
|
162
|
+
if op == mul and (S is InfinityRing or S is QQ or S is ZZ):
|
|
163
|
+
return ScaleAction(S, self, not self_on_left, op)
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def _an_element_(self):
|
|
167
|
+
r"""
|
|
168
|
+
Return a trivial valuation in this space.
|
|
169
|
+
|
|
170
|
+
EXAMPLES::
|
|
171
|
+
|
|
172
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
173
|
+
sage: DiscretePseudoValuationSpace(QQ).an_element() # indirect doctest
|
|
174
|
+
Trivial pseudo-valuation on Rational Field
|
|
175
|
+
"""
|
|
176
|
+
from .trivial_valuation import TrivialPseudoValuation
|
|
177
|
+
return TrivialPseudoValuation(self.domain())
|
|
178
|
+
|
|
179
|
+
def _repr_(self):
|
|
180
|
+
r"""
|
|
181
|
+
Return a printable representation of this space.
|
|
182
|
+
|
|
183
|
+
EXAMPLES::
|
|
184
|
+
|
|
185
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
186
|
+
sage: DiscretePseudoValuationSpace(QQ) # indirect doctest
|
|
187
|
+
Discrete pseudo-valuations on Rational Field
|
|
188
|
+
"""
|
|
189
|
+
return "Discrete pseudo-valuations on %r" % (self.domain(),)
|
|
190
|
+
|
|
191
|
+
def __contains__(self, x):
|
|
192
|
+
r"""
|
|
193
|
+
Return whether ``x`` is a valuation in this space.
|
|
194
|
+
|
|
195
|
+
EXAMPLES::
|
|
196
|
+
|
|
197
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
198
|
+
sage: H = DiscretePseudoValuationSpace(QQ)
|
|
199
|
+
sage: H.an_element() in H
|
|
200
|
+
True
|
|
201
|
+
sage: QQ.valuation(2) in H
|
|
202
|
+
True
|
|
203
|
+
"""
|
|
204
|
+
# override the logic from Homset with the original implementation for Parent
|
|
205
|
+
# which entirely relies on a proper implementation of
|
|
206
|
+
# _element_constructor_ and coercion maps
|
|
207
|
+
from sage.structure.parent import Parent
|
|
208
|
+
return Parent.__contains__(self, x)
|
|
209
|
+
|
|
210
|
+
def __call__(self, x):
|
|
211
|
+
r"""
|
|
212
|
+
Create an element in this space from ``x``.
|
|
213
|
+
|
|
214
|
+
EXAMPLES::
|
|
215
|
+
|
|
216
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
217
|
+
sage: H = DiscretePseudoValuationSpace(QQ)
|
|
218
|
+
sage: H(QQ.valuation(2))
|
|
219
|
+
2-adic valuation
|
|
220
|
+
"""
|
|
221
|
+
# override the logic from Homset with the original implementation for Parent
|
|
222
|
+
# which entirely relies on a proper implementation of
|
|
223
|
+
# _element_constructor_ and coercion maps
|
|
224
|
+
from sage.structure.parent import Parent
|
|
225
|
+
return Parent.__call__(self, x)
|
|
226
|
+
|
|
227
|
+
def _element_constructor_(self, x):
|
|
228
|
+
r"""
|
|
229
|
+
Create an element in this space from ``x``.
|
|
230
|
+
|
|
231
|
+
EXAMPLES:
|
|
232
|
+
|
|
233
|
+
We try to convert valuations defined on different domains by changing
|
|
234
|
+
their base ring::
|
|
235
|
+
|
|
236
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
237
|
+
sage: Z = DiscretePseudoValuationSpace(ZZ)
|
|
238
|
+
sage: Q = DiscretePseudoValuationSpace(QQ)
|
|
239
|
+
sage: v = ZZ.valuation(2)
|
|
240
|
+
sage: v in Q
|
|
241
|
+
False
|
|
242
|
+
sage: Q(v) in Q
|
|
243
|
+
True
|
|
244
|
+
sage: Q(v) in Z
|
|
245
|
+
False
|
|
246
|
+
sage: Z(Q(v)) in Z
|
|
247
|
+
True
|
|
248
|
+
"""
|
|
249
|
+
if isinstance(x.parent(), DiscretePseudoValuationSpace):
|
|
250
|
+
if x.domain() is not self.domain():
|
|
251
|
+
try:
|
|
252
|
+
return self(x.change_domain(self.domain()))
|
|
253
|
+
except NotImplementedError:
|
|
254
|
+
pass
|
|
255
|
+
else:
|
|
256
|
+
return x
|
|
257
|
+
raise ValueError("element cannot be converted into the space of %r" % (self,))
|
|
258
|
+
|
|
259
|
+
class ElementMethods:
|
|
260
|
+
r"""
|
|
261
|
+
Provides methods for discrete pseudo-valuations that are added
|
|
262
|
+
automatically to valuations in this space.
|
|
263
|
+
|
|
264
|
+
EXAMPLES:
|
|
265
|
+
|
|
266
|
+
Here is an example of a method that is automagically added to a
|
|
267
|
+
discrete valuation::
|
|
268
|
+
|
|
269
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
270
|
+
sage: H = DiscretePseudoValuationSpace(QQ)
|
|
271
|
+
sage: QQ.valuation(2).is_discrete_pseudo_valuation() # indirect doctest
|
|
272
|
+
True
|
|
273
|
+
|
|
274
|
+
The methods will be provided even if the concrete type is not created
|
|
275
|
+
with ``__make_element_class__``::
|
|
276
|
+
|
|
277
|
+
sage: from sage.rings.valuation.valuation import DiscretePseudoValuation
|
|
278
|
+
sage: m = DiscretePseudoValuation(H)
|
|
279
|
+
sage: m.parent() is H
|
|
280
|
+
True
|
|
281
|
+
sage: m.is_discrete_pseudo_valuation()
|
|
282
|
+
True
|
|
283
|
+
|
|
284
|
+
However, the category framework advises you to use inheritance::
|
|
285
|
+
|
|
286
|
+
sage: m._test_category()
|
|
287
|
+
Traceback (most recent call last):
|
|
288
|
+
...
|
|
289
|
+
AssertionError: False is not true
|
|
290
|
+
|
|
291
|
+
Using ``__make_element_class__``, makes your concrete valuation inherit
|
|
292
|
+
from this class::
|
|
293
|
+
|
|
294
|
+
sage: m = H.__make_element_class__(DiscretePseudoValuation)(H)
|
|
295
|
+
sage: m._test_category()
|
|
296
|
+
"""
|
|
297
|
+
def is_discrete_pseudo_valuation(self):
|
|
298
|
+
r"""
|
|
299
|
+
Return whether this valuation is a discrete pseudo-valuation.
|
|
300
|
+
|
|
301
|
+
EXAMPLES::
|
|
302
|
+
|
|
303
|
+
sage: QQ.valuation(2).is_discrete_pseudo_valuation()
|
|
304
|
+
True
|
|
305
|
+
"""
|
|
306
|
+
return True
|
|
307
|
+
|
|
308
|
+
@abstract_method
|
|
309
|
+
def is_discrete_valuation(self):
|
|
310
|
+
r"""
|
|
311
|
+
Return whether this valuation is a discrete valuation, i.e.,
|
|
312
|
+
whether it is a :meth:`discrete pseudo valuation
|
|
313
|
+
<is_discrete_pseudo_valuation>` that only sends zero to `\infty`.
|
|
314
|
+
|
|
315
|
+
EXAMPLES::
|
|
316
|
+
|
|
317
|
+
sage: QQ.valuation(2).is_discrete_valuation()
|
|
318
|
+
True
|
|
319
|
+
"""
|
|
320
|
+
|
|
321
|
+
def is_negative_pseudo_valuation(self):
|
|
322
|
+
r"""
|
|
323
|
+
Return whether this valuation is a discrete pseudo-valuation that
|
|
324
|
+
does attain `-\infty`, i.e., it is non-trivial and its domain
|
|
325
|
+
contains an element with valuation `\infty` that has an inverse.
|
|
326
|
+
|
|
327
|
+
EXAMPLES::
|
|
328
|
+
|
|
329
|
+
sage: QQ.valuation(2).is_negative_pseudo_valuation()
|
|
330
|
+
False
|
|
331
|
+
"""
|
|
332
|
+
from sage.categories.fields import Fields
|
|
333
|
+
if self.is_discrete_valuation():
|
|
334
|
+
return False
|
|
335
|
+
elif self.domain() in Fields():
|
|
336
|
+
return True
|
|
337
|
+
raise NotImplementedError
|
|
338
|
+
|
|
339
|
+
@cached_method
|
|
340
|
+
def is_trivial(self):
|
|
341
|
+
r"""
|
|
342
|
+
Return whether this valuation is trivial, i.e., whether it is
|
|
343
|
+
constant `\infty` or constant zero for everything but the zero
|
|
344
|
+
element.
|
|
345
|
+
|
|
346
|
+
Subclasses need to override this method if they do not implement
|
|
347
|
+
:meth:`uniformizer`.
|
|
348
|
+
|
|
349
|
+
EXAMPLES::
|
|
350
|
+
|
|
351
|
+
sage: QQ.valuation(7).is_trivial()
|
|
352
|
+
False
|
|
353
|
+
"""
|
|
354
|
+
from sage.rings.infinity import infinity
|
|
355
|
+
if self(self.domain().one()) is infinity:
|
|
356
|
+
# the constant infinity
|
|
357
|
+
return True
|
|
358
|
+
if self(self.uniformizer()) != 0:
|
|
359
|
+
# not constant on the nonzero elements
|
|
360
|
+
return False
|
|
361
|
+
return True
|
|
362
|
+
|
|
363
|
+
@abstract_method
|
|
364
|
+
def uniformizer(self):
|
|
365
|
+
r"""
|
|
366
|
+
Return an element in the domain which has positive valuation and
|
|
367
|
+
generates the value group of this valuation.
|
|
368
|
+
|
|
369
|
+
EXAMPLES::
|
|
370
|
+
|
|
371
|
+
sage: QQ.valuation(11).uniformizer()
|
|
372
|
+
11
|
|
373
|
+
|
|
374
|
+
Trivial valuations have no uniformizer::
|
|
375
|
+
|
|
376
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
377
|
+
sage: v = DiscretePseudoValuationSpace(QQ).an_element()
|
|
378
|
+
sage: v.is_trivial()
|
|
379
|
+
True
|
|
380
|
+
sage: v.uniformizer()
|
|
381
|
+
Traceback (most recent call last):
|
|
382
|
+
...
|
|
383
|
+
ValueError: Trivial valuations do not define a uniformizing element
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
@cached_method
|
|
387
|
+
def value_group(self):
|
|
388
|
+
r"""
|
|
389
|
+
Return the value group of this discrete pseudo-valuation, the
|
|
390
|
+
discrete additive subgroup of the rational numbers which is
|
|
391
|
+
generated by the valuation of the :meth:`uniformizer`.
|
|
392
|
+
|
|
393
|
+
EXAMPLES::
|
|
394
|
+
|
|
395
|
+
sage: QQ.valuation(2).value_group()
|
|
396
|
+
Additive Abelian Group generated by 1
|
|
397
|
+
|
|
398
|
+
A pseudo-valuation that is `\infty` everywhere, does not have a
|
|
399
|
+
value group::
|
|
400
|
+
|
|
401
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
402
|
+
sage: v = DiscretePseudoValuationSpace(QQ).an_element()
|
|
403
|
+
sage: v.value_group()
|
|
404
|
+
Traceback (most recent call last):
|
|
405
|
+
...
|
|
406
|
+
ValueError: The trivial pseudo-valuation that is infinity everywhere does not have a value group.
|
|
407
|
+
"""
|
|
408
|
+
from .value_group import DiscreteValueGroup
|
|
409
|
+
return DiscreteValueGroup(self(self.uniformizer()))
|
|
410
|
+
|
|
411
|
+
def value_semigroup(self):
|
|
412
|
+
r"""
|
|
413
|
+
Return the value semigroup of this discrete pseudo-valuation, the
|
|
414
|
+
additive subsemigroup of the rational numbers which is generated by
|
|
415
|
+
the valuations of the elements in the domain.
|
|
416
|
+
|
|
417
|
+
EXAMPLES:
|
|
418
|
+
|
|
419
|
+
Most commonly, in particular over fields, the semigroup is the
|
|
420
|
+
group generated by the valuation of the uniformizer::
|
|
421
|
+
|
|
422
|
+
sage: G = QQ.valuation(2).value_semigroup(); G
|
|
423
|
+
Additive Abelian Semigroup generated by -1, 1
|
|
424
|
+
sage: G in AdditiveMagmas().AdditiveAssociative().AdditiveUnital().AdditiveInverse()
|
|
425
|
+
True
|
|
426
|
+
|
|
427
|
+
If the domain is a discrete valuation ring, then the semigroup
|
|
428
|
+
consists of the positive elements of the :meth:`value_group`::
|
|
429
|
+
|
|
430
|
+
sage: Zp(2).valuation().value_semigroup()
|
|
431
|
+
Additive Abelian Semigroup generated by 1
|
|
432
|
+
|
|
433
|
+
The semigroup can have a more complicated structure when the
|
|
434
|
+
uniformizer is not in the domain::
|
|
435
|
+
|
|
436
|
+
sage: v = ZZ.valuation(2)
|
|
437
|
+
sage: R.<x> = ZZ[]
|
|
438
|
+
sage: w = GaussValuation(R, v)
|
|
439
|
+
sage: u = w.augmentation(x, 5/3)
|
|
440
|
+
sage: u.value_semigroup()
|
|
441
|
+
Additive Abelian Semigroup generated by 1, 5/3
|
|
442
|
+
"""
|
|
443
|
+
from sage.categories.fields import Fields
|
|
444
|
+
if self.domain() in Fields():
|
|
445
|
+
from .value_group import DiscreteValueSemigroup
|
|
446
|
+
# return the semigroup generated by the elements of the group
|
|
447
|
+
return DiscreteValueSemigroup([]) + self.value_group()
|
|
448
|
+
raise NotImplementedError("cannot determine value semigroup of %r" % (self,))
|
|
449
|
+
|
|
450
|
+
def element_with_valuation(self, s):
|
|
451
|
+
r"""
|
|
452
|
+
Return an element in the domain of this valuation with valuation
|
|
453
|
+
``s``.
|
|
454
|
+
|
|
455
|
+
EXAMPLES::
|
|
456
|
+
|
|
457
|
+
sage: v = ZZ.valuation(2)
|
|
458
|
+
sage: v.element_with_valuation(10)
|
|
459
|
+
1024
|
|
460
|
+
"""
|
|
461
|
+
from sage.rings.integer_ring import ZZ
|
|
462
|
+
from sage.rings.rational_field import QQ
|
|
463
|
+
s = QQ.coerce(s)
|
|
464
|
+
if s not in self.value_semigroup():
|
|
465
|
+
raise ValueError("s must be in the value semigroup of this valuation but %r is not in %r" % (s, self.value_semigroup()))
|
|
466
|
+
if s == 0:
|
|
467
|
+
return self.domain().one()
|
|
468
|
+
exp = s / self.value_group().gen()
|
|
469
|
+
if exp not in ZZ:
|
|
470
|
+
raise NotImplementedError("s must be a multiple of %r but %r is not" % (self.value_group().gen(), s))
|
|
471
|
+
ret = self.domain()(self.uniformizer() ** ZZ(exp))
|
|
472
|
+
return self.simplify(ret, error=s)
|
|
473
|
+
|
|
474
|
+
@abstract_method
|
|
475
|
+
def residue_ring(self):
|
|
476
|
+
r"""
|
|
477
|
+
Return the residue ring of this valuation, i.e., the elements of
|
|
478
|
+
nonnegative valuation modulo the elements of positive valuation.
|
|
479
|
+
EXAMPLES::
|
|
480
|
+
|
|
481
|
+
sage: QQ.valuation(2).residue_ring()
|
|
482
|
+
Finite Field of size 2
|
|
483
|
+
sage: valuations.TrivialValuation(QQ).residue_ring()
|
|
484
|
+
Rational Field
|
|
485
|
+
|
|
486
|
+
Note that a residue ring always exists, even when a residue field
|
|
487
|
+
may not::
|
|
488
|
+
|
|
489
|
+
sage: valuations.TrivialPseudoValuation(QQ).residue_ring()
|
|
490
|
+
Quotient of Rational Field by the ideal (1)
|
|
491
|
+
sage: valuations.TrivialValuation(ZZ).residue_ring()
|
|
492
|
+
Integer Ring
|
|
493
|
+
sage: GaussValuation(ZZ['x'], ZZ.valuation(2)).residue_ring()
|
|
494
|
+
Univariate Polynomial Ring in x over Finite Field of size 2...
|
|
495
|
+
"""
|
|
496
|
+
|
|
497
|
+
def residue_field(self):
|
|
498
|
+
r"""
|
|
499
|
+
Return the residue field of this valuation, i.e., the field of
|
|
500
|
+
fractions of the :meth:`residue_ring`, the elements of nonnegative
|
|
501
|
+
valuation modulo the elements of positive valuation.
|
|
502
|
+
|
|
503
|
+
EXAMPLES::
|
|
504
|
+
|
|
505
|
+
sage: QQ.valuation(2).residue_field()
|
|
506
|
+
Finite Field of size 2
|
|
507
|
+
sage: valuations.TrivialValuation(QQ).residue_field()
|
|
508
|
+
Rational Field
|
|
509
|
+
|
|
510
|
+
sage: valuations.TrivialValuation(ZZ).residue_field()
|
|
511
|
+
Rational Field
|
|
512
|
+
sage: GaussValuation(ZZ['x'], ZZ.valuation(2)).residue_field()
|
|
513
|
+
Rational function field in x over Finite Field of size 2
|
|
514
|
+
"""
|
|
515
|
+
ret = self.residue_ring()
|
|
516
|
+
from sage.categories.fields import Fields
|
|
517
|
+
if ret in Fields():
|
|
518
|
+
return ret
|
|
519
|
+
from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
|
|
520
|
+
if isinstance(ret, PolynomialRing_generic):
|
|
521
|
+
from sage.rings.function_field.constructor import FunctionField
|
|
522
|
+
return FunctionField(ret.base_ring().fraction_field(), names=(ret.variable_name(),))
|
|
523
|
+
return ret.fraction_field()
|
|
524
|
+
|
|
525
|
+
@abstract_method
|
|
526
|
+
def reduce(self, x):
|
|
527
|
+
r"""
|
|
528
|
+
Return the image of ``x`` in the :meth:`residue_ring` of this
|
|
529
|
+
valuation.
|
|
530
|
+
|
|
531
|
+
EXAMPLES::
|
|
532
|
+
|
|
533
|
+
sage: v = QQ.valuation(2)
|
|
534
|
+
sage: v.reduce(2)
|
|
535
|
+
0
|
|
536
|
+
sage: v.reduce(1)
|
|
537
|
+
1
|
|
538
|
+
sage: v.reduce(1/3)
|
|
539
|
+
1
|
|
540
|
+
sage: v.reduce(1/2)
|
|
541
|
+
Traceback (most recent call last):
|
|
542
|
+
...
|
|
543
|
+
ValueError: reduction is only defined for elements of nonnegative valuation
|
|
544
|
+
"""
|
|
545
|
+
|
|
546
|
+
@abstract_method
|
|
547
|
+
def lift(self, X):
|
|
548
|
+
r"""
|
|
549
|
+
Return a lift of ``X`` in the domain which reduces down to ``X``
|
|
550
|
+
again via :meth:`reduce`.
|
|
551
|
+
|
|
552
|
+
EXAMPLES::
|
|
553
|
+
|
|
554
|
+
sage: v = QQ.valuation(2)
|
|
555
|
+
sage: v.lift(v.residue_ring().one())
|
|
556
|
+
1
|
|
557
|
+
"""
|
|
558
|
+
|
|
559
|
+
def extension(self, ring):
|
|
560
|
+
r"""
|
|
561
|
+
Return the unique extension of this valuation to ``ring``.
|
|
562
|
+
|
|
563
|
+
EXAMPLES::
|
|
564
|
+
|
|
565
|
+
sage: v = ZZ.valuation(2)
|
|
566
|
+
sage: w = v.extension(QQ)
|
|
567
|
+
sage: w.domain()
|
|
568
|
+
Rational Field
|
|
569
|
+
"""
|
|
570
|
+
extensions = self.extensions(ring)
|
|
571
|
+
assert extensions
|
|
572
|
+
if len(extensions) > 1:
|
|
573
|
+
raise ValueError("there is no unique extension of %r from %r to %r" % (self, self.domain(), ring))
|
|
574
|
+
return extensions[0]
|
|
575
|
+
|
|
576
|
+
def extensions(self, ring):
|
|
577
|
+
r"""
|
|
578
|
+
Return the extensions of this valuation to ``ring``.
|
|
579
|
+
|
|
580
|
+
EXAMPLES::
|
|
581
|
+
|
|
582
|
+
sage: v = ZZ.valuation(2)
|
|
583
|
+
sage: v.extensions(QQ)
|
|
584
|
+
[2-adic valuation]
|
|
585
|
+
"""
|
|
586
|
+
if ring is self.domain():
|
|
587
|
+
return [self]
|
|
588
|
+
raise NotImplementedError("extending %r from %r to %r not implemented" % (self, self.domain(), ring))
|
|
589
|
+
|
|
590
|
+
def restriction(self, ring):
|
|
591
|
+
r"""
|
|
592
|
+
Return the restriction of this valuation to ``ring``.
|
|
593
|
+
|
|
594
|
+
EXAMPLES::
|
|
595
|
+
|
|
596
|
+
sage: v = QQ.valuation(2)
|
|
597
|
+
sage: w = v.restriction(ZZ)
|
|
598
|
+
sage: w.domain()
|
|
599
|
+
Integer Ring
|
|
600
|
+
"""
|
|
601
|
+
if ring is self.domain():
|
|
602
|
+
return self
|
|
603
|
+
raise NotImplementedError("restricting %r from %r to %r not implemented" % (self, self.domain(), ring))
|
|
604
|
+
|
|
605
|
+
def change_domain(self, ring):
|
|
606
|
+
r"""
|
|
607
|
+
Return this valuation over ``ring``.
|
|
608
|
+
|
|
609
|
+
Unlike :meth:`extension` or :meth:`restriction`, this might not be
|
|
610
|
+
completely sane mathematically. It is essentially a conversion of
|
|
611
|
+
this valuation into another space of valuations.
|
|
612
|
+
|
|
613
|
+
EXAMPLES::
|
|
614
|
+
|
|
615
|
+
sage: v = QQ.valuation(3)
|
|
616
|
+
sage: v.change_domain(ZZ)
|
|
617
|
+
3-adic valuation
|
|
618
|
+
"""
|
|
619
|
+
if ring is self.domain():
|
|
620
|
+
return self
|
|
621
|
+
if self.domain().is_subring(ring):
|
|
622
|
+
return self.extension(ring)
|
|
623
|
+
if ring.is_subring(self.domain()):
|
|
624
|
+
return self.restriction(ring)
|
|
625
|
+
raise NotImplementedError("changing %r from %r to %r not implemented" % (self, self.domain(), ring))
|
|
626
|
+
|
|
627
|
+
def scale(self, scalar):
|
|
628
|
+
r"""
|
|
629
|
+
Return this valuation scaled by ``scalar``.
|
|
630
|
+
|
|
631
|
+
INPUT:
|
|
632
|
+
|
|
633
|
+
- ``scalar`` -- a nonnegative rational number or infinity
|
|
634
|
+
|
|
635
|
+
EXAMPLES::
|
|
636
|
+
|
|
637
|
+
sage: v = ZZ.valuation(3)
|
|
638
|
+
sage: w = v.scale(3)
|
|
639
|
+
sage: w(3)
|
|
640
|
+
3
|
|
641
|
+
|
|
642
|
+
Scaling can also be done through multiplication with a scalar::
|
|
643
|
+
|
|
644
|
+
sage: w/3 == v
|
|
645
|
+
True
|
|
646
|
+
|
|
647
|
+
Multiplication by zero produces the trivial discrete valuation::
|
|
648
|
+
|
|
649
|
+
sage: w = 0*v
|
|
650
|
+
sage: w(3)
|
|
651
|
+
0
|
|
652
|
+
sage: w(0)
|
|
653
|
+
+Infinity
|
|
654
|
+
|
|
655
|
+
Multiplication by infinity produces the trivial discrete
|
|
656
|
+
pseudo-valuation::
|
|
657
|
+
|
|
658
|
+
sage: w = infinity*v
|
|
659
|
+
sage: w(3)
|
|
660
|
+
+Infinity
|
|
661
|
+
sage: w(0)
|
|
662
|
+
+Infinity
|
|
663
|
+
"""
|
|
664
|
+
from sage.rings.infinity import infinity
|
|
665
|
+
if scalar is infinity:
|
|
666
|
+
from .trivial_valuation import TrivialPseudoValuation
|
|
667
|
+
return TrivialPseudoValuation(self.domain())
|
|
668
|
+
if scalar == 0:
|
|
669
|
+
from .trivial_valuation import TrivialValuation
|
|
670
|
+
return TrivialValuation(self.domain())
|
|
671
|
+
if scalar == 1:
|
|
672
|
+
return self
|
|
673
|
+
if scalar < 0:
|
|
674
|
+
raise ValueError("scalar must be nonnegative")
|
|
675
|
+
if self.is_trivial():
|
|
676
|
+
return self
|
|
677
|
+
|
|
678
|
+
from .scaled_valuation import ScaledValuation_generic
|
|
679
|
+
if isinstance(self, ScaledValuation_generic):
|
|
680
|
+
return self._base_valuation.scale(scalar * self._scale)
|
|
681
|
+
|
|
682
|
+
from .scaled_valuation import ScaledValuation
|
|
683
|
+
return ScaledValuation(self, scalar)
|
|
684
|
+
|
|
685
|
+
def separating_element(self, others):
|
|
686
|
+
r"""
|
|
687
|
+
Return an element in the domain of this valuation which has
|
|
688
|
+
positive valuation with respect to this valuation but negative
|
|
689
|
+
valuation with respect to the valuations in ``others``.
|
|
690
|
+
|
|
691
|
+
EXAMPLES::
|
|
692
|
+
|
|
693
|
+
sage: v2 = QQ.valuation(2)
|
|
694
|
+
sage: v3 = QQ.valuation(3)
|
|
695
|
+
sage: v5 = QQ.valuation(5)
|
|
696
|
+
sage: v2.separating_element([v3,v5])
|
|
697
|
+
4/15
|
|
698
|
+
"""
|
|
699
|
+
try:
|
|
700
|
+
iter(others)
|
|
701
|
+
except TypeError:
|
|
702
|
+
raise ValueError("others must be a list of valuations")
|
|
703
|
+
|
|
704
|
+
for other in others + [self]:
|
|
705
|
+
if other.parent() is not self.parent():
|
|
706
|
+
raise ValueError("all valuations must be valuations on %r but %r is a valuation on %r" % (self.domain(), other, other.domain()))
|
|
707
|
+
if not other.is_discrete_valuation():
|
|
708
|
+
raise ValueError("all valuations must be discrete valuations but %r is not" % (other,))
|
|
709
|
+
if other.is_trivial():
|
|
710
|
+
raise ValueError("all valuations must be non-trivial but %r is not" % (other,))
|
|
711
|
+
|
|
712
|
+
if len(others) == 0:
|
|
713
|
+
return self.uniformizer()
|
|
714
|
+
|
|
715
|
+
# see the proof of Lemma 6.9 in http://www1.spms.ntu.edu.sg/~frederique/antchap6.pdf
|
|
716
|
+
ret = self._strictly_separating_element(others[0])
|
|
717
|
+
for i in range(1, len(others)):
|
|
718
|
+
# ret is an element which separates self and others[:i]
|
|
719
|
+
if others[i](ret) < 0:
|
|
720
|
+
# it also separates self and others[i]
|
|
721
|
+
continue
|
|
722
|
+
|
|
723
|
+
delta = self._strictly_separating_element(others[i])
|
|
724
|
+
if others[i](ret) == 0:
|
|
725
|
+
# combining powers of ret and delta, we produce a
|
|
726
|
+
# separating element for self and others[:i+1]
|
|
727
|
+
factor = ret
|
|
728
|
+
ret = delta
|
|
729
|
+
while any(other(ret) >= 0 for other in others[:i]):
|
|
730
|
+
assert others[i](ret) < 0
|
|
731
|
+
ret *= factor
|
|
732
|
+
else: # others[i](ret) > 0
|
|
733
|
+
# construct an element which approximates a unit with respect to others[i]
|
|
734
|
+
# and has negative valuation with respect to others[:i]
|
|
735
|
+
from sage.rings.semirings.non_negative_integer_semiring import NN
|
|
736
|
+
for r in iter(NN):
|
|
737
|
+
# When we enter this loop we are essentially out of
|
|
738
|
+
# luck. The size of the coefficients is likely going
|
|
739
|
+
# through the roof here and this is not going to
|
|
740
|
+
# terminate in reasonable time.
|
|
741
|
+
factor = (ret**r)/(1+ret**r)
|
|
742
|
+
ret = factor * delta
|
|
743
|
+
if all(other(ret) < 0 for other in others[:i+1]):
|
|
744
|
+
break
|
|
745
|
+
return ret
|
|
746
|
+
|
|
747
|
+
def _strictly_separating_element(self, other):
|
|
748
|
+
r"""
|
|
749
|
+
Return an element in the domain of this valuation which has
|
|
750
|
+
positive valuation with respect to this valuation but negative
|
|
751
|
+
valuation with respect to ``other``.
|
|
752
|
+
|
|
753
|
+
.. NOTE::
|
|
754
|
+
|
|
755
|
+
Overriding this method tends to be a nuisance as you need to
|
|
756
|
+
handle all possible types (as in Python type) of valuations.
|
|
757
|
+
This is essentially the same problem that you have when
|
|
758
|
+
implementing operators such as ``+`` or ``>=``. A sufficiently
|
|
759
|
+
fancy multimethod implementation could solve that here but
|
|
760
|
+
there is currently nothing like that in Sage/Python.
|
|
761
|
+
|
|
762
|
+
EXAMPLES::
|
|
763
|
+
|
|
764
|
+
sage: v2 = QQ.valuation(2)
|
|
765
|
+
sage: v3 = QQ.valuation(3)
|
|
766
|
+
sage: v2._strictly_separating_element(v3)
|
|
767
|
+
2/3
|
|
768
|
+
"""
|
|
769
|
+
from sage.rings.infinity import infinity
|
|
770
|
+
|
|
771
|
+
numerator = self._weakly_separating_element(other)
|
|
772
|
+
n = self(numerator)
|
|
773
|
+
nn = other(numerator)
|
|
774
|
+
assert n > 0
|
|
775
|
+
assert nn is not infinity
|
|
776
|
+
if nn < 0:
|
|
777
|
+
return numerator
|
|
778
|
+
|
|
779
|
+
denominator = other._weakly_separating_element(self)
|
|
780
|
+
d = self(denominator)
|
|
781
|
+
dd = other(denominator)
|
|
782
|
+
assert dd > 0
|
|
783
|
+
assert d is not infinity
|
|
784
|
+
if d < 0:
|
|
785
|
+
# The following may fail if denominator is not
|
|
786
|
+
# invertible in the domain, but we don't have a better
|
|
787
|
+
# option this generically.
|
|
788
|
+
return self.domain()(~denominator)
|
|
789
|
+
|
|
790
|
+
# We need nonnegative integers a and b such that
|
|
791
|
+
# a*n - b*d > 0 and a*nn - b*dd < 0
|
|
792
|
+
if nn == 0:
|
|
793
|
+
# the above becomes b != 0 and a/b > d/n
|
|
794
|
+
b = 1
|
|
795
|
+
a = (d/n + 1).floor()
|
|
796
|
+
else:
|
|
797
|
+
# Since n,nn,d,dd are all nonnegative this is essentially equivalent to
|
|
798
|
+
# a/b > d/n and b/a > nn/dd
|
|
799
|
+
# which is
|
|
800
|
+
# dd/nn > a/b > d/n
|
|
801
|
+
assert dd / nn > d / n
|
|
802
|
+
from sage.rings.continued_fraction import continued_fraction
|
|
803
|
+
ab_cf = []
|
|
804
|
+
dn_cf = continued_fraction(d / n)
|
|
805
|
+
ddnn_cf = continued_fraction(dd / nn)
|
|
806
|
+
for i, (x,y) in enumerate(zip(dn_cf, ddnn_cf)):
|
|
807
|
+
if x == y:
|
|
808
|
+
ab_cf.append(x)
|
|
809
|
+
elif x < y:
|
|
810
|
+
if y > x+1 or len(ddnn_cf) > i+1:
|
|
811
|
+
ab_cf.append(x+1)
|
|
812
|
+
else:
|
|
813
|
+
# the expansion of dd/nn is ending, so we can't append x+1
|
|
814
|
+
ab_cf.extend([x,1,1])
|
|
815
|
+
elif y < x:
|
|
816
|
+
if x > y+1 or len(dn_cf) > i+1:
|
|
817
|
+
ab_cf.append(y+1)
|
|
818
|
+
else:
|
|
819
|
+
ab_cf.extend([y,1,1])
|
|
820
|
+
ab = continued_fraction(ab_cf).value()
|
|
821
|
+
a,b = ab.numerator(), ab.denominator()
|
|
822
|
+
|
|
823
|
+
ret = self.domain()(numerator**a / denominator**b)
|
|
824
|
+
assert (self(ret) > 0)
|
|
825
|
+
assert (other(ret) < 0)
|
|
826
|
+
return ret
|
|
827
|
+
|
|
828
|
+
def _weakly_separating_element(self, other):
|
|
829
|
+
r"""
|
|
830
|
+
Return an element in the domain of this valuation which has
|
|
831
|
+
positive valuation with respect to this valuation and higher
|
|
832
|
+
valuation with respect to this valuation than with respect to
|
|
833
|
+
``other``.
|
|
834
|
+
|
|
835
|
+
.. NOTE::
|
|
836
|
+
|
|
837
|
+
Overriding this method tends to be a nuisance as you need to
|
|
838
|
+
handle all possible types (as in Python type) of valuations.
|
|
839
|
+
This is essentially the same problem that you have when
|
|
840
|
+
implementing operators such as ``+`` or ``>=``. A sufficiently
|
|
841
|
+
fancy multimethod implementation could solve that here but
|
|
842
|
+
there is currently nothing like that in Sage/Python.
|
|
843
|
+
|
|
844
|
+
EXAMPLES::
|
|
845
|
+
|
|
846
|
+
sage: v2 = QQ.valuation(2)
|
|
847
|
+
sage: v3 = QQ.valuation(3)
|
|
848
|
+
sage: v2._weakly_separating_element(v3)
|
|
849
|
+
2
|
|
850
|
+
"""
|
|
851
|
+
ret = self.uniformizer()
|
|
852
|
+
if self(ret) > other(ret):
|
|
853
|
+
return ret
|
|
854
|
+
raise NotImplementedError("weakly separating element for %r and %r" % (self, other))
|
|
855
|
+
|
|
856
|
+
def shift(self, x, s):
|
|
857
|
+
r"""
|
|
858
|
+
Shift ``x`` in its expansion with respect to :meth:`uniformizer` by
|
|
859
|
+
``s`` "digits".
|
|
860
|
+
|
|
861
|
+
For nonnegative ``s``, this just returns ``x`` multiplied by a
|
|
862
|
+
power of the uniformizer `\pi`.
|
|
863
|
+
|
|
864
|
+
For negative ``s``, it does the same but when not over a field, it
|
|
865
|
+
drops coefficients in the `\pi`-adic expansion which have negative
|
|
866
|
+
valuation.
|
|
867
|
+
|
|
868
|
+
EXAMPLES::
|
|
869
|
+
|
|
870
|
+
sage: v = ZZ.valuation(2)
|
|
871
|
+
sage: v.shift(1, 10)
|
|
872
|
+
1024
|
|
873
|
+
sage: v.shift(11, -1)
|
|
874
|
+
5
|
|
875
|
+
|
|
876
|
+
For some rings, there is no clear `\pi`-adic expansion. In this
|
|
877
|
+
case, this method performs negative shifts by iterated division by
|
|
878
|
+
the uniformizer and substraction of a lift of the reduction::
|
|
879
|
+
|
|
880
|
+
sage: R.<x> = ZZ[]
|
|
881
|
+
sage: v = ZZ.valuation(2)
|
|
882
|
+
sage: w = GaussValuation(R, v)
|
|
883
|
+
sage: w.shift(x, 1)
|
|
884
|
+
2*x
|
|
885
|
+
sage: w.shift(2*x, -1)
|
|
886
|
+
x
|
|
887
|
+
sage: w.shift(x + 2*x^2, -1)
|
|
888
|
+
x^2
|
|
889
|
+
"""
|
|
890
|
+
from sage.rings.integer_ring import ZZ
|
|
891
|
+
x = self.domain().coerce(x)
|
|
892
|
+
s = self.value_group()(s)
|
|
893
|
+
if s == 0:
|
|
894
|
+
return x
|
|
895
|
+
|
|
896
|
+
s = ZZ(s / self.value_group().gen())
|
|
897
|
+
if s > 0:
|
|
898
|
+
return x * self.uniformizer()**s
|
|
899
|
+
else: # s < 0
|
|
900
|
+
if ~self.uniformizer() in self.domain():
|
|
901
|
+
return self.domain()(x / self.uniformizer()**(-s))
|
|
902
|
+
else:
|
|
903
|
+
for i in range(-s):
|
|
904
|
+
if self(x) < 0:
|
|
905
|
+
raise NotImplementedError("cannot compute general shifts over non-fields which contain elements of negative valuation")
|
|
906
|
+
x -= self.lift(self.reduce(x))
|
|
907
|
+
x //= self.uniformizer()
|
|
908
|
+
return x
|
|
909
|
+
|
|
910
|
+
def simplify(self, x, error=None, force=False):
|
|
911
|
+
r"""
|
|
912
|
+
Return a simplified version of ``x``.
|
|
913
|
+
|
|
914
|
+
Produce an element which differs from ``x`` by an element of
|
|
915
|
+
valuation strictly greater than the valuation of ``x`` (or strictly
|
|
916
|
+
greater than ``error`` if set.)
|
|
917
|
+
|
|
918
|
+
If ``force`` is not set, then expensive simplifications may be avoided.
|
|
919
|
+
|
|
920
|
+
EXAMPLES::
|
|
921
|
+
|
|
922
|
+
sage: v = ZZ.valuation(2)
|
|
923
|
+
sage: v.simplify(6, force=True)
|
|
924
|
+
2
|
|
925
|
+
sage: v.simplify(6, error=0, force=True)
|
|
926
|
+
0
|
|
927
|
+
"""
|
|
928
|
+
x = self.domain().coerce(x)
|
|
929
|
+
|
|
930
|
+
if error is not None and self(x) > error:
|
|
931
|
+
return self.domain().zero()
|
|
932
|
+
return x
|
|
933
|
+
|
|
934
|
+
def lower_bound(self, x):
|
|
935
|
+
r"""
|
|
936
|
+
Return a lower bound of this valuation at ``x``.
|
|
937
|
+
|
|
938
|
+
Use this method to get an approximation of the valuation of ``x``
|
|
939
|
+
when speed is more important than accuracy.
|
|
940
|
+
|
|
941
|
+
EXAMPLES::
|
|
942
|
+
|
|
943
|
+
sage: v = ZZ.valuation(2)
|
|
944
|
+
sage: v.lower_bound(2^10)
|
|
945
|
+
10
|
|
946
|
+
"""
|
|
947
|
+
return self(x)
|
|
948
|
+
|
|
949
|
+
def upper_bound(self, x):
|
|
950
|
+
r"""
|
|
951
|
+
Return an upper bound of this valuation at ``x``.
|
|
952
|
+
|
|
953
|
+
Use this method to get an approximation of the valuation of ``x``
|
|
954
|
+
when speed is more important than accuracy.
|
|
955
|
+
|
|
956
|
+
EXAMPLES::
|
|
957
|
+
|
|
958
|
+
sage: v = ZZ.valuation(2)
|
|
959
|
+
sage: v.upper_bound(2^10)
|
|
960
|
+
10
|
|
961
|
+
"""
|
|
962
|
+
return self(x)
|
|
963
|
+
|
|
964
|
+
def inverse(self, x, precision):
|
|
965
|
+
r"""
|
|
966
|
+
Return an approximate inverse of ``x``.
|
|
967
|
+
|
|
968
|
+
The element returned is such that the product differs from 1 by an
|
|
969
|
+
element of valuation at least ``precision``.
|
|
970
|
+
|
|
971
|
+
INPUT:
|
|
972
|
+
|
|
973
|
+
- ``x`` -- an element in the domain of this valuation
|
|
974
|
+
|
|
975
|
+
- ``precision`` -- a rational or infinity
|
|
976
|
+
|
|
977
|
+
EXAMPLES::
|
|
978
|
+
|
|
979
|
+
sage: v = ZZ.valuation(2)
|
|
980
|
+
sage: x = 3
|
|
981
|
+
sage: y = v.inverse(3, 2); y
|
|
982
|
+
3
|
|
983
|
+
sage: x*y - 1
|
|
984
|
+
8
|
|
985
|
+
|
|
986
|
+
This might not be possible for elements of positive valuation::
|
|
987
|
+
|
|
988
|
+
sage: v.inverse(2, 2)
|
|
989
|
+
Traceback (most recent call last):
|
|
990
|
+
...
|
|
991
|
+
ValueError: element has no approximate inverse in this ring
|
|
992
|
+
|
|
993
|
+
Of course this always works over fields::
|
|
994
|
+
|
|
995
|
+
sage: v = QQ.valuation(2)
|
|
996
|
+
sage: v.inverse(2, 2)
|
|
997
|
+
1/2
|
|
998
|
+
"""
|
|
999
|
+
return x.inverse_of_unit()
|
|
1000
|
+
|
|
1001
|
+
def _relative_size(self, x):
|
|
1002
|
+
r"""
|
|
1003
|
+
Return an estimate on the coefficient size of ``x``.
|
|
1004
|
+
|
|
1005
|
+
The number returned is an estimate on the factor between the number of
|
|
1006
|
+
bits used by ``x`` and the minimal number of bits used by an element
|
|
1007
|
+
congruent to ``x``.
|
|
1008
|
+
|
|
1009
|
+
This is used by :meth:`simplify` to decide whether simplification of
|
|
1010
|
+
coefficients is going to lead to a significant shrinking of the
|
|
1011
|
+
coefficients of ``x``.
|
|
1012
|
+
|
|
1013
|
+
EXAMPLES::
|
|
1014
|
+
|
|
1015
|
+
sage: v = Qp(2).valuation()
|
|
1016
|
+
sage: v._relative_size(2)
|
|
1017
|
+
1
|
|
1018
|
+
|
|
1019
|
+
Some valuations do not overwrite this method because simplification
|
|
1020
|
+
does not increase the speed of valuations, e.g., some `p`-adic
|
|
1021
|
+
valuations::
|
|
1022
|
+
|
|
1023
|
+
sage: v._relative_size(2**20)
|
|
1024
|
+
1
|
|
1025
|
+
"""
|
|
1026
|
+
return 1
|
|
1027
|
+
|
|
1028
|
+
def _test_is_negative_pseudo_valuation(self, **options):
|
|
1029
|
+
r"""
|
|
1030
|
+
Check that :meth:`is_negative_pseudo_valuation` works correctly.
|
|
1031
|
+
|
|
1032
|
+
TESTS::
|
|
1033
|
+
|
|
1034
|
+
sage: v = ZZ.valuation(3)
|
|
1035
|
+
sage: v._test_is_negative_pseudo_valuation()
|
|
1036
|
+
"""
|
|
1037
|
+
tester = self._tester(**options)
|
|
1038
|
+
|
|
1039
|
+
if self.is_discrete_valuation():
|
|
1040
|
+
tester.assertFalse(self.is_negative_pseudo_valuation())
|
|
1041
|
+
return
|
|
1042
|
+
|
|
1043
|
+
if not self.is_negative_pseudo_valuation():
|
|
1044
|
+
X = self.domain().some_elements()
|
|
1045
|
+
for x in tester.some_elements(X):
|
|
1046
|
+
from sage.rings.infinity import infinity
|
|
1047
|
+
tester.assertNotEqual(self(x), -infinity)
|
|
1048
|
+
|
|
1049
|
+
def _test_bounds(self, **options):
|
|
1050
|
+
r"""
|
|
1051
|
+
Check that :meth:`lower_bound` and :meth:`upper_bound` work
|
|
1052
|
+
correctly.
|
|
1053
|
+
|
|
1054
|
+
TESTS::
|
|
1055
|
+
|
|
1056
|
+
sage: v = ZZ.valuation(3)
|
|
1057
|
+
sage: v._test_bounds()
|
|
1058
|
+
"""
|
|
1059
|
+
tester = self._tester(**options)
|
|
1060
|
+
|
|
1061
|
+
X = self.domain().some_elements()
|
|
1062
|
+
for x in tester.some_elements(X):
|
|
1063
|
+
tester.assertGreaterEqual(self.upper_bound(x), self(x))
|
|
1064
|
+
tester.assertLessEqual(self.lower_bound(x), self(x))
|
|
1065
|
+
|
|
1066
|
+
def _test_simplify(self, **options):
|
|
1067
|
+
r"""
|
|
1068
|
+
Check that :meth:`simplify` works correctly.
|
|
1069
|
+
|
|
1070
|
+
TESTS::
|
|
1071
|
+
|
|
1072
|
+
sage: v = ZZ.valuation(3)
|
|
1073
|
+
sage: v._test_simplify()
|
|
1074
|
+
"""
|
|
1075
|
+
tester = self._tester(**options)
|
|
1076
|
+
|
|
1077
|
+
try:
|
|
1078
|
+
self.residue_ring()
|
|
1079
|
+
has_residue_ring = True
|
|
1080
|
+
except NotImplementedError:
|
|
1081
|
+
# over non-fields (and especially polynomial rings over
|
|
1082
|
+
# non-fields) computation of the residue ring is often
|
|
1083
|
+
# difficult and not very interesting
|
|
1084
|
+
from sage.categories.fields import Fields
|
|
1085
|
+
if self.domain() not in Fields():
|
|
1086
|
+
return
|
|
1087
|
+
raise
|
|
1088
|
+
|
|
1089
|
+
X = self.domain().some_elements()
|
|
1090
|
+
for x in tester.some_elements(X):
|
|
1091
|
+
y = self.simplify(x)
|
|
1092
|
+
tester.assertEqual(self(x), self(y))
|
|
1093
|
+
if self(x) >= 0 and has_residue_ring:
|
|
1094
|
+
tester.assertEqual(self.reduce(x), self.reduce(y))
|
|
1095
|
+
|
|
1096
|
+
if self.is_trivial() and not self.is_discrete_valuation():
|
|
1097
|
+
return
|
|
1098
|
+
|
|
1099
|
+
S = self.value_group().some_elements()
|
|
1100
|
+
from itertools import product
|
|
1101
|
+
for x,s in tester.some_elements(product(X, S)):
|
|
1102
|
+
y = self.simplify(x, error=s)
|
|
1103
|
+
if self.domain().is_exact():
|
|
1104
|
+
tester.assertGreaterEqual(self(x-y), s)
|
|
1105
|
+
elif hasattr(y, 'precision_absolute'):
|
|
1106
|
+
tester.assertGreaterEqual(self(x-y), min(s, y.precision_absolute()))
|
|
1107
|
+
|
|
1108
|
+
def _test_shift(self, **options):
|
|
1109
|
+
r"""
|
|
1110
|
+
Check that :meth:`shift` works correctly.
|
|
1111
|
+
|
|
1112
|
+
TESTS::
|
|
1113
|
+
|
|
1114
|
+
sage: v = ZZ.valuation(3)
|
|
1115
|
+
sage: v._test_shift()
|
|
1116
|
+
"""
|
|
1117
|
+
if self.is_trivial() and not self.is_discrete_valuation():
|
|
1118
|
+
return
|
|
1119
|
+
|
|
1120
|
+
try:
|
|
1121
|
+
self.residue_ring()
|
|
1122
|
+
except Exception:
|
|
1123
|
+
# it is not clear what a shift should be in this case
|
|
1124
|
+
return
|
|
1125
|
+
|
|
1126
|
+
tester = self._tester(**options)
|
|
1127
|
+
X = self.domain().some_elements()
|
|
1128
|
+
S = self.value_group().some_elements()
|
|
1129
|
+
from itertools import product
|
|
1130
|
+
for x,s in tester.some_elements(product(X, S)):
|
|
1131
|
+
if self(x) < 0 and ~self.uniformizer() not in self.domain():
|
|
1132
|
+
# it is not clear what a shift should be in this case
|
|
1133
|
+
continue
|
|
1134
|
+
y = self.shift(x, s)
|
|
1135
|
+
if s >= 0:
|
|
1136
|
+
tester.assertGreaterEqual(self(y),self(x))
|
|
1137
|
+
from sage.categories.fields import Fields
|
|
1138
|
+
if self.domain().is_exact() and self.domain() in Fields():
|
|
1139
|
+
# the shift here sometimes fails if elements implement
|
|
1140
|
+
# __floordiv__ incorrectly, see #23971
|
|
1141
|
+
tester.assertEqual(x, self.shift(y, -s))
|
|
1142
|
+
|
|
1143
|
+
def _test_scale(self, **options):
|
|
1144
|
+
r"""
|
|
1145
|
+
Check that :meth:`scale` works correctly.
|
|
1146
|
+
|
|
1147
|
+
TESTS::
|
|
1148
|
+
|
|
1149
|
+
sage: v = ZZ.valuation(3)
|
|
1150
|
+
sage: v._test_scale()
|
|
1151
|
+
"""
|
|
1152
|
+
tester = self._tester(**options)
|
|
1153
|
+
|
|
1154
|
+
from sage.rings.rational_field import QQ
|
|
1155
|
+
from sage.rings.infinity import infinity
|
|
1156
|
+
from .trivial_valuation import TrivialValuation, TrivialPseudoValuation
|
|
1157
|
+
|
|
1158
|
+
tester.assertEqual(QQ(0)*self, TrivialValuation(self.domain()))
|
|
1159
|
+
tester.assertEqual(infinity*self, TrivialPseudoValuation(self.domain()))
|
|
1160
|
+
|
|
1161
|
+
for s in tester.some_elements(QQ.some_elements()):
|
|
1162
|
+
if s < 0:
|
|
1163
|
+
with tester.assertRaises(ValueError):
|
|
1164
|
+
s * self
|
|
1165
|
+
continue
|
|
1166
|
+
if s == 0:
|
|
1167
|
+
continue
|
|
1168
|
+
|
|
1169
|
+
scaled = s * self
|
|
1170
|
+
|
|
1171
|
+
tester.assertEqual(self.is_trivial(), scaled.is_trivial())
|
|
1172
|
+
if not self.is_trivial():
|
|
1173
|
+
tester.assertEqual(self.uniformizer(), scaled.uniformizer())
|
|
1174
|
+
tester.assertEqual(scaled(self.uniformizer()), s * self(self.uniformizer()))
|
|
1175
|
+
unscaled = scaled / s
|
|
1176
|
+
tester.assertEqual(self, unscaled)
|
|
1177
|
+
|
|
1178
|
+
def _test_add(self, **options):
|
|
1179
|
+
r"""
|
|
1180
|
+
Check that the (strict) triangle equality is satisfied for the
|
|
1181
|
+
valuation of this ring.
|
|
1182
|
+
|
|
1183
|
+
TESTS::
|
|
1184
|
+
|
|
1185
|
+
sage: v = ZZ.valuation(3)
|
|
1186
|
+
sage: v._test_add()
|
|
1187
|
+
"""
|
|
1188
|
+
tester = self._tester(**options)
|
|
1189
|
+
S = self.domain().some_elements()
|
|
1190
|
+
from itertools import product
|
|
1191
|
+
for x, y in tester.some_elements(product(S, S)):
|
|
1192
|
+
tester.assertGreaterEqual(self(x + y), min(self(x), self(y)))
|
|
1193
|
+
if self(x) != self(y):
|
|
1194
|
+
tester.assertEqual(self(x + y), min(self(x), self(y)))
|
|
1195
|
+
|
|
1196
|
+
def _test_infinite_zero(self, **options):
|
|
1197
|
+
r"""
|
|
1198
|
+
Check that zero is sent to infinity.
|
|
1199
|
+
|
|
1200
|
+
TESTS::
|
|
1201
|
+
|
|
1202
|
+
sage: v = QQ.valuation(5)
|
|
1203
|
+
sage: v._test_infinite_zero()
|
|
1204
|
+
"""
|
|
1205
|
+
tester = self._tester(**options)
|
|
1206
|
+
from sage.rings.infinity import infinity
|
|
1207
|
+
tester.assertEqual(self(self.domain().zero()), infinity)
|
|
1208
|
+
|
|
1209
|
+
def _test_mul(self, **options):
|
|
1210
|
+
r"""
|
|
1211
|
+
Check that multiplication translates to addition of valuations.
|
|
1212
|
+
|
|
1213
|
+
TESTS::
|
|
1214
|
+
|
|
1215
|
+
sage: v = QQ.valuation(5)
|
|
1216
|
+
sage: v._test_mul()
|
|
1217
|
+
"""
|
|
1218
|
+
from sage.rings.infinity import infinity
|
|
1219
|
+
from itertools import product
|
|
1220
|
+
tester = self._tester(**options)
|
|
1221
|
+
S = self.domain().some_elements()
|
|
1222
|
+
infis = {infinity, -infinity}
|
|
1223
|
+
|
|
1224
|
+
for x, y in tester.some_elements(product(S, S)):
|
|
1225
|
+
if {Sx := self(x), Sy := self(y)} == infis:
|
|
1226
|
+
continue
|
|
1227
|
+
tester.assertEqual(self(x * y), Sx + Sy)
|
|
1228
|
+
|
|
1229
|
+
def _test_no_infinite_units(self, **options):
|
|
1230
|
+
r"""
|
|
1231
|
+
Check that no units are sent to infinity.
|
|
1232
|
+
|
|
1233
|
+
TESTS::
|
|
1234
|
+
|
|
1235
|
+
sage: v = QQ.valuation(5)
|
|
1236
|
+
sage: v._test_no_infinite_units()
|
|
1237
|
+
|
|
1238
|
+
As multiplication translates to addition, pseudo-valuations which
|
|
1239
|
+
send a unit to infinity are necessarily trivial::
|
|
1240
|
+
|
|
1241
|
+
sage: from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace
|
|
1242
|
+
sage: v = DiscretePseudoValuationSpace(QQ).an_element()
|
|
1243
|
+
sage: v(1)
|
|
1244
|
+
+Infinity
|
|
1245
|
+
sage: v.is_trivial()
|
|
1246
|
+
True
|
|
1247
|
+
"""
|
|
1248
|
+
if not self.is_discrete_valuation() and self.is_trivial():
|
|
1249
|
+
return
|
|
1250
|
+
if self.is_negative_pseudo_valuation():
|
|
1251
|
+
return
|
|
1252
|
+
|
|
1253
|
+
from sage.rings.infinity import infinity
|
|
1254
|
+
tester = self._tester(**options)
|
|
1255
|
+
for x in tester.some_elements(self.domain().some_elements()):
|
|
1256
|
+
if self(x) is infinity:
|
|
1257
|
+
tester.assertFalse(x.is_unit())
|
|
1258
|
+
|
|
1259
|
+
def _test_value_group(self, **options):
|
|
1260
|
+
r"""
|
|
1261
|
+
Check correctness of the value group.
|
|
1262
|
+
|
|
1263
|
+
TESTS::
|
|
1264
|
+
|
|
1265
|
+
sage: v = QQ.valuation(5)
|
|
1266
|
+
sage: v._test_value_group()
|
|
1267
|
+
"""
|
|
1268
|
+
from sage.rings.infinity import infinity
|
|
1269
|
+
tester = self._tester(**options)
|
|
1270
|
+
# check consistency of trivial valuations first
|
|
1271
|
+
if self.is_trivial():
|
|
1272
|
+
if self(self.domain().one()) is infinity:
|
|
1273
|
+
# a trivial pseudo-valuation that sends everything to infinity
|
|
1274
|
+
with tester.assertRaises(ValueError):
|
|
1275
|
+
self.value_group()
|
|
1276
|
+
return
|
|
1277
|
+
|
|
1278
|
+
# check that all valuations are in the value group
|
|
1279
|
+
for x in tester.some_elements(self.domain().some_elements()):
|
|
1280
|
+
if self(x) is not infinity and self(x) is not -infinity:
|
|
1281
|
+
tester.assertIn(self(x), self.value_group())
|
|
1282
|
+
|
|
1283
|
+
if not self.is_trivial():
|
|
1284
|
+
# check that the uniformizer generates the value group
|
|
1285
|
+
tester.assertEqual(self.value_group().gen(), self(self.uniformizer()))
|
|
1286
|
+
|
|
1287
|
+
def _test_value_semigroup(self, **options):
|
|
1288
|
+
r"""
|
|
1289
|
+
Check correctness of the value semigroup.
|
|
1290
|
+
|
|
1291
|
+
TESTS::
|
|
1292
|
+
|
|
1293
|
+
sage: v = QQ.valuation(5)
|
|
1294
|
+
sage: v._test_value_semigroup() # needs sage.geometry.polyhedron
|
|
1295
|
+
"""
|
|
1296
|
+
tester = self._tester(**options)
|
|
1297
|
+
|
|
1298
|
+
if self.is_trivial() and not self.is_discrete_valuation():
|
|
1299
|
+
# the trivial pseudo-valuation does not have a value semigroup
|
|
1300
|
+
return
|
|
1301
|
+
|
|
1302
|
+
for s in tester.some_elements(self.value_semigroup().some_elements()):
|
|
1303
|
+
tester.assertIn(s, self.value_group())
|
|
1304
|
+
|
|
1305
|
+
def _test_element_with_valuation(self, **options):
|
|
1306
|
+
r"""
|
|
1307
|
+
Check correctness of :meth:`element_with_valuation`.
|
|
1308
|
+
|
|
1309
|
+
TESTS::
|
|
1310
|
+
|
|
1311
|
+
sage: v = QQ.valuation(5)
|
|
1312
|
+
sage: v._test_element_with_valuation() # needs sage.geometry.polyhedron
|
|
1313
|
+
"""
|
|
1314
|
+
tester = self._tester(**options)
|
|
1315
|
+
|
|
1316
|
+
if self.is_trivial() and not self.is_discrete_valuation():
|
|
1317
|
+
# the trivial pseudo-valuation does not have a value semigroup
|
|
1318
|
+
return
|
|
1319
|
+
|
|
1320
|
+
for s in tester.some_elements(self.value_semigroup().some_elements()):
|
|
1321
|
+
tester.assertEqual(self(self.element_with_valuation(s)), s)
|
|
1322
|
+
|
|
1323
|
+
def _test_residue_ring(self, **options):
|
|
1324
|
+
r"""
|
|
1325
|
+
Check the correctness of residue rings.
|
|
1326
|
+
|
|
1327
|
+
TESTS::
|
|
1328
|
+
|
|
1329
|
+
sage: v = QQ.valuation(5)
|
|
1330
|
+
sage: v._test_residue_ring()
|
|
1331
|
+
"""
|
|
1332
|
+
tester = self._tester(**options)
|
|
1333
|
+
|
|
1334
|
+
try:
|
|
1335
|
+
r = self.residue_ring()
|
|
1336
|
+
except NotImplementedError:
|
|
1337
|
+
# over non-fields (and especially polynomial rings over
|
|
1338
|
+
# non-fields) computation of the residue ring is often
|
|
1339
|
+
# difficult and not very interesting
|
|
1340
|
+
from sage.categories.fields import Fields
|
|
1341
|
+
if self.domain() not in Fields():
|
|
1342
|
+
return
|
|
1343
|
+
raise
|
|
1344
|
+
|
|
1345
|
+
if r.zero() == r.one():
|
|
1346
|
+
# residue ring is the zero rng
|
|
1347
|
+
tester.assertGreater(self(1), 0)
|
|
1348
|
+
return
|
|
1349
|
+
|
|
1350
|
+
c = self.residue_ring().characteristic()
|
|
1351
|
+
if c != 0:
|
|
1352
|
+
tester.assertGreater(self(c), 0)
|
|
1353
|
+
|
|
1354
|
+
def _test_reduce(self, **options):
|
|
1355
|
+
r"""
|
|
1356
|
+
Check the correctness of reductions.
|
|
1357
|
+
|
|
1358
|
+
TESTS::
|
|
1359
|
+
|
|
1360
|
+
sage: v = QQ.valuation(5)
|
|
1361
|
+
sage: v._test_reduce()
|
|
1362
|
+
"""
|
|
1363
|
+
tester = self._tester(**options)
|
|
1364
|
+
|
|
1365
|
+
try:
|
|
1366
|
+
self.residue_ring()
|
|
1367
|
+
except NotImplementedError:
|
|
1368
|
+
# over non-fields (and especially polynomial rings over
|
|
1369
|
+
# non-fields) computation of the residue ring is often
|
|
1370
|
+
# difficult and not very interesting
|
|
1371
|
+
from sage.categories.fields import Fields
|
|
1372
|
+
if self.domain() not in Fields():
|
|
1373
|
+
return
|
|
1374
|
+
raise
|
|
1375
|
+
|
|
1376
|
+
for x in tester.some_elements(self.domain().some_elements()):
|
|
1377
|
+
if self(x) < 0:
|
|
1378
|
+
with tester.assertRaises((ValueError, ArithmeticError)):
|
|
1379
|
+
self.reduce(x)
|
|
1380
|
+
continue
|
|
1381
|
+
if self(x) == 0:
|
|
1382
|
+
y = self.reduce(x)
|
|
1383
|
+
tester.assertIn(y, self.residue_ring())
|
|
1384
|
+
tester.assertNotEqual(y, 0)
|
|
1385
|
+
if x.is_unit() and ~x in self.domain():
|
|
1386
|
+
tester.assertTrue(y.is_unit())
|
|
1387
|
+
tester.assertIn(~y, self.residue_ring())
|
|
1388
|
+
tester.assertEqual(~y, self.reduce(self.domain()(~x)))
|
|
1389
|
+
if self(x) > 0:
|
|
1390
|
+
tester.assertEqual(self.reduce(x), 0)
|
|
1391
|
+
|
|
1392
|
+
def _test_lift(self, **options):
|
|
1393
|
+
r"""
|
|
1394
|
+
Check the correctness of lifts.
|
|
1395
|
+
|
|
1396
|
+
TESTS::
|
|
1397
|
+
|
|
1398
|
+
sage: v = QQ.valuation(5)
|
|
1399
|
+
sage: v._test_lift()
|
|
1400
|
+
"""
|
|
1401
|
+
tester = self._tester(**options)
|
|
1402
|
+
|
|
1403
|
+
try:
|
|
1404
|
+
self.residue_ring()
|
|
1405
|
+
except NotImplementedError:
|
|
1406
|
+
# over non-fields (and especially polynomial rings over
|
|
1407
|
+
# non-fields) computation of the residue ring is often
|
|
1408
|
+
# difficult and not very interesting
|
|
1409
|
+
from sage.categories.fields import Fields
|
|
1410
|
+
if self.domain() not in Fields():
|
|
1411
|
+
return
|
|
1412
|
+
raise
|
|
1413
|
+
|
|
1414
|
+
for X in tester.some_elements(self.residue_ring().some_elements()):
|
|
1415
|
+
x = self.lift(X)
|
|
1416
|
+
y = self.reduce(x)
|
|
1417
|
+
tester.assertEqual(X, y)
|
|
1418
|
+
if X != 0:
|
|
1419
|
+
tester.assertEqual(self(x), 0)
|
|
1420
|
+
|
|
1421
|
+
def _test_restriction(self, **options):
|
|
1422
|
+
r"""
|
|
1423
|
+
Check the correctness of reductions.
|
|
1424
|
+
|
|
1425
|
+
TESTS::
|
|
1426
|
+
|
|
1427
|
+
sage: v = QQ.valuation(5)
|
|
1428
|
+
sage: v._test_restriction()
|
|
1429
|
+
"""
|
|
1430
|
+
tester = self._tester(**options)
|
|
1431
|
+
|
|
1432
|
+
tester.assertEqual(self.restriction(self.domain()), self)
|
|
1433
|
+
|
|
1434
|
+
def _test_extension(self, **options):
|
|
1435
|
+
r"""
|
|
1436
|
+
Check the correctness of extensions.
|
|
1437
|
+
|
|
1438
|
+
TESTS::
|
|
1439
|
+
|
|
1440
|
+
sage: v = QQ.valuation(5)
|
|
1441
|
+
sage: v._test_extension()
|
|
1442
|
+
"""
|
|
1443
|
+
tester = self._tester(**options)
|
|
1444
|
+
|
|
1445
|
+
tester.assertEqual(self.extension(self.domain()), self)
|
|
1446
|
+
tester.assertEqual(self.extensions(self.domain()), [self])
|
|
1447
|
+
|
|
1448
|
+
def _test_change_domain(self, **options):
|
|
1449
|
+
r"""
|
|
1450
|
+
Check the correctness of :meth:`change_domain`.
|
|
1451
|
+
|
|
1452
|
+
TESTS::
|
|
1453
|
+
|
|
1454
|
+
sage: v = QQ.valuation(5)
|
|
1455
|
+
sage: v._test_change_domain()
|
|
1456
|
+
"""
|
|
1457
|
+
tester = self._tester(**options)
|
|
1458
|
+
|
|
1459
|
+
tester.assertEqual(self.change_domain(self.domain()), self)
|
|
1460
|
+
|
|
1461
|
+
def _test_no_infinite_nonzero(self, **options):
|
|
1462
|
+
r"""
|
|
1463
|
+
Check that only zero is sent to infinity.
|
|
1464
|
+
|
|
1465
|
+
TESTS::
|
|
1466
|
+
|
|
1467
|
+
sage: v = QQ.valuation(5)
|
|
1468
|
+
sage: v._test_no_infinite_nonzero()
|
|
1469
|
+
"""
|
|
1470
|
+
if not self.is_discrete_valuation():
|
|
1471
|
+
return
|
|
1472
|
+
|
|
1473
|
+
from sage.rings.infinity import infinity
|
|
1474
|
+
tester = self._tester(**options)
|
|
1475
|
+
for x in tester.some_elements(self.domain().some_elements()):
|
|
1476
|
+
if self(x) is infinity:
|
|
1477
|
+
tester.assertEqual(x, 0)
|
|
1478
|
+
|
|
1479
|
+
def _test_residue_field(self, **options):
|
|
1480
|
+
r"""
|
|
1481
|
+
Check the correctness of residue fields.
|
|
1482
|
+
|
|
1483
|
+
TESTS::
|
|
1484
|
+
|
|
1485
|
+
sage: v = QQ.valuation(5)
|
|
1486
|
+
sage: v._test_residue_field()
|
|
1487
|
+
"""
|
|
1488
|
+
if not self.is_discrete_valuation():
|
|
1489
|
+
return
|
|
1490
|
+
|
|
1491
|
+
tester = self._tester(**options)
|
|
1492
|
+
try:
|
|
1493
|
+
self.residue_field()
|
|
1494
|
+
except ValueError:
|
|
1495
|
+
from sage.categories.fields import Fields
|
|
1496
|
+
# a discrete valuation on a field has a residue field
|
|
1497
|
+
tester.assertNotIn(self.domain(), Fields())
|
|
1498
|
+
return
|
|
1499
|
+
except NotImplementedError:
|
|
1500
|
+
# over non-fields (and especially polynomial rings over
|
|
1501
|
+
# non-fields) computation of the residue ring is often
|
|
1502
|
+
# difficult and not very interesting
|
|
1503
|
+
from sage.categories.fields import Fields
|
|
1504
|
+
if self.domain() not in Fields():
|
|
1505
|
+
return
|
|
1506
|
+
raise
|
|
1507
|
+
|
|
1508
|
+
try:
|
|
1509
|
+
r = self.residue_ring()
|
|
1510
|
+
except Exception:
|
|
1511
|
+
# If the residue ring cannot be constructed for some reason
|
|
1512
|
+
# then we do not check its relation to the residue field.
|
|
1513
|
+
# _test_residue_ring() is responsible for checking whether the
|
|
1514
|
+
# residue ring should be constructible or not.
|
|
1515
|
+
pass
|
|
1516
|
+
else:
|
|
1517
|
+
# the residue ring must coerce into the residue field
|
|
1518
|
+
tester.assertTrue(self.residue_field().has_coerce_map_from(r))
|
|
1519
|
+
|
|
1520
|
+
c = self.residue_field().characteristic()
|
|
1521
|
+
if c != 0:
|
|
1522
|
+
tester.assertGreater(self(c), 0)
|
|
1523
|
+
|
|
1524
|
+
def _test_ge(self, **options):
|
|
1525
|
+
r"""
|
|
1526
|
+
Check the correctness of the ``>=`` operator.
|
|
1527
|
+
|
|
1528
|
+
TESTS::
|
|
1529
|
+
|
|
1530
|
+
sage: v = QQ.valuation(5)
|
|
1531
|
+
sage: v._test_ge()
|
|
1532
|
+
"""
|
|
1533
|
+
tester = self._tester(**options)
|
|
1534
|
+
|
|
1535
|
+
tester.assertGreaterEqual(self, self)
|
|
1536
|
+
|
|
1537
|
+
if self.is_negative_pseudo_valuation():
|
|
1538
|
+
return
|
|
1539
|
+
|
|
1540
|
+
from .trivial_valuation import TrivialPseudoValuation, TrivialValuation
|
|
1541
|
+
tester.assertGreaterEqual(self, TrivialValuation(self.domain()))
|
|
1542
|
+
tester.assertLessEqual(self, TrivialPseudoValuation(self.domain()))
|
|
1543
|
+
|
|
1544
|
+
def _test_le(self, **options):
|
|
1545
|
+
r"""
|
|
1546
|
+
Check the correctness of the ``<=`` operator.
|
|
1547
|
+
|
|
1548
|
+
TESTS::
|
|
1549
|
+
|
|
1550
|
+
sage: v = QQ.valuation(5)
|
|
1551
|
+
sage: v._test_le()
|
|
1552
|
+
"""
|
|
1553
|
+
tester = self._tester(**options)
|
|
1554
|
+
|
|
1555
|
+
tester.assertGreaterEqual(self, self)
|
|
1556
|
+
|
|
1557
|
+
if self.is_negative_pseudo_valuation():
|
|
1558
|
+
return
|
|
1559
|
+
|
|
1560
|
+
from .trivial_valuation import TrivialPseudoValuation, TrivialValuation
|
|
1561
|
+
tester.assertLessEqual(TrivialValuation(self.domain()), self)
|
|
1562
|
+
tester.assertGreaterEqual(TrivialPseudoValuation(self.domain()), self)
|
|
1563
|
+
|
|
1564
|
+
def _test_inverse(self, **options):
|
|
1565
|
+
r"""
|
|
1566
|
+
Check the correctness of :meth:`inverse`.
|
|
1567
|
+
|
|
1568
|
+
TESTS::
|
|
1569
|
+
|
|
1570
|
+
sage: v = QQ.valuation(5)
|
|
1571
|
+
sage: v._test_inverse()
|
|
1572
|
+
"""
|
|
1573
|
+
tester = self._tester(**options)
|
|
1574
|
+
|
|
1575
|
+
for x in tester.some_elements(self.domain().some_elements()):
|
|
1576
|
+
from sage.rings.infinity import infinity
|
|
1577
|
+
for prec in (0, 1, 42, infinity):
|
|
1578
|
+
try:
|
|
1579
|
+
y = self.inverse(x, prec)
|
|
1580
|
+
except ArithmeticError: # Inverse does not exist
|
|
1581
|
+
continue
|
|
1582
|
+
except ValueError:
|
|
1583
|
+
if prec is not infinity:
|
|
1584
|
+
tester.assertNotEqual(self(x), 0)
|
|
1585
|
+
tester.assertFalse(x.is_unit())
|
|
1586
|
+
continue
|
|
1587
|
+
|
|
1588
|
+
tester.assertIs(y.parent(), self.domain())
|
|
1589
|
+
if self.domain().is_exact():
|
|
1590
|
+
tester.assertGreaterEqual(self(x * y - 1), prec)
|
|
1591
|
+
|
|
1592
|
+
|
|
1593
|
+
class ScaleAction(Action):
|
|
1594
|
+
r"""
|
|
1595
|
+
Action of integers, rationals and the infinity ring on valuations by
|
|
1596
|
+
scaling it.
|
|
1597
|
+
|
|
1598
|
+
EXAMPLES::
|
|
1599
|
+
|
|
1600
|
+
sage: v = QQ.valuation(5)
|
|
1601
|
+
sage: from operator import mul
|
|
1602
|
+
sage: v.parent().get_action(ZZ, mul, self_on_left=False)
|
|
1603
|
+
Left action by Integer Ring on Discrete pseudo-valuations on Rational Field
|
|
1604
|
+
"""
|
|
1605
|
+
def _act_(self, s, v):
|
|
1606
|
+
r"""
|
|
1607
|
+
Let ``s`` act on ``v``.
|
|
1608
|
+
|
|
1609
|
+
EXAMPLES::
|
|
1610
|
+
|
|
1611
|
+
sage: v = QQ.valuation(5)
|
|
1612
|
+
sage: 3 * v # indirect doctest
|
|
1613
|
+
3 * 5-adic valuation
|
|
1614
|
+
"""
|
|
1615
|
+
return v.scale(s)
|