passagemath-flint 10.6.1rc10__cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_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.
- passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
- passagemath_flint-10.6.1rc10.dist-info/RECORD +361 -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-aecb9cc5.so.21.0.0 +0 -0
- passagemath_flint.libs/libgf2x-a4cdec90.so.3.0.0 +0 -0
- passagemath_flint.libs/libgfortran-8f1e9814.so.5.0.0 +0 -0
- passagemath_flint.libs/libgmp-6e109695.so.10.5.0 +0 -0
- passagemath_flint.libs/libgsl-cda90e79.so.28.0.0 +0 -0
- passagemath_flint.libs/libmpfi-e3c25853.so.0.0.0 +0 -0
- passagemath_flint.libs/libmpfr-82690d50.so.6.2.1 +0 -0
- passagemath_flint.libs/libntl-74e7d9a3.so.44.0.1 +0 -0
- passagemath_flint.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
- passagemath_flint.libs/libquadmath-828275a7.so.0.0.0 +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-312-x86_64-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-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/graphs/chrompoly.pyx +555 -0
- sage/graphs/matchpoly.cpython-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/matrix/change_ring.pyx +43 -0
- sage/matrix/matrix_complex_ball_dense.cpython-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/modular/modsym/apply.pxd +6 -0
- sage/modular/modsym/apply.pyx +113 -0
- sage/modular/modsym/heilbronn.cpython-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/rings/complex_arb.pxd +29 -0
- sage/rings/complex_arb.pyx +5176 -0
- sage/rings/complex_interval.cpython-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/rings/convert/mpfi.pxd +6 -0
- sage/rings/convert/mpfi.pyx +576 -0
- sage/rings/factorint_flint.cpython-312-x86_64-linux-gnu.so +0 -0
- sage/rings/factorint_flint.pyx +99 -0
- sage/rings/fraction_field_FpT.cpython-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/rings/polynomial/hilbert.pyx +602 -0
- sage/rings/polynomial/polynomial_complex_arb.cpython-312-x86_64-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-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_number_field.pyx +345 -0
- sage/rings/polynomial/polynomial_rational_flint.cpython-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-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-312-x86_64-linux-gnu.so +0 -0
- sage/rings/real_interval_absolute.pyx +1073 -0
- sage/rings/real_mpfi.cpython-312-x86_64-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-312-x86_64-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,2598 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-flint
|
2
|
+
# distutils: libraries = NTL_LIBRARIES gmp
|
3
|
+
# distutils: extra_compile_args = NTL_CFLAGS
|
4
|
+
# distutils: include_dirs = NTL_INCDIR
|
5
|
+
# distutils: library_dirs = NTL_LIBDIR
|
6
|
+
# distutils: extra_link_args = NTL_LIBEXTRA
|
7
|
+
# distutils: language = c++
|
8
|
+
r"""
|
9
|
+
Univariate polynomials over `\QQ` implemented via FLINT
|
10
|
+
|
11
|
+
AUTHOR:
|
12
|
+
|
13
|
+
- Sebastian Pancratz
|
14
|
+
"""
|
15
|
+
|
16
|
+
# ****************************************************************************
|
17
|
+
# Copyright (C) 2010 Sebastian Pancratz <sfp@pancratz.org>
|
18
|
+
#
|
19
|
+
# This program is free software: you can redistribute it and/or modify
|
20
|
+
# it under the terms of the GNU General Public License as published by
|
21
|
+
# the Free Software Foundation, either version 2 of the License, or
|
22
|
+
# (at your option) any later version.
|
23
|
+
# https://www.gnu.org/licenses/
|
24
|
+
# ****************************************************************************
|
25
|
+
|
26
|
+
from cysignals.signals cimport sig_on, sig_str, sig_off
|
27
|
+
|
28
|
+
from libc.limits cimport LONG_MIN
|
29
|
+
from cpython.long cimport PyLong_AsLong
|
30
|
+
from sage.arith.long cimport pyobject_to_long
|
31
|
+
|
32
|
+
from sage.libs.flint.acb cimport acb_div_fmpz
|
33
|
+
from sage.libs.flint.arb cimport arb_div_fmpz
|
34
|
+
from sage.libs.flint.arb_fmpz_poly cimport _arb_fmpz_poly_evaluate_arb, _arb_fmpz_poly_evaluate_acb
|
35
|
+
from sage.libs.flint.fmpz cimport *
|
36
|
+
from sage.libs.flint.fmpq cimport *
|
37
|
+
from sage.libs.flint.fmpz_poly cimport *
|
38
|
+
from sage.libs.flint.fmpq_poly cimport *
|
39
|
+
from sage.libs.flint.fmpq_poly_sage cimport *
|
40
|
+
from sage.libs.gmp.mpz cimport *
|
41
|
+
from sage.libs.gmp.mpq cimport *
|
42
|
+
|
43
|
+
from sage.rings.complex_arb cimport ComplexBall
|
44
|
+
from sage.rings.integer cimport Integer, smallInteger
|
45
|
+
from sage.rings.integer_ring import ZZ
|
46
|
+
from sage.rings.fraction_field_element import FractionFieldElement
|
47
|
+
from sage.rings.rational cimport Rational
|
48
|
+
from sage.rings.rational_field import QQ
|
49
|
+
from sage.rings.real_arb cimport RealBall
|
50
|
+
from sage.rings.polynomial.polynomial_element cimport Polynomial
|
51
|
+
from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint
|
52
|
+
|
53
|
+
from sage.structure.parent cimport Parent
|
54
|
+
from sage.structure.element cimport Element
|
55
|
+
from sage.structure.element import coerce_binop
|
56
|
+
|
57
|
+
from sage.misc.cachefunc import cached_method
|
58
|
+
|
59
|
+
try:
|
60
|
+
from cypari2.gen import Gen as pari_gen
|
61
|
+
except ImportError:
|
62
|
+
pari_gen = ()
|
63
|
+
|
64
|
+
|
65
|
+
cdef inline bint _do_sig(fmpq_poly_t op) noexcept:
|
66
|
+
"""
|
67
|
+
Return 1 when signal handling should be carried out for an operation
|
68
|
+
on this polynomial and 0 otherwise.
|
69
|
+
|
70
|
+
Strictly speaking, whether or not signal handling should be carried
|
71
|
+
ought to depend on the operation as well as the operands in question.
|
72
|
+
For simplicity we carry out signal handling for all but the simplest
|
73
|
+
of operands regardless of the operation.
|
74
|
+
|
75
|
+
TESTS::
|
76
|
+
|
77
|
+
sage: R.<t> = QQ[]
|
78
|
+
sage: f = 1 + t/2
|
79
|
+
sage: g = 2/3 + t^2
|
80
|
+
sage: _ = f * g # indirect doctest
|
81
|
+
"""
|
82
|
+
# Issue #12173: check that the degree is greater than 1000 before computing
|
83
|
+
# the max limb size
|
84
|
+
return (fmpq_poly_length(op) > 0 and
|
85
|
+
(fmpq_poly_degree(op) > 1000 or
|
86
|
+
sage_fmpq_poly_max_limbs(op) > 1))
|
87
|
+
|
88
|
+
cdef class Polynomial_rational_flint(Polynomial):
|
89
|
+
"""
|
90
|
+
Univariate polynomials over the rationals, implemented via FLINT.
|
91
|
+
|
92
|
+
Internally, we represent rational polynomial as the quotient of an integer
|
93
|
+
polynomial and a positive denominator which is coprime to the content of
|
94
|
+
the numerator.
|
95
|
+
|
96
|
+
TESTS::
|
97
|
+
|
98
|
+
sage: f = QQ['x'].random_element()
|
99
|
+
sage: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint
|
100
|
+
sage: isinstance(f, Polynomial_rational_flint)
|
101
|
+
True
|
102
|
+
|
103
|
+
.. automethod:: _add_
|
104
|
+
.. automethod:: _sub_
|
105
|
+
.. automethod:: _lmul_
|
106
|
+
.. automethod:: _rmul_
|
107
|
+
.. automethod:: _mul_
|
108
|
+
.. automethod:: _mul_trunc_
|
109
|
+
"""
|
110
|
+
|
111
|
+
###########################################################################
|
112
|
+
# Allocation & initialisation #
|
113
|
+
###########################################################################
|
114
|
+
|
115
|
+
cdef Polynomial_rational_flint _new(self):
|
116
|
+
"""
|
117
|
+
Quickly create a new polynomial object in this class.
|
118
|
+
|
119
|
+
OUTPUT: polynomial of type ``Polynomial_rational_flint``
|
120
|
+
|
121
|
+
TESTS::
|
122
|
+
|
123
|
+
sage: R.<t> = QQ[]
|
124
|
+
sage: f = 2/3*t^2
|
125
|
+
sage: g = -1/2*t + 2
|
126
|
+
sage: f + g # indirect doctest
|
127
|
+
2/3*t^2 - 1/2*t + 2
|
128
|
+
"""
|
129
|
+
cdef Polynomial_rational_flint res = Polynomial_rational_flint.__new__(Polynomial_rational_flint)
|
130
|
+
res._parent = self._parent
|
131
|
+
res._is_gen = 0
|
132
|
+
return res
|
133
|
+
|
134
|
+
cpdef Polynomial _new_constant_poly(self, x, Parent P):
|
135
|
+
r"""
|
136
|
+
Quickly create a new constant polynomial with value x in parent P.
|
137
|
+
|
138
|
+
ASSUMPTION:
|
139
|
+
|
140
|
+
x must be a rational or convertible to an int.
|
141
|
+
|
142
|
+
EXAMPLES::
|
143
|
+
|
144
|
+
sage: R.<x> = QQ[]
|
145
|
+
sage: x._new_constant_poly(2/1,R)
|
146
|
+
2
|
147
|
+
sage: x._new_constant_poly(2,R)
|
148
|
+
2
|
149
|
+
sage: x._new_constant_poly("2",R)
|
150
|
+
2
|
151
|
+
sage: x._new_constant_poly("2.1",R)
|
152
|
+
Traceback (most recent call last):
|
153
|
+
...
|
154
|
+
ValueError: invalid literal for int() with base 10: '2.1'
|
155
|
+
"""
|
156
|
+
cdef Polynomial_rational_flint res = Polynomial_rational_flint.__new__(Polynomial_rational_flint)
|
157
|
+
res._parent = P
|
158
|
+
res._is_gen = <char>0
|
159
|
+
if isinstance(x, int):
|
160
|
+
fmpq_poly_set_si(res._poly, <int> x)
|
161
|
+
|
162
|
+
elif isinstance(x, Integer):
|
163
|
+
fmpq_poly_set_mpz(res._poly, (<Integer> x).value)
|
164
|
+
|
165
|
+
elif isinstance(x, Rational):
|
166
|
+
fmpq_poly_set_mpq(res._poly, (<Rational> x).value)
|
167
|
+
|
168
|
+
else:
|
169
|
+
fmpq_poly_set_si(res._poly, int(x))
|
170
|
+
return res
|
171
|
+
|
172
|
+
def __cinit__(self):
|
173
|
+
"""
|
174
|
+
Initialises the underlying data structure.
|
175
|
+
|
176
|
+
TESTS::
|
177
|
+
|
178
|
+
sage: R.<t> = QQ[]
|
179
|
+
sage: f = 2/3 * t - 7 #indirect doctest
|
180
|
+
"""
|
181
|
+
fmpq_poly_init(self._poly)
|
182
|
+
|
183
|
+
def __dealloc__(self):
|
184
|
+
"""
|
185
|
+
Deallocate the underlying data structure.
|
186
|
+
|
187
|
+
TESTS::
|
188
|
+
|
189
|
+
sage: R.<t> = QQ[]
|
190
|
+
sage: f = 1/3 * t
|
191
|
+
sage: del f
|
192
|
+
"""
|
193
|
+
fmpq_poly_clear(self._poly)
|
194
|
+
|
195
|
+
def __init__(self, parent, x=None, check=True, is_gen=False, construct=False):
|
196
|
+
"""
|
197
|
+
Initialises the associated data for the polynomial ``self``.
|
198
|
+
|
199
|
+
INPUT:
|
200
|
+
|
201
|
+
- ``parent`` -- polynomial ring, the parent of ``self``
|
202
|
+
- ``x`` -- data for the new polynomial ``self``, e.g. a polynomial, an
|
203
|
+
integer, a rational, a list of rationals, a dictionary with keys
|
204
|
+
the degrees and the rational coefficients, etc (default: ``None``)
|
205
|
+
- ``check`` -- whether the integrity of the data needs to be verified,
|
206
|
+
largely ignored by this method (default: ``True``)
|
207
|
+
- ``is_gen`` -- whether ``self`` shall be initialised as the generator of
|
208
|
+
the parent polynomial ring
|
209
|
+
- ``construct`` -- whether the element shall always be constructed
|
210
|
+
as an independent copy of any input data (default: ``False``)
|
211
|
+
|
212
|
+
TESTS::
|
213
|
+
|
214
|
+
sage: R.<t> = QQ[]
|
215
|
+
sage: f = -4 * t^2 + 1/3 * t - 1/7 # indirect doctest
|
216
|
+
|
217
|
+
sage: f = ZZ['x']([1..10^6])
|
218
|
+
sage: g = f.change_ring(QQ)
|
219
|
+
sage: g[:10]
|
220
|
+
10*x^9 + 9*x^8 + 8*x^7 + 7*x^6 + 6*x^5 + 5*x^4 + 4*x^3 + 3*x^2 + 2*x + 1
|
221
|
+
"""
|
222
|
+
cdef long deg
|
223
|
+
cdef unsigned long n
|
224
|
+
cdef Rational c
|
225
|
+
cdef list L1
|
226
|
+
cdef fmpq_t q
|
227
|
+
|
228
|
+
Polynomial.__init__(self, parent, is_gen=is_gen)
|
229
|
+
|
230
|
+
if is_gen:
|
231
|
+
fmpq_poly_set_coeff_si(self._poly, 1, 1)
|
232
|
+
|
233
|
+
elif isinstance(x, Polynomial_rational_flint):
|
234
|
+
fmpq_poly_set(self._poly, (<Polynomial_rational_flint> x)._poly)
|
235
|
+
|
236
|
+
elif isinstance(x, int):
|
237
|
+
fmpq_poly_set_si(self._poly, <int> x)
|
238
|
+
|
239
|
+
elif isinstance(x, Integer):
|
240
|
+
fmpq_poly_set_mpz(self._poly, (<Integer> x).value)
|
241
|
+
|
242
|
+
elif isinstance(x, Rational):
|
243
|
+
fmpq_poly_set_mpq(self._poly, (<Rational> x).value)
|
244
|
+
|
245
|
+
elif isinstance(x, (list, tuple)):
|
246
|
+
|
247
|
+
if len(x) == 0:
|
248
|
+
return
|
249
|
+
elif len(x) == 1:
|
250
|
+
Polynomial_rational_flint.__init__(self, parent, x[0],
|
251
|
+
check=check, is_gen=False, construct=construct)
|
252
|
+
return
|
253
|
+
|
254
|
+
L1 = [e if isinstance(e, Rational) else Rational(e) for e in x]
|
255
|
+
n = <unsigned long> len(x)
|
256
|
+
sig_on()
|
257
|
+
fmpq_poly_fit_length(self._poly, n)
|
258
|
+
for deg from 0 <= deg < n:
|
259
|
+
fmpq_init_set_readonly(q, (<Rational> L1[deg]).value)
|
260
|
+
fmpq_poly_set_coeff_fmpq(self._poly, deg, q)
|
261
|
+
fmpq_clear_readonly(q)
|
262
|
+
sig_off()
|
263
|
+
|
264
|
+
# deg = 0
|
265
|
+
# for e in x:
|
266
|
+
# c = Rational(e)
|
267
|
+
# fmpq_poly_set_coeff_mpq(self._poly, deg, c.value)
|
268
|
+
# deg += 1
|
269
|
+
|
270
|
+
elif isinstance(x, dict):
|
271
|
+
for deg, e in x.iteritems():
|
272
|
+
c = Rational(e)
|
273
|
+
fmpq_poly_set_coeff_mpq(self._poly, deg, c.value)
|
274
|
+
|
275
|
+
elif isinstance(x, pari_gen):
|
276
|
+
k = self._parent.base_ring()
|
277
|
+
x = [k(w) for w in x.list()]
|
278
|
+
Polynomial_rational_flint.__init__(self, parent, x, check=True,
|
279
|
+
is_gen=False, construct=construct)
|
280
|
+
|
281
|
+
elif isinstance(x, Polynomial_integer_dense_flint):
|
282
|
+
fmpq_poly_set_fmpz_poly(self._poly, (<Polynomial_integer_dense_flint>x)._poly)
|
283
|
+
|
284
|
+
elif isinstance(x, Polynomial):
|
285
|
+
k = self._parent.base_ring()
|
286
|
+
x = [k(w) for w in list(x)]
|
287
|
+
Polynomial_rational_flint.__init__(self, parent, x, check=True,
|
288
|
+
is_gen=False, construct=construct)
|
289
|
+
|
290
|
+
elif isinstance(x, FractionFieldElement) and (x.parent().base() is parent or x.parent().base() == parent) and x.denominator() == 1:
|
291
|
+
x = x.numerator()
|
292
|
+
Polynomial_rational_flint.__init__(self, parent, x, check=check,
|
293
|
+
is_gen=is_gen, construct=construct)
|
294
|
+
|
295
|
+
else:
|
296
|
+
x = parent.base_ring()(x)
|
297
|
+
Polynomial_rational_flint.__init__(self, parent, x, check=check,
|
298
|
+
is_gen=is_gen, construct=construct)
|
299
|
+
|
300
|
+
def __reduce__(self):
|
301
|
+
"""
|
302
|
+
This is used when pickling polynomials.
|
303
|
+
|
304
|
+
TESTS::
|
305
|
+
|
306
|
+
sage: R.<t> = QQ[]
|
307
|
+
sage: f = 2/3 * t^2 + 1
|
308
|
+
sage: r = f.__reduce__(); r
|
309
|
+
(<class 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>, (Univariate Polynomial Ring in t over Rational Field, [1, 0, 2/3], False, False))
|
310
|
+
sage: r[0](*r[1])
|
311
|
+
2/3*t^2 + 1
|
312
|
+
sage: loads(dumps(f)) == f
|
313
|
+
True
|
314
|
+
"""
|
315
|
+
return (Polynomial_rational_flint,
|
316
|
+
(self.parent(), self.list(), False, self.is_gen()))
|
317
|
+
|
318
|
+
def __copy__(self):
|
319
|
+
"""
|
320
|
+
Return a copy of ``self``.
|
321
|
+
|
322
|
+
TESTS::
|
323
|
+
|
324
|
+
sage: R.<t> = QQ[]
|
325
|
+
sage: f = 4/5 * t^3 - 1/17
|
326
|
+
sage: copy(f) == f
|
327
|
+
True
|
328
|
+
"""
|
329
|
+
cdef Polynomial_rational_flint res = self._new()
|
330
|
+
fmpq_poly_set(res._poly, self._poly)
|
331
|
+
return res
|
332
|
+
|
333
|
+
def _singular_(self, singular=None):
|
334
|
+
"""
|
335
|
+
Return a Singular representation of ``self``.
|
336
|
+
|
337
|
+
INPUT:
|
338
|
+
|
339
|
+
- ``singular`` -- Singular interpreter (default: default interpreter)
|
340
|
+
|
341
|
+
EXAMPLES::
|
342
|
+
|
343
|
+
sage: P.<x> = PolynomialRing(QQ)
|
344
|
+
sage: f = 3*x^2 + 2*x + 5
|
345
|
+
sage: singular(f) # needs sage.libs.singular
|
346
|
+
3*x^2+2*x+5
|
347
|
+
"""
|
348
|
+
if singular is None:
|
349
|
+
from sage.interfaces.singular import singular
|
350
|
+
self._parent._singular_(singular).set_ring() # Expensive!
|
351
|
+
return singular(self._singular_init_())
|
352
|
+
|
353
|
+
cpdef list list(self, bint copy=True):
|
354
|
+
"""
|
355
|
+
Return a list with the coefficients of ``self``.
|
356
|
+
|
357
|
+
EXAMPLES::
|
358
|
+
|
359
|
+
sage: R.<t> = QQ[]
|
360
|
+
sage: f = 1 + t + t^2/2 + t^3/3 + t^4/4
|
361
|
+
sage: f.list()
|
362
|
+
[1, 1, 1/2, 1/3, 1/4]
|
363
|
+
sage: g = R(0)
|
364
|
+
sage: g.list()
|
365
|
+
[]
|
366
|
+
"""
|
367
|
+
cdef unsigned long length = fmpq_poly_length(self._poly)
|
368
|
+
return [self.get_unsafe(n) for n in range(length)]
|
369
|
+
|
370
|
+
###########################################################################
|
371
|
+
# Basis access #
|
372
|
+
###########################################################################
|
373
|
+
|
374
|
+
def degree(self):
|
375
|
+
"""
|
376
|
+
Return the degree of ``self``.
|
377
|
+
|
378
|
+
By convention, the degree of the zero polynomial is `-1`.
|
379
|
+
|
380
|
+
EXAMPLES::
|
381
|
+
|
382
|
+
sage: R.<t> = QQ[]
|
383
|
+
sage: f = 1 + t + t^2/2 + t^3/3 + t^4/4
|
384
|
+
sage: f.degree()
|
385
|
+
4
|
386
|
+
sage: g = R(0)
|
387
|
+
sage: g.degree()
|
388
|
+
-1
|
389
|
+
|
390
|
+
TESTS::
|
391
|
+
|
392
|
+
sage: type(f.degree())
|
393
|
+
<class 'sage.rings.integer.Integer'>
|
394
|
+
"""
|
395
|
+
return smallInteger(fmpq_poly_degree(self._poly))
|
396
|
+
|
397
|
+
cdef get_unsafe(self, Py_ssize_t n):
|
398
|
+
"""
|
399
|
+
Return the `n`-th coefficient of ``self``.
|
400
|
+
|
401
|
+
INPUT:
|
402
|
+
|
403
|
+
- ``n`` -- degree of the monomial whose coefficient is to be
|
404
|
+
returned
|
405
|
+
|
406
|
+
EXAMPLES::
|
407
|
+
|
408
|
+
sage: R.<t> = QQ[]
|
409
|
+
sage: f = 1 + t + t^2/2 + t^3/3 + t^4/4
|
410
|
+
sage: f[-1], f[0], f[3], f[5] # indirect doctest
|
411
|
+
(0, 1, 1/3, 0)
|
412
|
+
sage: f[:3] # indirect doctest
|
413
|
+
1/2*t^2 + t + 1
|
414
|
+
"""
|
415
|
+
cdef Rational z = Rational.__new__(Rational)
|
416
|
+
fmpq_poly_get_coeff_mpq(z.value, self._poly, n)
|
417
|
+
return z
|
418
|
+
|
419
|
+
cpdef _unsafe_mutate(self, unsigned long n, value):
|
420
|
+
"""
|
421
|
+
Set the `n`-th coefficient of ``self`` to ``value``.
|
422
|
+
|
423
|
+
TESTS::
|
424
|
+
|
425
|
+
sage: R.<t> = QQ[]
|
426
|
+
sage: f = 1 + t + t^2/2 + t^3/3 + t^4/4
|
427
|
+
sage: f._unsafe_mutate(4, 1/5)
|
428
|
+
sage: f
|
429
|
+
1/5*t^4 + 1/3*t^3 + 1/2*t^2 + t + 1
|
430
|
+
|
431
|
+
WARNING:
|
432
|
+
|
433
|
+
Polynomials in Sage are meant to be immutable, and some methods may
|
434
|
+
rely on this convention. This method should be used only with the
|
435
|
+
utmost care.
|
436
|
+
"""
|
437
|
+
cdef bint do_sig = _do_sig(self._poly)
|
438
|
+
cdef fmpz_t tmpfz
|
439
|
+
|
440
|
+
if isinstance(value, int):
|
441
|
+
if do_sig: sig_str("FLINT exception")
|
442
|
+
fmpq_poly_set_coeff_si(self._poly, n, value)
|
443
|
+
if do_sig: sig_off()
|
444
|
+
elif isinstance(value, Integer):
|
445
|
+
if do_sig: sig_str("FLINT exception")
|
446
|
+
fmpz_init_set_readonly(tmpfz, (<Integer> value).value)
|
447
|
+
fmpq_poly_set_coeff_fmpz(self._poly, n, tmpfz)
|
448
|
+
fmpz_clear_readonly(tmpfz)
|
449
|
+
if do_sig: sig_off()
|
450
|
+
elif isinstance(value, Rational):
|
451
|
+
if do_sig: sig_str("FLINT exception")
|
452
|
+
fmpq_poly_set_coeff_mpq(self._poly, n, (<Rational> value).value)
|
453
|
+
if do_sig: sig_off()
|
454
|
+
else:
|
455
|
+
value = Rational(value)
|
456
|
+
if do_sig: sig_str("FLINT exception")
|
457
|
+
fmpq_poly_set_coeff_mpq(self._poly, n, (<Rational> value).value)
|
458
|
+
if do_sig: sig_off()
|
459
|
+
|
460
|
+
def __call__(self, *x, **kwds):
|
461
|
+
"""
|
462
|
+
Call this polynomial with the given parameters, which can be
|
463
|
+
interpreted as polynomial composition or evaluation by this
|
464
|
+
method.
|
465
|
+
|
466
|
+
If the argument is not simply an integer, a rational, or a
|
467
|
+
polynomial, the call is passed on to the generic implementation
|
468
|
+
in the Polynomial class.
|
469
|
+
|
470
|
+
EXAMPLES:
|
471
|
+
|
472
|
+
The first example illustrates polynomial composition::
|
473
|
+
|
474
|
+
sage: R.<t> = QQ[]
|
475
|
+
sage: f = t^2 - 1
|
476
|
+
sage: g = t + 1
|
477
|
+
sage: f(g) # indirect doctest
|
478
|
+
t^2 + 2*t
|
479
|
+
|
480
|
+
Now we illustrate how a polynomial can be evaluated at a rational
|
481
|
+
number::
|
482
|
+
|
483
|
+
sage: f(-2/3) # indirect doctest
|
484
|
+
-5/9
|
485
|
+
|
486
|
+
TESTS:
|
487
|
+
|
488
|
+
sage: t(-sys.maxsize-1r) == t(-sys.maxsize-1)
|
489
|
+
True
|
490
|
+
sage: (t/3)(RealBallField(100)(1))
|
491
|
+
[0.33333333333333333333333333333...]
|
492
|
+
sage: (t/3)(ComplexBallField(10)(1+i)) # needs sage.symbolic
|
493
|
+
[0.33...] + [0.33...]*I
|
494
|
+
"""
|
495
|
+
cdef Polynomial_rational_flint f
|
496
|
+
cdef Rational r
|
497
|
+
cdef fmpz_t tmpfz
|
498
|
+
cdef fmpq_t tmpfq, tmpfq1
|
499
|
+
cdef RealBall arb_a, arb_z
|
500
|
+
cdef ComplexBall acb_a, acb_z
|
501
|
+
|
502
|
+
if len(x) == 1:
|
503
|
+
a = x[0]
|
504
|
+
if isinstance(a, Polynomial_rational_flint):
|
505
|
+
f = (<Polynomial_rational_flint> a)._new()
|
506
|
+
sig_str("FLINT exception")
|
507
|
+
fmpq_poly_compose(f._poly, self._poly,
|
508
|
+
(<Polynomial_rational_flint> a)._poly)
|
509
|
+
sig_off()
|
510
|
+
return f
|
511
|
+
elif isinstance(a, Rational):
|
512
|
+
r = Rational.__new__(Rational)
|
513
|
+
sig_str("FLINT exception")
|
514
|
+
fmpq_init_set_readonly(tmpfq, (<Rational> a).value)
|
515
|
+
fmpq_init(tmpfq1)
|
516
|
+
fmpq_poly_evaluate_fmpq(tmpfq1, self._poly, tmpfq)
|
517
|
+
fmpq_get_mpq(r.value, tmpfq1)
|
518
|
+
fmpq_clear(tmpfq1)
|
519
|
+
fmpq_clear_readonly(tmpfq)
|
520
|
+
sig_off()
|
521
|
+
return r
|
522
|
+
elif isinstance(a, Integer):
|
523
|
+
r = Rational.__new__(Rational)
|
524
|
+
sig_str("FLINT exception")
|
525
|
+
fmpz_init_set_readonly(tmpfz, (<Integer> a).value)
|
526
|
+
fmpq_init(tmpfq)
|
527
|
+
fmpq_poly_evaluate_fmpz(tmpfq, self._poly, tmpfz)
|
528
|
+
fmpq_get_mpq(r.value, tmpfq)
|
529
|
+
fmpq_clear(tmpfq)
|
530
|
+
fmpz_clear_readonly(tmpfz)
|
531
|
+
sig_off()
|
532
|
+
return r
|
533
|
+
elif isinstance(a, int):
|
534
|
+
r = Rational.__new__(Rational)
|
535
|
+
sig_str("FLINT exception")
|
536
|
+
fmpz_init(tmpfz)
|
537
|
+
fmpq_init(tmpfq)
|
538
|
+
fmpz_set_si(tmpfz, PyLong_AsLong(a))
|
539
|
+
fmpq_poly_evaluate_fmpz(tmpfq, self._poly, tmpfz)
|
540
|
+
fmpq_get_mpq(r.value, tmpfq)
|
541
|
+
fmpq_clear(tmpfq)
|
542
|
+
fmpz_clear(tmpfz)
|
543
|
+
sig_off()
|
544
|
+
return r
|
545
|
+
if isinstance(a, RealBall):
|
546
|
+
arb_a = <RealBall> a
|
547
|
+
arb_z = arb_a._new()
|
548
|
+
sig_on()
|
549
|
+
_arb_fmpz_poly_evaluate_arb(arb_z.value, fmpq_poly_numref(self._poly),
|
550
|
+
fmpq_poly_length(self._poly), arb_a.value, arb_a._parent._prec)
|
551
|
+
arb_div_fmpz(arb_z.value, arb_z.value, fmpq_poly_denref(self._poly), arb_a._parent._prec)
|
552
|
+
sig_off()
|
553
|
+
return arb_z
|
554
|
+
if isinstance(a, ComplexBall):
|
555
|
+
acb_a = <ComplexBall> a
|
556
|
+
acb_z = acb_a._new()
|
557
|
+
sig_on()
|
558
|
+
_arb_fmpz_poly_evaluate_acb(acb_z.value, fmpq_poly_numref(self._poly),
|
559
|
+
fmpq_poly_length(self._poly), acb_a.value, acb_a._parent._prec)
|
560
|
+
acb_div_fmpz(acb_z.value, acb_z.value, fmpq_poly_denref(self._poly), acb_a._parent._prec)
|
561
|
+
sig_off()
|
562
|
+
return acb_z
|
563
|
+
|
564
|
+
return Polynomial.__call__(self, *x, **kwds)
|
565
|
+
|
566
|
+
cpdef Polynomial truncate(self, long n):
|
567
|
+
"""
|
568
|
+
Return ``self`` truncated modulo `t^n`.
|
569
|
+
|
570
|
+
INPUT:
|
571
|
+
|
572
|
+
- ``n`` -- the power of `t` modulo which ``self`` is truncated
|
573
|
+
|
574
|
+
EXAMPLES::
|
575
|
+
|
576
|
+
sage: R.<t> = QQ[]
|
577
|
+
sage: f = 1 - t + 1/2*t^2 - 1/3*t^3
|
578
|
+
sage: f.truncate(0)
|
579
|
+
0
|
580
|
+
sage: f.truncate(2)
|
581
|
+
-t + 1
|
582
|
+
"""
|
583
|
+
cdef Polynomial_rational_flint res
|
584
|
+
cdef bint do_sig
|
585
|
+
|
586
|
+
if (n >= fmpq_poly_length(self._poly)):
|
587
|
+
return self
|
588
|
+
else:
|
589
|
+
res = self._new()
|
590
|
+
if n > 0:
|
591
|
+
do_sig = _do_sig(self._poly)
|
592
|
+
if do_sig: sig_str("FLINT exception")
|
593
|
+
fmpq_poly_get_slice(res._poly, self._poly, 0, n)
|
594
|
+
if do_sig: sig_off()
|
595
|
+
return res
|
596
|
+
|
597
|
+
def reverse(self, degree=None):
|
598
|
+
"""
|
599
|
+
Reverse the coefficients of this polynomial (thought of as a polynomial
|
600
|
+
of degree ``degree``).
|
601
|
+
|
602
|
+
INPUT:
|
603
|
+
|
604
|
+
- ``degree`` -- ``None`` or integral value that fits in an ``unsigned
|
605
|
+
long`` (default: degree of ``self``); if specified, truncate or zero
|
606
|
+
pad the list of coefficients to this degree before reversing it
|
607
|
+
|
608
|
+
EXAMPLES:
|
609
|
+
|
610
|
+
We first consider the simplest case, where we reverse all coefficients
|
611
|
+
of a polynomial and obtain a polynomial of the same degree::
|
612
|
+
|
613
|
+
sage: R.<t> = QQ[]
|
614
|
+
sage: f = 1 + t + t^2 / 2 + t^3 / 3 + t^4 / 4
|
615
|
+
sage: f.reverse()
|
616
|
+
t^4 + t^3 + 1/2*t^2 + 1/3*t + 1/4
|
617
|
+
|
618
|
+
Next, an example where the returned polynomial has lower degree because
|
619
|
+
the original polynomial has low coefficients equal to zero::
|
620
|
+
|
621
|
+
sage: R.<t> = QQ[]
|
622
|
+
sage: f = 3/4*t^2 + 6*t^7
|
623
|
+
sage: f.reverse()
|
624
|
+
3/4*t^5 + 6
|
625
|
+
|
626
|
+
The next example illustrates the passing of a value for ``degree`` less
|
627
|
+
than the length of ``self``, notationally resulting in truncation prior to
|
628
|
+
reversing::
|
629
|
+
|
630
|
+
sage: R.<t> = QQ[]
|
631
|
+
sage: f = 1 + t + t^2 / 2 + t^3 / 3 + t^4 / 4
|
632
|
+
sage: f.reverse(2)
|
633
|
+
t^2 + t + 1/2
|
634
|
+
|
635
|
+
Now we illustrate the passing of a value for ``degree`` greater than
|
636
|
+
the length of ``self``, notationally resulting in zero padding at the top
|
637
|
+
end prior to reversing::
|
638
|
+
|
639
|
+
sage: R.<t> = QQ[]
|
640
|
+
sage: f = 1 + t + t^2 / 2 + t^3 / 3
|
641
|
+
sage: f.reverse(4)
|
642
|
+
t^4 + t^3 + 1/2*t^2 + 1/3*t
|
643
|
+
|
644
|
+
TESTS:
|
645
|
+
|
646
|
+
We illustrate two ways in which the interpretation of ``degree`` as an
|
647
|
+
unsigned long int may fail. Firstly, an integral value which is
|
648
|
+
too large, yielding an :exc:`OverflowError`::
|
649
|
+
|
650
|
+
sage: R.<t> = QQ[]
|
651
|
+
sage: f = 1 + t/2
|
652
|
+
sage: f.reverse(2**64 - 1)
|
653
|
+
Traceback (most recent call last):
|
654
|
+
...
|
655
|
+
OverflowError:... int too large to convert...
|
656
|
+
|
657
|
+
Secondly, a value which cannot be converted to an integral value,
|
658
|
+
resulting in a ValueError::
|
659
|
+
|
660
|
+
sage: R.<t> = QQ[]
|
661
|
+
sage: f = 1 + t/2
|
662
|
+
sage: f.reverse(I)
|
663
|
+
Traceback (most recent call last):
|
664
|
+
...
|
665
|
+
ValueError: degree must be convertible to long
|
666
|
+
|
667
|
+
We check that this specialized implementation is compatible with the
|
668
|
+
generic one::
|
669
|
+
|
670
|
+
sage: all((t + 2*t^2).reverse(degree=d)
|
671
|
+
....: == Polynomial.reverse(t + 2*t^2, degree=d)
|
672
|
+
....: for d in [None, 0, 1, 2, 3, 4, 5])
|
673
|
+
True
|
674
|
+
"""
|
675
|
+
cdef unsigned long len
|
676
|
+
cdef Polynomial_rational_flint res
|
677
|
+
cdef bint do_sig
|
678
|
+
|
679
|
+
if degree is None:
|
680
|
+
len = fmpq_poly_length(self._poly)
|
681
|
+
else:
|
682
|
+
try:
|
683
|
+
len = <unsigned long> (degree + 1)
|
684
|
+
except (TypeError, ValueError):
|
685
|
+
raise ValueError('degree must be convertible to long')
|
686
|
+
|
687
|
+
res = self._new()
|
688
|
+
do_sig = _do_sig(self._poly)
|
689
|
+
if do_sig: sig_str("FLINT exception")
|
690
|
+
fmpq_poly_reverse(res._poly, self._poly, len)
|
691
|
+
if do_sig: sig_off()
|
692
|
+
return res
|
693
|
+
|
694
|
+
def revert_series(self, n):
|
695
|
+
r"""
|
696
|
+
Return a polynomial `f` such that ``f(self(x)) = self(f(x)) = x mod x^n``.
|
697
|
+
|
698
|
+
EXAMPLES::
|
699
|
+
|
700
|
+
sage: R.<t> = QQ[]
|
701
|
+
sage: f = t - t^3/6 + t^5/120
|
702
|
+
sage: f.revert_series(6)
|
703
|
+
3/40*t^5 + 1/6*t^3 + t
|
704
|
+
|
705
|
+
sage: f.revert_series(-1)
|
706
|
+
Traceback (most recent call last):
|
707
|
+
ValueError: argument n must be a nonnegative integer, got -1
|
708
|
+
|
709
|
+
sage: g = - t^3/3 + t^5/5
|
710
|
+
sage: g.revert_series(6)
|
711
|
+
Traceback (most recent call last):
|
712
|
+
...
|
713
|
+
ValueError: self must have constant coefficient 0 and a unit for coefficient t^1
|
714
|
+
"""
|
715
|
+
|
716
|
+
cdef Polynomial_rational_flint res = self._new()
|
717
|
+
cdef unsigned long m
|
718
|
+
if n < 0:
|
719
|
+
raise ValueError("argument n must be a nonnegative integer, got {}".format(n))
|
720
|
+
m = n
|
721
|
+
if not self[0].is_zero() or not self[1].is_unit():
|
722
|
+
raise ValueError("self must have constant coefficient 0 and a unit for coefficient {}^1".format(self.parent().gen()))
|
723
|
+
|
724
|
+
sig_str("FLINT exception")
|
725
|
+
fmpq_poly_revert_series(res._poly, self._poly, m)
|
726
|
+
sig_off()
|
727
|
+
|
728
|
+
return res
|
729
|
+
|
730
|
+
###########################################################################
|
731
|
+
# Comparisons #
|
732
|
+
###########################################################################
|
733
|
+
|
734
|
+
cpdef bint is_zero(self) except -1:
|
735
|
+
"""
|
736
|
+
Return whether or not ``self`` is the zero polynomial.
|
737
|
+
|
738
|
+
EXAMPLES::
|
739
|
+
|
740
|
+
sage: R.<t> = QQ[]
|
741
|
+
sage: f = 1 - t + 1/2*t^2 - 1/3*t^3
|
742
|
+
sage: f.is_zero()
|
743
|
+
False
|
744
|
+
sage: R(0).is_zero()
|
745
|
+
True
|
746
|
+
"""
|
747
|
+
return fmpq_poly_is_zero(self._poly)
|
748
|
+
|
749
|
+
cpdef bint is_one(self) except -1:
|
750
|
+
r"""
|
751
|
+
Return whether or not this polynomial is one.
|
752
|
+
|
753
|
+
EXAMPLES::
|
754
|
+
|
755
|
+
sage: R.<x> = QQ[]
|
756
|
+
sage: R([0,1]).is_one()
|
757
|
+
False
|
758
|
+
sage: R([1]).is_one()
|
759
|
+
True
|
760
|
+
sage: R([0]).is_one()
|
761
|
+
False
|
762
|
+
sage: R([-1]).is_one()
|
763
|
+
False
|
764
|
+
sage: R([1,1]).is_one()
|
765
|
+
False
|
766
|
+
"""
|
767
|
+
return fmpq_poly_is_one(self._poly)
|
768
|
+
|
769
|
+
def __bool__(self):
|
770
|
+
"""
|
771
|
+
Return whether or not ``self`` is nonzero.
|
772
|
+
|
773
|
+
EXAMPLES::
|
774
|
+
|
775
|
+
sage: R.<t> = QQ[]
|
776
|
+
sage: f = 1 - t + 1/2*t^2 - 1/3*t^3
|
777
|
+
sage: bool(f)
|
778
|
+
True
|
779
|
+
sage: bool(R(0))
|
780
|
+
False
|
781
|
+
"""
|
782
|
+
return not fmpq_poly_is_zero(self._poly)
|
783
|
+
|
784
|
+
###########################################################################
|
785
|
+
# Shifting #
|
786
|
+
###########################################################################
|
787
|
+
|
788
|
+
def __lshift__(self, long n):
|
789
|
+
"""
|
790
|
+
Notationally multiply ``self`` by `t^n`.
|
791
|
+
|
792
|
+
EXAMPLES::
|
793
|
+
|
794
|
+
sage: R.<t> = QQ[]
|
795
|
+
sage: t << 10 # indirect doctest
|
796
|
+
t^11
|
797
|
+
|
798
|
+
TESTS::
|
799
|
+
|
800
|
+
sage: R.<t> = QQ[]
|
801
|
+
sage: t << (-1)
|
802
|
+
1
|
803
|
+
sage: t << (-10)
|
804
|
+
0
|
805
|
+
sage: f = R.random_element(1000)
|
806
|
+
sage: (f << 23) >> 23 == f # indirect doctest
|
807
|
+
True
|
808
|
+
"""
|
809
|
+
if n < 0:
|
810
|
+
assert n != LONG_MIN
|
811
|
+
return self >> (-n)
|
812
|
+
|
813
|
+
cdef Polynomial_rational_flint f = <Polynomial_rational_flint> self
|
814
|
+
cdef Polynomial_rational_flint res
|
815
|
+
cdef bint do_sig
|
816
|
+
|
817
|
+
if n == 0 or fmpq_poly_is_zero(f._poly):
|
818
|
+
return self
|
819
|
+
else:
|
820
|
+
res = f._new()
|
821
|
+
do_sig = fmpq_poly_length(f._poly) > 5000 or n > 5000
|
822
|
+
|
823
|
+
if do_sig: sig_str("FLINT exception")
|
824
|
+
fmpq_poly_shift_left(res._poly, f._poly, n)
|
825
|
+
if do_sig: sig_off()
|
826
|
+
return res
|
827
|
+
|
828
|
+
def __rshift__(self, long n):
|
829
|
+
"""
|
830
|
+
Notationally return the quotient of Euclidean division of ``self``
|
831
|
+
by `t^n`.
|
832
|
+
|
833
|
+
EXAMPLES::
|
834
|
+
|
835
|
+
sage: R.<t> = QQ[]
|
836
|
+
sage: f = 1 + t + t^2/2 + t^3/3 + t^4/4
|
837
|
+
sage: f >> 2
|
838
|
+
1/4*t^2 + 1/3*t + 1/2
|
839
|
+
sage: f >> (-2)
|
840
|
+
1/4*t^6 + 1/3*t^5 + 1/2*t^4 + t^3 + t^2
|
841
|
+
"""
|
842
|
+
if n < 0:
|
843
|
+
assert n != LONG_MIN
|
844
|
+
return self << (-n)
|
845
|
+
|
846
|
+
cdef Polynomial_rational_flint f = <Polynomial_rational_flint> self
|
847
|
+
cdef Polynomial_rational_flint res
|
848
|
+
cdef bint do_sig
|
849
|
+
|
850
|
+
if n == 0 or fmpq_poly_is_zero(f._poly):
|
851
|
+
return self
|
852
|
+
else:
|
853
|
+
res = f._new()
|
854
|
+
do_sig = _do_sig(f._poly)
|
855
|
+
|
856
|
+
if do_sig: sig_str("FLINT exception")
|
857
|
+
fmpq_poly_shift_right(res._poly, f._poly, n)
|
858
|
+
if do_sig: sig_off()
|
859
|
+
return res
|
860
|
+
|
861
|
+
###########################################################################
|
862
|
+
# Arithmetic #
|
863
|
+
###########################################################################
|
864
|
+
|
865
|
+
cpdef _add_(self, right):
|
866
|
+
"""
|
867
|
+
Return the sum of two rational polynomials.
|
868
|
+
|
869
|
+
EXAMPLES::
|
870
|
+
|
871
|
+
sage: R.<t> = QQ[]
|
872
|
+
sage: f = 2/3 + t + 2*t^3
|
873
|
+
sage: g = -1 + t/3 - 10/11*t^4
|
874
|
+
sage: f + g
|
875
|
+
-10/11*t^4 + 2*t^3 + 4/3*t - 1/3
|
876
|
+
|
877
|
+
TESTS::
|
878
|
+
|
879
|
+
sage: R.<t> = QQ[]
|
880
|
+
sage: f = R.random_element(2000)
|
881
|
+
sage: f + f == 2 * f # indirect doctest
|
882
|
+
True
|
883
|
+
"""
|
884
|
+
cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right
|
885
|
+
cdef Polynomial_rational_flint res = self._new()
|
886
|
+
cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly)
|
887
|
+
|
888
|
+
if do_sig: sig_str("FLINT exception")
|
889
|
+
fmpq_poly_add(res._poly, self._poly, op2._poly)
|
890
|
+
if do_sig: sig_off()
|
891
|
+
return res
|
892
|
+
|
893
|
+
cpdef _sub_(self, right):
|
894
|
+
"""
|
895
|
+
Return the difference of two rational polynomials.
|
896
|
+
|
897
|
+
EXAMPLES::
|
898
|
+
|
899
|
+
sage: R.<t> = QQ[]
|
900
|
+
sage: f = -10/11*t^4 + 2*t^3 + 4/3*t - 1/3
|
901
|
+
sage: g = 2*t^3
|
902
|
+
sage: f - g # indirect doctest
|
903
|
+
-10/11*t^4 + 4/3*t - 1/3
|
904
|
+
|
905
|
+
TESTS::
|
906
|
+
|
907
|
+
sage: R.<t> = QQ[]
|
908
|
+
sage: f = R.random_element(2000)
|
909
|
+
sage: f - f/2 == 1/2 * f # indirect doctest
|
910
|
+
True
|
911
|
+
"""
|
912
|
+
cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right
|
913
|
+
cdef Polynomial_rational_flint res = self._new()
|
914
|
+
cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly)
|
915
|
+
|
916
|
+
if do_sig: sig_str("FLINT exception")
|
917
|
+
fmpq_poly_sub(res._poly, self._poly, op2._poly)
|
918
|
+
if do_sig: sig_off()
|
919
|
+
return res
|
920
|
+
|
921
|
+
cpdef _neg_(self):
|
922
|
+
"""
|
923
|
+
Return the difference of two rational polynomials.
|
924
|
+
|
925
|
+
EXAMPLES::
|
926
|
+
|
927
|
+
sage: R.<t> = QQ[]
|
928
|
+
sage: f = 3*t/2
|
929
|
+
sage: -f # indirect doctest
|
930
|
+
-3/2*t
|
931
|
+
|
932
|
+
TESTS::
|
933
|
+
|
934
|
+
sage: R.<t> = QQ[]
|
935
|
+
sage: f = R.random_element(2000)
|
936
|
+
sage: f + (-f) == 0 # indirect doctest
|
937
|
+
True
|
938
|
+
"""
|
939
|
+
cdef Polynomial_rational_flint res = self._new()
|
940
|
+
cdef bint do_sig = _do_sig(self._poly)
|
941
|
+
|
942
|
+
if do_sig: sig_str("FLINT exception")
|
943
|
+
fmpq_poly_neg(res._poly, self._poly)
|
944
|
+
if do_sig: sig_off()
|
945
|
+
return res
|
946
|
+
|
947
|
+
@coerce_binop
|
948
|
+
def quo_rem(self, right):
|
949
|
+
r"""
|
950
|
+
Return the quotient and remainder of the Euclidean division of
|
951
|
+
``self`` and ``right``.
|
952
|
+
|
953
|
+
Raises a :exc:`ZeroDivisionError` if ``right`` is zero.
|
954
|
+
|
955
|
+
EXAMPLES::
|
956
|
+
|
957
|
+
sage: R.<t> = QQ[]
|
958
|
+
sage: f = R.random_element(2000)
|
959
|
+
sage: g = R.random_element(1000)
|
960
|
+
sage: q, r = f.quo_rem(g)
|
961
|
+
sage: f == q*g + r
|
962
|
+
True
|
963
|
+
"""
|
964
|
+
if right.is_zero():
|
965
|
+
raise ZeroDivisionError("division by zero polynomial")
|
966
|
+
if self.is_zero():
|
967
|
+
return self, self
|
968
|
+
|
969
|
+
cdef Polynomial_rational_flint qq = self._new()
|
970
|
+
cdef Polynomial_rational_flint rr = self._new()
|
971
|
+
|
972
|
+
sig_str("FLINT exception")
|
973
|
+
fmpq_poly_divrem(qq._poly, rr._poly, self._poly,
|
974
|
+
(<Polynomial_rational_flint> right)._poly)
|
975
|
+
sig_off()
|
976
|
+
return qq, rr
|
977
|
+
|
978
|
+
@coerce_binop
|
979
|
+
def gcd(self, right):
|
980
|
+
r"""
|
981
|
+
Return the (monic) greatest common divisor of ``self`` and ``right``.
|
982
|
+
|
983
|
+
Corner cases: if ``self`` and ``right`` are both zero, returns zero. If
|
984
|
+
only one of them is zero, returns the other polynomial, up to
|
985
|
+
normalisation.
|
986
|
+
|
987
|
+
EXAMPLES::
|
988
|
+
|
989
|
+
sage: R.<t> = QQ[]
|
990
|
+
sage: f = -2 + 3*t/2 + 4*t^2/7 - t^3
|
991
|
+
sage: g = 1/2 + 4*t + 2*t^4/3
|
992
|
+
sage: f.gcd(g)
|
993
|
+
1
|
994
|
+
sage: f = (-3*t + 1/2) * f
|
995
|
+
sage: g = (-3*t + 1/2) * (4*t^2/3 - 1) * g
|
996
|
+
sage: f.gcd(g)
|
997
|
+
t - 1/6
|
998
|
+
"""
|
999
|
+
cdef Polynomial_rational_flint res = self._new()
|
1000
|
+
|
1001
|
+
sig_str("FLINT exception")
|
1002
|
+
fmpq_poly_gcd(res._poly, self._poly,
|
1003
|
+
(<Polynomial_rational_flint> right)._poly)
|
1004
|
+
sig_off()
|
1005
|
+
return res
|
1006
|
+
|
1007
|
+
@coerce_binop
|
1008
|
+
def lcm(self, right):
|
1009
|
+
r"""
|
1010
|
+
Return the monic (or zero) least common multiple of ``self`` and ``right``.
|
1011
|
+
|
1012
|
+
Corner cases: if either of ``self`` and ``right`` are zero, returns zero.
|
1013
|
+
This behaviour is ensures that the relation `\lcm(a,b)\cdot \gcd(a,b) = a\cdot b`
|
1014
|
+
holds up to multiplication by rationals.
|
1015
|
+
|
1016
|
+
EXAMPLES::
|
1017
|
+
|
1018
|
+
sage: R.<t> = QQ[]
|
1019
|
+
sage: f = -2 + 3*t/2 + 4*t^2/7 - t^3
|
1020
|
+
sage: g = 1/2 + 4*t + 2*t^4/3
|
1021
|
+
sage: f.lcm(g)
|
1022
|
+
t^7 - 4/7*t^6 - 3/2*t^5 + 8*t^4 - 75/28*t^3 - 66/7*t^2 + 87/8*t + 3/2
|
1023
|
+
sage: f.lcm(g) * f.gcd(g) // (f * g)
|
1024
|
+
-3/2
|
1025
|
+
"""
|
1026
|
+
cdef Polynomial_rational_flint res = self._new()
|
1027
|
+
|
1028
|
+
sig_str("FLINT exception")
|
1029
|
+
fmpq_poly_lcm(res._poly, self._poly,
|
1030
|
+
(<Polynomial_rational_flint> right)._poly)
|
1031
|
+
sig_off()
|
1032
|
+
return res
|
1033
|
+
|
1034
|
+
@coerce_binop
|
1035
|
+
def xgcd(self, right):
|
1036
|
+
r"""
|
1037
|
+
Return polynomials `d`, `s`, and `t` such that ``d == s * self + t * right``,
|
1038
|
+
where `d` is the (monic) greatest common divisor of ``self`` and ``right``.
|
1039
|
+
The choice of `s` and `t` is not specified any further.
|
1040
|
+
|
1041
|
+
Corner cases: if ``self`` and ``right`` are zero, returns zero polynomials.
|
1042
|
+
Otherwise, if only ``self`` is zero, returns ``(d, s, t) = (right, 0, 1)`` up
|
1043
|
+
to normalisation, and similarly if only ``right`` is zero.
|
1044
|
+
|
1045
|
+
EXAMPLES::
|
1046
|
+
|
1047
|
+
sage: R.<t> = QQ[]
|
1048
|
+
sage: f = 2/3 + 3/4 * t - t^2
|
1049
|
+
sage: g = -3 + 1/7 * t
|
1050
|
+
sage: f.xgcd(g)
|
1051
|
+
(1, -12/5095, -84/5095*t - 1701/5095)
|
1052
|
+
|
1053
|
+
TESTS:
|
1054
|
+
|
1055
|
+
The following example used to crash (cf. :issue:`11771`)::
|
1056
|
+
|
1057
|
+
sage: R.<t> = QQ[]
|
1058
|
+
sage: f = 10**383 * (t+1)
|
1059
|
+
sage: g = 10**445 * t^2 + 1
|
1060
|
+
sage: r = f.xgcd(g)
|
1061
|
+
sage: r[0] == f.gcd(g)
|
1062
|
+
True
|
1063
|
+
sage: r[1]*f + r[2]*g == r[0]
|
1064
|
+
True
|
1065
|
+
"""
|
1066
|
+
cdef Polynomial_rational_flint d = self._new()
|
1067
|
+
cdef Polynomial_rational_flint s = self._new()
|
1068
|
+
cdef Polynomial_rational_flint t = self._new()
|
1069
|
+
|
1070
|
+
sig_str("FLINT exception")
|
1071
|
+
fmpq_poly_xgcd(d._poly, s._poly, t._poly, self._poly, (<Polynomial_rational_flint>right)._poly)
|
1072
|
+
sig_off()
|
1073
|
+
return d, s, t
|
1074
|
+
|
1075
|
+
cpdef _mul_(self, right):
|
1076
|
+
"""
|
1077
|
+
Return the product of ``self`` and ``right``.
|
1078
|
+
|
1079
|
+
EXAMPLES::
|
1080
|
+
|
1081
|
+
sage: R.<t> = QQ[]
|
1082
|
+
sage: f = -1 + 3*t/2 - t^3
|
1083
|
+
sage: g = 2/3 + 7/3*t + 3*t^2
|
1084
|
+
sage: f * g # indirect doctest
|
1085
|
+
-3*t^5 - 7/3*t^4 + 23/6*t^3 + 1/2*t^2 - 4/3*t - 2/3
|
1086
|
+
|
1087
|
+
TESTS::
|
1088
|
+
|
1089
|
+
sage: R.<t> = QQ[]
|
1090
|
+
sage: f = R.random_element(2000)
|
1091
|
+
sage: g = R.random_element(2000)
|
1092
|
+
sage: (f + g) * (f - g) == f^2 - g^2 # indirect doctest
|
1093
|
+
True
|
1094
|
+
"""
|
1095
|
+
cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right
|
1096
|
+
cdef Polynomial_rational_flint res = self._new()
|
1097
|
+
cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly)
|
1098
|
+
|
1099
|
+
if do_sig: sig_str("FLINT exception")
|
1100
|
+
fmpq_poly_mul(res._poly, self._poly, op2._poly)
|
1101
|
+
if do_sig: sig_off()
|
1102
|
+
return res
|
1103
|
+
|
1104
|
+
cpdef Polynomial _mul_trunc_(self, Polynomial right, long n):
|
1105
|
+
r"""
|
1106
|
+
Truncated multiplication.
|
1107
|
+
|
1108
|
+
EXAMPLES::
|
1109
|
+
|
1110
|
+
sage: x = polygen(QQ)
|
1111
|
+
sage: p1 = 1/2 - 3*x + 2/7*x**3
|
1112
|
+
sage: p2 = x + 2/5*x**5 + x**7
|
1113
|
+
sage: p1._mul_trunc_(p2, 5)
|
1114
|
+
2/7*x^4 - 3*x^2 + 1/2*x
|
1115
|
+
sage: (p1*p2).truncate(5)
|
1116
|
+
2/7*x^4 - 3*x^2 + 1/2*x
|
1117
|
+
|
1118
|
+
sage: p1._mul_trunc_(p2, 1)
|
1119
|
+
0
|
1120
|
+
sage: p1._mul_trunc_(p2, 0)
|
1121
|
+
Traceback (most recent call last):
|
1122
|
+
...
|
1123
|
+
ValueError: n must be > 0
|
1124
|
+
|
1125
|
+
ALGORITHM:
|
1126
|
+
|
1127
|
+
Call the FLINT method ``fmpq_poly_mullow``.
|
1128
|
+
"""
|
1129
|
+
cdef Polynomial_rational_flint op2 = <Polynomial_rational_flint> right
|
1130
|
+
cdef Polynomial_rational_flint res = self._new()
|
1131
|
+
cdef bint do_sig = _do_sig(self._poly) or _do_sig(op2._poly)
|
1132
|
+
|
1133
|
+
if n <= 0:
|
1134
|
+
raise ValueError("n must be > 0")
|
1135
|
+
|
1136
|
+
if do_sig: sig_str("FLINT exception")
|
1137
|
+
fmpq_poly_mullow(res._poly, self._poly, op2._poly, n)
|
1138
|
+
if do_sig: sig_off()
|
1139
|
+
return res
|
1140
|
+
|
1141
|
+
cpdef _rmul_(self, Element left):
|
1142
|
+
r"""
|
1143
|
+
Return ``left * self``, where ``left`` is a rational number.
|
1144
|
+
|
1145
|
+
EXAMPLES::
|
1146
|
+
|
1147
|
+
sage: R.<t> = QQ[]
|
1148
|
+
sage: f = 3/2*t^3 - t + 1/3
|
1149
|
+
sage: 6 * f # indirect doctest
|
1150
|
+
9*t^3 - 6*t + 2
|
1151
|
+
"""
|
1152
|
+
cdef Polynomial_rational_flint res = self._new()
|
1153
|
+
cdef bint do_sig = _do_sig(self._poly)
|
1154
|
+
|
1155
|
+
if do_sig: sig_str("FLINT exception")
|
1156
|
+
fmpq_poly_scalar_mul_mpq(res._poly, self._poly,
|
1157
|
+
(<Rational> left).value)
|
1158
|
+
if do_sig: sig_off()
|
1159
|
+
return res
|
1160
|
+
|
1161
|
+
cpdef _lmul_(self, Element right):
|
1162
|
+
r"""
|
1163
|
+
Return ``self * right``, where ``right`` is a rational number.
|
1164
|
+
|
1165
|
+
EXAMPLES::
|
1166
|
+
|
1167
|
+
sage: R.<t> = QQ[]
|
1168
|
+
sage: f = 3/2*t^3 - t + 1/3
|
1169
|
+
sage: f * 6 # indirect doctest
|
1170
|
+
9*t^3 - 6*t + 2
|
1171
|
+
"""
|
1172
|
+
cdef Polynomial_rational_flint res = self._new()
|
1173
|
+
cdef bint do_sig = _do_sig(self._poly)
|
1174
|
+
|
1175
|
+
if do_sig: sig_str("FLINT exception")
|
1176
|
+
fmpq_poly_scalar_mul_mpq(res._poly, self._poly,
|
1177
|
+
(<Rational> right).value)
|
1178
|
+
if do_sig: sig_off()
|
1179
|
+
return res
|
1180
|
+
|
1181
|
+
def __pow__(Polynomial_rational_flint self, exp, mod):
|
1182
|
+
"""
|
1183
|
+
Return ``self`` raised to the power of ``exp``.
|
1184
|
+
|
1185
|
+
The corner case of ``exp == 0`` is handled by returning the constant
|
1186
|
+
polynomial 1. Note that this includes the case ``0^0 == 1``.
|
1187
|
+
|
1188
|
+
This method only supports integral values for ``exp`` that fit into
|
1189
|
+
a signed long int (except when this is a constant polynomial).
|
1190
|
+
|
1191
|
+
INPUT:
|
1192
|
+
|
1193
|
+
- ``exp`` -- exponent
|
1194
|
+
|
1195
|
+
OUTPUT: polynomial; this polynomial raised to the power of ``exp``
|
1196
|
+
|
1197
|
+
EXAMPLES::
|
1198
|
+
|
1199
|
+
sage: R.<t> = QQ[]
|
1200
|
+
sage: f = 1/2 + 2*t - t^2/3
|
1201
|
+
sage: f^0
|
1202
|
+
1
|
1203
|
+
sage: f^3
|
1204
|
+
-1/27*t^6 + 2/3*t^5 - 23/6*t^4 + 6*t^3 + 23/4*t^2 + 3/2*t + 1/8
|
1205
|
+
sage: f^(-3)
|
1206
|
+
-27/(t^6 - 18*t^5 + 207/2*t^4 - 162*t^3 - 621/4*t^2 - 81/2*t - 27/8)
|
1207
|
+
|
1208
|
+
TESTS::
|
1209
|
+
|
1210
|
+
sage: R.<t> = QQ[]
|
1211
|
+
sage: t^0
|
1212
|
+
1
|
1213
|
+
sage: R(0)^0
|
1214
|
+
1
|
1215
|
+
sage: R(0)^(-1)
|
1216
|
+
Traceback (most recent call last):
|
1217
|
+
...
|
1218
|
+
ZeroDivisionError: negative exponent in power of zero
|
1219
|
+
|
1220
|
+
We verify the checking of the exponent::
|
1221
|
+
|
1222
|
+
sage: R.<t> = QQ[]
|
1223
|
+
sage: (1 + t)^(2/3)
|
1224
|
+
Traceback (most recent call last):
|
1225
|
+
...
|
1226
|
+
ValueError: not a 3rd power
|
1227
|
+
sage: (1 + t)^(2^63)
|
1228
|
+
Traceback (most recent call last):
|
1229
|
+
...
|
1230
|
+
OverflowError: Sage Integer too large to convert to C long
|
1231
|
+
|
1232
|
+
FLINT memory errors do not crash Sage (:issue:`17629`)::
|
1233
|
+
|
1234
|
+
sage: t^(sys.maxsize//2)
|
1235
|
+
Traceback (most recent call last):
|
1236
|
+
...
|
1237
|
+
RuntimeError: FLINT exception
|
1238
|
+
|
1239
|
+
Flush the output buffer to get rid of stray output -- see
|
1240
|
+
:issue:`28649`::
|
1241
|
+
|
1242
|
+
sage: from sage.misc.misc_c import cyflush
|
1243
|
+
sage: cyflush()
|
1244
|
+
...
|
1245
|
+
|
1246
|
+
Test fractional powers (:issue:`20086`)::
|
1247
|
+
|
1248
|
+
sage: P.<R> = QQ[]
|
1249
|
+
sage: (1/27*R^3 + 2/3*R^2 + 4*R + 8)^(2/3)
|
1250
|
+
1/9*R^2 + 4/3*R + 4
|
1251
|
+
sage: _.parent()
|
1252
|
+
Univariate Polynomial Ring in R over Rational Field
|
1253
|
+
sage: P(1/4)^(1/2)
|
1254
|
+
1/2
|
1255
|
+
sage: _.parent()
|
1256
|
+
Univariate Polynomial Ring in R over Rational Field
|
1257
|
+
|
1258
|
+
sage: (R+2)^(2/5)
|
1259
|
+
Traceback (most recent call last):
|
1260
|
+
...
|
1261
|
+
ValueError: not a 5th power
|
1262
|
+
|
1263
|
+
sage: P(1/3)^(1/2)
|
1264
|
+
Traceback (most recent call last):
|
1265
|
+
...
|
1266
|
+
ValueError: not a perfect 2nd power
|
1267
|
+
sage: P(4)^P(1/2)
|
1268
|
+
Traceback (most recent call last):
|
1269
|
+
...
|
1270
|
+
TypeError: no canonical coercion from Univariate Polynomial
|
1271
|
+
Ring in R over Rational Field to Rational Field
|
1272
|
+
sage: (R + 1)^P(2)
|
1273
|
+
Traceback (most recent call last):
|
1274
|
+
...
|
1275
|
+
TypeError: no canonical coercion from Univariate Polynomial
|
1276
|
+
Ring in R over Rational Field to Rational Field
|
1277
|
+
sage: (R + 1)^R
|
1278
|
+
Traceback (most recent call last):
|
1279
|
+
...
|
1280
|
+
TypeError: no canonical coercion from Univariate Polynomial
|
1281
|
+
Ring in R over Rational Field to Rational Field
|
1282
|
+
sage: 2^R
|
1283
|
+
Traceback (most recent call last):
|
1284
|
+
...
|
1285
|
+
TypeError: no canonical coercion from Univariate Polynomial
|
1286
|
+
Ring in R over Rational Field to Rational Field
|
1287
|
+
|
1288
|
+
Check that using third argument raises an error::
|
1289
|
+
|
1290
|
+
sage: R.<x> = PolynomialRing(QQ)
|
1291
|
+
sage: pow(x, 2, x)
|
1292
|
+
Traceback (most recent call last):
|
1293
|
+
...
|
1294
|
+
NotImplementedError: pow() with a modulus is not implemented for this ring
|
1295
|
+
"""
|
1296
|
+
cdef Polynomial_rational_flint res
|
1297
|
+
cdef long n
|
1298
|
+
|
1299
|
+
if mod is not None:
|
1300
|
+
raise NotImplementedError(
|
1301
|
+
"pow() with a modulus is not implemented for this ring"
|
1302
|
+
)
|
1303
|
+
|
1304
|
+
try:
|
1305
|
+
n = pyobject_to_long(exp)
|
1306
|
+
except TypeError:
|
1307
|
+
r = QQ.coerce(exp)
|
1308
|
+
num = r.numerator()
|
1309
|
+
den = r.denominator()
|
1310
|
+
|
1311
|
+
if fmpq_poly_degree(self._poly) == 0:
|
1312
|
+
return self.parent()(self[0].nth_root(den) ** num)
|
1313
|
+
|
1314
|
+
return self.nth_root(den) ** num
|
1315
|
+
|
1316
|
+
else:
|
1317
|
+
if n < 0:
|
1318
|
+
if fmpq_poly_is_zero(self._poly):
|
1319
|
+
raise ZeroDivisionError("negative exponent in power of zero")
|
1320
|
+
res = self._new()
|
1321
|
+
sig_str("FLINT exception")
|
1322
|
+
fmpq_poly_pow(res._poly, self._poly, -n)
|
1323
|
+
sig_off()
|
1324
|
+
return ~res
|
1325
|
+
else:
|
1326
|
+
res = self._new()
|
1327
|
+
sig_str("FLINT exception")
|
1328
|
+
if self._is_gen:
|
1329
|
+
fmpq_poly_set_coeff_si(res._poly, n, 1)
|
1330
|
+
else:
|
1331
|
+
fmpq_poly_pow(res._poly, self._poly, n)
|
1332
|
+
sig_off()
|
1333
|
+
return res
|
1334
|
+
|
1335
|
+
def __floordiv__(Polynomial_rational_flint self, right):
|
1336
|
+
"""
|
1337
|
+
Return the quotient of ``self`` and ``right`` obtained by Euclidean division.
|
1338
|
+
|
1339
|
+
EXAMPLES::
|
1340
|
+
|
1341
|
+
sage: R.<t> = QQ[]
|
1342
|
+
sage: f = t^3 - t/2 + 1/5
|
1343
|
+
sage: g = 2/3*t - 1
|
1344
|
+
sage: f // g # indirect doctest
|
1345
|
+
3/2*t^2 + 9/4*t + 21/8
|
1346
|
+
|
1347
|
+
TESTS::
|
1348
|
+
|
1349
|
+
sage: R.<t> = QQ[]
|
1350
|
+
sage: f = R.random_element(1000)
|
1351
|
+
sage: g = R.random_element(500)
|
1352
|
+
sage: if g == 0: g = R(1)
|
1353
|
+
sage: qr = f.quo_rem(g)
|
1354
|
+
sage: q = f // g # indirect doctest
|
1355
|
+
sage: qr[0] == q
|
1356
|
+
True
|
1357
|
+
"""
|
1358
|
+
cdef Polynomial_rational_flint res
|
1359
|
+
cdef bint do_sig
|
1360
|
+
cdef fmpq_t tmpfq
|
1361
|
+
|
1362
|
+
if right == 0:
|
1363
|
+
raise ZeroDivisionError("division by zero polynomial")
|
1364
|
+
|
1365
|
+
if not isinstance(right, Polynomial_rational_flint):
|
1366
|
+
if right in QQ:
|
1367
|
+
res = self._new()
|
1368
|
+
do_sig = _do_sig(self._poly)
|
1369
|
+
|
1370
|
+
if do_sig: sig_str("FLINT exception")
|
1371
|
+
fmpq_init_set_readonly(tmpfq, (<Rational> QQ(right)).value)
|
1372
|
+
fmpq_poly_scalar_div_fmpq(res._poly, self._poly, tmpfq)
|
1373
|
+
fmpq_clear_readonly(tmpfq)
|
1374
|
+
if do_sig: sig_off()
|
1375
|
+
return res
|
1376
|
+
|
1377
|
+
right = self._parent(right)
|
1378
|
+
|
1379
|
+
res = self._new()
|
1380
|
+
sig_str("FLINT exception")
|
1381
|
+
fmpq_poly_div(res._poly, self._poly,
|
1382
|
+
(<Polynomial_rational_flint>right)._poly)
|
1383
|
+
sig_off()
|
1384
|
+
return res
|
1385
|
+
|
1386
|
+
cpdef Polynomial inverse_series_trunc(self, long prec):
|
1387
|
+
r"""
|
1388
|
+
Return a polynomial approximation of precision ``prec`` of the inverse
|
1389
|
+
series of this polynomial.
|
1390
|
+
|
1391
|
+
EXAMPLES::
|
1392
|
+
|
1393
|
+
sage: x = polygen(QQ)
|
1394
|
+
sage: p = 2 + x - 3/5*x**2
|
1395
|
+
sage: q5 = p.inverse_series_trunc(5)
|
1396
|
+
sage: q5
|
1397
|
+
151/800*x^4 - 17/80*x^3 + 11/40*x^2 - 1/4*x + 1/2
|
1398
|
+
sage: q5 * p
|
1399
|
+
-453/4000*x^6 + 253/800*x^5 + 1
|
1400
|
+
|
1401
|
+
sage: q100 = p.inverse_series_trunc(100)
|
1402
|
+
sage: (q100 * p).truncate(100)
|
1403
|
+
1
|
1404
|
+
|
1405
|
+
TESTS::
|
1406
|
+
|
1407
|
+
sage: (0*x).inverse_series_trunc(4)
|
1408
|
+
Traceback (most recent call last):
|
1409
|
+
...
|
1410
|
+
ValueError: constant term is zero
|
1411
|
+
sage: x.inverse_series_trunc(4)
|
1412
|
+
Traceback (most recent call last):
|
1413
|
+
...
|
1414
|
+
ValueError: constant term is zero
|
1415
|
+
sage: (x+1).inverse_series_trunc(0)
|
1416
|
+
Traceback (most recent call last):
|
1417
|
+
...
|
1418
|
+
ValueError: the precision must be positive, got 0
|
1419
|
+
"""
|
1420
|
+
if prec <= 0:
|
1421
|
+
raise ValueError("the precision must be positive, got {}".format(prec))
|
1422
|
+
if fmpq_poly_degree(self._poly) == -1 or \
|
1423
|
+
fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1424
|
+
raise ValueError("constant term is zero")
|
1425
|
+
|
1426
|
+
cdef Polynomial_rational_flint res = self._new()
|
1427
|
+
if prec <= 0:
|
1428
|
+
return res
|
1429
|
+
sig_on()
|
1430
|
+
fmpq_poly_inv_series(res._poly, self._poly, prec)
|
1431
|
+
sig_off()
|
1432
|
+
return res
|
1433
|
+
|
1434
|
+
cpdef _mod_(self, right):
|
1435
|
+
"""
|
1436
|
+
Return the remainder of ``self`` and ``right`` obtain by Euclidean division.
|
1437
|
+
|
1438
|
+
EXAMPLES::
|
1439
|
+
|
1440
|
+
sage: R.<t> = QQ[]
|
1441
|
+
sage: f = t^3 - t/2 + 1/5
|
1442
|
+
sage: g = 2/3*t - 1
|
1443
|
+
sage: f % g # indirect doctest
|
1444
|
+
113/40
|
1445
|
+
|
1446
|
+
TESTS::
|
1447
|
+
|
1448
|
+
sage: R.<t> = QQ[]
|
1449
|
+
sage: f = R.random_element(1000)
|
1450
|
+
sage: g = R.random_element(500)
|
1451
|
+
sage: if g == 0: g = R(1)
|
1452
|
+
sage: qr = f.quo_rem(g)
|
1453
|
+
sage: r = f % g # indirect doctest
|
1454
|
+
sage: qr[1] == r
|
1455
|
+
True
|
1456
|
+
"""
|
1457
|
+
cdef Polynomial_rational_flint res
|
1458
|
+
|
1459
|
+
if right == 0:
|
1460
|
+
raise ZeroDivisionError("division by zero polynomial")
|
1461
|
+
|
1462
|
+
res = self._new()
|
1463
|
+
sig_str("FLINT exception")
|
1464
|
+
fmpq_poly_rem(res._poly, self._poly,
|
1465
|
+
(<Polynomial_rational_flint>right)._poly)
|
1466
|
+
sig_off()
|
1467
|
+
return res
|
1468
|
+
|
1469
|
+
###########################################################################
|
1470
|
+
# Further methods #
|
1471
|
+
###########################################################################
|
1472
|
+
|
1473
|
+
def numerator(self):
|
1474
|
+
"""
|
1475
|
+
Return the numerator of ``self``.
|
1476
|
+
|
1477
|
+
Representing ``self`` as the quotient of an integer polynomial and
|
1478
|
+
a positive integer denominator (coprime to the content of the
|
1479
|
+
polynomial), returns the integer polynomial.
|
1480
|
+
|
1481
|
+
EXAMPLES::
|
1482
|
+
|
1483
|
+
sage: R.<t> = QQ[]
|
1484
|
+
sage: f = (3 * t^3 + 1) / -3
|
1485
|
+
sage: f.numerator()
|
1486
|
+
-3*t^3 - 1
|
1487
|
+
"""
|
1488
|
+
cdef Polynomial_integer_dense_flint num
|
1489
|
+
num = Polynomial_integer_dense_flint.__new__(Polynomial_integer_dense_flint)
|
1490
|
+
parent = ZZ[self.variable_name()]
|
1491
|
+
Polynomial_integer_dense_flint.__init__(num, parent, x=None,
|
1492
|
+
check=False, is_gen=False, construct=False)
|
1493
|
+
sig_str("FLINT exception")
|
1494
|
+
fmpq_poly_get_numerator(num._poly, self._poly)
|
1495
|
+
sig_off()
|
1496
|
+
return num
|
1497
|
+
|
1498
|
+
def denominator(self):
|
1499
|
+
"""
|
1500
|
+
Return the denominator of ``self``.
|
1501
|
+
|
1502
|
+
EXAMPLES::
|
1503
|
+
|
1504
|
+
sage: R.<t> = QQ[]
|
1505
|
+
sage: f = (3 * t^3 + 1) / -3
|
1506
|
+
sage: f.denominator()
|
1507
|
+
3
|
1508
|
+
"""
|
1509
|
+
cdef Integer den = Integer.__new__(Integer)
|
1510
|
+
if fmpq_poly_denref(self._poly) is NULL:
|
1511
|
+
mpz_set_ui(den.value, 1)
|
1512
|
+
else:
|
1513
|
+
fmpz_get_mpz(den.value, <fmpz *> fmpq_poly_denref(self._poly))
|
1514
|
+
return den
|
1515
|
+
|
1516
|
+
def _derivative(self, var=None):
|
1517
|
+
"""
|
1518
|
+
Return the derivative of this polynomial with respect to ``var``.
|
1519
|
+
|
1520
|
+
INPUT:
|
1521
|
+
|
1522
|
+
- ``var`` -- must be either (equal to) the generator of the polynomial
|
1523
|
+
ring to which this polynomial belongs, or ``None``; either way the
|
1524
|
+
behaviour is the same
|
1525
|
+
|
1526
|
+
OUTPUT: derivative as a ``Polynomial_rational_flint``
|
1527
|
+
|
1528
|
+
.. SEEALSO:: :meth:`~Polynomial.derivative`
|
1529
|
+
|
1530
|
+
EXAMPLES::
|
1531
|
+
|
1532
|
+
sage: R.<x> = QQ[]
|
1533
|
+
sage: f = x^4 - x - 1
|
1534
|
+
sage: f._derivative()
|
1535
|
+
4*x^3 - 1
|
1536
|
+
sage: f._derivative(None)
|
1537
|
+
4*x^3 - 1
|
1538
|
+
sage: f._derivative(2*x)
|
1539
|
+
Traceback (most recent call last):
|
1540
|
+
...
|
1541
|
+
ValueError: cannot differentiate with respect to 2*x
|
1542
|
+
|
1543
|
+
Check that :issue:`28187` is fixed::
|
1544
|
+
|
1545
|
+
sage: x = var("x") # needs sage.symbolic
|
1546
|
+
sage: f._derivative(x) # needs sage.symbolic
|
1547
|
+
4*x^3 - 1
|
1548
|
+
"""
|
1549
|
+
cdef Polynomial_rational_flint der
|
1550
|
+
cdef bint do_sig
|
1551
|
+
|
1552
|
+
if var is not None and var != self._parent.gen():
|
1553
|
+
raise ValueError("cannot differentiate with respect to {}".format(var))
|
1554
|
+
|
1555
|
+
der = self._new()
|
1556
|
+
do_sig = _do_sig(self._poly)
|
1557
|
+
|
1558
|
+
if do_sig: sig_str("FLINT exception")
|
1559
|
+
fmpq_poly_derivative(der._poly, self._poly)
|
1560
|
+
if do_sig: sig_off()
|
1561
|
+
return der
|
1562
|
+
|
1563
|
+
def real_root_intervals(self):
|
1564
|
+
"""
|
1565
|
+
Return isolating intervals for the real roots of ``self``.
|
1566
|
+
|
1567
|
+
EXAMPLES:
|
1568
|
+
|
1569
|
+
We compute the roots of the characteristic polynomial of some
|
1570
|
+
Salem numbers::
|
1571
|
+
|
1572
|
+
sage: R.<t> = QQ[]
|
1573
|
+
sage: f = 1 - t^2 - t^3 - t^4 + t^6
|
1574
|
+
sage: f.real_root_intervals()
|
1575
|
+
[((1/2, 3/4), 1), ((1, 3/2), 1)]
|
1576
|
+
"""
|
1577
|
+
from sage.rings.polynomial.real_roots import real_roots
|
1578
|
+
return real_roots(self)
|
1579
|
+
|
1580
|
+
@coerce_binop
|
1581
|
+
def resultant(Polynomial_rational_flint self, right):
|
1582
|
+
r"""
|
1583
|
+
Return the resultant of ``self`` and ``right``.
|
1584
|
+
|
1585
|
+
Enumerating the roots over `\QQ` as `r_1, \dots, r_m` and
|
1586
|
+
`s_1, \dots, s_n` and letting `x` and `y` denote the leading
|
1587
|
+
coefficients of `f` and `g`, the resultant of the two polynomials
|
1588
|
+
is defined by
|
1589
|
+
|
1590
|
+
.. MATH::
|
1591
|
+
|
1592
|
+
x^{\deg g} y^{\deg f} \prod_{i,j} (r_i - s_j).
|
1593
|
+
|
1594
|
+
Corner cases: if one of the polynomials is zero, the resultant
|
1595
|
+
is zero. Note that otherwise if one of the polynomials is constant,
|
1596
|
+
the last term in the above is the empty product.
|
1597
|
+
|
1598
|
+
EXAMPLES::
|
1599
|
+
|
1600
|
+
sage: R.<t> = QQ[]
|
1601
|
+
sage: f = (t - 2/3) * (t + 4/5) * (t - 1)
|
1602
|
+
sage: g = (t - 1/3) * (t + 1/2) * (t + 1)
|
1603
|
+
sage: f.resultant(g)
|
1604
|
+
119/1350
|
1605
|
+
sage: h = (t - 1/3) * (t + 1/2) * (t - 1)
|
1606
|
+
sage: f.resultant(h)
|
1607
|
+
0
|
1608
|
+
"""
|
1609
|
+
cdef Rational res = Rational.__new__(Rational)
|
1610
|
+
cdef fmpq_t t
|
1611
|
+
fmpq_init(t)
|
1612
|
+
sig_str("FLINT exception")
|
1613
|
+
fmpq_poly_resultant(t, self._poly,
|
1614
|
+
(<Polynomial_rational_flint>right)._poly)
|
1615
|
+
fmpq_get_mpq(res.value, t)
|
1616
|
+
sig_off()
|
1617
|
+
fmpq_clear(t)
|
1618
|
+
return res
|
1619
|
+
|
1620
|
+
@cached_method
|
1621
|
+
def is_irreducible(self):
|
1622
|
+
r"""
|
1623
|
+
Return whether this polynomial is irreducible.
|
1624
|
+
|
1625
|
+
This method computes the primitive part as an element of `\ZZ[t]` and
|
1626
|
+
calls the method ``is_irreducible`` for elements of that polynomial
|
1627
|
+
ring.
|
1628
|
+
|
1629
|
+
By definition, over any integral domain, an element `r` is irreducible
|
1630
|
+
if and only if it is nonzero, not a unit and whenever `r = ab` then
|
1631
|
+
`a` or `b` is a unit.
|
1632
|
+
|
1633
|
+
EXAMPLES::
|
1634
|
+
|
1635
|
+
sage: R.<t> = QQ[]
|
1636
|
+
sage: (t^2 + 2).is_irreducible()
|
1637
|
+
True
|
1638
|
+
sage: (t^2 - 1).is_irreducible()
|
1639
|
+
False
|
1640
|
+
|
1641
|
+
TESTS::
|
1642
|
+
|
1643
|
+
sage: R.<t> = QQ[]
|
1644
|
+
sage: R(0).is_irreducible()
|
1645
|
+
False
|
1646
|
+
sage: R(-1/2).is_irreducible()
|
1647
|
+
False
|
1648
|
+
sage: (t + 1).is_irreducible()
|
1649
|
+
True
|
1650
|
+
|
1651
|
+
Test that caching works::
|
1652
|
+
|
1653
|
+
sage: R.<t> = QQ[]
|
1654
|
+
sage: f = t + 1
|
1655
|
+
sage: f.is_irreducible()
|
1656
|
+
True
|
1657
|
+
sage: f.is_irreducible.cache
|
1658
|
+
True
|
1659
|
+
"""
|
1660
|
+
cdef Polynomial_integer_dense_flint primitive
|
1661
|
+
cdef unsigned long length = fmpq_poly_length(self._poly)
|
1662
|
+
|
1663
|
+
if length < 2:
|
1664
|
+
return False
|
1665
|
+
elif length == 2:
|
1666
|
+
return True
|
1667
|
+
else:
|
1668
|
+
primitive = Polynomial_integer_dense_flint.__new__(Polynomial_integer_dense_flint)
|
1669
|
+
parent = ZZ[self.variable_name()]
|
1670
|
+
Polynomial_integer_dense_flint.__init__(primitive, parent,
|
1671
|
+
x=None, check=True, is_gen=False, construct=False)
|
1672
|
+
|
1673
|
+
sig_str("FLINT exception")
|
1674
|
+
fmpq_poly_get_numerator(primitive._poly, self._poly)
|
1675
|
+
fmpz_poly_primitive_part(primitive._poly, primitive._poly)
|
1676
|
+
sig_off()
|
1677
|
+
return primitive.is_irreducible()
|
1678
|
+
|
1679
|
+
#######################################################
|
1680
|
+
# Transcendental functions (return truncated series) #
|
1681
|
+
#######################################################
|
1682
|
+
|
1683
|
+
def _log_series(self, long prec):
|
1684
|
+
r"""
|
1685
|
+
Return the logarithm of this polynomial up to precision ``prec``.
|
1686
|
+
|
1687
|
+
EXAMPLES::
|
1688
|
+
|
1689
|
+
sage: x = polygen(QQ)
|
1690
|
+
sage: (1+x)._log_series(5)
|
1691
|
+
-1/4*x^4 + 1/3*x^3 - 1/2*x^2 + x
|
1692
|
+
|
1693
|
+
sage: (1/3*x^3 - 2*x^2 + x + 1)._log_series(10)._exp_series(10)
|
1694
|
+
1/3*x^3 - 2*x^2 + x + 1
|
1695
|
+
|
1696
|
+
TESTS::
|
1697
|
+
|
1698
|
+
sage: x._log_series(5)
|
1699
|
+
Traceback (most recent call last):
|
1700
|
+
...
|
1701
|
+
ValueError: constant term should be 1 in order to take logarithm
|
1702
|
+
sage: (0*x)._log_series(5)
|
1703
|
+
Traceback (most recent call last):
|
1704
|
+
...
|
1705
|
+
ValueError: constant term should be 1 in order to take logarithm
|
1706
|
+
"""
|
1707
|
+
if fmpq_poly_degree(self._poly) == -1 or \
|
1708
|
+
fmpz_cmp(fmpq_poly_numref(self._poly),
|
1709
|
+
fmpq_poly_denref(self._poly)):
|
1710
|
+
raise ValueError("constant term should be 1 in order to take logarithm")
|
1711
|
+
|
1712
|
+
cdef Polynomial_rational_flint res = self._new()
|
1713
|
+
sig_on()
|
1714
|
+
fmpq_poly_log_series(res._poly, self._poly, prec)
|
1715
|
+
sig_off()
|
1716
|
+
return res
|
1717
|
+
|
1718
|
+
def _exp_series(self, long prec):
|
1719
|
+
r"""
|
1720
|
+
Return the exponential of this polynomial up to precision ``prec``.
|
1721
|
+
|
1722
|
+
EXAMPLES::
|
1723
|
+
|
1724
|
+
sage: x = polygen(QQ)
|
1725
|
+
sage: x._exp_series(5)
|
1726
|
+
1/24*x^4 + 1/6*x^3 + 1/2*x^2 + x + 1
|
1727
|
+
sage: (1/3*x^4 - 3*x^2 - 1/2*x)._exp_series(5)._log_series(5)
|
1728
|
+
1/3*x^4 - 3*x^2 - 1/2*x
|
1729
|
+
|
1730
|
+
TESTS::
|
1731
|
+
|
1732
|
+
sage: (x+1)._exp_series(5)
|
1733
|
+
Traceback (most recent call last):
|
1734
|
+
...
|
1735
|
+
ValueError: constant term should be 0 in order to take exponential
|
1736
|
+
sage: (0*x)._exp_series(5)
|
1737
|
+
1
|
1738
|
+
sage: _.parent()
|
1739
|
+
Univariate Polynomial Ring in x over Rational Field
|
1740
|
+
"""
|
1741
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1742
|
+
return self._parent.one()
|
1743
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1744
|
+
raise ValueError("constant term should be 0 in order to take exponential")
|
1745
|
+
|
1746
|
+
cdef Polynomial_rational_flint res = self._new()
|
1747
|
+
sig_on()
|
1748
|
+
fmpq_poly_exp_series(res._poly, self._poly, prec)
|
1749
|
+
sig_off()
|
1750
|
+
return res
|
1751
|
+
|
1752
|
+
def _atan_series(self, long prec):
|
1753
|
+
r"""
|
1754
|
+
Return the arctangent of this polynomial up to precision ``prec``.
|
1755
|
+
|
1756
|
+
EXAMPLES::
|
1757
|
+
|
1758
|
+
sage: x = polygen(QQ)
|
1759
|
+
sage: x._atan_series(7)
|
1760
|
+
1/5*x^5 - 1/3*x^3 + x
|
1761
|
+
sage: (1/5*x^3 + 2*x^2 - x)._atan_series(10)._tan_series(10)
|
1762
|
+
1/5*x^3 + 2*x^2 - x
|
1763
|
+
|
1764
|
+
TESTS::
|
1765
|
+
|
1766
|
+
sage: (1+x)._atan_series(3)
|
1767
|
+
Traceback (most recent call last):
|
1768
|
+
...
|
1769
|
+
ValueError: constant term should be 0 in order to take arctangent
|
1770
|
+
sage: (0*x)._atan_series(10)
|
1771
|
+
0
|
1772
|
+
sage: _.parent()
|
1773
|
+
Univariate Polynomial Ring in x over Rational Field
|
1774
|
+
"""
|
1775
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1776
|
+
return self._parent.zero()
|
1777
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1778
|
+
raise ValueError("constant term should be 0 in order to take arctangent")
|
1779
|
+
|
1780
|
+
cdef Polynomial_rational_flint res = self._new()
|
1781
|
+
sig_on()
|
1782
|
+
fmpq_poly_atan_series(res._poly, self._poly, prec)
|
1783
|
+
sig_off()
|
1784
|
+
return res
|
1785
|
+
|
1786
|
+
def _atanh_series(self, long prec):
|
1787
|
+
r"""
|
1788
|
+
Return the hyperbolic arctangent of this polynomial up to precision
|
1789
|
+
``prec``.
|
1790
|
+
|
1791
|
+
EXAMPLES::
|
1792
|
+
|
1793
|
+
sage: x = polygen(QQ)
|
1794
|
+
sage: x._atanh_series(7)
|
1795
|
+
1/5*x^5 + 1/3*x^3 + x
|
1796
|
+
sage: (1/5*x^3 + 2*x^2 - x)._atanh_series(10)._tanh_series(10)
|
1797
|
+
1/5*x^3 + 2*x^2 - x
|
1798
|
+
|
1799
|
+
TESTS::
|
1800
|
+
|
1801
|
+
sage: (0*x)._atanh_series(10)
|
1802
|
+
0
|
1803
|
+
sage: _.parent()
|
1804
|
+
Univariate Polynomial Ring in x over Rational Field
|
1805
|
+
"""
|
1806
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1807
|
+
return self._parent.zero()
|
1808
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1809
|
+
raise ValueError("constant term should be 0 in order to take hyperbolic arctangent")
|
1810
|
+
|
1811
|
+
cdef Polynomial_rational_flint res = self._new()
|
1812
|
+
sig_on()
|
1813
|
+
fmpq_poly_atanh_series(res._poly, self._poly, prec)
|
1814
|
+
sig_off()
|
1815
|
+
return res
|
1816
|
+
|
1817
|
+
def _asin_series(self, long prec):
|
1818
|
+
r"""
|
1819
|
+
Return the arcsine of this polynomial up to precision ``prec``.
|
1820
|
+
|
1821
|
+
EXAMPLES::
|
1822
|
+
|
1823
|
+
sage: x = polygen(QQ)
|
1824
|
+
sage: x._asin_series(7)
|
1825
|
+
3/40*x^5 + 1/6*x^3 + x
|
1826
|
+
sage: (1/5*x^3 + 2*x^2 - x)._asin_series(10)._sin_series(10)
|
1827
|
+
1/5*x^3 + 2*x^2 - x
|
1828
|
+
|
1829
|
+
TESTS::
|
1830
|
+
|
1831
|
+
sage: (x+1)._asin_series(5)
|
1832
|
+
Traceback (most recent call last):
|
1833
|
+
...
|
1834
|
+
ValueError: constant term should be 0 in order to take arcsine
|
1835
|
+
sage: (0*x)._asin_series(5)
|
1836
|
+
0
|
1837
|
+
sage: _.parent()
|
1838
|
+
Univariate Polynomial Ring in x over Rational Field
|
1839
|
+
"""
|
1840
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1841
|
+
return self._parent.zero()
|
1842
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1843
|
+
raise ValueError("constant term should be 0 in order to take arcsine")
|
1844
|
+
|
1845
|
+
cdef Polynomial_rational_flint res = self._new()
|
1846
|
+
sig_on()
|
1847
|
+
fmpq_poly_asin_series(res._poly, self._poly, prec)
|
1848
|
+
sig_off()
|
1849
|
+
return res
|
1850
|
+
|
1851
|
+
def _asinh_series(self, long prec):
|
1852
|
+
r"""
|
1853
|
+
Return the hyperbolic arcsine of this polynomial up to precision
|
1854
|
+
``prec``.
|
1855
|
+
|
1856
|
+
EXAMPLES::
|
1857
|
+
|
1858
|
+
sage: x = polygen(QQ)
|
1859
|
+
sage: x._asinh_series(7)
|
1860
|
+
3/40*x^5 - 1/6*x^3 + x
|
1861
|
+
sage: (1/5*x^3 + 2*x^2 - x)._asinh_series(10)._sinh_series(10)
|
1862
|
+
1/5*x^3 + 2*x^2 - x
|
1863
|
+
|
1864
|
+
TESTS::
|
1865
|
+
|
1866
|
+
sage: (x+1)._asinh_series(5)
|
1867
|
+
Traceback (most recent call last):
|
1868
|
+
...
|
1869
|
+
ValueError: constant term should be 0 in order to take hyperbolic arcsine
|
1870
|
+
sage: (0*x)._asinh_series(5)
|
1871
|
+
0
|
1872
|
+
sage: _.parent()
|
1873
|
+
Univariate Polynomial Ring in x over Rational Field
|
1874
|
+
"""
|
1875
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1876
|
+
return self._parent.zero()
|
1877
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1878
|
+
raise ValueError("constant term should be 0 in order to take hyperbolic arcsine")
|
1879
|
+
|
1880
|
+
cdef Polynomial_rational_flint res = self._new()
|
1881
|
+
sig_on()
|
1882
|
+
fmpq_poly_asinh_series(res._poly, self._poly, prec)
|
1883
|
+
sig_off()
|
1884
|
+
return res
|
1885
|
+
|
1886
|
+
def _tan_series(self, long prec):
|
1887
|
+
r"""
|
1888
|
+
Return the tangent of this polynomial up to precision ``prec``.
|
1889
|
+
|
1890
|
+
EXAMPLES::
|
1891
|
+
|
1892
|
+
sage: x = polygen(QQ)
|
1893
|
+
sage: x._tan_series(8)
|
1894
|
+
17/315*x^7 + 2/15*x^5 + 1/3*x^3 + x
|
1895
|
+
sage: (1/5*x^3 + 2*x^2 - x)._tan_series(10)._atan_series(10)
|
1896
|
+
1/5*x^3 + 2*x^2 - x
|
1897
|
+
|
1898
|
+
TESTS::
|
1899
|
+
|
1900
|
+
sage: (x+1)._tan_series(10)
|
1901
|
+
Traceback (most recent call last):
|
1902
|
+
...
|
1903
|
+
ValueError: constant term should be 0 in order to take tangent
|
1904
|
+
sage: (0*x)._tan_series(5)
|
1905
|
+
0
|
1906
|
+
sage: _.parent()
|
1907
|
+
Univariate Polynomial Ring in x over Rational Field
|
1908
|
+
"""
|
1909
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1910
|
+
return self._parent.zero()
|
1911
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1912
|
+
raise ValueError("constant term should be 0 in order to take tangent")
|
1913
|
+
|
1914
|
+
cdef Polynomial_rational_flint res = self._new()
|
1915
|
+
sig_on()
|
1916
|
+
fmpq_poly_tan_series(res._poly, self._poly, prec)
|
1917
|
+
sig_off()
|
1918
|
+
return res
|
1919
|
+
|
1920
|
+
def _sin_series(self, long prec):
|
1921
|
+
r"""
|
1922
|
+
Return the sine of this polynomial up to precision ``prec``.
|
1923
|
+
|
1924
|
+
EXAMPLES::
|
1925
|
+
|
1926
|
+
sage: x = polygen(QQ)
|
1927
|
+
sage: x._sin_series(8)
|
1928
|
+
-1/5040*x^7 + 1/120*x^5 - 1/6*x^3 + x
|
1929
|
+
sage: (1/5*x^3 - 2*x^2 + 1/2*x)._sin_series(10)._asin_series(10)
|
1930
|
+
1/5*x^3 - 2*x^2 + 1/2*x
|
1931
|
+
|
1932
|
+
TESTS::
|
1933
|
+
|
1934
|
+
sage: (x+1)._sin_series(10)
|
1935
|
+
Traceback (most recent call last):
|
1936
|
+
...
|
1937
|
+
ValueError: constant term should be 0 in order to take sine
|
1938
|
+
sage: (0*x)._sin_series(5)
|
1939
|
+
0
|
1940
|
+
sage: _.parent()
|
1941
|
+
Univariate Polynomial Ring in x over Rational Field
|
1942
|
+
"""
|
1943
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1944
|
+
return self._parent.zero()
|
1945
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1946
|
+
raise ValueError("constant term should be 0 in order to take sine")
|
1947
|
+
|
1948
|
+
cdef Polynomial_rational_flint res = self._new()
|
1949
|
+
sig_on()
|
1950
|
+
fmpq_poly_sin_series(res._poly, self._poly, prec)
|
1951
|
+
sig_off()
|
1952
|
+
return res
|
1953
|
+
|
1954
|
+
def _cos_series(self, long prec):
|
1955
|
+
r"""
|
1956
|
+
Return the cosine of this polynomial up to precision ``prec``.
|
1957
|
+
|
1958
|
+
EXAMPLES::
|
1959
|
+
|
1960
|
+
sage: x = polygen(QQ)
|
1961
|
+
sage: x._cos_series(10)
|
1962
|
+
1/40320*x^8 - 1/720*x^6 + 1/24*x^4 - 1/2*x^2 + 1
|
1963
|
+
|
1964
|
+
TESTS::
|
1965
|
+
|
1966
|
+
sage: (x+1)._cos_series(5)
|
1967
|
+
Traceback (most recent call last):
|
1968
|
+
...
|
1969
|
+
ValueError: constant term should be 0 in order to take cosine
|
1970
|
+
sage: (0*x)._cos_series(5)
|
1971
|
+
0
|
1972
|
+
sage: _.parent()
|
1973
|
+
Univariate Polynomial Ring in x over Rational Field
|
1974
|
+
"""
|
1975
|
+
if fmpq_poly_degree(self._poly) == -1:
|
1976
|
+
return self._parent.zero()
|
1977
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
1978
|
+
raise ValueError("constant term should be 0 in order to take cosine")
|
1979
|
+
|
1980
|
+
cdef Polynomial_rational_flint res = self._new()
|
1981
|
+
sig_on()
|
1982
|
+
fmpq_poly_cos_series(res._poly, self._poly, prec)
|
1983
|
+
sig_off()
|
1984
|
+
return res
|
1985
|
+
|
1986
|
+
def _sinh_series(self, long prec):
|
1987
|
+
r"""
|
1988
|
+
Return the hyperbolic sine of this polynomial up to precision ``prec``.
|
1989
|
+
|
1990
|
+
EXAMPLES::
|
1991
|
+
|
1992
|
+
sage: x = polygen(QQ)
|
1993
|
+
sage: x._sinh_series(8)
|
1994
|
+
1/5040*x^7 + 1/120*x^5 + 1/6*x^3 + x
|
1995
|
+
|
1996
|
+
TESTS::
|
1997
|
+
|
1998
|
+
sage: (x+1)._sinh_series(5)
|
1999
|
+
Traceback (most recent call last):
|
2000
|
+
...
|
2001
|
+
ValueError: constant term should be 0 in order to take hyperbolic sine
|
2002
|
+
sage: (0*x)._sinh_series(5)
|
2003
|
+
0
|
2004
|
+
sage: _.parent()
|
2005
|
+
Univariate Polynomial Ring in x over Rational Field
|
2006
|
+
"""
|
2007
|
+
if fmpq_poly_degree(self._poly) == -1:
|
2008
|
+
return self._parent.zero()
|
2009
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
2010
|
+
raise ValueError("constant term should be 0 in order to take hyperbolic sine")
|
2011
|
+
|
2012
|
+
cdef Polynomial_rational_flint res = self._new()
|
2013
|
+
sig_on()
|
2014
|
+
fmpq_poly_sinh_series(res._poly, self._poly, prec)
|
2015
|
+
sig_off()
|
2016
|
+
return res
|
2017
|
+
|
2018
|
+
def _cosh_series(self, long prec):
|
2019
|
+
r"""
|
2020
|
+
Return the hyperbolic cosine of this polynomial up to precision
|
2021
|
+
``prec``.
|
2022
|
+
|
2023
|
+
EXAMPLES::
|
2024
|
+
|
2025
|
+
sage: x = polygen(QQ)
|
2026
|
+
sage: x._cosh_series(8)
|
2027
|
+
1/720*x^6 + 1/24*x^4 + 1/2*x^2 + 1
|
2028
|
+
|
2029
|
+
A trigonometric identity::
|
2030
|
+
|
2031
|
+
sage: x._cosh_series(8) + x._sinh_series(8) == x._exp_series(8)
|
2032
|
+
True
|
2033
|
+
|
2034
|
+
TESTS::
|
2035
|
+
|
2036
|
+
sage: (x+1)._cosh_series(5)
|
2037
|
+
Traceback (most recent call last):
|
2038
|
+
...
|
2039
|
+
ValueError: constant term should be 0 in order to take hyperbolic cosine
|
2040
|
+
sage: (0*x)._cosh_series(5)
|
2041
|
+
1
|
2042
|
+
sage: _.parent()
|
2043
|
+
Univariate Polynomial Ring in x over Rational Field
|
2044
|
+
"""
|
2045
|
+
if fmpq_poly_degree(self._poly) == -1:
|
2046
|
+
return self._parent.one()
|
2047
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
2048
|
+
raise ValueError("constant term should be 0 in order to take hyperbolic cosine")
|
2049
|
+
|
2050
|
+
cdef Polynomial_rational_flint res = self._new()
|
2051
|
+
sig_on()
|
2052
|
+
fmpq_poly_cosh_series(res._poly, self._poly, prec)
|
2053
|
+
sig_off()
|
2054
|
+
return res
|
2055
|
+
|
2056
|
+
def _tanh_series(self, long prec):
|
2057
|
+
r"""
|
2058
|
+
Return the hyperbolic tangent of this polynomial up to precision
|
2059
|
+
``prec``.
|
2060
|
+
|
2061
|
+
EXAMPLES::
|
2062
|
+
|
2063
|
+
sage: x = polygen(QQ)
|
2064
|
+
sage: x._tanh_series(8)
|
2065
|
+
-17/315*x^7 + 2/15*x^5 - 1/3*x^3 + x
|
2066
|
+
|
2067
|
+
TESTS::
|
2068
|
+
|
2069
|
+
sage: (x+1)._tanh_series(5)
|
2070
|
+
Traceback (most recent call last):
|
2071
|
+
...
|
2072
|
+
ValueError: constant term should be 0 in order to take hyperbolic tangent
|
2073
|
+
sage: (0*x)._tanh_series(5)
|
2074
|
+
0
|
2075
|
+
sage: _.parent()
|
2076
|
+
Univariate Polynomial Ring in x over Rational Field
|
2077
|
+
"""
|
2078
|
+
if fmpq_poly_degree(self._poly) == -1:
|
2079
|
+
return self._parent.zero()
|
2080
|
+
elif not fmpz_is_zero(fmpq_poly_numref(self._poly)):
|
2081
|
+
raise ValueError("constant term should be 0 in order to take hyperbolic tangent")
|
2082
|
+
|
2083
|
+
cdef Polynomial_rational_flint res = self._new()
|
2084
|
+
sig_on()
|
2085
|
+
fmpq_poly_tanh_series(res._poly, self._poly, prec)
|
2086
|
+
sig_off()
|
2087
|
+
return res
|
2088
|
+
|
2089
|
+
###########################################################################
|
2090
|
+
# Methods using PARI #
|
2091
|
+
###########################################################################
|
2092
|
+
|
2093
|
+
def galois_group(self, pari_group=False, algorithm='pari'):
|
2094
|
+
"""
|
2095
|
+
Return the Galois group of this polynomial as a permutation group.
|
2096
|
+
|
2097
|
+
INPUT:
|
2098
|
+
|
2099
|
+
- ``self`` -- irreducible polynomial
|
2100
|
+
|
2101
|
+
- ``pari_group`` -- boolean (default: ``False``); if ``True`` instead
|
2102
|
+
return the Galois group as a PARI group. This has a useful label
|
2103
|
+
in it, and may be slightly faster since it doesn't require looking
|
2104
|
+
up a group in GAP. To get a permutation group from a PARI
|
2105
|
+
group ``P``, type ``PermutationGroup(P)``.
|
2106
|
+
|
2107
|
+
- ``algorithm`` -- ``'pari'``, ``'gap'``, ``'kash'``, ``'magma'`` (default:
|
2108
|
+
``'pari'``, for degrees is at most 11;
|
2109
|
+
``'gap'``, for degrees from 12 to 15;
|
2110
|
+
``'kash'``, for degrees from 16 or more).
|
2111
|
+
|
2112
|
+
OUTPUT: Galois group
|
2113
|
+
|
2114
|
+
ALGORITHM:
|
2115
|
+
|
2116
|
+
The Galois group is computed using PARI in C library mode, or possibly
|
2117
|
+
GAP, KASH, or MAGMA.
|
2118
|
+
|
2119
|
+
.. NOTE::
|
2120
|
+
|
2121
|
+
The PARI documentation contains the following warning: The method
|
2122
|
+
used is that of resolvent polynomials and is sensitive to the
|
2123
|
+
current precision. The precision is updated internally but, in very
|
2124
|
+
rare cases, a wrong result may be returned if the initial precision
|
2125
|
+
was not sufficient.
|
2126
|
+
|
2127
|
+
GAP uses the "Transitive Groups Libraries" from the "TransGrp"
|
2128
|
+
GAP package which comes installed with the "gap" Sage package.
|
2129
|
+
|
2130
|
+
MAGMA does not return a provably correct result. Please see the
|
2131
|
+
MAGMA documentation for how to obtain a provably correct result.
|
2132
|
+
|
2133
|
+
EXAMPLES::
|
2134
|
+
|
2135
|
+
sage: # needs sage.groups sage.libs.pari
|
2136
|
+
sage: R.<x> = QQ[]
|
2137
|
+
sage: f = x^4 - 17*x^3 - 2*x + 1
|
2138
|
+
sage: G = f.galois_group(); G
|
2139
|
+
Transitive group number 5 of degree 4
|
2140
|
+
sage: G.gens()
|
2141
|
+
((1,2,3,4), (1,2))
|
2142
|
+
sage: G.order()
|
2143
|
+
24
|
2144
|
+
|
2145
|
+
It is potentially useful to instead obtain the corresponding PARI
|
2146
|
+
group, which is little more than a 4-tuple. See the PARI manual for
|
2147
|
+
the exact details. (Note that the third entry in the tuple is in the
|
2148
|
+
new standard ordering.)
|
2149
|
+
|
2150
|
+
::
|
2151
|
+
|
2152
|
+
sage: # needs sage.groups sage.libs.pari
|
2153
|
+
sage: f = x^4 - 17*x^3 - 2*x + 1
|
2154
|
+
sage: G = f.galois_group(pari_group=True); G
|
2155
|
+
PARI group [24, -1, 5, "S4"] of degree 4
|
2156
|
+
sage: PermutationGroup(G)
|
2157
|
+
Transitive group number 5 of degree 4
|
2158
|
+
|
2159
|
+
You can use KASH or GAP to compute Galois groups as well. The advantage is
|
2160
|
+
that KASH (resp. GAP) can compute Galois groups of fields up to
|
2161
|
+
degree 23 (resp. 15), whereas PARI only goes to degree 11.
|
2162
|
+
(In my not-so-thorough experiments PARI is faster than KASH.)
|
2163
|
+
|
2164
|
+
::
|
2165
|
+
|
2166
|
+
sage: R.<x> = QQ[]
|
2167
|
+
sage: f = x^4 - 17*x^3 - 2*x + 1
|
2168
|
+
sage: f.galois_group(algorithm='kash') # optional - kash
|
2169
|
+
Transitive group number 5 of degree 4
|
2170
|
+
|
2171
|
+
sage: # needs sage.libs.gap
|
2172
|
+
sage: f = x^4 - 17*x^3 - 2*x + 1
|
2173
|
+
sage: f.galois_group(algorithm='gap')
|
2174
|
+
Transitive group number 5 of degree 4
|
2175
|
+
sage: f = x^13 - 17*x^3 - 2*x + 1
|
2176
|
+
sage: f.galois_group(algorithm='gap')
|
2177
|
+
Transitive group number 9 of degree 13
|
2178
|
+
sage: f = x^12 - 2*x^8 - x^7 + 2*x^6 + 4*x^4 - 2*x^3 - x^2 - x + 1
|
2179
|
+
sage: f.galois_group(algorithm='gap')
|
2180
|
+
Transitive group number 183 of degree 12
|
2181
|
+
|
2182
|
+
sage: f.galois_group(algorithm='magma') # optional - magma
|
2183
|
+
Transitive group number 183 of degree 12
|
2184
|
+
|
2185
|
+
TESTS:
|
2186
|
+
|
2187
|
+
We illustrate the behaviour in the case of reducible polynomials::
|
2188
|
+
|
2189
|
+
sage: R.<t> = QQ[]
|
2190
|
+
sage: f = (1 + t)^2
|
2191
|
+
sage: f.galois_group()
|
2192
|
+
Traceback (most recent call last):
|
2193
|
+
...
|
2194
|
+
ValueError: The polynomial must be irreducible
|
2195
|
+
|
2196
|
+
Variable names that are reserved in PARI, such as ``zeta``,
|
2197
|
+
are supported (see :issue:`20631`)::
|
2198
|
+
|
2199
|
+
sage: R.<zeta> = QQ[]
|
2200
|
+
sage: (zeta^2 + zeta + 1).galois_group(pari_group=True) # needs sage.libs.pari
|
2201
|
+
PARI group [2, -1, 1, "S2"] of degree 2
|
2202
|
+
"""
|
2203
|
+
if not self.is_irreducible():
|
2204
|
+
raise ValueError("The polynomial must be irreducible")
|
2205
|
+
|
2206
|
+
if self.degree() > 11 and algorithm == 'pari':
|
2207
|
+
if self.degree() < 16:
|
2208
|
+
algorithm = 'gap'
|
2209
|
+
else:
|
2210
|
+
algorithm = 'kash'
|
2211
|
+
|
2212
|
+
if self.degree() > 21 and algorithm == 'kash':
|
2213
|
+
raise NotImplementedError("Galois group computation is "
|
2214
|
+
"supported for degrees up to 11 using PARI, or up to 21 "
|
2215
|
+
"if KASH is installed. Try "
|
2216
|
+
"algorithm='magma' if you have magma.")
|
2217
|
+
|
2218
|
+
if algorithm == 'pari':
|
2219
|
+
from sage.groups.pari_group import PariGroup
|
2220
|
+
G = self._pari_with_name().Polrev().polgalois()
|
2221
|
+
H = PariGroup(G, self.degree())
|
2222
|
+
if pari_group:
|
2223
|
+
return H
|
2224
|
+
else:
|
2225
|
+
from sage.groups.perm_gps.permgroup import PermutationGroup
|
2226
|
+
return PermutationGroup(H)
|
2227
|
+
|
2228
|
+
elif algorithm == 'kash':
|
2229
|
+
try:
|
2230
|
+
from sage.interfaces.kash import kash
|
2231
|
+
from sage.groups.perm_gps.permgroup_named import TransitiveGroup
|
2232
|
+
kash.eval('X := PolynomialRing(RationalField()).1')
|
2233
|
+
s = self._repr(name='X')
|
2234
|
+
G = kash('Galois(%s)' % s)
|
2235
|
+
d = int(kash.eval('%s.ext1' % G.name()))
|
2236
|
+
n = int(kash.eval('%s.ext2' % G.name()))
|
2237
|
+
return TransitiveGroup(d, n)
|
2238
|
+
except RuntimeError as msg:
|
2239
|
+
raise NotImplementedError(str(msg) + "\nSorry, " +
|
2240
|
+
"computation of Galois groups of fields of degree " +
|
2241
|
+
"bigger than 11 is not yet implemented. Try installing " +
|
2242
|
+
"the optional free (closed source) KASH software, which " +
|
2243
|
+
"supports degrees up to 21, or use algorithm='magma' if " +
|
2244
|
+
"you have magma.")
|
2245
|
+
|
2246
|
+
elif algorithm == 'gap':
|
2247
|
+
if self.degree() > 15:
|
2248
|
+
raise NotImplementedError("Galois group computation is " +
|
2249
|
+
"supported for degrees up to 15 using GAP. Try " +
|
2250
|
+
"algorithm='kash'.")
|
2251
|
+
from sage.libs.gap.libgap import libgap
|
2252
|
+
from sage.groups.perm_gps.permgroup_named import TransitiveGroup
|
2253
|
+
fgap = libgap(self)
|
2254
|
+
return TransitiveGroup(self.degree(), fgap.GaloisType())
|
2255
|
+
|
2256
|
+
elif algorithm == 'magma':
|
2257
|
+
from sage.interfaces.magma import magma
|
2258
|
+
from sage.groups.perm_gps.permgroup_named import TransitiveGroup
|
2259
|
+
X = magma(self).GaloisGroup()
|
2260
|
+
try:
|
2261
|
+
n, d = X.TransitiveGroupIdentification(nvals=2)
|
2262
|
+
d = int(d)
|
2263
|
+
n = int(n)
|
2264
|
+
except RuntimeError as msg:
|
2265
|
+
raise RuntimeError(str(msg) + "\nUnable to lookup " +
|
2266
|
+
"description of Galois group as a transitive " +
|
2267
|
+
"group.\n%s" % X)
|
2268
|
+
return TransitiveGroup(d, n)
|
2269
|
+
|
2270
|
+
else:
|
2271
|
+
raise ValueError("Algorithm %s not supported." % algorithm)
|
2272
|
+
|
2273
|
+
def factor_mod(self, p):
|
2274
|
+
"""
|
2275
|
+
Return the factorization of ``self`` modulo the prime `p`.
|
2276
|
+
|
2277
|
+
Assumes that the degree of this polynomial is at least one, and raises
|
2278
|
+
a :exc:`ValueError` otherwise.
|
2279
|
+
|
2280
|
+
INPUT:
|
2281
|
+
|
2282
|
+
- ``p`` -- prime number
|
2283
|
+
|
2284
|
+
OUTPUT: factorization of this polynomial modulo `p`
|
2285
|
+
|
2286
|
+
EXAMPLES::
|
2287
|
+
|
2288
|
+
sage: # needs sage.libs.pari
|
2289
|
+
sage: R.<x> = QQ[]
|
2290
|
+
sage: (x^5 + 17*x^3 + x + 3).factor_mod(3)
|
2291
|
+
x * (x^2 + 1)^2
|
2292
|
+
sage: (x^5 + 2).factor_mod(5)
|
2293
|
+
(x + 2)^5
|
2294
|
+
|
2295
|
+
Variable names that are reserved in PARI, such as ``zeta``,
|
2296
|
+
are supported (see :issue:`20631`)::
|
2297
|
+
|
2298
|
+
sage: R.<zeta> = QQ[]
|
2299
|
+
sage: (zeta^2 + zeta + 1).factor_mod(7) # needs sage.libs.pari
|
2300
|
+
(zeta + 3) * (zeta + 5)
|
2301
|
+
"""
|
2302
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField
|
2303
|
+
|
2304
|
+
p = Integer(p)
|
2305
|
+
if not p.is_prime():
|
2306
|
+
raise ValueError("p must be prime")
|
2307
|
+
|
2308
|
+
if self.degree() < 1:
|
2309
|
+
raise ValueError("The polynomial must have degree at least 1")
|
2310
|
+
|
2311
|
+
G = self._pari_with_name().factormod(p)
|
2312
|
+
K = FiniteField(p)
|
2313
|
+
R = K[self.parent().variable_name()]
|
2314
|
+
return R(1)._factor_pari_helper(G, unit=R(self).leading_coefficient())
|
2315
|
+
|
2316
|
+
def factor_padic(self, p, prec=10):
|
2317
|
+
r"""
|
2318
|
+
Return the `p`-adic factorization of this polynomial to the given
|
2319
|
+
precision.
|
2320
|
+
|
2321
|
+
INPUT:
|
2322
|
+
|
2323
|
+
- ``p`` -- prime number
|
2324
|
+
|
2325
|
+
- ``prec`` -- integer; the precision
|
2326
|
+
|
2327
|
+
OUTPUT: factorization of ``self`` viewed as a `p`-adic polynomial
|
2328
|
+
|
2329
|
+
EXAMPLES::
|
2330
|
+
|
2331
|
+
sage: # needs sage.rings.padic
|
2332
|
+
sage: R.<x> = QQ[]
|
2333
|
+
sage: f = x^3 - 2
|
2334
|
+
sage: f.factor_padic(2)
|
2335
|
+
(1 + O(2^10))*x^3 + O(2^10)*x^2 + O(2^10)*x
|
2336
|
+
+ 2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + O(2^10)
|
2337
|
+
sage: f.factor_padic(3)
|
2338
|
+
(1 + O(3^10))*x^3 + O(3^10)*x^2 + O(3^10)*x
|
2339
|
+
+ 1 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10)
|
2340
|
+
sage: f.factor_padic(5)
|
2341
|
+
((1 + O(5^10))*x
|
2342
|
+
+ 2 + 4*5 + 2*5^2 + 2*5^3 + 5^4 + 3*5^5 + 4*5^7 + 2*5^8 + 5^9 + O(5^10))
|
2343
|
+
* ((1 + O(5^10))*x^2
|
2344
|
+
+ (3 + 2*5^2 + 2*5^3 + 3*5^4 + 5^5 + 4*5^6 + 2*5^8 + 3*5^9 + O(5^10))*x
|
2345
|
+
+ 4 + 5 + 2*5^2 + 4*5^3 + 4*5^4 + 3*5^5 + 3*5^6 + 4*5^7 + 4*5^9 + O(5^10))
|
2346
|
+
|
2347
|
+
The input polynomial is considered to have "infinite" precision,
|
2348
|
+
therefore the `p`-adic factorization of the polynomial is not
|
2349
|
+
the same as first coercing to `\QQ_p` and then factoring
|
2350
|
+
(see also :issue:`15422`)::
|
2351
|
+
|
2352
|
+
sage: # needs sage.rings.padic
|
2353
|
+
sage: f = x^2 - 3^6
|
2354
|
+
sage: f.factor_padic(3, 5)
|
2355
|
+
((1 + O(3^5))*x + 3^3 + O(3^5)) * ((1 + O(3^5))*x + 2*3^3 + 2*3^4 + O(3^5))
|
2356
|
+
sage: f.change_ring(Qp(3,5)).factor()
|
2357
|
+
Traceback (most recent call last):
|
2358
|
+
...
|
2359
|
+
PrecisionError: p-adic factorization not well-defined since
|
2360
|
+
the discriminant is zero up to the requestion p-adic precision
|
2361
|
+
|
2362
|
+
A more difficult example::
|
2363
|
+
|
2364
|
+
sage: R.<x> = QQ[]
|
2365
|
+
sage: f = 100 * (5*x + 1)^2 * (x + 5)^2
|
2366
|
+
sage: f.factor_padic(5, 10) # needs sage.rings.padic
|
2367
|
+
(4*5^4 + O(5^14)) * ((1 + O(5^9))*x + 5^-1 + O(5^9))^2
|
2368
|
+
* ((1 + O(5^10))*x + 5 + O(5^10))^2
|
2369
|
+
|
2370
|
+
Try some bogus inputs::
|
2371
|
+
|
2372
|
+
sage: # needs sage.rings.padic
|
2373
|
+
sage: f.factor_padic(3, -1)
|
2374
|
+
Traceback (most recent call last):
|
2375
|
+
...
|
2376
|
+
ValueError: prec_cap must be nonnegative
|
2377
|
+
sage: f.factor_padic(6, 10)
|
2378
|
+
Traceback (most recent call last):
|
2379
|
+
...
|
2380
|
+
ValueError: p must be prime
|
2381
|
+
sage: f.factor_padic('hello', 'world')
|
2382
|
+
Traceback (most recent call last):
|
2383
|
+
...
|
2384
|
+
TypeError: unable to convert 'hello' to an integer
|
2385
|
+
"""
|
2386
|
+
from sage.rings.padics.factory import Qp
|
2387
|
+
|
2388
|
+
p = Integer(p)
|
2389
|
+
prec = Integer(prec)
|
2390
|
+
|
2391
|
+
# Parent field for coefficients and polynomial
|
2392
|
+
K = Qp(p, prec, type='capped-rel')
|
2393
|
+
R = K[self.parent().variable_name()]
|
2394
|
+
|
2395
|
+
# Factor the *exact* polynomial using factorpadic()
|
2396
|
+
G = self._pari_with_name().factorpadic(p, prec)
|
2397
|
+
|
2398
|
+
from sage.rings.polynomial.padics.polynomial_padic import _pari_padic_factorization_to_sage
|
2399
|
+
return _pari_padic_factorization_to_sage(G, R, self.leading_coefficient())
|
2400
|
+
|
2401
|
+
def hensel_lift(self, p, e):
|
2402
|
+
r"""
|
2403
|
+
Assuming that this polynomial factors modulo `p` into distinct
|
2404
|
+
monic factors, computes the Hensel lifts of these factors modulo
|
2405
|
+
`p^e`. We assume that ``self`` has integer coefficients.
|
2406
|
+
|
2407
|
+
Return an empty list if this polynomial has degree less than one.
|
2408
|
+
|
2409
|
+
INPUT:
|
2410
|
+
|
2411
|
+
- ``p`` -- prime number; coerceable to :class:`Integer`
|
2412
|
+
- ``e`` -- exponent; coerceable to :class:`Integer`
|
2413
|
+
|
2414
|
+
OUTPUT: Hensel lifts; list of polynomials over `\ZZ / p^e \ZZ`
|
2415
|
+
|
2416
|
+
EXAMPLES::
|
2417
|
+
|
2418
|
+
sage: R.<x> = QQ[]
|
2419
|
+
sage: R((x-1)*(x+1)).hensel_lift(7, 2) # needs sage.libs.pari
|
2420
|
+
[x + 1, x + 48]
|
2421
|
+
|
2422
|
+
If the input polynomial `f` is not monic, we get a factorization of
|
2423
|
+
`f / lc(f)`::
|
2424
|
+
|
2425
|
+
sage: R(2*x^2 - 2).hensel_lift(7, 2) # needs sage.libs.pari
|
2426
|
+
[x + 1, x + 48]
|
2427
|
+
|
2428
|
+
TESTS::
|
2429
|
+
|
2430
|
+
sage: # needs sage.libs.pari
|
2431
|
+
sage: R.<x> = QQ[]
|
2432
|
+
sage: R(0).hensel_lift(7, 2)
|
2433
|
+
[]
|
2434
|
+
sage: R(x).hensel_lift(7, 2)
|
2435
|
+
[x]
|
2436
|
+
sage: R(x - 1).hensel_lift(7, 2)
|
2437
|
+
[x + 48]
|
2438
|
+
|
2439
|
+
Variable names that are reserved in PARI, such as ``I``, are
|
2440
|
+
supported (see :issue:`20631`)::
|
2441
|
+
|
2442
|
+
sage: # needs sage.libs.pari
|
2443
|
+
sage: R.<I> = QQ[]
|
2444
|
+
sage: (I^2 + 1).hensel_lift(5, 3)
|
2445
|
+
[I + 57, I + 68]
|
2446
|
+
sage: (I^2 + 1).hensel_lift(2, 3)
|
2447
|
+
Traceback (most recent call last):
|
2448
|
+
...
|
2449
|
+
ValueError: I^2 + 1 is not square-free modulo 2
|
2450
|
+
"""
|
2451
|
+
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
|
2452
|
+
|
2453
|
+
p = Integer(p)
|
2454
|
+
if not p.is_prime():
|
2455
|
+
raise ValueError("p must be prime")
|
2456
|
+
e = Integer(e)
|
2457
|
+
if e < 1:
|
2458
|
+
raise ValueError("e must be at least 1")
|
2459
|
+
|
2460
|
+
# The relevant PARI method doesn't seem to play well with constant and
|
2461
|
+
# linear polynomials, so we handle these separately.
|
2462
|
+
#
|
2463
|
+
if self.degree() < 1:
|
2464
|
+
return [ ]
|
2465
|
+
elif self.degree() == 1:
|
2466
|
+
R = IntegerModRing(p**e)
|
2467
|
+
S = R[self.parent().variable_name()]
|
2468
|
+
return [S(self)]
|
2469
|
+
|
2470
|
+
f = self._pari_with_name()
|
2471
|
+
F = f.factormod(p)
|
2472
|
+
if any(n > 1 for n in F[1]):
|
2473
|
+
raise ValueError("{} is not square-free modulo {}".format(self, p))
|
2474
|
+
H = f.polhensellift(F[0].liftint(), p, e)
|
2475
|
+
R = IntegerModRing(p**e)
|
2476
|
+
S = R[self.parent().variable_name()]
|
2477
|
+
return [S(m) for m in H]
|
2478
|
+
|
2479
|
+
def discriminant(self):
|
2480
|
+
r"""
|
2481
|
+
Return the discriminant of this polynomial.
|
2482
|
+
|
2483
|
+
The discriminant `R_n` is defined as
|
2484
|
+
|
2485
|
+
.. MATH::
|
2486
|
+
|
2487
|
+
R_n = a_n^{2 n-2} \prod_{1 \le i < j \le n} (r_i - r_j)^2,
|
2488
|
+
|
2489
|
+
where `n` is the degree of this polynomial, `a_n` is the leading
|
2490
|
+
coefficient and the roots over `\QQbar` are `r_1, \ldots, r_n`.
|
2491
|
+
|
2492
|
+
The discriminant of constant polynomials is defined to be 0.
|
2493
|
+
|
2494
|
+
OUTPUT: discriminant, an element of the base ring of the polynomial ring
|
2495
|
+
|
2496
|
+
.. NOTE::
|
2497
|
+
|
2498
|
+
Note the identity `R_n(f) := (-1)^{(n (n-1)/2)} R(f,f') a_n^{(n-k-2)}`,
|
2499
|
+
where `n` is the degree of this polynomial, `a_n` is the leading
|
2500
|
+
coefficient, `f'` is the derivative of `f`, and `k` is the degree
|
2501
|
+
of `f'`. Calls :meth:`resultant`.
|
2502
|
+
|
2503
|
+
ALGORITHM:
|
2504
|
+
|
2505
|
+
Use PARI.
|
2506
|
+
|
2507
|
+
EXAMPLES:
|
2508
|
+
|
2509
|
+
In the case of elliptic curves in special form, the discriminant is
|
2510
|
+
easy to calculate::
|
2511
|
+
|
2512
|
+
sage: R.<t> = QQ[]
|
2513
|
+
sage: f = t^3 + t + 1
|
2514
|
+
sage: d = f.discriminant(); d # needs sage.libs.pari
|
2515
|
+
-31
|
2516
|
+
sage: d.parent() is QQ # needs sage.libs.pari
|
2517
|
+
True
|
2518
|
+
sage: EllipticCurve([1, 1]).discriminant() / 16 # needs sage.schemes
|
2519
|
+
-31
|
2520
|
+
|
2521
|
+
::
|
2522
|
+
|
2523
|
+
sage: R.<t> = QQ[]
|
2524
|
+
sage: f = 2*t^3 + t + 1
|
2525
|
+
sage: d = f.discriminant(); d # needs sage.libs.pari
|
2526
|
+
-116
|
2527
|
+
|
2528
|
+
::
|
2529
|
+
|
2530
|
+
sage: R.<t> = QQ[]
|
2531
|
+
sage: f = t^3 + 3*t - 17
|
2532
|
+
sage: f.discriminant() # needs sage.libs.pari
|
2533
|
+
-7911
|
2534
|
+
|
2535
|
+
TESTS::
|
2536
|
+
|
2537
|
+
sage: # needs sage.libs.pari
|
2538
|
+
sage: R.<t> = QQ[]
|
2539
|
+
sage: R(0).discriminant()
|
2540
|
+
0
|
2541
|
+
sage: R(2/3).discriminant()
|
2542
|
+
0
|
2543
|
+
sage: (t + 1/2).discriminant()
|
2544
|
+
1
|
2545
|
+
|
2546
|
+
Variable names that are reserved in PARI, such as ``I``, are
|
2547
|
+
supported (see :issue:`20631`)::
|
2548
|
+
|
2549
|
+
sage: R.<I> = QQ[]
|
2550
|
+
sage: (I^2 + 1).discriminant() # needs sage.libs.pari
|
2551
|
+
-4
|
2552
|
+
"""
|
2553
|
+
return QQ(self._pari_with_name().poldisc())
|
2554
|
+
|
2555
|
+
# Alias for discriminant
|
2556
|
+
disc = discriminant
|
2557
|
+
|
2558
|
+
def galois_group_davenport_smith_test(self, num_trials=50, assume_irreducible=False):
|
2559
|
+
"""
|
2560
|
+
Use the Davenport-Smith test to attempt to certify that `f` has Galois group `A_n` or `S_n`.
|
2561
|
+
|
2562
|
+
Return 1 if the Galois group is certified as `S_n`, 2 if `A_n`, or 0 if no conclusion is reached.
|
2563
|
+
|
2564
|
+
By default, we first check that `f` is irreducible. For extra efficiency, one can override this
|
2565
|
+
by specifying ``assume_irreducible=True``; this yields undefined results if `f` is not irreducible.
|
2566
|
+
|
2567
|
+
A corresponding function in Magma is ``IsEasySnAn``.
|
2568
|
+
|
2569
|
+
EXAMPLES::
|
2570
|
+
|
2571
|
+
sage: # needs sage.libs.pari
|
2572
|
+
sage: P.<x> = QQ[]
|
2573
|
+
sage: u = x^7 + x + 1
|
2574
|
+
sage: u.galois_group_davenport_smith_test()
|
2575
|
+
1
|
2576
|
+
sage: u = x^7 - x^4 - x^3 + 3*x^2 - 1
|
2577
|
+
sage: u.galois_group_davenport_smith_test()
|
2578
|
+
2
|
2579
|
+
sage: u = x^7 - 2
|
2580
|
+
sage: u.galois_group_davenport_smith_test()
|
2581
|
+
0
|
2582
|
+
"""
|
2583
|
+
from sage.arith.misc import primes_first_n
|
2584
|
+
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
|
2585
|
+
|
2586
|
+
if not assume_irreducible and not self.is_irreducible():
|
2587
|
+
return 0
|
2588
|
+
d = self.degree()
|
2589
|
+
for p in primes_first_n(num_trials):
|
2590
|
+
fp = self.change_ring(IntegerModRing(p))
|
2591
|
+
g = fp.factor()[-1][0]
|
2592
|
+
d1 = g.degree()
|
2593
|
+
# Here we use the fact that a transitive permutation representation with a long prime cycle
|
2594
|
+
# must have image at least as big as A_n.
|
2595
|
+
if (d1 <= 7 and (d,d1) in ((1,1),(2,2),(3,2),(3,3),(4,3),(5,3),(5,4),(6,5),(7,5))) or\
|
2596
|
+
(d1 > d/2 and d1 < d-2 and d1.is_prime()):
|
2597
|
+
return (2 if self.disc().is_square() else 1)
|
2598
|
+
return 0
|