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,1018 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
# sage.doctest: needs sage.geometry.polyhedron sage.libs.linbox sage.modules sage.rings.number_field
|
|
3
|
+
r"""
|
|
4
|
+
Enumeration of totally real fields: relative extensions
|
|
5
|
+
|
|
6
|
+
This module contains functions to enumerate primitive extensions `L / K`, where
|
|
7
|
+
`K` is a given totally real number field, with given degree and small root
|
|
8
|
+
discriminant. This is a relative analogue of the problem described in
|
|
9
|
+
:mod:`sage.rings.number_field.totallyreal`, and we use a similar approach
|
|
10
|
+
based on a relative version of Hunter's theorem.
|
|
11
|
+
|
|
12
|
+
In this first simple example, we compute the totally real quadratic
|
|
13
|
+
fields of `F = \QQ(\sqrt{2})` of discriminant `\le 2000`.
|
|
14
|
+
|
|
15
|
+
::
|
|
16
|
+
|
|
17
|
+
sage: ZZx.<x> = ZZ[]
|
|
18
|
+
sage: F.<t> = NumberField(x^2 - 2)
|
|
19
|
+
sage: enumerate_totallyreal_fields_rel(F, 2, 2000)
|
|
20
|
+
[[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]]
|
|
21
|
+
|
|
22
|
+
There is indeed only one such extension, given by `F(\sqrt{5})`.
|
|
23
|
+
|
|
24
|
+
Next, we list all totally real quadratic extensions of `\QQ(\sqrt 5)`
|
|
25
|
+
with root discriminant `\le 10`.
|
|
26
|
+
|
|
27
|
+
::
|
|
28
|
+
|
|
29
|
+
sage: F.<t> = NumberField(x^2 - 5)
|
|
30
|
+
sage: ls = enumerate_totallyreal_fields_rel(F, 2, 10^4)
|
|
31
|
+
sage: ls # random (the second factor is platform-dependent)
|
|
32
|
+
[[725, x^4 - x^3 - 3*x^2 + x + 1, xF^2 + (-1/2*t - 7/2)*xF + 1],
|
|
33
|
+
[1125, x^4 - x^3 - 4*x^2 + 4*x + 1, xF^2 + (-1/2*t - 7/2)*xF + 1/2*t + 3/2],
|
|
34
|
+
[1600, x^4 - 6*x^2 + 4, xF^2 - 2],
|
|
35
|
+
[2000, x^4 - 5*x^2 + 5, xF^2 - 1/2*t - 5/2],
|
|
36
|
+
[2225, x^4 - x^3 - 5*x^2 + 2*x + 4, xF^2 + (-1/2*t + 1/2)*xF - 3/2*t - 7/2],
|
|
37
|
+
[2525, x^4 - 2*x^3 - 4*x^2 + 5*x + 5, xF^2 + (-1/2*t - 1/2)*xF - 1/2*t - 5/2],
|
|
38
|
+
[3600, x^4 - 2*x^3 - 7*x^2 + 8*x + 1, xF^2 - 3],
|
|
39
|
+
[4225, x^4 - 9*x^2 + 4, xF^2 + (-1/2*t - 1/2)*xF - 3/2*t - 9/2],
|
|
40
|
+
[4400, x^4 - 7*x^2 + 11, xF^2 - 1/2*t - 7/2],
|
|
41
|
+
[4525, x^4 - x^3 - 7*x^2 + 3*x + 9, xF^2 + (-1/2*t - 1/2)*xF - 3],
|
|
42
|
+
[5125, x^4 - 2*x^3 - 6*x^2 + 7*x + 11, xF^2 + (-1/2*t - 1/2)*xF - t - 4],
|
|
43
|
+
[5225, x^4 - x^3 - 8*x^2 + x + 11, xF^2 + (-1/2*t - 1/2)*xF - 1/2*t - 7/2],
|
|
44
|
+
[5725, x^4 - x^3 - 8*x^2 + 6*x + 11, xF^2 + (-1/2*t + 1/2)*xF - 1/2*t - 7/2],
|
|
45
|
+
[6125, x^4 - x^3 - 9*x^2 + 9*x + 11, xF^2 + (-1/2*t + 1/2)*xF - t - 4],
|
|
46
|
+
[7225, x^4 - 11*x^2 + 9, xF^2 + (-1)*xF - 4],
|
|
47
|
+
[7600, x^4 - 9*x^2 + 19, xF^2 - 1/2*t - 9/2],
|
|
48
|
+
[7625, x^4 - x^3 - 9*x^2 + 4*x + 16, xF^2 + (-1/2*t - 1/2)*xF - 4],
|
|
49
|
+
[8000, x^4 - 10*x^2 + 20, xF^2 - t - 5],
|
|
50
|
+
[8525, x^4 - 2*x^3 - 8*x^2 + 9*x + 19, xF^2 + (-1)*xF - 1/2*t - 9/2],
|
|
51
|
+
[8725, x^4 - x^3 - 10*x^2 + 2*x + 19, xF^2 + (-1/2*t - 1/2)*xF - 1/2*t - 9/2],
|
|
52
|
+
[9225, x^4 - x^3 - 10*x^2 + 7*x + 19, xF^2 + (-1/2*t + 1/2)*xF - 1/2*t - 9/2]]
|
|
53
|
+
sage: [ f[0] for f in ls ]
|
|
54
|
+
[725, 1125, 1600, 2000, 2225, 2525, 3600, 4225, 4400, 4525, 5125, 5225, 5725, 6125, 7225, 7600, 7625, 8000, 8525, 8725, 9225]
|
|
55
|
+
|
|
56
|
+
sage: [NumberField(ZZx(x[1]), 't').is_galois() for x in ls] # needs sage.groups
|
|
57
|
+
[False, True, True, True, False, False, True, True, False, False, False, False, False, True, True, False, False, True, False, False, False]
|
|
58
|
+
|
|
59
|
+
Eight out of 21 such fields are Galois (with Galois group `C_4`
|
|
60
|
+
or `C_2 \times C_2`); the others have Galois closure of degree 8
|
|
61
|
+
(with Galois group `D_8`).
|
|
62
|
+
|
|
63
|
+
Finally, we compute the cubic extensions of `\QQ(\zeta_7)^+` with
|
|
64
|
+
discriminant `\le 17 \times 10^9`.
|
|
65
|
+
|
|
66
|
+
::
|
|
67
|
+
|
|
68
|
+
sage: F.<t> = NumberField(ZZx([1,-4,3,1]))
|
|
69
|
+
sage: F.disc()
|
|
70
|
+
49
|
|
71
|
+
sage: enumerate_totallyreal_fields_rel(F, 3, 17*10^9) # not tested, too long time (258s on sage.math, 2013)
|
|
72
|
+
[[16240385609L, x^9 - x^8 - 9*x^7 + 4*x^6 + 26*x^5 - 2*x^4 - 25*x^3 - x^2 + 7*x + 1, xF^3 + (-t^2 - 4*t + 1)*xF^2 + (t^2 + 3*t - 5)*xF + 3*t^2 + 11*t - 5]] # 32-bit
|
|
73
|
+
[[16240385609, x^9 - x^8 - 9*x^7 + 4*x^6 + 26*x^5 - 2*x^4 - 25*x^3 - x^2 + 7*x + 1, xF^3 + (-t^2 - 4*t + 1)*xF^2 + (t^2 + 3*t - 5)*xF + 3*t^2 + 11*t - 5]] # 64-bit
|
|
74
|
+
|
|
75
|
+
TESTS:
|
|
76
|
+
|
|
77
|
+
Check that :issue:`27646` is fixed::
|
|
78
|
+
|
|
79
|
+
sage: L = enumerate_totallyreal_fields_all(6,435000) # long time
|
|
80
|
+
|
|
81
|
+
AUTHORS:
|
|
82
|
+
|
|
83
|
+
- John Voight (2007-11-03): initial version
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# ****************************************************************************
|
|
87
|
+
# Copyright (C) 2007 William Stein and John Voight
|
|
88
|
+
#
|
|
89
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
90
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
91
|
+
# the License, or (at your option) any later version.
|
|
92
|
+
# https://www.gnu.org/licenses/
|
|
93
|
+
# ****************************************************************************
|
|
94
|
+
|
|
95
|
+
from sage.arith.misc import binomial
|
|
96
|
+
from sage.arith.misc import GCD as gcd
|
|
97
|
+
from sage.arith.misc import divisors
|
|
98
|
+
from sage.rings.integer import Integer
|
|
99
|
+
from sage.rings.integer_ring import IntegerRing
|
|
100
|
+
from sage.rings.number_field.totallyreal_data import ZZx, lagrange_degree_3, int_has_small_square_divisor, hermite_constant
|
|
101
|
+
from sage.rings.number_field.number_field import NumberField
|
|
102
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
103
|
+
from sage.rings.number_field.totallyreal import weed_fields, odlyzko_bound_totallyreal, enumerate_totallyreal_fields_prim
|
|
104
|
+
from sage.libs.pari import pari
|
|
105
|
+
from sage.rings.integer_ring import ZZ
|
|
106
|
+
from sage.rings.rational_field import QQ
|
|
107
|
+
|
|
108
|
+
import math
|
|
109
|
+
import sys
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def integral_elements_in_box(K, C):
|
|
113
|
+
r"""
|
|
114
|
+
Return all integral elements of the totally real field `K` whose
|
|
115
|
+
embeddings lie *numerically* within the bounds specified by the
|
|
116
|
+
list ``C``. The output is architecture dependent, and one may want
|
|
117
|
+
to expand the bounds that define ``C`` by some epsilon.
|
|
118
|
+
|
|
119
|
+
INPUT:
|
|
120
|
+
|
|
121
|
+
- ``K`` -- a totally real number field
|
|
122
|
+
- ``C`` -- list ``[[lower, upper], ...]`` of lower and upper bounds,
|
|
123
|
+
for each embedding
|
|
124
|
+
|
|
125
|
+
EXAMPLES::
|
|
126
|
+
|
|
127
|
+
sage: x = polygen(QQ)
|
|
128
|
+
sage: K.<alpha> = NumberField(x^2 - 2)
|
|
129
|
+
sage: eps = 10e-6
|
|
130
|
+
sage: C = [[0-eps, 5+eps], [0-eps, 10+eps]]
|
|
131
|
+
sage: ls = sage.rings.number_field.totallyreal_rel.integral_elements_in_box(K, C) # needs palp
|
|
132
|
+
sage: sorted(a.trace() for a in ls) # needs palp
|
|
133
|
+
[0, 2, 4, 4, 4, 6, 6, 6, 6, 8, 8, 8, 10, 10, 10, 10, 12, 12, 14]
|
|
134
|
+
sage: len(ls) # needs palp
|
|
135
|
+
19
|
|
136
|
+
|
|
137
|
+
sage: v = sage.rings.number_field.totallyreal_rel.integral_elements_in_box(K, C) # needs palp
|
|
138
|
+
sage: sorted(v) # needs palp
|
|
139
|
+
[0, -alpha + 2, 1, -alpha + 3, 2, 3, alpha + 2, 4, alpha + 3, 5, alpha + 4,
|
|
140
|
+
2*alpha + 3, alpha + 5, 2*alpha + 4, alpha + 6, 2*alpha + 5, 2*alpha + 6,
|
|
141
|
+
3*alpha + 5, 2*alpha + 7]
|
|
142
|
+
|
|
143
|
+
A cubic field::
|
|
144
|
+
|
|
145
|
+
sage: x = polygen(QQ)
|
|
146
|
+
sage: K.<a> = NumberField(x^3 - 16*x +16)
|
|
147
|
+
sage: eps = 10e-6
|
|
148
|
+
sage: C = [[0-eps,5+eps]]*3
|
|
149
|
+
sage: v = sage.rings.number_field.totallyreal_rel.integral_elements_in_box(K, C) # needs palp
|
|
150
|
+
|
|
151
|
+
Note that the output is platform dependent (sometimes a 5 is listed
|
|
152
|
+
below, and sometimes it isn't)::
|
|
153
|
+
|
|
154
|
+
sage: sorted(v) # needs palp
|
|
155
|
+
[-1/2*a + 2, 1/4*a^2 + 1/2*a, 0, 1, 2, 3, 4,...-1/4*a^2 - 1/2*a + 5,
|
|
156
|
+
1/2*a + 3, -1/4*a^2 + 5]
|
|
157
|
+
"""
|
|
158
|
+
d = K.degree()
|
|
159
|
+
Foo = K.real_embeddings()
|
|
160
|
+
B = K.reduced_basis()
|
|
161
|
+
|
|
162
|
+
import numpy
|
|
163
|
+
import numpy.linalg
|
|
164
|
+
L = numpy.array([[v(b) for b in B] for v in Foo])
|
|
165
|
+
Linv = numpy.linalg.inv(L)
|
|
166
|
+
Vi = [[C[0][0]], [C[0][1]]]
|
|
167
|
+
for i in range(1, d):
|
|
168
|
+
Vi = sum([[v + [C[i][0]], v + [C[i][1]]] for v in Vi], [])
|
|
169
|
+
V = numpy.matrix(Linv) * numpy.matrix(Vi).transpose()
|
|
170
|
+
j = 0
|
|
171
|
+
while j < 2**d:
|
|
172
|
+
for i in range(d):
|
|
173
|
+
if V[i, j] < V[i, j+1]:
|
|
174
|
+
V[i, j] = math.floor(V[i, j])
|
|
175
|
+
V[i, j+1] = math.ceil(V[i, j+1])
|
|
176
|
+
else:
|
|
177
|
+
V[i, j] = math.ceil(V[i, j])
|
|
178
|
+
V[i, j+1] = math.floor(V[i, j+1])
|
|
179
|
+
j += 2
|
|
180
|
+
W0 = (Linv*numpy.array([Vi[0]] * d)).transpose()
|
|
181
|
+
W = (Linv*numpy.array([Vi[2**i] for i in range(d)])).transpose()
|
|
182
|
+
for j in range(d):
|
|
183
|
+
for i in range(d):
|
|
184
|
+
if W[i,j] < W0[i,j]:
|
|
185
|
+
W[i,j] = math.floor(W[i,j])
|
|
186
|
+
W0[i,j] = math.ceil(W0[i,j])
|
|
187
|
+
else:
|
|
188
|
+
W[i,j] = math.ceil(W[i,j])
|
|
189
|
+
W0[i,j] = math.floor(W0[i,j])
|
|
190
|
+
M = [[int(V[i,j]) for i in range(V.shape[0])] for j in range(V.shape[1])]
|
|
191
|
+
M += [[int(W0[i,j]) for j in range(W0.shape[0])] for i in range(W0.shape[0])]
|
|
192
|
+
M += [[int(W[i,j]) for j in range(W.shape[1])] for i in range(W.shape[0])]
|
|
193
|
+
|
|
194
|
+
from sage.matrix.constructor import matrix
|
|
195
|
+
M = (matrix(IntegerRing(),len(M),len(M[0]), M).transpose()).columns()
|
|
196
|
+
|
|
197
|
+
i = 0
|
|
198
|
+
while i < len(M):
|
|
199
|
+
j = i+1
|
|
200
|
+
while j < len(M):
|
|
201
|
+
if M[i] == M[j]:
|
|
202
|
+
M.pop(j)
|
|
203
|
+
else:
|
|
204
|
+
j += 1
|
|
205
|
+
i += 1
|
|
206
|
+
|
|
207
|
+
from sage.geometry.lattice_polytope import LatticePolytope
|
|
208
|
+
P = LatticePolytope(M)
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
pts = P.points()
|
|
212
|
+
except ValueError:
|
|
213
|
+
return []
|
|
214
|
+
|
|
215
|
+
S = []
|
|
216
|
+
for p in pts:
|
|
217
|
+
theta = sum(a * b for a, b in zip(p.list(), B))
|
|
218
|
+
if all((C[i][0] <= Foo[i](theta) <= C[i][1])
|
|
219
|
+
for i in range(d)):
|
|
220
|
+
S.append(theta)
|
|
221
|
+
|
|
222
|
+
return S
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
#********************************************************************************
|
|
226
|
+
# Main class
|
|
227
|
+
#********************************************************************************
|
|
228
|
+
|
|
229
|
+
eps_global = 10**(-6)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class tr_data_rel:
|
|
233
|
+
r"""
|
|
234
|
+
This class encodes the data used in the enumeration of totally real
|
|
235
|
+
fields for relative extensions.
|
|
236
|
+
|
|
237
|
+
We do not give a complete description here. For more information,
|
|
238
|
+
see the attached functions; all of these are used internally by the
|
|
239
|
+
functions in totallyreal_rel.py, so see that file for examples and
|
|
240
|
+
further documentation.
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
def __init__(self, F, m, B, a=None):
|
|
244
|
+
r"""
|
|
245
|
+
Initialization routine (constructor).
|
|
246
|
+
|
|
247
|
+
INPUT:
|
|
248
|
+
|
|
249
|
+
- ``F`` -- number field; the base field
|
|
250
|
+
- ``m`` -- integer; the relative degree
|
|
251
|
+
- ``B`` -- integer; the discriminant bound
|
|
252
|
+
- ``a`` -- list (default: ``[]``); the coefficient list to begin with,
|
|
253
|
+
corresponding to ``a[len(a)]*x^n + ... + a[0]x^(n-len(a))``
|
|
254
|
+
|
|
255
|
+
OUTPUT:
|
|
256
|
+
|
|
257
|
+
the data initialized to begin enumeration of totally real fields
|
|
258
|
+
with base field `F`, degree `n`, discriminant bounded by `B`, and starting
|
|
259
|
+
with coefficients `a`.
|
|
260
|
+
|
|
261
|
+
EXAMPLES::
|
|
262
|
+
|
|
263
|
+
sage: x = polygen(ZZ, 'x')
|
|
264
|
+
sage: F.<t> = NumberField(x^2 - 2)
|
|
265
|
+
sage: T = sage.rings.number_field.totallyreal_rel.tr_data_rel(F, 2, 2000)
|
|
266
|
+
"""
|
|
267
|
+
if a is None: # don't make the stupid noob mistake of putting a=[]
|
|
268
|
+
a = [] # in the function signature above.
|
|
269
|
+
|
|
270
|
+
# Initialize constants.
|
|
271
|
+
self.m = m
|
|
272
|
+
d = F.degree()
|
|
273
|
+
self.d = d
|
|
274
|
+
self.n = n = m*d
|
|
275
|
+
self.B = B
|
|
276
|
+
self.gamma = hermite_constant(self.n-self.d)
|
|
277
|
+
|
|
278
|
+
self.F = F
|
|
279
|
+
self.Z_F = F.maximal_order()
|
|
280
|
+
self.Foo = F.real_embeddings()
|
|
281
|
+
self.dF = abs(F.disc())
|
|
282
|
+
self.Fx = PolynomialRing(F, 'xF')
|
|
283
|
+
|
|
284
|
+
self.beta = [[]]*m
|
|
285
|
+
self.gnk = [[]]*m
|
|
286
|
+
|
|
287
|
+
self.trace_elts = []
|
|
288
|
+
|
|
289
|
+
Z_Fbasis = self.Z_F.basis()
|
|
290
|
+
|
|
291
|
+
# Initialize variables.
|
|
292
|
+
if not a:
|
|
293
|
+
# No starting input, all polynomials will be found; initialize to zero.
|
|
294
|
+
self.a = [0]*m + [1]
|
|
295
|
+
self.amaxvals = [[]]*m
|
|
296
|
+
anm1s = [[i] for i in range(0,m//2+1)]
|
|
297
|
+
for i in range(1,self.d):
|
|
298
|
+
for j in range(len(anm1s)):
|
|
299
|
+
anm1s[j] = [anm1s[j] + [i] for i in range(m)]
|
|
300
|
+
anm1s = sum(anm1s, [])
|
|
301
|
+
anm1s = [sum([Z_Fbasis[i] * aa[i] for i in range(self.d)]) for aa in anm1s]
|
|
302
|
+
# Minimize trace in class.
|
|
303
|
+
import numpy
|
|
304
|
+
for i in range(len(anm1s)):
|
|
305
|
+
Q = [[v(m*x) for v in self.Foo] + [0] for x in Z_Fbasis] + [[v(anm1s[i]) for v in self.Foo] + [10**6]]
|
|
306
|
+
pari_string = '[' + ';'.join(','.join("%s" % ii for ii in row) for row in zip(*Q)) + ']'
|
|
307
|
+
adj = pari(pari_string).qflll()[self.d]
|
|
308
|
+
anm1s[i] += sum([m*Z_Fbasis[ii]*int(adj[ii])//int(adj[self.d]) for ii in range(self.d)])
|
|
309
|
+
|
|
310
|
+
self.amaxvals[m-1] = anm1s
|
|
311
|
+
self.a[m-1] = self.amaxvals[m-1].pop()
|
|
312
|
+
self.k = m-2
|
|
313
|
+
|
|
314
|
+
bl = math.ceil(1.7719*self.n)
|
|
315
|
+
br = max([1./m*(am1**2).trace() +
|
|
316
|
+
self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d))
|
|
317
|
+
for am1 in anm1s])
|
|
318
|
+
br = math.floor(br)
|
|
319
|
+
T2s = self.F._positive_integral_elements_with_trace([bl, br])
|
|
320
|
+
self.trace_elts.append([bl, br, T2s])
|
|
321
|
+
|
|
322
|
+
elif len(a) <= m + 1:
|
|
323
|
+
# First few coefficients have been specified.
|
|
324
|
+
# The value of k is the largest index of the coefficients of a which is
|
|
325
|
+
# currently unknown; e.g., if k == -1, then we can iterate
|
|
326
|
+
# over polynomials, and if k == n-1, then we have finished iterating.
|
|
327
|
+
if a[len(a)-1] != 1:
|
|
328
|
+
raise ValueError("a[len(a)-1](=%s) must be 1 so polynomial is monic" % a[len(a)-1])
|
|
329
|
+
|
|
330
|
+
raise NotImplementedError("These have not been checked.")
|
|
331
|
+
|
|
332
|
+
k = m-len(a)
|
|
333
|
+
self.k = k
|
|
334
|
+
a = [0]*(k+1) + a
|
|
335
|
+
self.amaxvals = [[]]*m
|
|
336
|
+
for i in range(n+1):
|
|
337
|
+
self.a[i] = a[i]
|
|
338
|
+
|
|
339
|
+
# Bounds come from an application of Lagrange multipliers in degrees 2,3.
|
|
340
|
+
self.b_lower = [-1./m*(v(self.a[m-1]) +
|
|
341
|
+
(m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
|
|
342
|
+
self.b_upper = [-1./m*(v(self.a[m-1]) -
|
|
343
|
+
(m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
|
|
344
|
+
if k < m - 2:
|
|
345
|
+
bminmax = [lagrange_degree_3(n,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo]
|
|
346
|
+
self.b_lower = bminmax[0]
|
|
347
|
+
self.b_upper = bminmax[1]
|
|
348
|
+
|
|
349
|
+
# Annoying, but must reverse coefficients for numpy.
|
|
350
|
+
gnk = [binomial(j,k+2)*a[j] for j in range(k+2,n+1)]
|
|
351
|
+
self.beta[k+1] = [[self.b_lower] + numpy.roots([v(gnk[i]) for i in range(len(gnk))].reverse()).tolist().sort() + [self.b_upper] for v in self.Foo]
|
|
352
|
+
|
|
353
|
+
# Now to really initialize gnk.
|
|
354
|
+
self.gnk[k+1] = [[0] + [binomial(j,k+1)*v(a[j])
|
|
355
|
+
for j in range(k+2,m+1)] for v in self.Foo]
|
|
356
|
+
else:
|
|
357
|
+
# Bad input!
|
|
358
|
+
raise ValueError("a has length %s > m+1" % len(a))
|
|
359
|
+
|
|
360
|
+
def incr(self, f_out, verbose=False, haltk=0):
|
|
361
|
+
r"""
|
|
362
|
+
'Increment' the totally real data to the next
|
|
363
|
+
value which satisfies the bounds essentially given by Rolle's
|
|
364
|
+
theorem, and return the next polynomial in the sequence
|
|
365
|
+
``f_out``.
|
|
366
|
+
|
|
367
|
+
The default or usual case just increments the constant
|
|
368
|
+
coefficient; then inductively, if this is outside of the
|
|
369
|
+
bounds we increment the next higher coefficient, and so on.
|
|
370
|
+
|
|
371
|
+
If there are no more coefficients to be had, returns the zero
|
|
372
|
+
polynomial.
|
|
373
|
+
|
|
374
|
+
INPUT:
|
|
375
|
+
|
|
376
|
+
- ``f_out`` -- integer sequence; to be written with the coefficients of
|
|
377
|
+
the next polynomial
|
|
378
|
+
- ``verbose`` -- boolean or nonnegative integer (default: ``False``);
|
|
379
|
+
print verbosely computational details. It prints extra information if
|
|
380
|
+
``verbose`` is set to ``2`` or more.
|
|
381
|
+
- ``haltk`` -- integer; the level at which to halt the inductive
|
|
382
|
+
coefficient bounds
|
|
383
|
+
|
|
384
|
+
OUTPUT: the successor polynomial as a coefficient list
|
|
385
|
+
"""
|
|
386
|
+
import numpy
|
|
387
|
+
|
|
388
|
+
m = self.m
|
|
389
|
+
k = self.k
|
|
390
|
+
d = self.d
|
|
391
|
+
|
|
392
|
+
# If k == -1, we have a full polynomial, so we add 1 to the constant coefficient.
|
|
393
|
+
if k == -1:
|
|
394
|
+
if len(self.amaxvals[0]) > 0 and self.amaxvals[0]:
|
|
395
|
+
self.a[0] = self.amaxvals[0].pop()
|
|
396
|
+
for i in range(0,m):
|
|
397
|
+
f_out[i] = self.a[i]
|
|
398
|
+
return
|
|
399
|
+
else:
|
|
400
|
+
if verbose:
|
|
401
|
+
print(" finished")
|
|
402
|
+
|
|
403
|
+
# Already reached maximum, so "carry the 1" to find the next value of k.
|
|
404
|
+
k += 1
|
|
405
|
+
while k < m and len(self.amaxvals[k]) == 0:
|
|
406
|
+
k += 1
|
|
407
|
+
if k < m:
|
|
408
|
+
self.a[k] = self.amaxvals[k].pop()
|
|
409
|
+
k -= 1
|
|
410
|
+
|
|
411
|
+
# If we are working through an initialization routine, treat that.
|
|
412
|
+
elif haltk and k == haltk-1:
|
|
413
|
+
if len(self.maxvals[k]) == 0:
|
|
414
|
+
k += 1
|
|
415
|
+
while k <= m-1 and len(self.amaxvals[k]) == 0:
|
|
416
|
+
k += 1
|
|
417
|
+
if k < m:
|
|
418
|
+
self.a[k] = self.amaxvals[k].pop()
|
|
419
|
+
k -= 1
|
|
420
|
+
|
|
421
|
+
# If in the previous step we finished all possible values of
|
|
422
|
+
# the lastmost coefficient, so we must compute bounds on the next coefficient.
|
|
423
|
+
# Recall k == n-1 implies iteration is complete.
|
|
424
|
+
while k < m-1:
|
|
425
|
+
# maxoutflag flags a required abort along the way
|
|
426
|
+
maxoutflag = False
|
|
427
|
+
|
|
428
|
+
# Recall k == -1 means all coefficients are good to go.
|
|
429
|
+
while k >= 0 and (not haltk or k >= haltk):
|
|
430
|
+
if verbose:
|
|
431
|
+
print(k, ":", end="")
|
|
432
|
+
for i in range(self.m + 1):
|
|
433
|
+
print(self.a[i], end="")
|
|
434
|
+
print("")
|
|
435
|
+
|
|
436
|
+
if k == m - 2:
|
|
437
|
+
# We only know the value of a[n-1], the trace.
|
|
438
|
+
bl = max(math.ceil(1.7719*self.n), ((self.a[m-1]**2).trace()*1./m))
|
|
439
|
+
br = 1./m*(self.a[m-1]**2).trace() + \
|
|
440
|
+
self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d))
|
|
441
|
+
br = math.floor(br)
|
|
442
|
+
|
|
443
|
+
# Check for trivially empty.
|
|
444
|
+
if bl > br:
|
|
445
|
+
if verbose:
|
|
446
|
+
print(" ", br, ">", bl)
|
|
447
|
+
maxoutflag = 1
|
|
448
|
+
break
|
|
449
|
+
|
|
450
|
+
if verbose >= 2:
|
|
451
|
+
print(" bl, br:", bl, br)
|
|
452
|
+
|
|
453
|
+
# Enumerate all elements of Z_F with T_2 <= br
|
|
454
|
+
T2s = []
|
|
455
|
+
trace_elts_found = False
|
|
456
|
+
for tre in self.trace_elts:
|
|
457
|
+
if tre[0] <= bl and tre[1] >= br:
|
|
458
|
+
trace_elts_found = True
|
|
459
|
+
if verbose >= 2:
|
|
460
|
+
print(" found copy!")
|
|
461
|
+
T2s.extend(theta for theta in tre[2]
|
|
462
|
+
if bl <= theta.trace() <= br)
|
|
463
|
+
break
|
|
464
|
+
if not trace_elts_found:
|
|
465
|
+
T2s = self.F._positive_integral_elements_with_trace([bl,br])
|
|
466
|
+
self.trace_elts.append([bl,br,T2s])
|
|
467
|
+
|
|
468
|
+
# Now ensure that T2 satisfies the correct parity condition
|
|
469
|
+
am2s = []
|
|
470
|
+
for t2 in T2s:
|
|
471
|
+
am2 = (self.a[m-1]**2-t2)/2
|
|
472
|
+
if am2.is_integral():
|
|
473
|
+
ispositive = True
|
|
474
|
+
for v in self.Foo:
|
|
475
|
+
ispositive = ispositive and v((m-1)*self.a[m-1]**2-2*m*am2) > 0
|
|
476
|
+
if ispositive:
|
|
477
|
+
am2s.append(am2)
|
|
478
|
+
|
|
479
|
+
if verbose >= 2:
|
|
480
|
+
print(" am2s:", am2s)
|
|
481
|
+
|
|
482
|
+
# If none survive, break!
|
|
483
|
+
if len(am2s) == 0:
|
|
484
|
+
if verbose:
|
|
485
|
+
print(" finished")
|
|
486
|
+
maxoutflag = 1
|
|
487
|
+
break
|
|
488
|
+
|
|
489
|
+
self.amaxvals[m-2] = am2s
|
|
490
|
+
self.a[m-2] = self.amaxvals[m-2].pop()
|
|
491
|
+
|
|
492
|
+
# Initialize the second derivative.
|
|
493
|
+
self.b_lower = [-1./m*(v(self.a[m-1]) +
|
|
494
|
+
(m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
|
|
495
|
+
self.b_upper = [-1./m*(v(self.a[m-1]) -
|
|
496
|
+
(m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
|
|
497
|
+
self.beta[k] = [[self.b_lower[i], -self.Foo[i](self.a[m-1])/m, self.b_upper[i]] for i in range(d)]
|
|
498
|
+
self.gnk[k] = [0, (m-1)*self.a[m-1], m*(m-1)/2]
|
|
499
|
+
|
|
500
|
+
if verbose >= 2:
|
|
501
|
+
print(" betak:", self.beta[k])
|
|
502
|
+
else:
|
|
503
|
+
# Compute the roots of the derivative.
|
|
504
|
+
self.gnk[k+1][0] = self.a[k+1]
|
|
505
|
+
gnk = self.gnk[k+1]
|
|
506
|
+
self.beta[k] = [numpy.roots([v(gnk[len(gnk)-1-i]) for i in range(len(gnk))]).tolist() for v in self.Foo]
|
|
507
|
+
|
|
508
|
+
try:
|
|
509
|
+
for i in range(d):
|
|
510
|
+
self.beta[k][i].sort()
|
|
511
|
+
except TypeError:
|
|
512
|
+
if verbose:
|
|
513
|
+
print(" betak:", self.beta[k])
|
|
514
|
+
maxoutflag = True
|
|
515
|
+
break
|
|
516
|
+
|
|
517
|
+
# Check for double roots
|
|
518
|
+
for i in range(len(self.beta[k][0])-1):
|
|
519
|
+
if abs(self.beta[k][0][i] - self.beta[k][0][i+1]) < 2*eps_global:
|
|
520
|
+
# This happens reasonably infrequently, so calling
|
|
521
|
+
# the Python routine should be sufficiently fast...
|
|
522
|
+
f = self.Fx(self.gnk[k+1])
|
|
523
|
+
df = self.Fx(self.gnk[k+2])
|
|
524
|
+
if gcd(f,df) != 1:
|
|
525
|
+
if verbose:
|
|
526
|
+
print(" gnk has multiple factor!")
|
|
527
|
+
maxoutflag = True
|
|
528
|
+
break
|
|
529
|
+
if maxoutflag:
|
|
530
|
+
break
|
|
531
|
+
|
|
532
|
+
if k == m-3:
|
|
533
|
+
self.b_lower = [-1./m*(v(self.a[m-1]) +
|
|
534
|
+
(m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
|
|
535
|
+
self.b_upper = [-1./m*(v(self.a[m-1]) -
|
|
536
|
+
(m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
|
|
537
|
+
elif k == m-4:
|
|
538
|
+
# New bounds from Lagrange multiplier in degree 3.
|
|
539
|
+
bminmax = [lagrange_degree_3(m,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo]
|
|
540
|
+
self.b_lower = [bminmax[i][0] for i in range(len(bminmax))]
|
|
541
|
+
self.b_upper = [bminmax[i][1] for i in range(len(bminmax))]
|
|
542
|
+
|
|
543
|
+
self.beta[k] = [[self.b_lower[i]] + self.beta[k][i] + [self.b_upper[i]] for i in range(len(self.beta[k]))]
|
|
544
|
+
|
|
545
|
+
if verbose >= 2:
|
|
546
|
+
print(" betak:", self.beta[k])
|
|
547
|
+
|
|
548
|
+
# Compute next g_(m-(k+1)), k times the formal integral of g_(m-k).
|
|
549
|
+
self.gnk[k] = [self.F.primitive_element()*0] + [self.gnk[k+1][i-1]*(k+1)/i for i in range(1,m-k+1)]
|
|
550
|
+
gnk = self.gnk[k]
|
|
551
|
+
gnks = [[v(gnk[len(gnk)-1-i])
|
|
552
|
+
for i in range(len(gnk))]
|
|
553
|
+
for v in self.Foo]
|
|
554
|
+
gnkm1 = self.gnk[k+1]
|
|
555
|
+
gnkm1s = [[v(gnkm1[len(gnkm1)-1-i])
|
|
556
|
+
for i in range(len(gnkm1))]
|
|
557
|
+
for v in self.Foo]
|
|
558
|
+
mk = m - (k + 1)
|
|
559
|
+
|
|
560
|
+
if verbose >= 2:
|
|
561
|
+
print(" gnk:", self.gnk[k])
|
|
562
|
+
print(" gnks:", gnks)
|
|
563
|
+
|
|
564
|
+
# Compute upper and lower bounds which guarantee one retains
|
|
565
|
+
# a polynomial with all real roots.
|
|
566
|
+
betak = self.beta[k]
|
|
567
|
+
akmin = [-numpy.polyval(gnks[j], betak[j][mk+1]) -
|
|
568
|
+
abs(numpy.polyval(gnkm1s[j], betak[j][mk+1]))*eps_global for j in range(self.d)]
|
|
569
|
+
for i in range(1,(mk+1)//2+1):
|
|
570
|
+
# Use the fact that f(z) <= f(x)+|f'(x)|eps if |x-z| < eps
|
|
571
|
+
# for sufficiently small eps, f(z) = 0, and f''(z) < 0.
|
|
572
|
+
akmin = [max(akmin[j],
|
|
573
|
+
-numpy.polyval(gnks[j], betak[j][mk+1-2*i]) -
|
|
574
|
+
abs(numpy.polyval(gnkm1s[j], betak[j][mk+1-2*i])*eps_global)) for j in range(self.d)]
|
|
575
|
+
|
|
576
|
+
akmax = [-numpy.polyval(gnks[j], betak[j][mk]) +
|
|
577
|
+
abs(numpy.polyval(gnkm1s[j], betak[j][mk]))*eps_global for j in range(self.d)]
|
|
578
|
+
for i in range(1, mk//2+1):
|
|
579
|
+
akmax = [min(akmax[j],
|
|
580
|
+
-numpy.polyval(gnks[j], betak[j][mk-2*i]) +
|
|
581
|
+
abs(numpy.polyval(gnkm1s[j], betak[j][mk-2*i])*eps_global)) for j in range(self.d)]
|
|
582
|
+
|
|
583
|
+
if verbose >= 2:
|
|
584
|
+
print(" akmin:", akmin)
|
|
585
|
+
print(" akmax:", akmax)
|
|
586
|
+
|
|
587
|
+
for i in range(self.d):
|
|
588
|
+
if akmin[i] > akmax[i]:
|
|
589
|
+
if verbose:
|
|
590
|
+
print(" ", akmin[i], ">", akmax[i])
|
|
591
|
+
maxoutflag = 1
|
|
592
|
+
break
|
|
593
|
+
if maxoutflag:
|
|
594
|
+
break
|
|
595
|
+
|
|
596
|
+
self.amaxvals[k] = integral_elements_in_box(self.F, [[akmin[i],akmax[i]] for i in range(d)])
|
|
597
|
+
if k == 0:
|
|
598
|
+
a0s = [0, -sum([self.a[i] for i in range(1,m+1)]),
|
|
599
|
+
-sum([self.a[i]*(-1)**i for i in range(1,m+1)]),
|
|
600
|
+
-sum([self.a[i]*2**i for i in range(1,m+1)]),
|
|
601
|
+
-sum([self.a[i]*(-2)**i for i in range(1,m+1)])]
|
|
602
|
+
for a0 in a0s:
|
|
603
|
+
try:
|
|
604
|
+
self.amaxvals[0].remove(a0)
|
|
605
|
+
except Exception:
|
|
606
|
+
pass
|
|
607
|
+
|
|
608
|
+
if verbose:
|
|
609
|
+
print(" amaxvals[k]:", self.amaxvals[k])
|
|
610
|
+
if len(self.amaxvals[k]) == 0:
|
|
611
|
+
if verbose:
|
|
612
|
+
print(" finished")
|
|
613
|
+
maxoutflag = True
|
|
614
|
+
break
|
|
615
|
+
self.a[k] = self.amaxvals[k].pop()
|
|
616
|
+
|
|
617
|
+
self.k -= 1
|
|
618
|
+
k -= 1
|
|
619
|
+
|
|
620
|
+
if not maxoutflag:
|
|
621
|
+
self.k = k
|
|
622
|
+
for i in range(m):
|
|
623
|
+
f_out[i] = self.a[i]
|
|
624
|
+
return
|
|
625
|
+
else:
|
|
626
|
+
k += 1
|
|
627
|
+
while k < m and len(self.amaxvals[k]) == 0:
|
|
628
|
+
k += 1
|
|
629
|
+
if k < m:
|
|
630
|
+
self.a[k] = self.amaxvals[k].pop()
|
|
631
|
+
k -= 1
|
|
632
|
+
|
|
633
|
+
# k == n-1, so iteration is complete; return the zero polynomial (of degree n+1).
|
|
634
|
+
self.k = k
|
|
635
|
+
f_out[m] = 0
|
|
636
|
+
return
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
# ****************************************************************************
|
|
640
|
+
# Main routine
|
|
641
|
+
# ****************************************************************************
|
|
642
|
+
|
|
643
|
+
def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0,
|
|
644
|
+
return_seqs=False,
|
|
645
|
+
return_pari_objects=True):
|
|
646
|
+
r"""
|
|
647
|
+
This function enumerates (primitive) totally real field extensions of
|
|
648
|
+
degree `m>1` of the totally real field F with discriminant `d \leq B`;
|
|
649
|
+
optionally one can specify the first few coefficients, where the sequence ``a``
|
|
650
|
+
corresponds to a polynomial by
|
|
651
|
+
|
|
652
|
+
::
|
|
653
|
+
|
|
654
|
+
a[k]*x^m + ... + a[0]*x^(m-k)
|
|
655
|
+
|
|
656
|
+
if ``length(a) = k+1``, so in particular always ``a[k] = 1``.
|
|
657
|
+
|
|
658
|
+
.. NOTE::
|
|
659
|
+
|
|
660
|
+
This is guaranteed to give all primitive such fields, and
|
|
661
|
+
seems in practice to give many imprimitive ones.
|
|
662
|
+
|
|
663
|
+
INPUT:
|
|
664
|
+
|
|
665
|
+
- ``F`` -- number field; the base field
|
|
666
|
+
- ``m`` -- integer; the degree
|
|
667
|
+
- ``B`` -- integer; the discriminant bound
|
|
668
|
+
- ``a`` -- list (default: ``[]``); the coefficient list to begin with
|
|
669
|
+
- ``verbose`` -- boolean or nonnegative integer or string (default: 0);
|
|
670
|
+
give a verbose description of the computations being performed. If
|
|
671
|
+
``verbose`` is set to ``2`` or more then it outputs some extra
|
|
672
|
+
information. If ``verbose`` is a string then it outputs to a file
|
|
673
|
+
specified by ``verbose``.
|
|
674
|
+
- ``return_seqs`` -- boolean (default: ``False``); if ``True``, then return
|
|
675
|
+
the polynomials as sequences (for easier exporting to a file). This
|
|
676
|
+
also returns a list of four numbers, as explained in the OUTPUT
|
|
677
|
+
section below.
|
|
678
|
+
- ``return_pari_objects`` -- boolean (default: ``True``); if both
|
|
679
|
+
``return_seqs`` and ``return_pari_objects`` are ``False`` then it returns
|
|
680
|
+
the elements as Sage objects; otherwise it returns PARI objects.
|
|
681
|
+
|
|
682
|
+
OUTPUT:
|
|
683
|
+
|
|
684
|
+
- the list of fields with entries ``[d,fabs,f]``, where ``d`` is the
|
|
685
|
+
discriminant, ``fabs`` is an absolute defining polynomial, and ``f``
|
|
686
|
+
is a defining polynomial relative to `F`, sorted by discriminant.
|
|
687
|
+
|
|
688
|
+
- if ``return_seqs`` is ``True``, then the first field of the list is
|
|
689
|
+
a list containing the count of four items as explained below
|
|
690
|
+
|
|
691
|
+
- the first entry gives the number of polynomials tested
|
|
692
|
+
- the second entry gives the number of polynomials with its
|
|
693
|
+
discriminant having a large enough square divisor
|
|
694
|
+
- the third entry is the number of irreducible polynomials
|
|
695
|
+
- the fourth entry is the number of irreducible polynomials with
|
|
696
|
+
discriminant at most `B`
|
|
697
|
+
|
|
698
|
+
EXAMPLES::
|
|
699
|
+
|
|
700
|
+
sage: ZZx.<x> = ZZ[]
|
|
701
|
+
sage: F.<t> = NumberField(x^2 - 2)
|
|
702
|
+
sage: enumerate_totallyreal_fields_rel(F, 1, 2000)
|
|
703
|
+
[[1, [-2, 0, 1], xF - 1]]
|
|
704
|
+
sage: enumerate_totallyreal_fields_rel(F, 2, 2000)
|
|
705
|
+
[[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]]
|
|
706
|
+
sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)
|
|
707
|
+
[[9, 6, 5, 0], [[1600, [4, 0, -6, 0, 1], [-1, 1, 1]]]]
|
|
708
|
+
|
|
709
|
+
TESTS:
|
|
710
|
+
|
|
711
|
+
Each of the outputs must be elements of Sage if ``return_pari_objects``
|
|
712
|
+
is set to ``False``::
|
|
713
|
+
|
|
714
|
+
sage: type(enumerate_totallyreal_fields_rel(F, 2, 2000)[0][1])
|
|
715
|
+
<class 'cypari2.gen.Gen'>
|
|
716
|
+
sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][0].parent()
|
|
717
|
+
Integer Ring
|
|
718
|
+
sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][1].parent()
|
|
719
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
720
|
+
sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][2].parent()
|
|
721
|
+
Univariate Polynomial Ring in xF over Number Field in t with defining polynomial x^2 - 2
|
|
722
|
+
sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)[1][0][1][0].parent()
|
|
723
|
+
Rational Field
|
|
724
|
+
|
|
725
|
+
AUTHORS:
|
|
726
|
+
|
|
727
|
+
- John Voight (2007-11-01)
|
|
728
|
+
"""
|
|
729
|
+
|
|
730
|
+
if not isinstance(m, Integer):
|
|
731
|
+
try:
|
|
732
|
+
m = Integer(m)
|
|
733
|
+
except TypeError:
|
|
734
|
+
raise TypeError("cannot coerce m (= %s) to an integer" % m)
|
|
735
|
+
if (m < 1):
|
|
736
|
+
raise ValueError("m must be at least 1.")
|
|
737
|
+
|
|
738
|
+
n = F.degree()*m
|
|
739
|
+
|
|
740
|
+
# Initialize
|
|
741
|
+
S = {} # dictionary of the form {(d, fabs): f, ...}
|
|
742
|
+
dB_odlyzko = odlyzko_bound_totallyreal(n)
|
|
743
|
+
dB = math.ceil(40000*dB_odlyzko**n)
|
|
744
|
+
counts = [0,0,0,0]
|
|
745
|
+
|
|
746
|
+
# Trivial case
|
|
747
|
+
if m == 1:
|
|
748
|
+
g = pari(F.defining_polynomial()).polrecip().Vec()
|
|
749
|
+
if return_seqs:
|
|
750
|
+
return [[0,0,0,0], [1, [-1, 1], g]]
|
|
751
|
+
elif return_pari_objects:
|
|
752
|
+
return [[1, g, pari('xF-1')]]
|
|
753
|
+
else:
|
|
754
|
+
Px = PolynomialRing(QQ, 'xF')
|
|
755
|
+
return [[ZZ(1), [QQ(_) for _ in g], Px.gen()-1]]
|
|
756
|
+
|
|
757
|
+
if verbose:
|
|
758
|
+
saveout = sys.stdout
|
|
759
|
+
if isinstance(verbose, str):
|
|
760
|
+
fsock = open(verbose, 'w')
|
|
761
|
+
sys.stdout = fsock
|
|
762
|
+
# Else, print to screen
|
|
763
|
+
f_out = [0]*m + [1]
|
|
764
|
+
T = tr_data_rel(F, m, B, a)
|
|
765
|
+
if verbose == 2:
|
|
766
|
+
T.incr(f_out,verbose)
|
|
767
|
+
else:
|
|
768
|
+
T.incr(f_out)
|
|
769
|
+
|
|
770
|
+
Fx = PolynomialRing(F, 'xF')
|
|
771
|
+
|
|
772
|
+
nfF = pari(str(F.defining_polynomial()).replace('x',
|
|
773
|
+
str(F.primitive_element())))
|
|
774
|
+
parit = pari(str(F.primitive_element()))
|
|
775
|
+
|
|
776
|
+
while f_out[m] != 0:
|
|
777
|
+
counts[0] += 1
|
|
778
|
+
if verbose:
|
|
779
|
+
print("==>", f_out, end="")
|
|
780
|
+
|
|
781
|
+
f_str = ''
|
|
782
|
+
for i in range(len(f_out)):
|
|
783
|
+
f_str += '(' + str(f_out[i]) + ')*x^' + str(i)
|
|
784
|
+
if i < len(f_out)-1:
|
|
785
|
+
f_str += '+'
|
|
786
|
+
nf = pari(f_str)
|
|
787
|
+
if nf.poldegree('t') == 0:
|
|
788
|
+
nf = nf.subst('x', 'x-t')
|
|
789
|
+
nf = nf.polresultant(nfF, parit) # either monic or -monic
|
|
790
|
+
if nf[n] == -1:
|
|
791
|
+
nf *= -1
|
|
792
|
+
d = nf.poldisc()
|
|
793
|
+
#counts[0] += 1
|
|
794
|
+
if d > 0 and nf.polsturm() == n:
|
|
795
|
+
da = int_has_small_square_divisor(Integer(d))
|
|
796
|
+
if d > dB or d <= B*da:
|
|
797
|
+
counts[1] += 1
|
|
798
|
+
if nf.polisirreducible():
|
|
799
|
+
counts[2] += 1
|
|
800
|
+
zk, d = nf.nfbasis_d()
|
|
801
|
+
|
|
802
|
+
if d <= B:
|
|
803
|
+
if verbose:
|
|
804
|
+
print("has discriminant", d, end="")
|
|
805
|
+
|
|
806
|
+
# Find a minimal lattice element
|
|
807
|
+
counts[3] += 1
|
|
808
|
+
ng = pari([nf,zk]).polredabs()
|
|
809
|
+
|
|
810
|
+
# Check if K is contained in the list.
|
|
811
|
+
if (d, ng) in S:
|
|
812
|
+
if verbose:
|
|
813
|
+
print("but is not new")
|
|
814
|
+
else:
|
|
815
|
+
if verbose:
|
|
816
|
+
print("and is new!")
|
|
817
|
+
S[(d, ng)] = Fx(f_out)
|
|
818
|
+
else:
|
|
819
|
+
if verbose:
|
|
820
|
+
print("has discriminant", abs(d), "> B")
|
|
821
|
+
else:
|
|
822
|
+
if verbose:
|
|
823
|
+
print("is not absolutely irreducible")
|
|
824
|
+
else:
|
|
825
|
+
if verbose:
|
|
826
|
+
print("has discriminant", abs(d), "with no large enough square divisor")
|
|
827
|
+
else:
|
|
828
|
+
if verbose:
|
|
829
|
+
if d == 0:
|
|
830
|
+
print("is not squarefree")
|
|
831
|
+
else:
|
|
832
|
+
print("is not totally real")
|
|
833
|
+
if verbose == 2:
|
|
834
|
+
T.incr(f_out,verbose=verbose)
|
|
835
|
+
else:
|
|
836
|
+
T.incr(f_out)
|
|
837
|
+
|
|
838
|
+
# In the application of Smyth's theorem above, we exclude finitely
|
|
839
|
+
# many possibilities which we must now throw back in.
|
|
840
|
+
if m == 2:
|
|
841
|
+
if Fx([-1,1,1]).is_irreducible():
|
|
842
|
+
K = F.extension(Fx([-1,1,1]), 'tK')
|
|
843
|
+
Kabs = K.absolute_field('tKabs')
|
|
844
|
+
Kabs_pari = pari(Kabs.defining_polynomial())
|
|
845
|
+
d = K.absolute_discriminant()
|
|
846
|
+
if abs(d) <= B:
|
|
847
|
+
ng = Kabs_pari.polredabs()
|
|
848
|
+
S[(d, ng)] = Fx([-1,1,1])
|
|
849
|
+
elif F.degree() == 2:
|
|
850
|
+
for ff in [[1,-7,13,-7,1],[1,-8,14,-7,1]]:
|
|
851
|
+
f = Fx(ff).factor()[0][0]
|
|
852
|
+
K = F.extension(f, 'tK')
|
|
853
|
+
Kabs = K.absolute_field('tKabs')
|
|
854
|
+
Kabs_pari = pari(Kabs.defining_polynomial())
|
|
855
|
+
d = K.absolute_discriminant()
|
|
856
|
+
if abs(d) <= B:
|
|
857
|
+
ng = Kabs_pari.polredabs()
|
|
858
|
+
S[(d, ng)] = f
|
|
859
|
+
elif m == 3:
|
|
860
|
+
if Fx([-1, 6, -5, 1]).is_irreducible():
|
|
861
|
+
K = F.extension(Fx([-1, 6, -5, 1]), 'tK')
|
|
862
|
+
Kabs = K.absolute_field('tKabs')
|
|
863
|
+
Kabs_pari = pari(Kabs.defining_polynomial())
|
|
864
|
+
d = K.absolute_discriminant()
|
|
865
|
+
if abs(d) <= B:
|
|
866
|
+
ng = Kabs_pari.polredabs()
|
|
867
|
+
S[(d, ng)] = Fx([-1, 6, -5, 1])
|
|
868
|
+
|
|
869
|
+
# Convert S to a sorted list of triples [d, fabs, f], taking care
|
|
870
|
+
# not to use the comparison operators on PARI polynomials.
|
|
871
|
+
S = [[s[0], s[1], t] for s, t in S.items()]
|
|
872
|
+
S.sort(key=lambda x: (x[0], [QQ(cf) for cf in x[1].polrecip().Vec()]))
|
|
873
|
+
|
|
874
|
+
# Now check for isomorphic fields
|
|
875
|
+
weed_fields(S)
|
|
876
|
+
|
|
877
|
+
# Output.
|
|
878
|
+
if verbose:
|
|
879
|
+
print("=" * 80)
|
|
880
|
+
print("Polynomials tested: {}".format(counts[0]))
|
|
881
|
+
print("Polynomials with discriminant with large enough square"
|
|
882
|
+
" divisor: {}".format(counts[1]))
|
|
883
|
+
print("Irreducible polynomials: {}".format(counts[2]))
|
|
884
|
+
print("Polynomials with nfdisc <= B: {}".format(counts[3]))
|
|
885
|
+
for i in range(len(S)):
|
|
886
|
+
print(S[i])
|
|
887
|
+
if isinstance(verbose, str):
|
|
888
|
+
fsock.close()
|
|
889
|
+
sys.stdout = saveout
|
|
890
|
+
|
|
891
|
+
# Make sure to return elements that belong to Sage
|
|
892
|
+
if return_seqs:
|
|
893
|
+
return [[ZZ(x) for x in counts],
|
|
894
|
+
[[s[0], [QQ(x) for x in s[1].polrecip().Vec()],
|
|
895
|
+
s[2].coefficients(sparse=False)]
|
|
896
|
+
for s in S]]
|
|
897
|
+
elif return_pari_objects:
|
|
898
|
+
return S
|
|
899
|
+
else:
|
|
900
|
+
Px = PolynomialRing(QQ, 'x')
|
|
901
|
+
return [[s[0], Px([QQ(_) for _ in s[1].list()]), s[2]] for s in S]
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False,
|
|
905
|
+
return_pari_objects=True):
|
|
906
|
+
r"""
|
|
907
|
+
Enumerate *all* totally real fields of degree ``n`` with discriminant
|
|
908
|
+
at most ``B``, primitive or otherwise.
|
|
909
|
+
|
|
910
|
+
INPUT:
|
|
911
|
+
|
|
912
|
+
- ``n`` -- integer; the degree
|
|
913
|
+
- ``B`` -- integer; the discriminant bound
|
|
914
|
+
- ``verbose`` -- boolean or nonnegative integer or string (default: 0);
|
|
915
|
+
give a verbose description of the computations being performed. If
|
|
916
|
+
``verbose`` is set to ``2`` or more, it outputs some extra information.
|
|
917
|
+
If ``verbose`` is a string, it outputs to a file specified by ``verbose``.
|
|
918
|
+
- ``return_seqs`` -- boolean (default: ``False``); if ``True``, then return
|
|
919
|
+
the polynomials as sequences (for easier exporting to a file). This
|
|
920
|
+
also returns a list of four numbers, as explained in the OUTPUT
|
|
921
|
+
section below.
|
|
922
|
+
- ``return_pari_objects`` -- boolean (default: ``True``); if both
|
|
923
|
+
``return_seqs`` and ``return_pari_objects`` are ``False`` then it
|
|
924
|
+
returns the elements as Sage objects; otherwise it returns PARI objects.
|
|
925
|
+
|
|
926
|
+
EXAMPLES::
|
|
927
|
+
|
|
928
|
+
sage: enumerate_totallyreal_fields_all(4, 2000)
|
|
929
|
+
[[725, x^4 - x^3 - 3*x^2 + x + 1],
|
|
930
|
+
[1125, x^4 - x^3 - 4*x^2 + 4*x + 1],
|
|
931
|
+
[1600, x^4 - 6*x^2 + 4],
|
|
932
|
+
[1957, x^4 - 4*x^2 - x + 1],
|
|
933
|
+
[2000, x^4 - 5*x^2 + 5]]
|
|
934
|
+
sage: enumerate_totallyreal_fields_all(1, 10)
|
|
935
|
+
[[1, x - 1]]
|
|
936
|
+
|
|
937
|
+
TESTS:
|
|
938
|
+
|
|
939
|
+
Each of the outputs must be elements of Sage if ``return_pari_objects``
|
|
940
|
+
is set to ``False``::
|
|
941
|
+
|
|
942
|
+
sage: enumerate_totallyreal_fields_all(2, 10)
|
|
943
|
+
[[5, x^2 - x - 1], [8, x^2 - 2]]
|
|
944
|
+
sage: type(enumerate_totallyreal_fields_all(2, 10)[0][1])
|
|
945
|
+
<class 'cypari2.gen.Gen'>
|
|
946
|
+
sage: enumerate_totallyreal_fields_all(2, 10, return_pari_objects=False)[0][1].parent()
|
|
947
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
948
|
+
|
|
949
|
+
In practice most of these will be found by
|
|
950
|
+
:func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`,
|
|
951
|
+
which is guaranteed to return all primitive fields but often returns
|
|
952
|
+
many non-primitive ones as well. For instance, only one of the five
|
|
953
|
+
fields in the example above is primitive, but
|
|
954
|
+
:func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`
|
|
955
|
+
finds four out of the five (the exception being `x^4 - 6x^2 + 4`).
|
|
956
|
+
|
|
957
|
+
The following was fixed in :issue:`13101`::
|
|
958
|
+
|
|
959
|
+
sage: enumerate_totallyreal_fields_all(8, 10^6) # long time (about 2 s)
|
|
960
|
+
[]
|
|
961
|
+
"""
|
|
962
|
+
S = []
|
|
963
|
+
counts = [0, 0, 0, 0]
|
|
964
|
+
div_n = divisors(n)
|
|
965
|
+
if len(div_n) > 4:
|
|
966
|
+
raise ValueError("Only implemented for n = p*q with p,q prime")
|
|
967
|
+
for d in div_n:
|
|
968
|
+
if 1 < d < n:
|
|
969
|
+
Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.*B)**(1.*d/n))), verbose=verbose)
|
|
970
|
+
for i in range(len(Sds)):
|
|
971
|
+
if verbose:
|
|
972
|
+
print("=" * 80)
|
|
973
|
+
print("Taking F =", Sds[i][1])
|
|
974
|
+
F = NumberField(ZZx(Sds[i][1]), 't')
|
|
975
|
+
T = enumerate_totallyreal_fields_rel(F, n/d, B, verbose=verbose, return_seqs=return_seqs)
|
|
976
|
+
if return_seqs:
|
|
977
|
+
for k in range(4):
|
|
978
|
+
counts[k] += T[0][k]
|
|
979
|
+
S += [[t[0],pari(t[1]).Polrev()] for t in T[1]]
|
|
980
|
+
else:
|
|
981
|
+
S += [[t[0],t[1]] for t in T]
|
|
982
|
+
for E in enumerate_totallyreal_fields_prim(n/d, int(math.floor((1.*B)**(1./d)/(1.*Sds[i][0])**(n*1./d**2)))):
|
|
983
|
+
for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')):
|
|
984
|
+
if EF.degree() == n and EF.disc() <= B:
|
|
985
|
+
S.append([EF.disc(), pari(EF.absolute_polynomial())])
|
|
986
|
+
S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose)
|
|
987
|
+
S.sort(key=lambda x: (x[0], [QQ(cf) for cf in x[1].polrecip().Vec()]))
|
|
988
|
+
weed_fields(S)
|
|
989
|
+
|
|
990
|
+
# Output.
|
|
991
|
+
if verbose:
|
|
992
|
+
saveout = sys.stdout
|
|
993
|
+
if isinstance(verbose, str):
|
|
994
|
+
fsock = open(verbose, 'w')
|
|
995
|
+
sys.stdout = fsock
|
|
996
|
+
# Else, print to screen
|
|
997
|
+
print("=" * 80)
|
|
998
|
+
print("Polynomials tested: {}".format(counts[0]))
|
|
999
|
+
print("Polynomials with discriminant with large enough square"
|
|
1000
|
+
" divisor: {}".format(counts[1]))
|
|
1001
|
+
print("Irreducible polynomials: {}".format(counts[2]))
|
|
1002
|
+
print("Polynomials with nfdisc <= B: {}".format(counts[3]))
|
|
1003
|
+
for i in range(len(S)):
|
|
1004
|
+
print(S[i])
|
|
1005
|
+
if isinstance(verbose, str):
|
|
1006
|
+
fsock.close()
|
|
1007
|
+
sys.stdout = saveout
|
|
1008
|
+
|
|
1009
|
+
# Make sure to return elements that belong to Sage
|
|
1010
|
+
if return_seqs:
|
|
1011
|
+
return [[ZZ(_) for _ in counts],
|
|
1012
|
+
[[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]] for s in S]]
|
|
1013
|
+
elif return_pari_objects:
|
|
1014
|
+
return S
|
|
1015
|
+
else:
|
|
1016
|
+
Px = PolynomialRing(QQ, 'x')
|
|
1017
|
+
return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])]
|
|
1018
|
+
for s in S]
|