passagemath-flint 10.6.1rc10__cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
- passagemath_flint-10.6.1rc10.dist-info/RECORD +360 -0
- passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
- passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
- passagemath_flint.libs/libflint-3701249d.so.21.0.0 +0 -0
- passagemath_flint.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
- passagemath_flint.libs/libgfortran-8a9a71bc.so.5.0.0 +0 -0
- passagemath_flint.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
- passagemath_flint.libs/libgsl-e3525837.so.28.0.0 +0 -0
- passagemath_flint.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
- passagemath_flint.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
- passagemath_flint.libs/libntl-1004113e.so.44.0.1 +0 -0
- passagemath_flint.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
- sage/all__sagemath_flint.py +29 -0
- sage/combinat/all__sagemath_flint.py +1 -0
- sage/combinat/posets/all__sagemath_flint.py +1 -0
- sage/combinat/posets/hasse_cython_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython_flint.pyx +194 -0
- sage/data_structures/all__sagemath_flint.py +1 -0
- sage/data_structures/bounded_integer_sequences.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/data_structures/bounded_integer_sequences.pxd +62 -0
- sage/data_structures/bounded_integer_sequences.pyx +1418 -0
- sage/graphs/all__sagemath_flint.py +1 -0
- sage/graphs/chrompoly.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/chrompoly.pyx +555 -0
- sage/graphs/matchpoly.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/matchpoly.pyx +412 -0
- sage/libs/all__sagemath_flint.py +17 -0
- sage/libs/arb/__init__.py +1 -0
- sage/libs/arb/acb.pxd +154 -0
- sage/libs/arb/acb_calc.pxd +9 -0
- sage/libs/arb/acb_elliptic.pxd +25 -0
- sage/libs/arb/acb_hypgeom.pxd +74 -0
- sage/libs/arb/acb_mat.pxd +62 -0
- sage/libs/arb/acb_modular.pxd +17 -0
- sage/libs/arb/acb_poly.pxd +216 -0
- sage/libs/arb/arb.pxd +240 -0
- sage/libs/arb/arb_fmpz_poly.pxd +21 -0
- sage/libs/arb/arb_hypgeom.pxd +83 -0
- sage/libs/arb/arb_wrap.h +34 -0
- sage/libs/arb/arf.pxd +131 -0
- sage/libs/arb/arith.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/arb/arith.pyx +87 -0
- sage/libs/arb/bernoulli.pxd +6 -0
- sage/libs/arb/mag.pxd +77 -0
- sage/libs/arb/types.pxd +37 -0
- sage/libs/flint/__init__.py +1 -0
- sage/libs/flint/acb.pxd +270 -0
- sage/libs/flint/acb_calc.pxd +22 -0
- sage/libs/flint/acb_dft.pxd +51 -0
- sage/libs/flint/acb_dirichlet.pxd +112 -0
- sage/libs/flint/acb_elliptic.pxd +42 -0
- sage/libs/flint/acb_hypgeom.pxd +169 -0
- sage/libs/flint/acb_macros.pxd +9 -0
- sage/libs/flint/acb_mat.pxd +136 -0
- sage/libs/flint/acb_mat_macros.pxd +10 -0
- sage/libs/flint/acb_modular.pxd +62 -0
- sage/libs/flint/acb_poly.pxd +251 -0
- sage/libs/flint/acb_poly_macros.pxd +8 -0
- sage/libs/flint/acb_theta.pxd +124 -0
- sage/libs/flint/acf.pxd +32 -0
- sage/libs/flint/aprcl.pxd +84 -0
- sage/libs/flint/arb.pxd +382 -0
- sage/libs/flint/arb_calc.pxd +31 -0
- sage/libs/flint/arb_fmpz_poly.pxd +34 -0
- sage/libs/flint/arb_fpwrap.pxd +215 -0
- sage/libs/flint/arb_hypgeom.pxd +147 -0
- sage/libs/flint/arb_macros.pxd +9 -0
- sage/libs/flint/arb_mat.pxd +140 -0
- sage/libs/flint/arb_mat_macros.pxd +10 -0
- sage/libs/flint/arb_poly.pxd +237 -0
- sage/libs/flint/arf.pxd +167 -0
- sage/libs/flint/arith.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith.pxd +76 -0
- sage/libs/flint/arith.pyx +77 -0
- sage/libs/flint/arith_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/arith_sage.pyx +308 -0
- sage/libs/flint/bernoulli.pxd +28 -0
- sage/libs/flint/bool_mat.pxd +52 -0
- sage/libs/flint/ca.pxd +203 -0
- sage/libs/flint/ca_ext.pxd +34 -0
- sage/libs/flint/ca_field.pxd +32 -0
- sage/libs/flint/ca_mat.pxd +117 -0
- sage/libs/flint/ca_poly.pxd +104 -0
- sage/libs/flint/ca_vec.pxd +46 -0
- sage/libs/flint/calcium.pxd +27 -0
- sage/libs/flint/d_mat.pxd +39 -0
- sage/libs/flint/d_vec.pxd +32 -0
- sage/libs/flint/dirichlet.pxd +57 -0
- sage/libs/flint/dlog.pxd +53 -0
- sage/libs/flint/double_extras.pxd +24 -0
- sage/libs/flint/double_interval.pxd +36 -0
- sage/libs/flint/fexpr.pxd +104 -0
- sage/libs/flint/fexpr_builtin.pxd +20 -0
- sage/libs/flint/fft.pxd +66 -0
- sage/libs/flint/flint.pxd +36 -0
- sage/libs/flint/flint_ntl_wrap.h +35 -0
- sage/libs/flint/flint_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/flint_sage.pyx +163 -0
- sage/libs/flint/flint_wrap.h +190 -0
- sage/libs/flint/fmpq.pxd +137 -0
- sage/libs/flint/fmpq_mat.pxd +105 -0
- sage/libs/flint/fmpq_mat_macros.pxd +10 -0
- sage/libs/flint/fmpq_mpoly.pxd +165 -0
- sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
- sage/libs/flint/fmpq_poly.pxd +241 -0
- sage/libs/flint/fmpq_poly_macros.pxd +9 -0
- sage/libs/flint/fmpq_poly_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpq_poly_sage.pxd +31 -0
- sage/libs/flint/fmpq_poly_sage.pyx +48 -0
- sage/libs/flint/fmpq_vec.pxd +27 -0
- sage/libs/flint/fmpz.pxd +256 -0
- sage/libs/flint/fmpz_extras.pxd +32 -0
- sage/libs/flint/fmpz_factor.pxd +42 -0
- sage/libs/flint/fmpz_factor_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_factor_sage.pxd +4 -0
- sage/libs/flint/fmpz_factor_sage.pyx +29 -0
- sage/libs/flint/fmpz_lll.pxd +49 -0
- sage/libs/flint/fmpz_macros.pxd +8 -0
- sage/libs/flint/fmpz_mat.pxd +184 -0
- sage/libs/flint/fmpz_mat_macros.pxd +10 -0
- sage/libs/flint/fmpz_mod.pxd +46 -0
- sage/libs/flint/fmpz_mod_mat.pxd +71 -0
- sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
- sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fmpz_mod_poly.pxd +249 -0
- sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
- sage/libs/flint/fmpz_mod_vec.pxd +27 -0
- sage/libs/flint/fmpz_mpoly.pxd +224 -0
- sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
- sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
- sage/libs/flint/fmpz_poly.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly.pxd +407 -0
- sage/libs/flint/fmpz_poly.pyx +19 -0
- sage/libs/flint/fmpz_poly_factor.pxd +33 -0
- sage/libs/flint/fmpz_poly_macros.pxd +8 -0
- sage/libs/flint/fmpz_poly_mat.pxd +71 -0
- sage/libs/flint/fmpz_poly_q.pxd +55 -0
- sage/libs/flint/fmpz_poly_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/fmpz_poly_sage.pxd +20 -0
- sage/libs/flint/fmpz_poly_sage.pyx +500 -0
- sage/libs/flint/fmpz_vec.pxd +80 -0
- sage/libs/flint/fmpzi.pxd +52 -0
- sage/libs/flint/fq.pxd +97 -0
- sage/libs/flint/fq_default.pxd +84 -0
- sage/libs/flint/fq_default_mat.pxd +70 -0
- sage/libs/flint/fq_default_poly.pxd +97 -0
- sage/libs/flint/fq_default_poly_factor.pxd +39 -0
- sage/libs/flint/fq_embed.pxd +28 -0
- sage/libs/flint/fq_mat.pxd +83 -0
- sage/libs/flint/fq_nmod.pxd +95 -0
- sage/libs/flint/fq_nmod_embed.pxd +28 -0
- sage/libs/flint/fq_nmod_mat.pxd +83 -0
- sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
- sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/fq_nmod_poly.pxd +202 -0
- sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
- sage/libs/flint/fq_nmod_vec.pxd +33 -0
- sage/libs/flint/fq_poly.pxd +204 -0
- sage/libs/flint/fq_poly_factor.pxd +47 -0
- sage/libs/flint/fq_vec.pxd +33 -0
- sage/libs/flint/fq_zech.pxd +99 -0
- sage/libs/flint/fq_zech_embed.pxd +28 -0
- sage/libs/flint/fq_zech_mat.pxd +78 -0
- sage/libs/flint/fq_zech_poly.pxd +198 -0
- sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
- sage/libs/flint/fq_zech_vec.pxd +33 -0
- sage/libs/flint/gr.pxd +174 -0
- sage/libs/flint/gr_generic.pxd +215 -0
- sage/libs/flint/gr_mat.pxd +161 -0
- sage/libs/flint/gr_mpoly.pxd +68 -0
- sage/libs/flint/gr_poly.pxd +276 -0
- sage/libs/flint/gr_special.pxd +237 -0
- sage/libs/flint/gr_vec.pxd +120 -0
- sage/libs/flint/hypgeom.pxd +24 -0
- sage/libs/flint/long_extras.pxd +23 -0
- sage/libs/flint/mag.pxd +131 -0
- sage/libs/flint/mag_macros.pxd +8 -0
- sage/libs/flint/mpf_mat.pxd +36 -0
- sage/libs/flint/mpf_vec.pxd +34 -0
- sage/libs/flint/mpfr_mat.pxd +27 -0
- sage/libs/flint/mpfr_vec.pxd +25 -0
- sage/libs/flint/mpn_extras.pxd +41 -0
- sage/libs/flint/mpoly.pxd +72 -0
- sage/libs/flint/nf.pxd +19 -0
- sage/libs/flint/nf_elem.pxd +74 -0
- sage/libs/flint/nmod.pxd +35 -0
- sage/libs/flint/nmod_mat.pxd +104 -0
- sage/libs/flint/nmod_mpoly.pxd +144 -0
- sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
- sage/libs/flint/nmod_poly.pxd +339 -0
- sage/libs/flint/nmod_poly_factor.pxd +44 -0
- sage/libs/flint/nmod_poly_linkage.pxi +710 -0
- sage/libs/flint/nmod_poly_mat.pxd +76 -0
- sage/libs/flint/nmod_vec.pxd +40 -0
- sage/libs/flint/ntl_interface.pxd +17 -0
- sage/libs/flint/padic.pxd +93 -0
- sage/libs/flint/padic_mat.pxd +64 -0
- sage/libs/flint/padic_poly.pxd +88 -0
- sage/libs/flint/partitions.pxd +23 -0
- sage/libs/flint/perm.pxd +26 -0
- sage/libs/flint/profiler.pxd +24 -0
- sage/libs/flint/qadic.pxd +77 -0
- sage/libs/flint/qfb.pxd +44 -0
- sage/libs/flint/qqbar.pxd +172 -0
- sage/libs/flint/qsieve.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve.pxd +41 -0
- sage/libs/flint/qsieve.pyx +21 -0
- sage/libs/flint/qsieve_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/qsieve_sage.pyx +67 -0
- sage/libs/flint/thread_pool.pxd +25 -0
- sage/libs/flint/types.pxd +2076 -0
- sage/libs/flint/ulong_extras.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras.pxd +141 -0
- sage/libs/flint/ulong_extras.pyx +21 -0
- sage/libs/flint/ulong_extras_sage.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/libs/flint/ulong_extras_sage.pyx +21 -0
- sage/matrix/all__sagemath_flint.py +1 -0
- sage/matrix/change_ring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/change_ring.pyx +43 -0
- sage/matrix/matrix_complex_ball_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_complex_ball_dense.pxd +14 -0
- sage/matrix/matrix_complex_ball_dense.pyx +973 -0
- sage/matrix/matrix_cyclo_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_cyclo_dense.pxd +16 -0
- sage/matrix/matrix_cyclo_dense.pyx +1761 -0
- sage/matrix/matrix_integer_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_dense.pxd +32 -0
- sage/matrix/matrix_integer_dense.pyx +5801 -0
- sage/matrix/matrix_integer_dense_hnf.py +1294 -0
- sage/matrix/matrix_integer_dense_saturation.py +346 -0
- sage/matrix/matrix_integer_sparse.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_sparse.pxd +9 -0
- sage/matrix/matrix_integer_sparse.pyx +1090 -0
- sage/matrix/matrix_rational_dense.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_dense.pxd +23 -0
- sage/matrix/matrix_rational_dense.pyx +2995 -0
- sage/matrix/matrix_rational_sparse.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_sparse.pxd +11 -0
- sage/matrix/matrix_rational_sparse.pyx +789 -0
- sage/matrix/misc_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/matrix/misc_flint.pyx +109 -0
- sage/modular/all__sagemath_flint.py +1 -0
- sage/modular/modform/all__sagemath_flint.py +1 -0
- sage/modular/modform/eis_series_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/modform/eis_series_cython.pyx +226 -0
- sage/modular/modsym/all__sagemath_flint.py +1 -0
- sage/modular/modsym/apply.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/apply.pxd +6 -0
- sage/modular/modsym/apply.pyx +113 -0
- sage/modular/modsym/heilbronn.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/modsym/heilbronn.pyx +966 -0
- sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
- sage/modular/pollack_stevens/dist.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/modular/pollack_stevens/dist.pxd +38 -0
- sage/modular/pollack_stevens/dist.pyx +1439 -0
- sage/quivers/algebra.py +691 -0
- sage/quivers/algebra_elements.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/quivers/algebra_elements.pxd +97 -0
- sage/quivers/algebra_elements.pxi +1324 -0
- sage/quivers/algebra_elements.pyx +1424 -0
- sage/quivers/all.py +1 -0
- sage/quivers/ar_quiver.py +917 -0
- sage/quivers/homspace.py +640 -0
- sage/quivers/morphism.py +1282 -0
- sage/quivers/path_semigroup.py +1155 -0
- sage/quivers/paths.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/quivers/paths.pxd +13 -0
- sage/quivers/paths.pyx +809 -0
- sage/quivers/representation.py +2975 -0
- sage/rings/all__sagemath_flint.py +37 -0
- sage/rings/cif.py +4 -0
- sage/rings/complex_arb.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_arb.pxd +29 -0
- sage/rings/complex_arb.pyx +5176 -0
- sage/rings/complex_interval.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/complex_interval.pxd +30 -0
- sage/rings/complex_interval.pyx +2475 -0
- sage/rings/complex_interval_field.py +711 -0
- sage/rings/convert/all.py +1 -0
- sage/rings/convert/mpfi.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/convert/mpfi.pxd +6 -0
- sage/rings/convert/mpfi.pyx +576 -0
- sage/rings/factorint_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/factorint_flint.pyx +99 -0
- sage/rings/fraction_field_FpT.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/fraction_field_FpT.pxd +28 -0
- sage/rings/fraction_field_FpT.pyx +2043 -0
- sage/rings/imaginary_unit.py +5 -0
- sage/rings/monomials.py +73 -0
- sage/rings/number_field/S_unit_solver.py +2870 -0
- sage/rings/number_field/all__sagemath_flint.py +7 -0
- sage/rings/number_field/bdd_height.py +664 -0
- sage/rings/number_field/class_group.py +762 -0
- sage/rings/number_field/galois_group.py +1307 -0
- sage/rings/number_field/homset.py +612 -0
- sage/rings/number_field/maps.py +687 -0
- sage/rings/number_field/morphism.py +272 -0
- sage/rings/number_field/number_field.py +12820 -0
- sage/rings/number_field/number_field_element.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element.pxd +59 -0
- sage/rings/number_field/number_field_element.pyx +5735 -0
- sage/rings/number_field/number_field_element_quadratic.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
- sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
- sage/rings/number_field/number_field_ideal_rel.py +925 -0
- sage/rings/number_field/number_field_morphisms.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/number_field/number_field_morphisms.pyx +781 -0
- sage/rings/number_field/number_field_rel.py +2734 -0
- sage/rings/number_field/order.py +2981 -0
- sage/rings/number_field/order_ideal.py +804 -0
- sage/rings/number_field/selmer_group.py +715 -0
- sage/rings/number_field/small_primes_of_degree_one.py +242 -0
- sage/rings/number_field/splitting_field.py +606 -0
- sage/rings/number_field/structure.py +380 -0
- sage/rings/number_field/unit_group.py +721 -0
- sage/rings/padics/all__sagemath_flint.py +3 -0
- sage/rings/polynomial/all__sagemath_flint.py +1 -0
- sage/rings/polynomial/complex_roots.py +312 -0
- sage/rings/polynomial/evaluation_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/evaluation_flint.pxd +7 -0
- sage/rings/polynomial/evaluation_flint.pyx +68 -0
- sage/rings/polynomial/hilbert.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/hilbert.pyx +602 -0
- sage/rings/polynomial/polynomial_complex_arb.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
- sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
- sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
- sage/rings/polynomial/polynomial_number_field.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_number_field.pyx +345 -0
- sage/rings/polynomial/polynomial_rational_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
- sage/rings/polynomial/polynomial_zmod_flint.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
- sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
- sage/rings/polynomial/real_roots.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/real_roots.pxd +81 -0
- sage/rings/polynomial/real_roots.pyx +4704 -0
- sage/rings/polynomial/refine_root.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/refine_root.pyx +142 -0
- sage/rings/polynomial/weil/all.py +4 -0
- sage/rings/polynomial/weil/power_sums.h +46 -0
- sage/rings/polynomial/weil/weil_polynomials.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
- sage/rings/qqbar.py +9025 -0
- sage/rings/real_arb.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/real_arb.pxd +21 -0
- sage/rings/real_arb.pyx +4065 -0
- sage/rings/real_interval_absolute.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/real_interval_absolute.pyx +1073 -0
- sage/rings/real_mpfi.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/rings/real_mpfi.pyx +5428 -0
- sage/schemes/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
- sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,2043 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-flint
|
2
|
+
# distutils: libraries = gmp NTL_LIBRARIES
|
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
|
+
"Univariate rational functions over prime fields"
|
9
|
+
|
10
|
+
from cysignals.signals cimport sig_on, sig_off
|
11
|
+
|
12
|
+
from sage.rings.finite_rings.stdint cimport INTEGER_MOD_INT32_LIMIT
|
13
|
+
|
14
|
+
from sage.libs.gmp.mpz cimport *
|
15
|
+
from sage.libs.flint.nmod_poly cimport *
|
16
|
+
from sage.libs.flint.ulong_extras cimport n_jacobi
|
17
|
+
from sage.structure.element cimport Element, FieldElement
|
18
|
+
from sage.rings.integer_ring import ZZ
|
19
|
+
from sage.rings.fraction_field import FractionField_1poly_field
|
20
|
+
from sage.rings.finite_rings.integer_mod cimport IntegerMod_int
|
21
|
+
from sage.rings.integer cimport Integer
|
22
|
+
from sage.rings.polynomial.polynomial_zmod_flint cimport Polynomial_zmod_flint, get_cparent
|
23
|
+
|
24
|
+
from sage.structure.richcmp cimport rich_to_bool
|
25
|
+
from sage.rings.finite_rings.integer_mod cimport mod_inverse_int
|
26
|
+
|
27
|
+
|
28
|
+
class FpT(FractionField_1poly_field):
|
29
|
+
r"""
|
30
|
+
This class represents the fraction field `\GF{p}(T)` for `2 < p < \sqrt{2^31-1}`.
|
31
|
+
|
32
|
+
EXAMPLES::
|
33
|
+
|
34
|
+
sage: R.<T> = GF(71)[]
|
35
|
+
sage: K = FractionField(R); K
|
36
|
+
Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 71
|
37
|
+
sage: 1-1/T
|
38
|
+
(T + 70)/T
|
39
|
+
sage: parent(1-1/T) is K
|
40
|
+
True
|
41
|
+
"""
|
42
|
+
INTEGER_LIMIT = INTEGER_MOD_INT32_LIMIT
|
43
|
+
|
44
|
+
def __init__(self, R, names=None): # we include names so that one can use the syntax K.<t> = FpT(GF(5)['t']). It's actually ignored
|
45
|
+
"""
|
46
|
+
INPUT:
|
47
|
+
|
48
|
+
- ``R`` -- a dense polynomial ring over a finite field of prime order
|
49
|
+
`p` with `2 < p < 2^{16}`
|
50
|
+
|
51
|
+
EXAMPLES::
|
52
|
+
|
53
|
+
sage: R.<x> = GF(31)[]
|
54
|
+
sage: K = R.fraction_field(); K
|
55
|
+
Fraction Field of Univariate Polynomial Ring in x over Finite Field of size 31
|
56
|
+
|
57
|
+
TESTS::
|
58
|
+
|
59
|
+
sage: from sage.rings.fraction_field_FpT import FpT
|
60
|
+
sage: FpT(PolynomialRing(GF(37), ['x'], sparse=True))
|
61
|
+
Traceback (most recent call last):
|
62
|
+
...
|
63
|
+
TypeError: unsupported polynomial ring
|
64
|
+
"""
|
65
|
+
cdef long p = R.base_ring().characteristic()
|
66
|
+
assert 2 < p < FpT.INTEGER_LIMIT
|
67
|
+
if not issubclass(R.element_class, Polynomial_zmod_flint):
|
68
|
+
raise TypeError("unsupported polynomial ring")
|
69
|
+
self.p = p
|
70
|
+
self.poly_ring = R
|
71
|
+
FractionField_1poly_field.__init__(self, R, element_class=FpTElement)
|
72
|
+
self._populate_coercion_lists_(coerce_list=[Polyring_FpT_coerce(self), Fp_FpT_coerce(self), ZZ_FpT_coerce(self)])
|
73
|
+
|
74
|
+
def __iter__(self):
|
75
|
+
"""
|
76
|
+
Return an iterator over this fraction field.
|
77
|
+
|
78
|
+
EXAMPLES::
|
79
|
+
|
80
|
+
sage: R.<t> = GF(3)[]; K = R.fraction_field()
|
81
|
+
sage: iter(K)
|
82
|
+
<sage.rings.fraction_field_FpT.FpT_iter object at ...>
|
83
|
+
"""
|
84
|
+
return self.iter()
|
85
|
+
|
86
|
+
def iter(self, bound=None, start=None):
|
87
|
+
"""
|
88
|
+
EXAMPLES::
|
89
|
+
|
90
|
+
sage: from sage.rings.fraction_field_FpT import *
|
91
|
+
sage: R.<t> = FpT(GF(5)['t'])
|
92
|
+
sage: list(R.iter(2))[350:355]
|
93
|
+
[(t^2 + t + 1)/(t + 2),
|
94
|
+
(t^2 + t + 2)/(t + 2),
|
95
|
+
(t^2 + t + 4)/(t + 2),
|
96
|
+
(t^2 + 2*t + 1)/(t + 2),
|
97
|
+
(t^2 + 2*t + 2)/(t + 2)]
|
98
|
+
"""
|
99
|
+
return FpT_iter(self, bound, start)
|
100
|
+
|
101
|
+
|
102
|
+
cdef class FpTElement(FieldElement):
|
103
|
+
"""
|
104
|
+
An element of an :class:`FpT` fraction field.
|
105
|
+
|
106
|
+
TESTS::
|
107
|
+
|
108
|
+
sage: R.<t> = GF(5)[]
|
109
|
+
sage: K = R.fraction_field()
|
110
|
+
sage: A.<x> = K[]
|
111
|
+
sage: x.divides(x) # Testing issue #27064
|
112
|
+
True
|
113
|
+
"""
|
114
|
+
|
115
|
+
def __init__(self, parent, numer, denom=1, coerce=True, reduce=True):
|
116
|
+
"""
|
117
|
+
INPUT:
|
118
|
+
|
119
|
+
- ``parent`` -- the Fraction field containing this element
|
120
|
+
- ``numer`` -- something that can be converted into the polynomial
|
121
|
+
ring, giving the numerator
|
122
|
+
- ``denom`` -- something that can be converted into the polynomial
|
123
|
+
ring, giving the numerator (default: 1)
|
124
|
+
|
125
|
+
EXAMPLES::
|
126
|
+
|
127
|
+
sage: from sage.rings.fraction_field_FpT import *
|
128
|
+
sage: R.<t> = FpT(GF(5)['t'])
|
129
|
+
sage: R(7)
|
130
|
+
2
|
131
|
+
"""
|
132
|
+
super().__init__(parent)
|
133
|
+
if coerce:
|
134
|
+
numer = parent.poly_ring(numer)
|
135
|
+
denom = parent.poly_ring(denom)
|
136
|
+
self.p = parent.p
|
137
|
+
nmod_poly_init(self._numer, self.p)
|
138
|
+
nmod_poly_init(self._denom, self.p)
|
139
|
+
self.initialized = True
|
140
|
+
cdef long n
|
141
|
+
for n, a in enumerate(numer):
|
142
|
+
nmod_poly_set_coeff_ui(self._numer, n, a)
|
143
|
+
for n, a in enumerate(denom):
|
144
|
+
nmod_poly_set_coeff_ui(self._denom, n, a)
|
145
|
+
if reduce:
|
146
|
+
normalize(self._numer, self._denom, self.p)
|
147
|
+
|
148
|
+
def __dealloc__(self):
|
149
|
+
"""
|
150
|
+
Deallocation.
|
151
|
+
|
152
|
+
EXAMPLES::
|
153
|
+
|
154
|
+
sage: K = GF(11)['t'].fraction_field()
|
155
|
+
sage: t = K.gen()
|
156
|
+
sage: del t # indirect doctest
|
157
|
+
"""
|
158
|
+
if self.initialized:
|
159
|
+
nmod_poly_clear(self._numer)
|
160
|
+
nmod_poly_clear(self._denom)
|
161
|
+
|
162
|
+
def __reduce__(self):
|
163
|
+
"""
|
164
|
+
For pickling.
|
165
|
+
|
166
|
+
TESTS::
|
167
|
+
|
168
|
+
sage: K = GF(11)['t'].fraction_field()
|
169
|
+
sage: loads(dumps(K.gen()))
|
170
|
+
t
|
171
|
+
sage: loads(dumps(1/K.gen()))
|
172
|
+
1/t
|
173
|
+
"""
|
174
|
+
return (unpickle_FpT_element,
|
175
|
+
(self._parent, self.numer(), self.denom()))
|
176
|
+
|
177
|
+
cdef FpTElement _new_c(self):
|
178
|
+
"""
|
179
|
+
Create a new FpTElement in the same field, leaving the value to be
|
180
|
+
initialized.
|
181
|
+
"""
|
182
|
+
cdef FpTElement x = <FpTElement>FpTElement.__new__(FpTElement)
|
183
|
+
x._parent = self._parent
|
184
|
+
x.p = self.p
|
185
|
+
nmod_poly_init_preinv(x._numer, x.p, self._numer.mod.ninv)
|
186
|
+
nmod_poly_init_preinv(x._denom, x.p, self._numer.mod.ninv)
|
187
|
+
x.initialized = True
|
188
|
+
return x
|
189
|
+
|
190
|
+
cdef FpTElement _copy_c(self):
|
191
|
+
"""
|
192
|
+
Create a new FpTElement in the same field, with the same value as
|
193
|
+
``self``.
|
194
|
+
"""
|
195
|
+
cdef FpTElement x = <FpTElement>FpTElement.__new__(FpTElement)
|
196
|
+
x._parent = self._parent
|
197
|
+
x.p = self.p
|
198
|
+
nmod_poly_init2_preinv(x._numer, x.p, self._numer.mod.ninv, self._numer.length)
|
199
|
+
nmod_poly_init2_preinv(x._denom, x.p, self._denom.mod.ninv, self._denom.length)
|
200
|
+
nmod_poly_set(x._numer, self._numer)
|
201
|
+
nmod_poly_set(x._denom, self._denom)
|
202
|
+
x.initialized = True
|
203
|
+
return x
|
204
|
+
|
205
|
+
def numer(self):
|
206
|
+
"""
|
207
|
+
Return the numerator of this element, as an element of the polynomial ring.
|
208
|
+
|
209
|
+
EXAMPLES::
|
210
|
+
|
211
|
+
sage: K = GF(11)['t'].fraction_field()
|
212
|
+
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
|
213
|
+
sage: a.numer()
|
214
|
+
t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1
|
215
|
+
"""
|
216
|
+
return self.numerator()
|
217
|
+
|
218
|
+
cpdef numerator(self):
|
219
|
+
"""
|
220
|
+
Return the numerator of this element, as an element of the polynomial ring.
|
221
|
+
|
222
|
+
EXAMPLES::
|
223
|
+
|
224
|
+
sage: K = GF(11)['t'].fraction_field()
|
225
|
+
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
|
226
|
+
sage: a.numerator()
|
227
|
+
t^6 + 3*t^4 + 10*t^3 + 3*t^2 + 1
|
228
|
+
"""
|
229
|
+
cdef Polynomial_zmod_flint res = <Polynomial_zmod_flint>Polynomial_zmod_flint.__new__(Polynomial_zmod_flint)
|
230
|
+
nmod_poly_init2_preinv(&res.x, self.p, self._numer.mod.ninv, self._numer.length)
|
231
|
+
nmod_poly_set(&res.x, self._numer)
|
232
|
+
res._parent = self._parent.poly_ring
|
233
|
+
res._cparent = get_cparent(self._parent.poly_ring)
|
234
|
+
return res
|
235
|
+
|
236
|
+
def denom(self):
|
237
|
+
"""
|
238
|
+
Return the denominator of this element, as an element of the polynomial ring.
|
239
|
+
|
240
|
+
EXAMPLES::
|
241
|
+
|
242
|
+
sage: K = GF(11)['t'].fraction_field()
|
243
|
+
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
|
244
|
+
sage: a.denom()
|
245
|
+
t^3
|
246
|
+
"""
|
247
|
+
return self.denominator()
|
248
|
+
|
249
|
+
cpdef denominator(self):
|
250
|
+
"""
|
251
|
+
Return the denominator of this element, as an element of the polynomial ring.
|
252
|
+
|
253
|
+
EXAMPLES::
|
254
|
+
|
255
|
+
sage: K = GF(11)['t'].fraction_field()
|
256
|
+
sage: t = K.gen(0); a = (t + 1/t)^3 - 1
|
257
|
+
sage: a.denominator()
|
258
|
+
t^3
|
259
|
+
"""
|
260
|
+
cdef Polynomial_zmod_flint res = <Polynomial_zmod_flint>Polynomial_zmod_flint.__new__(Polynomial_zmod_flint)
|
261
|
+
nmod_poly_init2_preinv(&res.x, self.p, self._denom.mod.ninv, self._denom.length)
|
262
|
+
nmod_poly_set(&res.x, self._denom)
|
263
|
+
res._parent = self._parent.poly_ring
|
264
|
+
res._cparent = get_cparent(self._parent.poly_ring)
|
265
|
+
return res
|
266
|
+
|
267
|
+
def __call__(self, *args, **kwds):
|
268
|
+
"""
|
269
|
+
EXAMPLES::
|
270
|
+
|
271
|
+
sage: K = Frac(GF(5)['t'])
|
272
|
+
sage: t = K.gen()
|
273
|
+
sage: t(3)
|
274
|
+
3
|
275
|
+
sage: f = t^2/(1-t)
|
276
|
+
sage: f(2)
|
277
|
+
1
|
278
|
+
sage: f(t)
|
279
|
+
4*t^2/(t + 4)
|
280
|
+
sage: f(t^3)
|
281
|
+
4*t^6/(t^3 + 4)
|
282
|
+
sage: f((t+1)/t^3)
|
283
|
+
(t^2 + 2*t + 1)/(t^6 + 4*t^4 + 4*t^3)
|
284
|
+
"""
|
285
|
+
return self.numer()(*args, **kwds) / self.denom()(*args, **kwds)
|
286
|
+
|
287
|
+
def subs(self, in_dict=None, *args, **kwds):
|
288
|
+
"""
|
289
|
+
EXAMPLES::
|
290
|
+
|
291
|
+
sage: K = Frac(GF(11)['t'])
|
292
|
+
sage: t = K.gen()
|
293
|
+
sage: f = (t+1)/(t-1)
|
294
|
+
sage: f.subs(t=2)
|
295
|
+
3
|
296
|
+
sage: f.subs(X=2)
|
297
|
+
(t + 1)/(t + 10)
|
298
|
+
"""
|
299
|
+
return self.numer().subs(in_dict, *args, **kwds) / self.denom().subs(in_dict, *args, **kwds)
|
300
|
+
|
301
|
+
def valuation(self, v):
|
302
|
+
"""
|
303
|
+
Return the valuation of ``self`` at `v`.
|
304
|
+
|
305
|
+
EXAMPLES::
|
306
|
+
|
307
|
+
sage: R.<t> = GF(5)[]
|
308
|
+
sage: f = (t+1)^2 * (t^2+t+1) / (t-1)^3
|
309
|
+
sage: f.valuation(t+1)
|
310
|
+
2
|
311
|
+
sage: f.valuation(t-1)
|
312
|
+
-3
|
313
|
+
sage: f.valuation(t)
|
314
|
+
0
|
315
|
+
"""
|
316
|
+
return self.numer().valuation(v) - self.denom().valuation(v)
|
317
|
+
|
318
|
+
def factor(self):
|
319
|
+
"""
|
320
|
+
EXAMPLES::
|
321
|
+
|
322
|
+
sage: K = Frac(GF(5)['t'])
|
323
|
+
sage: t = K.gen()
|
324
|
+
sage: f = 2 * (t+1) * (t^2+t+1)^2 / (t-1)
|
325
|
+
sage: factor(f)
|
326
|
+
(2) * (t + 4)^-1 * (t + 1) * (t^2 + t + 1)^2
|
327
|
+
"""
|
328
|
+
return self.numer().factor() / self.denom().factor()
|
329
|
+
|
330
|
+
def _repr_(self):
|
331
|
+
"""
|
332
|
+
Return a string representation of this element.
|
333
|
+
|
334
|
+
EXAMPLES::
|
335
|
+
|
336
|
+
sage: from sage.rings.fraction_field_FpT import *
|
337
|
+
sage: R.<t> = FpT(GF(17)['t'])
|
338
|
+
sage: -t # indirect doctest
|
339
|
+
16*t
|
340
|
+
sage: 1/t
|
341
|
+
1/t
|
342
|
+
sage: 1/(t+1)
|
343
|
+
1/(t + 1)
|
344
|
+
sage: 1-t/t
|
345
|
+
0
|
346
|
+
sage: (1-t)/t
|
347
|
+
(16*t + 1)/t
|
348
|
+
"""
|
349
|
+
if nmod_poly_degree(self._denom) == 0 and nmod_poly_get_coeff_ui(self._denom, 0) == 1:
|
350
|
+
return repr(self.numer())
|
351
|
+
else:
|
352
|
+
numer_s = repr(self.numer())
|
353
|
+
denom_s = repr(self.denom())
|
354
|
+
if '-' in numer_s or '+' in numer_s:
|
355
|
+
numer_s = "(%s)" % numer_s
|
356
|
+
if '-' in denom_s or '+' in denom_s:
|
357
|
+
denom_s = "(%s)" % denom_s
|
358
|
+
return "%s/%s" % (numer_s, denom_s)
|
359
|
+
|
360
|
+
def _latex_(self):
|
361
|
+
r"""
|
362
|
+
Return a latex representation of this element.
|
363
|
+
|
364
|
+
EXAMPLES::
|
365
|
+
|
366
|
+
sage: K = GF(7)['t'].fraction_field(); t = K.gen(0)
|
367
|
+
sage: latex(t^2 + 1) # indirect doctest
|
368
|
+
t^{2} + 1
|
369
|
+
sage: latex((t + 1)/(t-1))
|
370
|
+
\frac{t + 1}{t + 6}
|
371
|
+
"""
|
372
|
+
if nmod_poly_degree(self._denom) == 0 and nmod_poly_get_coeff_ui(self._denom, 0) == 1:
|
373
|
+
return self.numer()._latex_()
|
374
|
+
else:
|
375
|
+
return "\\frac{%s}{%s}" % (self.numer()._latex_(), self.denom()._latex_())
|
376
|
+
|
377
|
+
cpdef _richcmp_(self, other, int op):
|
378
|
+
"""
|
379
|
+
Compare this with another element.
|
380
|
+
|
381
|
+
The ordering is arbitrary, but it is an ordering, and it is
|
382
|
+
consistent between runs. It has nothing to do with the
|
383
|
+
algebra structure.
|
384
|
+
|
385
|
+
TESTS::
|
386
|
+
|
387
|
+
sage: from sage.rings.fraction_field_FpT import *
|
388
|
+
sage: R.<t> = FpT(GF(7)['t'])
|
389
|
+
sage: t == t
|
390
|
+
True
|
391
|
+
sage: t == -t
|
392
|
+
False
|
393
|
+
sage: -t == 6*t
|
394
|
+
True
|
395
|
+
sage: 1/t == 1/t
|
396
|
+
True
|
397
|
+
sage: 1/t == 1/(t+1)
|
398
|
+
False
|
399
|
+
sage: 2*t/t == 2
|
400
|
+
True
|
401
|
+
sage: 2*t/2 == t
|
402
|
+
True
|
403
|
+
|
404
|
+
sage: a = (t^3 + 3*t)/(5*t-2); b = (t^2-2)/(t-1)
|
405
|
+
sage: b < a
|
406
|
+
True
|
407
|
+
sage: a < b
|
408
|
+
False
|
409
|
+
sage: 1/a < b
|
410
|
+
True
|
411
|
+
sage: b < 1/a
|
412
|
+
False
|
413
|
+
|
414
|
+
::
|
415
|
+
|
416
|
+
sage: K = Frac(GF(5)['t']); t = K.gen()
|
417
|
+
sage: t == 1
|
418
|
+
False
|
419
|
+
sage: t + 1 < t^2
|
420
|
+
True
|
421
|
+
"""
|
422
|
+
# They are normalized.
|
423
|
+
cdef int j = sage_cmp_nmod_poly_t(self._numer, (<FpTElement>other)._numer)
|
424
|
+
if j:
|
425
|
+
return rich_to_bool(op, j)
|
426
|
+
j = sage_cmp_nmod_poly_t(self._denom, (<FpTElement>other)._denom)
|
427
|
+
return rich_to_bool(op, j)
|
428
|
+
|
429
|
+
def __hash__(self):
|
430
|
+
"""
|
431
|
+
Return a hash value for this element.
|
432
|
+
|
433
|
+
TESTS::
|
434
|
+
|
435
|
+
sage: from sage.rings.fraction_field_FpT import *
|
436
|
+
sage: K.<t> = FpT(GF(7)['t'])
|
437
|
+
sage: hash(K(0))
|
438
|
+
0
|
439
|
+
sage: hash(K(5))
|
440
|
+
5
|
441
|
+
sage: set([1, t, 1/t, t, t, 1/t, 1+1/t, t/t])
|
442
|
+
{1, 1/t, t, (t + 1)/t}
|
443
|
+
sage: a = (t+1)/(t^2-1); hash(a) == hash((a.numer(),a.denom()))
|
444
|
+
True
|
445
|
+
"""
|
446
|
+
if self.denom() == 1:
|
447
|
+
return hash(self.numer())
|
448
|
+
return hash((self.numer(), self.denom()))
|
449
|
+
|
450
|
+
def __neg__(self):
|
451
|
+
"""
|
452
|
+
Negate this element.
|
453
|
+
|
454
|
+
EXAMPLES::
|
455
|
+
|
456
|
+
sage: K = GF(5)['t'].fraction_field(); t = K.gen(0)
|
457
|
+
sage: a = (t^2 + 2)/(t-1)
|
458
|
+
sage: -a # indirect doctest
|
459
|
+
(4*t^2 + 3)/(t + 4)
|
460
|
+
"""
|
461
|
+
cdef FpTElement x = self._copy_c()
|
462
|
+
nmod_poly_neg(x._numer, x._numer)
|
463
|
+
return x
|
464
|
+
|
465
|
+
def __invert__(self):
|
466
|
+
"""
|
467
|
+
Return the multiplicative inverse of this element.
|
468
|
+
|
469
|
+
EXAMPLES::
|
470
|
+
|
471
|
+
sage: K = GF(5)['t'].fraction_field(); t = K.gen(0)
|
472
|
+
sage: a = (t^2 + 2)/(t-1)
|
473
|
+
sage: ~a # indirect doctest
|
474
|
+
(t + 4)/(t^2 + 2)
|
475
|
+
"""
|
476
|
+
if nmod_poly_degree(self._numer) == -1:
|
477
|
+
raise ZeroDivisionError
|
478
|
+
cdef FpTElement x = self._copy_c()
|
479
|
+
nmod_poly_swap(x._numer, x._denom)
|
480
|
+
return x
|
481
|
+
|
482
|
+
cpdef _add_(self, _other):
|
483
|
+
"""
|
484
|
+
Return the sum of this fraction field element and another.
|
485
|
+
|
486
|
+
EXAMPLES::
|
487
|
+
|
488
|
+
sage: from sage.rings.fraction_field_FpT import *
|
489
|
+
sage: R.<t> = FpT(GF(7)['t'])
|
490
|
+
sage: t + t # indirect doctest
|
491
|
+
2*t
|
492
|
+
sage: (t + 3) + (t + 10)
|
493
|
+
2*t + 6
|
494
|
+
sage: sum([t] * 7)
|
495
|
+
0
|
496
|
+
sage: 1/t + t
|
497
|
+
(t^2 + 1)/t
|
498
|
+
sage: 1/t + 1/t^2
|
499
|
+
(t + 1)/t^2
|
500
|
+
"""
|
501
|
+
cdef FpTElement other = <FpTElement>_other
|
502
|
+
cdef FpTElement x = self._new_c()
|
503
|
+
nmod_poly_mul(x._numer, self._numer, other._denom)
|
504
|
+
nmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp
|
505
|
+
nmod_poly_add(x._numer, x._numer, x._denom)
|
506
|
+
nmod_poly_mul(x._denom, self._denom, other._denom)
|
507
|
+
normalize(x._numer, x._denom, self.p)
|
508
|
+
return x
|
509
|
+
|
510
|
+
cpdef _sub_(self, _other):
|
511
|
+
"""
|
512
|
+
Return the difference of this fraction field element and another.
|
513
|
+
|
514
|
+
EXAMPLES::
|
515
|
+
|
516
|
+
sage: from sage.rings.fraction_field_FpT import *
|
517
|
+
sage: R.<t> = FpT(GF(7)['t'])
|
518
|
+
sage: t - t # indirect doctest
|
519
|
+
0
|
520
|
+
sage: (t + 3) - (t + 11)
|
521
|
+
6
|
522
|
+
"""
|
523
|
+
cdef FpTElement other = <FpTElement>_other
|
524
|
+
cdef FpTElement x = self._new_c()
|
525
|
+
nmod_poly_mul(x._numer, self._numer, other._denom)
|
526
|
+
nmod_poly_mul(x._denom, self._denom, other._numer) # use x._denom as a temp
|
527
|
+
nmod_poly_sub(x._numer, x._numer, x._denom)
|
528
|
+
nmod_poly_mul(x._denom, self._denom, other._denom)
|
529
|
+
normalize(x._numer, x._denom, self.p)
|
530
|
+
return x
|
531
|
+
|
532
|
+
cpdef _mul_(self, _other):
|
533
|
+
"""
|
534
|
+
Return the product of this fraction field element and another.
|
535
|
+
|
536
|
+
EXAMPLES::
|
537
|
+
|
538
|
+
sage: from sage.rings.fraction_field_FpT import *
|
539
|
+
sage: R.<t> = FpT(GF(7)['t'])
|
540
|
+
sage: t * t # indirect doctest
|
541
|
+
t^2
|
542
|
+
sage: (t + 3) * (t + 10)
|
543
|
+
t^2 + 6*t + 2
|
544
|
+
"""
|
545
|
+
cdef FpTElement other = <FpTElement>_other
|
546
|
+
cdef FpTElement x = self._new_c()
|
547
|
+
nmod_poly_mul(x._numer, self._numer, other._numer)
|
548
|
+
nmod_poly_mul(x._denom, self._denom, other._denom)
|
549
|
+
normalize(x._numer, x._denom, self.p)
|
550
|
+
return x
|
551
|
+
|
552
|
+
cpdef _div_(self, _other):
|
553
|
+
"""
|
554
|
+
Return the quotient of this fraction field element and another.
|
555
|
+
|
556
|
+
EXAMPLES::
|
557
|
+
|
558
|
+
sage: from sage.rings.fraction_field_FpT import *
|
559
|
+
sage: R.<t> = FpT(GF(5)['t'])
|
560
|
+
sage: t / t # indirect doctest
|
561
|
+
1
|
562
|
+
sage: (t + 3) / (t + 11)
|
563
|
+
(t + 3)/(t + 1)
|
564
|
+
sage: (t^2 + 2*t + 1) / (t + 1)
|
565
|
+
t + 1
|
566
|
+
"""
|
567
|
+
cdef FpTElement other = <FpTElement>_other
|
568
|
+
if nmod_poly_degree(other._numer) == -1:
|
569
|
+
raise ZeroDivisionError
|
570
|
+
cdef FpTElement x = self._new_c()
|
571
|
+
nmod_poly_mul(x._numer, self._numer, other._denom)
|
572
|
+
nmod_poly_mul(x._denom, self._denom, other._numer)
|
573
|
+
normalize(x._numer, x._denom, self.p)
|
574
|
+
return x
|
575
|
+
|
576
|
+
def _im_gens_(self, codomain, im_gens, base_map=None):
|
577
|
+
r"""
|
578
|
+
Return the image of this element in ``codomain`` under the
|
579
|
+
map that sends the image of the generator of the parent to
|
580
|
+
the element in ``im_gens``.
|
581
|
+
|
582
|
+
INPUT:
|
583
|
+
|
584
|
+
- ``codomain`` -- a ring; where the image is computed
|
585
|
+
|
586
|
+
- ``im_gens`` -- a list containing the image of the
|
587
|
+
generator of the parent as unique element
|
588
|
+
|
589
|
+
- ``base_map`` -- a morphism (default: ``None``);
|
590
|
+
the action on the underlying base ring
|
591
|
+
|
592
|
+
EXAMPLES::
|
593
|
+
|
594
|
+
sage: A.<T> = GF(5)[]
|
595
|
+
sage: K.<T> = Frac(A)
|
596
|
+
sage: f = K.hom([T^2])
|
597
|
+
sage: f(1/T)
|
598
|
+
1/T^2
|
599
|
+
"""
|
600
|
+
nden = self.denom()._im_gens_(codomain, im_gens, base_map=base_map)
|
601
|
+
invden = nden.inverse_of_unit()
|
602
|
+
nnum = self.numer()._im_gens_(codomain, im_gens, base_map=base_map)
|
603
|
+
return nnum * invden
|
604
|
+
|
605
|
+
cpdef FpTElement next(self):
|
606
|
+
"""
|
607
|
+
Iterate through all polynomials, returning the "next" polynomial after this one.
|
608
|
+
|
609
|
+
The strategy is as follows:
|
610
|
+
|
611
|
+
- We always leave the denominator monic.
|
612
|
+
|
613
|
+
- We progress through the elements with both numerator and denominator monic, and with the denominator less than the numerator.
|
614
|
+
For each such, we output all the scalar multiples of it, then all of the scalar multiples of its inverse.
|
615
|
+
|
616
|
+
- So if the leading coefficient of the numerator is less than `p-1`, we scale the numerator to increase it by 1.
|
617
|
+
|
618
|
+
- Otherwise, we consider the multiple with numerator and denominator monic.
|
619
|
+
|
620
|
+
- If the numerator is less than the denominator (lexicographically), we return the inverse of that element.
|
621
|
+
|
622
|
+
- If the numerator is greater than the denominator, we invert, and then increase the numerator (remaining monic) until we either get something relatively prime to the new denominator, or we reach the new denominator. In this case, we increase the denominator and set the numerator to 1.
|
623
|
+
|
624
|
+
EXAMPLES::
|
625
|
+
|
626
|
+
sage: from sage.rings.fraction_field_FpT import *
|
627
|
+
sage: R.<t> = FpT(GF(3)['t'])
|
628
|
+
sage: a = R(0)
|
629
|
+
sage: for _ in range(30):
|
630
|
+
....: a = a.next()
|
631
|
+
....: print(a)
|
632
|
+
1
|
633
|
+
2
|
634
|
+
1/t
|
635
|
+
2/t
|
636
|
+
t
|
637
|
+
2*t
|
638
|
+
1/(t + 1)
|
639
|
+
2/(t + 1)
|
640
|
+
t + 1
|
641
|
+
2*t + 2
|
642
|
+
t/(t + 1)
|
643
|
+
2*t/(t + 1)
|
644
|
+
(t + 1)/t
|
645
|
+
(2*t + 2)/t
|
646
|
+
1/(t + 2)
|
647
|
+
2/(t + 2)
|
648
|
+
t + 2
|
649
|
+
2*t + 1
|
650
|
+
t/(t + 2)
|
651
|
+
2*t/(t + 2)
|
652
|
+
(t + 2)/t
|
653
|
+
(2*t + 1)/t
|
654
|
+
(t + 1)/(t + 2)
|
655
|
+
(2*t + 2)/(t + 2)
|
656
|
+
(t + 2)/(t + 1)
|
657
|
+
(2*t + 1)/(t + 1)
|
658
|
+
1/t^2
|
659
|
+
2/t^2
|
660
|
+
t^2
|
661
|
+
2*t^2
|
662
|
+
"""
|
663
|
+
cdef FpTElement next = self._copy_c()
|
664
|
+
cdef long a, lead
|
665
|
+
cdef nmod_poly_t g
|
666
|
+
if nmod_poly_degree(self._numer) == -1:
|
667
|
+
# self should be normalized, so denom == 1
|
668
|
+
nmod_poly_set_coeff_ui(next._numer, 0, 1)
|
669
|
+
return next
|
670
|
+
lead = nmod_poly_leading(next._numer)
|
671
|
+
if lead < self.p - 1:
|
672
|
+
a = mod_inverse_int(lead, self.p)
|
673
|
+
# no overflow since self.p < 2^16
|
674
|
+
a = a * (lead + 1) % self.p
|
675
|
+
nmod_poly_scalar_mul_nmod(next._numer, next._numer, a)
|
676
|
+
else:
|
677
|
+
a = mod_inverse_int(lead, self.p)
|
678
|
+
nmod_poly_scalar_mul_nmod(next._numer, next._numer, a)
|
679
|
+
# now both next._numer and next._denom are monic. We figure out which is lexicographically bigger:
|
680
|
+
a = nmod_poly_cmp(next._numer, next._denom)
|
681
|
+
if a == 0:
|
682
|
+
# next._numer and next._denom are relatively prime, so they're both 1.
|
683
|
+
nmod_poly_inc(next._denom, True)
|
684
|
+
return next
|
685
|
+
nmod_poly_set(next._denom, next._numer)
|
686
|
+
nmod_poly_set(next._numer, self._denom)
|
687
|
+
if a < 0:
|
688
|
+
# since next._numer is smaller, we flip and return the inverse.
|
689
|
+
return next
|
690
|
+
elif a > 0:
|
691
|
+
# since next._numer is bigger, we're in the flipped phase. We flip back, and increment the numerator (until we reach the denominator).
|
692
|
+
nmod_poly_init(g, self.p)
|
693
|
+
try:
|
694
|
+
while True:
|
695
|
+
nmod_poly_inc(next._numer, True)
|
696
|
+
if nmod_poly_equal(next._numer, next._denom):
|
697
|
+
# Since we've reached the denominator, we reset the numerator to 1 and increment the denominator.
|
698
|
+
nmod_poly_inc(next._denom, True)
|
699
|
+
nmod_poly_zero(next._numer)
|
700
|
+
nmod_poly_set_coeff_ui(next._numer, 0, 1)
|
701
|
+
break
|
702
|
+
else:
|
703
|
+
# otherwise, we keep incrementing until we have a relatively prime numerator.
|
704
|
+
nmod_poly_gcd(g, next._numer, next._denom)
|
705
|
+
if nmod_poly_is_one(g):
|
706
|
+
break
|
707
|
+
finally:
|
708
|
+
nmod_poly_clear(g)
|
709
|
+
return next
|
710
|
+
|
711
|
+
cpdef _sqrt_or_None(self):
|
712
|
+
"""
|
713
|
+
Return the square root of ``self``, or ``None``.
|
714
|
+
|
715
|
+
Differs from sqrt() by not raising an exception.
|
716
|
+
|
717
|
+
TESTS::
|
718
|
+
|
719
|
+
sage: from sage.rings.fraction_field_FpT import *
|
720
|
+
sage: R.<t> = FpT(GF(17)['t'])
|
721
|
+
sage: sqrt(t^2) # indirect doctest
|
722
|
+
t
|
723
|
+
sage: sqrt(1/t^2)
|
724
|
+
1/t
|
725
|
+
sage: sqrt((1+t)^2)
|
726
|
+
t + 1
|
727
|
+
sage: sqrt((1+t)^2 / t^2)
|
728
|
+
(t + 1)/t
|
729
|
+
|
730
|
+
sage: sqrt(4 * (1+t)^2 / t^2)
|
731
|
+
(2*t + 2)/t
|
732
|
+
|
733
|
+
sage: sqrt(R(0))
|
734
|
+
0
|
735
|
+
sage: sqrt(R(-1))
|
736
|
+
4
|
737
|
+
|
738
|
+
sage: sqrt(t^4)
|
739
|
+
t^2
|
740
|
+
sage: sqrt(4*t^4/(1+t)^8)
|
741
|
+
2*t^2/(t^4 + 4*t^3 + 6*t^2 + 4*t + 1)
|
742
|
+
|
743
|
+
sage: R.<t> = FpT(GF(5)['t'])
|
744
|
+
sage: [a for a in R.iter(2) if (a^2).sqrt() not in (a,-a)]
|
745
|
+
[]
|
746
|
+
sage: [a for a in R.iter(2) if a.is_square() and a.sqrt()^2 != a]
|
747
|
+
[]
|
748
|
+
"""
|
749
|
+
if nmod_poly_is_zero(self._numer):
|
750
|
+
return self
|
751
|
+
|
752
|
+
if not nmod_poly_sqrt_check(self._numer) or not nmod_poly_sqrt_check(self._denom):
|
753
|
+
return None
|
754
|
+
|
755
|
+
cdef nmod_poly_t numer
|
756
|
+
cdef nmod_poly_t denom
|
757
|
+
cdef long a
|
758
|
+
cdef FpTElement res
|
759
|
+
|
760
|
+
nmod_poly_init(denom, self.p)
|
761
|
+
nmod_poly_init(numer, self.p)
|
762
|
+
|
763
|
+
if nmod_poly_sqrt(numer, self._numer) and nmod_poly_sqrt(denom, self._denom):
|
764
|
+
# Make denominator monic
|
765
|
+
a = nmod_poly_leading(denom)
|
766
|
+
if a != 1:
|
767
|
+
a = mod_inverse_int(a, self.p)
|
768
|
+
nmod_poly_scalar_mul_nmod(numer, numer, a)
|
769
|
+
nmod_poly_scalar_mul_nmod(denom, denom, a)
|
770
|
+
# Choose numerator with smaller leading coefficient
|
771
|
+
a = nmod_poly_leading(numer)
|
772
|
+
if a > self.p - a:
|
773
|
+
nmod_poly_neg(numer, numer)
|
774
|
+
res = self._new_c()
|
775
|
+
nmod_poly_swap(numer, res._numer)
|
776
|
+
nmod_poly_swap(denom, res._denom)
|
777
|
+
return res
|
778
|
+
else:
|
779
|
+
nmod_poly_clear(numer)
|
780
|
+
nmod_poly_clear(denom)
|
781
|
+
return None
|
782
|
+
|
783
|
+
cpdef bint is_square(self) noexcept:
|
784
|
+
"""
|
785
|
+
Return ``True`` if this element is the square of another element of the fraction field.
|
786
|
+
|
787
|
+
EXAMPLES::
|
788
|
+
|
789
|
+
sage: K = GF(13)['t'].fraction_field(); t = K.gen()
|
790
|
+
sage: t.is_square()
|
791
|
+
False
|
792
|
+
sage: (1/t^2).is_square()
|
793
|
+
True
|
794
|
+
sage: K(0).is_square()
|
795
|
+
True
|
796
|
+
"""
|
797
|
+
return self._sqrt_or_None() is not None
|
798
|
+
|
799
|
+
def sqrt(self, extend=True, all=False):
|
800
|
+
"""
|
801
|
+
Return the square root of this element.
|
802
|
+
|
803
|
+
INPUT:
|
804
|
+
|
805
|
+
- ``extend`` -- boolean (default: ``True``); if ``True``, return a
|
806
|
+
square root in an extension ring, if necessary. Otherwise, raise a
|
807
|
+
:exc:`ValueError` if the square is not in the base ring.
|
808
|
+
|
809
|
+
- ``all`` -- boolean (default: ``False``); if ``True``, return all
|
810
|
+
square roots of self, instead of just one
|
811
|
+
|
812
|
+
EXAMPLES::
|
813
|
+
|
814
|
+
sage: from sage.rings.fraction_field_FpT import *
|
815
|
+
sage: K = GF(7)['t'].fraction_field(); t = K.gen(0)
|
816
|
+
sage: p = (t + 2)^2/(3*t^3 + 1)^4
|
817
|
+
sage: p.sqrt()
|
818
|
+
(3*t + 6)/(t^6 + 3*t^3 + 4)
|
819
|
+
sage: p.sqrt()^2 == p
|
820
|
+
True
|
821
|
+
"""
|
822
|
+
s = self._sqrt_or_None()
|
823
|
+
if s is None:
|
824
|
+
if extend:
|
825
|
+
raise NotImplementedError("function fields not yet implemented")
|
826
|
+
else:
|
827
|
+
raise ValueError("not a perfect square")
|
828
|
+
else:
|
829
|
+
if all:
|
830
|
+
if not s:
|
831
|
+
return [s]
|
832
|
+
else:
|
833
|
+
return [s, -s]
|
834
|
+
else:
|
835
|
+
return s
|
836
|
+
|
837
|
+
def __pow__(FpTElement self, Py_ssize_t e, dummy):
|
838
|
+
r"""
|
839
|
+
Return the `e`-th power of this element.
|
840
|
+
|
841
|
+
EXAMPLES::
|
842
|
+
|
843
|
+
sage: from sage.rings.fraction_field_FpT import *
|
844
|
+
sage: R.<t> = FpT(GF(7)['t'])
|
845
|
+
sage: t^5
|
846
|
+
t^5
|
847
|
+
sage: t^-5
|
848
|
+
1/t^5
|
849
|
+
|
850
|
+
sage: a = (t+1)/(t-1); a
|
851
|
+
(t + 1)/(t + 6)
|
852
|
+
sage: a^5
|
853
|
+
(t^5 + 5*t^4 + 3*t^3 + 3*t^2 + 5*t + 1)/(t^5 + 2*t^4 + 3*t^3 + 4*t^2 + 5*t + 6)
|
854
|
+
sage: a^7
|
855
|
+
(t^7 + 1)/(t^7 + 6)
|
856
|
+
sage: a^14
|
857
|
+
(t^14 + 2*t^7 + 1)/(t^14 + 5*t^7 + 1)
|
858
|
+
|
859
|
+
sage: (a^2)^2 == a^4
|
860
|
+
True
|
861
|
+
sage: a^3 * a^2 == a^5
|
862
|
+
True
|
863
|
+
sage: a^47 * a^92 == a^(47+92)
|
864
|
+
True
|
865
|
+
"""
|
866
|
+
cdef long a
|
867
|
+
assert dummy is None
|
868
|
+
cdef FpTElement x = self._new_c()
|
869
|
+
if e >= 0:
|
870
|
+
nmod_poly_pow(x._numer, self._numer, e)
|
871
|
+
nmod_poly_pow(x._denom, self._denom, e)
|
872
|
+
else:
|
873
|
+
nmod_poly_pow(x._denom, self._numer, -e)
|
874
|
+
nmod_poly_pow(x._numer, self._denom, -e)
|
875
|
+
if nmod_poly_leading(x._denom) != 1:
|
876
|
+
a = mod_inverse_int(nmod_poly_leading(x._denom), self.p)
|
877
|
+
nmod_poly_scalar_mul_nmod(x._numer, x._numer, a)
|
878
|
+
nmod_poly_scalar_mul_nmod(x._denom, x._denom, a)
|
879
|
+
return x
|
880
|
+
|
881
|
+
|
882
|
+
cdef class FpT_iter:
|
883
|
+
"""
|
884
|
+
Return a class that iterates over all elements of an FpT.
|
885
|
+
|
886
|
+
EXAMPLES::
|
887
|
+
|
888
|
+
sage: K = GF(3)['t'].fraction_field()
|
889
|
+
sage: I = K.iter(1)
|
890
|
+
sage: list(I)
|
891
|
+
[0,
|
892
|
+
1,
|
893
|
+
2,
|
894
|
+
t,
|
895
|
+
t + 1,
|
896
|
+
t + 2,
|
897
|
+
2*t,
|
898
|
+
2*t + 1,
|
899
|
+
2*t + 2,
|
900
|
+
1/t,
|
901
|
+
2/t,
|
902
|
+
(t + 1)/t,
|
903
|
+
(t + 2)/t,
|
904
|
+
(2*t + 1)/t,
|
905
|
+
(2*t + 2)/t,
|
906
|
+
1/(t + 1),
|
907
|
+
2/(t + 1),
|
908
|
+
t/(t + 1),
|
909
|
+
(t + 2)/(t + 1),
|
910
|
+
2*t/(t + 1),
|
911
|
+
(2*t + 1)/(t + 1),
|
912
|
+
1/(t + 2),
|
913
|
+
2/(t + 2),
|
914
|
+
t/(t + 2),
|
915
|
+
(t + 1)/(t + 2),
|
916
|
+
2*t/(t + 2),
|
917
|
+
(2*t + 2)/(t + 2)]
|
918
|
+
"""
|
919
|
+
def __init__(self, parent, degree=None, FpTElement start=None):
|
920
|
+
"""
|
921
|
+
INPUT:
|
922
|
+
|
923
|
+
- ``parent`` -- the FpT that we're iterating over
|
924
|
+
|
925
|
+
- ``degree`` -- the maximum degree of the numerator and denominator of
|
926
|
+
the elements over which we iterate
|
927
|
+
|
928
|
+
- ``start`` -- (default: 0) the element on which to start
|
929
|
+
|
930
|
+
EXAMPLES::
|
931
|
+
|
932
|
+
sage: K = GF(11)['t'].fraction_field()
|
933
|
+
sage: I = K.iter(2) # indirect doctest
|
934
|
+
sage: for a in I:
|
935
|
+
....: if a.denom()[0] == 3 and a.numer()[1] == 2:
|
936
|
+
....: print(a); break
|
937
|
+
2*t/(t + 3)
|
938
|
+
"""
|
939
|
+
# if degree is None:
|
940
|
+
# raise NotImplementedError
|
941
|
+
self.parent = parent
|
942
|
+
self.cur = start
|
943
|
+
self.degree = -2 if degree is None else degree
|
944
|
+
|
945
|
+
def __cinit__(self, parent, *args, **kwds):
|
946
|
+
"""
|
947
|
+
Memory allocation for the temp variable storing the gcd of the numerator and denominator.
|
948
|
+
|
949
|
+
TESTS::
|
950
|
+
|
951
|
+
sage: from sage.rings.fraction_field_FpT import FpT_iter
|
952
|
+
sage: K = GF(7)['t'].fraction_field()
|
953
|
+
sage: I = FpT_iter(K, 3) # indirect doctest
|
954
|
+
sage: I
|
955
|
+
<sage.rings.fraction_field_FpT.FpT_iter object at ...>
|
956
|
+
"""
|
957
|
+
nmod_poly_init(self.g, parent.characteristic())
|
958
|
+
|
959
|
+
def __dealloc__(self):
|
960
|
+
"""
|
961
|
+
Deallocating of self.g.
|
962
|
+
|
963
|
+
TESTS::
|
964
|
+
|
965
|
+
sage: from sage.rings.fraction_field_FpT import FpT_iter
|
966
|
+
sage: K = GF(7)['t'].fraction_field()
|
967
|
+
sage: I = FpT_iter(K, 3)
|
968
|
+
sage: del I # indirect doctest
|
969
|
+
"""
|
970
|
+
nmod_poly_clear(self.g)
|
971
|
+
|
972
|
+
def __iter__(self):
|
973
|
+
"""
|
974
|
+
Return this iterator.
|
975
|
+
|
976
|
+
TESTS::
|
977
|
+
|
978
|
+
sage: from sage.rings.fraction_field_FpT import FpT_iter
|
979
|
+
sage: K = GF(3)['t'].fraction_field()
|
980
|
+
sage: I = FpT_iter(K, 3)
|
981
|
+
sage: for a in I: # indirect doctest
|
982
|
+
....: if a.numer()[1] == 1 and a.denom()[1] == 2 and a.is_square():
|
983
|
+
....: print(a); break
|
984
|
+
(t^2 + t + 1)/(t^2 + 2*t + 1)
|
985
|
+
"""
|
986
|
+
return self
|
987
|
+
|
988
|
+
def __next__(self):
|
989
|
+
"""
|
990
|
+
Return the next element to iterate over.
|
991
|
+
|
992
|
+
This is achieved by iterating over monic denominators, and for each denominator,
|
993
|
+
iterating over all numerators relatively prime to the given denominator.
|
994
|
+
|
995
|
+
EXAMPLES::
|
996
|
+
|
997
|
+
sage: from sage.rings.fraction_field_FpT import *
|
998
|
+
sage: K.<t> = FpT(GF(3)['t'])
|
999
|
+
sage: list(K.iter(1)) # indirect doctest
|
1000
|
+
[0,
|
1001
|
+
1,
|
1002
|
+
2,
|
1003
|
+
t,
|
1004
|
+
t + 1,
|
1005
|
+
t + 2,
|
1006
|
+
2*t,
|
1007
|
+
2*t + 1,
|
1008
|
+
2*t + 2,
|
1009
|
+
1/t,
|
1010
|
+
2/t,
|
1011
|
+
(t + 1)/t,
|
1012
|
+
(t + 2)/t,
|
1013
|
+
(2*t + 1)/t,
|
1014
|
+
(2*t + 2)/t,
|
1015
|
+
1/(t + 1),
|
1016
|
+
2/(t + 1),
|
1017
|
+
t/(t + 1),
|
1018
|
+
(t + 2)/(t + 1),
|
1019
|
+
2*t/(t + 1),
|
1020
|
+
(2*t + 1)/(t + 1),
|
1021
|
+
1/(t + 2),
|
1022
|
+
2/(t + 2),
|
1023
|
+
t/(t + 2),
|
1024
|
+
(t + 1)/(t + 2),
|
1025
|
+
2*t/(t + 2),
|
1026
|
+
(2*t + 2)/(t + 2)]
|
1027
|
+
|
1028
|
+
sage: len(list(K.iter(3)))
|
1029
|
+
2187
|
1030
|
+
|
1031
|
+
sage: K.<t> = FpT(GF(5)['t'])
|
1032
|
+
sage: L = list(K.iter(3)); len(L)
|
1033
|
+
78125
|
1034
|
+
sage: L[:10]
|
1035
|
+
[0, 1, 2, 3, 4, t, t + 1, t + 2, t + 3, t + 4]
|
1036
|
+
sage: L[2000]
|
1037
|
+
(3*t^3 + 3*t^2 + 3*t + 4)/(t + 2)
|
1038
|
+
sage: L[-1]
|
1039
|
+
(4*t^3 + 4*t^2 + 4*t + 4)/(t^3 + 4*t^2 + 4*t + 4)
|
1040
|
+
"""
|
1041
|
+
cdef FpTElement next_
|
1042
|
+
if self.cur is None:
|
1043
|
+
self.cur = self.parent(0)
|
1044
|
+
elif self.degree == -2:
|
1045
|
+
self.cur = next(self.cur)
|
1046
|
+
else:
|
1047
|
+
next_ = self.cur._copy_c()
|
1048
|
+
sig_on()
|
1049
|
+
while True:
|
1050
|
+
nmod_poly_inc(next_._numer, False)
|
1051
|
+
if nmod_poly_degree(next_._numer) > self.degree:
|
1052
|
+
nmod_poly_inc(next_._denom, True)
|
1053
|
+
if nmod_poly_degree(next_._denom) > self.degree:
|
1054
|
+
sig_off()
|
1055
|
+
raise StopIteration
|
1056
|
+
nmod_poly_zero(next_._numer)
|
1057
|
+
nmod_poly_set_coeff_ui(next_._numer, 0, 1)
|
1058
|
+
nmod_poly_gcd(self.g, next_._numer, next_._denom)
|
1059
|
+
if nmod_poly_is_one(self.g):
|
1060
|
+
break
|
1061
|
+
sig_off()
|
1062
|
+
self.cur = next_
|
1063
|
+
return self.cur
|
1064
|
+
|
1065
|
+
cdef class Polyring_FpT_coerce(RingHomomorphism):
|
1066
|
+
"""
|
1067
|
+
This class represents the coercion map from GF(p)[t] to GF(p)(t).
|
1068
|
+
|
1069
|
+
EXAMPLES::
|
1070
|
+
|
1071
|
+
sage: R.<t> = GF(5)[]
|
1072
|
+
sage: K = R.fraction_field()
|
1073
|
+
sage: f = K.coerce_map_from(R); f
|
1074
|
+
Ring morphism:
|
1075
|
+
From: Univariate Polynomial Ring in t over Finite Field of size 5
|
1076
|
+
To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1077
|
+
sage: type(f)
|
1078
|
+
<class 'sage.rings.fraction_field_FpT.Polyring_FpT_coerce'>
|
1079
|
+
|
1080
|
+
TESTS::
|
1081
|
+
|
1082
|
+
TestSuite(f).run()
|
1083
|
+
"""
|
1084
|
+
cdef long p
|
1085
|
+
|
1086
|
+
def __init__(self, R):
|
1087
|
+
"""
|
1088
|
+
INPUT:
|
1089
|
+
|
1090
|
+
- ``R`` -- an FpT
|
1091
|
+
|
1092
|
+
EXAMPLES::
|
1093
|
+
|
1094
|
+
sage: # needs sage.rings.finite_rings
|
1095
|
+
sage: R.<t> = GF(next_prime(2000))[]
|
1096
|
+
sage: K = R.fraction_field() # indirect doctest
|
1097
|
+
"""
|
1098
|
+
RingHomomorphism.__init__(self, R.ring_of_integers().Hom(R))
|
1099
|
+
self.p = R.base_ring().characteristic()
|
1100
|
+
|
1101
|
+
cdef dict _extra_slots(self):
|
1102
|
+
"""
|
1103
|
+
Helper for copying and pickling.
|
1104
|
+
|
1105
|
+
EXAMPLES::
|
1106
|
+
|
1107
|
+
sage: R.<t> = GF(5)[]
|
1108
|
+
sage: K = R.fraction_field()
|
1109
|
+
sage: f = K.coerce_map_from(R) # indirect doctest
|
1110
|
+
sage: f(t^2 + 1)
|
1111
|
+
t^2 + 1
|
1112
|
+
"""
|
1113
|
+
slots = RingHomomorphism._extra_slots(self)
|
1114
|
+
slots['p'] = self.p
|
1115
|
+
return slots
|
1116
|
+
|
1117
|
+
cdef _update_slots(self, dict _slots):
|
1118
|
+
"""
|
1119
|
+
Helper for copying and pickling.
|
1120
|
+
|
1121
|
+
EXAMPLES::
|
1122
|
+
|
1123
|
+
sage: R.<t> = GF(5)[]
|
1124
|
+
sage: K = R.fraction_field()
|
1125
|
+
sage: f = K.coerce_map_from(R) # indirect doctest
|
1126
|
+
sage: f(t^2 + 1)
|
1127
|
+
t^2 + 1
|
1128
|
+
"""
|
1129
|
+
self.p = _slots['p']
|
1130
|
+
RingHomomorphism._update_slots(self, _slots)
|
1131
|
+
|
1132
|
+
cpdef Element _call_(self, _x):
|
1133
|
+
"""
|
1134
|
+
Applies the coercion.
|
1135
|
+
|
1136
|
+
EXAMPLES::
|
1137
|
+
|
1138
|
+
sage: R.<t> = GF(5)[]
|
1139
|
+
sage: K = R.fraction_field()
|
1140
|
+
sage: f = K.coerce_map_from(R)
|
1141
|
+
sage: f(t^2 + 1) # indirect doctest
|
1142
|
+
t^2 + 1
|
1143
|
+
"""
|
1144
|
+
cdef Polynomial_zmod_flint x = <Polynomial_zmod_flint?> _x
|
1145
|
+
cdef FpTElement ans = <FpTElement>FpTElement.__new__(FpTElement)
|
1146
|
+
ans._parent = self.codomain()
|
1147
|
+
ans.p = self.p
|
1148
|
+
nmod_poly_init(ans._numer, ans.p)
|
1149
|
+
nmod_poly_init(ans._denom, ans.p)
|
1150
|
+
nmod_poly_set(ans._numer, &x.x)
|
1151
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
|
1152
|
+
ans.initialized = True
|
1153
|
+
return ans
|
1154
|
+
|
1155
|
+
cpdef Element _call_with_args(self, _x, args=(), kwds={}):
|
1156
|
+
"""
|
1157
|
+
This function allows the map to take multiple arguments,
|
1158
|
+
usually used to specify both numerator and denominator.
|
1159
|
+
|
1160
|
+
If ``reduce`` is specified as False, then the result won't be
|
1161
|
+
normalized.
|
1162
|
+
|
1163
|
+
EXAMPLES::
|
1164
|
+
|
1165
|
+
sage: R.<t> = GF(5)[]
|
1166
|
+
sage: K = R.fraction_field()
|
1167
|
+
sage: f = K.coerce_map_from(R)
|
1168
|
+
sage: f(2*t + 2, t + 3) # indirect doctest
|
1169
|
+
(2*t + 2)/(t + 3)
|
1170
|
+
sage: f(2*t + 2, 2)
|
1171
|
+
t + 1
|
1172
|
+
sage: f(2*t + 2, 2, reduce=False)
|
1173
|
+
(2*t + 2)/2
|
1174
|
+
|
1175
|
+
TESTS:
|
1176
|
+
|
1177
|
+
Check that :issue:`12217` and :issue:`16811` are fixed::
|
1178
|
+
|
1179
|
+
sage: R.<t> = GF(5)[]
|
1180
|
+
sage: K = R.fraction_field()
|
1181
|
+
sage: f = K.coerce_map_from(R)
|
1182
|
+
sage: f(t, 0)
|
1183
|
+
Traceback (most recent call last):
|
1184
|
+
...
|
1185
|
+
ZeroDivisionError: fraction has denominator 0
|
1186
|
+
sage: f(t, GF(5).zero())
|
1187
|
+
Traceback (most recent call last):
|
1188
|
+
...
|
1189
|
+
ZeroDivisionError: fraction has denominator 0
|
1190
|
+
sage: f(t, R.zero())
|
1191
|
+
Traceback (most recent call last):
|
1192
|
+
...
|
1193
|
+
ZeroDivisionError: fraction has denominator 0
|
1194
|
+
"""
|
1195
|
+
cdef Polynomial_zmod_flint x
|
1196
|
+
cdef unsigned long r
|
1197
|
+
try:
|
1198
|
+
x = <Polynomial_zmod_flint?> _x
|
1199
|
+
except TypeError:
|
1200
|
+
raise NotImplementedError('Fraction fields not implemented for this type.')
|
1201
|
+
cdef FpTElement ans = <FpTElement>FpTElement.__new__(FpTElement)
|
1202
|
+
ans._parent = self.codomain()
|
1203
|
+
ans.p = self.p
|
1204
|
+
nmod_poly_init(ans._numer, ans.p)
|
1205
|
+
nmod_poly_init(ans._denom, ans.p)
|
1206
|
+
nmod_poly_set(ans._numer, &x.x)
|
1207
|
+
if len(args) == 0:
|
1208
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, 1) # No need to normalize
|
1209
|
+
elif len(args) == 1:
|
1210
|
+
y = args[0]
|
1211
|
+
if isinstance(y, Integer):
|
1212
|
+
r = mpz_fdiv_ui((<Integer>y).value, self.p)
|
1213
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, r)
|
1214
|
+
else:
|
1215
|
+
# could use the coerce keyword being set to False to not check this...
|
1216
|
+
if not (isinstance(y, Element) and y.parent() is self.domain()):
|
1217
|
+
# We could special case integers and GF(p) elements here.
|
1218
|
+
y = self.domain()(y)
|
1219
|
+
nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))
|
1220
|
+
# Normalize the fraction, checking for division by zero
|
1221
|
+
if nmod_poly_is_zero(ans._denom):
|
1222
|
+
raise ZeroDivisionError('fraction has denominator 0')
|
1223
|
+
if kwds.get('reduce', True):
|
1224
|
+
normalize(ans._numer, ans._denom, ans.p)
|
1225
|
+
else:
|
1226
|
+
raise TypeError("FpT only supports two positional arguments")
|
1227
|
+
ans.initialized = True
|
1228
|
+
return ans
|
1229
|
+
|
1230
|
+
def section(self):
|
1231
|
+
"""
|
1232
|
+
Return the section of this inclusion: the partially defined map from ``GF(p)(t)``
|
1233
|
+
back to ``GF(p)[t]``, defined on elements with unit denominator.
|
1234
|
+
|
1235
|
+
EXAMPLES::
|
1236
|
+
|
1237
|
+
sage: R.<t> = GF(5)[]
|
1238
|
+
sage: K = R.fraction_field()
|
1239
|
+
sage: f = K.coerce_map_from(R)
|
1240
|
+
sage: g = f.section(); g
|
1241
|
+
Section map:
|
1242
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1243
|
+
To: Univariate Polynomial Ring in t over Finite Field of size 5
|
1244
|
+
sage: t = K.gen()
|
1245
|
+
sage: g(t)
|
1246
|
+
t
|
1247
|
+
sage: g(1/t)
|
1248
|
+
Traceback (most recent call last):
|
1249
|
+
...
|
1250
|
+
ValueError: not integral
|
1251
|
+
"""
|
1252
|
+
return FpT_Polyring_section(self)
|
1253
|
+
|
1254
|
+
cdef class FpT_Polyring_section(Section):
|
1255
|
+
"""
|
1256
|
+
This class represents the section from GF(p)(t) back to GF(p)[t].
|
1257
|
+
|
1258
|
+
EXAMPLES::
|
1259
|
+
|
1260
|
+
sage: R.<t> = GF(5)[]
|
1261
|
+
sage: K = R.fraction_field()
|
1262
|
+
sage: f = R.convert_map_from(K); f
|
1263
|
+
Section map:
|
1264
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1265
|
+
To: Univariate Polynomial Ring in t over Finite Field of size 5
|
1266
|
+
sage: type(f)
|
1267
|
+
<class 'sage.rings.fraction_field_FpT.FpT_Polyring_section'>
|
1268
|
+
|
1269
|
+
.. WARNING::
|
1270
|
+
|
1271
|
+
Comparison of ``FpT_Polyring_section`` objects is not currently
|
1272
|
+
implemented. See :issue:`23469`. ::
|
1273
|
+
|
1274
|
+
sage: fprime = loads(dumps(f))
|
1275
|
+
sage: fprime == f
|
1276
|
+
False
|
1277
|
+
|
1278
|
+
sage: fprime(1+t) == f(1+t)
|
1279
|
+
True
|
1280
|
+
|
1281
|
+
TESTS::
|
1282
|
+
|
1283
|
+
sage: TestSuite(f).run(skip='_test_pickling')
|
1284
|
+
"""
|
1285
|
+
cdef long p
|
1286
|
+
|
1287
|
+
def __init__(self, Polyring_FpT_coerce f):
|
1288
|
+
"""
|
1289
|
+
INPUT:
|
1290
|
+
|
1291
|
+
- ``f`` -- a Polyring_FpT_coerce homomorphism
|
1292
|
+
|
1293
|
+
EXAMPLES::
|
1294
|
+
|
1295
|
+
sage: # needs sage.rings.finite_rings
|
1296
|
+
sage: R.<t> = GF(next_prime(2000))[]
|
1297
|
+
sage: K = R.fraction_field()
|
1298
|
+
sage: R(K.gen(0)) # indirect doctest
|
1299
|
+
t
|
1300
|
+
"""
|
1301
|
+
self.p = f.p
|
1302
|
+
Section.__init__(self, f)
|
1303
|
+
|
1304
|
+
cdef dict _extra_slots(self):
|
1305
|
+
"""
|
1306
|
+
Helper for copying and pickling.
|
1307
|
+
|
1308
|
+
EXAMPLES::
|
1309
|
+
|
1310
|
+
sage: R.<t> = GF(7)[]
|
1311
|
+
sage: K = R.fraction_field()
|
1312
|
+
sage: f = K.coerce_map_from(R)
|
1313
|
+
sage: g = f.section() # indirect doctest
|
1314
|
+
sage: t = K.gen()
|
1315
|
+
sage: g(t^2)
|
1316
|
+
t^2
|
1317
|
+
sage: g(1/t)
|
1318
|
+
Traceback (most recent call last):
|
1319
|
+
...
|
1320
|
+
ValueError: not integral
|
1321
|
+
"""
|
1322
|
+
slots = Section._extra_slots(self)
|
1323
|
+
slots['p'] = self.p
|
1324
|
+
return slots
|
1325
|
+
|
1326
|
+
cdef _update_slots(self, dict _slots):
|
1327
|
+
"""
|
1328
|
+
Helper for copying and pickling.
|
1329
|
+
|
1330
|
+
EXAMPLES::
|
1331
|
+
|
1332
|
+
sage: R.<t> = GF(7)[]
|
1333
|
+
sage: K = R.fraction_field()
|
1334
|
+
sage: f = K.coerce_map_from(R)
|
1335
|
+
sage: g = f.section() # indirect doctest
|
1336
|
+
sage: t = K.gen()
|
1337
|
+
sage: g(t^2)
|
1338
|
+
t^2
|
1339
|
+
sage: g(1/t)
|
1340
|
+
Traceback (most recent call last):
|
1341
|
+
...
|
1342
|
+
ValueError: not integral
|
1343
|
+
"""
|
1344
|
+
self.p = _slots['p']
|
1345
|
+
Section._update_slots(self, _slots)
|
1346
|
+
|
1347
|
+
cpdef Element _call_(self, _x):
|
1348
|
+
"""
|
1349
|
+
Applies the section.
|
1350
|
+
|
1351
|
+
EXAMPLES::
|
1352
|
+
|
1353
|
+
sage: R.<t> = GF(7)[]
|
1354
|
+
sage: K = R.fraction_field()
|
1355
|
+
sage: f = K.coerce_map_from(R)
|
1356
|
+
sage: g = f.section(); g
|
1357
|
+
Section map:
|
1358
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7
|
1359
|
+
To: Univariate Polynomial Ring in t over Finite Field of size 7
|
1360
|
+
sage: t = K.gen()
|
1361
|
+
sage: g(t^2) # indirect doctest
|
1362
|
+
t^2
|
1363
|
+
sage: g(1/t)
|
1364
|
+
Traceback (most recent call last):
|
1365
|
+
...
|
1366
|
+
ValueError: not integral
|
1367
|
+
"""
|
1368
|
+
cdef FpTElement x = <FpTElement?>_x
|
1369
|
+
cdef Polynomial_zmod_flint ans
|
1370
|
+
if nmod_poly_degree(x._denom) != 0:
|
1371
|
+
normalize(x._numer, x._denom, self.p)
|
1372
|
+
if nmod_poly_degree(x._denom) != 0:
|
1373
|
+
raise ValueError("not integral")
|
1374
|
+
ans = Polynomial_zmod_flint.__new__(Polynomial_zmod_flint)
|
1375
|
+
if nmod_poly_get_coeff_ui(x._denom, 0) != 1:
|
1376
|
+
normalize(x._numer, x._denom, self.p)
|
1377
|
+
nmod_poly_init(&ans.x, self.p)
|
1378
|
+
nmod_poly_set(&ans.x, x._numer)
|
1379
|
+
ans._parent = self.codomain()
|
1380
|
+
ans._cparent = get_cparent(ans._parent)
|
1381
|
+
return ans
|
1382
|
+
|
1383
|
+
cdef class Fp_FpT_coerce(RingHomomorphism):
|
1384
|
+
"""
|
1385
|
+
This class represents the coercion map from GF(p) to GF(p)(t).
|
1386
|
+
|
1387
|
+
EXAMPLES::
|
1388
|
+
|
1389
|
+
sage: R.<t> = GF(5)[]
|
1390
|
+
sage: K = R.fraction_field()
|
1391
|
+
sage: f = K.coerce_map_from(GF(5)); f
|
1392
|
+
Ring morphism:
|
1393
|
+
From: Finite Field of size 5
|
1394
|
+
To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1395
|
+
sage: type(f)
|
1396
|
+
<class 'sage.rings.fraction_field_FpT.Fp_FpT_coerce'>
|
1397
|
+
|
1398
|
+
TESTS::
|
1399
|
+
|
1400
|
+
sage: TestSuite(f).run()
|
1401
|
+
"""
|
1402
|
+
cdef long p
|
1403
|
+
|
1404
|
+
def __init__(self, R):
|
1405
|
+
"""
|
1406
|
+
INPUT:
|
1407
|
+
|
1408
|
+
- ``R`` -- an FpT
|
1409
|
+
|
1410
|
+
EXAMPLES::
|
1411
|
+
|
1412
|
+
sage: # needs sage.rings.finite_rings
|
1413
|
+
sage: R.<t> = GF(next_prime(3000))[]
|
1414
|
+
sage: K = R.fraction_field() # indirect doctest
|
1415
|
+
"""
|
1416
|
+
RingHomomorphism.__init__(self, R.base_ring().Hom(R))
|
1417
|
+
self.p = R.base_ring().characteristic()
|
1418
|
+
|
1419
|
+
cdef dict _extra_slots(self):
|
1420
|
+
"""
|
1421
|
+
Helper for copying and pickling.
|
1422
|
+
|
1423
|
+
EXAMPLES::
|
1424
|
+
|
1425
|
+
sage: R.<t> = GF(5)[]
|
1426
|
+
sage: K = R.fraction_field()
|
1427
|
+
sage: f = K.coerce_map_from(GF(5))
|
1428
|
+
sage: g = copy(f)
|
1429
|
+
sage: g == f
|
1430
|
+
True
|
1431
|
+
sage: g(GF(5)(2)) == f(GF(5)(2))
|
1432
|
+
True
|
1433
|
+
"""
|
1434
|
+
slots = RingHomomorphism._extra_slots(self)
|
1435
|
+
slots['p'] = self.p
|
1436
|
+
return slots
|
1437
|
+
|
1438
|
+
cdef _update_slots(self, dict _slots):
|
1439
|
+
"""
|
1440
|
+
Helper for copying and pickling.
|
1441
|
+
|
1442
|
+
EXAMPLES::
|
1443
|
+
|
1444
|
+
sage: R.<t> = GF(5)[]
|
1445
|
+
sage: K = R.fraction_field()
|
1446
|
+
sage: f = K.coerce_map_from(GF(5))
|
1447
|
+
sage: g = copy(f)
|
1448
|
+
sage: g == f
|
1449
|
+
True
|
1450
|
+
sage: g(GF(5)(2)) == f(GF(5)(2))
|
1451
|
+
True
|
1452
|
+
"""
|
1453
|
+
self.p = _slots['p']
|
1454
|
+
RingHomomorphism._update_slots(self, _slots)
|
1455
|
+
|
1456
|
+
cpdef Element _call_(self, _x):
|
1457
|
+
"""
|
1458
|
+
Applies the coercion.
|
1459
|
+
|
1460
|
+
EXAMPLES::
|
1461
|
+
|
1462
|
+
sage: R.<t> = GF(5)[]
|
1463
|
+
sage: K = R.fraction_field()
|
1464
|
+
sage: f = K.coerce_map_from(GF(5))
|
1465
|
+
sage: f(GF(5)(3)) # indirect doctest
|
1466
|
+
3
|
1467
|
+
"""
|
1468
|
+
cdef IntegerMod_int x = <IntegerMod_int?> _x
|
1469
|
+
cdef FpTElement ans = <FpTElement>FpTElement.__new__(FpTElement)
|
1470
|
+
ans._parent = self.codomain()
|
1471
|
+
ans.p = self.p
|
1472
|
+
nmod_poly_init(ans._numer, ans.p)
|
1473
|
+
nmod_poly_init(ans._denom, ans.p)
|
1474
|
+
nmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue)
|
1475
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
|
1476
|
+
ans.initialized = True
|
1477
|
+
return ans
|
1478
|
+
|
1479
|
+
cpdef Element _call_with_args(self, _x, args=(), kwds={}):
|
1480
|
+
"""
|
1481
|
+
This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.
|
1482
|
+
|
1483
|
+
If ``reduce`` is specified as False, then the result won't be normalized.
|
1484
|
+
|
1485
|
+
EXAMPLES::
|
1486
|
+
|
1487
|
+
sage: R.<t> = GF(5)[]
|
1488
|
+
sage: K = R.fraction_field()
|
1489
|
+
sage: f = K.coerce_map_from(GF(5))
|
1490
|
+
sage: f(1, t + 3) # indirect doctest
|
1491
|
+
1/(t + 3)
|
1492
|
+
sage: f(2, 2*t)
|
1493
|
+
1/t
|
1494
|
+
sage: f(2, 2*t, reduce=False)
|
1495
|
+
2/2*t
|
1496
|
+
"""
|
1497
|
+
cdef IntegerMod_int x = <IntegerMod_int?> _x
|
1498
|
+
cdef FpTElement ans = <FpTElement>FpTElement.__new__(FpTElement)
|
1499
|
+
ans._parent = self.codomain()
|
1500
|
+
ans.p = self.p
|
1501
|
+
nmod_poly_init(ans._numer, ans.p)
|
1502
|
+
nmod_poly_init(ans._denom, ans.p)
|
1503
|
+
cdef long r
|
1504
|
+
nmod_poly_set_coeff_ui(ans._numer, 0, x.ivalue)
|
1505
|
+
if len(args) == 0:
|
1506
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
|
1507
|
+
if len(args) == 1:
|
1508
|
+
y = args[0]
|
1509
|
+
if isinstance(y, Integer):
|
1510
|
+
r = mpz_fdiv_ui((<Integer>y).value, self.p)
|
1511
|
+
if r == 0:
|
1512
|
+
raise ZeroDivisionError
|
1513
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, r)
|
1514
|
+
else:
|
1515
|
+
R = ans._parent.ring_of_integers()
|
1516
|
+
# could use the coerce keyword being set to False to not check this...
|
1517
|
+
if not (isinstance(y, Element) and y.parent() is R):
|
1518
|
+
# We could special case integers and GF(p) elements here.
|
1519
|
+
y = R(y)
|
1520
|
+
nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))
|
1521
|
+
else:
|
1522
|
+
raise ValueError("FpT only supports two positional arguments")
|
1523
|
+
if 'reduce' not in kwds or kwds['reduce']:
|
1524
|
+
normalize(ans._numer, ans._denom, ans.p)
|
1525
|
+
ans.initialized = True
|
1526
|
+
return ans
|
1527
|
+
|
1528
|
+
def section(self):
|
1529
|
+
"""
|
1530
|
+
Return the section of this inclusion: the partially defined map from ``GF(p)(t)``
|
1531
|
+
back to ``GF(p)``, defined on constant elements.
|
1532
|
+
|
1533
|
+
EXAMPLES::
|
1534
|
+
|
1535
|
+
sage: R.<t> = GF(5)[]
|
1536
|
+
sage: K = R.fraction_field()
|
1537
|
+
sage: f = K.coerce_map_from(GF(5))
|
1538
|
+
sage: g = f.section(); g
|
1539
|
+
Section map:
|
1540
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1541
|
+
To: Finite Field of size 5
|
1542
|
+
sage: t = K.gen()
|
1543
|
+
sage: g(f(1,3,reduce=False))
|
1544
|
+
2
|
1545
|
+
sage: g(t)
|
1546
|
+
Traceback (most recent call last):
|
1547
|
+
...
|
1548
|
+
ValueError: not constant
|
1549
|
+
sage: g(1/t)
|
1550
|
+
Traceback (most recent call last):
|
1551
|
+
...
|
1552
|
+
ValueError: not integral
|
1553
|
+
"""
|
1554
|
+
return FpT_Fp_section(self)
|
1555
|
+
|
1556
|
+
cdef class FpT_Fp_section(Section):
|
1557
|
+
"""
|
1558
|
+
This class represents the section from GF(p)(t) back to GF(p)[t].
|
1559
|
+
|
1560
|
+
EXAMPLES::
|
1561
|
+
|
1562
|
+
sage: R.<t> = GF(5)[]
|
1563
|
+
sage: K = R.fraction_field()
|
1564
|
+
sage: f = GF(5).convert_map_from(K); f
|
1565
|
+
Section map:
|
1566
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1567
|
+
To: Finite Field of size 5
|
1568
|
+
sage: type(f)
|
1569
|
+
<class 'sage.rings.fraction_field_FpT.FpT_Fp_section'>
|
1570
|
+
|
1571
|
+
.. WARNING::
|
1572
|
+
|
1573
|
+
Comparison of ``FpT_Fp_section`` objects is not currently
|
1574
|
+
implemented. See :issue:`23469`. ::
|
1575
|
+
|
1576
|
+
sage: fprime = loads(dumps(f))
|
1577
|
+
sage: fprime == f
|
1578
|
+
False
|
1579
|
+
|
1580
|
+
sage: fprime(3) == f(3)
|
1581
|
+
True
|
1582
|
+
|
1583
|
+
TESTS::
|
1584
|
+
|
1585
|
+
sage: TestSuite(f).run(skip='_test_pickling')
|
1586
|
+
"""
|
1587
|
+
cdef long p
|
1588
|
+
|
1589
|
+
def __init__(self, Fp_FpT_coerce f):
|
1590
|
+
"""
|
1591
|
+
INPUT:
|
1592
|
+
|
1593
|
+
- ``f`` -- an ``Fp_FpT_coerce`` homomorphism
|
1594
|
+
|
1595
|
+
EXAMPLES::
|
1596
|
+
|
1597
|
+
sage: # needs sage.rings.finite_rings
|
1598
|
+
sage: R.<t> = GF(next_prime(2000))[]
|
1599
|
+
sage: K = R.fraction_field()
|
1600
|
+
sage: GF(next_prime(2000))(K(127)) # indirect doctest
|
1601
|
+
127
|
1602
|
+
"""
|
1603
|
+
self.p = f.p
|
1604
|
+
Section.__init__(self, f)
|
1605
|
+
|
1606
|
+
cdef dict _extra_slots(self):
|
1607
|
+
"""
|
1608
|
+
Helper for copying and pickling.
|
1609
|
+
|
1610
|
+
EXAMPLES::
|
1611
|
+
|
1612
|
+
sage: R.<t> = GF(7)[]
|
1613
|
+
sage: K = R.fraction_field()
|
1614
|
+
sage: f = K.coerce_map_from(GF(7))
|
1615
|
+
sage: g = f.section() # indirect doctest
|
1616
|
+
sage: t = K.gen()
|
1617
|
+
sage: g(t^2)
|
1618
|
+
Traceback (most recent call last):
|
1619
|
+
...
|
1620
|
+
ValueError: not constant
|
1621
|
+
sage: g(1/t)
|
1622
|
+
Traceback (most recent call last):
|
1623
|
+
...
|
1624
|
+
ValueError: not integral
|
1625
|
+
sage: g(K(4))
|
1626
|
+
4
|
1627
|
+
sage: g(K(0))
|
1628
|
+
0
|
1629
|
+
"""
|
1630
|
+
slots = Section._extra_slots(self)
|
1631
|
+
slots['p'] = self.p
|
1632
|
+
return slots
|
1633
|
+
|
1634
|
+
cdef _update_slots(self, dict _slots):
|
1635
|
+
"""
|
1636
|
+
Helper for copying and pickling.
|
1637
|
+
|
1638
|
+
EXAMPLES::
|
1639
|
+
|
1640
|
+
sage: R.<t> = GF(7)[]
|
1641
|
+
sage: K = R.fraction_field()
|
1642
|
+
sage: f = K.coerce_map_from(GF(7))
|
1643
|
+
sage: g = f.section() # indirect doctest
|
1644
|
+
sage: t = K.gen()
|
1645
|
+
sage: g(t^2)
|
1646
|
+
Traceback (most recent call last):
|
1647
|
+
...
|
1648
|
+
ValueError: not constant
|
1649
|
+
sage: g(1/t)
|
1650
|
+
Traceback (most recent call last):
|
1651
|
+
...
|
1652
|
+
ValueError: not integral
|
1653
|
+
sage: g(K(4))
|
1654
|
+
4
|
1655
|
+
sage: g(K(0))
|
1656
|
+
0
|
1657
|
+
"""
|
1658
|
+
self.p = _slots['p']
|
1659
|
+
Section._update_slots(self, _slots)
|
1660
|
+
|
1661
|
+
cpdef Element _call_(self, _x):
|
1662
|
+
"""
|
1663
|
+
Applies the section.
|
1664
|
+
|
1665
|
+
EXAMPLES::
|
1666
|
+
|
1667
|
+
sage: R.<t> = GF(7)[]
|
1668
|
+
sage: K = R.fraction_field()
|
1669
|
+
sage: f = K.coerce_map_from(GF(7))
|
1670
|
+
sage: g = f.section(); g
|
1671
|
+
Section map:
|
1672
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7
|
1673
|
+
To: Finite Field of size 7
|
1674
|
+
sage: t = K.gen()
|
1675
|
+
sage: g(t^2) # indirect doctest
|
1676
|
+
Traceback (most recent call last):
|
1677
|
+
...
|
1678
|
+
ValueError: not constant
|
1679
|
+
sage: g(1/t)
|
1680
|
+
Traceback (most recent call last):
|
1681
|
+
...
|
1682
|
+
ValueError: not integral
|
1683
|
+
sage: g(K(4))
|
1684
|
+
4
|
1685
|
+
sage: g(K(0))
|
1686
|
+
0
|
1687
|
+
"""
|
1688
|
+
cdef FpTElement x = <FpTElement?>_x
|
1689
|
+
cdef IntegerMod_int ans
|
1690
|
+
if nmod_poly_degree(x._denom) != 0 or nmod_poly_degree(x._numer) > 0:
|
1691
|
+
normalize(x._numer, x._denom, self.p)
|
1692
|
+
if nmod_poly_degree(x._denom) != 0:
|
1693
|
+
raise ValueError("not integral")
|
1694
|
+
if nmod_poly_degree(x._numer) > 0:
|
1695
|
+
raise ValueError("not constant")
|
1696
|
+
ans = IntegerMod_int.__new__(IntegerMod_int)
|
1697
|
+
ans._parent = self.codomain()
|
1698
|
+
ans._modulus = ans._parent._pyx_order
|
1699
|
+
if nmod_poly_get_coeff_ui(x._denom, 0) != 1:
|
1700
|
+
normalize(x._numer, x._denom, self.p)
|
1701
|
+
ans.ivalue = nmod_poly_get_coeff_ui(x._numer, 0)
|
1702
|
+
return ans
|
1703
|
+
|
1704
|
+
cdef class ZZ_FpT_coerce(RingHomomorphism):
|
1705
|
+
"""
|
1706
|
+
This class represents the coercion map from ZZ to GF(p)(t).
|
1707
|
+
|
1708
|
+
EXAMPLES::
|
1709
|
+
|
1710
|
+
sage: R.<t> = GF(17)[]
|
1711
|
+
sage: K = R.fraction_field()
|
1712
|
+
sage: f = K.coerce_map_from(ZZ); f
|
1713
|
+
Ring morphism:
|
1714
|
+
From: Integer Ring
|
1715
|
+
To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 17
|
1716
|
+
sage: type(f)
|
1717
|
+
<class 'sage.rings.fraction_field_FpT.ZZ_FpT_coerce'>
|
1718
|
+
|
1719
|
+
TESTS::
|
1720
|
+
|
1721
|
+
sage: TestSuite(f).run()
|
1722
|
+
"""
|
1723
|
+
cdef long p
|
1724
|
+
|
1725
|
+
def __init__(self, R):
|
1726
|
+
"""
|
1727
|
+
INPUT:
|
1728
|
+
|
1729
|
+
- ``R`` -- an FpT
|
1730
|
+
|
1731
|
+
EXAMPLES::
|
1732
|
+
|
1733
|
+
sage: # needs sage.rings.finite_rings
|
1734
|
+
sage: R.<t> = GF(next_prime(3000))[]
|
1735
|
+
sage: K = R.fraction_field() # indirect doctest
|
1736
|
+
"""
|
1737
|
+
RingHomomorphism.__init__(self, ZZ.Hom(R))
|
1738
|
+
self.p = R.base_ring().characteristic()
|
1739
|
+
|
1740
|
+
cdef dict _extra_slots(self):
|
1741
|
+
"""
|
1742
|
+
Helper for copying and pickling.
|
1743
|
+
|
1744
|
+
EXAMPLES::
|
1745
|
+
|
1746
|
+
sage: R.<t> = GF(5)[]
|
1747
|
+
sage: K = R.fraction_field()
|
1748
|
+
sage: f = K.coerce_map_from(ZZ)
|
1749
|
+
sage: g = copy(f) # indirect doctest
|
1750
|
+
sage: g == f
|
1751
|
+
True
|
1752
|
+
sage: g(5) == f(5)
|
1753
|
+
True
|
1754
|
+
sage: g(0) == f(0)
|
1755
|
+
True
|
1756
|
+
"""
|
1757
|
+
slots = RingHomomorphism._extra_slots(self)
|
1758
|
+
slots['p'] = self.p
|
1759
|
+
return slots
|
1760
|
+
|
1761
|
+
cdef _update_slots(self, dict _slots):
|
1762
|
+
"""
|
1763
|
+
Helper for copying and pickling.
|
1764
|
+
|
1765
|
+
EXAMPLES::
|
1766
|
+
|
1767
|
+
sage: R.<t> = GF(5)[]
|
1768
|
+
sage: K = R.fraction_field()
|
1769
|
+
sage: f = K.coerce_map_from(ZZ)
|
1770
|
+
sage: g = copy(f) # indirect doctest
|
1771
|
+
sage: g == f
|
1772
|
+
True
|
1773
|
+
sage: g(5) == f(5)
|
1774
|
+
True
|
1775
|
+
sage: g(0) == f(0)
|
1776
|
+
True
|
1777
|
+
"""
|
1778
|
+
self.p = _slots['p']
|
1779
|
+
RingHomomorphism._update_slots(self, _slots)
|
1780
|
+
|
1781
|
+
cpdef Element _call_(self, _x):
|
1782
|
+
"""
|
1783
|
+
Applies the coercion.
|
1784
|
+
|
1785
|
+
EXAMPLES::
|
1786
|
+
|
1787
|
+
sage: R.<t> = GF(5)[]
|
1788
|
+
sage: K = R.fraction_field()
|
1789
|
+
sage: f = K.coerce_map_from(ZZ)
|
1790
|
+
sage: f(3) # indirect doctest
|
1791
|
+
3
|
1792
|
+
"""
|
1793
|
+
cdef Integer x = <Integer?> _x
|
1794
|
+
cdef FpTElement ans = <FpTElement>FpTElement.__new__(FpTElement)
|
1795
|
+
ans._parent = self.codomain()
|
1796
|
+
ans.p = self.p
|
1797
|
+
nmod_poly_init(ans._numer, ans.p)
|
1798
|
+
nmod_poly_init(ans._denom, ans.p)
|
1799
|
+
nmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p))
|
1800
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
|
1801
|
+
ans.initialized = True
|
1802
|
+
return ans
|
1803
|
+
|
1804
|
+
cpdef Element _call_with_args(self, _x, args=(), kwds={}):
|
1805
|
+
"""
|
1806
|
+
This function allows the map to take multiple arguments, usually used to specify both numerator and denominator.
|
1807
|
+
|
1808
|
+
If ``reduce`` is specified as False, then the result won't be normalized.
|
1809
|
+
|
1810
|
+
EXAMPLES::
|
1811
|
+
|
1812
|
+
sage: R.<t> = GF(5)[]
|
1813
|
+
sage: K = R.fraction_field()
|
1814
|
+
sage: f = K.coerce_map_from(ZZ)
|
1815
|
+
sage: f(1, t + 3) # indirect doctest
|
1816
|
+
1/(t + 3)
|
1817
|
+
sage: f(1,2)
|
1818
|
+
3
|
1819
|
+
sage: f(2, 2*t)
|
1820
|
+
1/t
|
1821
|
+
sage: f(2, 2*t, reduce=False)
|
1822
|
+
2/2*t
|
1823
|
+
"""
|
1824
|
+
cdef Integer x = <Integer?> _x
|
1825
|
+
cdef FpTElement ans = <FpTElement>FpTElement.__new__(FpTElement)
|
1826
|
+
ans._parent = self.codomain()
|
1827
|
+
ans.p = self.p
|
1828
|
+
nmod_poly_init(ans._numer, ans.p)
|
1829
|
+
nmod_poly_init(ans._denom, ans.p)
|
1830
|
+
cdef long r
|
1831
|
+
nmod_poly_set_coeff_ui(ans._numer, 0, mpz_fdiv_ui(x.value, self.p))
|
1832
|
+
if len(args) == 0:
|
1833
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, 1)
|
1834
|
+
if len(args) == 1:
|
1835
|
+
y = args[0]
|
1836
|
+
if isinstance(y, Integer):
|
1837
|
+
r = mpz_fdiv_ui((<Integer>y).value, self.p)
|
1838
|
+
if r == 0:
|
1839
|
+
raise ZeroDivisionError
|
1840
|
+
nmod_poly_set_coeff_ui(ans._denom, 0, r)
|
1841
|
+
else:
|
1842
|
+
R = ans._parent.ring_of_integers()
|
1843
|
+
# could use the coerce keyword being set to False to not check this...
|
1844
|
+
if not (isinstance(y, Element) and y.parent() is R):
|
1845
|
+
# We could special case integers and GF(p) elements here.
|
1846
|
+
y = R(y)
|
1847
|
+
nmod_poly_set(ans._denom, &((<Polynomial_zmod_flint?>y).x))
|
1848
|
+
else:
|
1849
|
+
raise ValueError("FpT only supports two positional arguments")
|
1850
|
+
if 'reduce' not in kwds or kwds['reduce']:
|
1851
|
+
normalize(ans._numer, ans._denom, ans.p)
|
1852
|
+
ans.initialized = True
|
1853
|
+
return ans
|
1854
|
+
|
1855
|
+
def section(self):
|
1856
|
+
"""
|
1857
|
+
Return the section of this inclusion: the partially defined map from ``GF(p)(t)``
|
1858
|
+
back to ``ZZ``, defined on constant elements.
|
1859
|
+
|
1860
|
+
EXAMPLES::
|
1861
|
+
|
1862
|
+
sage: R.<t> = GF(5)[]
|
1863
|
+
sage: K = R.fraction_field()
|
1864
|
+
sage: f = K.coerce_map_from(ZZ)
|
1865
|
+
sage: g = f.section(); g
|
1866
|
+
Composite map:
|
1867
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1868
|
+
To: Integer Ring
|
1869
|
+
Defn: Section map:
|
1870
|
+
From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
|
1871
|
+
To: Finite Field of size 5
|
1872
|
+
then
|
1873
|
+
Lifting map:
|
1874
|
+
From: Finite Field of size 5
|
1875
|
+
To: Integer Ring
|
1876
|
+
sage: t = K.gen()
|
1877
|
+
sage: g(f(1,3,reduce=False))
|
1878
|
+
2
|
1879
|
+
sage: g(t)
|
1880
|
+
Traceback (most recent call last):
|
1881
|
+
...
|
1882
|
+
ValueError: not constant
|
1883
|
+
sage: g(1/t)
|
1884
|
+
Traceback (most recent call last):
|
1885
|
+
...
|
1886
|
+
ValueError: not integral
|
1887
|
+
"""
|
1888
|
+
return ZZ.convert_map_from(self.codomain().base_ring()) * Fp_FpT_coerce(self.codomain()).section()
|
1889
|
+
|
1890
|
+
cdef inline bint normalize(nmod_poly_t numer, nmod_poly_t denom, long p) noexcept:
|
1891
|
+
"""
|
1892
|
+
Put ``numer`` / ``denom`` into a normal form: denominator monic and sharing no common factor with the numerator.
|
1893
|
+
|
1894
|
+
The normalized form of 0 is 0/1.
|
1895
|
+
|
1896
|
+
Return ``True`` if ``numer`` and ``denom`` were changed.
|
1897
|
+
"""
|
1898
|
+
cdef long a
|
1899
|
+
cdef bint changed
|
1900
|
+
if nmod_poly_degree(numer) == -1:
|
1901
|
+
if nmod_poly_degree(denom) > 0 or nmod_poly_leading(denom) != 1:
|
1902
|
+
changed = True
|
1903
|
+
else:
|
1904
|
+
changed = False
|
1905
|
+
nmod_poly_truncate(denom, 0)
|
1906
|
+
nmod_poly_set_coeff_ui(denom, 0, 1)
|
1907
|
+
return changed
|
1908
|
+
elif nmod_poly_degree(numer) == 0 or nmod_poly_degree(denom) == 0:
|
1909
|
+
if nmod_poly_leading(denom) != 1:
|
1910
|
+
a = mod_inverse_int(nmod_poly_leading(denom), p)
|
1911
|
+
nmod_poly_scalar_mul_nmod(numer, numer, a)
|
1912
|
+
nmod_poly_scalar_mul_nmod(denom, denom, a)
|
1913
|
+
return True
|
1914
|
+
return False
|
1915
|
+
cdef nmod_poly_t g
|
1916
|
+
changed = False
|
1917
|
+
try:
|
1918
|
+
nmod_poly_init_preinv(g, p, numer.mod.ninv)
|
1919
|
+
nmod_poly_gcd(g, numer, denom)
|
1920
|
+
if nmod_poly_degree(g) != 0:
|
1921
|
+
# Divide knowing divisible by? Can we get these quotients as a byproduct of the gcd?
|
1922
|
+
nmod_poly_div(numer, numer, g)
|
1923
|
+
nmod_poly_div(denom, denom, g)
|
1924
|
+
changed = True
|
1925
|
+
if nmod_poly_leading(denom) != 1:
|
1926
|
+
a = mod_inverse_int(nmod_poly_leading(denom), p)
|
1927
|
+
nmod_poly_scalar_mul_nmod(numer, numer, a)
|
1928
|
+
nmod_poly_scalar_mul_nmod(denom, denom, a)
|
1929
|
+
changed = True
|
1930
|
+
return changed
|
1931
|
+
finally:
|
1932
|
+
nmod_poly_clear(g)
|
1933
|
+
|
1934
|
+
|
1935
|
+
cdef inline unsigned long nmod_poly_leading(nmod_poly_t poly) noexcept:
|
1936
|
+
"""
|
1937
|
+
Return the leading coefficient of ``poly``.
|
1938
|
+
"""
|
1939
|
+
return nmod_poly_get_coeff_ui(poly, nmod_poly_degree(poly))
|
1940
|
+
|
1941
|
+
|
1942
|
+
cdef inline void nmod_poly_inc(nmod_poly_t poly, bint monic) noexcept:
|
1943
|
+
"""
|
1944
|
+
Set poly to the "next" polynomial: this is just counting in base p.
|
1945
|
+
|
1946
|
+
If monic is ``True`` then will only iterate through monic polynomials.
|
1947
|
+
"""
|
1948
|
+
cdef long n
|
1949
|
+
cdef long a
|
1950
|
+
cdef long p = poly.mod.n
|
1951
|
+
for n from 0 <= n <= nmod_poly_degree(poly) + 1:
|
1952
|
+
a = nmod_poly_get_coeff_ui(poly, n) + 1
|
1953
|
+
if a == p:
|
1954
|
+
nmod_poly_set_coeff_ui(poly, n, 0)
|
1955
|
+
else:
|
1956
|
+
nmod_poly_set_coeff_ui(poly, n, a)
|
1957
|
+
break
|
1958
|
+
if monic and a == 2 and n == nmod_poly_degree(poly):
|
1959
|
+
nmod_poly_set_coeff_ui(poly, n, 0)
|
1960
|
+
nmod_poly_set_coeff_ui(poly, n + 1, 1)
|
1961
|
+
|
1962
|
+
|
1963
|
+
cdef inline long nmod_poly_cmp(nmod_poly_t a, nmod_poly_t b) noexcept:
|
1964
|
+
"""
|
1965
|
+
Compare `a` and `b`, returning 0 if they are equal.
|
1966
|
+
|
1967
|
+
- If the degree of `a` is less than that of `b`, returns `-1`.
|
1968
|
+
|
1969
|
+
- If the degree of `b` is less than that of `a`, returns `1`.
|
1970
|
+
|
1971
|
+
- Otherwise, compares `a` and `b` lexicographically, starting at the leading terms.
|
1972
|
+
"""
|
1973
|
+
cdef long ad = nmod_poly_degree(a)
|
1974
|
+
cdef long bd = nmod_poly_degree(b)
|
1975
|
+
if ad < bd:
|
1976
|
+
return -1
|
1977
|
+
elif ad > bd:
|
1978
|
+
return 1
|
1979
|
+
cdef long d = nmod_poly_degree(a)
|
1980
|
+
while d >= 0:
|
1981
|
+
ad = nmod_poly_get_coeff_ui(a, d)
|
1982
|
+
bd = nmod_poly_get_coeff_ui(b, d)
|
1983
|
+
if ad < bd:
|
1984
|
+
return -1
|
1985
|
+
elif ad > bd:
|
1986
|
+
return 1
|
1987
|
+
d -= 1
|
1988
|
+
return 0
|
1989
|
+
|
1990
|
+
|
1991
|
+
cdef bint nmod_poly_sqrt_check(nmod_poly_t poly) noexcept:
|
1992
|
+
"""
|
1993
|
+
Quick check to see if ``poly`` could possibly be a square.
|
1994
|
+
"""
|
1995
|
+
# We could use Sage's jacobi_int which is for 32 bits integers rather
|
1996
|
+
# than FLINT's n_jacobi which is for longs as the FpT class is crafted
|
1997
|
+
# for primes 2 < p < 2^16
|
1998
|
+
return (nmod_poly_degree(poly) % 2 == 0
|
1999
|
+
and n_jacobi(nmod_poly_leading(poly), poly.mod.n) == 1
|
2000
|
+
and n_jacobi(nmod_poly_get_coeff_ui(poly, 0), poly.mod.n) != -1)
|
2001
|
+
|
2002
|
+
|
2003
|
+
def unpickle_FpT_element(K, numer, denom):
|
2004
|
+
"""
|
2005
|
+
Used for pickling.
|
2006
|
+
|
2007
|
+
TESTS::
|
2008
|
+
|
2009
|
+
sage: from sage.rings.fraction_field_FpT import unpickle_FpT_element
|
2010
|
+
sage: R.<t> = GF(13)['t']
|
2011
|
+
sage: unpickle_FpT_element(Frac(R), t+1, t)
|
2012
|
+
(t + 1)/t
|
2013
|
+
"""
|
2014
|
+
return FpTElement(K, numer, denom, coerce=False, reduce=False)
|
2015
|
+
|
2016
|
+
|
2017
|
+
# Somehow this isn't in FLINT, evidently. It could be moved
|
2018
|
+
# elsewhere at some point.
|
2019
|
+
cdef int sage_cmp_nmod_poly_t(nmod_poly_t L, nmod_poly_t R) noexcept:
|
2020
|
+
"""
|
2021
|
+
Compare two ``nmod_poly_t`` in a Pythonic way, so this returns `-1`, `0`,
|
2022
|
+
or `1`, and is consistent.
|
2023
|
+
"""
|
2024
|
+
cdef int j
|
2025
|
+
cdef Py_ssize_t i
|
2026
|
+
|
2027
|
+
# First compare the degrees
|
2028
|
+
j = nmod_poly_degree(L) - nmod_poly_degree(R)
|
2029
|
+
if j < 0:
|
2030
|
+
return -1
|
2031
|
+
elif j > 0:
|
2032
|
+
return 1
|
2033
|
+
|
2034
|
+
# Same degree, so compare coefficients, term by term
|
2035
|
+
for i in range(nmod_poly_degree(L) + 1):
|
2036
|
+
j = nmod_poly_get_coeff_ui(L, i) - nmod_poly_get_coeff_ui(R, i)
|
2037
|
+
if j < 0:
|
2038
|
+
return -1
|
2039
|
+
elif j > 0:
|
2040
|
+
return 1
|
2041
|
+
|
2042
|
+
# Two polynomials are equal
|
2043
|
+
return 0
|