passagemath-flint 10.6.1rc10__cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.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.
- passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
- passagemath_flint-10.6.1rc10.dist-info/RECORD +360 -0
- passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
- passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
- passagemath_flint.libs/libflint-3701249d.so.21.0.0 +0 -0
- passagemath_flint.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
- passagemath_flint.libs/libgfortran-8a9a71bc.so.5.0.0 +0 -0
- passagemath_flint.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_flint.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_flint.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
- passagemath_flint.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
- passagemath_flint.libs/libntl-1004113e.so.44.0.1 +0 -0
- passagemath_flint.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
- sage/all__sagemath_flint.py +29 -0
- sage/combinat/all__sagemath_flint.py +1 -0
- sage/combinat/posets/all__sagemath_flint.py +1 -0
- sage/combinat/posets/hasse_cython_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython_flint.pyx +194 -0
- sage/data_structures/all__sagemath_flint.py +1 -0
- sage/data_structures/bounded_integer_sequences.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/data_structures/bounded_integer_sequences.pxd +62 -0
- sage/data_structures/bounded_integer_sequences.pyx +1418 -0
- sage/graphs/all__sagemath_flint.py +1 -0
- sage/graphs/chrompoly.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/graphs/chrompoly.pyx +555 -0
- sage/graphs/matchpoly.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/graphs/matchpoly.pyx +412 -0
- sage/libs/all__sagemath_flint.py +17 -0
- sage/libs/arb/__init__.py +1 -0
- sage/libs/arb/acb.pxd +154 -0
- sage/libs/arb/acb_calc.pxd +9 -0
- sage/libs/arb/acb_elliptic.pxd +25 -0
- sage/libs/arb/acb_hypgeom.pxd +74 -0
- sage/libs/arb/acb_mat.pxd +62 -0
- sage/libs/arb/acb_modular.pxd +17 -0
- sage/libs/arb/acb_poly.pxd +216 -0
- sage/libs/arb/arb.pxd +240 -0
- sage/libs/arb/arb_fmpz_poly.pxd +21 -0
- sage/libs/arb/arb_hypgeom.pxd +83 -0
- sage/libs/arb/arb_wrap.h +34 -0
- sage/libs/arb/arf.pxd +131 -0
- sage/libs/arb/arith.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/arb/arith.pyx +87 -0
- sage/libs/arb/bernoulli.pxd +6 -0
- sage/libs/arb/mag.pxd +77 -0
- sage/libs/arb/types.pxd +37 -0
- sage/libs/flint/__init__.py +1 -0
- sage/libs/flint/acb.pxd +270 -0
- sage/libs/flint/acb_calc.pxd +22 -0
- sage/libs/flint/acb_dft.pxd +51 -0
- sage/libs/flint/acb_dirichlet.pxd +112 -0
- sage/libs/flint/acb_elliptic.pxd +42 -0
- sage/libs/flint/acb_hypgeom.pxd +169 -0
- sage/libs/flint/acb_macros.pxd +9 -0
- sage/libs/flint/acb_mat.pxd +136 -0
- sage/libs/flint/acb_mat_macros.pxd +10 -0
- sage/libs/flint/acb_modular.pxd +62 -0
- sage/libs/flint/acb_poly.pxd +251 -0
- sage/libs/flint/acb_poly_macros.pxd +8 -0
- sage/libs/flint/acb_theta.pxd +124 -0
- sage/libs/flint/acf.pxd +32 -0
- sage/libs/flint/aprcl.pxd +84 -0
- sage/libs/flint/arb.pxd +382 -0
- sage/libs/flint/arb_calc.pxd +31 -0
- sage/libs/flint/arb_fmpz_poly.pxd +34 -0
- sage/libs/flint/arb_fpwrap.pxd +215 -0
- sage/libs/flint/arb_hypgeom.pxd +147 -0
- sage/libs/flint/arb_macros.pxd +9 -0
- sage/libs/flint/arb_mat.pxd +140 -0
- sage/libs/flint/arb_mat_macros.pxd +10 -0
- sage/libs/flint/arb_poly.pxd +237 -0
- sage/libs/flint/arf.pxd +167 -0
- sage/libs/flint/arith.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith.pxd +76 -0
- sage/libs/flint/arith.pyx +77 -0
- sage/libs/flint/arith_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith_sage.pyx +308 -0
- sage/libs/flint/bernoulli.pxd +28 -0
- sage/libs/flint/bool_mat.pxd +52 -0
- sage/libs/flint/ca.pxd +203 -0
- sage/libs/flint/ca_ext.pxd +34 -0
- sage/libs/flint/ca_field.pxd +32 -0
- sage/libs/flint/ca_mat.pxd +117 -0
- sage/libs/flint/ca_poly.pxd +104 -0
- sage/libs/flint/ca_vec.pxd +46 -0
- sage/libs/flint/calcium.pxd +27 -0
- sage/libs/flint/d_mat.pxd +39 -0
- sage/libs/flint/d_vec.pxd +32 -0
- sage/libs/flint/dirichlet.pxd +57 -0
- sage/libs/flint/dlog.pxd +53 -0
- sage/libs/flint/double_extras.pxd +24 -0
- sage/libs/flint/double_interval.pxd +36 -0
- sage/libs/flint/fexpr.pxd +104 -0
- sage/libs/flint/fexpr_builtin.pxd +20 -0
- sage/libs/flint/fft.pxd +66 -0
- sage/libs/flint/flint.pxd +36 -0
- sage/libs/flint/flint_ntl_wrap.h +35 -0
- sage/libs/flint/flint_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/flint_sage.pyx +163 -0
- sage/libs/flint/flint_wrap.h +190 -0
- sage/libs/flint/fmpq.pxd +137 -0
- sage/libs/flint/fmpq_mat.pxd +105 -0
- sage/libs/flint/fmpq_mat_macros.pxd +10 -0
- sage/libs/flint/fmpq_mpoly.pxd +165 -0
- sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
- sage/libs/flint/fmpq_poly.pxd +241 -0
- sage/libs/flint/fmpq_poly_macros.pxd +9 -0
- sage/libs/flint/fmpq_poly_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpq_poly_sage.pxd +31 -0
- sage/libs/flint/fmpq_poly_sage.pyx +48 -0
- sage/libs/flint/fmpq_vec.pxd +27 -0
- sage/libs/flint/fmpz.pxd +256 -0
- sage/libs/flint/fmpz_extras.pxd +32 -0
- sage/libs/flint/fmpz_factor.pxd +42 -0
- sage/libs/flint/fmpz_factor_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_factor_sage.pxd +4 -0
- sage/libs/flint/fmpz_factor_sage.pyx +29 -0
- sage/libs/flint/fmpz_lll.pxd +49 -0
- sage/libs/flint/fmpz_macros.pxd +8 -0
- sage/libs/flint/fmpz_mat.pxd +184 -0
- sage/libs/flint/fmpz_mat_macros.pxd +10 -0
- sage/libs/flint/fmpz_mod.pxd +46 -0
- sage/libs/flint/fmpz_mod_mat.pxd +71 -0
- sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
- sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fmpz_mod_poly.pxd +249 -0
- sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
- sage/libs/flint/fmpz_mod_vec.pxd +27 -0
- sage/libs/flint/fmpz_mpoly.pxd +224 -0
- sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
- sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
- sage/libs/flint/fmpz_poly.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly.pxd +407 -0
- sage/libs/flint/fmpz_poly.pyx +19 -0
- sage/libs/flint/fmpz_poly_factor.pxd +33 -0
- sage/libs/flint/fmpz_poly_macros.pxd +8 -0
- sage/libs/flint/fmpz_poly_mat.pxd +71 -0
- sage/libs/flint/fmpz_poly_q.pxd +55 -0
- sage/libs/flint/fmpz_poly_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly_sage.pxd +20 -0
- sage/libs/flint/fmpz_poly_sage.pyx +500 -0
- sage/libs/flint/fmpz_vec.pxd +80 -0
- sage/libs/flint/fmpzi.pxd +52 -0
- sage/libs/flint/fq.pxd +97 -0
- sage/libs/flint/fq_default.pxd +84 -0
- sage/libs/flint/fq_default_mat.pxd +70 -0
- sage/libs/flint/fq_default_poly.pxd +97 -0
- sage/libs/flint/fq_default_poly_factor.pxd +39 -0
- sage/libs/flint/fq_embed.pxd +28 -0
- sage/libs/flint/fq_mat.pxd +83 -0
- sage/libs/flint/fq_nmod.pxd +95 -0
- sage/libs/flint/fq_nmod_embed.pxd +28 -0
- sage/libs/flint/fq_nmod_mat.pxd +83 -0
- sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
- sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fq_nmod_poly.pxd +202 -0
- sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
- sage/libs/flint/fq_nmod_vec.pxd +33 -0
- sage/libs/flint/fq_poly.pxd +204 -0
- sage/libs/flint/fq_poly_factor.pxd +47 -0
- sage/libs/flint/fq_vec.pxd +33 -0
- sage/libs/flint/fq_zech.pxd +99 -0
- sage/libs/flint/fq_zech_embed.pxd +28 -0
- sage/libs/flint/fq_zech_mat.pxd +78 -0
- sage/libs/flint/fq_zech_poly.pxd +198 -0
- sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
- sage/libs/flint/fq_zech_vec.pxd +33 -0
- sage/libs/flint/gr.pxd +174 -0
- sage/libs/flint/gr_generic.pxd +215 -0
- sage/libs/flint/gr_mat.pxd +161 -0
- sage/libs/flint/gr_mpoly.pxd +68 -0
- sage/libs/flint/gr_poly.pxd +276 -0
- sage/libs/flint/gr_special.pxd +237 -0
- sage/libs/flint/gr_vec.pxd +120 -0
- sage/libs/flint/hypgeom.pxd +24 -0
- sage/libs/flint/long_extras.pxd +23 -0
- sage/libs/flint/mag.pxd +131 -0
- sage/libs/flint/mag_macros.pxd +8 -0
- sage/libs/flint/mpf_mat.pxd +36 -0
- sage/libs/flint/mpf_vec.pxd +34 -0
- sage/libs/flint/mpfr_mat.pxd +27 -0
- sage/libs/flint/mpfr_vec.pxd +25 -0
- sage/libs/flint/mpn_extras.pxd +41 -0
- sage/libs/flint/mpoly.pxd +72 -0
- sage/libs/flint/nf.pxd +19 -0
- sage/libs/flint/nf_elem.pxd +74 -0
- sage/libs/flint/nmod.pxd +35 -0
- sage/libs/flint/nmod_mat.pxd +104 -0
- sage/libs/flint/nmod_mpoly.pxd +144 -0
- sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/nmod_poly.pxd +339 -0
- sage/libs/flint/nmod_poly_factor.pxd +44 -0
- sage/libs/flint/nmod_poly_linkage.pxi +710 -0
- sage/libs/flint/nmod_poly_mat.pxd +76 -0
- sage/libs/flint/nmod_vec.pxd +40 -0
- sage/libs/flint/ntl_interface.pxd +17 -0
- sage/libs/flint/padic.pxd +93 -0
- sage/libs/flint/padic_mat.pxd +64 -0
- sage/libs/flint/padic_poly.pxd +88 -0
- sage/libs/flint/partitions.pxd +23 -0
- sage/libs/flint/perm.pxd +26 -0
- sage/libs/flint/profiler.pxd +24 -0
- sage/libs/flint/qadic.pxd +77 -0
- sage/libs/flint/qfb.pxd +44 -0
- sage/libs/flint/qqbar.pxd +172 -0
- sage/libs/flint/qsieve.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve.pxd +41 -0
- sage/libs/flint/qsieve.pyx +21 -0
- sage/libs/flint/qsieve_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve_sage.pyx +67 -0
- sage/libs/flint/thread_pool.pxd +25 -0
- sage/libs/flint/types.pxd +2076 -0
- sage/libs/flint/ulong_extras.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras.pxd +141 -0
- sage/libs/flint/ulong_extras.pyx +21 -0
- sage/libs/flint/ulong_extras_sage.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras_sage.pyx +21 -0
- sage/matrix/all__sagemath_flint.py +1 -0
- sage/matrix/change_ring.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/change_ring.pyx +43 -0
- sage/matrix/matrix_complex_ball_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_complex_ball_dense.pxd +14 -0
- sage/matrix/matrix_complex_ball_dense.pyx +973 -0
- sage/matrix/matrix_cyclo_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_cyclo_dense.pxd +16 -0
- sage/matrix/matrix_cyclo_dense.pyx +1761 -0
- sage/matrix/matrix_integer_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_dense.pxd +32 -0
- sage/matrix/matrix_integer_dense.pyx +5801 -0
- sage/matrix/matrix_integer_dense_hnf.py +1294 -0
- sage/matrix/matrix_integer_dense_saturation.py +346 -0
- sage/matrix/matrix_integer_sparse.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_sparse.pxd +9 -0
- sage/matrix/matrix_integer_sparse.pyx +1090 -0
- sage/matrix/matrix_rational_dense.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_dense.pxd +23 -0
- sage/matrix/matrix_rational_dense.pyx +2995 -0
- sage/matrix/matrix_rational_sparse.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_sparse.pxd +11 -0
- sage/matrix/matrix_rational_sparse.pyx +789 -0
- sage/matrix/misc_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/matrix/misc_flint.pyx +109 -0
- sage/modular/all__sagemath_flint.py +1 -0
- sage/modular/modform/all__sagemath_flint.py +1 -0
- sage/modular/modform/eis_series_cython.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/modform/eis_series_cython.pyx +226 -0
- sage/modular/modsym/all__sagemath_flint.py +1 -0
- sage/modular/modsym/apply.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/apply.pxd +6 -0
- sage/modular/modsym/apply.pyx +113 -0
- sage/modular/modsym/heilbronn.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/heilbronn.pyx +966 -0
- sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
- sage/modular/pollack_stevens/dist.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/modular/pollack_stevens/dist.pxd +38 -0
- sage/modular/pollack_stevens/dist.pyx +1439 -0
- sage/quivers/algebra.py +691 -0
- sage/quivers/algebra_elements.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/quivers/algebra_elements.pxd +97 -0
- sage/quivers/algebra_elements.pxi +1324 -0
- sage/quivers/algebra_elements.pyx +1424 -0
- sage/quivers/all.py +1 -0
- sage/quivers/ar_quiver.py +917 -0
- sage/quivers/homspace.py +640 -0
- sage/quivers/morphism.py +1282 -0
- sage/quivers/path_semigroup.py +1155 -0
- sage/quivers/paths.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/quivers/paths.pxd +13 -0
- sage/quivers/paths.pyx +809 -0
- sage/quivers/representation.py +2975 -0
- sage/rings/all__sagemath_flint.py +37 -0
- sage/rings/cif.py +4 -0
- sage/rings/complex_arb.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_arb.pxd +29 -0
- sage/rings/complex_arb.pyx +5176 -0
- sage/rings/complex_interval.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_interval.pxd +30 -0
- sage/rings/complex_interval.pyx +2475 -0
- sage/rings/complex_interval_field.py +711 -0
- sage/rings/convert/all.py +1 -0
- sage/rings/convert/mpfi.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/convert/mpfi.pxd +6 -0
- sage/rings/convert/mpfi.pyx +576 -0
- sage/rings/factorint_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/factorint_flint.pyx +99 -0
- sage/rings/fraction_field_FpT.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/fraction_field_FpT.pxd +28 -0
- sage/rings/fraction_field_FpT.pyx +2043 -0
- sage/rings/imaginary_unit.py +5 -0
- sage/rings/monomials.py +73 -0
- sage/rings/number_field/S_unit_solver.py +2870 -0
- sage/rings/number_field/all__sagemath_flint.py +7 -0
- sage/rings/number_field/bdd_height.py +664 -0
- sage/rings/number_field/class_group.py +762 -0
- sage/rings/number_field/galois_group.py +1307 -0
- sage/rings/number_field/homset.py +612 -0
- sage/rings/number_field/maps.py +687 -0
- sage/rings/number_field/morphism.py +272 -0
- sage/rings/number_field/number_field.py +12820 -0
- sage/rings/number_field/number_field_element.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element.pxd +59 -0
- sage/rings/number_field/number_field_element.pyx +5735 -0
- sage/rings/number_field/number_field_element_quadratic.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
- sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
- sage/rings/number_field/number_field_ideal_rel.py +925 -0
- sage/rings/number_field/number_field_morphisms.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_morphisms.pyx +781 -0
- sage/rings/number_field/number_field_rel.py +2734 -0
- sage/rings/number_field/order.py +2981 -0
- sage/rings/number_field/order_ideal.py +804 -0
- sage/rings/number_field/selmer_group.py +715 -0
- sage/rings/number_field/small_primes_of_degree_one.py +242 -0
- sage/rings/number_field/splitting_field.py +606 -0
- sage/rings/number_field/structure.py +380 -0
- sage/rings/number_field/unit_group.py +721 -0
- sage/rings/padics/all__sagemath_flint.py +3 -0
- sage/rings/polynomial/all__sagemath_flint.py +1 -0
- sage/rings/polynomial/complex_roots.py +312 -0
- sage/rings/polynomial/evaluation_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/evaluation_flint.pxd +7 -0
- sage/rings/polynomial/evaluation_flint.pyx +68 -0
- sage/rings/polynomial/hilbert.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/hilbert.pyx +602 -0
- sage/rings/polynomial/polynomial_complex_arb.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
- sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
- sage/rings/polynomial/polynomial_number_field.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_number_field.pyx +345 -0
- sage/rings/polynomial/polynomial_rational_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
- sage/rings/polynomial/polynomial_zmod_flint.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
- sage/rings/polynomial/real_roots.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/real_roots.pxd +81 -0
- sage/rings/polynomial/real_roots.pyx +4704 -0
- sage/rings/polynomial/refine_root.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/refine_root.pyx +142 -0
- sage/rings/polynomial/weil/all.py +4 -0
- sage/rings/polynomial/weil/power_sums.h +46 -0
- sage/rings/polynomial/weil/weil_polynomials.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
- sage/rings/qqbar.py +9025 -0
- sage/rings/real_arb.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/real_arb.pxd +21 -0
- sage/rings/real_arb.pyx +4065 -0
- sage/rings/real_interval_absolute.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/real_interval_absolute.pyx +1073 -0
- sage/rings/real_mpfi.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/rings/real_mpfi.pyx +5428 -0
- sage/schemes/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.cpython-313-aarch64-linux-gnu.so +0 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
- sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,1387 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-flint
|
2
|
+
# sage.doctest: needs sage.libs.ntl sage.libs.pari
|
3
|
+
r"""
|
4
|
+
Descent on elliptic curves over `\QQ` with a 2-isogeny
|
5
|
+
"""
|
6
|
+
|
7
|
+
# ***************************************************************************
|
8
|
+
# Copyright (C) 2009 Robert L. Miller <rlmillster@gmail.com>
|
9
|
+
#
|
10
|
+
# This program is free software: you can redistribute it and/or modify
|
11
|
+
# it under the terms of the GNU General Public License as published by
|
12
|
+
# the Free Software Foundation, either version 2 of the License, or
|
13
|
+
# (at your option) any later version.
|
14
|
+
# https://www.gnu.org/licenses/
|
15
|
+
# ***************************************************************************
|
16
|
+
|
17
|
+
from cysignals.memory cimport sig_malloc, sig_free
|
18
|
+
|
19
|
+
from sage.rings.integer_ring import ZZ
|
20
|
+
from sage.rings.polynomial.polynomial_ring import polygen
|
21
|
+
cdef object x_ZZ = polygen(ZZ)
|
22
|
+
from sage.rings.polynomial.real_roots import real_roots
|
23
|
+
from sage.arith.misc import prime_divisors
|
24
|
+
import sage.libs.ntl.all as ntl
|
25
|
+
|
26
|
+
from sage.rings.integer cimport Integer
|
27
|
+
from sage.libs.gmp.mpz cimport *
|
28
|
+
from sage.libs.flint.fmpz_poly cimport *
|
29
|
+
from sage.libs.flint.fmpz_poly_sage cimport *
|
30
|
+
from sage.libs.flint.nmod_poly cimport *
|
31
|
+
from sage.libs.flint.nmod_poly_factor cimport *
|
32
|
+
from sage.libs.flint.ulong_extras cimport *
|
33
|
+
|
34
|
+
from sage.schemes.elliptic_curves.descent_two_isogeny_pari cimport ratpoints_mpz_exists_only
|
35
|
+
|
36
|
+
DEF N_RES_CLASSES_BSD = 10
|
37
|
+
|
38
|
+
|
39
|
+
cdef unsigned long valuation(mpz_t a, mpz_t p) noexcept:
|
40
|
+
"""
|
41
|
+
Return the number of times p divides a.
|
42
|
+
"""
|
43
|
+
cdef mpz_t aa
|
44
|
+
cdef unsigned long v
|
45
|
+
mpz_init(aa)
|
46
|
+
v = mpz_remove(aa, a, p)
|
47
|
+
mpz_clear(aa)
|
48
|
+
return v
|
49
|
+
|
50
|
+
|
51
|
+
def test_valuation(a, p):
|
52
|
+
"""
|
53
|
+
Doctest function for cdef long valuation(mpz_t, mpz_t).
|
54
|
+
|
55
|
+
EXAMPLES::
|
56
|
+
|
57
|
+
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_valuation as tv
|
58
|
+
sage: for i in [1..20]:
|
59
|
+
....: print('{:>10} {} {} {}'.format(str(factor(i)), tv(i,2), tv(i,3), tv(i,5)))
|
60
|
+
1 0 0 0
|
61
|
+
2 1 0 0
|
62
|
+
3 0 1 0
|
63
|
+
2^2 2 0 0
|
64
|
+
5 0 0 1
|
65
|
+
2 * 3 1 1 0
|
66
|
+
7 0 0 0
|
67
|
+
2^3 3 0 0
|
68
|
+
3^2 0 2 0
|
69
|
+
2 * 5 1 0 1
|
70
|
+
11 0 0 0
|
71
|
+
2^2 * 3 2 1 0
|
72
|
+
13 0 0 0
|
73
|
+
2 * 7 1 0 0
|
74
|
+
3 * 5 0 1 1
|
75
|
+
2^4 4 0 0
|
76
|
+
17 0 0 0
|
77
|
+
2 * 3^2 1 2 0
|
78
|
+
19 0 0 0
|
79
|
+
2^2 * 5 2 0 1
|
80
|
+
"""
|
81
|
+
cdef Integer A = Integer(a)
|
82
|
+
cdef Integer P = Integer(p)
|
83
|
+
return valuation(A.value, P.value)
|
84
|
+
|
85
|
+
|
86
|
+
cdef int padic_square(mpz_t a, mpz_t p) noexcept:
|
87
|
+
"""
|
88
|
+
Test if a is a `p`-adic square.
|
89
|
+
"""
|
90
|
+
cdef unsigned long v
|
91
|
+
cdef mpz_t aa
|
92
|
+
cdef int result
|
93
|
+
|
94
|
+
if mpz_sgn(a) == 0:
|
95
|
+
return 1
|
96
|
+
|
97
|
+
v = valuation(a, p)
|
98
|
+
if v & 1:
|
99
|
+
return 0
|
100
|
+
|
101
|
+
mpz_init_set(aa, a)
|
102
|
+
while v:
|
103
|
+
v -= 1
|
104
|
+
mpz_divexact(aa, aa, p)
|
105
|
+
if mpz_cmp_ui(p, 2) == 0:
|
106
|
+
result = bool(mpz_fdiv_ui(aa, 8) == 1)
|
107
|
+
else:
|
108
|
+
result = bool(mpz_legendre(aa, p) == 1)
|
109
|
+
mpz_clear(aa)
|
110
|
+
return result
|
111
|
+
|
112
|
+
|
113
|
+
def test_padic_square(a, p):
|
114
|
+
"""
|
115
|
+
Doctest function for cdef int padic_square(mpz_t, unsigned long).
|
116
|
+
|
117
|
+
EXAMPLES::
|
118
|
+
|
119
|
+
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_padic_square as ps
|
120
|
+
sage: for i in [1..300]:
|
121
|
+
....: for p in prime_range(100):
|
122
|
+
....: if Qp(p)(i).is_square() != bool(ps(i,p)):
|
123
|
+
....: print(i, p)
|
124
|
+
"""
|
125
|
+
cdef Integer A = Integer(a)
|
126
|
+
cdef Integer P = Integer(p)
|
127
|
+
return padic_square(A.value, P.value)
|
128
|
+
|
129
|
+
|
130
|
+
cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
|
131
|
+
mpz_t x, mpz_t p, unsigned long nu) noexcept:
|
132
|
+
"""
|
133
|
+
Implement Lemma 6 of BSD's "Notes on elliptic curves, I" for odd `p`.
|
134
|
+
|
135
|
+
Returns -1 for insoluble, 0 for undecided, +1 for soluble.
|
136
|
+
"""
|
137
|
+
cdef mpz_t g_of_x, g_prime_of_x
|
138
|
+
cdef unsigned long lambd, mu
|
139
|
+
cdef int result = -1
|
140
|
+
|
141
|
+
mpz_init(g_of_x)
|
142
|
+
mpz_mul(g_of_x, a, x)
|
143
|
+
mpz_add(g_of_x, g_of_x, b)
|
144
|
+
mpz_mul(g_of_x, g_of_x, x)
|
145
|
+
mpz_add(g_of_x, g_of_x, c)
|
146
|
+
mpz_mul(g_of_x, g_of_x, x)
|
147
|
+
mpz_add(g_of_x, g_of_x, d)
|
148
|
+
mpz_mul(g_of_x, g_of_x, x)
|
149
|
+
mpz_add(g_of_x, g_of_x, e)
|
150
|
+
|
151
|
+
if padic_square(g_of_x, p):
|
152
|
+
mpz_clear(g_of_x)
|
153
|
+
return +1 # soluble
|
154
|
+
|
155
|
+
mpz_init_set(g_prime_of_x, x)
|
156
|
+
mpz_mul(g_prime_of_x, a, x)
|
157
|
+
mpz_mul_ui(g_prime_of_x, g_prime_of_x, 4)
|
158
|
+
mpz_addmul_ui(g_prime_of_x, b, 3)
|
159
|
+
mpz_mul(g_prime_of_x, g_prime_of_x, x)
|
160
|
+
mpz_addmul_ui(g_prime_of_x, c, 2)
|
161
|
+
mpz_mul(g_prime_of_x, g_prime_of_x, x)
|
162
|
+
mpz_add(g_prime_of_x, g_prime_of_x, d)
|
163
|
+
|
164
|
+
lambd = valuation(g_of_x, p)
|
165
|
+
if mpz_sgn(g_prime_of_x) == 0:
|
166
|
+
if lambd >= 2*nu:
|
167
|
+
result = 0 # undecided
|
168
|
+
else:
|
169
|
+
mu = valuation(g_prime_of_x, p)
|
170
|
+
if lambd > 2*mu:
|
171
|
+
result = 1 # soluble
|
172
|
+
elif lambd >= 2*nu and mu >= nu:
|
173
|
+
result = 0 # undecided
|
174
|
+
|
175
|
+
mpz_clear(g_prime_of_x)
|
176
|
+
mpz_clear(g_of_x)
|
177
|
+
return result
|
178
|
+
|
179
|
+
|
180
|
+
cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
|
181
|
+
mpz_t x, mpz_t p, unsigned long nu) noexcept:
|
182
|
+
"""
|
183
|
+
Implement Lemma 7 of BSD's "Notes on elliptic curves, I" for `p=2`.
|
184
|
+
|
185
|
+
Returns -1 for insoluble, 0 for undecided, +1 for soluble.
|
186
|
+
"""
|
187
|
+
cdef mpz_t g_of_x, g_prime_of_x, g_of_x_odd_part
|
188
|
+
cdef unsigned long lambd, mu, g_of_x_odd_part_mod_4
|
189
|
+
cdef int result = -1
|
190
|
+
|
191
|
+
mpz_init(g_of_x)
|
192
|
+
mpz_mul(g_of_x, a, x)
|
193
|
+
mpz_add(g_of_x, g_of_x, b)
|
194
|
+
mpz_mul(g_of_x, g_of_x, x)
|
195
|
+
mpz_add(g_of_x, g_of_x, c)
|
196
|
+
mpz_mul(g_of_x, g_of_x, x)
|
197
|
+
mpz_add(g_of_x, g_of_x, d)
|
198
|
+
mpz_mul(g_of_x, g_of_x, x)
|
199
|
+
mpz_add(g_of_x, g_of_x, e)
|
200
|
+
|
201
|
+
if padic_square(g_of_x, p):
|
202
|
+
mpz_clear(g_of_x)
|
203
|
+
return +1 # soluble
|
204
|
+
|
205
|
+
mpz_init_set(g_prime_of_x, x)
|
206
|
+
mpz_mul(g_prime_of_x, a, x)
|
207
|
+
mpz_mul_ui(g_prime_of_x, g_prime_of_x, 4)
|
208
|
+
mpz_addmul_ui(g_prime_of_x, b, 3)
|
209
|
+
mpz_mul(g_prime_of_x, g_prime_of_x, x)
|
210
|
+
mpz_addmul_ui(g_prime_of_x, c, 2)
|
211
|
+
mpz_mul(g_prime_of_x, g_prime_of_x, x)
|
212
|
+
mpz_add(g_prime_of_x, g_prime_of_x, d)
|
213
|
+
|
214
|
+
lambd = valuation(g_of_x, p)
|
215
|
+
mpz_init_set(g_of_x_odd_part, g_of_x)
|
216
|
+
while mpz_even_p(g_of_x_odd_part):
|
217
|
+
mpz_divexact_ui(g_of_x_odd_part, g_of_x_odd_part, 2)
|
218
|
+
g_of_x_odd_part_mod_4 = mpz_fdiv_ui(g_of_x_odd_part, 4)
|
219
|
+
if mpz_sgn(g_prime_of_x) == 0:
|
220
|
+
if lambd >= 2*nu:
|
221
|
+
result = 0 # undecided
|
222
|
+
elif lambd == 2*nu-2 and g_of_x_odd_part_mod_4==1:
|
223
|
+
result = 0 # undecided
|
224
|
+
else:
|
225
|
+
mu = valuation(g_prime_of_x, p)
|
226
|
+
if lambd > 2*mu:
|
227
|
+
result = 1 # soluble
|
228
|
+
elif nu > mu:
|
229
|
+
if lambd >= mu+nu:
|
230
|
+
result = 1 # soluble
|
231
|
+
elif lambd+1 == mu+nu and (lambd & 1) == 0:
|
232
|
+
result = 1 # soluble
|
233
|
+
elif lambd+2 == mu+nu and (lambd & 1) == 0 and g_of_x_odd_part_mod_4 == 1:
|
234
|
+
result = 1 # soluble
|
235
|
+
else: # nu <= mu
|
236
|
+
if lambd >= 2*nu:
|
237
|
+
result = 0 # undecided
|
238
|
+
elif lambd+2 == 2*nu and g_of_x_odd_part_mod_4==1:
|
239
|
+
result = 0 # undecided
|
240
|
+
|
241
|
+
mpz_clear(g_prime_of_x)
|
242
|
+
mpz_clear(g_of_x)
|
243
|
+
return result
|
244
|
+
|
245
|
+
|
246
|
+
cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
|
247
|
+
mpz_t x_k, mpz_t p, unsigned long k) noexcept:
|
248
|
+
"""
|
249
|
+
Uses the approach of BSD's "Notes on elliptic curves, I" to test for
|
250
|
+
solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp, with
|
251
|
+
x=x_k (mod p^k).
|
252
|
+
"""
|
253
|
+
# returns solubility of y^2 = ax^4 + bx^3 + cx^2 + dx + e
|
254
|
+
# in Zp with x=x_k (mod p^k)
|
255
|
+
cdef int code
|
256
|
+
cdef unsigned long t
|
257
|
+
cdef mpz_t s
|
258
|
+
|
259
|
+
if mpz_cmp_ui(p, 2) == 0:
|
260
|
+
code = lemma7(a, b, c, d, e, x_k, p, k)
|
261
|
+
else:
|
262
|
+
code = lemma6(a, b, c, d, e, x_k, p, k)
|
263
|
+
if code == 1:
|
264
|
+
return 1
|
265
|
+
if code == -1:
|
266
|
+
return 0
|
267
|
+
|
268
|
+
# now code == 0
|
269
|
+
t = 0
|
270
|
+
mpz_init(s)
|
271
|
+
while code == 0 and mpz_cmp_ui(p, t) > 0 and t < N_RES_CLASSES_BSD:
|
272
|
+
mpz_pow_ui(s, p, k)
|
273
|
+
mpz_mul_ui(s, s, t)
|
274
|
+
mpz_add(s, s, x_k)
|
275
|
+
code = Zp_soluble_BSD(a, b, c, d, e, s, p, k+1)
|
276
|
+
t += 1
|
277
|
+
mpz_clear(s)
|
278
|
+
return code
|
279
|
+
|
280
|
+
|
281
|
+
cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e,
|
282
|
+
mpz_t pp, unsigned long pp_ui,
|
283
|
+
nmod_poly_factor_t f_factzn, nmod_poly_t f,
|
284
|
+
fmpz_poly_t f1, fmpz_poly_t linear) noexcept:
|
285
|
+
"""
|
286
|
+
Uses the approach of Algorithm 5.3.1 of Siksek's thesis to test for
|
287
|
+
solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp.
|
288
|
+
"""
|
289
|
+
cdef unsigned long v_min, v
|
290
|
+
cdef unsigned long roots[4]
|
291
|
+
cdef int i, j, has_roots, has_single_roots
|
292
|
+
cdef bint result
|
293
|
+
|
294
|
+
cdef mpz_t aa, bb, cc, dd, ee
|
295
|
+
cdef mpz_t aaa, bbb, ccc, ddd, eee
|
296
|
+
cdef unsigned long qq
|
297
|
+
cdef unsigned long rr, ss
|
298
|
+
cdef mpz_t tt
|
299
|
+
|
300
|
+
# Step 0: divide out all common p from the quartic
|
301
|
+
v_min = valuation(a, pp)
|
302
|
+
if mpz_cmp_ui(b, 0) != 0:
|
303
|
+
v = valuation(b, pp)
|
304
|
+
if v < v_min:
|
305
|
+
v_min = v
|
306
|
+
if mpz_cmp_ui(c, 0) != 0:
|
307
|
+
v = valuation(c, pp)
|
308
|
+
if v < v_min:
|
309
|
+
v_min = v
|
310
|
+
if mpz_cmp_ui(d, 0) != 0:
|
311
|
+
v = valuation(d, pp)
|
312
|
+
if v < v_min:
|
313
|
+
v_min = v
|
314
|
+
if mpz_cmp_ui(e, 0) != 0:
|
315
|
+
v = valuation(e, pp)
|
316
|
+
if v < v_min:
|
317
|
+
v_min = v
|
318
|
+
for v in range(v_min):
|
319
|
+
mpz_divexact(a, a, pp)
|
320
|
+
mpz_divexact(b, b, pp)
|
321
|
+
mpz_divexact(c, c, pp)
|
322
|
+
mpz_divexact(d, d, pp)
|
323
|
+
mpz_divexact(e, e, pp)
|
324
|
+
|
325
|
+
if not v_min % 2:
|
326
|
+
# Step I in Alg. 5.3.1 of Siksek's thesis
|
327
|
+
nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui))
|
328
|
+
nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui))
|
329
|
+
nmod_poly_set_coeff_ui(f, 2, mpz_fdiv_ui(c, pp_ui))
|
330
|
+
nmod_poly_set_coeff_ui(f, 3, mpz_fdiv_ui(b, pp_ui))
|
331
|
+
nmod_poly_set_coeff_ui(f, 4, mpz_fdiv_ui(a, pp_ui))
|
332
|
+
|
333
|
+
result = 0
|
334
|
+
(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct
|
335
|
+
qq = nmod_poly_factor(f_factzn, f)
|
336
|
+
for i in range(f_factzn.num):
|
337
|
+
if f_factzn.exp[i]&1:
|
338
|
+
result = 1
|
339
|
+
break
|
340
|
+
if result == 0 and n_jacobi(qq, pp_ui) == 1:
|
341
|
+
result = 1
|
342
|
+
if result:
|
343
|
+
return 1
|
344
|
+
|
345
|
+
nmod_poly_zero(f)
|
346
|
+
nmod_poly_set_coeff_ui(f, 0, 1)
|
347
|
+
for i in range(f_factzn.num):
|
348
|
+
for j in range(f_factzn.exp[i]>>1):
|
349
|
+
nmod_poly_mul(f, f, &f_factzn.p[i])
|
350
|
+
|
351
|
+
(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct
|
352
|
+
nmod_poly_factor(f_factzn, f)
|
353
|
+
has_roots = 0
|
354
|
+
j = 0
|
355
|
+
for i in range(f_factzn.num):
|
356
|
+
if nmod_poly_degree(&f_factzn.p[i]) == 1 and 0 != nmod_poly_get_coeff_ui(&f_factzn.p[i], 1):
|
357
|
+
has_roots = 1
|
358
|
+
roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0)
|
359
|
+
j += 1
|
360
|
+
if not has_roots:
|
361
|
+
return 0
|
362
|
+
|
363
|
+
i = nmod_poly_degree(f)
|
364
|
+
mpz_init(aaa)
|
365
|
+
mpz_init(bbb)
|
366
|
+
mpz_init(ccc)
|
367
|
+
mpz_init(ddd)
|
368
|
+
mpz_init(eee)
|
369
|
+
|
370
|
+
if i == 0: # g == 1
|
371
|
+
mpz_set(aaa, a)
|
372
|
+
mpz_set(bbb, b)
|
373
|
+
mpz_set(ccc, c)
|
374
|
+
mpz_set(ddd, d)
|
375
|
+
mpz_sub_ui(eee, e, qq)
|
376
|
+
elif i == 1: # g == x + rr
|
377
|
+
mpz_set(aaa, a)
|
378
|
+
mpz_set(bbb, b)
|
379
|
+
mpz_sub_ui(ccc, c, qq)
|
380
|
+
rr = nmod_poly_get_coeff_ui(f, 0)
|
381
|
+
ss = rr*qq
|
382
|
+
mpz_set(ddd,d)
|
383
|
+
mpz_sub_ui(ddd, ddd, ss*2)
|
384
|
+
mpz_set(eee,e)
|
385
|
+
mpz_sub_ui(eee, eee, ss*rr)
|
386
|
+
elif i == 2: # g == x^2 + rr*x + ss
|
387
|
+
mpz_sub_ui(aaa, a, qq)
|
388
|
+
rr = nmod_poly_get_coeff_ui(f, 1)
|
389
|
+
mpz_init(tt)
|
390
|
+
mpz_set_ui(tt, rr*qq)
|
391
|
+
mpz_set(bbb,b)
|
392
|
+
mpz_submul_ui(bbb, tt, 2)
|
393
|
+
mpz_set(ccc,c)
|
394
|
+
mpz_submul_ui(ccc, tt, rr)
|
395
|
+
ss = nmod_poly_get_coeff_ui(f, 0)
|
396
|
+
mpz_set_ui(tt, ss*qq)
|
397
|
+
mpz_set(eee,e)
|
398
|
+
mpz_submul_ui(eee, tt, ss)
|
399
|
+
mpz_mul_ui(tt, tt, 2)
|
400
|
+
mpz_sub(ccc, ccc, tt)
|
401
|
+
mpz_set(ddd,d)
|
402
|
+
mpz_submul_ui(ddd, tt, rr)
|
403
|
+
mpz_clear(tt)
|
404
|
+
mpz_divexact(aaa, aaa, pp)
|
405
|
+
mpz_divexact(bbb, bbb, pp)
|
406
|
+
mpz_divexact(ccc, ccc, pp)
|
407
|
+
mpz_divexact(ddd, ddd, pp)
|
408
|
+
mpz_divexact(eee, eee, pp)
|
409
|
+
# now aaa, bbb, ccc, ddd, eee represents h(x)
|
410
|
+
|
411
|
+
result = 0
|
412
|
+
mpz_init(tt)
|
413
|
+
for i in range(j):
|
414
|
+
mpz_mul_ui(tt, aaa, roots[i])
|
415
|
+
mpz_add(tt, tt, bbb)
|
416
|
+
mpz_mul_ui(tt, tt, roots[i])
|
417
|
+
mpz_add(tt, tt, ccc)
|
418
|
+
mpz_mul_ui(tt, tt, roots[i])
|
419
|
+
mpz_add(tt, tt, ddd)
|
420
|
+
mpz_mul_ui(tt, tt, roots[i])
|
421
|
+
mpz_add(tt, tt, eee)
|
422
|
+
# tt == h(r) mod p
|
423
|
+
mpz_mod(tt, tt, pp)
|
424
|
+
if mpz_sgn(tt) == 0:
|
425
|
+
fmpz_poly_zero(f1)
|
426
|
+
fmpz_poly_zero(linear)
|
427
|
+
fmpz_poly_set_coeff_mpz(f1, 0, e)
|
428
|
+
fmpz_poly_set_coeff_mpz(f1, 1, d)
|
429
|
+
fmpz_poly_set_coeff_mpz(f1, 2, c)
|
430
|
+
fmpz_poly_set_coeff_mpz(f1, 3, b)
|
431
|
+
fmpz_poly_set_coeff_mpz(f1, 4, a)
|
432
|
+
fmpz_poly_set_coeff_ui(linear, 0, roots[i])
|
433
|
+
fmpz_poly_set_coeff_mpz(linear, 1, pp)
|
434
|
+
fmpz_poly_compose(f1, f1, linear)
|
435
|
+
fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)
|
436
|
+
fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)
|
437
|
+
mpz_init(aa)
|
438
|
+
mpz_init(bb)
|
439
|
+
mpz_init(cc)
|
440
|
+
mpz_init(dd)
|
441
|
+
mpz_init(ee)
|
442
|
+
fmpz_poly_get_coeff_mpz(aa, f1, 4)
|
443
|
+
fmpz_poly_get_coeff_mpz(bb, f1, 3)
|
444
|
+
fmpz_poly_get_coeff_mpz(cc, f1, 2)
|
445
|
+
fmpz_poly_get_coeff_mpz(dd, f1, 1)
|
446
|
+
fmpz_poly_get_coeff_mpz(ee, f1, 0)
|
447
|
+
result = Zp_soluble_siksek(aa, bb, cc, dd, ee, pp, pp_ui, f_factzn, f, f1, linear)
|
448
|
+
mpz_clear(aa)
|
449
|
+
mpz_clear(bb)
|
450
|
+
mpz_clear(cc)
|
451
|
+
mpz_clear(dd)
|
452
|
+
mpz_clear(ee)
|
453
|
+
if result == 1:
|
454
|
+
break
|
455
|
+
mpz_clear(aaa)
|
456
|
+
mpz_clear(bbb)
|
457
|
+
mpz_clear(ccc)
|
458
|
+
mpz_clear(ddd)
|
459
|
+
mpz_clear(eee)
|
460
|
+
mpz_clear(tt)
|
461
|
+
return result
|
462
|
+
else:
|
463
|
+
# Step II in Alg. 5.3.1 of Siksek's thesis
|
464
|
+
nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui))
|
465
|
+
nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui))
|
466
|
+
nmod_poly_set_coeff_ui(f, 2, mpz_fdiv_ui(c, pp_ui))
|
467
|
+
nmod_poly_set_coeff_ui(f, 3, mpz_fdiv_ui(b, pp_ui))
|
468
|
+
nmod_poly_set_coeff_ui(f, 4, mpz_fdiv_ui(a, pp_ui))
|
469
|
+
(<nmod_poly_factor_struct *>f_factzn)[0].num = 0 # reset data struct
|
470
|
+
nmod_poly_factor(f_factzn, f)
|
471
|
+
has_roots = 0
|
472
|
+
has_single_roots = 0
|
473
|
+
j = 0
|
474
|
+
for i in range(f_factzn.num):
|
475
|
+
if nmod_poly_degree(&f_factzn.p[i]) == 1 and 0 != nmod_poly_get_coeff_ui(&f_factzn.p[i], 1):
|
476
|
+
has_roots = 1
|
477
|
+
if f_factzn.exp[i] == 1:
|
478
|
+
has_single_roots = 1
|
479
|
+
break
|
480
|
+
roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0)
|
481
|
+
j += 1
|
482
|
+
|
483
|
+
if not has_roots:
|
484
|
+
return 0
|
485
|
+
if has_single_roots:
|
486
|
+
return 1
|
487
|
+
|
488
|
+
result = 0
|
489
|
+
if j > 0:
|
490
|
+
mpz_init(aa)
|
491
|
+
mpz_init(bb)
|
492
|
+
mpz_init(cc)
|
493
|
+
mpz_init(dd)
|
494
|
+
mpz_init(ee)
|
495
|
+
for i in range(j):
|
496
|
+
fmpz_poly_zero(f1)
|
497
|
+
fmpz_poly_zero(linear)
|
498
|
+
fmpz_poly_set_coeff_mpz(f1, 0, e)
|
499
|
+
fmpz_poly_set_coeff_mpz(f1, 1, d)
|
500
|
+
fmpz_poly_set_coeff_mpz(f1, 2, c)
|
501
|
+
fmpz_poly_set_coeff_mpz(f1, 3, b)
|
502
|
+
fmpz_poly_set_coeff_mpz(f1, 4, a)
|
503
|
+
fmpz_poly_set_coeff_ui(linear, 0, roots[i])
|
504
|
+
fmpz_poly_set_coeff_mpz(linear, 1, pp)
|
505
|
+
fmpz_poly_compose(f1, f1, linear)
|
506
|
+
fmpz_poly_scalar_fdiv_ui(f1, f1, pp_ui)
|
507
|
+
fmpz_poly_get_coeff_mpz(aa, f1, 4)
|
508
|
+
fmpz_poly_get_coeff_mpz(bb, f1, 3)
|
509
|
+
fmpz_poly_get_coeff_mpz(cc, f1, 2)
|
510
|
+
fmpz_poly_get_coeff_mpz(dd, f1, 1)
|
511
|
+
fmpz_poly_get_coeff_mpz(ee, f1, 0)
|
512
|
+
result = Zp_soluble_siksek(aa, bb, cc, dd, ee, pp, pp_ui, f_factzn, f, f1, linear)
|
513
|
+
if result == 1:
|
514
|
+
break
|
515
|
+
if j > 0:
|
516
|
+
mpz_clear(aa)
|
517
|
+
mpz_clear(bb)
|
518
|
+
mpz_clear(cc)
|
519
|
+
mpz_clear(dd)
|
520
|
+
mpz_clear(ee)
|
521
|
+
return result
|
522
|
+
|
523
|
+
cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t pp,
|
524
|
+
fmpz_poly_t f1, fmpz_poly_t linear) noexcept:
|
525
|
+
"""
|
526
|
+
Uses the approach of Algorithm 5.3.1 of Siksek's thesis to test for
|
527
|
+
solubility of y^2 == ax^4 + bx^3 + cx^2 + dx + e over Zp.
|
528
|
+
"""
|
529
|
+
cdef unsigned long v_min, v
|
530
|
+
cdef mpz_t roots[4]
|
531
|
+
cdef int i, j, has_roots, has_single_roots
|
532
|
+
cdef bint result
|
533
|
+
|
534
|
+
cdef mpz_t aa, bb, cc, dd, ee
|
535
|
+
cdef mpz_t aaa, bbb, ccc, ddd, eee
|
536
|
+
cdef mpz_t qq, rr, ss, tt
|
537
|
+
cdef Integer A, B, C, D, E, P
|
538
|
+
|
539
|
+
# Step 0: divide out all common p from the quartic
|
540
|
+
v_min = valuation(a, pp)
|
541
|
+
if mpz_cmp_ui(b, 0) != 0:
|
542
|
+
v = valuation(b, pp)
|
543
|
+
if v < v_min:
|
544
|
+
v_min = v
|
545
|
+
if mpz_cmp_ui(c, 0) != 0:
|
546
|
+
v = valuation(c, pp)
|
547
|
+
if v < v_min:
|
548
|
+
v_min = v
|
549
|
+
if mpz_cmp_ui(d, 0) != 0:
|
550
|
+
v = valuation(d, pp)
|
551
|
+
if v < v_min:
|
552
|
+
v_min = v
|
553
|
+
if mpz_cmp_ui(e, 0) != 0:
|
554
|
+
v = valuation(e, pp)
|
555
|
+
if v < v_min:
|
556
|
+
v_min = v
|
557
|
+
for v in range(v_min):
|
558
|
+
mpz_divexact(a, a, pp)
|
559
|
+
mpz_divexact(b, b, pp)
|
560
|
+
mpz_divexact(c, c, pp)
|
561
|
+
mpz_divexact(d, d, pp)
|
562
|
+
mpz_divexact(e, e, pp)
|
563
|
+
|
564
|
+
if not v_min % 2:
|
565
|
+
# Step I in Alg. 5.3.1 of Siksek's thesis
|
566
|
+
A = Integer(0)
|
567
|
+
B = Integer(0)
|
568
|
+
C = Integer(0)
|
569
|
+
D = Integer(0)
|
570
|
+
E = Integer(0)
|
571
|
+
P = Integer(0)
|
572
|
+
mpz_set(A.value, a)
|
573
|
+
mpz_set(B.value, b)
|
574
|
+
mpz_set(C.value, c)
|
575
|
+
mpz_set(D.value, d)
|
576
|
+
mpz_set(E.value, e)
|
577
|
+
mpz_set(P.value, pp)
|
578
|
+
f = ntl.ZZ_pX([E, D, C, B, A], P)
|
579
|
+
f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E
|
580
|
+
mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial
|
581
|
+
f_factzn = f.factor()
|
582
|
+
result = 0
|
583
|
+
for factor, exponent in f_factzn:
|
584
|
+
if exponent&1:
|
585
|
+
result = 1
|
586
|
+
break
|
587
|
+
if result == 0 and mpz_legendre(qq, pp) == 1:
|
588
|
+
result = 1
|
589
|
+
if result:
|
590
|
+
return 1
|
591
|
+
|
592
|
+
f = ntl.ZZ_pX([1], P)
|
593
|
+
for factor, exponent in f_factzn:
|
594
|
+
for j in range(exponent // 2):
|
595
|
+
f *= factor
|
596
|
+
|
597
|
+
f /= f.leading_coefficient()
|
598
|
+
f_factzn = f.factor()
|
599
|
+
|
600
|
+
has_roots = 0
|
601
|
+
j = 0
|
602
|
+
for factor, exponent in f_factzn:
|
603
|
+
if factor.degree() == 1:
|
604
|
+
has_roots = 1
|
605
|
+
A = P - Integer(factor[0])
|
606
|
+
mpz_set(roots[j], A.value)
|
607
|
+
j += 1
|
608
|
+
if not has_roots:
|
609
|
+
return 0
|
610
|
+
|
611
|
+
i = f.degree()
|
612
|
+
mpz_init(aaa)
|
613
|
+
mpz_init(bbb)
|
614
|
+
mpz_init(ccc)
|
615
|
+
mpz_init(ddd)
|
616
|
+
mpz_init(eee)
|
617
|
+
|
618
|
+
if i == 0: # g == 1
|
619
|
+
mpz_set(aaa, a)
|
620
|
+
mpz_set(bbb, b)
|
621
|
+
mpz_set(ccc, c)
|
622
|
+
mpz_set(ddd, d)
|
623
|
+
mpz_sub(eee, e, qq)
|
624
|
+
elif i == 1: # g == x + rr
|
625
|
+
mpz_set(aaa, a)
|
626
|
+
mpz_set(bbb, b)
|
627
|
+
mpz_sub(ccc, c, qq)
|
628
|
+
A = Integer(f[0])
|
629
|
+
mpz_set(rr, A.value)
|
630
|
+
mpz_mul(ss, rr, qq)
|
631
|
+
mpz_set(ddd,d)
|
632
|
+
mpz_sub(ddd, ddd, ss)
|
633
|
+
mpz_sub(ddd, ddd, ss)
|
634
|
+
mpz_set(eee,e)
|
635
|
+
mpz_mul(ss, ss, rr)
|
636
|
+
mpz_sub(eee, eee, ss)
|
637
|
+
mpz_divexact(ss, ss, rr)
|
638
|
+
elif i == 2: # g == x^2 + rr*x + ss
|
639
|
+
mpz_sub(aaa, a, qq)
|
640
|
+
A = Integer(f[1])
|
641
|
+
mpz_set(rr, A.value)
|
642
|
+
mpz_init(tt)
|
643
|
+
mpz_mul(tt, rr, qq)
|
644
|
+
mpz_set(bbb,b)
|
645
|
+
mpz_submul_ui(bbb, tt, 2)
|
646
|
+
mpz_set(ccc,c)
|
647
|
+
mpz_submul(ccc, tt, rr)
|
648
|
+
A = Integer(f[0])
|
649
|
+
mpz_set(ss, A.value)
|
650
|
+
mpz_mul(tt, ss, qq)
|
651
|
+
mpz_set(eee,e)
|
652
|
+
mpz_submul(eee, tt, ss)
|
653
|
+
mpz_mul_ui(tt, tt, 2)
|
654
|
+
mpz_sub(ccc, ccc, tt)
|
655
|
+
mpz_set(ddd,d)
|
656
|
+
mpz_submul(ddd, tt, rr)
|
657
|
+
mpz_clear(tt)
|
658
|
+
mpz_divexact(aaa, aaa, pp)
|
659
|
+
mpz_divexact(bbb, bbb, pp)
|
660
|
+
mpz_divexact(ccc, ccc, pp)
|
661
|
+
mpz_divexact(ddd, ddd, pp)
|
662
|
+
mpz_divexact(eee, eee, pp)
|
663
|
+
# now aaa, bbb, ccc, ddd, eee represents h(x)
|
664
|
+
|
665
|
+
result = 0
|
666
|
+
mpz_init(tt)
|
667
|
+
for i in range(j):
|
668
|
+
mpz_mul(tt, aaa, roots[i])
|
669
|
+
mpz_add(tt, tt, bbb)
|
670
|
+
mpz_mul(tt, tt, roots[i])
|
671
|
+
mpz_add(tt, tt, ccc)
|
672
|
+
mpz_mul(tt, tt, roots[i])
|
673
|
+
mpz_add(tt, tt, ddd)
|
674
|
+
mpz_mul(tt, tt, roots[i])
|
675
|
+
mpz_add(tt, tt, eee)
|
676
|
+
# tt == h(r) mod p
|
677
|
+
mpz_mod(tt, tt, pp)
|
678
|
+
if mpz_sgn(tt) == 0:
|
679
|
+
fmpz_poly_zero(f1)
|
680
|
+
fmpz_poly_zero(linear)
|
681
|
+
fmpz_poly_set_coeff_mpz(f1, 0, e)
|
682
|
+
fmpz_poly_set_coeff_mpz(f1, 1, d)
|
683
|
+
fmpz_poly_set_coeff_mpz(f1, 2, c)
|
684
|
+
fmpz_poly_set_coeff_mpz(f1, 3, b)
|
685
|
+
fmpz_poly_set_coeff_mpz(f1, 4, a)
|
686
|
+
fmpz_poly_set_coeff_mpz(linear, 0, roots[i])
|
687
|
+
fmpz_poly_set_coeff_mpz(linear, 1, pp)
|
688
|
+
fmpz_poly_compose(f1, f1, linear)
|
689
|
+
fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)
|
690
|
+
fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)
|
691
|
+
|
692
|
+
mpz_init(aa)
|
693
|
+
mpz_init(bb)
|
694
|
+
mpz_init(cc)
|
695
|
+
mpz_init(dd)
|
696
|
+
mpz_init(ee)
|
697
|
+
fmpz_poly_get_coeff_mpz(aa, f1, 4)
|
698
|
+
fmpz_poly_get_coeff_mpz(bb, f1, 3)
|
699
|
+
fmpz_poly_get_coeff_mpz(cc, f1, 2)
|
700
|
+
fmpz_poly_get_coeff_mpz(dd, f1, 1)
|
701
|
+
fmpz_poly_get_coeff_mpz(ee, f1, 0)
|
702
|
+
result = Zp_soluble_siksek_large_p(aa, bb, cc, dd, ee, pp, f1, linear)
|
703
|
+
mpz_clear(aa)
|
704
|
+
mpz_clear(bb)
|
705
|
+
mpz_clear(cc)
|
706
|
+
mpz_clear(dd)
|
707
|
+
mpz_clear(ee)
|
708
|
+
if result == 1:
|
709
|
+
break
|
710
|
+
mpz_clear(aaa)
|
711
|
+
mpz_clear(bbb)
|
712
|
+
mpz_clear(ccc)
|
713
|
+
mpz_clear(ddd)
|
714
|
+
mpz_clear(eee)
|
715
|
+
mpz_clear(tt)
|
716
|
+
return result
|
717
|
+
else:
|
718
|
+
# Step II in Alg. 5.3.1 of Siksek's thesis
|
719
|
+
A = Integer(0)
|
720
|
+
B = Integer(0)
|
721
|
+
C = Integer(0)
|
722
|
+
D = Integer(0)
|
723
|
+
E = Integer(0)
|
724
|
+
P = Integer(0)
|
725
|
+
mpz_set(A.value, a)
|
726
|
+
mpz_set(B.value, b)
|
727
|
+
mpz_set(C.value, c)
|
728
|
+
mpz_set(D.value, d)
|
729
|
+
mpz_set(E.value, e)
|
730
|
+
mpz_set(P.value, pp)
|
731
|
+
f = ntl.ZZ_pX([E, D, C, B, A], P)
|
732
|
+
f /= ntl.ZZ_pX([A], P) # now f is monic
|
733
|
+
f_factzn = f.factor()
|
734
|
+
|
735
|
+
has_roots = 0
|
736
|
+
has_single_roots = 0
|
737
|
+
j = 0
|
738
|
+
for factor, exponent in f_factzn:
|
739
|
+
if factor.degree() == 1:
|
740
|
+
has_roots = 1
|
741
|
+
if exponent == 1:
|
742
|
+
has_single_roots = 1
|
743
|
+
break
|
744
|
+
A = P - Integer(factor[0])
|
745
|
+
mpz_set(roots[j], A.value)
|
746
|
+
j += 1
|
747
|
+
|
748
|
+
if not has_roots:
|
749
|
+
return 0
|
750
|
+
if has_single_roots:
|
751
|
+
return 1
|
752
|
+
|
753
|
+
result = 0
|
754
|
+
if j > 0:
|
755
|
+
mpz_init(aa)
|
756
|
+
mpz_init(bb)
|
757
|
+
mpz_init(cc)
|
758
|
+
mpz_init(dd)
|
759
|
+
mpz_init(ee)
|
760
|
+
for i in range(j):
|
761
|
+
fmpz_poly_zero(f1)
|
762
|
+
fmpz_poly_zero(linear)
|
763
|
+
fmpz_poly_set_coeff_mpz(f1, 0, e)
|
764
|
+
fmpz_poly_set_coeff_mpz(f1, 1, d)
|
765
|
+
fmpz_poly_set_coeff_mpz(f1, 2, c)
|
766
|
+
fmpz_poly_set_coeff_mpz(f1, 3, b)
|
767
|
+
fmpz_poly_set_coeff_mpz(f1, 4, a)
|
768
|
+
fmpz_poly_set_coeff_mpz(linear, 0, roots[i])
|
769
|
+
fmpz_poly_set_coeff_mpz(linear, 1, pp)
|
770
|
+
fmpz_poly_compose(f1, f1, linear)
|
771
|
+
fmpz_poly_scalar_fdiv_mpz(f1, f1, pp)
|
772
|
+
fmpz_poly_get_coeff_mpz(aa, f1, 4)
|
773
|
+
fmpz_poly_get_coeff_mpz(bb, f1, 3)
|
774
|
+
fmpz_poly_get_coeff_mpz(cc, f1, 2)
|
775
|
+
fmpz_poly_get_coeff_mpz(dd, f1, 1)
|
776
|
+
fmpz_poly_get_coeff_mpz(ee, f1, 0)
|
777
|
+
result = Zp_soluble_siksek_large_p(aa, bb, cc, dd, ee, pp, f1, linear)
|
778
|
+
if result == 1:
|
779
|
+
break
|
780
|
+
if j > 0:
|
781
|
+
mpz_clear(aa)
|
782
|
+
mpz_clear(bb)
|
783
|
+
mpz_clear(cc)
|
784
|
+
mpz_clear(dd)
|
785
|
+
mpz_clear(ee)
|
786
|
+
return result
|
787
|
+
|
788
|
+
cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E,
|
789
|
+
mpz_t p, unsigned long P,
|
790
|
+
nmod_poly_factor_t f_factzn, fmpz_poly_t f1,
|
791
|
+
fmpz_poly_t linear) noexcept:
|
792
|
+
"""
|
793
|
+
Uses Samir Siksek's thesis results to determine whether the quartic is
|
794
|
+
locally soluble at p.
|
795
|
+
"""
|
796
|
+
cdef int result = 0
|
797
|
+
cdef mpz_t a, b, c, d, e
|
798
|
+
cdef nmod_poly_t f
|
799
|
+
nmod_poly_init(f, P)
|
800
|
+
|
801
|
+
mpz_init_set(a, A)
|
802
|
+
mpz_init_set(b, B)
|
803
|
+
mpz_init_set(c, C)
|
804
|
+
mpz_init_set(d, D)
|
805
|
+
mpz_init_set(e, E)
|
806
|
+
|
807
|
+
if Zp_soluble_siksek(a, b, c, d, e,
|
808
|
+
p, P, f_factzn, f, f1, linear):
|
809
|
+
result = 1
|
810
|
+
else:
|
811
|
+
mpz_set(a, A)
|
812
|
+
mpz_set(b, B)
|
813
|
+
mpz_set(c, C)
|
814
|
+
mpz_set(d, D)
|
815
|
+
mpz_set(e, E)
|
816
|
+
if Zp_soluble_siksek(e, d, c, b, a,
|
817
|
+
p, P,f_factzn, f, f1, linear):
|
818
|
+
result = 1
|
819
|
+
|
820
|
+
mpz_clear(a)
|
821
|
+
mpz_clear(b)
|
822
|
+
mpz_clear(c)
|
823
|
+
mpz_clear(d)
|
824
|
+
mpz_clear(e)
|
825
|
+
nmod_poly_clear(f)
|
826
|
+
return result
|
827
|
+
|
828
|
+
|
829
|
+
cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E,
|
830
|
+
mpz_t p, fmpz_poly_t f1, fmpz_poly_t linear) noexcept:
|
831
|
+
"""
|
832
|
+
Uses Samir Siksek's thesis results to determine whether the quartic is
|
833
|
+
locally soluble at p, when p is bigger than wordsize, and we can't use
|
834
|
+
FLINT.
|
835
|
+
"""
|
836
|
+
cdef int result = 0
|
837
|
+
cdef mpz_t a, b, c, d, e
|
838
|
+
|
839
|
+
mpz_init_set(a,A)
|
840
|
+
mpz_init_set(b,B)
|
841
|
+
mpz_init_set(c,C)
|
842
|
+
mpz_init_set(d,D)
|
843
|
+
mpz_init_set(e,E)
|
844
|
+
|
845
|
+
if Zp_soluble_siksek_large_p(a, b, c, d, e,
|
846
|
+
p, f1, linear):
|
847
|
+
result = 1
|
848
|
+
else:
|
849
|
+
mpz_set(a,A)
|
850
|
+
mpz_set(b,B)
|
851
|
+
mpz_set(c,C)
|
852
|
+
mpz_set(d,D)
|
853
|
+
mpz_set(e,E)
|
854
|
+
if Zp_soluble_siksek_large_p(e,d,c,b,a,p,f1,linear):
|
855
|
+
result = 1
|
856
|
+
|
857
|
+
mpz_clear(a)
|
858
|
+
mpz_clear(b)
|
859
|
+
mpz_clear(c)
|
860
|
+
mpz_clear(d)
|
861
|
+
mpz_clear(e)
|
862
|
+
return result
|
863
|
+
|
864
|
+
cdef bint Qp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p) noexcept:
|
865
|
+
"""
|
866
|
+
Uses the original test of Birch and Swinnerton-Dyer to test for local
|
867
|
+
solubility of the quartic at p.
|
868
|
+
"""
|
869
|
+
cdef mpz_t zero
|
870
|
+
cdef int result = 0
|
871
|
+
mpz_init_set_ui(zero, 0)
|
872
|
+
if Zp_soluble_BSD(a, b, c, d, e,
|
873
|
+
zero, p, 0):
|
874
|
+
result = 1
|
875
|
+
elif Zp_soluble_BSD(e, d, c, b, a,
|
876
|
+
zero, p, 1):
|
877
|
+
result = 1
|
878
|
+
mpz_clear(zero)
|
879
|
+
return result
|
880
|
+
|
881
|
+
cdef bint Qp_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p) noexcept:
|
882
|
+
"""
|
883
|
+
Try the BSD approach for a few residue classes and if no solution is found,
|
884
|
+
switch to Siksek to try to prove insolubility.
|
885
|
+
"""
|
886
|
+
cdef int bsd_sol, sik_sol
|
887
|
+
cdef unsigned long pp
|
888
|
+
cdef fmpz_poly_t f1, linear
|
889
|
+
cdef nmod_poly_factor_t f_factzn
|
890
|
+
bsd_sol = Qp_soluble_BSD(a, b, c, d, e, p)
|
891
|
+
if mpz_cmp_ui(p,N_RES_CLASSES_BSD)>0 and not bsd_sol:
|
892
|
+
fmpz_poly_init(f1)
|
893
|
+
fmpz_poly_init(linear)
|
894
|
+
if mpz_fits_ulong_p(p):
|
895
|
+
nmod_poly_factor_init(f_factzn)
|
896
|
+
pp = mpz_get_ui(p)
|
897
|
+
sik_sol = Qp_soluble_siksek(a, b, c, d, e,
|
898
|
+
p, pp, f_factzn, f1,linear)
|
899
|
+
nmod_poly_factor_clear(f_factzn)
|
900
|
+
else:
|
901
|
+
sik_sol = Qp_soluble_siksek_large_p(a, b, c, d, e,
|
902
|
+
p, f1, linear)
|
903
|
+
fmpz_poly_clear(f1)
|
904
|
+
fmpz_poly_clear(linear)
|
905
|
+
else:
|
906
|
+
sik_sol = bsd_sol
|
907
|
+
return sik_sol
|
908
|
+
|
909
|
+
|
910
|
+
def test_qpls(a, b, c, d, e, p):
|
911
|
+
"""
|
912
|
+
Testing function for Qp_soluble.
|
913
|
+
|
914
|
+
EXAMPLES::
|
915
|
+
|
916
|
+
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_qpls as tq
|
917
|
+
sage: tq(1,2,3,4,5,7)
|
918
|
+
1
|
919
|
+
"""
|
920
|
+
cdef Integer A, B, C, D, E, P
|
921
|
+
cdef int result
|
922
|
+
cdef mpz_t aa, bb, cc, dd, ee, pp
|
923
|
+
A = Integer(a)
|
924
|
+
B = Integer(b)
|
925
|
+
C = Integer(c)
|
926
|
+
D = Integer(d)
|
927
|
+
E = Integer(e)
|
928
|
+
P = Integer(p)
|
929
|
+
mpz_init_set(aa, A.value)
|
930
|
+
mpz_init_set(bb, B.value)
|
931
|
+
mpz_init_set(cc, C.value)
|
932
|
+
mpz_init_set(dd, D.value)
|
933
|
+
mpz_init_set(ee, E.value)
|
934
|
+
mpz_init_set(pp, P.value)
|
935
|
+
result = Qp_soluble(aa, bb, cc, dd, ee, pp)
|
936
|
+
mpz_clear(aa)
|
937
|
+
mpz_clear(bb)
|
938
|
+
mpz_clear(cc)
|
939
|
+
mpz_clear(dd)
|
940
|
+
mpz_clear(ee)
|
941
|
+
mpz_clear(pp)
|
942
|
+
return result
|
943
|
+
|
944
|
+
|
945
|
+
cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) except -1:
|
946
|
+
"""
|
947
|
+
Return whether the quartic has local solutions at all primes `p`.
|
948
|
+
"""
|
949
|
+
cdef Integer A, B, C, D, E, Delta,p
|
950
|
+
cdef mpz_t mpz_2
|
951
|
+
A = Integer(0)
|
952
|
+
B = Integer(0)
|
953
|
+
C = Integer(0)
|
954
|
+
D = Integer(0)
|
955
|
+
E = Integer(0)
|
956
|
+
mpz_set(A.value, a)
|
957
|
+
mpz_set(B.value, b)
|
958
|
+
mpz_set(C.value, c)
|
959
|
+
mpz_set(D.value, d)
|
960
|
+
mpz_set(E.value, e)
|
961
|
+
f = (((A*x_ZZ + B)*x_ZZ + C)*x_ZZ + D)*x_ZZ + E
|
962
|
+
|
963
|
+
# RR soluble:
|
964
|
+
if mpz_sgn(a) != 1:
|
965
|
+
if not real_roots(f):
|
966
|
+
return 0
|
967
|
+
|
968
|
+
# Q2 soluble:
|
969
|
+
mpz_init_set_ui(mpz_2, 2)
|
970
|
+
if not Qp_soluble(a, b, c, d, e, mpz_2):
|
971
|
+
mpz_clear(mpz_2)
|
972
|
+
return 0
|
973
|
+
mpz_clear(mpz_2)
|
974
|
+
|
975
|
+
# Odd finite primes
|
976
|
+
Delta = f.discriminant()
|
977
|
+
if not Delta:
|
978
|
+
raise ValueError("the curve is singular, Delta is zero")
|
979
|
+
for p in prime_divisors(Delta):
|
980
|
+
if p == 2:
|
981
|
+
continue
|
982
|
+
if not Qp_soluble(a, b, c, d, e, p.value):
|
983
|
+
return 0
|
984
|
+
|
985
|
+
return 1
|
986
|
+
|
987
|
+
|
988
|
+
def test_els(a, b, c, d, e):
|
989
|
+
"""
|
990
|
+
Doctest function for cdef int everywhere_locally_soluble(mpz_t, mpz_t, mpz_t, mpz_t, mpz_t).
|
991
|
+
|
992
|
+
EXAMPLES::
|
993
|
+
|
994
|
+
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_els
|
995
|
+
sage: for _ in range(1000):
|
996
|
+
....: a,b,c,d,e = randint(1,1000), randint(1,1000), randint(1,1000), randint(1,1000), randint(1,1000)
|
997
|
+
....: if pari.Pol([a,b,c,d,e]).hyperellratpoints(1000, 1):
|
998
|
+
....: try:
|
999
|
+
....: if not test_els(a,b,c,d,e):
|
1000
|
+
....: print("This never happened", a, b, c, d, e)
|
1001
|
+
....: except ValueError:
|
1002
|
+
....: continue
|
1003
|
+
|
1004
|
+
TESTS:
|
1005
|
+
|
1006
|
+
Check that :issue:`39864` is fixed::
|
1007
|
+
|
1008
|
+
sage: test_els(194, 617, 846, 617, 194)
|
1009
|
+
Traceback (most recent call last):
|
1010
|
+
...
|
1011
|
+
ValueError: the curve is singular, Delta is zero
|
1012
|
+
"""
|
1013
|
+
cdef Integer A, B, C, D, E
|
1014
|
+
A = Integer(a)
|
1015
|
+
B = Integer(b)
|
1016
|
+
C = Integer(c)
|
1017
|
+
D = Integer(d)
|
1018
|
+
E = Integer(e)
|
1019
|
+
return everywhere_locally_soluble(A.value, B.value, C.value, D.value, E.value)
|
1020
|
+
|
1021
|
+
|
1022
|
+
cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len,
|
1023
|
+
int global_limit_small, int global_limit_large,
|
1024
|
+
int verbosity, bint selmer_only, mpz_t n1, mpz_t n2) except -1:
|
1025
|
+
"""
|
1026
|
+
Count the number of els/gls quartic 2-covers of E.
|
1027
|
+
"""
|
1028
|
+
cdef unsigned long n_primes, i
|
1029
|
+
cdef bint found_global_points, els, check_negs, verbose = (verbosity > 4)
|
1030
|
+
cdef Integer a_Int, c_Int, e_Int
|
1031
|
+
cdef mpz_t c_sq_mpz, d_prime_mpz
|
1032
|
+
cdef mpz_t n_divisors, j
|
1033
|
+
|
1034
|
+
mpz_init(c_sq_mpz)
|
1035
|
+
mpz_mul(c_sq_mpz, c_mpz, c_mpz)
|
1036
|
+
mpz_init_set(d_prime_mpz, c_sq_mpz)
|
1037
|
+
mpz_submul_ui(d_prime_mpz, d_mpz, 4)
|
1038
|
+
check_negs = 0
|
1039
|
+
if mpz_sgn(d_prime_mpz) > 0:
|
1040
|
+
if mpz_sgn(c_mpz) >= 0 or mpz_cmp(c_sq_mpz, d_prime_mpz) <= 0:
|
1041
|
+
check_negs = 1
|
1042
|
+
mpz_clear(c_sq_mpz)
|
1043
|
+
mpz_clear(d_prime_mpz)
|
1044
|
+
|
1045
|
+
# Set up coefficient array, and static variables
|
1046
|
+
cdef mpz_t *coeffs = <mpz_t *> sig_malloc(5 * sizeof(mpz_t))
|
1047
|
+
for i in range(5):
|
1048
|
+
mpz_init(coeffs[i])
|
1049
|
+
mpz_set_ui(coeffs[1], 0) #
|
1050
|
+
mpz_set(coeffs[2], c_mpz) # These never change
|
1051
|
+
mpz_set_ui(coeffs[3], 0) #
|
1052
|
+
|
1053
|
+
# Get prime divisors, and put them in an mpz_t array
|
1054
|
+
# (this block, by setting check_negs, takes care of
|
1055
|
+
# local solubility over RR)
|
1056
|
+
cdef mpz_t *p_div_d_mpz = <mpz_t *> sig_malloc((p_list_len+1) * sizeof(mpz_t))
|
1057
|
+
n_primes = 0
|
1058
|
+
for i in range(p_list_len):
|
1059
|
+
if mpz_divisible_p(d_mpz, p_list[i]):
|
1060
|
+
mpz_init(p_div_d_mpz[n_primes])
|
1061
|
+
mpz_set(p_div_d_mpz[n_primes], p_list[i])
|
1062
|
+
n_primes += 1
|
1063
|
+
if check_negs:
|
1064
|
+
mpz_init(p_div_d_mpz[n_primes])
|
1065
|
+
mpz_set_si(p_div_d_mpz[n_primes], -1)
|
1066
|
+
n_primes += 1
|
1067
|
+
mpz_init_set_ui(n_divisors, 1)
|
1068
|
+
mpz_mul_2exp(n_divisors, n_divisors, n_primes)
|
1069
|
+
|
1070
|
+
mpz_init_set_ui(j, 0)
|
1071
|
+
if not selmer_only:
|
1072
|
+
mpz_set_ui(n1, 0)
|
1073
|
+
mpz_set_ui(n2, 0)
|
1074
|
+
while mpz_cmp(j, n_divisors) < 0:
|
1075
|
+
mpz_set_ui(coeffs[4], 1)
|
1076
|
+
for i in range(n_primes):
|
1077
|
+
if mpz_tstbit(j, i):
|
1078
|
+
mpz_mul(coeffs[4], coeffs[4], p_div_d_mpz[i])
|
1079
|
+
if verbosity > 3:
|
1080
|
+
a_Int = Integer(0)
|
1081
|
+
mpz_set(a_Int.value, coeffs[4])
|
1082
|
+
print('\nSquarefree divisor:', a_Int)
|
1083
|
+
mpz_divexact(coeffs[0], d_mpz, coeffs[4])
|
1084
|
+
found_global_points = 0
|
1085
|
+
if not selmer_only:
|
1086
|
+
if verbose:
|
1087
|
+
print("\nCalling ratpoints for small point search")
|
1088
|
+
found_global_points = ratpoints_mpz_exists_only(coeffs, 4, global_limit_small)
|
1089
|
+
if found_global_points:
|
1090
|
+
if verbosity > 2:
|
1091
|
+
a_Int = Integer(0)
|
1092
|
+
mpz_set(a_Int.value, coeffs[4])
|
1093
|
+
c_Int = Integer(0)
|
1094
|
+
mpz_set(c_Int.value, coeffs[2])
|
1095
|
+
e_Int = Integer(0)
|
1096
|
+
mpz_set(e_Int.value, coeffs[0])
|
1097
|
+
print('Found small global point, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int))
|
1098
|
+
mpz_add_ui(n1, n1, 1)
|
1099
|
+
mpz_add_ui(n2, n2, 1)
|
1100
|
+
if verbose:
|
1101
|
+
print("\nDone calling ratpoints for small point search")
|
1102
|
+
if not found_global_points:
|
1103
|
+
# Test whether the quartic is everywhere locally soluble:
|
1104
|
+
els = 1
|
1105
|
+
for i in range(p_list_len):
|
1106
|
+
if not Qp_soluble(coeffs[4], coeffs[3], coeffs[2], coeffs[1], coeffs[0], p_list[i]):
|
1107
|
+
els = 0
|
1108
|
+
break
|
1109
|
+
if els:
|
1110
|
+
if verbosity > 2:
|
1111
|
+
a_Int = Integer(0)
|
1112
|
+
mpz_set(a_Int.value, coeffs[4])
|
1113
|
+
c_Int = Integer(0)
|
1114
|
+
mpz_set(c_Int.value, coeffs[2])
|
1115
|
+
e_Int = Integer(0)
|
1116
|
+
mpz_set(e_Int.value, coeffs[0])
|
1117
|
+
print('ELS without small global points, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int))
|
1118
|
+
mpz_add_ui(n2, n2, 1)
|
1119
|
+
if not selmer_only:
|
1120
|
+
if verbose:
|
1121
|
+
print("\nCalling ratpoints for large point search")
|
1122
|
+
found_global_points = ratpoints_mpz_exists_only(coeffs, 4, global_limit_large)
|
1123
|
+
if found_global_points:
|
1124
|
+
if verbosity > 2:
|
1125
|
+
print(' -- Found large global point.')
|
1126
|
+
mpz_add_ui(n1, n1, 1)
|
1127
|
+
if verbose:
|
1128
|
+
print("\nDone calling ratpoints for large point search")
|
1129
|
+
mpz_add_ui(j, j, 1)
|
1130
|
+
mpz_clear(j)
|
1131
|
+
for i in range(n_primes):
|
1132
|
+
mpz_clear(p_div_d_mpz[i])
|
1133
|
+
sig_free(p_div_d_mpz)
|
1134
|
+
mpz_clear(n_divisors)
|
1135
|
+
for i in range(5):
|
1136
|
+
mpz_clear(coeffs[i])
|
1137
|
+
sig_free(coeffs)
|
1138
|
+
return 0
|
1139
|
+
|
1140
|
+
|
1141
|
+
def two_descent_by_two_isogeny(E,
|
1142
|
+
int global_limit_small=10,
|
1143
|
+
int global_limit_large=10000,
|
1144
|
+
int verbosity=0,
|
1145
|
+
bint selmer_only=0, bint proof=1):
|
1146
|
+
"""
|
1147
|
+
Given an elliptic curve E with a two-isogeny phi : E --> E' and dual isogeny
|
1148
|
+
phi', runs a two-isogeny descent on E, returning n1, n2, n1' and n2'. Here
|
1149
|
+
n1 is the number of quartic covers found with a rational point, and n2 is
|
1150
|
+
the number which are ELS.
|
1151
|
+
|
1152
|
+
EXAMPLES::
|
1153
|
+
|
1154
|
+
sage: # needs sage.schemes
|
1155
|
+
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny
|
1156
|
+
sage: E = EllipticCurve('14a')
|
1157
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
|
1158
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1159
|
+
0
|
1160
|
+
sage: E = EllipticCurve('65a')
|
1161
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
|
1162
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1163
|
+
1
|
1164
|
+
|
1165
|
+
sage: # needs sage.schemes sage.symbolic
|
1166
|
+
sage: x,y = var('x,y')
|
1167
|
+
sage: E = EllipticCurve(y^2 == x^3 + x^2 - 25*x + 39)
|
1168
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
|
1169
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1170
|
+
2
|
1171
|
+
sage: E = EllipticCurve(y^2 + x*y + y == x^3 - 131*x + 558)
|
1172
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
|
1173
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1174
|
+
3
|
1175
|
+
|
1176
|
+
Using the verbosity option::
|
1177
|
+
|
1178
|
+
sage: # needs sage.schemes
|
1179
|
+
sage: E = EllipticCurve('14a')
|
1180
|
+
sage: two_descent_by_two_isogeny(E, verbosity=1)
|
1181
|
+
2-isogeny
|
1182
|
+
Results:
|
1183
|
+
2 <= #E(Q)/phi'(E'(Q)) <= 2
|
1184
|
+
2 <= #E'(Q)/phi(E(Q)) <= 2
|
1185
|
+
#Sel^(phi')(E'/Q) = 2
|
1186
|
+
#Sel^(phi)(E/Q) = 2
|
1187
|
+
1 <= #Sha(E'/Q)[phi'] <= 1
|
1188
|
+
1 <= #Sha(E/Q)[phi] <= 1
|
1189
|
+
1 <= #Sha(E/Q)[2], #Sha(E'/Q)[2] <= 1
|
1190
|
+
0 <= rank of E(Q) = rank of E'(Q) <= 0
|
1191
|
+
(2, 2, 2, 2)
|
1192
|
+
|
1193
|
+
Handling curves whose discriminants involve larger than wordsize primes::
|
1194
|
+
|
1195
|
+
sage: # needs sage.schemes
|
1196
|
+
sage: E = EllipticCurve('14a')
|
1197
|
+
sage: E = E.quadratic_twist(next_prime(10^20))
|
1198
|
+
sage: E
|
1199
|
+
Elliptic Curve defined by y^2 = x^3 + x^2 + 716666666666666667225666666666666666775672*x - 391925925925925926384240370370370370549019837037037037060249356 over Rational Field
|
1200
|
+
sage: E.discriminant().factor()
|
1201
|
+
-1 * 2^18 * 7^3 * 100000000000000000039^6
|
1202
|
+
sage: log(100000000000000000039.0, 2.0)
|
1203
|
+
66.438...
|
1204
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny(E)
|
1205
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1206
|
+
0
|
1207
|
+
|
1208
|
+
TESTS:
|
1209
|
+
|
1210
|
+
Here we contrive an example to demonstrate that a keyboard interrupt
|
1211
|
+
is caught. Here we let `E` be the smallest optimal curve with two-torsion
|
1212
|
+
and nontrivial `Sha[2]`. This ensures that the two-descent will be looking
|
1213
|
+
for rational points which do not exist, and by setting global_limit_large
|
1214
|
+
to a very high bound, it will still be working when we simulate a ``CTRL-C``::
|
1215
|
+
|
1216
|
+
sage: # needs sage.schemes
|
1217
|
+
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny
|
1218
|
+
sage: E = EllipticCurve('960d'); E
|
1219
|
+
Elliptic Curve defined by y^2 = x^3 - x^2 - 900*x - 10098 over Rational Field
|
1220
|
+
sage: E.sha().an()
|
1221
|
+
4
|
1222
|
+
sage: from sage.doctest.util import ensure_interruptible_after
|
1223
|
+
sage: with ensure_interruptible_after(0.5): two_descent_by_two_isogeny(E, global_limit_large=10^8)
|
1224
|
+
"""
|
1225
|
+
cdef Integer a1, a2, a3, a4, a6, s2, s4, s6
|
1226
|
+
cdef Integer c, d, x0
|
1227
|
+
cdef list x_list
|
1228
|
+
assert E.torsion_order() % 2 == 0, 'Need rational two-torsion for isogeny descent.'
|
1229
|
+
if verbosity > 0:
|
1230
|
+
print('\n2-isogeny')
|
1231
|
+
if verbosity > 1:
|
1232
|
+
print('\nchanging coordinates')
|
1233
|
+
a1 = Integer(E.a1())
|
1234
|
+
a2 = Integer(E.a2())
|
1235
|
+
a3 = Integer(E.a3())
|
1236
|
+
a4 = Integer(E.a4())
|
1237
|
+
a6 = Integer(E.a6())
|
1238
|
+
if a1 == 0 == a3:
|
1239
|
+
s2 = a2
|
1240
|
+
s4 = a4
|
1241
|
+
s6 = a6
|
1242
|
+
else:
|
1243
|
+
s2 = a1*a1+4*a2
|
1244
|
+
s4 = 8*(a1*a3+2*a4)
|
1245
|
+
s6 = 16*(a3*a3+4*a6)
|
1246
|
+
f = ((x_ZZ + s2)*x_ZZ + s4)*x_ZZ + s6
|
1247
|
+
x_list = f.roots() # over ZZ -- use FLINT directly?
|
1248
|
+
x0 = x_list[0][0]
|
1249
|
+
c = 3*x0+s2
|
1250
|
+
d = (c+s2)*x0+s4
|
1251
|
+
return two_descent_by_two_isogeny_work(c, d,
|
1252
|
+
global_limit_small,
|
1253
|
+
global_limit_large, verbosity,
|
1254
|
+
selmer_only, proof)
|
1255
|
+
|
1256
|
+
|
1257
|
+
def two_descent_by_two_isogeny_work(Integer c, Integer d,
|
1258
|
+
int global_limit_small=10,
|
1259
|
+
int global_limit_large=10000,
|
1260
|
+
int verbosity=0, bint selmer_only=0,
|
1261
|
+
bint proof=1):
|
1262
|
+
"""
|
1263
|
+
Do all the work in doing a two-isogeny descent.
|
1264
|
+
|
1265
|
+
EXAMPLES::
|
1266
|
+
|
1267
|
+
sage: from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny_work
|
1268
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(13,128)
|
1269
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1270
|
+
0
|
1271
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(1,-16)
|
1272
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1273
|
+
1
|
1274
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(10,8)
|
1275
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1276
|
+
2
|
1277
|
+
sage: n1, n2, n1_prime, n2_prime = two_descent_by_two_isogeny_work(85,320)
|
1278
|
+
sage: log(n1,2) + log(n1_prime,2) - 2 # the rank
|
1279
|
+
3
|
1280
|
+
"""
|
1281
|
+
cdef mpz_t c_mpz, d_mpz, c_prime_mpz, d_prime_mpz
|
1282
|
+
cdef mpz_t *p_list_mpz
|
1283
|
+
cdef unsigned long i, j, p, p_list_len
|
1284
|
+
cdef Integer P, n1, n2, n1_prime, n2_prime, c_prime, d_prime
|
1285
|
+
cdef object PO
|
1286
|
+
cdef bint found, d_neg, d_prime_neg
|
1287
|
+
cdef n_factor_t fact
|
1288
|
+
cdef list primes
|
1289
|
+
mpz_init_set(c_mpz, c.value)
|
1290
|
+
mpz_init_set(d_mpz, d.value)
|
1291
|
+
mpz_init(c_prime_mpz)
|
1292
|
+
mpz_init(d_prime_mpz)
|
1293
|
+
mpz_mul_si(c_prime_mpz, c_mpz, -2)
|
1294
|
+
mpz_mul(d_prime_mpz, c_mpz, c_mpz)
|
1295
|
+
mpz_submul_ui(d_prime_mpz, d_mpz, 4)
|
1296
|
+
|
1297
|
+
d_neg = 0
|
1298
|
+
d_prime_neg = 0
|
1299
|
+
if mpz_sgn(d_mpz) < 0:
|
1300
|
+
d_neg = 1
|
1301
|
+
mpz_neg(d_mpz, d_mpz)
|
1302
|
+
if mpz_sgn(d_prime_mpz) < 0:
|
1303
|
+
d_prime_neg = 1
|
1304
|
+
mpz_neg(d_prime_mpz, d_prime_mpz)
|
1305
|
+
if mpz_fits_ulong_p(d_mpz) and mpz_fits_ulong_p(d_prime_mpz):
|
1306
|
+
# Factor very quickly using FLINT.
|
1307
|
+
p_list_mpz = <mpz_t *> sig_malloc(20 * sizeof(mpz_t))
|
1308
|
+
mpz_init_set_ui(p_list_mpz[0], 2)
|
1309
|
+
p_list_len = 1
|
1310
|
+
n_factor_init(&fact)
|
1311
|
+
n_factor(&fact, mpz_get_ui(d_mpz), proof)
|
1312
|
+
for i in range(fact.num):
|
1313
|
+
p = fact.p[i]
|
1314
|
+
if p != 2:
|
1315
|
+
mpz_init_set_ui(p_list_mpz[p_list_len], p)
|
1316
|
+
p_list_len += 1
|
1317
|
+
n_factor(&fact, mpz_get_ui(d_prime_mpz), proof)
|
1318
|
+
for i in range(fact.num):
|
1319
|
+
p = fact.p[i]
|
1320
|
+
found = 0
|
1321
|
+
for j in range(p_list_len):
|
1322
|
+
if mpz_cmp_ui(p_list_mpz[j], p) == 0:
|
1323
|
+
found = 1
|
1324
|
+
break
|
1325
|
+
if not found:
|
1326
|
+
mpz_init_set_ui(p_list_mpz[p_list_len], p)
|
1327
|
+
p_list_len += 1
|
1328
|
+
else:
|
1329
|
+
# Factor more slowly using Pari via Python.
|
1330
|
+
from sage.libs.pari import pari
|
1331
|
+
d = Integer(0)
|
1332
|
+
mpz_set(d.value, d_mpz)
|
1333
|
+
primes = list(pari(d).factor()[0])
|
1334
|
+
d_prime = Integer(0)
|
1335
|
+
mpz_set(d_prime.value, d_prime_mpz)
|
1336
|
+
for PO in pari(d_prime).factor()[0]:
|
1337
|
+
if PO not in primes:
|
1338
|
+
primes.append(PO)
|
1339
|
+
P = Integer(2)
|
1340
|
+
if P not in primes:
|
1341
|
+
primes.append(P)
|
1342
|
+
p_list_len = len(primes)
|
1343
|
+
p_list_mpz = <mpz_t *> sig_malloc(p_list_len * sizeof(mpz_t))
|
1344
|
+
for i in range(p_list_len):
|
1345
|
+
P = Integer(primes[i])
|
1346
|
+
mpz_init_set(p_list_mpz[i], P.value)
|
1347
|
+
if d_neg:
|
1348
|
+
mpz_neg(d_mpz, d_mpz)
|
1349
|
+
if d_prime_neg:
|
1350
|
+
mpz_neg(d_prime_mpz, d_prime_mpz)
|
1351
|
+
|
1352
|
+
if verbosity > 1:
|
1353
|
+
c_prime = -2*c
|
1354
|
+
d_prime = c*c-4*d
|
1355
|
+
print('\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )' % (int(c), int(d)))
|
1356
|
+
print('new isogenous curve is' +
|
1357
|
+
' y^2 == x( x^2 + (%d)x + (%d) )' % (int(c_prime), int(d_prime)))
|
1358
|
+
|
1359
|
+
n1 = Integer(0)
|
1360
|
+
n2 = Integer(0)
|
1361
|
+
n1_prime = Integer(0)
|
1362
|
+
n2_prime = Integer(0)
|
1363
|
+
count(c.value, d.value, p_list_mpz, p_list_len,
|
1364
|
+
global_limit_small, global_limit_large, verbosity, selmer_only,
|
1365
|
+
n1.value, n2.value)
|
1366
|
+
count(c_prime_mpz, d_prime_mpz, p_list_mpz, p_list_len,
|
1367
|
+
global_limit_small, global_limit_large, verbosity, selmer_only,
|
1368
|
+
n1_prime.value, n2_prime.value)
|
1369
|
+
|
1370
|
+
for i in range(p_list_len):
|
1371
|
+
mpz_clear(p_list_mpz[i])
|
1372
|
+
sig_free(p_list_mpz)
|
1373
|
+
|
1374
|
+
if verbosity > 0:
|
1375
|
+
print("\nResults:")
|
1376
|
+
print(n1, "<= #E(Q)/phi'(E'(Q)) <=", n2)
|
1377
|
+
print(n1_prime, "<= #E'(Q)/phi(E(Q)) <=", n2_prime)
|
1378
|
+
print("#Sel^(phi')(E'/Q) =", n2)
|
1379
|
+
print("#Sel^(phi)(E/Q) =", n2_prime)
|
1380
|
+
print("1 <= #Sha(E'/Q)[phi'] <=", n2/n1)
|
1381
|
+
print("1 <= #Sha(E/Q)[phi] <=", n2_prime/n1_prime)
|
1382
|
+
print("1 <= #Sha(E/Q)[2], #Sha(E'/Q)[2] <=", (n2_prime/n1_prime)*(n2/n1))
|
1383
|
+
a = Integer(n1*n1_prime).log(Integer(2))
|
1384
|
+
e = Integer(n2*n2_prime).log(Integer(2))
|
1385
|
+
print(a - 2, "<= rank of E(Q) = rank of E'(Q) <=", e - 2)
|
1386
|
+
|
1387
|
+
return n1, n2, n1_prime, n2_prime
|