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,1686 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
r"""
|
|
3
|
+
Inductive valuations on polynomial rings
|
|
4
|
+
|
|
5
|
+
This module provides functionality for inductive valuations, i.e., finite
|
|
6
|
+
chains of :mod:`augmented valuations <sage.rings.valuation.augmented_valuation>` on top of a :mod:`Gauss valuation <sage.rings.valuation.gauss_valuation>`.
|
|
7
|
+
|
|
8
|
+
AUTHORS:
|
|
9
|
+
|
|
10
|
+
- Julian Rüth (2016-11-01): initial version
|
|
11
|
+
|
|
12
|
+
EXAMPLES:
|
|
13
|
+
|
|
14
|
+
A :mod:`Gauss valuation <sage.rings.valuation.gauss_valuation>` is an example of an inductive valuation::
|
|
15
|
+
|
|
16
|
+
sage: R.<x> = QQ[]
|
|
17
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
18
|
+
|
|
19
|
+
Generally, an inductive valuation is an augmentation of an inductive valuation,
|
|
20
|
+
i.e., a valuation that was created from a Gauss valuation in a finite number of
|
|
21
|
+
augmentation steps::
|
|
22
|
+
|
|
23
|
+
sage: w = v.augmentation(x, 1)
|
|
24
|
+
sage: w = w.augmentation(x^2 + 2*x + 4, 3)
|
|
25
|
+
|
|
26
|
+
REFERENCES:
|
|
27
|
+
|
|
28
|
+
Inductive valuations are originally discussed in [Mac1936I]_ and [Mac1936II]_.
|
|
29
|
+
An introduction is also given in Chapter 4 of [Rüt2014]_.
|
|
30
|
+
"""
|
|
31
|
+
# ****************************************************************************
|
|
32
|
+
# Copyright (C) 2016-2018 Julian Rüth <julian.rueth@fsfe.org>
|
|
33
|
+
#
|
|
34
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
35
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
36
|
+
# the License, or (at your option) any later version.
|
|
37
|
+
# https://www.gnu.org/licenses/
|
|
38
|
+
# ****************************************************************************
|
|
39
|
+
|
|
40
|
+
from .valuation import DiscreteValuation, InfiniteDiscretePseudoValuation
|
|
41
|
+
from .developing_valuation import DevelopingValuation
|
|
42
|
+
|
|
43
|
+
from sage.misc.cachefunc import cached_method
|
|
44
|
+
from sage.misc.abstract_method import abstract_method
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class InductiveValuation(DevelopingValuation):
|
|
48
|
+
r"""
|
|
49
|
+
Abstract base class for iterated :mod:`augmented valuations <sage.rings.valuation.augmented_valuation>` on top of a :mod:`Gauss valuation <sage.rings.valuation.gauss_valuation>`.
|
|
50
|
+
|
|
51
|
+
EXAMPLES::
|
|
52
|
+
|
|
53
|
+
sage: R.<x> = QQ[]
|
|
54
|
+
sage: v = GaussValuation(R, QQ.valuation(5))
|
|
55
|
+
|
|
56
|
+
TESTS::
|
|
57
|
+
|
|
58
|
+
sage: TestSuite(v).run() # long time # needs sage.geometry.polyhedron
|
|
59
|
+
"""
|
|
60
|
+
def is_equivalence_unit(self, f, valuations=None):
|
|
61
|
+
r"""
|
|
62
|
+
Return whether the polynomial ``f`` is an equivalence unit, i.e., an
|
|
63
|
+
element of :meth:`~sage.rings.valuation.developing_valuation.DevelopingValuation.effective_degree`
|
|
64
|
+
zero (see [Mac1936II]_ p.497.)
|
|
65
|
+
|
|
66
|
+
INPUT:
|
|
67
|
+
|
|
68
|
+
- ``f`` -- a polynomial in the domain of this valuation
|
|
69
|
+
|
|
70
|
+
EXAMPLES::
|
|
71
|
+
|
|
72
|
+
sage: # needs sage.libs.ntl
|
|
73
|
+
sage: R = Zp(2,5)
|
|
74
|
+
sage: S.<x> = R[]
|
|
75
|
+
sage: v = GaussValuation(S)
|
|
76
|
+
sage: v.is_equivalence_unit(x)
|
|
77
|
+
False
|
|
78
|
+
sage: v.is_equivalence_unit(S.zero())
|
|
79
|
+
False
|
|
80
|
+
sage: v.is_equivalence_unit(2*x + 1)
|
|
81
|
+
True
|
|
82
|
+
"""
|
|
83
|
+
f = self.domain().coerce(f)
|
|
84
|
+
|
|
85
|
+
if f.is_zero():
|
|
86
|
+
return False
|
|
87
|
+
return self.effective_degree(f, valuations=valuations) == 0
|
|
88
|
+
|
|
89
|
+
def equivalence_reciprocal(self, f, coefficients=None, valuations=None, check=True):
|
|
90
|
+
r"""
|
|
91
|
+
Return an equivalence reciprocal of ``f``.
|
|
92
|
+
|
|
93
|
+
An equivalence reciprocal of `f` is a polynomial `h` such that `f\cdot
|
|
94
|
+
h` is equivalent to 1 modulo this valuation (see [Mac1936II]_ p.497.)
|
|
95
|
+
|
|
96
|
+
INPUT:
|
|
97
|
+
|
|
98
|
+
- ``f`` -- a polynomial in the domain of this valuation which is an
|
|
99
|
+
:meth:`equivalence_unit`
|
|
100
|
+
|
|
101
|
+
- ``coefficients`` -- the coefficients of ``f`` in the :meth:`~sage.rings.valuation.developing_valuation.DevelopingValuation.phi`-adic
|
|
102
|
+
expansion if known (default: ``None``)
|
|
103
|
+
|
|
104
|
+
- ``valuations`` -- the valuations of ``coefficients`` if known
|
|
105
|
+
(default: ``None``)
|
|
106
|
+
|
|
107
|
+
- ``check`` -- whether or not to check the validity of ``f`` (default:
|
|
108
|
+
``True``)
|
|
109
|
+
|
|
110
|
+
.. WARNING::
|
|
111
|
+
|
|
112
|
+
This method may not work over `p`-adic rings due to problems with
|
|
113
|
+
the xgcd implementation there.
|
|
114
|
+
|
|
115
|
+
EXAMPLES::
|
|
116
|
+
|
|
117
|
+
sage: # needs sage.libs.ntl
|
|
118
|
+
sage: R = Zp(3,5)
|
|
119
|
+
sage: S.<x> = R[]
|
|
120
|
+
sage: v = GaussValuation(S)
|
|
121
|
+
sage: f = 3*x + 2
|
|
122
|
+
sage: h = v.equivalence_reciprocal(f); h
|
|
123
|
+
2 + O(3^5)
|
|
124
|
+
sage: v.is_equivalent(f*h, 1)
|
|
125
|
+
True
|
|
126
|
+
|
|
127
|
+
In an extended valuation over an extension field::
|
|
128
|
+
|
|
129
|
+
sage: # needs sage.libs.ntl
|
|
130
|
+
sage: R.<u> = Qq(4,5)
|
|
131
|
+
sage: S.<x> = R[]
|
|
132
|
+
sage: v = GaussValuation(S)
|
|
133
|
+
sage: v = v.augmentation(x^2 + x + u, 1)
|
|
134
|
+
sage: f = 2*x + u
|
|
135
|
+
sage: h = v.equivalence_reciprocal(f); h
|
|
136
|
+
(u + 1) + O(2^5)
|
|
137
|
+
sage: v.is_equivalent(f*h, 1)
|
|
138
|
+
True
|
|
139
|
+
|
|
140
|
+
Extending the valuation once more::
|
|
141
|
+
|
|
142
|
+
sage: # needs sage.libs.ntl
|
|
143
|
+
sage: v = v.augmentation((x^2 + x + u)^2 + 2*x*(x^2 + x + u) + 4*x, 3)
|
|
144
|
+
sage: h = v.equivalence_reciprocal(f); h
|
|
145
|
+
(u + 1) + O(2^5)
|
|
146
|
+
sage: v.is_equivalent(f*h, 1)
|
|
147
|
+
True
|
|
148
|
+
|
|
149
|
+
TESTS:
|
|
150
|
+
|
|
151
|
+
A case that caused problems at some point::
|
|
152
|
+
|
|
153
|
+
sage: # needs sage.libs.ntl
|
|
154
|
+
sage: K = Qp(2, 4)
|
|
155
|
+
sage: R.<x> = K[]
|
|
156
|
+
sage: L.<a> = K.extension(x^4 + 4*x^3 + 6*x^2 + 4*x + 2)
|
|
157
|
+
sage: R.<t> = L[]
|
|
158
|
+
sage: v = GaussValuation(R)
|
|
159
|
+
sage: w = v.augmentation(t + 1, 5/16)
|
|
160
|
+
sage: w = w.augmentation(t^4 + (a^8 + a^12 + a^14 + a^16 + a^17 + a^19 + a^20 + a^23)*t^3 + (a^6 + a^9 + a^13 + a^15 + a^18 + a^19 + a^21)*t^2 + a^10*t + 1 + a^4 + a^5 + a^8 + a^13 + a^14 + a^15, 17/8)
|
|
161
|
+
sage: f = a^-15*t^2 + (a^-11 + a^-9 + a^-6 + a^-5 + a^-3 + a^-2)*t + a^-15
|
|
162
|
+
sage: f_ = w.equivalence_reciprocal(f)
|
|
163
|
+
sage: w.reduce(f*f_)
|
|
164
|
+
1
|
|
165
|
+
sage: f = f.parent()([f[0], f[1].add_bigoh(1), f[2]])
|
|
166
|
+
sage: f_ = w.equivalence_reciprocal(f)
|
|
167
|
+
sage: w.reduce(f*f_)
|
|
168
|
+
1
|
|
169
|
+
"""
|
|
170
|
+
f = self.domain().coerce(f)
|
|
171
|
+
|
|
172
|
+
if check:
|
|
173
|
+
if coefficients is None:
|
|
174
|
+
coefficients = list(self.coefficients(f))
|
|
175
|
+
if valuations is None:
|
|
176
|
+
valuations = list(self.valuations(f, coefficients=coefficients))
|
|
177
|
+
if not self.is_equivalence_unit(f, valuations=valuations):
|
|
178
|
+
raise ValueError("f must be an equivalence unit but %r is not" % (f,))
|
|
179
|
+
|
|
180
|
+
if coefficients is None:
|
|
181
|
+
e0 = next(self.coefficients(f))
|
|
182
|
+
else:
|
|
183
|
+
e0 = coefficients[0]
|
|
184
|
+
|
|
185
|
+
# f is an equivalence unit, its valuation is given by the constant coefficient
|
|
186
|
+
if valuations is None:
|
|
187
|
+
vf = self(e0)
|
|
188
|
+
else:
|
|
189
|
+
vf = valuations[0]
|
|
190
|
+
|
|
191
|
+
e0 = self.simplify(e0, error=vf)
|
|
192
|
+
s_ = self.equivalence_unit(-vf)
|
|
193
|
+
residue = self.reduce(e0 * s_)
|
|
194
|
+
if not isinstance(self, FinalInductiveValuation):
|
|
195
|
+
assert residue.is_constant()
|
|
196
|
+
residue = residue[0]
|
|
197
|
+
h = self.lift(~residue) * s_
|
|
198
|
+
|
|
199
|
+
h = self.simplify(h, -vf)
|
|
200
|
+
|
|
201
|
+
# it might be the case that f*h has nonzero valuation because h has
|
|
202
|
+
# insufficient precision, so we must not assert that here but only
|
|
203
|
+
# until we lifted to higher precision
|
|
204
|
+
|
|
205
|
+
# We do not actually need g*phi + h*e0 = 1, it is only important that
|
|
206
|
+
# the RHS is 1 in reduction.
|
|
207
|
+
# This allows us to do two things:
|
|
208
|
+
# - we may lift h to arbitrary precision
|
|
209
|
+
# - we can add anything which times e0 has positive valuation, e.g., we
|
|
210
|
+
# may drop coefficients of positive valuation
|
|
211
|
+
return h.map_coefficients(_lift_to_maximal_precision)
|
|
212
|
+
|
|
213
|
+
@cached_method
|
|
214
|
+
def mu(self):
|
|
215
|
+
r"""
|
|
216
|
+
Return the valuation of :meth:`~sage.rings.valuation.developing_valuation.DevelopingValuation.phi`.
|
|
217
|
+
|
|
218
|
+
EXAMPLES::
|
|
219
|
+
|
|
220
|
+
sage: R.<x> = QQ[]
|
|
221
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
222
|
+
sage: v.mu()
|
|
223
|
+
0
|
|
224
|
+
"""
|
|
225
|
+
return self(self.phi())
|
|
226
|
+
|
|
227
|
+
@abstract_method
|
|
228
|
+
def equivalence_unit(self, s, reciprocal=False):
|
|
229
|
+
"""
|
|
230
|
+
Return an equivalence unit of valuation ``s``.
|
|
231
|
+
|
|
232
|
+
INPUT:
|
|
233
|
+
|
|
234
|
+
- ``s`` -- an element of the :meth:`~sage.rings.valuation.valuation_space.DiscretePseudoValuationSpace.ElementMethods.value_group`
|
|
235
|
+
|
|
236
|
+
- ``reciprocal`` -- boolean (default: ``False``); whether or not to
|
|
237
|
+
return the equivalence unit as the :meth:`equivalence_reciprocal` of
|
|
238
|
+
the equivalence unit of valuation ``-s``.
|
|
239
|
+
|
|
240
|
+
EXAMPLES::
|
|
241
|
+
|
|
242
|
+
sage: # needs sage.libs.ntl
|
|
243
|
+
sage: S.<x> = Qp(3,5)[]
|
|
244
|
+
sage: v = GaussValuation(S)
|
|
245
|
+
sage: v.equivalence_unit(2)
|
|
246
|
+
3^2 + O(3^7)
|
|
247
|
+
sage: v.equivalence_unit(-2)
|
|
248
|
+
3^-2 + O(3^3)
|
|
249
|
+
|
|
250
|
+
Note that this might fail for negative ``s`` if the domain is not
|
|
251
|
+
defined over a field::
|
|
252
|
+
|
|
253
|
+
sage: v = ZZ.valuation(2)
|
|
254
|
+
sage: R.<x> = ZZ[]
|
|
255
|
+
sage: w = GaussValuation(R, v)
|
|
256
|
+
sage: w.equivalence_unit(1)
|
|
257
|
+
2
|
|
258
|
+
sage: w.equivalence_unit(-1)
|
|
259
|
+
Traceback (most recent call last):
|
|
260
|
+
...
|
|
261
|
+
ValueError: s must be in the value semigroup of this valuation
|
|
262
|
+
but -1 is not in Additive Abelian Semigroup generated by 1
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
@abstract_method
|
|
266
|
+
def augmentation_chain(self):
|
|
267
|
+
r"""
|
|
268
|
+
Return a list with the chain of augmentations down to the underlying
|
|
269
|
+
:mod:`Gauss valuation <sage.rings.valuation.gauss_valuation>`.
|
|
270
|
+
|
|
271
|
+
EXAMPLES::
|
|
272
|
+
|
|
273
|
+
sage: # needs sage.libs.ntl
|
|
274
|
+
sage: R.<u> = Qq(4,5)
|
|
275
|
+
sage: S.<x> = R[]
|
|
276
|
+
sage: v = GaussValuation(S)
|
|
277
|
+
sage: v.augmentation_chain()
|
|
278
|
+
[Gauss valuation induced by 2-adic valuation]
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
@abstract_method
|
|
282
|
+
def is_gauss_valuation(self):
|
|
283
|
+
r"""
|
|
284
|
+
Return whether this valuation is a Gauss valuation over the domain.
|
|
285
|
+
|
|
286
|
+
EXAMPLES::
|
|
287
|
+
|
|
288
|
+
sage: # needs sage.libs.ntl
|
|
289
|
+
sage: R.<u> = Qq(4,5)
|
|
290
|
+
sage: S.<x> = R[]
|
|
291
|
+
sage: v = GaussValuation(S)
|
|
292
|
+
sage: v.is_gauss_valuation()
|
|
293
|
+
True
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
@abstract_method
|
|
297
|
+
def E(self):
|
|
298
|
+
"""
|
|
299
|
+
Return the ramification index of this valuation over its underlying
|
|
300
|
+
Gauss valuation.
|
|
301
|
+
|
|
302
|
+
EXAMPLES::
|
|
303
|
+
|
|
304
|
+
sage: # needs sage.libs.ntl
|
|
305
|
+
sage: R.<u> = Qq(4,5)
|
|
306
|
+
sage: S.<x> = R[]
|
|
307
|
+
sage: v = GaussValuation(S)
|
|
308
|
+
sage: v.E()
|
|
309
|
+
1
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
@abstract_method
|
|
313
|
+
def F(self):
|
|
314
|
+
"""
|
|
315
|
+
Return the residual degree of this valuation over its Gauss extension.
|
|
316
|
+
|
|
317
|
+
EXAMPLES::
|
|
318
|
+
|
|
319
|
+
sage: # needs sage.libs.ntl
|
|
320
|
+
sage: R.<u> = Qq(4,5)
|
|
321
|
+
sage: S.<x> = R[]
|
|
322
|
+
sage: v = GaussValuation(S)
|
|
323
|
+
sage: v.F()
|
|
324
|
+
1
|
|
325
|
+
"""
|
|
326
|
+
|
|
327
|
+
@abstract_method
|
|
328
|
+
def monic_integral_model(self, G):
|
|
329
|
+
r"""
|
|
330
|
+
Return a monic integral irreducible polynomial which defines the same
|
|
331
|
+
extension of the base ring of the domain as the irreducible polynomial
|
|
332
|
+
``G`` together with maps between the old and the new polynomial.
|
|
333
|
+
|
|
334
|
+
EXAMPLES::
|
|
335
|
+
|
|
336
|
+
sage: R.<x> = QQ[]
|
|
337
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
338
|
+
sage: v.monic_integral_model(5*x^2 + 1/2*x + 1/4)
|
|
339
|
+
(Ring endomorphism of Univariate Polynomial Ring in x over Rational Field
|
|
340
|
+
Defn: x |--> 1/2*x,
|
|
341
|
+
Ring endomorphism of Univariate Polynomial Ring in x over Rational Field
|
|
342
|
+
Defn: x |--> 2*x,
|
|
343
|
+
x^2 + 1/5*x + 1/5)
|
|
344
|
+
"""
|
|
345
|
+
|
|
346
|
+
@abstract_method
|
|
347
|
+
def element_with_valuation(self, s):
|
|
348
|
+
r"""
|
|
349
|
+
Return a polynomial of minimal degree with valuation ``s``.
|
|
350
|
+
|
|
351
|
+
EXAMPLES::
|
|
352
|
+
|
|
353
|
+
sage: R.<x> = QQ[]
|
|
354
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
355
|
+
sage: v.element_with_valuation(-2)
|
|
356
|
+
1/4
|
|
357
|
+
|
|
358
|
+
Depending on the base ring, an element of valuation ``s`` might not
|
|
359
|
+
exist::
|
|
360
|
+
|
|
361
|
+
sage: R.<x> = ZZ[]
|
|
362
|
+
sage: v = GaussValuation(R, ZZ.valuation(2))
|
|
363
|
+
sage: v.element_with_valuation(-2)
|
|
364
|
+
Traceback (most recent call last):
|
|
365
|
+
...
|
|
366
|
+
ValueError: s must be in the value semigroup of this valuation
|
|
367
|
+
but -2 is not in Additive Abelian Semigroup generated by 1
|
|
368
|
+
"""
|
|
369
|
+
|
|
370
|
+
def _test_element_with_valuation_inductive_valuation(self, **options):
|
|
371
|
+
r"""
|
|
372
|
+
Test the correctness of :meth:`element_with_valuation`.
|
|
373
|
+
|
|
374
|
+
EXAMPLES::
|
|
375
|
+
|
|
376
|
+
sage: R.<x> = QQ[]
|
|
377
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
378
|
+
sage: v._test_element_with_valuation_inductive_valuation()
|
|
379
|
+
"""
|
|
380
|
+
tester = self._tester(**options)
|
|
381
|
+
chain = self.augmentation_chain()
|
|
382
|
+
for s in tester.some_elements(self.value_group().some_elements()):
|
|
383
|
+
try:
|
|
384
|
+
R = self.element_with_valuation(s)
|
|
385
|
+
except (ValueError, NotImplementedError):
|
|
386
|
+
# this is often not possible unless the underlying ring of
|
|
387
|
+
# constants is a field
|
|
388
|
+
from sage.categories.fields import Fields
|
|
389
|
+
if self.domain().base() not in Fields():
|
|
390
|
+
continue
|
|
391
|
+
raise
|
|
392
|
+
tester.assertEqual(self(R), s)
|
|
393
|
+
if chain != [self]:
|
|
394
|
+
base = chain[1]
|
|
395
|
+
if s in base.value_group():
|
|
396
|
+
S = base.element_with_valuation(s)
|
|
397
|
+
tester.assertEqual(self(S), s)
|
|
398
|
+
tester.assertGreaterEqual(S.degree(), R.degree())
|
|
399
|
+
|
|
400
|
+
def _test_EF(self, **options):
|
|
401
|
+
r"""
|
|
402
|
+
Test the correctness of :meth:`E` and :meth:`F`.
|
|
403
|
+
|
|
404
|
+
EXAMPLES::
|
|
405
|
+
|
|
406
|
+
sage: # needs sage.libs.ntl
|
|
407
|
+
sage: R.<u> = Qq(4,5)
|
|
408
|
+
sage: S.<x> = R[]
|
|
409
|
+
sage: v = GaussValuation(S)
|
|
410
|
+
sage: v._test_EF()
|
|
411
|
+
"""
|
|
412
|
+
tester = self._tester(**options)
|
|
413
|
+
chain = self.augmentation_chain()
|
|
414
|
+
for w, v in zip(chain, chain[1:]):
|
|
415
|
+
from sage.rings.infinity import infinity
|
|
416
|
+
from sage.rings.integer_ring import ZZ
|
|
417
|
+
if w(w.phi()) is infinity:
|
|
418
|
+
tester.assertEqual(w.E(), v.E())
|
|
419
|
+
tester.assertIn(w.E(), ZZ)
|
|
420
|
+
tester.assertIn(w.F(), ZZ)
|
|
421
|
+
tester.assertGreaterEqual(w.E(), v.E())
|
|
422
|
+
tester.assertGreaterEqual(w.F(), v.F())
|
|
423
|
+
|
|
424
|
+
def _test_augmentation_chain(self, **options):
|
|
425
|
+
r"""
|
|
426
|
+
Test the correctness of :meth:`augmentation_chain`.
|
|
427
|
+
|
|
428
|
+
EXAMPLES::
|
|
429
|
+
|
|
430
|
+
sage: R.<x> = QQ[]
|
|
431
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
432
|
+
sage: v._test_augmentation_chain()
|
|
433
|
+
"""
|
|
434
|
+
tester = self._tester(**options)
|
|
435
|
+
chain = self.augmentation_chain()
|
|
436
|
+
tester.assertIs(chain[0], self)
|
|
437
|
+
tester.assertTrue(chain[-1].is_gauss_valuation())
|
|
438
|
+
for w, v in zip(chain, chain[1:]):
|
|
439
|
+
tester.assertGreaterEqual(w, v)
|
|
440
|
+
|
|
441
|
+
def _test_equivalence_unit(self, **options):
|
|
442
|
+
r"""
|
|
443
|
+
Test the correctness of :meth:`lift_to_key`.
|
|
444
|
+
|
|
445
|
+
EXAMPLES::
|
|
446
|
+
|
|
447
|
+
sage: R.<x> = QQ[]
|
|
448
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
449
|
+
sage: v._test_equivalence_unit()
|
|
450
|
+
"""
|
|
451
|
+
tester = self._tester(**options)
|
|
452
|
+
|
|
453
|
+
if self.is_gauss_valuation():
|
|
454
|
+
value_group = self.value_group()
|
|
455
|
+
else:
|
|
456
|
+
value_group = self.augmentation_chain()[1].value_group()
|
|
457
|
+
|
|
458
|
+
for s in tester.some_elements(value_group.some_elements()):
|
|
459
|
+
try:
|
|
460
|
+
R = self.equivalence_unit(s)
|
|
461
|
+
except (ValueError, NotImplementedError):
|
|
462
|
+
# this is often not possible unless the underlying ring of
|
|
463
|
+
# constants is a field
|
|
464
|
+
from sage.categories.fields import Fields
|
|
465
|
+
if self.domain().base() not in Fields():
|
|
466
|
+
continue
|
|
467
|
+
raise
|
|
468
|
+
tester.assertIs(R.parent(), self.domain())
|
|
469
|
+
tester.assertEqual(self(R), s)
|
|
470
|
+
tester.assertTrue(self.is_equivalence_unit(R))
|
|
471
|
+
|
|
472
|
+
def _test_is_equivalence_unit(self, **options):
|
|
473
|
+
r"""
|
|
474
|
+
Test the correctness of :meth:`is_equivalence_unit`.
|
|
475
|
+
|
|
476
|
+
EXAMPLES::
|
|
477
|
+
|
|
478
|
+
sage: R.<x> = QQ[]
|
|
479
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
480
|
+
sage: v._test_is_equivalence_unit()
|
|
481
|
+
"""
|
|
482
|
+
tester = self._tester(**options)
|
|
483
|
+
tester.assertFalse(self.is_equivalence_unit(self.phi()))
|
|
484
|
+
|
|
485
|
+
def _test_equivalence_reciprocal(self, **options):
|
|
486
|
+
r"""
|
|
487
|
+
Test the correctness of :meth:`equivalence_reciprocal`.
|
|
488
|
+
|
|
489
|
+
EXAMPLES::
|
|
490
|
+
|
|
491
|
+
sage: R.<x> = QQ[]
|
|
492
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
493
|
+
sage: v._test_equivalence_reciprocal()
|
|
494
|
+
"""
|
|
495
|
+
tester = self._tester(**options)
|
|
496
|
+
S = tester.some_elements(self.domain().some_elements())
|
|
497
|
+
for f in S:
|
|
498
|
+
if self.is_equivalence_unit(f):
|
|
499
|
+
try:
|
|
500
|
+
g = self.equivalence_reciprocal(f)
|
|
501
|
+
except (ValueError, NotImplementedError):
|
|
502
|
+
# this is often not possible unless the underlying ring of
|
|
503
|
+
# constants is a field
|
|
504
|
+
from sage.categories.fields import Fields
|
|
505
|
+
if self.domain().base() not in Fields():
|
|
506
|
+
continue
|
|
507
|
+
raise
|
|
508
|
+
tester.assertEqual(self.reduce(f * g), 1)
|
|
509
|
+
|
|
510
|
+
def _test_inductive_valuation_inheritance(self, **options):
|
|
511
|
+
r"""
|
|
512
|
+
Test that every instance that is a :class:`InductiveValuation` is
|
|
513
|
+
either a :class:`FiniteInductiveValuation` or a
|
|
514
|
+
:class:`InfiniteInductiveValuation`. Same for
|
|
515
|
+
:class:`FinalInductiveValuation` and
|
|
516
|
+
:class:`NonFinalInductiveValuation`.
|
|
517
|
+
|
|
518
|
+
EXAMPLES::
|
|
519
|
+
|
|
520
|
+
sage: R.<x> = QQ[]
|
|
521
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
522
|
+
sage: v._test_inductive_valuation_inheritance()
|
|
523
|
+
"""
|
|
524
|
+
tester = self._tester(**options)
|
|
525
|
+
tester.assertNotEqual(isinstance(self, InfiniteInductiveValuation),
|
|
526
|
+
isinstance(self, FiniteInductiveValuation))
|
|
527
|
+
tester.assertNotEqual(isinstance(self, FinalInductiveValuation),
|
|
528
|
+
isinstance(self, NonFinalInductiveValuation))
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
class FiniteInductiveValuation(InductiveValuation, DiscreteValuation):
|
|
532
|
+
r"""
|
|
533
|
+
Abstract base class for iterated :mod:`augmented valuations <sage.rings.valuation.augmented_valuation>`
|
|
534
|
+
on top of a :mod:`Gauss valuation <sage.rings.valuation.gauss_valuation>` which is a discrete valuation,
|
|
535
|
+
i.e., the last key polynomial has finite valuation.
|
|
536
|
+
|
|
537
|
+
EXAMPLES::
|
|
538
|
+
|
|
539
|
+
sage: R.<x> = QQ[]
|
|
540
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
541
|
+
"""
|
|
542
|
+
def __init__(self, parent, phi):
|
|
543
|
+
r"""
|
|
544
|
+
TESTS::
|
|
545
|
+
|
|
546
|
+
sage: R.<x> = QQ[]
|
|
547
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
548
|
+
sage: from sage.rings.valuation.inductive_valuation import FiniteInductiveValuation
|
|
549
|
+
sage: isinstance(v, FiniteInductiveValuation)
|
|
550
|
+
True
|
|
551
|
+
"""
|
|
552
|
+
InductiveValuation.__init__(self, parent, phi)
|
|
553
|
+
DiscreteValuation.__init__(self, parent)
|
|
554
|
+
|
|
555
|
+
def extensions(self, other):
|
|
556
|
+
r"""
|
|
557
|
+
Return the extensions of this valuation to ``other``.
|
|
558
|
+
|
|
559
|
+
EXAMPLES::
|
|
560
|
+
|
|
561
|
+
sage: R.<x> = ZZ[]
|
|
562
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(ZZ))
|
|
563
|
+
sage: K.<x> = FunctionField(QQ)
|
|
564
|
+
sage: v.extensions(K)
|
|
565
|
+
[Trivial valuation on Rational Field]
|
|
566
|
+
"""
|
|
567
|
+
from sage.categories.function_fields import FunctionFields
|
|
568
|
+
if other in FunctionFields() and other.ngens() == 1:
|
|
569
|
+
# extend to K[x] and from there to K(x)
|
|
570
|
+
v = self.extension(self.domain().change_ring(self.domain().base().fraction_field()))
|
|
571
|
+
return [other.valuation(v)]
|
|
572
|
+
return super().extensions(other)
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
class NonFinalInductiveValuation(FiniteInductiveValuation, DiscreteValuation):
|
|
576
|
+
r"""
|
|
577
|
+
Abstract base class for iterated :mod:`augmented valuations <sage.rings.valuation.augmented_valuation>`
|
|
578
|
+
on top of a :mod:`Gauss valuation <sage.rings.valuation.gauss_valuation>` which can be extended further
|
|
579
|
+
through :meth:`augmentation`.
|
|
580
|
+
|
|
581
|
+
EXAMPLES::
|
|
582
|
+
|
|
583
|
+
sage: # needs sage.libs.ntl
|
|
584
|
+
sage: R.<u> = Qq(4,5)
|
|
585
|
+
sage: S.<x> = R[]
|
|
586
|
+
sage: v = GaussValuation(S)
|
|
587
|
+
sage: v = v.augmentation(x^2 + x + u, 1)
|
|
588
|
+
"""
|
|
589
|
+
def __init__(self, parent, phi):
|
|
590
|
+
r"""
|
|
591
|
+
TESTS::
|
|
592
|
+
|
|
593
|
+
sage: # needs sage.libs.ntl
|
|
594
|
+
sage: R.<u> = Qq(4,5)
|
|
595
|
+
sage: S.<x> = R[]
|
|
596
|
+
sage: v = GaussValuation(S)
|
|
597
|
+
sage: v = v.augmentation(x^2 + x + u, 1)
|
|
598
|
+
sage: from sage.rings.valuation.inductive_valuation import NonFinalInductiveValuation
|
|
599
|
+
sage: isinstance(v, NonFinalInductiveValuation)
|
|
600
|
+
True
|
|
601
|
+
"""
|
|
602
|
+
FiniteInductiveValuation.__init__(self, parent, phi)
|
|
603
|
+
DiscreteValuation.__init__(self, parent)
|
|
604
|
+
|
|
605
|
+
def augmentation(self, phi, mu, check=True):
|
|
606
|
+
r"""
|
|
607
|
+
Return the inductive valuation which extends this valuation by mapping
|
|
608
|
+
``phi`` to ``mu``.
|
|
609
|
+
|
|
610
|
+
INPUT:
|
|
611
|
+
|
|
612
|
+
- ``phi`` -- a polynomial in the domain of this valuation; this must be
|
|
613
|
+
a key polynomial, see :meth:`is_key` for properties of key
|
|
614
|
+
polynomials.
|
|
615
|
+
|
|
616
|
+
- ``mu`` -- a rational number or infinity, the valuation of ``phi`` in
|
|
617
|
+
the extended valuation
|
|
618
|
+
|
|
619
|
+
- ``check`` -- boolean (default: ``True``); whether or not to check
|
|
620
|
+
the correctness of the parameters
|
|
621
|
+
|
|
622
|
+
EXAMPLES::
|
|
623
|
+
|
|
624
|
+
sage: # needs sage.libs.ntl
|
|
625
|
+
sage: R.<u> = Qq(4,5)
|
|
626
|
+
sage: S.<x> = R[]
|
|
627
|
+
sage: v = GaussValuation(S)
|
|
628
|
+
sage: v = v.augmentation(x^2 + x + u, 1)
|
|
629
|
+
sage: v = v.augmentation((x^2 + x + u)^2 + 2*x*(x^2 + x + u) + 4*x, 3)
|
|
630
|
+
sage: v
|
|
631
|
+
[ Gauss valuation induced by 2-adic valuation,
|
|
632
|
+
v((1 + O(2^5))*x^2 + (1 + O(2^5))*x + u + O(2^5)) = 1,
|
|
633
|
+
v((1 + O(2^5))*x^4
|
|
634
|
+
+ (2^2 + O(2^6))*x^3
|
|
635
|
+
+ (1 + (u + 1)*2 + O(2^5))*x^2
|
|
636
|
+
+ ((u + 1)*2^2 + O(2^6))*x
|
|
637
|
+
+ (u + 1) + (u + 1)*2 + (u + 1)*2^2 + (u + 1)*2^3 + (u + 1)*2^4 + O(2^5)) = 3 ]
|
|
638
|
+
|
|
639
|
+
TESTS:
|
|
640
|
+
|
|
641
|
+
Make sure that we do not make the assumption that the degrees of the
|
|
642
|
+
key polynomials are strictly increasing::
|
|
643
|
+
|
|
644
|
+
sage: v_K = QQ.valuation(3)
|
|
645
|
+
sage: A.<t> = QQ[]
|
|
646
|
+
sage: v0 = GaussValuation(A,v_K)
|
|
647
|
+
|
|
648
|
+
sage: v1 = v0.augmentation(t, 1/12)
|
|
649
|
+
sage: v2 = v1.augmentation(t^12 + 3, 7/6)
|
|
650
|
+
sage: v3 = v2.augmentation(t^12 + 3*t^2 + 3, 9/4)
|
|
651
|
+
sage: v4 = v1.augmentation(t^12 + 3*t^2 + 3, 9/4)
|
|
652
|
+
sage: v3 <= v4 and v3 >= v4
|
|
653
|
+
True
|
|
654
|
+
|
|
655
|
+
.. SEEALSO::
|
|
656
|
+
|
|
657
|
+
:mod:`~sage.rings.valuation.augmented_valuation`
|
|
658
|
+
"""
|
|
659
|
+
from .augmented_valuation import AugmentedValuation
|
|
660
|
+
return AugmentedValuation(self, phi, mu, check)
|
|
661
|
+
|
|
662
|
+
def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, assume_equivalence_irreducible=False, report_degree_bounds_and_caches=False, coefficients=None, valuations=None, check=True, allow_equivalent_key=True):
|
|
663
|
+
r"""
|
|
664
|
+
Perform an approximation step towards the squarefree monic non-constant
|
|
665
|
+
integral polynomial ``G`` which is not an :meth:`equivalence unit <InductiveValuation.is_equivalence_unit>`.
|
|
666
|
+
|
|
667
|
+
This performs the individual steps that are used in
|
|
668
|
+
:meth:`~sage.rings.valuation.valuation.DiscreteValuation.mac_lane_approximants`.
|
|
669
|
+
|
|
670
|
+
INPUT:
|
|
671
|
+
|
|
672
|
+
- ``G`` -- a squarefree monic non-constant integral polynomial ``G``
|
|
673
|
+
which is not an :meth:`equivalence unit <InductiveValuation.is_equivalence_unit>`
|
|
674
|
+
|
|
675
|
+
- ``principal_part_bound`` -- integer or ``None`` (default:
|
|
676
|
+
``None``), a bound on the length of the principal part, i.e., the
|
|
677
|
+
section of negative slope, of the Newton polygon of ``G``
|
|
678
|
+
|
|
679
|
+
- ``assume_squarefree`` -- whether or not to assume that ``G`` is
|
|
680
|
+
squarefree (default: ``False``)
|
|
681
|
+
|
|
682
|
+
- ``assume_equivalence_irreducible`` -- whether or not to assume that
|
|
683
|
+
``G`` is equivalence irreducible (default: ``False``)
|
|
684
|
+
|
|
685
|
+
- ``report_degree_bounds_and_caches`` -- whether or not to include internal state with the returned value (used by :meth:`~sage.rings.valuation.valuation.DiscreteValuation.mac_lane_approximants` to speed up sequential calls)
|
|
686
|
+
|
|
687
|
+
- ``coefficients`` -- the coefficients of ``G`` in the :meth:`~sage.rings.valuation.developing_valuation.DevelopingValuation.phi`-adic expansion if known (default: ``None``)
|
|
688
|
+
|
|
689
|
+
- ``valuations`` -- the valuations of ``coefficients`` if known
|
|
690
|
+
(default: ``None``)
|
|
691
|
+
|
|
692
|
+
- ``check`` -- whether to check that ``G`` is a squarefree monic
|
|
693
|
+
non-constant integral polynomial and not an :meth:`equivalence unit <InductiveValuation.is_equivalence_unit>`
|
|
694
|
+
(default: ``True``)
|
|
695
|
+
|
|
696
|
+
- ``allow_equivalent_key`` -- whether to return valuations which end in
|
|
697
|
+
essentially the same key polynomial as this valuation but have a
|
|
698
|
+
higher valuation assigned to that key polynomial (default: ``True``)
|
|
699
|
+
|
|
700
|
+
EXAMPLES:
|
|
701
|
+
|
|
702
|
+
We can use this method to perform the individual steps of
|
|
703
|
+
:meth:`~sage.rings.valuation.valuation.DiscreteValuation.mac_lane_approximants`::
|
|
704
|
+
|
|
705
|
+
sage: R.<x> = QQ[]
|
|
706
|
+
sage: v = QQ.valuation(2)
|
|
707
|
+
sage: f = x^36 + 1160/81*x^31 + 9920/27*x^30 + 1040/81*x^26 + 52480/81*x^25 + 220160/81*x^24 - 5120/81*x^21 - 143360/81*x^20 - 573440/81*x^19 + 12451840/81*x^18 - 266240/567*x^16 - 20316160/567*x^15 - 198737920/189*x^14 - 1129840640/81*x^13 - 1907359744/27*x^12 + 8192/81*x^11 + 655360/81*x^10 + 5242880/21*x^9 + 2118123520/567*x^8 + 15460204544/567*x^7 + 6509559808/81*x^6 - 16777216/567*x^2 - 268435456/567*x - 1073741824/567
|
|
708
|
+
sage: v.mac_lane_approximants(f) # needs sage.geometry.polyhedron
|
|
709
|
+
[[ Gauss valuation induced by 2-adic valuation, v(x + 2056) = 23/2 ],
|
|
710
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 11/9 ],
|
|
711
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 2/5, v(x^5 + 4) = 7/2 ],
|
|
712
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 3/5, v(x^10 + 8*x^5 + 64) = 7 ],
|
|
713
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 3/5, v(x^5 + 8) = 5 ]]
|
|
714
|
+
|
|
715
|
+
Starting from the Gauss valuation, a MacLane step branches off with
|
|
716
|
+
some linear key polynomials in the above example::
|
|
717
|
+
|
|
718
|
+
sage: v0 = GaussValuation(R, v)
|
|
719
|
+
sage: V1 = sorted(v0.mac_lane_step(f)); V1 # needs sage.geometry.polyhedron
|
|
720
|
+
[[ Gauss valuation induced by 2-adic valuation, v(x) = 2/5 ],
|
|
721
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 3/5 ],
|
|
722
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 11/9 ],
|
|
723
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 3 ]]
|
|
724
|
+
|
|
725
|
+
The computation of MacLane approximants would now perform a MacLane
|
|
726
|
+
step on each of these branches, note however, that a direct call to
|
|
727
|
+
this method might produce some unexpected results::
|
|
728
|
+
|
|
729
|
+
sage: V1[1].mac_lane_step(f) # needs sage.geometry.polyhedron
|
|
730
|
+
[[ Gauss valuation induced by 2-adic valuation, v(x) = 3/5, v(x^5 + 8) = 5 ],
|
|
731
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 3/5, v(x^10 + 8*x^5 + 64) = 7 ],
|
|
732
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 3 ],
|
|
733
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 11/9 ]]
|
|
734
|
+
|
|
735
|
+
Note how this detected the two augmentations of ``V1[1]`` but also two
|
|
736
|
+
other valuations that we had seen in the previous step and that are
|
|
737
|
+
greater than ``V1[1]``. To ignore such trivial augmentations, we can
|
|
738
|
+
set ``allow_equivalent_key``::
|
|
739
|
+
|
|
740
|
+
sage: V1[1].mac_lane_step(f, allow_equivalent_key=False) # needs sage.geometry.polyhedron
|
|
741
|
+
[[ Gauss valuation induced by 2-adic valuation, v(x) = 3/5, v(x^5 + 8) = 5 ],
|
|
742
|
+
[ Gauss valuation induced by 2-adic valuation, v(x) = 3/5, v(x^10 + 8*x^5 + 64) = 7 ]]
|
|
743
|
+
|
|
744
|
+
TESTS::
|
|
745
|
+
|
|
746
|
+
sage: K.<x> = FunctionField(QQ)
|
|
747
|
+
sage: S.<y> = K[]
|
|
748
|
+
sage: F = y^2 - x^2 - x^3 - 3
|
|
749
|
+
sage: v0 = GaussValuation(K._ring, QQ.valuation(3))
|
|
750
|
+
sage: v1 = v0.augmentation(K._ring.gen(), 1/3)
|
|
751
|
+
sage: mu0 = K.valuation(v1)
|
|
752
|
+
sage: eta0 = GaussValuation(S, mu0)
|
|
753
|
+
sage: eta1 = eta0.mac_lane_step(F)[0] # needs sage.geometry.polyhedron
|
|
754
|
+
sage: eta2 = eta1.mac_lane_step(F)[0] # needs sage.geometry.polyhedron
|
|
755
|
+
sage: eta2 # needs sage.geometry.polyhedron
|
|
756
|
+
[ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by 3-adic valuation, v(x) = 1/3 ], v(y + x) = 2/3 ]
|
|
757
|
+
|
|
758
|
+
Check that :issue:`26066` has been resolved::
|
|
759
|
+
|
|
760
|
+
sage: R.<x> = QQ[]
|
|
761
|
+
sage: v = QQ.valuation(2)
|
|
762
|
+
sage: v = GaussValuation(R, v).augmentation(x+1, 1/2)
|
|
763
|
+
sage: f = x^4 - 30*x^2 - 75
|
|
764
|
+
sage: v.mac_lane_step(f) # needs sage.geometry.polyhedron
|
|
765
|
+
[[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 3/4 ]]
|
|
766
|
+
"""
|
|
767
|
+
G = self.domain().coerce(G)
|
|
768
|
+
|
|
769
|
+
if G.is_constant():
|
|
770
|
+
raise ValueError("G must not be constant")
|
|
771
|
+
|
|
772
|
+
from itertools import islice
|
|
773
|
+
from sage.misc.verbose import verbose
|
|
774
|
+
verbose("Augmenting %s towards %s" % (self, G), level=10)
|
|
775
|
+
|
|
776
|
+
if not G.is_monic():
|
|
777
|
+
raise ValueError("G must be monic")
|
|
778
|
+
|
|
779
|
+
if coefficients is None:
|
|
780
|
+
coefficients = self.coefficients(G)
|
|
781
|
+
if principal_part_bound:
|
|
782
|
+
coefficients = islice(coefficients, 0,
|
|
783
|
+
int(principal_part_bound) + 1, 1)
|
|
784
|
+
coefficients = list(coefficients)
|
|
785
|
+
if valuations is None:
|
|
786
|
+
valuations = self.valuations(G, coefficients=coefficients)
|
|
787
|
+
if principal_part_bound:
|
|
788
|
+
valuations = islice(valuations, 0,
|
|
789
|
+
int(principal_part_bound) + 1, 1)
|
|
790
|
+
valuations = list(valuations)
|
|
791
|
+
|
|
792
|
+
if check and min(valuations) < 0:
|
|
793
|
+
raise ValueError("G must be integral")
|
|
794
|
+
|
|
795
|
+
if check and self.is_equivalence_unit(G, valuations=valuations):
|
|
796
|
+
raise ValueError("G must not be an equivalence-unit")
|
|
797
|
+
|
|
798
|
+
if check and not assume_squarefree and not G.is_squarefree():
|
|
799
|
+
raise ValueError("G must be squarefree")
|
|
800
|
+
|
|
801
|
+
from sage.rings.infinity import infinity
|
|
802
|
+
assert self(G) is not infinity # this is a valuation and G is nonzero
|
|
803
|
+
|
|
804
|
+
ret = []
|
|
805
|
+
|
|
806
|
+
F = self.equivalence_decomposition(G, assume_not_equivalence_unit=True, coefficients=coefficients, valuations=valuations, compute_unit=False, degree_bound=principal_part_bound)
|
|
807
|
+
assert len(F), "%s equivalence-decomposes as an equivalence-unit %s" % (G, F)
|
|
808
|
+
if len(F) == 1 and F[0][1] == 1 and F[0][0].degree() == G.degree():
|
|
809
|
+
assert self.is_key(G, assume_equivalence_irreducible=assume_equivalence_irreducible)
|
|
810
|
+
ret.append((self.augmentation(G, infinity, check=False), G.degree(), principal_part_bound, None, None))
|
|
811
|
+
else:
|
|
812
|
+
for phi, e in F:
|
|
813
|
+
if G == phi:
|
|
814
|
+
# Something strange happened here:
|
|
815
|
+
# G is not a key (we checked that before) but phi==G is; so phi must have less precision than G
|
|
816
|
+
# this can happen if not all coefficients of G have the same precision
|
|
817
|
+
# if we drop some precision of G then it will be a key (but is
|
|
818
|
+
# that really what we should do?)
|
|
819
|
+
assert not G.base_ring().is_exact()
|
|
820
|
+
prec = min([c.precision_absolute() for c in phi.list()])
|
|
821
|
+
g = G.map_coefficients(lambda c: c.add_bigoh(prec))
|
|
822
|
+
assert self.is_key(g)
|
|
823
|
+
ret.append((self.augmentation(g, infinity, check=False), g.degree(), principal_part_bound, None, None))
|
|
824
|
+
assert len(F) == 1
|
|
825
|
+
break
|
|
826
|
+
|
|
827
|
+
if not allow_equivalent_key and self.phi().degree() == phi.degree():
|
|
828
|
+
# We ignore augmentations that could have been detected in
|
|
829
|
+
# the previous MacLane step, see [Rüt2014, Theorem 4.33],
|
|
830
|
+
# i.e., we ignore key polynomials that are equivalent to
|
|
831
|
+
# the current key in the sense of that theorem.
|
|
832
|
+
if self.is_equivalent(self.phi(), phi):
|
|
833
|
+
continue
|
|
834
|
+
|
|
835
|
+
verbose("Determining the augmentation of %s for %s" % (self, phi), level=11)
|
|
836
|
+
|
|
837
|
+
base = self
|
|
838
|
+
if phi.degree() == base.phi().degree():
|
|
839
|
+
# very frequently, the degree of the key polynomials
|
|
840
|
+
# stagnate for a bit while the valuation of the key
|
|
841
|
+
# polynomial is slowly increased.
|
|
842
|
+
# In this case, we can drop previous key polynomials
|
|
843
|
+
# of the same degree. (They have no influence on the
|
|
844
|
+
# phi-adic expansion.)
|
|
845
|
+
if not base.is_gauss_valuation():
|
|
846
|
+
base = base._base_valuation
|
|
847
|
+
old_mu = self(phi)
|
|
848
|
+
w = base.augmentation(phi, old_mu, check=False)
|
|
849
|
+
|
|
850
|
+
# we made some experiments here: instead of computing the
|
|
851
|
+
# coefficients again from scratch, update the coefficients when
|
|
852
|
+
# phi - self.phi() is a constant.
|
|
853
|
+
# It turned out to be slightly slower than just recomputing the
|
|
854
|
+
# coefficients. The main issue with the approach was that we
|
|
855
|
+
# needed to keep track of all the coefficients and not just of
|
|
856
|
+
# the coefficients up to principal_part_bound.
|
|
857
|
+
|
|
858
|
+
w_coefficients = w.coefficients(G)
|
|
859
|
+
if principal_part_bound:
|
|
860
|
+
w_coefficients = islice(w_coefficients, 0,
|
|
861
|
+
int(principal_part_bound) + 1, 1)
|
|
862
|
+
w_coefficients = list(w_coefficients)
|
|
863
|
+
|
|
864
|
+
w_valuations = w.valuations(G, coefficients=w_coefficients)
|
|
865
|
+
if principal_part_bound:
|
|
866
|
+
w_valuations = islice(w_valuations, 0,
|
|
867
|
+
int(principal_part_bound) + 1, 1)
|
|
868
|
+
w_valuations = list(w_valuations)
|
|
869
|
+
|
|
870
|
+
from sage.geometry.newton_polygon import NewtonPolygon
|
|
871
|
+
NP = NewtonPolygon(w.newton_polygon(G, valuations=w_valuations).vertices(), last_slope=0)
|
|
872
|
+
|
|
873
|
+
verbose("Newton-Polygon for v(phi)=%s : %s" % (self(phi), NP), level=11)
|
|
874
|
+
slopes = NP.slopes(repetition=True)
|
|
875
|
+
multiplicities = {slope: len([s for s in slopes if s == slope]) for slope in slopes}
|
|
876
|
+
slopes = list(multiplicities)
|
|
877
|
+
if NP.vertices()[0][0] != 0:
|
|
878
|
+
slopes = [-infinity] + slopes
|
|
879
|
+
multiplicities[-infinity] = 1
|
|
880
|
+
|
|
881
|
+
for i, slope in enumerate(slopes):
|
|
882
|
+
verbose("Slope = %s" % slope, level=12)
|
|
883
|
+
new_mu = old_mu - slope
|
|
884
|
+
new_valuations = [val - (j * slope if slope is not -infinity else (0 if j == 0 else -infinity))
|
|
885
|
+
for j, val in enumerate(w_valuations)]
|
|
886
|
+
if phi.degree() == self.phi().degree():
|
|
887
|
+
assert new_mu > self(phi), "the valuation of the key polynomial must increase when the degree stagnates"
|
|
888
|
+
# phi has already been simplified internally by the
|
|
889
|
+
# equivalence_decomposition method but we can now possibly
|
|
890
|
+
# simplify it further as we know exactly up to which
|
|
891
|
+
# precision it needs to be defined.
|
|
892
|
+
phi = base.simplify(phi, new_mu, force=True)
|
|
893
|
+
w = base.augmentation(phi, new_mu, check=False)
|
|
894
|
+
verbose("Augmented %s to %s" % (self, w), level=13)
|
|
895
|
+
assert slope is -infinity or 0 in w.newton_polygon(G).slopes(repetition=False)
|
|
896
|
+
|
|
897
|
+
from sage.rings.integer_ring import ZZ
|
|
898
|
+
assert (phi.degree() / self.phi().degree()) in ZZ
|
|
899
|
+
degree_bound = multiplicities[slope] * phi.degree()
|
|
900
|
+
assert degree_bound <= G.degree()
|
|
901
|
+
assert degree_bound >= phi.degree()
|
|
902
|
+
ret.append((w, degree_bound, multiplicities[slope], w_coefficients, new_valuations))
|
|
903
|
+
|
|
904
|
+
if len(ret) == 0:
|
|
905
|
+
assert not allow_equivalent_key, "a MacLane step produced no augmentation"
|
|
906
|
+
assert 0 not in self.newton_polygon(G).slopes(), "a MacLane step produced no augmentation but the valuation given to the key polynomial was correct, i.e., it appears to come out of a call to mac_lane_approximants"
|
|
907
|
+
|
|
908
|
+
assert ret, "a MacLane step produced no augmentations"
|
|
909
|
+
if not report_degree_bounds_and_caches:
|
|
910
|
+
ret = [v for v, _, _, _, _ in ret]
|
|
911
|
+
return ret
|
|
912
|
+
|
|
913
|
+
def is_key(self, phi, explain=False, assume_equivalence_irreducible=False):
|
|
914
|
+
r"""
|
|
915
|
+
Return whether ``phi`` is a key polynomial for this valuation, i.e.,
|
|
916
|
+
whether it is monic, whether it :meth:`is_equivalence_irreducible`, and
|
|
917
|
+
whether it is :meth:`is_minimal`.
|
|
918
|
+
|
|
919
|
+
INPUT:
|
|
920
|
+
|
|
921
|
+
- ``phi`` -- a polynomial in the domain of this valuation
|
|
922
|
+
|
|
923
|
+
- ``explain`` -- boolean (default: ``False``); if ``True``, return a
|
|
924
|
+
string explaining why ``phi`` is not a key polynomial
|
|
925
|
+
|
|
926
|
+
EXAMPLES::
|
|
927
|
+
|
|
928
|
+
sage: # needs sage.libs.ntl
|
|
929
|
+
sage: R.<u> = Qq(4, 5)
|
|
930
|
+
sage: S.<x> = R[]
|
|
931
|
+
sage: v = GaussValuation(S)
|
|
932
|
+
sage: v.is_key(x)
|
|
933
|
+
True
|
|
934
|
+
sage: v.is_key(2*x, explain=True)
|
|
935
|
+
(False, 'phi must be monic')
|
|
936
|
+
sage: v.is_key(x^2, explain=True)
|
|
937
|
+
(False, 'phi must be equivalence irreducible')
|
|
938
|
+
sage: w = v.augmentation(x, 1)
|
|
939
|
+
sage: w.is_key(x + 1, explain = True)
|
|
940
|
+
(False, 'phi must be minimal')
|
|
941
|
+
"""
|
|
942
|
+
phi = self.domain().coerce(phi)
|
|
943
|
+
|
|
944
|
+
reason = None
|
|
945
|
+
|
|
946
|
+
if not phi.is_monic():
|
|
947
|
+
reason = "phi must be monic"
|
|
948
|
+
elif not assume_equivalence_irreducible and not self.is_equivalence_irreducible(phi):
|
|
949
|
+
reason = "phi must be equivalence irreducible"
|
|
950
|
+
elif not self.is_minimal(phi, assume_equivalence_irreducible=True):
|
|
951
|
+
reason = "phi must be minimal"
|
|
952
|
+
|
|
953
|
+
if explain:
|
|
954
|
+
return reason is None, reason
|
|
955
|
+
else:
|
|
956
|
+
return reason is None
|
|
957
|
+
|
|
958
|
+
def is_minimal(self, f, assume_equivalence_irreducible=False):
|
|
959
|
+
r"""
|
|
960
|
+
Return whether the polynomial ``f`` is minimal with respect to this
|
|
961
|
+
valuation.
|
|
962
|
+
|
|
963
|
+
A polynomial `f` is minimal with respect to `v` if it is not a constant
|
|
964
|
+
and any nonzero polynomial `h` which is `v`-divisible by `f` has at
|
|
965
|
+
least the degree of `f`.
|
|
966
|
+
|
|
967
|
+
A polynomial `h` is `v`-divisible by `f` if there is a polynomial `c`
|
|
968
|
+
such that `fc` :meth:`~sage.rings.valuation.valuation.DiscretePseudoValuation.is_equivalent` to `h`.
|
|
969
|
+
|
|
970
|
+
ALGORITHM:
|
|
971
|
+
|
|
972
|
+
Based on Theorem 9.4 of [Mac1936II]_.
|
|
973
|
+
|
|
974
|
+
EXAMPLES::
|
|
975
|
+
|
|
976
|
+
sage: # needs sage.libs.ntl
|
|
977
|
+
sage: R.<u> = Qq(4, 5)
|
|
978
|
+
sage: S.<x> = R[]
|
|
979
|
+
sage: v = GaussValuation(S)
|
|
980
|
+
sage: v.is_minimal(x + 1)
|
|
981
|
+
True
|
|
982
|
+
sage: w = v.augmentation(x, 1)
|
|
983
|
+
sage: w.is_minimal(x + 1)
|
|
984
|
+
False
|
|
985
|
+
|
|
986
|
+
TESTS::
|
|
987
|
+
|
|
988
|
+
sage: # needs sage.libs.ntl
|
|
989
|
+
sage: K = Qp(2, 10)
|
|
990
|
+
sage: R.<x> = K[]
|
|
991
|
+
sage: vp = K.valuation()
|
|
992
|
+
sage: v0 = GaussValuation(R, vp)
|
|
993
|
+
sage: v1 = v0.augmentation(x, 1/4)
|
|
994
|
+
sage: v2 = v1.augmentation(x^4 + 2, 5/4)
|
|
995
|
+
sage: v2.is_minimal(x^5 + x^4 + 2)
|
|
996
|
+
False
|
|
997
|
+
|
|
998
|
+
Polynomials which are equivalent to the key polynomial are minimal if
|
|
999
|
+
and only if they have the same degree as the key polynomial::
|
|
1000
|
+
|
|
1001
|
+
sage: v2.is_minimal(x^4 + 2) # needs sage.libs.ntl
|
|
1002
|
+
True
|
|
1003
|
+
sage: v2.is_minimal(x^4 + 4) # needs sage.libs.ntl
|
|
1004
|
+
False
|
|
1005
|
+
"""
|
|
1006
|
+
f = self.domain().coerce(f)
|
|
1007
|
+
|
|
1008
|
+
if f.is_constant():
|
|
1009
|
+
return False
|
|
1010
|
+
|
|
1011
|
+
if not assume_equivalence_irreducible and not self.is_equivalence_irreducible(f):
|
|
1012
|
+
# any factor divides f with respect to this valuation
|
|
1013
|
+
return False
|
|
1014
|
+
|
|
1015
|
+
if not f.is_monic():
|
|
1016
|
+
# divide out the leading factor, it does not change minimality
|
|
1017
|
+
v = self
|
|
1018
|
+
if not self.domain().base_ring().is_field():
|
|
1019
|
+
domain = self.domain().change_ring(self.domain().base_ring().fraction_field())
|
|
1020
|
+
v = self.extension(domain)
|
|
1021
|
+
f = domain(f)
|
|
1022
|
+
return v.is_minimal(f / f.leading_coefficient())
|
|
1023
|
+
|
|
1024
|
+
if self.is_gauss_valuation():
|
|
1025
|
+
if self(f) == 0:
|
|
1026
|
+
F = self.reduce(f, check=False)
|
|
1027
|
+
assert not F.is_constant()
|
|
1028
|
+
return F.is_irreducible()
|
|
1029
|
+
else:
|
|
1030
|
+
assert (self(f) <= 0) # f is monic
|
|
1031
|
+
# f is not minimal:
|
|
1032
|
+
# Let g be f stripped of its leading term, i.e., g = f - x^n.
|
|
1033
|
+
# Then g and f are equivalent with respect to this valuation
|
|
1034
|
+
# and in particular g divides f with respect to this valuation
|
|
1035
|
+
return False
|
|
1036
|
+
|
|
1037
|
+
if self.is_equivalent(self.phi(), f):
|
|
1038
|
+
assert f.degree() >= self.phi().degree()
|
|
1039
|
+
# If an h divides f with respect to this valuation, then it also divides phi:
|
|
1040
|
+
# v(f - c*h) > v(f) = v(c*h) => v(phi - c*h) = v((phi - f) + (f - c*h)) > v(phi) = v(c*h)
|
|
1041
|
+
# So if f were not minimal then phi would not be minimal but it is.
|
|
1042
|
+
return f.degree() == self.phi().degree()
|
|
1043
|
+
|
|
1044
|
+
else:
|
|
1045
|
+
tau = self.value_group().index(self._base_valuation.value_group())
|
|
1046
|
+
# see Theorem 9.4 of [Mac1936II]
|
|
1047
|
+
return list(self.valuations(f))[-1] == self(f) and \
|
|
1048
|
+
list(self.coefficients(f))[-1].is_constant() and \
|
|
1049
|
+
list(self.valuations(f))[0] == self(f) and \
|
|
1050
|
+
tau.divides(len(list(self.coefficients(f))) - 1)
|
|
1051
|
+
|
|
1052
|
+
def _equivalence_reduction(self, f, coefficients=None, valuations=None, degree_bound=None):
|
|
1053
|
+
r"""
|
|
1054
|
+
Helper method for :meth:`is_equivalence_irreducible` and
|
|
1055
|
+
:meth:`equivalence_decomposition` which essentially returns the
|
|
1056
|
+
reduction of ``f`` after multiplication with an ``R`` which
|
|
1057
|
+
:meth:`is_equivalence_unit`.
|
|
1058
|
+
|
|
1059
|
+
This only works when ``f`` is not divisible by :meth:`phi` with respect
|
|
1060
|
+
to this valuation. Therefore, we also return the number of times that
|
|
1061
|
+
we took out :meth:`phi` of ``f`` before we computed the reduction.
|
|
1062
|
+
|
|
1063
|
+
EXAMPLES::
|
|
1064
|
+
|
|
1065
|
+
sage: R.<x> = QQ[]
|
|
1066
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
1067
|
+
sage: v._equivalence_reduction(2*x^6 + 4*x^5 + 2*x^4 + 8)
|
|
1068
|
+
(1, 4, x^2 + 1)
|
|
1069
|
+
"""
|
|
1070
|
+
f = self.domain().coerce(f)
|
|
1071
|
+
|
|
1072
|
+
# base change from R[x] to K[x], so divisions work and sufficient
|
|
1073
|
+
# elements of negative valuation exist
|
|
1074
|
+
if not self.domain().base_ring().is_field():
|
|
1075
|
+
domain = self.domain().change_ring(self.domain().base_ring().fraction_field())
|
|
1076
|
+
v = self.extension(domain)
|
|
1077
|
+
assert self.residue_ring() is v.residue_ring()
|
|
1078
|
+
return v._equivalence_reduction(f)
|
|
1079
|
+
|
|
1080
|
+
if coefficients is None:
|
|
1081
|
+
coefficients = list(self.coefficients(f))
|
|
1082
|
+
if valuations is None:
|
|
1083
|
+
valuations = list(self.valuations(f, coefficients=coefficients))
|
|
1084
|
+
valuation = min(valuations)
|
|
1085
|
+
for phi_divides in range(len(valuations)):
|
|
1086
|
+
# count how many times phi divides f
|
|
1087
|
+
if valuations[phi_divides] <= valuation:
|
|
1088
|
+
break
|
|
1089
|
+
|
|
1090
|
+
if phi_divides:
|
|
1091
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
1092
|
+
R = PolynomialRing(f.parent(), 'phi')
|
|
1093
|
+
f = R(coefficients[phi_divides:])(self.phi())
|
|
1094
|
+
valuations = [vv - self.mu() * phi_divides
|
|
1095
|
+
for vv in valuations[phi_divides:]]
|
|
1096
|
+
coefficients = coefficients[phi_divides:]
|
|
1097
|
+
valuation = min(valuations)
|
|
1098
|
+
|
|
1099
|
+
R = self.equivalence_unit(-valuation)
|
|
1100
|
+
R = next(self.coefficients(R))
|
|
1101
|
+
fR_valuations = [vv - valuation for vv in valuations]
|
|
1102
|
+
from sage.rings.infinity import infinity
|
|
1103
|
+
fR_coefficients = [next(self.coefficients(c * R))
|
|
1104
|
+
if vv is not infinity and vv == 0 else 0
|
|
1105
|
+
for c, vv in zip(coefficients, fR_valuations)]
|
|
1106
|
+
|
|
1107
|
+
return valuation, phi_divides, self.reduce(f * R, check=False, degree_bound=degree_bound, coefficients=fR_coefficients, valuations=fR_valuations)
|
|
1108
|
+
|
|
1109
|
+
def is_equivalence_irreducible(self, f, coefficients=None, valuations=None):
|
|
1110
|
+
r"""
|
|
1111
|
+
Return whether the polynomial ``f`` is equivalence-irreducible, i.e.,
|
|
1112
|
+
whether its :meth:`equivalence_decomposition` is trivial.
|
|
1113
|
+
|
|
1114
|
+
ALGORITHM:
|
|
1115
|
+
|
|
1116
|
+
We use the same algorithm as in :meth:`equivalence_decomposition` we
|
|
1117
|
+
just do not lift the result to key polynomials.
|
|
1118
|
+
|
|
1119
|
+
INPUT:
|
|
1120
|
+
|
|
1121
|
+
- ``f`` -- a non-constant polynomial in the domain of this valuation
|
|
1122
|
+
|
|
1123
|
+
EXAMPLES::
|
|
1124
|
+
|
|
1125
|
+
sage: # needs sage.libs.ntl
|
|
1126
|
+
sage: R.<u> = Qq(4,5)
|
|
1127
|
+
sage: S.<x> = R[]
|
|
1128
|
+
sage: v = GaussValuation(S)
|
|
1129
|
+
sage: v.is_equivalence_irreducible(x)
|
|
1130
|
+
True
|
|
1131
|
+
sage: v.is_equivalence_irreducible(x^2)
|
|
1132
|
+
False
|
|
1133
|
+
sage: v.is_equivalence_irreducible(x^2 + 2)
|
|
1134
|
+
False
|
|
1135
|
+
"""
|
|
1136
|
+
f = self.domain().coerce(f)
|
|
1137
|
+
|
|
1138
|
+
if not self.domain().base_ring().is_field():
|
|
1139
|
+
domain = self.domain().change_ring(self.domain().base_ring().fraction_field())
|
|
1140
|
+
v = self.extension(domain)
|
|
1141
|
+
return v.is_equivalence_irreducible(v.domain()(f))
|
|
1142
|
+
|
|
1143
|
+
if f.is_constant():
|
|
1144
|
+
raise ValueError("f must not be constant")
|
|
1145
|
+
|
|
1146
|
+
_, phi_divides, F = self._equivalence_reduction(f, coefficients=coefficients, valuations=valuations)
|
|
1147
|
+
if phi_divides == 0:
|
|
1148
|
+
return F.is_constant() or F.is_irreducible()
|
|
1149
|
+
if phi_divides == 1:
|
|
1150
|
+
return F.is_constant()
|
|
1151
|
+
if phi_divides > 1:
|
|
1152
|
+
return False
|
|
1153
|
+
|
|
1154
|
+
def equivalence_decomposition(self, f, assume_not_equivalence_unit=False, coefficients=None, valuations=None, compute_unit=True, degree_bound=None):
|
|
1155
|
+
r"""
|
|
1156
|
+
Return an equivalence decomposition of ``f``, i.e., a polynomial
|
|
1157
|
+
`g(x)=e(x)\prod_i \phi_i(x)` with `e(x)` an :meth:`equivalence unit
|
|
1158
|
+
<InductiveValuation.is_equivalence_unit>` and the `\phi_i` :meth:`key
|
|
1159
|
+
polynomials <is_key>` such that ``f`` :meth:`~sage.rings.valuation.valuation.DiscretePseudoValuation.is_equivalent` to `g`.
|
|
1160
|
+
|
|
1161
|
+
INPUT:
|
|
1162
|
+
|
|
1163
|
+
- ``f`` -- a nonzero polynomial in the domain of this valuation
|
|
1164
|
+
|
|
1165
|
+
- ``assume_not_equivalence_unit`` -- whether or not to assume that
|
|
1166
|
+
``f`` is not an :meth:`equivalence unit <InductiveValuation.is_equivalence_unit>`
|
|
1167
|
+
(default: ``False``)
|
|
1168
|
+
|
|
1169
|
+
- ``coefficients`` -- the coefficients of ``f`` in the
|
|
1170
|
+
:meth:`~sage.rings.valuation.developing_valuation.DevelopingValuation.phi`-adic
|
|
1171
|
+
expansion if known (default: ``None``)
|
|
1172
|
+
|
|
1173
|
+
- ``valuations`` -- the valuations of ``coefficients`` if known
|
|
1174
|
+
(default: ``None``)
|
|
1175
|
+
|
|
1176
|
+
- ``compute_unit`` -- whether or not to compute the unit part of the
|
|
1177
|
+
decomposition (default: ``True``)
|
|
1178
|
+
|
|
1179
|
+
- ``degree_bound`` -- a bound on the degree of the
|
|
1180
|
+
:meth:`_equivalence_reduction` of ``f`` (default: ``None``)
|
|
1181
|
+
|
|
1182
|
+
ALGORITHM:
|
|
1183
|
+
|
|
1184
|
+
We use the algorithm described in Theorem 4.4 of [Mac1936II]_. After
|
|
1185
|
+
removing all factors `\phi` from a polynomial `f`, there is an
|
|
1186
|
+
equivalence unit `R` such that `Rf` has valuation zero. Now `Rf` can be
|
|
1187
|
+
factored as `\prod_i \alpha_i` over the :meth:`~sage.rings.valuation.valuation_space.DiscretePseudoValuationSpace.ElementMethods.residue_field`. Lifting
|
|
1188
|
+
all `\alpha_i` to key polynomials `\phi_i` gives `Rf=\prod_i R_i f_i`
|
|
1189
|
+
for suitable equivalence units `R_i` (see :meth:`lift_to_key`). Taking
|
|
1190
|
+
`R'` an :meth:`~InductiveValuation.equivalence_reciprocal` of `R`, we have `f` equivalent
|
|
1191
|
+
to `(R'\prod_i R_i)\prod_i\phi_i`.
|
|
1192
|
+
|
|
1193
|
+
EXAMPLES::
|
|
1194
|
+
|
|
1195
|
+
sage: # needs sage.libs.ntl
|
|
1196
|
+
sage: R.<u> = Qq(4,10)
|
|
1197
|
+
sage: S.<x> = R[]
|
|
1198
|
+
sage: v = GaussValuation(S)
|
|
1199
|
+
sage: v.equivalence_decomposition(S.zero())
|
|
1200
|
+
Traceback (most recent call last):
|
|
1201
|
+
...
|
|
1202
|
+
ValueError: equivalence decomposition of zero is not defined
|
|
1203
|
+
sage: v.equivalence_decomposition(S.one())
|
|
1204
|
+
1 + O(2^10)
|
|
1205
|
+
sage: v.equivalence_decomposition(x^2+2)
|
|
1206
|
+
((1 + O(2^10))*x)^2
|
|
1207
|
+
sage: v.equivalence_decomposition(x^2+1)
|
|
1208
|
+
((1 + O(2^10))*x + 1 + O(2^10))^2
|
|
1209
|
+
|
|
1210
|
+
A polynomial that is an equivalence unit, is returned as the unit part
|
|
1211
|
+
of a :class:`~sage.structure.factorization.Factorization`, leading to a unit
|
|
1212
|
+
non-minimal degree::
|
|
1213
|
+
|
|
1214
|
+
sage: w = v.augmentation(x, 1) # needs sage.libs.ntl
|
|
1215
|
+
sage: F = w.equivalence_decomposition(x^2+1); F # needs sage.libs.ntl
|
|
1216
|
+
(1 + O(2^10))*x^2 + 1 + O(2^10)
|
|
1217
|
+
sage: F.unit() # needs sage.libs.ntl
|
|
1218
|
+
(1 + O(2^10))*x^2 + 1 + O(2^10)
|
|
1219
|
+
|
|
1220
|
+
However, if the polynomial has a non-unit factor, then the unit might
|
|
1221
|
+
be replaced by a factor of lower degree::
|
|
1222
|
+
|
|
1223
|
+
sage: f = x * (x^2 + 1) # needs sage.libs.ntl
|
|
1224
|
+
sage: F = w.equivalence_decomposition(f); F # needs sage.libs.ntl
|
|
1225
|
+
(1 + O(2^10))*x
|
|
1226
|
+
sage: F.unit() # needs sage.libs.ntl
|
|
1227
|
+
1 + O(2^10)
|
|
1228
|
+
|
|
1229
|
+
Examples over an iterated unramified extension::
|
|
1230
|
+
|
|
1231
|
+
sage: # needs sage.libs.ntl
|
|
1232
|
+
sage: v = v.augmentation(x^2 + x + u, 1)
|
|
1233
|
+
sage: v = v.augmentation((x^2 + x + u)^2 + 2*x*(x^2 + x + u) + 4*x, 3)
|
|
1234
|
+
sage: v.equivalence_decomposition(x)
|
|
1235
|
+
(1 + O(2^10))*x
|
|
1236
|
+
sage: F = v.equivalence_decomposition( v.phi() )
|
|
1237
|
+
sage: len(F)
|
|
1238
|
+
1
|
|
1239
|
+
sage: F = v.equivalence_decomposition( v.phi() * (x^4 + 4*x^3 + (7 + 2*u)*x^2 + (8 + 4*u)*x + 1023 + 3*u) )
|
|
1240
|
+
sage: len(F)
|
|
1241
|
+
2
|
|
1242
|
+
|
|
1243
|
+
TESTS::
|
|
1244
|
+
|
|
1245
|
+
sage: # needs sage.geometry.polyhedron sage.groups sage.rings.number_field
|
|
1246
|
+
sage: R.<x> = QQ[]
|
|
1247
|
+
sage: K1.<pi> = NumberField(x^3 - 2)
|
|
1248
|
+
sage: K.<alpha> = K1.galois_closure()
|
|
1249
|
+
sage: R.<x> = K[]
|
|
1250
|
+
sage: vp = QQ.valuation(2)
|
|
1251
|
+
sage: vp = vp.extension(K)
|
|
1252
|
+
sage: v0 = GaussValuation(R, vp)
|
|
1253
|
+
sage: G = x^36 + 36*x^35 + 630*x^34 + 7144*x^33 + 59055*x^32 + 379688*x^31 +1978792*x^30 + 8604440*x^29 + 31895428*x^28 + 102487784*x^27 + 289310720*x^26 + 725361352*x^25 + 1629938380*x^24 + 3307417800*x^23 + 6098786184*x^22+10273444280*x^21 + 15878121214*x^20 + 22596599536*x^19 + 29695703772*x^18 +36117601976*x^17 + 40722105266*x^16 + 42608585080*x^15 + 41395961848*x^14 +37344435656*x^13 + 31267160756*x^12 + 24271543640*x^11 + 17439809008*x^10 + 11571651608*x^9 + 7066815164*x^8 + 3953912472*x^7 + 2013737432*x^6 + 925014888*x^5 + 378067657*x^4 + 134716588*x^3 + 40441790*x^2 + 9532544*x + 1584151
|
|
1254
|
+
sage: v1 = v0.mac_lane_step(G)[0]
|
|
1255
|
+
sage: V = v1.mac_lane_step(G)
|
|
1256
|
+
sage: v2 = V[0]
|
|
1257
|
+
sage: F = v2.equivalence_decomposition(G); F # needs sage.libs.singular
|
|
1258
|
+
(x^4 + 2*alpha + 1)^3 * (x^4 + 1/2*alpha^4 + alpha + 1)^3 * (x^4 + 1/2*alpha^4 + 3*alpha + 1)^3
|
|
1259
|
+
sage: v2.is_equivalent(F.prod(), G) # needs sage.libs.singular
|
|
1260
|
+
True
|
|
1261
|
+
|
|
1262
|
+
Check that :issue:`33422` is fixed::
|
|
1263
|
+
|
|
1264
|
+
sage: R.<x> = QQ[]
|
|
1265
|
+
sage: v_7 = QQ.valuation(7)
|
|
1266
|
+
sage: v0 = GaussValuation(R, v_7)
|
|
1267
|
+
sage: v1 = v0.augmentation(x, 3/2)
|
|
1268
|
+
sage: v2 = v1.augmentation(x^2-686, 7/2)
|
|
1269
|
+
sage: f = x^4 - 8001504*x^2 - 592815428352
|
|
1270
|
+
sage: F = v2.equivalence_decomposition(f); F # needs sage.libs.singular
|
|
1271
|
+
x^4 - 343/2*x^2 + 1294139
|
|
1272
|
+
sage: v2.is_equivalent(F.prod(), f) # needs sage.libs.singular
|
|
1273
|
+
True
|
|
1274
|
+
"""
|
|
1275
|
+
f = self.domain().coerce(f)
|
|
1276
|
+
|
|
1277
|
+
if f.is_zero():
|
|
1278
|
+
raise ValueError("equivalence decomposition of zero is not defined")
|
|
1279
|
+
|
|
1280
|
+
from sage.structure.factorization import Factorization
|
|
1281
|
+
if not assume_not_equivalence_unit and self.is_equivalence_unit(f):
|
|
1282
|
+
return Factorization([], unit=f, sort=False)
|
|
1283
|
+
|
|
1284
|
+
if not self.domain().base_ring().is_field():
|
|
1285
|
+
nonfractions = self.domain().base_ring()
|
|
1286
|
+
domain = self.domain().change_ring(nonfractions.fraction_field())
|
|
1287
|
+
v = self.extension(domain)
|
|
1288
|
+
ret = v.equivalence_decomposition(v.domain()(f))
|
|
1289
|
+
return Factorization([(self._eliminate_denominators(g), e)
|
|
1290
|
+
for (g, e) in ret], unit=self._eliminate_denominators(ret.unit()), sort=False)
|
|
1291
|
+
|
|
1292
|
+
valuation, phi_divides, F = self._equivalence_reduction(f, coefficients=coefficients, valuations=valuations, degree_bound=degree_bound)
|
|
1293
|
+
F = F.factor()
|
|
1294
|
+
from sage.misc.verbose import verbose
|
|
1295
|
+
verbose("%s factors as %s = %s in reduction" % (f, F.prod(), F), level=20)
|
|
1296
|
+
|
|
1297
|
+
unit = self.domain().one()
|
|
1298
|
+
if compute_unit:
|
|
1299
|
+
R_ = self.equivalence_unit(valuation, reciprocal=True)
|
|
1300
|
+
unit = self.lift(self.residue_ring()(F.unit())) * R_
|
|
1301
|
+
F = list(F)
|
|
1302
|
+
|
|
1303
|
+
if compute_unit:
|
|
1304
|
+
from sage.misc.misc_c import prod
|
|
1305
|
+
unit *= self.lift(self.residue_ring()(prod([psi.leading_coefficient()**e for psi, e in F])))
|
|
1306
|
+
if not self.is_gauss_valuation():
|
|
1307
|
+
unit *= prod([self._Q_reciprocal(e*psi.degree()) for psi, e in F])
|
|
1308
|
+
unit = self.simplify(unit, effective_degree=0, force=True)
|
|
1309
|
+
|
|
1310
|
+
# A potential speedup that we tried to implement here:
|
|
1311
|
+
# When F factors as T^n - a, then instead of using any lift of T^n - a
|
|
1312
|
+
# we tried to take a lift that approximates well an n-th root of the
|
|
1313
|
+
# constant coefficient of f[0]. Doing so saved a few invocations of
|
|
1314
|
+
# mac_lane_step but in the end made hardly any difference.
|
|
1315
|
+
|
|
1316
|
+
F = [(self.lift_to_key(psi / psi.leading_coefficient()), e)
|
|
1317
|
+
for psi, e in F]
|
|
1318
|
+
|
|
1319
|
+
if phi_divides:
|
|
1320
|
+
for i, (g, e) in enumerate(F):
|
|
1321
|
+
if g == self.phi():
|
|
1322
|
+
F[i] = (self.phi(), e + phi_divides)
|
|
1323
|
+
break
|
|
1324
|
+
else:
|
|
1325
|
+
F.append((self.phi(), phi_divides))
|
|
1326
|
+
|
|
1327
|
+
ret = Factorization(F, unit=unit, sort=False)
|
|
1328
|
+
|
|
1329
|
+
if compute_unit:
|
|
1330
|
+
assert self.is_equivalent(ret.prod(), f) # this might fail because of leading zeros in inexact rings
|
|
1331
|
+
assert self.is_equivalence_unit(ret.unit())
|
|
1332
|
+
|
|
1333
|
+
return ret
|
|
1334
|
+
|
|
1335
|
+
def minimal_representative(self, f):
|
|
1336
|
+
r"""
|
|
1337
|
+
Return a minimal representative for ``f``, i.e., a pair `e, a` such
|
|
1338
|
+
that ``f`` :meth:`~sage.rings.valuation.valuation.DiscretePseudoValuation.is_equivalent` to `e a`, `e` is an
|
|
1339
|
+
:meth:`equivalence unit <InductiveValuation.is_equivalence_unit>`, and `a` :meth:`is_minimal` and monic.
|
|
1340
|
+
|
|
1341
|
+
INPUT:
|
|
1342
|
+
|
|
1343
|
+
- ``f`` -- a nonzero polynomial which is not an equivalence unit
|
|
1344
|
+
|
|
1345
|
+
OUTPUT: a factorization which has `e` as its unit and `a` as its unique factor
|
|
1346
|
+
|
|
1347
|
+
ALGORITHM:
|
|
1348
|
+
|
|
1349
|
+
We use the algorithm described in the proof of Lemma 4.1 of [Mac1936II]_.
|
|
1350
|
+
In the expansion `f=\sum_i f_i\phi^i` take `e=f_i` for the largest `i`
|
|
1351
|
+
with `f_i\phi^i` minimal (see :meth:`~sage.rings.valuation.developing_valuation.DevelopingValuation.effective_degree`).
|
|
1352
|
+
Let `h` be the :meth:`~InductiveValuation.equivalence_reciprocal` of `e` and take `a` given
|
|
1353
|
+
by the terms of minimal valuation in the expansion of `e f`.
|
|
1354
|
+
|
|
1355
|
+
EXAMPLES::
|
|
1356
|
+
|
|
1357
|
+
sage: # needs sage.libs.ntl
|
|
1358
|
+
sage: R.<u> = Qq(4,10)
|
|
1359
|
+
sage: S.<x> = R[]
|
|
1360
|
+
sage: v = GaussValuation(S)
|
|
1361
|
+
sage: v.minimal_representative(x + 2)
|
|
1362
|
+
(1 + O(2^10))*x
|
|
1363
|
+
|
|
1364
|
+
sage: # needs sage.libs.ntl
|
|
1365
|
+
sage: v = v.augmentation(x, 1)
|
|
1366
|
+
sage: v.minimal_representative(x + 2)
|
|
1367
|
+
(1 + O(2^10))*x + 2 + O(2^11)
|
|
1368
|
+
sage: f = x^3 + 6*x + 4
|
|
1369
|
+
sage: F = v.minimal_representative(f); F
|
|
1370
|
+
(2 + 2^2 + O(2^11)) * ((1 + O(2^10))*x + 2 + O(2^11))
|
|
1371
|
+
sage: v.is_minimal(F[0][0])
|
|
1372
|
+
True
|
|
1373
|
+
sage: v.is_equivalent(F.prod(), f)
|
|
1374
|
+
True
|
|
1375
|
+
"""
|
|
1376
|
+
f = self.domain().coerce(f)
|
|
1377
|
+
|
|
1378
|
+
from sage.categories.fields import Fields
|
|
1379
|
+
if self.domain().base_ring() not in Fields():
|
|
1380
|
+
raise NotImplementedError("only implemented for polynomial rings over fields")
|
|
1381
|
+
|
|
1382
|
+
if f.is_zero():
|
|
1383
|
+
raise ValueError("zero has no minimal representative")
|
|
1384
|
+
|
|
1385
|
+
degree = self.effective_degree(f)
|
|
1386
|
+
if degree == 0:
|
|
1387
|
+
raise ValueError("equivalence units cannot have a minimal representative")
|
|
1388
|
+
|
|
1389
|
+
e = list(self.coefficients(f))[degree]
|
|
1390
|
+
h = self.equivalence_reciprocal(e).map_coefficients(_lift_to_maximal_precision)
|
|
1391
|
+
g = h * f
|
|
1392
|
+
vg = self(g)
|
|
1393
|
+
|
|
1394
|
+
coeffs = [c if v == vg else c.parent().zero()
|
|
1395
|
+
for v, c in zip(self.valuations(g), self.coefficients(g))]
|
|
1396
|
+
coeffs[degree] = self.domain().base_ring().one()
|
|
1397
|
+
ret = sum([c * self._phi**i for i, c in enumerate(coeffs)])
|
|
1398
|
+
|
|
1399
|
+
assert self.effective_degree(ret) == degree
|
|
1400
|
+
assert ret.is_monic()
|
|
1401
|
+
assert self.is_minimal(ret)
|
|
1402
|
+
|
|
1403
|
+
from sage.structure.factorization import Factorization
|
|
1404
|
+
ret = Factorization([(ret, 1)], unit=e, sort=False)
|
|
1405
|
+
|
|
1406
|
+
assert self.is_equivalent(ret.prod(), f) # this might fail because of leading zeros
|
|
1407
|
+
return ret
|
|
1408
|
+
|
|
1409
|
+
@abstract_method
|
|
1410
|
+
def lift_to_key(self, F):
|
|
1411
|
+
"""
|
|
1412
|
+
Lift the irreducible polynomial ``F`` from the
|
|
1413
|
+
:meth:`~sage.rings.valuation.valuation_space.DiscretePseudoValuationSpace.ElementMethods.residue_ring`
|
|
1414
|
+
to a key polynomial over this valuation.
|
|
1415
|
+
|
|
1416
|
+
INPUT:
|
|
1417
|
+
|
|
1418
|
+
- ``F`` -- an irreducible non-constant monic polynomial in
|
|
1419
|
+
:meth:`~sage.rings.valuation.valuation_space.DiscretePseudoValuationSpace.ElementMethods.residue_ring`
|
|
1420
|
+
of this valuation
|
|
1421
|
+
|
|
1422
|
+
OUTPUT:
|
|
1423
|
+
|
|
1424
|
+
A polynomial `f` in the domain of this valuation which is a key
|
|
1425
|
+
polynomial for this valuation and which is such that an
|
|
1426
|
+
:meth:`augmentation` with this polynomial adjoins a root of ``F`` to
|
|
1427
|
+
the resulting :meth:`~sage.rings.valuation.valuation_space.DiscretePseudoValuationSpace.ElementMethods.residue_ring`.
|
|
1428
|
+
|
|
1429
|
+
More specifically, if ``F`` is not the generator of the residue ring,
|
|
1430
|
+
then multiplying ``f`` with the :meth:`~InductiveValuation.equivalence_reciprocal` of the
|
|
1431
|
+
:meth:`~InductiveValuation.equivalence_unit` of the valuation of ``f``, produces a unit
|
|
1432
|
+
which reduces to ``F``.
|
|
1433
|
+
|
|
1434
|
+
EXAMPLES::
|
|
1435
|
+
|
|
1436
|
+
sage: # needs sage.libs.ntl
|
|
1437
|
+
sage: R.<u> = Qq(4,10)
|
|
1438
|
+
sage: S.<x> = R[]
|
|
1439
|
+
sage: v = GaussValuation(S)
|
|
1440
|
+
sage: y = v.residue_ring().gen()
|
|
1441
|
+
sage: u0 = v.residue_ring().base_ring().gen()
|
|
1442
|
+
sage: f = v.lift_to_key(y^2 + y + u0); f
|
|
1443
|
+
(1 + O(2^10))*x^2 + (1 + O(2^10))*x + u + O(2^10)
|
|
1444
|
+
"""
|
|
1445
|
+
|
|
1446
|
+
def _eliminate_denominators(self, f):
|
|
1447
|
+
r"""
|
|
1448
|
+
Return a polynomial in the domain of this valuation that
|
|
1449
|
+
:meth:`is_equivalent` to ``f``.
|
|
1450
|
+
|
|
1451
|
+
INPUT:
|
|
1452
|
+
|
|
1453
|
+
- ``f`` -- a polynomial with coefficients in the fraction field of the
|
|
1454
|
+
base ring of the domain of this valuation
|
|
1455
|
+
|
|
1456
|
+
EXAMPLES::
|
|
1457
|
+
|
|
1458
|
+
sage: R.<x> = ZZ[]
|
|
1459
|
+
sage: v = GaussValuation(R, ZZ.valuation(2))
|
|
1460
|
+
sage: v._eliminate_denominators(x/3)
|
|
1461
|
+
x
|
|
1462
|
+
|
|
1463
|
+
In general such a polynomial may not exist::
|
|
1464
|
+
|
|
1465
|
+
sage: w = v.augmentation(x, 1)
|
|
1466
|
+
sage: w._eliminate_denominators(x/2)
|
|
1467
|
+
Traceback (most recent call last):
|
|
1468
|
+
...
|
|
1469
|
+
ValueError: element has no approximate inverse in this ring
|
|
1470
|
+
|
|
1471
|
+
In general it exists iff the coefficients of minimal valuation in the
|
|
1472
|
+
`\phi`-adic expansion of ``f`` do not have denominators of positive
|
|
1473
|
+
valuation and if the same is true for these coefficients in their
|
|
1474
|
+
expansion; at least if the coefficient ring's residue ring is already a
|
|
1475
|
+
field::
|
|
1476
|
+
|
|
1477
|
+
sage: w._eliminate_denominators(x^3/2 + x)
|
|
1478
|
+
x
|
|
1479
|
+
"""
|
|
1480
|
+
if f in self.domain():
|
|
1481
|
+
return self.domain()(f)
|
|
1482
|
+
|
|
1483
|
+
nonfractions = self.domain().base_ring()
|
|
1484
|
+
fractions = nonfractions.fraction_field()
|
|
1485
|
+
|
|
1486
|
+
extended_domain = self.domain().change_ring(fractions)
|
|
1487
|
+
|
|
1488
|
+
g = extended_domain.coerce(f)
|
|
1489
|
+
|
|
1490
|
+
w = self.extension(extended_domain)
|
|
1491
|
+
# drop coefficients whose valuation is not minimal (recursively)
|
|
1492
|
+
valuation = w(g)
|
|
1493
|
+
g = w.simplify(g, error=valuation, force=True, phiadic=True)
|
|
1494
|
+
|
|
1495
|
+
if g in self.domain():
|
|
1496
|
+
return self.domain()(g)
|
|
1497
|
+
|
|
1498
|
+
nonfraction_valuation = self.restriction(nonfractions)
|
|
1499
|
+
# if this fails then there is no equivalent polynomial in the domain of this valuation
|
|
1500
|
+
ret = g.map_coefficients(
|
|
1501
|
+
lambda c: c.numerator() * nonfraction_valuation.inverse(c.denominator(),
|
|
1502
|
+
valuation
|
|
1503
|
+
+ nonfraction_valuation(c.denominator())
|
|
1504
|
+
- nonfraction_valuation(c.numerator())
|
|
1505
|
+
+ nonfraction_valuation.value_group().gen()),
|
|
1506
|
+
nonfractions)
|
|
1507
|
+
assert w.is_equivalent(f, ret)
|
|
1508
|
+
return ret
|
|
1509
|
+
|
|
1510
|
+
def _test_eliminate_denominators(self, **options):
|
|
1511
|
+
r"""
|
|
1512
|
+
Test the correctness of :meth:`_eliminate_denominators`.
|
|
1513
|
+
|
|
1514
|
+
EXAMPLES::
|
|
1515
|
+
|
|
1516
|
+
sage: R.<x> = ZZ[]
|
|
1517
|
+
sage: v = GaussValuation(R, ZZ.valuation(2))
|
|
1518
|
+
sage: v._test_eliminate_denominators()
|
|
1519
|
+
"""
|
|
1520
|
+
tester = self._tester(**options)
|
|
1521
|
+
|
|
1522
|
+
nonfractions = self.domain().base_ring()
|
|
1523
|
+
fractions = nonfractions.fraction_field()
|
|
1524
|
+
extended_domain = self.domain().change_ring(fractions)
|
|
1525
|
+
w = self.extension(extended_domain)
|
|
1526
|
+
|
|
1527
|
+
S = tester.some_elements(w.domain().some_elements())
|
|
1528
|
+
for f in S:
|
|
1529
|
+
try:
|
|
1530
|
+
g = self._eliminate_denominators(f)
|
|
1531
|
+
except ValueError:
|
|
1532
|
+
continue
|
|
1533
|
+
tester.assertIs(g.parent(), self.domain())
|
|
1534
|
+
tester.assertTrue(w.is_equivalent(f, g))
|
|
1535
|
+
|
|
1536
|
+
def _test_lift_to_key(self, **options):
|
|
1537
|
+
r"""
|
|
1538
|
+
Test the correctness of :meth:`lift_to_key`.
|
|
1539
|
+
|
|
1540
|
+
EXAMPLES::
|
|
1541
|
+
|
|
1542
|
+
sage: R.<x> = QQ[]
|
|
1543
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
1544
|
+
sage: v._test_lift_to_key() # needs sage.rings.number_field
|
|
1545
|
+
"""
|
|
1546
|
+
tester = self._tester(**options)
|
|
1547
|
+
|
|
1548
|
+
try:
|
|
1549
|
+
self.residue_ring()
|
|
1550
|
+
except NotImplementedError:
|
|
1551
|
+
from sage.categories.fields import Fields
|
|
1552
|
+
if self.domain().base() in Fields():
|
|
1553
|
+
raise
|
|
1554
|
+
return
|
|
1555
|
+
|
|
1556
|
+
S = tester.some_elements(self.residue_ring().some_elements())
|
|
1557
|
+
for F in S:
|
|
1558
|
+
if F.is_monic() and not F.is_constant() and F.is_irreducible():
|
|
1559
|
+
try:
|
|
1560
|
+
f = self.lift_to_key(F)
|
|
1561
|
+
except NotImplementedError:
|
|
1562
|
+
from sage.categories.fields import Fields
|
|
1563
|
+
if self.domain().base() in Fields():
|
|
1564
|
+
raise
|
|
1565
|
+
continue
|
|
1566
|
+
tester.assertIs(f.parent(), self.domain())
|
|
1567
|
+
tester.assertTrue(self.is_key(f))
|
|
1568
|
+
|
|
1569
|
+
# check that augmentation produces a valuation with roots of F
|
|
1570
|
+
# in the residue ring
|
|
1571
|
+
from sage.rings.infinity import infinity
|
|
1572
|
+
w = self.augmentation(f, infinity)
|
|
1573
|
+
F = F.change_ring(w.residue_ring())
|
|
1574
|
+
roots = F.roots(multiplicities=False)
|
|
1575
|
+
tester.assertGreaterEqual(len(roots), 1)
|
|
1576
|
+
|
|
1577
|
+
# check that f has the right reduction
|
|
1578
|
+
if F == F.parent().gen():
|
|
1579
|
+
tester.assertTrue(self.is_equivalent(f, self.phi()))
|
|
1580
|
+
else:
|
|
1581
|
+
tester.assertEqual(self.reduce(f * self.equivalence_reciprocal(self.equivalence_unit(self(f)))), F)
|
|
1582
|
+
|
|
1583
|
+
def _test_is_equivalence_irreducible(self, **options):
|
|
1584
|
+
r"""
|
|
1585
|
+
Test the correctness of :meth:`is_equivalence_irreducible`.
|
|
1586
|
+
|
|
1587
|
+
EXAMPLES::
|
|
1588
|
+
|
|
1589
|
+
sage: R.<x> = QQ[]
|
|
1590
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
1591
|
+
sage: v._test_is_equivalence_irreducible()
|
|
1592
|
+
"""
|
|
1593
|
+
tester = self._tester(**options)
|
|
1594
|
+
S = tester.some_elements(self.domain().some_elements())
|
|
1595
|
+
for f in S:
|
|
1596
|
+
if f.is_constant():
|
|
1597
|
+
continue
|
|
1598
|
+
is_equivalence_irreducible = self.is_equivalence_irreducible(f)
|
|
1599
|
+
F = self.equivalence_decomposition(f)
|
|
1600
|
+
tester.assertEqual(is_equivalence_irreducible, len(F) == 0 or (len(F) == 1 and F[0][1] == 1))
|
|
1601
|
+
if self.is_equivalence_unit(f):
|
|
1602
|
+
tester.assertTrue(f.is_constant() or self.is_equivalence_irreducible(f))
|
|
1603
|
+
|
|
1604
|
+
tester.assertTrue(self.is_equivalence_irreducible(self.phi()))
|
|
1605
|
+
tester.assertTrue(self.is_equivalence_irreducible(-self.phi()))
|
|
1606
|
+
tester.assertFalse(self.is_equivalence_irreducible(self.phi() ** 2))
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
class FinalInductiveValuation(InductiveValuation):
|
|
1610
|
+
r"""
|
|
1611
|
+
Abstract base class for an inductive valuation which cannot be augmented further.
|
|
1612
|
+
|
|
1613
|
+
TESTS::
|
|
1614
|
+
|
|
1615
|
+
sage: R.<x> = QQ[]
|
|
1616
|
+
sage: v = GaussValuation(R, valuations.TrivialValuation(QQ))
|
|
1617
|
+
sage: w = v.augmentation(x^2 + x + 1, infinity)
|
|
1618
|
+
sage: from sage.rings.valuation.inductive_valuation import FinalInductiveValuation
|
|
1619
|
+
sage: isinstance(w, FinalInductiveValuation)
|
|
1620
|
+
True
|
|
1621
|
+
"""
|
|
1622
|
+
|
|
1623
|
+
|
|
1624
|
+
class InfiniteInductiveValuation(FinalInductiveValuation, InfiniteDiscretePseudoValuation):
|
|
1625
|
+
r"""
|
|
1626
|
+
Abstract base class for an inductive valuation which is not discrete, i.e.,
|
|
1627
|
+
which assigns infinite valuation to its last key polynomial.
|
|
1628
|
+
|
|
1629
|
+
EXAMPLES::
|
|
1630
|
+
|
|
1631
|
+
sage: R.<x> = QQ[]
|
|
1632
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
1633
|
+
sage: w = v.augmentation(x^2 + x + 1, infinity)
|
|
1634
|
+
"""
|
|
1635
|
+
def __init__(self, parent, base_valuation):
|
|
1636
|
+
r"""
|
|
1637
|
+
TESTS::
|
|
1638
|
+
|
|
1639
|
+
sage: R.<x> = QQ[]
|
|
1640
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
1641
|
+
sage: w = v.augmentation(x^2 + x + 1, infinity)
|
|
1642
|
+
sage: from sage.rings.valuation.inductive_valuation import InfiniteInductiveValuation
|
|
1643
|
+
sage: isinstance(w, InfiniteInductiveValuation)
|
|
1644
|
+
True
|
|
1645
|
+
"""
|
|
1646
|
+
FinalInductiveValuation.__init__(self, parent, base_valuation)
|
|
1647
|
+
InfiniteDiscretePseudoValuation.__init__(self, parent)
|
|
1648
|
+
|
|
1649
|
+
def change_domain(self, ring):
|
|
1650
|
+
r"""
|
|
1651
|
+
Return this valuation over ``ring``.
|
|
1652
|
+
|
|
1653
|
+
EXAMPLES:
|
|
1654
|
+
|
|
1655
|
+
We can turn an infinite valuation into a valuation on the quotient::
|
|
1656
|
+
|
|
1657
|
+
sage: R.<x> = QQ[]
|
|
1658
|
+
sage: v = GaussValuation(R, QQ.valuation(2))
|
|
1659
|
+
sage: w = v.augmentation(x^2 + x + 1, infinity)
|
|
1660
|
+
sage: w.change_domain(R.quo(x^2 + x + 1))
|
|
1661
|
+
2-adic valuation
|
|
1662
|
+
"""
|
|
1663
|
+
from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic
|
|
1664
|
+
if isinstance(ring, PolynomialQuotientRing_generic) and ring.base() is self.domain() and ring.modulus() == self.phi():
|
|
1665
|
+
return self.restriction(self.domain().base())._extensions_to_quotient(ring, approximants=[self])[0]
|
|
1666
|
+
return super().change_domain(ring)
|
|
1667
|
+
|
|
1668
|
+
|
|
1669
|
+
def _lift_to_maximal_precision(c):
|
|
1670
|
+
r"""
|
|
1671
|
+
Lift ``c`` to maximal precision if the parent is not exact.
|
|
1672
|
+
|
|
1673
|
+
EXAMPLES::
|
|
1674
|
+
|
|
1675
|
+
sage: R = Zp(2,5)
|
|
1676
|
+
sage: x = R(1,2); x
|
|
1677
|
+
1 + O(2^2)
|
|
1678
|
+
sage: from sage.rings.valuation.inductive_valuation import _lift_to_maximal_precision
|
|
1679
|
+
sage: _lift_to_maximal_precision(x)
|
|
1680
|
+
1 + O(2^5)
|
|
1681
|
+
|
|
1682
|
+
sage: x = 1
|
|
1683
|
+
sage: _lift_to_maximal_precision(x)
|
|
1684
|
+
1
|
|
1685
|
+
"""
|
|
1686
|
+
return c if c.parent().is_exact() else c.lift_to_precision()
|