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,427 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
# sage.doctest: needs sage.libs.pari sage.modules
|
|
3
|
+
"""
|
|
4
|
+
Automorphisms of Quadratic Forms
|
|
5
|
+
"""
|
|
6
|
+
# ****************************************************************************
|
|
7
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
8
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
9
|
+
# the License, or (at your option) any later version.
|
|
10
|
+
# https://www.gnu.org/licenses/
|
|
11
|
+
# ****************************************************************************
|
|
12
|
+
from sage.misc.cachefunc import cached_method
|
|
13
|
+
from sage.matrix.constructor import Matrix
|
|
14
|
+
from sage.rings.integer_ring import ZZ
|
|
15
|
+
|
|
16
|
+
from sage.modules.free_module import FreeModule
|
|
17
|
+
from sage.modules.free_module_element import vector
|
|
18
|
+
from sage.arith.misc import GCD
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@cached_method
|
|
22
|
+
def basis_of_short_vectors(self, show_lengths=False):
|
|
23
|
+
r"""
|
|
24
|
+
Return a basis for `\ZZ^n` made of vectors with minimal lengths `Q(v)`.
|
|
25
|
+
|
|
26
|
+
OUTPUT: a tuple of vectors, and optionally a tuple of values for each vector
|
|
27
|
+
|
|
28
|
+
This uses :pari:`qfminim`.
|
|
29
|
+
|
|
30
|
+
EXAMPLES::
|
|
31
|
+
|
|
32
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
|
|
33
|
+
sage: Q.basis_of_short_vectors()
|
|
34
|
+
((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
|
|
35
|
+
sage: Q.basis_of_short_vectors(True)
|
|
36
|
+
(((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)), (1, 3, 5, 7))
|
|
37
|
+
|
|
38
|
+
The returned vectors are immutable::
|
|
39
|
+
|
|
40
|
+
sage: v = Q.basis_of_short_vectors()[0]
|
|
41
|
+
sage: v
|
|
42
|
+
(1, 0, 0, 0)
|
|
43
|
+
sage: v[0] = 0
|
|
44
|
+
Traceback (most recent call last):
|
|
45
|
+
...
|
|
46
|
+
ValueError: vector is immutable; please change a copy instead (use copy())
|
|
47
|
+
"""
|
|
48
|
+
# Set an upper bound for the number of vectors to consider
|
|
49
|
+
Max_number_of_vectors = 10000
|
|
50
|
+
|
|
51
|
+
# Generate a PARI matrix for the associated Hessian matrix
|
|
52
|
+
M_pari = self.__pari__()
|
|
53
|
+
|
|
54
|
+
# Run through all possible minimal lengths to find a spanning set of vectors
|
|
55
|
+
n = self.dim()
|
|
56
|
+
M1 = Matrix([[0]])
|
|
57
|
+
vec_len = 0
|
|
58
|
+
while M1.rank() < n:
|
|
59
|
+
vec_len += 1
|
|
60
|
+
pari_mat = M_pari.qfminim(vec_len, Max_number_of_vectors)[2]
|
|
61
|
+
number_of_vecs = ZZ(pari_mat.matsize()[1])
|
|
62
|
+
vector_list = []
|
|
63
|
+
for i in range(number_of_vecs):
|
|
64
|
+
new_vec = vector([ZZ(x) for x in list(pari_mat[i])])
|
|
65
|
+
vector_list.append(new_vec)
|
|
66
|
+
|
|
67
|
+
# Make a matrix from the short vectors
|
|
68
|
+
if vector_list:
|
|
69
|
+
M1 = Matrix(vector_list)
|
|
70
|
+
|
|
71
|
+
# Organize these vectors by length (and also introduce their negatives)
|
|
72
|
+
max_len = vec_len // 2
|
|
73
|
+
vector_list_by_length = [[] for _ in range(max_len + 1)]
|
|
74
|
+
for v in vector_list:
|
|
75
|
+
l = self(v)
|
|
76
|
+
vector_list_by_length[l].append(v)
|
|
77
|
+
vector_list_by_length[l].append(vector([-x for x in v]))
|
|
78
|
+
|
|
79
|
+
# Make a matrix from the column vectors (in order of ascending length).
|
|
80
|
+
sorted_list = [v for i in range(len(vector_list_by_length))
|
|
81
|
+
for v in vector_list_by_length[i]]
|
|
82
|
+
sorted_matrix = Matrix(sorted_list).transpose()
|
|
83
|
+
|
|
84
|
+
# Determine a basis of vectors of minimal length
|
|
85
|
+
pivots = sorted_matrix.pivots()
|
|
86
|
+
basis = tuple(sorted_matrix.column(i) for i in pivots)
|
|
87
|
+
for v in basis:
|
|
88
|
+
v.set_immutable()
|
|
89
|
+
|
|
90
|
+
# Return the appropriate result
|
|
91
|
+
if show_lengths:
|
|
92
|
+
pivot_lengths = tuple(self(v) for v in basis)
|
|
93
|
+
return basis, pivot_lengths
|
|
94
|
+
else:
|
|
95
|
+
return basis
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False):
|
|
99
|
+
"""
|
|
100
|
+
Return a list of lists of short vectors `v`, sorted by length, with
|
|
101
|
+
`Q(v) <` ``len_bound``.
|
|
102
|
+
|
|
103
|
+
INPUT:
|
|
104
|
+
|
|
105
|
+
- ``len_bound`` -- bound for the length of the vectors
|
|
106
|
+
|
|
107
|
+
- ``up_to_sign_flag`` -- boolean (default: ``False``); if set to ``True``,
|
|
108
|
+
then only one of the vectors of the pair `[v, -v]` is listed
|
|
109
|
+
|
|
110
|
+
OUTPUT:
|
|
111
|
+
|
|
112
|
+
A list of lists of vectors such that entry `[i]` contains all
|
|
113
|
+
vectors of length `i`.
|
|
114
|
+
|
|
115
|
+
EXAMPLES::
|
|
116
|
+
|
|
117
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
|
|
118
|
+
sage: Q.short_vector_list_up_to_length(3)
|
|
119
|
+
[[(0, 0, 0, 0)], [(1, 0, 0, 0), (-1, 0, 0, 0)], []]
|
|
120
|
+
sage: Q.short_vector_list_up_to_length(4)
|
|
121
|
+
[[(0, 0, 0, 0)],
|
|
122
|
+
[(1, 0, 0, 0), (-1, 0, 0, 0)],
|
|
123
|
+
[],
|
|
124
|
+
[(0, 1, 0, 0), (0, -1, 0, 0)]]
|
|
125
|
+
sage: Q.short_vector_list_up_to_length(5)
|
|
126
|
+
[[(0, 0, 0, 0)],
|
|
127
|
+
[(1, 0, 0, 0), (-1, 0, 0, 0)],
|
|
128
|
+
[],
|
|
129
|
+
[(0, 1, 0, 0), (0, -1, 0, 0)],
|
|
130
|
+
[(1, 1, 0, 0),
|
|
131
|
+
(-1, -1, 0, 0),
|
|
132
|
+
(1, -1, 0, 0),
|
|
133
|
+
(-1, 1, 0, 0),
|
|
134
|
+
(2, 0, 0, 0),
|
|
135
|
+
(-2, 0, 0, 0)]]
|
|
136
|
+
sage: Q.short_vector_list_up_to_length(5, True)
|
|
137
|
+
[[(0, 0, 0, 0)],
|
|
138
|
+
[(1, 0, 0, 0)],
|
|
139
|
+
[],
|
|
140
|
+
[(0, 1, 0, 0)],
|
|
141
|
+
[(1, 1, 0, 0), (1, -1, 0, 0), (2, 0, 0, 0)]]
|
|
142
|
+
sage: m6 = matrix(6, [2, 1, 1, 1, -1, -1, 1, 2, 1, 1, -1, -1,
|
|
143
|
+
....: 1, 1, 2, 0, -1, -1, 1, 1, 0, 2, 0, -1,
|
|
144
|
+
....: -1, -1, -1, 0, 2, 1, -1, -1, -1, -1, 1, 2])
|
|
145
|
+
sage: Q = QuadraticForm(m6)
|
|
146
|
+
sage: vs = Q.short_vector_list_up_to_length(8)
|
|
147
|
+
sage: [len(vs[i]) for i in range(len(vs))]
|
|
148
|
+
[1, 72, 270, 720, 936, 2160, 2214, 3600]
|
|
149
|
+
|
|
150
|
+
The cases of ``len_bound < 2`` led to exception or infinite runtime before.
|
|
151
|
+
|
|
152
|
+
::
|
|
153
|
+
|
|
154
|
+
sage: Q.short_vector_list_up_to_length(-1)
|
|
155
|
+
[]
|
|
156
|
+
sage: Q.short_vector_list_up_to_length(0)
|
|
157
|
+
[]
|
|
158
|
+
sage: Q.short_vector_list_up_to_length(1)
|
|
159
|
+
[[(0, 0, 0, 0, 0, 0)]]
|
|
160
|
+
|
|
161
|
+
In the case of quadratic forms that are not positive definite an error is raised.
|
|
162
|
+
|
|
163
|
+
::
|
|
164
|
+
|
|
165
|
+
sage: QuadraticForm(matrix(2, [2, 0, 0, -2])).short_vector_list_up_to_length(3)
|
|
166
|
+
Traceback (most recent call last):
|
|
167
|
+
...
|
|
168
|
+
ValueError: Quadratic form must be positive definite in order to enumerate short vectors
|
|
169
|
+
|
|
170
|
+
Check that PARI does not return vectors which are too long::
|
|
171
|
+
|
|
172
|
+
sage: Q = QuadraticForm(matrix(2, [72, 12, 12, 120]))
|
|
173
|
+
sage: len_bound_pari = 2*22953421 - 2; len_bound_pari
|
|
174
|
+
45906840
|
|
175
|
+
sage: vs = list(Q.__pari__().qfminim(len_bound_pari)[2]) # long time (18s on sage.math, 2014)
|
|
176
|
+
sage: v = vs[0]; v # long time
|
|
177
|
+
[66, -623]~
|
|
178
|
+
sage: v.Vec() * Q.__pari__() * v # long time
|
|
179
|
+
45902280
|
|
180
|
+
"""
|
|
181
|
+
if not self.is_positive_definite():
|
|
182
|
+
raise ValueError("Quadratic form must be positive definite "
|
|
183
|
+
"in order to enumerate short vectors")
|
|
184
|
+
|
|
185
|
+
from sage.libs.pari import pari
|
|
186
|
+
|
|
187
|
+
if len_bound <= 0:
|
|
188
|
+
return []
|
|
189
|
+
|
|
190
|
+
# Free module in which the vectors live
|
|
191
|
+
V = FreeModule(ZZ, self.dim())
|
|
192
|
+
|
|
193
|
+
# Adjust length for PARI. We need to subtract 1 because PARI returns
|
|
194
|
+
# returns vectors of length less than or equal to b, but we want
|
|
195
|
+
# strictly less. We need to double because the matrix is doubled.
|
|
196
|
+
len_bound_pari = 2 * (len_bound - 1)
|
|
197
|
+
|
|
198
|
+
# Call PARI's qfminim()
|
|
199
|
+
parilist = self.__pari__().qfminim(len_bound_pari)[2].Vec()
|
|
200
|
+
|
|
201
|
+
# List of lengths
|
|
202
|
+
parilens = pari(r"(M,v) -> vector(#v, i, (v[i]~ * M * v[i])\2)")(self, parilist)
|
|
203
|
+
|
|
204
|
+
# Sort the vectors into lists by their length
|
|
205
|
+
vec_sorted_list = [[] for i in range(len_bound)]
|
|
206
|
+
for i in range(len(parilist)):
|
|
207
|
+
length = int(parilens[i])
|
|
208
|
+
# In certain trivial cases, PARI can sometimes return longer
|
|
209
|
+
# vectors than requested.
|
|
210
|
+
if length < len_bound:
|
|
211
|
+
sagevec = V(list(parilist[i]))
|
|
212
|
+
vec_sorted_list[length].append(sagevec)
|
|
213
|
+
if not up_to_sign_flag:
|
|
214
|
+
vec_sorted_list[length].append(-sagevec)
|
|
215
|
+
|
|
216
|
+
# Add the zero vector by hand
|
|
217
|
+
vec_sorted_list[0].append(V.zero_vector())
|
|
218
|
+
|
|
219
|
+
return vec_sorted_list
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def short_primitive_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False):
|
|
223
|
+
r"""
|
|
224
|
+
Return a list of lists of short primitive vectors `v`, sorted by length, with
|
|
225
|
+
`Q(v) <` ``len_bound``. The list in output `[i]` indexes all vectors of
|
|
226
|
+
length `i`. If the ``up_to_sign_flag`` is set to ``True``, then only one of
|
|
227
|
+
the vectors of the pair `[v, -v]` is listed.
|
|
228
|
+
|
|
229
|
+
.. NOTE::
|
|
230
|
+
|
|
231
|
+
This processes the PARI/GP output to always give elements of type `\ZZ`.
|
|
232
|
+
|
|
233
|
+
OUTPUT: list of lists of vectors
|
|
234
|
+
|
|
235
|
+
EXAMPLES::
|
|
236
|
+
|
|
237
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
|
|
238
|
+
sage: Q.short_vector_list_up_to_length(5, True)
|
|
239
|
+
[[(0, 0, 0, 0)],
|
|
240
|
+
[(1, 0, 0, 0)],
|
|
241
|
+
[],
|
|
242
|
+
[(0, 1, 0, 0)],
|
|
243
|
+
[(1, 1, 0, 0), (1, -1, 0, 0), (2, 0, 0, 0)]]
|
|
244
|
+
sage: Q.short_primitive_vector_list_up_to_length(5, True)
|
|
245
|
+
[[], [(1, 0, 0, 0)], [], [(0, 1, 0, 0)], [(1, 1, 0, 0), (1, -1, 0, 0)]]
|
|
246
|
+
"""
|
|
247
|
+
# Get a list of short vectors
|
|
248
|
+
full_vec_list = self.short_vector_list_up_to_length(len_bound, up_to_sign_flag)
|
|
249
|
+
|
|
250
|
+
# Make a new list of the primitive vectors
|
|
251
|
+
prim_vec_list = [[v for v in L if GCD(v) == 1]
|
|
252
|
+
for L in full_vec_list]
|
|
253
|
+
|
|
254
|
+
# Return the list of primitive vectors
|
|
255
|
+
return prim_vec_list
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _compute_automorphisms(self):
|
|
259
|
+
"""
|
|
260
|
+
Call PARI to compute the automorphism group of the quadratic form.
|
|
261
|
+
|
|
262
|
+
This uses :pari:`qfauto`.
|
|
263
|
+
|
|
264
|
+
OUTPUT: none, this just caches the result
|
|
265
|
+
|
|
266
|
+
TESTS::
|
|
267
|
+
|
|
268
|
+
sage: DiagonalQuadraticForm(ZZ, [-1,1,1])._compute_automorphisms()
|
|
269
|
+
Traceback (most recent call last):
|
|
270
|
+
...
|
|
271
|
+
ValueError: not a definite form in QuadraticForm.automorphisms()
|
|
272
|
+
sage: DiagonalQuadraticForm(GF(5), [1,1,1])._compute_automorphisms()
|
|
273
|
+
Traceback (most recent call last):
|
|
274
|
+
...
|
|
275
|
+
NotImplementedError: computing the automorphism group of a quadratic form is only supported over ZZ
|
|
276
|
+
"""
|
|
277
|
+
if self.base_ring() is not ZZ:
|
|
278
|
+
raise NotImplementedError("computing the automorphism group of a quadratic form is only supported over ZZ")
|
|
279
|
+
if not self.is_definite():
|
|
280
|
+
raise ValueError("not a definite form in QuadraticForm.automorphisms()")
|
|
281
|
+
|
|
282
|
+
if hasattr(self, "__automorphisms_pari"):
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
A = self.__pari__().qfauto()
|
|
286
|
+
self.__number_of_automorphisms = A[0]
|
|
287
|
+
self.__automorphisms_pari = A[1]
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def automorphism_group(self):
|
|
291
|
+
"""
|
|
292
|
+
Return the group of automorphisms of the quadratic form.
|
|
293
|
+
|
|
294
|
+
OUTPUT: a :class:`MatrixGroup`
|
|
295
|
+
|
|
296
|
+
EXAMPLES::
|
|
297
|
+
|
|
298
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
|
|
299
|
+
sage: Q.automorphism_group()
|
|
300
|
+
Matrix group over Rational Field with 3 generators (
|
|
301
|
+
[ 0 0 1] [1 0 0] [ 1 0 0]
|
|
302
|
+
[-1 0 0] [0 0 1] [ 0 -1 0]
|
|
303
|
+
[ 0 1 0], [0 1 0], [ 0 0 1]
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
::
|
|
307
|
+
|
|
308
|
+
sage: DiagonalQuadraticForm(ZZ, [1,3,5,7]).automorphism_group()
|
|
309
|
+
Matrix group over Rational Field with 4 generators (
|
|
310
|
+
[-1 0 0 0] [ 1 0 0 0] [ 1 0 0 0] [ 1 0 0 0]
|
|
311
|
+
[ 0 -1 0 0] [ 0 -1 0 0] [ 0 1 0 0] [ 0 1 0 0]
|
|
312
|
+
[ 0 0 -1 0] [ 0 0 1 0] [ 0 0 -1 0] [ 0 0 1 0]
|
|
313
|
+
[ 0 0 0 -1], [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 -1]
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
The smallest possible automorphism group has order two, since we
|
|
317
|
+
can always change all signs::
|
|
318
|
+
|
|
319
|
+
sage: Q = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3])
|
|
320
|
+
sage: Q.automorphism_group()
|
|
321
|
+
Matrix group over Rational Field with 1 generators (
|
|
322
|
+
[-1 0 0]
|
|
323
|
+
[ 0 -1 0]
|
|
324
|
+
[ 0 0 -1]
|
|
325
|
+
)
|
|
326
|
+
"""
|
|
327
|
+
self._compute_automorphisms()
|
|
328
|
+
|
|
329
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
330
|
+
from sage.groups.matrix_gps.finitely_generated import MatrixGroup
|
|
331
|
+
MS = MatrixSpace(self.base_ring().fraction_field(), self.dim(), self.dim())
|
|
332
|
+
gens = [MS(x.sage()) for x in self.__automorphisms_pari]
|
|
333
|
+
return MatrixGroup(gens)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def automorphisms(self):
|
|
337
|
+
"""
|
|
338
|
+
Return the list of the automorphisms of the quadratic form.
|
|
339
|
+
|
|
340
|
+
OUTPUT: list of matrices
|
|
341
|
+
|
|
342
|
+
EXAMPLES::
|
|
343
|
+
|
|
344
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
|
|
345
|
+
sage: Q.number_of_automorphisms()
|
|
346
|
+
48
|
|
347
|
+
sage: 2^3 * factorial(3)
|
|
348
|
+
48
|
|
349
|
+
sage: len(Q.automorphisms()) # needs sage.libs.gap
|
|
350
|
+
48
|
|
351
|
+
|
|
352
|
+
::
|
|
353
|
+
|
|
354
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
|
|
355
|
+
sage: Q.number_of_automorphisms()
|
|
356
|
+
16
|
|
357
|
+
sage: aut = Q.automorphisms() # needs sage.libs.gap
|
|
358
|
+
sage: len(aut) # needs sage.libs.gap
|
|
359
|
+
16
|
|
360
|
+
sage: all(Q(M) == Q for M in aut) # needs sage.libs.gap
|
|
361
|
+
True
|
|
362
|
+
|
|
363
|
+
sage: Q = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3])
|
|
364
|
+
sage: sorted(Q.automorphisms()) # needs sage.libs.gap
|
|
365
|
+
[
|
|
366
|
+
[-1 0 0] [1 0 0]
|
|
367
|
+
[ 0 -1 0] [0 1 0]
|
|
368
|
+
[ 0 0 -1], [0 0 1]
|
|
369
|
+
]
|
|
370
|
+
"""
|
|
371
|
+
return [x.matrix() for x in self.automorphism_group()]
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def number_of_automorphisms(self):
|
|
375
|
+
r"""
|
|
376
|
+
Return the number of automorphisms (of det `1` and `-1`) of
|
|
377
|
+
the quadratic form.
|
|
378
|
+
|
|
379
|
+
OUTPUT: integer `\geq 2`
|
|
380
|
+
|
|
381
|
+
EXAMPLES::
|
|
382
|
+
|
|
383
|
+
sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 1], unsafe_initialization=True)
|
|
384
|
+
sage: Q.number_of_automorphisms()
|
|
385
|
+
48
|
|
386
|
+
|
|
387
|
+
::
|
|
388
|
+
|
|
389
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1])
|
|
390
|
+
sage: Q.number_of_automorphisms()
|
|
391
|
+
384
|
|
392
|
+
sage: 2^4 * factorial(4)
|
|
393
|
+
384
|
|
394
|
+
"""
|
|
395
|
+
try:
|
|
396
|
+
return self.__number_of_automorphisms
|
|
397
|
+
except AttributeError:
|
|
398
|
+
self._compute_automorphisms()
|
|
399
|
+
return self.__number_of_automorphisms
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def set_number_of_automorphisms(self, num_autos):
|
|
403
|
+
r"""
|
|
404
|
+
Set the number of automorphisms to be the value given. No error
|
|
405
|
+
checking is performed, to this may lead to erroneous results.
|
|
406
|
+
|
|
407
|
+
The fact that this result was set externally is recorded in the
|
|
408
|
+
internal list of external initializations, accessible by the
|
|
409
|
+
method :meth:`list_external_initializations`.
|
|
410
|
+
|
|
411
|
+
OUTPUT: none
|
|
412
|
+
|
|
413
|
+
EXAMPLES::
|
|
414
|
+
|
|
415
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1, 1, 1])
|
|
416
|
+
sage: Q.list_external_initializations()
|
|
417
|
+
[]
|
|
418
|
+
sage: Q.set_number_of_automorphisms(-3)
|
|
419
|
+
sage: Q.number_of_automorphisms()
|
|
420
|
+
-3
|
|
421
|
+
sage: Q.list_external_initializations()
|
|
422
|
+
['number_of_automorphisms']
|
|
423
|
+
"""
|
|
424
|
+
self.__number_of_automorphisms = num_autos
|
|
425
|
+
text = 'number_of_automorphisms'
|
|
426
|
+
if text not in self._external_initialization_list:
|
|
427
|
+
self._external_initialization_list.append(text)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
# sage.doctest: needs sage.libs.pari sage.modules
|
|
3
|
+
"""
|
|
4
|
+
Local and Global Genus Symbols
|
|
5
|
+
"""
|
|
6
|
+
#############################################################
|
|
7
|
+
# #
|
|
8
|
+
# Wrappers for the Genus/Genus Symbol Code in ../genera/ #
|
|
9
|
+
# #
|
|
10
|
+
#############################################################
|
|
11
|
+
|
|
12
|
+
from sage.arith.misc import is_prime, prime_divisors
|
|
13
|
+
from sage.quadratic_forms.genera.genus import Genus, LocalGenusSymbol
|
|
14
|
+
from sage.rings.integer_ring import ZZ
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def global_genus_symbol(self):
|
|
18
|
+
r"""
|
|
19
|
+
Return the genus of two times a quadratic form over `\ZZ`.
|
|
20
|
+
|
|
21
|
+
These are defined by a collection of local genus symbols (a la
|
|
22
|
+
Chapter 15 of Conway-Sloane [CS1999]_), and a signature.
|
|
23
|
+
|
|
24
|
+
EXAMPLES::
|
|
25
|
+
|
|
26
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
|
|
27
|
+
sage: Q.global_genus_symbol()
|
|
28
|
+
Genus of
|
|
29
|
+
[2 0 0 0]
|
|
30
|
+
[0 4 0 0]
|
|
31
|
+
[0 0 6 0]
|
|
32
|
+
[0 0 0 8]
|
|
33
|
+
Signature: (4, 0)
|
|
34
|
+
Genus symbol at 2: [2^-2 4^1 8^1]_6
|
|
35
|
+
Genus symbol at 3: 1^3 3^-1
|
|
36
|
+
|
|
37
|
+
::
|
|
38
|
+
|
|
39
|
+
sage: Q = QuadraticForm(ZZ, 4, range(10))
|
|
40
|
+
sage: Q.global_genus_symbol()
|
|
41
|
+
Genus of
|
|
42
|
+
[ 0 1 2 3]
|
|
43
|
+
[ 1 8 5 6]
|
|
44
|
+
[ 2 5 14 8]
|
|
45
|
+
[ 3 6 8 18]
|
|
46
|
+
Signature: (3, 1)
|
|
47
|
+
Genus symbol at 2: 1^-4
|
|
48
|
+
Genus symbol at 563: 1^3 563^-1
|
|
49
|
+
"""
|
|
50
|
+
if self.base_ring() is not ZZ:
|
|
51
|
+
raise TypeError("the quadratic form is not defined over the integers")
|
|
52
|
+
return Genus(self.Hessian_matrix())
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def local_genus_symbol(self, p):
|
|
56
|
+
r"""
|
|
57
|
+
Return the Conway-Sloane genus symbol of 2 times a quadratic form
|
|
58
|
+
defined over `\ZZ` at a prime number `p`.
|
|
59
|
+
|
|
60
|
+
This is defined (in the class
|
|
61
|
+
:class:`~sage.quadratic_forms.genera.genus.Genus_Symbol_p_adic_ring`)
|
|
62
|
+
to be a list of tuples (one for each Jordan component
|
|
63
|
+
`p^m\cdot A` at `p`, where `A` is a unimodular symmetric matrix with
|
|
64
|
+
coefficients the `p`-adic integers) of the following form:
|
|
65
|
+
|
|
66
|
+
- If `p>2`, then return triples of the form [`m`, `n`, `d`] where
|
|
67
|
+
|
|
68
|
+
- `m` = valuation of the component
|
|
69
|
+
|
|
70
|
+
- `n` = rank of `A`
|
|
71
|
+
|
|
72
|
+
- `d` = det(`A`) in {1, `u`} for normalized quadratic non-residue `u`.
|
|
73
|
+
|
|
74
|
+
- If `p=2`, then return quintuples of the form [`m`, `n`, `s`, `d`, `o`] where
|
|
75
|
+
|
|
76
|
+
- `m` = valuation of the component
|
|
77
|
+
|
|
78
|
+
- `n` = rank of `A`
|
|
79
|
+
|
|
80
|
+
- `d` = det(`A`) in {1, 3, 5, 7}
|
|
81
|
+
|
|
82
|
+
- `s` = 0 (or 1) if `A` is even (or odd)
|
|
83
|
+
|
|
84
|
+
- `o` = oddity of `A` (= 0 if `s` = 0) in `\ZZ/8\ZZ` = the trace of the diagonalization of `A`
|
|
85
|
+
|
|
86
|
+
.. NOTE::
|
|
87
|
+
|
|
88
|
+
The Conway-Sloane convention for describing the prime `p = -1`
|
|
89
|
+
is not supported here, and neither is the convention for
|
|
90
|
+
including the 'prime' Infinity. See note on p370 of Conway-Sloane
|
|
91
|
+
(3rd ed) [CS1999]_ for a discussion of this convention.
|
|
92
|
+
|
|
93
|
+
INPUT:
|
|
94
|
+
|
|
95
|
+
- ``p`` -- a prime number > 0
|
|
96
|
+
|
|
97
|
+
OUTPUT:
|
|
98
|
+
|
|
99
|
+
a Conway-Sloane genus symbol at `p`, which is an
|
|
100
|
+
instance of the class :class:`~sage.quadratic_forms.genera.genus.Genus_Symbol_p_adic_ring`.
|
|
101
|
+
|
|
102
|
+
EXAMPLES::
|
|
103
|
+
|
|
104
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
|
|
105
|
+
sage: Q.local_genus_symbol(2)
|
|
106
|
+
Genus symbol at 2: [2^-2 4^1 8^1]_6
|
|
107
|
+
sage: Q.local_genus_symbol(3)
|
|
108
|
+
Genus symbol at 3: 1^3 3^-1
|
|
109
|
+
sage: Q.local_genus_symbol(5)
|
|
110
|
+
Genus symbol at 5: 1^4
|
|
111
|
+
"""
|
|
112
|
+
if not is_prime(p):
|
|
113
|
+
raise TypeError("the number " + str(p) + " is not prime")
|
|
114
|
+
if self.base_ring() is not ZZ:
|
|
115
|
+
raise TypeError("the quadratic form is not defined over the integers")
|
|
116
|
+
return LocalGenusSymbol(self.Hessian_matrix(), p)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def CS_genus_symbol_list(self, force_recomputation=False):
|
|
120
|
+
"""
|
|
121
|
+
Return the list of Conway-Sloane genus symbols in increasing order of primes dividing 2*det.
|
|
122
|
+
|
|
123
|
+
EXAMPLES::
|
|
124
|
+
|
|
125
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
|
|
126
|
+
sage: Q.CS_genus_symbol_list()
|
|
127
|
+
[Genus symbol at 2: [2^-2 4^1 8^1]_6, Genus symbol at 3: 1^3 3^-1]
|
|
128
|
+
"""
|
|
129
|
+
# Try to use the cached list
|
|
130
|
+
if not force_recomputation:
|
|
131
|
+
try:
|
|
132
|
+
return self.__CS_genus_symbol_list
|
|
133
|
+
except AttributeError:
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
# Otherwise recompute and cache the list
|
|
137
|
+
list_of_CS_genus_symbols = [self.local_genus_symbol(p)
|
|
138
|
+
for p in prime_divisors(2 * self.det())]
|
|
139
|
+
|
|
140
|
+
self.__CS_genus_symbol_list = list_of_CS_genus_symbols
|
|
141
|
+
return list_of_CS_genus_symbols
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
# sage.doctest: needs sage.libs.pari sage.modules
|
|
3
|
+
"""
|
|
4
|
+
Local Density Interfaces
|
|
5
|
+
"""
|
|
6
|
+
# // This is needed in the filter for primitivity...
|
|
7
|
+
# #include "../max-min.h"
|
|
8
|
+
|
|
9
|
+
from sage.arith.misc import valuation
|
|
10
|
+
from sage.rings.rational_field import QQ
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def local_density(self, p, m):
|
|
14
|
+
"""
|
|
15
|
+
Return the local density.
|
|
16
|
+
|
|
17
|
+
.. NOTE::
|
|
18
|
+
|
|
19
|
+
This screens for imprimitive forms, and puts the quadratic
|
|
20
|
+
form in local normal form, which is a *requirement* of the
|
|
21
|
+
routines performing the computations!
|
|
22
|
+
|
|
23
|
+
INPUT:
|
|
24
|
+
|
|
25
|
+
- ``p`` -- a prime number > 0
|
|
26
|
+
- ``m`` -- integer
|
|
27
|
+
|
|
28
|
+
OUTPUT: a rational number
|
|
29
|
+
|
|
30
|
+
EXAMPLES::
|
|
31
|
+
|
|
32
|
+
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) # NOTE: This is already in local normal form for *all* primes p!
|
|
33
|
+
sage: Q.local_density(p=2, m=1)
|
|
34
|
+
1
|
|
35
|
+
sage: Q.local_density(p=3, m=1)
|
|
36
|
+
8/9
|
|
37
|
+
sage: Q.local_density(p=5, m=1)
|
|
38
|
+
24/25
|
|
39
|
+
sage: Q.local_density(p=7, m=1)
|
|
40
|
+
48/49
|
|
41
|
+
sage: Q.local_density(p=11, m=1)
|
|
42
|
+
120/121
|
|
43
|
+
"""
|
|
44
|
+
n = self.dim()
|
|
45
|
+
if n == 0:
|
|
46
|
+
raise TypeError("we do not currently handle 0-dim'l forms")
|
|
47
|
+
|
|
48
|
+
# Find the local normal form and p-scale of Q -- Note: This uses the valuation ordering of local_normal_form.
|
|
49
|
+
# TO DO: Write a separate p-scale and p-norm routines!
|
|
50
|
+
Q_local = self.local_normal_form(p)
|
|
51
|
+
if n == 1:
|
|
52
|
+
p_valuation = valuation(Q_local[0, 0], p)
|
|
53
|
+
else:
|
|
54
|
+
p_valuation = min(valuation(Q_local[0, 0], p),
|
|
55
|
+
valuation(Q_local[0, 1], p))
|
|
56
|
+
|
|
57
|
+
# If m is less p-divisible than the matrix, return zero
|
|
58
|
+
if ((m != 0) and (valuation(m, p) < p_valuation)): # Note: The (m != 0) condition protects taking the valuation of zero.
|
|
59
|
+
return QQ(0)
|
|
60
|
+
|
|
61
|
+
# If the form is imprimitive, rescale it and call the local density routine
|
|
62
|
+
p_adjustment = QQ(1) / p**p_valuation
|
|
63
|
+
m_prim = QQ(m) / p**p_valuation
|
|
64
|
+
Q_prim = Q_local.scale_by_factor(p_adjustment)
|
|
65
|
+
|
|
66
|
+
# Return the densities for the reduced problem
|
|
67
|
+
return Q_prim.local_density_congruence(p, m_prim)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def local_primitive_density(self, p, m):
|
|
71
|
+
"""
|
|
72
|
+
Return the local primitive density -- should be called by the user.
|
|
73
|
+
|
|
74
|
+
NOTE: This screens for imprimitive forms, and puts the
|
|
75
|
+
quadratic form in local normal form, which is a *requirement* of
|
|
76
|
+
the routines performing the computations!
|
|
77
|
+
|
|
78
|
+
INPUT:
|
|
79
|
+
|
|
80
|
+
- ``p`` -- a prime number > 0
|
|
81
|
+
- ``m`` -- integer
|
|
82
|
+
|
|
83
|
+
OUTPUT: a rational number
|
|
84
|
+
|
|
85
|
+
EXAMPLES::
|
|
86
|
+
|
|
87
|
+
sage: Q = QuadraticForm(ZZ, 4, range(10))
|
|
88
|
+
sage: Q[0,0] = 5
|
|
89
|
+
sage: Q[1,1] = 10
|
|
90
|
+
sage: Q[2,2] = 15
|
|
91
|
+
sage: Q[3,3] = 20
|
|
92
|
+
sage: Q
|
|
93
|
+
Quadratic form in 4 variables over Integer Ring with coefficients:
|
|
94
|
+
[ 5 1 2 3 ]
|
|
95
|
+
[ * 10 5 6 ]
|
|
96
|
+
[ * * 15 8 ]
|
|
97
|
+
[ * * * 20 ]
|
|
98
|
+
sage: Q.theta_series(20) # needs sage.libs.pari
|
|
99
|
+
1 + 2*q^5 + 2*q^10 + 2*q^14 + 2*q^15 + 2*q^16 + 2*q^18 + O(q^20)
|
|
100
|
+
sage: Q.local_normal_form(2)
|
|
101
|
+
Quadratic form in 4 variables over Integer Ring with coefficients:
|
|
102
|
+
[ 0 1 0 0 ]
|
|
103
|
+
[ * 0 0 0 ]
|
|
104
|
+
[ * * 0 1 ]
|
|
105
|
+
[ * * * 0 ]
|
|
106
|
+
|
|
107
|
+
sage: Q.local_primitive_density(2, 1)
|
|
108
|
+
3/4
|
|
109
|
+
sage: Q.local_primitive_density(5, 1)
|
|
110
|
+
24/25
|
|
111
|
+
|
|
112
|
+
sage: Q.local_primitive_density(2, 5)
|
|
113
|
+
3/4
|
|
114
|
+
sage: Q.local_density(2, 5)
|
|
115
|
+
3/4
|
|
116
|
+
"""
|
|
117
|
+
n = self.dim()
|
|
118
|
+
if n == 0:
|
|
119
|
+
raise TypeError("we do not currently handle 0-dim'l forms")
|
|
120
|
+
|
|
121
|
+
# Find the local normal form and p-scale of Q -- Note: This uses the valuation ordering of local_normal_form.
|
|
122
|
+
# TO DO: Write a separate p-scale and p-norm routines!
|
|
123
|
+
Q_local = self.local_normal_form(p)
|
|
124
|
+
if n == 1:
|
|
125
|
+
p_valuation = valuation(Q_local[0, 0], p)
|
|
126
|
+
else:
|
|
127
|
+
p_valuation = min(valuation(Q_local[0, 0], p),
|
|
128
|
+
valuation(Q_local[0, 1], p))
|
|
129
|
+
|
|
130
|
+
# If m is less p-divisible than the matrix, return zero
|
|
131
|
+
if m != 0 and valuation(m, p) < p_valuation: # Note: The (m != 0) condition protects taking the valuation of zero.
|
|
132
|
+
return QQ.zero()
|
|
133
|
+
|
|
134
|
+
# If the form is imprimitive, rescale it and call the local density routine
|
|
135
|
+
p_adjustment = QQ.one() / p**p_valuation
|
|
136
|
+
m_prim = QQ(m) / p**p_valuation
|
|
137
|
+
Q_prim = Q_local.scale_by_factor(p_adjustment)
|
|
138
|
+
|
|
139
|
+
# Return the densities for the reduced problem
|
|
140
|
+
return Q_prim.local_primitive_density_congruence(p, m_prim)
|