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,243 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
# sage.doctest: needs sage.groups
|
|
3
|
+
r"""
|
|
4
|
+
Spinor genus computations.
|
|
5
|
+
|
|
6
|
+
This file defines the group of spinor operators used
|
|
7
|
+
for the computation of spinor genera.
|
|
8
|
+
It is meant for internal use only.
|
|
9
|
+
|
|
10
|
+
EXAMPLES::
|
|
11
|
+
|
|
12
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import SpinorOperators
|
|
13
|
+
sage: A = SpinorOperators((2, 3, 7))
|
|
14
|
+
|
|
15
|
+
AUTHORS:
|
|
16
|
+
|
|
17
|
+
- Simon Brandhorst (2020-11-1): initial version
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# ****************************************************************************
|
|
21
|
+
# Copyright (C) 2020 Simon Brandhorst <sbrandhorst@web.de>
|
|
22
|
+
#
|
|
23
|
+
# This program is free software: you can redistribute it and/or modify
|
|
24
|
+
# it under the terms of the GNU General Public License as published by
|
|
25
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
26
|
+
# (at your option) any later version.
|
|
27
|
+
# https://www.gnu.org/licenses/
|
|
28
|
+
# ****************************************************************************
|
|
29
|
+
|
|
30
|
+
from sage.groups.abelian_gps.abelian_group_gap import (AbelianGroupGap,
|
|
31
|
+
AbelianGroupElement_gap)
|
|
32
|
+
from sage.rings.integer_ring import ZZ
|
|
33
|
+
from sage.rings.rational_field import QQ
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SpinorOperator(AbelianGroupElement_gap):
|
|
37
|
+
r"""
|
|
38
|
+
A spinor operator seen as a tuple of square classes.
|
|
39
|
+
|
|
40
|
+
For `2` the square class is represented as one of `1,3,5,7` and for
|
|
41
|
+
`p` odd it is `1` for a `p`-adic unit square and `-1` for a non-square.
|
|
42
|
+
|
|
43
|
+
EXAMPLES::
|
|
44
|
+
|
|
45
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import *
|
|
46
|
+
sage: A = SpinorOperators((2, 3, 7))
|
|
47
|
+
sage: A.an_element()
|
|
48
|
+
[2:7, 3:-1, 7:-1]
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def _repr_(self) -> str:
|
|
52
|
+
r"""
|
|
53
|
+
Return the print representation.
|
|
54
|
+
|
|
55
|
+
EXAMPLES::
|
|
56
|
+
|
|
57
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import *
|
|
58
|
+
sage: A = SpinorOperators((2, 3, 7))
|
|
59
|
+
sage: A.an_element()
|
|
60
|
+
[2:7, 3:-1, 7:-1]
|
|
61
|
+
"""
|
|
62
|
+
e = self.exponents()
|
|
63
|
+
p = self.parent()._primes
|
|
64
|
+
s = "[2:"
|
|
65
|
+
if e[0] == 0 == e[1]:
|
|
66
|
+
s += "1"
|
|
67
|
+
elif e[0] == 1 and e[1] == 0:
|
|
68
|
+
s += "3"
|
|
69
|
+
elif e[0] == 0 and e[1] == 1:
|
|
70
|
+
s += "5"
|
|
71
|
+
elif e[0] == 1 == e[1]:
|
|
72
|
+
s += "7"
|
|
73
|
+
for k in range(1, len(p)):
|
|
74
|
+
s += f", {p[k]}:{(-1)**e[k + 1]}"
|
|
75
|
+
s += "]"
|
|
76
|
+
return s
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class SpinorOperators(AbelianGroupGap):
|
|
80
|
+
r"""
|
|
81
|
+
The group of spinor operators of a genus.
|
|
82
|
+
|
|
83
|
+
It is a product of `p`-adic unit square classes
|
|
84
|
+
used for spinor genus computations.
|
|
85
|
+
|
|
86
|
+
INPUT:
|
|
87
|
+
|
|
88
|
+
- a tuple of primes `(p_1=2,\dots, p_n`)
|
|
89
|
+
|
|
90
|
+
EXAMPLES::
|
|
91
|
+
|
|
92
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import *
|
|
93
|
+
sage: SpinorOperators((2, 3, 7))
|
|
94
|
+
Group of SpinorOperators at primes (2, 3, 7)
|
|
95
|
+
"""
|
|
96
|
+
def __init__(self, primes):
|
|
97
|
+
r"""
|
|
98
|
+
Initialize the group of spinor operators.
|
|
99
|
+
|
|
100
|
+
TESTS::
|
|
101
|
+
|
|
102
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import *
|
|
103
|
+
sage: S = SpinorOperators((2, 3, 7))
|
|
104
|
+
sage: TestSuite(S).run()
|
|
105
|
+
"""
|
|
106
|
+
if primes[0] != 2:
|
|
107
|
+
raise ValueError("first prime must be 2")
|
|
108
|
+
self._primes = tuple(ZZ(p) for p in primes)
|
|
109
|
+
orders = len(self._primes) * [2] + [2]
|
|
110
|
+
# 3, 5, unit_p1, unit_p2,...
|
|
111
|
+
orders = tuple(orders)
|
|
112
|
+
AbelianGroupGap.__init__(self, orders)
|
|
113
|
+
|
|
114
|
+
def __reduce__(self):
|
|
115
|
+
r"""
|
|
116
|
+
Implement pickling.
|
|
117
|
+
|
|
118
|
+
OUTPUT:
|
|
119
|
+
|
|
120
|
+
a tuple ``f`` such that this element is ``f[0](*f[1])``
|
|
121
|
+
|
|
122
|
+
EXAMPLES::
|
|
123
|
+
|
|
124
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import SpinorOperators
|
|
125
|
+
sage: S = SpinorOperators((2, 3, 7))
|
|
126
|
+
sage: S == loads(dumps(S))
|
|
127
|
+
True
|
|
128
|
+
"""
|
|
129
|
+
return SpinorOperators, (self._primes,)
|
|
130
|
+
|
|
131
|
+
Element = SpinorOperator
|
|
132
|
+
|
|
133
|
+
def _repr_(self) -> str:
|
|
134
|
+
r"""
|
|
135
|
+
Return the print representation of ``self``.
|
|
136
|
+
|
|
137
|
+
EXAMPLES::
|
|
138
|
+
|
|
139
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import SpinorOperators
|
|
140
|
+
sage: SpinorOperators((2, 3, 7))
|
|
141
|
+
Group of SpinorOperators at primes (2, 3, 7)
|
|
142
|
+
"""
|
|
143
|
+
return f"Group of SpinorOperators at primes {self._primes}"
|
|
144
|
+
|
|
145
|
+
def to_square_class(self, x, p):
|
|
146
|
+
r"""
|
|
147
|
+
Return `(1,...,1,x,1,...,1)` with the square class of `x` at position `p`.
|
|
148
|
+
|
|
149
|
+
INPUT:
|
|
150
|
+
|
|
151
|
+
- ``p`` -- a prime
|
|
152
|
+
|
|
153
|
+
- ``x`` -- nonzero rational number
|
|
154
|
+
|
|
155
|
+
EXAMPLES::
|
|
156
|
+
|
|
157
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import SpinorOperators
|
|
158
|
+
sage: AS = SpinorOperators((2, 3, 7))
|
|
159
|
+
sage: AS.to_square_class(5, 7)
|
|
160
|
+
[2:1, 3:1, 7:-1]
|
|
161
|
+
sage: AS.to_square_class(5, 2)
|
|
162
|
+
[2:5, 3:1, 7:1]
|
|
163
|
+
sage: AS.to_square_class(-5, 2)
|
|
164
|
+
[2:3, 3:1, 7:1]
|
|
165
|
+
sage: AS.to_square_class(7, 2)
|
|
166
|
+
[2:7, 3:1, 7:1]
|
|
167
|
+
"""
|
|
168
|
+
x = QQ(x)
|
|
169
|
+
if x == 0:
|
|
170
|
+
raise ValueError("x must be nonzero")
|
|
171
|
+
if p not in self._primes:
|
|
172
|
+
raise ValueError("not a coordinate prime")
|
|
173
|
+
v, u = x.val_unit(p)
|
|
174
|
+
v = v % 2
|
|
175
|
+
if v != 0:
|
|
176
|
+
raise ValueError(f"x(={x}) must be a p-adic unit")
|
|
177
|
+
y = self.one()
|
|
178
|
+
if p == 2:
|
|
179
|
+
u = u % 8
|
|
180
|
+
if u == 3:
|
|
181
|
+
y *= self.gens()[0]
|
|
182
|
+
if u == 5:
|
|
183
|
+
y *= self.gens()[1]
|
|
184
|
+
if u == 7:
|
|
185
|
+
y *= self.gens()[0] * self.gens()[1]
|
|
186
|
+
return y
|
|
187
|
+
i = 1 + self._primes.index(p)
|
|
188
|
+
if not u.is_padic_square(p):
|
|
189
|
+
y *= self.gens()[i]
|
|
190
|
+
return y
|
|
191
|
+
|
|
192
|
+
def delta(self, r, prime=None):
|
|
193
|
+
r"""
|
|
194
|
+
Diagonal embedding of rational square classes.
|
|
195
|
+
|
|
196
|
+
INPUT:
|
|
197
|
+
|
|
198
|
+
- ``r`` -- a nonzero integer; if ``prime`` is ``None``, ``r`` must not
|
|
199
|
+
be divisible by the defining primes of ``self``
|
|
200
|
+
|
|
201
|
+
- ``prime`` -- (default: ``None``) a prime or `-1`
|
|
202
|
+
|
|
203
|
+
OUTPUT:
|
|
204
|
+
|
|
205
|
+
If a prime `p` is given, the method returns
|
|
206
|
+
`\Delta_p(r)`
|
|
207
|
+
otherwise returns `\Delta(r)`
|
|
208
|
+
where both are as defined by Conway-Sloane in
|
|
209
|
+
Chapter 15 9.3 of [CS1988]_.
|
|
210
|
+
|
|
211
|
+
EXAMPLES::
|
|
212
|
+
|
|
213
|
+
sage: from sage.quadratic_forms.genera.spinor_genus import SpinorOperators
|
|
214
|
+
sage: AS = SpinorOperators((2, 3, 7))
|
|
215
|
+
sage: AS.delta(5)
|
|
216
|
+
[2:5, 3:-1, 7:-1]
|
|
217
|
+
sage: AS.delta(2, prime=3)
|
|
218
|
+
[2:1, 3:-1, 7:1]
|
|
219
|
+
sage: AS.delta(11)
|
|
220
|
+
[2:3, 3:-1, 7:1]
|
|
221
|
+
sage: AS.delta(3, prime=7)
|
|
222
|
+
[2:1, 3:1, 7:-1]
|
|
223
|
+
"""
|
|
224
|
+
r = ZZ(r)
|
|
225
|
+
if prime is None:
|
|
226
|
+
if any(p.divides(r) for p in self._primes):
|
|
227
|
+
raise ValueError(f"r must not be divisible by {self._primes}")
|
|
228
|
+
return self.prod([self.to_square_class(r, p)
|
|
229
|
+
for p in self._primes])
|
|
230
|
+
prime = ZZ(prime)
|
|
231
|
+
if prime == -1:
|
|
232
|
+
r = r.sign()
|
|
233
|
+
return self.prod([self.to_square_class(r, p)
|
|
234
|
+
for p in self._primes])
|
|
235
|
+
if prime not in self._primes:
|
|
236
|
+
raise ValueError("prime must be among %s" % self._primes)
|
|
237
|
+
v, u = r.val_unit(prime)
|
|
238
|
+
pv = prime**v
|
|
239
|
+
y = self.prod([self.to_square_class(pv, q)
|
|
240
|
+
for q in self._primes if q != prime])
|
|
241
|
+
if prime in self._primes:
|
|
242
|
+
y *= self.to_square_class(u, p=prime)
|
|
243
|
+
return y
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-pari
|
|
2
|
+
# sage.doctest: needs sage.libs.pari sage.modules
|
|
3
|
+
"""
|
|
4
|
+
Solving quadratic equations
|
|
5
|
+
|
|
6
|
+
Interface to the PARI/GP quadratic forms code of Denis Simon.
|
|
7
|
+
|
|
8
|
+
AUTHORS:
|
|
9
|
+
|
|
10
|
+
- Denis Simon (GP code)
|
|
11
|
+
|
|
12
|
+
- Nick Alexander (Sage interface)
|
|
13
|
+
|
|
14
|
+
- Jeroen Demeyer (2014-09-23): use PARI instead of GP scripts,
|
|
15
|
+
return vectors instead of tuples (:issue:`16997`).
|
|
16
|
+
|
|
17
|
+
- Tyler Gaona (2015-11-14): added the `solve` method
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# ****************************************************************************
|
|
21
|
+
# Copyright (C) 2008 Nick Alexander
|
|
22
|
+
# Copyright (C) 2014 Jeroen Demeyer
|
|
23
|
+
#
|
|
24
|
+
# This program is free software: you can redistribute it and/or modify
|
|
25
|
+
# it under the terms of the GNU General Public License as published by
|
|
26
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
27
|
+
# (at your option) any later version.
|
|
28
|
+
# https://www.gnu.org/licenses/
|
|
29
|
+
# ****************************************************************************
|
|
30
|
+
|
|
31
|
+
from sage.rings.integer_ring import ZZ
|
|
32
|
+
from sage.rings.rational_field import QQ
|
|
33
|
+
from sage.rings.integer import Integer
|
|
34
|
+
from sage.modules.free_module_element import vector
|
|
35
|
+
from sage.matrix.constructor import Matrix
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def qfsolve(G):
|
|
39
|
+
r"""
|
|
40
|
+
Find a solution `x = (x_0,...,x_n)` to `x G x^t = 0` for an
|
|
41
|
+
`n \times n`-matrix ``G`` over `\QQ`.
|
|
42
|
+
|
|
43
|
+
OUTPUT:
|
|
44
|
+
|
|
45
|
+
If a solution exists, return a vector of rational numbers `x`.
|
|
46
|
+
Otherwise, returns `-1` if no solution exists over the reals or a
|
|
47
|
+
prime `p` if no solution exists over the `p`-adic field `\QQ_p`.
|
|
48
|
+
|
|
49
|
+
ALGORITHM:
|
|
50
|
+
|
|
51
|
+
Uses PARI/GP function :pari:`qfsolve`.
|
|
52
|
+
|
|
53
|
+
EXAMPLES::
|
|
54
|
+
|
|
55
|
+
sage: from sage.quadratic_forms.qfsolve import qfsolve
|
|
56
|
+
sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M
|
|
57
|
+
[ 0 0 -12]
|
|
58
|
+
[ 0 -12 0]
|
|
59
|
+
[-12 0 -1]
|
|
60
|
+
sage: sol = qfsolve(M); sol
|
|
61
|
+
(1, 0, 0)
|
|
62
|
+
sage: sol.parent()
|
|
63
|
+
Vector space of dimension 3 over Rational Field
|
|
64
|
+
|
|
65
|
+
sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
|
66
|
+
sage: ret = qfsolve(M); ret
|
|
67
|
+
-1
|
|
68
|
+
sage: ret.parent()
|
|
69
|
+
Integer Ring
|
|
70
|
+
|
|
71
|
+
sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, -7]])
|
|
72
|
+
sage: qfsolve(M)
|
|
73
|
+
7
|
|
74
|
+
|
|
75
|
+
sage: M = Matrix(QQ, [[3, 0, 0, 0], [0, 5, 0, 0], [0, 0, -7, 0], [0, 0, 0, -11]])
|
|
76
|
+
sage: qfsolve(M)
|
|
77
|
+
(3, 4, -3, -2)
|
|
78
|
+
"""
|
|
79
|
+
ret = G.__pari__().qfsolve()
|
|
80
|
+
if ret.type() == 't_COL':
|
|
81
|
+
return vector(QQ, ret)
|
|
82
|
+
return ZZ(ret)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def qfparam(G, sol):
|
|
86
|
+
r"""
|
|
87
|
+
Parametrize the conic defined by the matrix `G`.
|
|
88
|
+
|
|
89
|
+
INPUT:
|
|
90
|
+
|
|
91
|
+
- ``G`` -- a `3 \times 3`-matrix over `\QQ`
|
|
92
|
+
|
|
93
|
+
- ``sol`` -- a triple of rational numbers providing a solution
|
|
94
|
+
to `x\cdot G\cdot x^t = 0`
|
|
95
|
+
|
|
96
|
+
OUTPUT:
|
|
97
|
+
|
|
98
|
+
A triple of polynomials that parametrizes all solutions of
|
|
99
|
+
`x\cdot G\cdot x^t = 0` up to scaling.
|
|
100
|
+
|
|
101
|
+
ALGORITHM:
|
|
102
|
+
|
|
103
|
+
Uses PARI/GP function :pari:`qfparam`.
|
|
104
|
+
|
|
105
|
+
EXAMPLES::
|
|
106
|
+
|
|
107
|
+
sage: from sage.quadratic_forms.qfsolve import qfsolve, qfparam
|
|
108
|
+
sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M
|
|
109
|
+
[ 0 0 -12]
|
|
110
|
+
[ 0 -12 0]
|
|
111
|
+
[-12 0 -1]
|
|
112
|
+
sage: sol = qfsolve(M)
|
|
113
|
+
sage: ret = qfparam(M, sol); ret
|
|
114
|
+
(-12*t^2 - 1, 24*t, 24)
|
|
115
|
+
sage: ret.parent()
|
|
116
|
+
Ambient free module of rank 3 over the principal ideal domain
|
|
117
|
+
Univariate Polynomial Ring in t over Rational Field
|
|
118
|
+
"""
|
|
119
|
+
R = QQ['t']
|
|
120
|
+
mat = G.__pari__().qfparam(sol)
|
|
121
|
+
# Interpret the rows of mat as coefficients of polynomials
|
|
122
|
+
return vector(R, mat.Col())
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def solve(self, c=0):
|
|
126
|
+
r"""
|
|
127
|
+
Return a vector `x` such that ``self(x) == c``.
|
|
128
|
+
|
|
129
|
+
INPUT:
|
|
130
|
+
|
|
131
|
+
- ``c`` -- (default: 0) a rational number
|
|
132
|
+
|
|
133
|
+
OUTPUT: a nonzero vector `x` satisfying ``self(x) == c``
|
|
134
|
+
|
|
135
|
+
ALGORITHM:
|
|
136
|
+
|
|
137
|
+
Uses PARI's :pari:`qfsolve`. Algorithm described by Jeroen Demeyer; see comments on :issue:`19112`
|
|
138
|
+
|
|
139
|
+
EXAMPLES::
|
|
140
|
+
|
|
141
|
+
sage: F = DiagonalQuadraticForm(QQ, [1, -1]); F
|
|
142
|
+
Quadratic form in 2 variables over Rational Field with coefficients:
|
|
143
|
+
[ 1 0 ]
|
|
144
|
+
[ * -1 ]
|
|
145
|
+
sage: F.solve()
|
|
146
|
+
(1, 1)
|
|
147
|
+
sage: F.solve(1)
|
|
148
|
+
(1, 0)
|
|
149
|
+
sage: F.solve(2)
|
|
150
|
+
(3/2, -1/2)
|
|
151
|
+
sage: F.solve(3)
|
|
152
|
+
(2, -1)
|
|
153
|
+
|
|
154
|
+
::
|
|
155
|
+
|
|
156
|
+
sage: F = DiagonalQuadraticForm(QQ, [1, 1, 1, 1])
|
|
157
|
+
sage: F.solve(7)
|
|
158
|
+
(1, 2, -1, -1)
|
|
159
|
+
sage: F.solve()
|
|
160
|
+
Traceback (most recent call last):
|
|
161
|
+
...
|
|
162
|
+
ArithmeticError: no solution found (local obstruction at -1)
|
|
163
|
+
|
|
164
|
+
::
|
|
165
|
+
|
|
166
|
+
sage: Q = QuadraticForm(QQ, 2, [17, 94, 130])
|
|
167
|
+
sage: x = Q.solve(5); x
|
|
168
|
+
(17, -6)
|
|
169
|
+
sage: Q(x)
|
|
170
|
+
5
|
|
171
|
+
|
|
172
|
+
sage: Q.solve(6)
|
|
173
|
+
Traceback (most recent call last):
|
|
174
|
+
...
|
|
175
|
+
ArithmeticError: no solution found (local obstruction at 3)
|
|
176
|
+
|
|
177
|
+
sage: G = DiagonalQuadraticForm(QQ, [5, -3, -2])
|
|
178
|
+
sage: x = G.solve(10); x
|
|
179
|
+
(3/2, -1/2, 1/2)
|
|
180
|
+
sage: G(x)
|
|
181
|
+
10
|
|
182
|
+
|
|
183
|
+
sage: F = DiagonalQuadraticForm(QQ, [1, -4])
|
|
184
|
+
sage: x = F.solve(); x
|
|
185
|
+
(2, 1)
|
|
186
|
+
sage: F(x)
|
|
187
|
+
0
|
|
188
|
+
|
|
189
|
+
::
|
|
190
|
+
|
|
191
|
+
sage: F = QuadraticForm(QQ, 4, [0, 0, 1, 0, 0, 0, 1, 0, 0, 0]); F
|
|
192
|
+
Quadratic form in 4 variables over Rational Field with coefficients:
|
|
193
|
+
[ 0 0 1 0 ]
|
|
194
|
+
[ * 0 0 1 ]
|
|
195
|
+
[ * * 0 0 ]
|
|
196
|
+
[ * * * 0 ]
|
|
197
|
+
sage: F.solve(23)
|
|
198
|
+
(23, 0, 1, 0)
|
|
199
|
+
|
|
200
|
+
Other fields besides the rationals are currently not supported::
|
|
201
|
+
|
|
202
|
+
sage: F = DiagonalQuadraticForm(GF(11), [1, 1])
|
|
203
|
+
sage: F.solve()
|
|
204
|
+
Traceback (most recent call last):
|
|
205
|
+
...
|
|
206
|
+
TypeError: solving quadratic forms is only implemented over QQ
|
|
207
|
+
"""
|
|
208
|
+
if self.base_ring() is not QQ:
|
|
209
|
+
raise TypeError("solving quadratic forms is only implemented over QQ")
|
|
210
|
+
|
|
211
|
+
M = self.Gram_matrix()
|
|
212
|
+
|
|
213
|
+
# If no argument passed for c, we just pass self into qfsolve().
|
|
214
|
+
if not c:
|
|
215
|
+
x = qfsolve(M)
|
|
216
|
+
if isinstance(x, Integer):
|
|
217
|
+
raise ArithmeticError(f"no solution found (local obstruction at {x})")
|
|
218
|
+
return x
|
|
219
|
+
|
|
220
|
+
# If c != 0, define a new quadratic form Q = self - c*z^2
|
|
221
|
+
d = self.dim()
|
|
222
|
+
N = Matrix(self.base_ring(), d+1, d+1)
|
|
223
|
+
for i in range(d):
|
|
224
|
+
for j in range(d):
|
|
225
|
+
N[i, j] = M[i, j]
|
|
226
|
+
N[d, d] = -c
|
|
227
|
+
|
|
228
|
+
# Find a solution x to Q(x) = 0, using qfsolve()
|
|
229
|
+
x = qfsolve(N)
|
|
230
|
+
# Raise an error if qfsolve() doesn't find a solution
|
|
231
|
+
if isinstance(x, Integer):
|
|
232
|
+
raise ArithmeticError(f"no solution found (local obstruction at {x})")
|
|
233
|
+
|
|
234
|
+
# Let z be the last term of x, and remove z from x
|
|
235
|
+
z = x[-1]
|
|
236
|
+
x = x[:-1]
|
|
237
|
+
# If z != 0, then Q(x/z) = c
|
|
238
|
+
if z:
|
|
239
|
+
return x * (1/z)
|
|
240
|
+
|
|
241
|
+
# Case 2: We found a solution self(x) = 0. Let e be any vector such
|
|
242
|
+
# that B(x,e) != 0, where B is the bilinear form corresponding to self.
|
|
243
|
+
# To find e, just try all unit vectors (0,..0,1,0...0).
|
|
244
|
+
# Let a = (c - self(e))/(2B(x,e)) and let y = e + a*x.
|
|
245
|
+
# Then self(y) = B(e + a*x, e + a*x) = self(e) + 2B(e, a*x)
|
|
246
|
+
# = self(e) + 2([c - self(e)]/[2B(x,e)]) * B(x,e) = c.
|
|
247
|
+
e = vector([1] + [0] * (d-1))
|
|
248
|
+
i = 0
|
|
249
|
+
while self.bilinear_map(x, e) == 0:
|
|
250
|
+
e[i] = 0
|
|
251
|
+
i += 1
|
|
252
|
+
e[i] = 1
|
|
253
|
+
|
|
254
|
+
a = (c - self(e)) / (2 * self.bilinear_map(x, e))
|
|
255
|
+
return e + a*x
|