passagemath-flint 10.6.1rc10__cp311-cp311-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-311-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-311-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-311-aarch64-linux-gnu.so +0 -0
- sage/graphs/chrompoly.pyx +555 -0
- sage/graphs/matchpoly.cpython-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-aarch64-linux-gnu.so +0 -0
- sage/matrix/change_ring.pyx +43 -0
- sage/matrix/matrix_complex_ball_dense.cpython-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-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-311-aarch64-linux-gnu.so +0 -0
- sage/rings/factorint_flint.pyx +99 -0
- sage/rings/fraction_field_FpT.cpython-311-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-311-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-311-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-311-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-311-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-311-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/hilbert.pyx +602 -0
- sage/rings/polynomial/polynomial_complex_arb.cpython-311-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-311-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-311-aarch64-linux-gnu.so +0 -0
- sage/rings/polynomial/polynomial_number_field.pyx +345 -0
- sage/rings/polynomial/polynomial_rational_flint.cpython-311-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-311-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-311-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-311-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-311-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-311-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-311-aarch64-linux-gnu.so +0 -0
- sage/rings/real_interval_absolute.pyx +1073 -0
- sage/rings/real_mpfi.cpython-311-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-311-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,3185 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-flint
|
2
|
+
# distutils: libraries = 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
|
+
# sage.doctest: needs sage.rings.number_field
|
9
|
+
r"""
|
10
|
+
Elements optimized for quadratic number fields
|
11
|
+
|
12
|
+
This module defines a Cython class :class:`NumberFieldElement_quadratic` to speed up
|
13
|
+
computations in quadratic extensions of `\QQ`.
|
14
|
+
|
15
|
+
.. TODO::
|
16
|
+
|
17
|
+
The ``_new()`` method should be overridden in this class to copy the ``D``
|
18
|
+
and ``standard_embedding`` attributes.
|
19
|
+
|
20
|
+
AUTHORS:
|
21
|
+
|
22
|
+
- Robert Bradshaw (2007-09): initial version
|
23
|
+
- David Harvey (2007-10): fixed up a few bugs, polish around the edges
|
24
|
+
- David Loeffler (2009-05): added more documentation and tests
|
25
|
+
- Vincent Delecroix (2012-07): added comparisons for quadratic number fields
|
26
|
+
(:issue:`13213`), abs, floor and ceil functions (:issue:`13256`)
|
27
|
+
"""
|
28
|
+
# ****************************************************************************
|
29
|
+
# Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu>
|
30
|
+
#
|
31
|
+
# This program is free software: you can redistribute it and/or modify
|
32
|
+
# it under the terms of the GNU General Public License as published by
|
33
|
+
# the Free Software Foundation, either version 2 of the License, or
|
34
|
+
# (at your option) any later version.
|
35
|
+
# https://www.gnu.org/licenses/
|
36
|
+
# ****************************************************************************
|
37
|
+
|
38
|
+
include "sage/libs/ntl/decl.pxi"
|
39
|
+
from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT
|
40
|
+
|
41
|
+
from cysignals.signals cimport sig_on, sig_off
|
42
|
+
|
43
|
+
from sage.libs.gmp.mpz cimport *
|
44
|
+
from sage.libs.gmp.mpq cimport *
|
45
|
+
from sage.libs.flint.fmpz cimport *
|
46
|
+
from sage.libs.flint.arb cimport *
|
47
|
+
from sage.libs.flint.acb cimport *
|
48
|
+
from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ
|
49
|
+
from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX
|
50
|
+
from sage.libs.mpfi cimport *
|
51
|
+
|
52
|
+
from sage.structure.parent cimport Parent
|
53
|
+
from sage.structure.element cimport Element
|
54
|
+
from sage.structure.richcmp cimport rich_to_bool_sgn
|
55
|
+
|
56
|
+
from sage.rings.rational cimport Rational
|
57
|
+
from sage.rings.integer_ring import ZZ
|
58
|
+
from sage.rings.rational_field import QQ
|
59
|
+
from sage.categories.morphism cimport Morphism
|
60
|
+
from sage.rings.number_field.number_field_element import _inverse_mod_generic
|
61
|
+
from sage.rings.real_mpfi cimport RealIntervalField_class
|
62
|
+
from sage.rings.complex_interval cimport ComplexIntervalFieldElement
|
63
|
+
from sage.rings.real_arb cimport RealBall
|
64
|
+
from sage.rings.complex_arb cimport ComplexBall
|
65
|
+
|
66
|
+
from sage.libs.gmp.pylong cimport mpz_pythonhash
|
67
|
+
|
68
|
+
|
69
|
+
def __make_NumberFieldElement_quadratic0(parent, a, b, denom):
|
70
|
+
"""
|
71
|
+
Used in unpickling elements of number fields.
|
72
|
+
|
73
|
+
TESTS::
|
74
|
+
|
75
|
+
sage: x = polygen(ZZ, 'x')
|
76
|
+
sage: K.<a> = NumberField(x^2 - x + 13)
|
77
|
+
sage: loads(dumps(a)) == a # indirect doctest
|
78
|
+
True
|
79
|
+
"""
|
80
|
+
return NumberFieldElement_quadratic(parent, (a, b, denom))
|
81
|
+
|
82
|
+
|
83
|
+
def __make_NumberFieldElement_quadratic1(parent, cls, a, b, denom):
|
84
|
+
"""
|
85
|
+
Used in unpickling elements of number fields.
|
86
|
+
|
87
|
+
TESTS::
|
88
|
+
|
89
|
+
sage: x = polygen(ZZ, 'x')
|
90
|
+
sage: K.<a> = NumberField(x^2 - x + 13)
|
91
|
+
sage: loads(dumps(a)) == a # indirect doctest
|
92
|
+
True
|
93
|
+
|
94
|
+
We test that :issue:`6462` is fixed::
|
95
|
+
|
96
|
+
sage: L = QuadraticField(-11,'a'); OL = L.maximal_order(); w = OL.0
|
97
|
+
sage: loads(dumps(w)) == w # indirect doctest
|
98
|
+
True
|
99
|
+
"""
|
100
|
+
return cls(parent, (a, b, denom))
|
101
|
+
|
102
|
+
|
103
|
+
cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute):
|
104
|
+
r"""
|
105
|
+
A :class:`NumberFieldElement_quadratic` object gives an efficient representation of
|
106
|
+
an element of a quadratic extension of `\QQ`.
|
107
|
+
|
108
|
+
Elements are represented internally as triples `(a, b, c)` of integers,
|
109
|
+
where `\gcd(a, b, c) = 1` and `c > 0`, representing the element `(a +
|
110
|
+
b \sqrt{D}) / c`. Note that if the discriminant `D` is `1 \bmod 4`,
|
111
|
+
integral elements do not necessarily have `c = 1`.
|
112
|
+
|
113
|
+
TESTS::
|
114
|
+
|
115
|
+
sage: from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic
|
116
|
+
sage: from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic_sqrt
|
117
|
+
|
118
|
+
We set up some fields::
|
119
|
+
|
120
|
+
sage: x = polygen(ZZ, 'x')
|
121
|
+
sage: K.<a> = NumberField(x^2 + 23)
|
122
|
+
sage: a.parts()
|
123
|
+
(0, 1)
|
124
|
+
sage: F.<b> = NumberField(x^2 - x + 7)
|
125
|
+
sage: b.parts()
|
126
|
+
(1/2, 3/2)
|
127
|
+
|
128
|
+
We construct elements of these fields in various ways -- firstly, from
|
129
|
+
polynomials::
|
130
|
+
|
131
|
+
sage: NumberFieldElement_quadratic_sqrt(K, x - 1)
|
132
|
+
a - 1
|
133
|
+
sage: NumberFieldElement_quadratic(F, x - 1)
|
134
|
+
b - 1
|
135
|
+
|
136
|
+
From triples of Integers::
|
137
|
+
|
138
|
+
sage: NumberFieldElement_quadratic_sqrt(K, (1,2,3))
|
139
|
+
2/3*a + 1/3
|
140
|
+
sage: NumberFieldElement_quadratic(F, (1,2,3))
|
141
|
+
4/9*b + 1/9
|
142
|
+
sage: NumberFieldElement_quadratic(F, (1,2,3)).parts()
|
143
|
+
(1/3, 2/3)
|
144
|
+
|
145
|
+
From pairs of Rationals::
|
146
|
+
|
147
|
+
sage: NumberFieldElement_quadratic_sqrt(K, (1/2, 1/3))
|
148
|
+
1/3*a + 1/2
|
149
|
+
sage: NumberFieldElement_quadratic(F, (1/2, 1/3))
|
150
|
+
2/9*b + 7/18
|
151
|
+
sage: NumberFieldElement_quadratic(F, (1/2, 1/3)).parts()
|
152
|
+
(1/2, 1/3)
|
153
|
+
|
154
|
+
Direct from Rationals::
|
155
|
+
|
156
|
+
sage: NumberFieldElement_quadratic_sqrt(K, 2/3)
|
157
|
+
2/3
|
158
|
+
sage: NumberFieldElement_quadratic(F, 2/3)
|
159
|
+
2/3
|
160
|
+
|
161
|
+
This checks a bug when converting from lists::
|
162
|
+
|
163
|
+
sage: w = CyclotomicField(3)([1/2, 1])
|
164
|
+
sage: w == w.__invert__().__invert__()
|
165
|
+
True
|
166
|
+
"""
|
167
|
+
|
168
|
+
def __init__(self, parent, f):
|
169
|
+
"""
|
170
|
+
Standard initialisation function.
|
171
|
+
|
172
|
+
EXAMPLES::
|
173
|
+
|
174
|
+
sage: F.<a> = QuadraticField(-7)
|
175
|
+
sage: c = a + 7
|
176
|
+
sage: type(c) # indirect doctest
|
177
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_quadratic_sqrt'>
|
178
|
+
"""
|
179
|
+
self.D = parent._D
|
180
|
+
cdef Integer a, b, denom
|
181
|
+
cdef Rational ad, bd
|
182
|
+
|
183
|
+
cdef NumberFieldElement_quadratic gen
|
184
|
+
|
185
|
+
if isinstance(f, NumberFieldElement_quadratic):
|
186
|
+
self._parent = parent # NOTE: We do *not* call NumberFieldElement_absolute.__init__, for speed reasons.
|
187
|
+
mpz_set(self.a, (<NumberFieldElement_quadratic>f).a)
|
188
|
+
mpz_set(self.b, (<NumberFieldElement_quadratic>f).b)
|
189
|
+
mpz_set(self.denom, (<NumberFieldElement_quadratic>f).denom)
|
190
|
+
|
191
|
+
elif type(f) is tuple and len(f) == 2:
|
192
|
+
NumberFieldElement_absolute.__init__(self, parent, None)
|
193
|
+
ad, bd = f
|
194
|
+
mpz_lcm(self.denom, mpq_denref(ad.value), mpq_denref(bd.value))
|
195
|
+
mpz_divexact(self.a, self.denom, mpq_denref(ad.value))
|
196
|
+
mpz_mul(self.a, self.a, mpq_numref(ad.value))
|
197
|
+
mpz_divexact(self.b, self.denom, mpq_denref(bd.value))
|
198
|
+
mpz_mul(self.b, self.b, mpq_numref(bd.value))
|
199
|
+
|
200
|
+
elif type(f) is tuple and len(f) == 3:
|
201
|
+
NumberFieldElement_absolute.__init__(self, parent, None)
|
202
|
+
a, b, denom = f
|
203
|
+
mpz_set(self.a, a.value)
|
204
|
+
mpz_set(self.b, b.value)
|
205
|
+
mpz_set(self.denom, denom.value)
|
206
|
+
self._reduce_c_()
|
207
|
+
|
208
|
+
else:
|
209
|
+
NumberFieldElement_absolute.__init__(self, parent, f)
|
210
|
+
# poly is in gen (which may not be sqrt(d))
|
211
|
+
self._ntl_coeff_as_mpz(self.a, 0)
|
212
|
+
self._ntl_coeff_as_mpz(self.b, 1)
|
213
|
+
if mpz_cmp_ui(self.a, 0) or mpz_cmp_ui(self.b, 0):
|
214
|
+
gen = parent.gen() # should this be cached?
|
215
|
+
self._ntl_denom_as_mpz(self.denom)
|
216
|
+
if mpz_cmp_ui(self.b, 0):
|
217
|
+
mpz_mul(self.a, self.a, gen.denom)
|
218
|
+
mpz_addmul(self.a, self.b, gen.a)
|
219
|
+
mpz_mul(self.b, self.b, gen.b)
|
220
|
+
mpz_mul(self.denom, self.denom, gen.denom)
|
221
|
+
else:
|
222
|
+
mpz_set_ui(self.denom, 1)
|
223
|
+
self._reduce_c_()
|
224
|
+
|
225
|
+
# set the attribute standard embedding which is used in the methods
|
226
|
+
# __cmp__, sign, real, imag, floor, ceil, ...
|
227
|
+
self.standard_embedding = parent._standard_embedding
|
228
|
+
|
229
|
+
cdef _new(self):
|
230
|
+
"""
|
231
|
+
Quickly create a new initialized NumberFieldElement_quadratic with the
|
232
|
+
same parent as ``self``.
|
233
|
+
|
234
|
+
EXAMPLES::
|
235
|
+
|
236
|
+
sage: F.<b> = CyclotomicField(3)
|
237
|
+
sage: b + b # indirect doctest
|
238
|
+
2*b
|
239
|
+
"""
|
240
|
+
cdef type t = type(self)
|
241
|
+
cdef NumberFieldElement_quadratic x = <NumberFieldElement_quadratic>t.__new__(t)
|
242
|
+
x._parent = self._parent
|
243
|
+
x.standard_embedding = self.standard_embedding
|
244
|
+
x.D = self.D
|
245
|
+
return x
|
246
|
+
|
247
|
+
cdef number_field(self):
|
248
|
+
r"""
|
249
|
+
Return the number field to which this element belongs. Since this is a
|
250
|
+
Cython cdef method, it is not directly accessible by the user, but the
|
251
|
+
function "_number_field" calls this one.
|
252
|
+
|
253
|
+
EXAMPLES::
|
254
|
+
|
255
|
+
sage: F.<b> = QuadraticField(-7)
|
256
|
+
sage: b._number_field() # indirect doctest
|
257
|
+
Number Field in b with defining polynomial x^2 + 7 with b = 2.645751311064591?*I
|
258
|
+
"""
|
259
|
+
return self._parent
|
260
|
+
|
261
|
+
def _maxima_init_(self, I=None):
|
262
|
+
"""
|
263
|
+
EXAMPLES::
|
264
|
+
|
265
|
+
sage: K.<a> = QuadraticField(-1)
|
266
|
+
sage: (1 + a)._maxima_init_()
|
267
|
+
'1+%i*1'
|
268
|
+
sage: (1+3*a)._fricas_init_()
|
269
|
+
'1+%i*3'
|
270
|
+
|
271
|
+
sage: K.<J> = QuadraticField(-1, embedding=CC(0,-1))
|
272
|
+
sage: J._maxima_init_()
|
273
|
+
Traceback (most recent call last):
|
274
|
+
...
|
275
|
+
NotImplementedError: conversion implemented only for elements of quadratic fields with discriminant -1 and standard embedding
|
276
|
+
|
277
|
+
sage: K.<sqrt2> = QuadraticField(2, embedding=AA(2))
|
278
|
+
sage: sqrt2._maxima_init_()
|
279
|
+
Traceback (most recent call last):
|
280
|
+
...
|
281
|
+
NotImplementedError: conversion implemented only for elements of quadratic fields with discriminant -1 and standard embedding
|
282
|
+
"""
|
283
|
+
a = self.parent().gen()
|
284
|
+
if a**2 == -1 and self.standard_embedding:
|
285
|
+
x0, x1 = self
|
286
|
+
return str(x0) + "+" + "%i*" + str(x1)
|
287
|
+
raise NotImplementedError("conversion implemented only for elements of quadratic fields with discriminant -1 and standard embedding")
|
288
|
+
|
289
|
+
# by coincidence, maxima and fricas both use %i for the imaginary unit I
|
290
|
+
_fricas_init_ = _maxima_init_
|
291
|
+
|
292
|
+
def _sympy_(self):
|
293
|
+
"""
|
294
|
+
Convert this number to Sympy.
|
295
|
+
|
296
|
+
EXAMPLES::
|
297
|
+
|
298
|
+
sage: K.<a> = QuadraticField(-1)
|
299
|
+
sage: (1/3 + a/2)._sympy_() # needs sympy
|
300
|
+
1/3 + I/2
|
301
|
+
sage: type(_) # needs sympy
|
302
|
+
<class 'sympy.core.add.Add'>
|
303
|
+
"""
|
304
|
+
a = self.parent().gen()
|
305
|
+
if a**2 == -1 and self.standard_embedding:
|
306
|
+
x0, x1 = self
|
307
|
+
import sympy
|
308
|
+
return x0._sympy_() + x1._sympy_() * sympy.I
|
309
|
+
raise NotImplementedError(
|
310
|
+
"conversion implemented only for elements of quadratic "
|
311
|
+
"fields with discriminant -1 and standard embedding")
|
312
|
+
|
313
|
+
def _polymake_init_(self):
|
314
|
+
"""
|
315
|
+
EXAMPLES::
|
316
|
+
|
317
|
+
sage: K.<sqrt5> = QuadraticField(5)
|
318
|
+
sage: polymake(3 + 2*sqrt5) # optional - jupymake
|
319
|
+
3+2r5
|
320
|
+
sage: polymake(2**100/7 - 2*sqrt5/3**50) # optional - jupymake
|
321
|
+
1267650600228229401496703205376/7-2/717897987691852588770249r5
|
322
|
+
sage: K.<i> = QuadraticField(-1)
|
323
|
+
sage: polymake(i) # optional - jupymake
|
324
|
+
Traceback (most recent call last):
|
325
|
+
...
|
326
|
+
TypeError: Negative values for the root of the extension ... Bad Thing...
|
327
|
+
|
328
|
+
TESTS:
|
329
|
+
|
330
|
+
Test that :issue:`28377` is fixed::
|
331
|
+
|
332
|
+
sage: x = polygen(QQ, 'x')
|
333
|
+
sage: K = NumberField(x^2 - x -1, 'a', embedding=(1-AA(5).sqrt())/2)
|
334
|
+
sage: L = NumberField(x^2 - x -1, 'a', embedding=(1+AA(5).sqrt())/2)
|
335
|
+
sage: polymake(K.gen()) # optional - jupymake
|
336
|
+
1/2-1/2r5
|
337
|
+
sage: polymake(L.gen()) # optional - jupymake
|
338
|
+
1/2+1/2r5
|
339
|
+
"""
|
340
|
+
cdef Integer a = Integer.__new__(Integer)
|
341
|
+
cdef Integer b = Integer.__new__(Integer)
|
342
|
+
cdef Integer denom
|
343
|
+
mpz_set(a.value, self.a)
|
344
|
+
mpz_set(b.value, self.b)
|
345
|
+
if not self.standard_embedding:
|
346
|
+
mpz_neg(b.value, b.value)
|
347
|
+
if mpz_cmp_ui(self.denom, 1) == 0:
|
348
|
+
return "new QuadraticExtension({}, {}, {})".format(a, b, self.D)
|
349
|
+
else:
|
350
|
+
denom = Integer.__new__(Integer)
|
351
|
+
mpz_set(denom.value, self.denom)
|
352
|
+
return "new QuadraticExtension({}, {}, {})".format(a/denom, b/denom, self.D)
|
353
|
+
|
354
|
+
cpdef _copy_for_parent(self, Parent parent):
|
355
|
+
r"""
|
356
|
+
Return a copy of ``self`` with the parent replaced by ``parent``.
|
357
|
+
|
358
|
+
EXAMPLES::
|
359
|
+
|
360
|
+
sage: K.<a> = QuadraticField(3)
|
361
|
+
sage: L.<b> = K.change_names()
|
362
|
+
sage: La = a._copy_for_parent(L)
|
363
|
+
sage: La.parent() is L
|
364
|
+
True
|
365
|
+
sage: La == b
|
366
|
+
True
|
367
|
+
"""
|
368
|
+
cdef NumberFieldElement_quadratic x = <NumberFieldElement_quadratic>self._new()
|
369
|
+
mpz_set(x.a, self.a)
|
370
|
+
mpz_set(x.b, self.b)
|
371
|
+
mpz_set(x.denom, self.denom)
|
372
|
+
x._set_parent(parent)
|
373
|
+
return x
|
374
|
+
|
375
|
+
def __copy__(self):
|
376
|
+
r"""
|
377
|
+
TESTS::
|
378
|
+
|
379
|
+
sage: K.<a> = QuadraticField(-3)
|
380
|
+
sage: b = a + 3
|
381
|
+
sage: c = b.__copy__()
|
382
|
+
sage: b is c
|
383
|
+
True
|
384
|
+
"""
|
385
|
+
# immutable
|
386
|
+
return self
|
387
|
+
|
388
|
+
def __deepcopy__(self, memo):
|
389
|
+
r"""
|
390
|
+
TESTS::
|
391
|
+
|
392
|
+
sage: K.<a> = QuadraticField(-3)
|
393
|
+
sage: b = a + 3
|
394
|
+
sage: c = deepcopy(b)
|
395
|
+
sage: b is c
|
396
|
+
True
|
397
|
+
"""
|
398
|
+
# immutable
|
399
|
+
return self
|
400
|
+
|
401
|
+
def __cinit__(self):
|
402
|
+
r"""
|
403
|
+
Initialisation function.
|
404
|
+
|
405
|
+
EXAMPLES::
|
406
|
+
|
407
|
+
sage: QuadraticField(-3, 'a').gen() # indirect doctest
|
408
|
+
a
|
409
|
+
"""
|
410
|
+
mpz_init(self.a)
|
411
|
+
mpz_init(self.b)
|
412
|
+
mpz_init(self.denom)
|
413
|
+
|
414
|
+
def __dealloc__(self):
|
415
|
+
mpz_clear(self.a)
|
416
|
+
mpz_clear(self.b)
|
417
|
+
mpz_clear(self.denom)
|
418
|
+
|
419
|
+
def __reduce__(self):
|
420
|
+
"""
|
421
|
+
Used for pickling.
|
422
|
+
|
423
|
+
TESTS::
|
424
|
+
|
425
|
+
sage: x = polygen(ZZ, 'x')
|
426
|
+
sage: K.<a> = NumberField(x^2 - 13)
|
427
|
+
sage: loads(dumps(a)) == a
|
428
|
+
True
|
429
|
+
sage: loads(dumps(a/3+5)) == a/3+5
|
430
|
+
True
|
431
|
+
"""
|
432
|
+
cdef Integer a = Integer.__new__(Integer)
|
433
|
+
cdef Integer b = Integer.__new__(Integer)
|
434
|
+
cdef Integer denom = Integer.__new__(Integer)
|
435
|
+
mpz_set(a.value, self.a)
|
436
|
+
mpz_set(b.value, self.b)
|
437
|
+
mpz_set(denom.value, self.denom)
|
438
|
+
return __make_NumberFieldElement_quadratic1, (self._parent, type(self), a, b, denom)
|
439
|
+
|
440
|
+
cdef int _randomize(self, num_bound, den_bound, distribution) except -1:
|
441
|
+
"""
|
442
|
+
TESTS::
|
443
|
+
|
444
|
+
sage: a = ZZ.random_element(-100, 100)
|
445
|
+
sage: while a.is_square():
|
446
|
+
....: a = ZZ.random_element(-100, 100)
|
447
|
+
sage: K = QuadraticField(a)
|
448
|
+
sage: K.random_element().parent() is K # indirect doctest
|
449
|
+
True
|
450
|
+
sage: len(set(K.random_element() for _ in range(100))) >= 40
|
451
|
+
True
|
452
|
+
|
453
|
+
Verify that :issue:`30017` is fixed::
|
454
|
+
|
455
|
+
sage: all(K.random_element().is_integral() for s in range(100))
|
456
|
+
False
|
457
|
+
"""
|
458
|
+
cdef Integer temp, denom1, denom2
|
459
|
+
|
460
|
+
# in theory, we could just generate two random numerators and
|
461
|
+
# a random denominator. however, this would mean that we were
|
462
|
+
# extraordinarily unlikely to run into results of the form
|
463
|
+
# 1/3 + 1/5*sqrt(D), which are often some of the best examples
|
464
|
+
# for testing out code. since this is probably the primary use
|
465
|
+
# of the random element code, it's worth doing slightly more
|
466
|
+
# work to make this possible.
|
467
|
+
|
468
|
+
# generate denominators
|
469
|
+
if den_bound is None:
|
470
|
+
denom1 = <Integer>(1 + abs(ZZ.random_element(distribution=distribution)))
|
471
|
+
denom2 = <Integer>(1 + abs(ZZ.random_element(distribution=distribution)))
|
472
|
+
else:
|
473
|
+
# normalize denominator bound
|
474
|
+
if den_bound < 1:
|
475
|
+
den_bound = 1
|
476
|
+
denom1 = <Integer>(ZZ.random_element(x=1,
|
477
|
+
y=den_bound+1,
|
478
|
+
distribution=distribution))
|
479
|
+
denom2 = <Integer>(ZZ.random_element(x=1,
|
480
|
+
y=den_bound+1,
|
481
|
+
distribution=distribution))
|
482
|
+
|
483
|
+
# set a, b
|
484
|
+
temp = <Integer>(ZZ.random_element(x=num_bound, distribution=distribution))
|
485
|
+
mpz_mul(self.a, temp.value, denom2.value)
|
486
|
+
temp = <Integer>(ZZ.random_element(x=num_bound, distribution=distribution))
|
487
|
+
mpz_mul(self.b, temp.value, denom1.value)
|
488
|
+
# set denom
|
489
|
+
mpz_mul(self.denom, denom1.value, denom2.value)
|
490
|
+
|
491
|
+
self._reduce_c_()
|
492
|
+
return 0 # No error
|
493
|
+
|
494
|
+
def _lift_cyclotomic_element(self, new_parent, bint check=True, int rel=0):
|
495
|
+
"""
|
496
|
+
Create an element of the passed field from this field. This
|
497
|
+
is specific to creating elements in a cyclotomic field from
|
498
|
+
elements in another cyclotomic field, in the case that
|
499
|
+
self.number_field()._n() divides new_parent()._n(). This
|
500
|
+
function aims to make this common coercion extremely fast!
|
501
|
+
|
502
|
+
More general coercion (i.e. of zeta6 into CyclotomicField(3))
|
503
|
+
is implemented in the _coerce_from_other_cyclotomic_field
|
504
|
+
method of a CyclotomicField.
|
505
|
+
|
506
|
+
EXAMPLES::
|
507
|
+
|
508
|
+
sage: C.<zeta4>=CyclotomicField(4)
|
509
|
+
sage: CyclotomicField(20)(zeta4+1) # The function _lift_cyclotomic_element does the heavy lifting in the background
|
510
|
+
zeta20^5 + 1
|
511
|
+
sage: (zeta4+1)._lift_cyclotomic_element(CyclotomicField(40)) # There is rarely a purpose to call this function directly
|
512
|
+
zeta40^10 + 1
|
513
|
+
|
514
|
+
sage: cf3 = CyclotomicField(3) ; z3 = cf3.0
|
515
|
+
sage: cf6 = CyclotomicField(6) ; z6 = cf6.0
|
516
|
+
sage: z6._lift_cyclotomic_element(cf3)
|
517
|
+
Traceback (most recent call last):
|
518
|
+
...
|
519
|
+
TypeError: The zeta_order of the new field must be a multiple of the zeta_order of the original.
|
520
|
+
sage: cf3(z6)
|
521
|
+
zeta3 + 1
|
522
|
+
sage: z3._lift_cyclotomic_element(cf6)
|
523
|
+
zeta6 - 1
|
524
|
+
|
525
|
+
Verify embeddings are respected::
|
526
|
+
|
527
|
+
sage: cf6c = CyclotomicField(6, embedding=CDF(exp(-pi*I/3))); z6c = cf6c.0 # needs sage.symbolic
|
528
|
+
sage: cf3(z6c) # needs sage.symbolic
|
529
|
+
-zeta3
|
530
|
+
sage: cf6c(z3) # needs sage.symbolic
|
531
|
+
-zeta6
|
532
|
+
|
533
|
+
AUTHOR:
|
534
|
+
|
535
|
+
- Joel B. Mohler (original version)
|
536
|
+
|
537
|
+
- Craig Citro (reworked for quadratic elements)
|
538
|
+
"""
|
539
|
+
if check:
|
540
|
+
from sage.rings.number_field.number_field import NumberField_cyclotomic
|
541
|
+
if not isinstance(self.number_field(), NumberField_cyclotomic) \
|
542
|
+
or not isinstance(new_parent, NumberField_cyclotomic):
|
543
|
+
raise TypeError("The field and the new parent field must both be cyclotomic fields.")
|
544
|
+
|
545
|
+
if rel == 0:
|
546
|
+
small_order = self.number_field()._n()
|
547
|
+
large_order = new_parent._n()
|
548
|
+
|
549
|
+
try:
|
550
|
+
rel = ZZ(large_order / small_order)
|
551
|
+
except TypeError:
|
552
|
+
raise TypeError("The zeta_order of the new field must be a multiple of the zeta_order of the original.")
|
553
|
+
|
554
|
+
cdef NumberFieldElement_quadratic x2
|
555
|
+
cdef int n = self._parent._n()
|
556
|
+
|
557
|
+
if new_parent.degree() == 2:
|
558
|
+
## since self is a *quadratic* element, we can only get
|
559
|
+
## here if self.parent() and new_parent are:
|
560
|
+
## - CyclotomicField(3) and CyclotomicField(6)
|
561
|
+
## - CyclotomicField(3) and CyclotomicField(3)
|
562
|
+
## - CyclotomicField(6) and CyclotomicField(6)
|
563
|
+
## - CyclotomicField(4) and CyclotomicField(4)
|
564
|
+
## In all cases, conversion of elements is trivial!
|
565
|
+
if n == <int>new_parent._n():
|
566
|
+
conjugate = rel != 1
|
567
|
+
else:
|
568
|
+
# n = 3, new_n = 6
|
569
|
+
conjugate = rel == 4
|
570
|
+
x2 = <NumberFieldElement_quadratic>(self._new())
|
571
|
+
x2._parent = new_parent
|
572
|
+
mpz_set(x2.a, self.a)
|
573
|
+
if conjugate:
|
574
|
+
mpz_neg(x2.b, self.b)
|
575
|
+
else:
|
576
|
+
mpz_set(x2.b, self.b)
|
577
|
+
mpz_set(x2.denom, self.denom)
|
578
|
+
x2.D = self.D
|
579
|
+
return x2
|
580
|
+
|
581
|
+
cdef NumberFieldElement x
|
582
|
+
cdef ZZX_c elt_num
|
583
|
+
cdef ZZ_c elt_den, tmp_coeff
|
584
|
+
cdef mpz_t tmp_mpz
|
585
|
+
cdef long tmp_const
|
586
|
+
|
587
|
+
x = <NumberFieldElement_absolute>NumberFieldElement_absolute.__new__(NumberFieldElement_absolute)
|
588
|
+
|
589
|
+
mpz_to_ZZ(&elt_den, self.denom)
|
590
|
+
|
591
|
+
mpz_init(tmp_mpz)
|
592
|
+
|
593
|
+
## set the two terms in the polynomial
|
594
|
+
if n == 4:
|
595
|
+
mpz_to_ZZ(&tmp_coeff, self.a)
|
596
|
+
ZZX_SetCoeff(elt_num, 0, tmp_coeff)
|
597
|
+
mpz_to_ZZ(&tmp_coeff, self.b)
|
598
|
+
ZZX_SetCoeff(elt_num, 1, tmp_coeff)
|
599
|
+
|
600
|
+
elif n == 3:
|
601
|
+
## num[0] = a + b
|
602
|
+
mpz_add(tmp_mpz, tmp_mpz, self.a)
|
603
|
+
mpz_add(tmp_mpz, tmp_mpz, self.b)
|
604
|
+
mpz_to_ZZ(&tmp_coeff, tmp_mpz)
|
605
|
+
ZZX_SetCoeff(elt_num, 0, tmp_coeff)
|
606
|
+
|
607
|
+
## num[1] = 2*b
|
608
|
+
mpz_sub(tmp_mpz, tmp_mpz, self.a)
|
609
|
+
tmp_const = 2
|
610
|
+
mpz_mul_si(tmp_mpz, tmp_mpz, tmp_const)
|
611
|
+
mpz_to_ZZ(&tmp_coeff, tmp_mpz)
|
612
|
+
ZZX_SetCoeff(elt_num, 1, tmp_coeff)
|
613
|
+
|
614
|
+
elif n == 6:
|
615
|
+
## num[0] = a - b
|
616
|
+
mpz_add(tmp_mpz, tmp_mpz, self.a)
|
617
|
+
mpz_sub(tmp_mpz, tmp_mpz, self.b)
|
618
|
+
mpz_to_ZZ(&tmp_coeff, tmp_mpz)
|
619
|
+
ZZX_SetCoeff(elt_num, 0, tmp_coeff)
|
620
|
+
|
621
|
+
## num[1] = 2*b
|
622
|
+
mpz_sub(tmp_mpz, tmp_mpz, self.a)
|
623
|
+
tmp_const = -2
|
624
|
+
mpz_mul_si(tmp_mpz, tmp_mpz, tmp_const)
|
625
|
+
mpz_to_ZZ(&tmp_coeff, tmp_mpz)
|
626
|
+
ZZX_SetCoeff(elt_num, 1, tmp_coeff)
|
627
|
+
|
628
|
+
mpz_clear(tmp_mpz)
|
629
|
+
|
630
|
+
x._parent = <Parent>new_parent
|
631
|
+
x._fld_numerator, x._fld_denominator = new_parent.polynomial_ntl()
|
632
|
+
x._denominator = elt_den
|
633
|
+
cdef ZZX_c result
|
634
|
+
cdef ZZ_c tmp
|
635
|
+
cdef int i
|
636
|
+
cdef ntl_ZZX _num
|
637
|
+
cdef ntl_ZZ _den
|
638
|
+
_num, _den = new_parent.polynomial_ntl()
|
639
|
+
for i from 0 <= i <= ZZX_deg(elt_num):
|
640
|
+
tmp = ZZX_coeff(elt_num, i)
|
641
|
+
ZZX_SetCoeff(result, i*rel, tmp)
|
642
|
+
ZZX_rem(x._numerator, result, _num.x)
|
643
|
+
(<NumberFieldElement_absolute>x)._reduce_c_()
|
644
|
+
return x
|
645
|
+
|
646
|
+
def _real_mpfi_(self, R):
|
647
|
+
r"""
|
648
|
+
Conversion to a real interval field.
|
649
|
+
|
650
|
+
TESTS::
|
651
|
+
|
652
|
+
sage: K1 = QuadraticField(2)
|
653
|
+
sage: RIF(K1.gen())
|
654
|
+
1.414213562373095?
|
655
|
+
sage: RIF(K1(1/5))
|
656
|
+
0.2000000000000000?
|
657
|
+
sage: RIF(3/5*K1.gen() + 1/5)
|
658
|
+
1.048528137423857?
|
659
|
+
|
660
|
+
sage: K2 = QuadraticField(2, embedding=-RLF(2).sqrt())
|
661
|
+
sage: RIF(K2.gen())
|
662
|
+
-1.414213562373095?
|
663
|
+
|
664
|
+
sage: K3 = QuadraticField(-1)
|
665
|
+
sage: RIF(K3.gen())
|
666
|
+
Traceback (most recent call last):
|
667
|
+
...
|
668
|
+
ValueError: unable to convert complex algebraic number a to real interval
|
669
|
+
sage: RIF(K3(2))
|
670
|
+
2
|
671
|
+
|
672
|
+
Check that :issue:`21979` is fixed::
|
673
|
+
|
674
|
+
sage: a = QuadraticField(5).gen()
|
675
|
+
sage: u = -573147844013817084101/2*a + 1281597540372340914251/2
|
676
|
+
sage: RealIntervalField(128)(u)
|
677
|
+
0.?e-17
|
678
|
+
sage: RealIntervalField(128)(u).is_zero()
|
679
|
+
False
|
680
|
+
|
681
|
+
This was fixed in :issue:`24371`::
|
682
|
+
|
683
|
+
sage: RIF.convert_map_from(QuadraticField(5))
|
684
|
+
Conversion via _real_mpfi_ method map:
|
685
|
+
From: Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?
|
686
|
+
To: Real Interval Field with 53 bits of precision
|
687
|
+
"""
|
688
|
+
ans = (<RealIntervalField_class?>R)._new()
|
689
|
+
|
690
|
+
if mpz_cmp_ui(self.b, 0):
|
691
|
+
if mpz_cmp_ui(self.D.value, 0) < 0:
|
692
|
+
raise ValueError(f"unable to convert complex algebraic number {self!r} to real interval")
|
693
|
+
mpfi_set_z(ans.value, self.D.value)
|
694
|
+
mpfi_sqrt(ans.value, ans.value)
|
695
|
+
if not self.standard_embedding:
|
696
|
+
mpfi_neg(ans.value, ans.value)
|
697
|
+
mpfi_mul_z(ans.value, ans.value, self.b)
|
698
|
+
mpfi_add_z(ans.value, ans.value, self.a)
|
699
|
+
else:
|
700
|
+
mpfi_set_z(ans.value, self.a)
|
701
|
+
|
702
|
+
mpfi_div_z(ans.value, ans.value, self.denom)
|
703
|
+
return ans
|
704
|
+
|
705
|
+
def _complex_mpfi_(self, R):
|
706
|
+
r"""
|
707
|
+
Conversion to a complex interval field.
|
708
|
+
|
709
|
+
TESTS::
|
710
|
+
|
711
|
+
sage: K.<a> = QuadraticField(2)
|
712
|
+
sage: CIF(a)
|
713
|
+
1.414213562373095?
|
714
|
+
sage: CIF(K(1/5))
|
715
|
+
0.2000000000000000?
|
716
|
+
sage: CIF(1/5 + 3/5*a)
|
717
|
+
1.048528137423857?
|
718
|
+
|
719
|
+
sage: K.<a> = QuadraticField(-2)
|
720
|
+
sage: CIF(a)
|
721
|
+
1.414213562373095?*I
|
722
|
+
sage: CIF(K(1/5))
|
723
|
+
0.2000000000000000?
|
724
|
+
sage: CIF(1/5 + 3/5*a)
|
725
|
+
0.2000000000000000? + 0.848528137423857?*I
|
726
|
+
|
727
|
+
sage: K.<a> = QuadraticField(-2, embedding=-CLF(-2).sqrt())
|
728
|
+
sage: CIF(a)
|
729
|
+
-1.414213562373095?*I
|
730
|
+
|
731
|
+
This was fixed in :issue:`24371`::
|
732
|
+
|
733
|
+
sage: CIF.convert_map_from(QuadraticField(-5))
|
734
|
+
Conversion via _complex_mpfi_ method map:
|
735
|
+
From: Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I
|
736
|
+
To: Complex Interval Field with 53 bits of precision
|
737
|
+
"""
|
738
|
+
ans = <ComplexIntervalFieldElement>ComplexIntervalFieldElement.__new__(ComplexIntervalFieldElement, R)
|
739
|
+
|
740
|
+
if mpz_cmp_ui(self.b, 0):
|
741
|
+
mpfi_set_z(ans.__re, self.D.value)
|
742
|
+
if mpfi_is_neg(ans.__re):
|
743
|
+
# Imaginary quadratic
|
744
|
+
mpfi_neg(ans.__re, ans.__re)
|
745
|
+
mpfi_sqrt(ans.__im, ans.__re)
|
746
|
+
if not self.standard_embedding:
|
747
|
+
mpfi_neg(ans.__im, ans.__im)
|
748
|
+
mpfi_set_z(ans.__re, self.a)
|
749
|
+
mpfi_mul_z(ans.__im, ans.__im, self.b)
|
750
|
+
mpfi_div_z(ans.__im, ans.__im, self.denom)
|
751
|
+
else:
|
752
|
+
# Real quadratic
|
753
|
+
mpfi_sqrt(ans.__re, ans.__re)
|
754
|
+
if not self.standard_embedding:
|
755
|
+
mpfi_neg(ans.__re, ans.__re)
|
756
|
+
mpfi_mul_z(ans.__re, ans.__re, self.b)
|
757
|
+
mpfi_add_z(ans.__re, ans.__re, self.a)
|
758
|
+
mpfi_set_ui(ans.__im, 0)
|
759
|
+
else:
|
760
|
+
mpfi_set_z(ans.__re, self.a)
|
761
|
+
mpfi_set_ui(ans.__im, 0)
|
762
|
+
|
763
|
+
mpfi_div_z(ans.__re, ans.__re, self.denom)
|
764
|
+
return ans
|
765
|
+
|
766
|
+
cdef int arb_set_real(self, arb_t x, long prec) except -1:
|
767
|
+
"Set x to the real part of this element"
|
768
|
+
cdef fmpz_t tmpz
|
769
|
+
cdef arb_t rootD
|
770
|
+
cdef long prec2
|
771
|
+
|
772
|
+
fmpz_init(tmpz)
|
773
|
+
|
774
|
+
if mpz_sgn(self.D.value) > 0:
|
775
|
+
# To mitigate the effect of cancellations between
|
776
|
+
# a and b*sqrt(D) we perform a loop with increasing
|
777
|
+
# working precision
|
778
|
+
arb_init(rootD)
|
779
|
+
prec2 = prec
|
780
|
+
sig_on()
|
781
|
+
while True:
|
782
|
+
fmpz_set_mpz(tmpz, self.a)
|
783
|
+
arb_set_fmpz(x, tmpz)
|
784
|
+
fmpz_set_mpz(tmpz, self.D.value)
|
785
|
+
arb_sqrt_fmpz(rootD, tmpz, prec2)
|
786
|
+
fmpz_set_mpz(tmpz, self.b)
|
787
|
+
if self.standard_embedding:
|
788
|
+
arb_addmul_fmpz(x, rootD, tmpz, prec2)
|
789
|
+
else:
|
790
|
+
arb_submul_fmpz(x, rootD, tmpz, prec2)
|
791
|
+
if arb_rel_accuracy_bits(x) < prec - 4:
|
792
|
+
prec2 *= 2
|
793
|
+
continue
|
794
|
+
else:
|
795
|
+
break
|
796
|
+
sig_off()
|
797
|
+
arb_clear(rootD)
|
798
|
+
else:
|
799
|
+
fmpz_set_mpz(tmpz, self.a)
|
800
|
+
arb_set_fmpz(x, tmpz)
|
801
|
+
|
802
|
+
fmpz_set_mpz(tmpz, self.denom)
|
803
|
+
arb_div_fmpz(x, x, tmpz, prec)
|
804
|
+
fmpz_clear(tmpz)
|
805
|
+
return 0
|
806
|
+
|
807
|
+
cdef void arb_set_imag(self, arb_t x, long prec) noexcept:
|
808
|
+
"Set x to the imaginary part of this element"
|
809
|
+
cdef fmpz_t tmpz
|
810
|
+
cdef arb_t rootD
|
811
|
+
|
812
|
+
if mpz_sgn(self.D.value) < 0 and mpz_sgn(self.b):
|
813
|
+
arb_init(rootD)
|
814
|
+
fmpz_init(tmpz)
|
815
|
+
fmpz_set_mpz(tmpz, self.D.value)
|
816
|
+
fmpz_neg(tmpz, tmpz)
|
817
|
+
arb_sqrt_fmpz(rootD, tmpz, prec)
|
818
|
+
fmpz_set_mpz(tmpz, self.b)
|
819
|
+
if self.standard_embedding:
|
820
|
+
arb_addmul_fmpz(x, rootD, tmpz, prec)
|
821
|
+
else:
|
822
|
+
arb_submul_fmpz(x, rootD, tmpz, prec)
|
823
|
+
fmpz_set_mpz(tmpz, self.denom)
|
824
|
+
arb_div_fmpz(x, x, tmpz, prec)
|
825
|
+
|
826
|
+
fmpz_clear(tmpz)
|
827
|
+
arb_clear(rootD)
|
828
|
+
|
829
|
+
def _arb_(self, R):
|
830
|
+
r"""
|
831
|
+
Conversion to a real ball with parent ``R``.
|
832
|
+
|
833
|
+
EXAMPLES::
|
834
|
+
|
835
|
+
sage: a = QuadraticField(7).gen()
|
836
|
+
sage: a._arb_(RBF)
|
837
|
+
[2.645751311064590 +/- 7.17e-16]
|
838
|
+
sage: RBF(a)
|
839
|
+
[2.645751311064590 +/- 7.17e-16]
|
840
|
+
|
841
|
+
sage: a = QuadraticField(7, embedding=-AA(7).sqrt()).gen()
|
842
|
+
sage: a._arb_(RBF)
|
843
|
+
[-2.645751311064590 +/- 7.17e-16]
|
844
|
+
|
845
|
+
sage: a = QuadraticField(-1).gen()
|
846
|
+
sage: RBF(a)
|
847
|
+
Traceback (most recent call last):
|
848
|
+
...
|
849
|
+
ValueError: nonzero imaginary part
|
850
|
+
|
851
|
+
This conversion takes care of cancellations::
|
852
|
+
|
853
|
+
sage: K.<a> = QuadraticField(3)
|
854
|
+
sage: b = (a - 1)**1000
|
855
|
+
sage: RBF(b)
|
856
|
+
[3.477155118441024e-136 +/- 8.45e-152]
|
857
|
+
|
858
|
+
TESTS:
|
859
|
+
|
860
|
+
Check that coercions and conversions go through this method::
|
861
|
+
|
862
|
+
sage: RBF.convert_map_from(QuadraticField(5))
|
863
|
+
Conversion via _arb_ method map:
|
864
|
+
From: Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?
|
865
|
+
To: Real ball field with 53 bits of precision
|
866
|
+
sage: RBF.coerce_map_from(QuadraticField(5, embedding=-AA(5).sqrt()))
|
867
|
+
Conversion via _arb_ method map:
|
868
|
+
From: Number Field in a with defining polynomial x^2 - 5 with a = -2.236067977499790?
|
869
|
+
To: Real ball field with 53 bits of precision
|
870
|
+
"""
|
871
|
+
cdef RealBall res = RealBall.__new__(RealBall)
|
872
|
+
res._parent = R
|
873
|
+
if mpz_sgn(self.D.value) < 0 and mpz_sgn(self.b):
|
874
|
+
raise ValueError('nonzero imaginary part')
|
875
|
+
self.arb_set_real(res.value, R._prec)
|
876
|
+
return res
|
877
|
+
|
878
|
+
def _acb_(self, R):
|
879
|
+
r"""
|
880
|
+
Conversion to complex ball with parent ``R``.
|
881
|
+
|
882
|
+
EXAMPLES::
|
883
|
+
|
884
|
+
sage: K.<a> = QuadraticField(-3)
|
885
|
+
sage: CBF(1/7 + 3/2 * a)
|
886
|
+
[0.1428571428571428 +/- 7.70e-17] + [2.59807621135332 +/- 6.17e-15]*I
|
887
|
+
sage: CBF(1/7) + CBF(3/2) * CBF(a)
|
888
|
+
[0.1428571428571428 +/- 7.70e-17] + [2.59807621135332 +/- 5.21e-15]*I
|
889
|
+
|
890
|
+
sage: a._acb_(CBF)
|
891
|
+
[1.732050807568877 +/- 4.16e-16]*I
|
892
|
+
|
893
|
+
TESTS:
|
894
|
+
|
895
|
+
Check that coercions and conversions go through this method::
|
896
|
+
|
897
|
+
sage: CBF.convert_map_from(QuadraticField(-3))
|
898
|
+
Conversion via _acb_ method map:
|
899
|
+
From: Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
|
900
|
+
To: Complex ball field with 53 bits of precision
|
901
|
+
|
902
|
+
sage: CBF.coerce_map_from(QuadraticField(-3, embedding=-QQbar(-3).sqrt()))
|
903
|
+
Conversion via _acb_ method map:
|
904
|
+
From: Number Field in a with defining polynomial x^2 + 3 with a = -1.732050807568878?*I
|
905
|
+
To: Complex ball field with 53 bits of precision
|
906
|
+
"""
|
907
|
+
cdef ComplexBall res = ComplexBall.__new__(ComplexBall)
|
908
|
+
res._parent = R
|
909
|
+
self.arb_set_real(acb_realref(res.value), R._prec)
|
910
|
+
self.arb_set_imag(acb_imagref(res.value), R._prec)
|
911
|
+
return res
|
912
|
+
|
913
|
+
cpdef tuple parts(self):
|
914
|
+
r"""
|
915
|
+
Return a pair of rationals `a` and `b` such that ``self`` `=
|
916
|
+
a+b\sqrt{D}`.
|
917
|
+
|
918
|
+
This is much closer to the internal storage format of the
|
919
|
+
elements than the polynomial representation coefficients (the output of
|
920
|
+
``self.list()``), unless the generator with which this number field was
|
921
|
+
constructed was equal to `\sqrt{D}`. See the last example below.
|
922
|
+
|
923
|
+
EXAMPLES::
|
924
|
+
|
925
|
+
sage: x = polygen(ZZ, 'x')
|
926
|
+
sage: K.<a> = NumberField(x^2 - 13)
|
927
|
+
sage: K.discriminant()
|
928
|
+
13
|
929
|
+
sage: a.parts()
|
930
|
+
(0, 1)
|
931
|
+
sage: (a/2 - 4).parts()
|
932
|
+
(-4, 1/2)
|
933
|
+
sage: K.<a> = NumberField(x^2 - 7)
|
934
|
+
sage: K.discriminant()
|
935
|
+
28
|
936
|
+
sage: a.parts()
|
937
|
+
(0, 1)
|
938
|
+
sage: K.<a> = NumberField(x^2 - x + 7)
|
939
|
+
sage: a.parts()
|
940
|
+
(1/2, 3/2)
|
941
|
+
sage: a._coefficients()
|
942
|
+
[0, 1]
|
943
|
+
"""
|
944
|
+
cdef Rational ad = <Rational>Rational.__new__(Rational)
|
945
|
+
cdef Rational bd = <Rational>Rational.__new__(Rational)
|
946
|
+
if mpz_cmp_ui(self.a, 0) == 0:
|
947
|
+
mpq_set_ui(ad.value, 0, 1)
|
948
|
+
else:
|
949
|
+
mpz_set(mpq_numref(ad.value), self.a)
|
950
|
+
mpz_set(mpq_denref(ad.value), self.denom)
|
951
|
+
mpq_canonicalize(ad.value)
|
952
|
+
if mpz_cmp_ui(self.b, 0) == 0:
|
953
|
+
mpq_set_ui(bd.value, 0, 1)
|
954
|
+
else:
|
955
|
+
mpz_set(mpq_numref(bd.value), self.b)
|
956
|
+
mpz_set(mpq_denref(bd.value), self.denom)
|
957
|
+
mpq_canonicalize(bd.value)
|
958
|
+
|
959
|
+
return (ad, bd)
|
960
|
+
|
961
|
+
#########################################################
|
962
|
+
# Comparisons
|
963
|
+
#########################################################
|
964
|
+
|
965
|
+
def sign(self):
|
966
|
+
r"""
|
967
|
+
Return the sign of ``self`` (`0` if zero, `+1` if positive, and `-1` if
|
968
|
+
negative).
|
969
|
+
|
970
|
+
EXAMPLES::
|
971
|
+
|
972
|
+
sage: K.<sqrt2> = QuadraticField(2, name='sqrt2')
|
973
|
+
sage: K(0).sign()
|
974
|
+
0
|
975
|
+
sage: sqrt2.sign()
|
976
|
+
1
|
977
|
+
sage: (sqrt2+1).sign()
|
978
|
+
1
|
979
|
+
sage: (sqrt2-1).sign()
|
980
|
+
1
|
981
|
+
sage: (sqrt2-2).sign()
|
982
|
+
-1
|
983
|
+
sage: (-sqrt2).sign()
|
984
|
+
-1
|
985
|
+
sage: (-sqrt2+1).sign()
|
986
|
+
-1
|
987
|
+
sage: (-sqrt2+2).sign()
|
988
|
+
1
|
989
|
+
|
990
|
+
sage: K.<a> = QuadraticField(2, embedding=-1.4142)
|
991
|
+
sage: K(0).sign()
|
992
|
+
0
|
993
|
+
sage: a.sign()
|
994
|
+
-1
|
995
|
+
sage: (a+1).sign()
|
996
|
+
-1
|
997
|
+
sage: (a+2).sign()
|
998
|
+
1
|
999
|
+
sage: (a-1).sign()
|
1000
|
+
-1
|
1001
|
+
sage: (-a).sign()
|
1002
|
+
1
|
1003
|
+
sage: (-a-1).sign()
|
1004
|
+
1
|
1005
|
+
sage: (-a-2).sign()
|
1006
|
+
-1
|
1007
|
+
|
1008
|
+
sage: # needs sage.symbolic
|
1009
|
+
sage: x = polygen(ZZ, 'x')
|
1010
|
+
sage: K.<b> = NumberField(x^2 + 2*x + 7, 'b', embedding=CC(-1,-sqrt(6)))
|
1011
|
+
sage: b.sign()
|
1012
|
+
Traceback (most recent call last):
|
1013
|
+
...
|
1014
|
+
ValueError: a complex number has no sign!
|
1015
|
+
sage: K(1).sign()
|
1016
|
+
1
|
1017
|
+
sage: K(0).sign()
|
1018
|
+
0
|
1019
|
+
sage: K(-2/3).sign()
|
1020
|
+
-1
|
1021
|
+
"""
|
1022
|
+
cdef mpz_t i, j
|
1023
|
+
cdef int s = 1, test
|
1024
|
+
|
1025
|
+
if mpz_sgn(self.b) == 0:
|
1026
|
+
return mpz_sgn(self.a)
|
1027
|
+
|
1028
|
+
if mpz_sgn(self.D.value) == -1:
|
1029
|
+
raise ValueError("a complex number has no sign!")
|
1030
|
+
|
1031
|
+
if not self.standard_embedding:
|
1032
|
+
s = -1
|
1033
|
+
|
1034
|
+
if mpz_sgn(self.a) == 0:
|
1035
|
+
return s*mpz_sgn(self.b)
|
1036
|
+
|
1037
|
+
if mpz_sgn(self.a) == 1:
|
1038
|
+
if mpz_sgn(self.b) == s:
|
1039
|
+
return 1
|
1040
|
+
|
1041
|
+
elif mpz_sgn(self.b) == -s:
|
1042
|
+
return -1
|
1043
|
+
|
1044
|
+
mpz_init_set(i,self.a)
|
1045
|
+
mpz_mul(i,i,i)
|
1046
|
+
mpz_init_set(j,self.b)
|
1047
|
+
mpz_mul(j,j,j)
|
1048
|
+
mpz_mul(j,j,self.D.value)
|
1049
|
+
test = mpz_cmp(i,j)
|
1050
|
+
mpz_clear(i)
|
1051
|
+
mpz_clear(j)
|
1052
|
+
if test > 0:
|
1053
|
+
test = 1
|
1054
|
+
elif test < 0:
|
1055
|
+
test = -1
|
1056
|
+
if mpz_sgn(self.a) == 1 and mpz_sgn(self.b) == -s:
|
1057
|
+
return test
|
1058
|
+
return -test
|
1059
|
+
|
1060
|
+
cpdef _richcmp_(left, _right, int op):
|
1061
|
+
r"""
|
1062
|
+
Rich comparison of elements.
|
1063
|
+
|
1064
|
+
TESTS::
|
1065
|
+
|
1066
|
+
sage: K.<i> = QuadraticField(-1)
|
1067
|
+
sage: sorted([5*i+1, 2, 3*i+1, 2-i])
|
1068
|
+
[3*i + 1, 5*i + 1, -i + 2, 2]
|
1069
|
+
|
1070
|
+
Make some random tests to check that the order is compatible with the
|
1071
|
+
ones of the real field (RR) and complex field (CC)::
|
1072
|
+
|
1073
|
+
sage: x = polygen(ZZ, 'x')
|
1074
|
+
sage: K1 = NumberField(x^2 - 2, 'a', embedding=RR(1.4))
|
1075
|
+
sage: K2 = NumberField(x^2 - 2, 'a', embedding=RR(-1.4))
|
1076
|
+
sage: for _ in range(500): # long time
|
1077
|
+
....: for K in K1, K2:
|
1078
|
+
....: a = K.random_element()
|
1079
|
+
....: b = K.random_element()
|
1080
|
+
....: assert (a < b) == (RR(a) < RR(b))
|
1081
|
+
....: assert (a > b) == (RR(a) > RR(b))
|
1082
|
+
....: assert (a == b) == (RR(a) == RR(b))
|
1083
|
+
....: assert (a != b) == (RR(a) != RR(b))
|
1084
|
+
....: assert (a >= b) == (RR(a) >= RR(b))
|
1085
|
+
....: assert (a <= b) == (RR(a) <= RR(b))
|
1086
|
+
|
1087
|
+
::
|
1088
|
+
|
1089
|
+
sage: K1 = NumberField(x^2 + 2, 'a', embedding=CC(0,1))
|
1090
|
+
sage: K2 = NumberField(x^2 + 2, 'a', embedding=CC(0,-1))
|
1091
|
+
sage: for _ in range(500): # long time
|
1092
|
+
....: for K in K1, K2:
|
1093
|
+
....: a = K.random_element()
|
1094
|
+
....: b = K.random_element()
|
1095
|
+
....: assert (a < b) == (CC(a) < CC(b))
|
1096
|
+
....: assert (a > b) == (CC(a) > CC(b))
|
1097
|
+
....: assert (a == b) == (CC(a) == CC(b))
|
1098
|
+
....: assert (a != b) == (CC(a) != CC(b))
|
1099
|
+
....: assert (a >= b) == (CC(a) >= CC(b))
|
1100
|
+
....: assert (a <= b) == (CC(a) <= CC(b))
|
1101
|
+
|
1102
|
+
The following is tested because of the implementation of
|
1103
|
+
:func:`Q_to_quadratic_field_element` which was the cause of
|
1104
|
+
some problems with :issue:`13213`::
|
1105
|
+
|
1106
|
+
sage: K.<sqrt2> = QuadraticField(2)
|
1107
|
+
sage: 1/2 + sqrt2 > 0
|
1108
|
+
True
|
1109
|
+
|
1110
|
+
Two examples from the same number field with its two possible real
|
1111
|
+
embeddings::
|
1112
|
+
|
1113
|
+
sage: K.<phi> = NumberField(x^2-x-1, 'phi', embedding=1.618)
|
1114
|
+
sage: phi > 0
|
1115
|
+
True
|
1116
|
+
sage: -phi > 0
|
1117
|
+
False
|
1118
|
+
sage: phi - 3 == 2*phi + 1
|
1119
|
+
False
|
1120
|
+
sage: fibonacci(10)*phi < fibonacci(11)
|
1121
|
+
True
|
1122
|
+
sage: RDF(fibonacci(10)*phi)
|
1123
|
+
88.99186938124421
|
1124
|
+
sage: fibonacci(11)
|
1125
|
+
89
|
1126
|
+
sage: l = [-2, phi+3, 2*phi-1, 2*phi-5, 0, -phi+2, fibonacci(20)*phi - fibonacci(21)]
|
1127
|
+
sage: l.sort()
|
1128
|
+
sage: l
|
1129
|
+
[-2, 2*phi - 5, 6765*phi - 10946, 0, -phi + 2, 2*phi - 1, phi + 3]
|
1130
|
+
sage: list(map(RDF, l))
|
1131
|
+
[-2.0, -1.7639320225002102, -6.610696073039435e-05, 0.0, 0.3819660112501051, 2.23606797749979, 4.618033988749895]
|
1132
|
+
|
1133
|
+
::
|
1134
|
+
|
1135
|
+
sage: L.<psi> = NumberField(x^2-x-1, 'psi', embedding=-0.618)
|
1136
|
+
sage: psi < 0
|
1137
|
+
True
|
1138
|
+
sage: 2*psi + 3 == 2*psi + 3
|
1139
|
+
True
|
1140
|
+
sage: fibonacci(10)*psi < -fibonacci(9)
|
1141
|
+
False
|
1142
|
+
sage: RDF(fibonacci(10)*psi)
|
1143
|
+
-33.99186938124422
|
1144
|
+
sage: fibonacci(9)
|
1145
|
+
34
|
1146
|
+
sage: l = [-1, psi, 0, fibonacci(20)*psi + fibonacci(19), 3*psi+2]
|
1147
|
+
sage: l.sort()
|
1148
|
+
sage: l
|
1149
|
+
[-1, psi, 0, 6765*psi + 4181, 3*psi + 2]
|
1150
|
+
sage: list(map(RDF, l))
|
1151
|
+
[-1.0, -0.6180339887498949, 0.0, 6.610696073039435e-05, 0.1458980337503153]
|
1152
|
+
|
1153
|
+
For a field with no specified embedding the comparison uses the standard
|
1154
|
+
embedding::
|
1155
|
+
|
1156
|
+
sage: K.<sqrt2> = NumberField(x^2-2, 'sqrt2')
|
1157
|
+
sage: sqrt2 > 1 and sqrt2 < 2
|
1158
|
+
True
|
1159
|
+
|
1160
|
+
The following examples illustrate the same behavior for a complex
|
1161
|
+
quadratic field::
|
1162
|
+
|
1163
|
+
sage: K.<i> = QuadraticField(-1)
|
1164
|
+
sage: l = [-2, i-3, 2*i-2, 2*i+2, 5*i, 1-3*i, -1+i, 1]
|
1165
|
+
sage: l.sort()
|
1166
|
+
sage: l
|
1167
|
+
[i - 3, -2, 2*i - 2, i - 1, 5*i, -3*i + 1, 1, 2*i + 2]
|
1168
|
+
sage: list(map(CDF, l))
|
1169
|
+
[-3.0 + 1.0*I, -2.0, -2.0 + 2.0*I, -1.0 + 1.0*I, 5.0*I, 1.0 - 3.0*I, 1.0, 2.0 + 2.0*I]
|
1170
|
+
sage: list(map(CDF, l)) == sorted(map(CDF, l))
|
1171
|
+
True
|
1172
|
+
"""
|
1173
|
+
# When D > 0 and standard embedding, we compare (a + b * sqrt(D)) / d and (aa +
|
1174
|
+
# bb * sqrt(D)) / dd using the comparison of (dd*a - d * aa)^2 and (d*bb - dd*b)^2 * D
|
1175
|
+
# mpz_sgn: returns 1 if > 0, 0 if 0 and -1 if < 0
|
1176
|
+
cdef mpz_t i, j
|
1177
|
+
cdef NumberFieldElement_quadratic right = <NumberFieldElement_quadratic> _right
|
1178
|
+
cdef int test
|
1179
|
+
|
1180
|
+
# inequality and equality
|
1181
|
+
if mpz_cmp(left.a, right.a) or mpz_cmp(left.b, right.b) or mpz_cmp(left.denom, right.denom):
|
1182
|
+
if op == Py_EQ:
|
1183
|
+
return False
|
1184
|
+
elif op == Py_NE:
|
1185
|
+
return True
|
1186
|
+
else: # equality
|
1187
|
+
if op == Py_EQ or op == Py_LE or op == Py_GE:
|
1188
|
+
return True
|
1189
|
+
if op == Py_NE or op == Py_LT or op == Py_GT:
|
1190
|
+
return False
|
1191
|
+
|
1192
|
+
# comparisons are valid only in *real* quadratic number field
|
1193
|
+
# when no embedding is specified or in the case of complex embeddings we
|
1194
|
+
# use a lexicographic order.
|
1195
|
+
if mpz_sgn(left.D.value) == -1:
|
1196
|
+
mpz_init(i)
|
1197
|
+
mpz_init(j)
|
1198
|
+
mpz_mul(i, left.a, right.denom)
|
1199
|
+
mpz_mul(j, right.a, left.denom)
|
1200
|
+
test = mpz_cmp(i,j)
|
1201
|
+
if test:
|
1202
|
+
mpz_clear(i)
|
1203
|
+
mpz_clear(j)
|
1204
|
+
return rich_to_bool_sgn(op, test)
|
1205
|
+
mpz_mul(i, left.b, right.denom)
|
1206
|
+
mpz_mul(j, right.b, left.denom)
|
1207
|
+
test = mpz_cmp(i,j)
|
1208
|
+
if test:
|
1209
|
+
if not left.standard_embedding:
|
1210
|
+
test = -test
|
1211
|
+
mpz_clear(i)
|
1212
|
+
mpz_clear(j)
|
1213
|
+
return rich_to_bool_sgn(op, test)
|
1214
|
+
test = mpz_cmp(left.denom, right.denom)
|
1215
|
+
mpz_clear(i)
|
1216
|
+
mpz_clear(j)
|
1217
|
+
return rich_to_bool_sgn(op, test)
|
1218
|
+
|
1219
|
+
# comparison in the real case
|
1220
|
+
mpz_init(i)
|
1221
|
+
mpz_mul(i, right.denom, left.a)
|
1222
|
+
mpz_submul(i, left.denom, right.a)
|
1223
|
+
|
1224
|
+
mpz_init(j)
|
1225
|
+
mpz_mul(j, left.denom, right.b)
|
1226
|
+
mpz_submul(j, right.denom, left.b)
|
1227
|
+
|
1228
|
+
if not left.standard_embedding:
|
1229
|
+
mpz_neg(j, j)
|
1230
|
+
|
1231
|
+
if mpz_sgn(i) == 1:
|
1232
|
+
if mpz_sgn(j) == 1:
|
1233
|
+
mpz_mul(i, i, i)
|
1234
|
+
mpz_mul(j, j, j)
|
1235
|
+
mpz_mul(j, j, left.D.value)
|
1236
|
+
test = mpz_cmp(i, j)
|
1237
|
+
else:
|
1238
|
+
test = 1
|
1239
|
+
|
1240
|
+
else:
|
1241
|
+
if mpz_sgn(j) == -1:
|
1242
|
+
mpz_mul(i, i, i)
|
1243
|
+
mpz_mul(j, j, j)
|
1244
|
+
mpz_mul(j, j, left.D.value)
|
1245
|
+
test = mpz_cmp(j, i)
|
1246
|
+
else:
|
1247
|
+
test = -1
|
1248
|
+
|
1249
|
+
mpz_clear(i)
|
1250
|
+
mpz_clear(j)
|
1251
|
+
return rich_to_bool_sgn(op, test)
|
1252
|
+
|
1253
|
+
def continued_fraction_list(self):
|
1254
|
+
r"""
|
1255
|
+
Return the preperiod and the period of the continued fraction expansion
|
1256
|
+
of ``self``.
|
1257
|
+
|
1258
|
+
EXAMPLES::
|
1259
|
+
|
1260
|
+
sage: K.<sqrt2> = QuadraticField(2)
|
1261
|
+
sage: sqrt2.continued_fraction_list()
|
1262
|
+
((1,), (2,))
|
1263
|
+
sage: (1/2 + sqrt2/3).continued_fraction_list()
|
1264
|
+
((0, 1, 33), (1, 32))
|
1265
|
+
|
1266
|
+
For rational entries a pair of tuples is also returned but the second
|
1267
|
+
one is empty::
|
1268
|
+
|
1269
|
+
sage: K(123/567).continued_fraction_list()
|
1270
|
+
((0, 4, 1, 1, 1, 1, 3, 2), ())
|
1271
|
+
"""
|
1272
|
+
if mpz_sgn(self.b) == 0:
|
1273
|
+
return tuple(Rational(self).continued_fraction_list()),()
|
1274
|
+
|
1275
|
+
if mpz_sgn(self.D.value) < 0:
|
1276
|
+
raise ValueError("the method is only available for positive discriminant")
|
1277
|
+
|
1278
|
+
x = self
|
1279
|
+
orbit = []
|
1280
|
+
quots = []
|
1281
|
+
while x not in orbit:
|
1282
|
+
quots.append(x.floor())
|
1283
|
+
orbit.append(x)
|
1284
|
+
x = ~(x - quots[-1])
|
1285
|
+
|
1286
|
+
i = orbit.index(x)
|
1287
|
+
|
1288
|
+
return tuple(quots[:i]), tuple(quots[i:])
|
1289
|
+
|
1290
|
+
def continued_fraction(self):
|
1291
|
+
r"""
|
1292
|
+
Return the (finite or ultimately periodic) continued fraction of ``self``.
|
1293
|
+
|
1294
|
+
EXAMPLES::
|
1295
|
+
|
1296
|
+
sage: K.<sqrt2> = QuadraticField(2)
|
1297
|
+
sage: cf = sqrt2.continued_fraction(); cf
|
1298
|
+
[1; (2)*]
|
1299
|
+
sage: cf.n()
|
1300
|
+
1.41421356237310
|
1301
|
+
sage: sqrt2.n()
|
1302
|
+
1.41421356237309
|
1303
|
+
sage: cf.value()
|
1304
|
+
sqrt2
|
1305
|
+
|
1306
|
+
sage: (sqrt2/3 + 1/4).continued_fraction()
|
1307
|
+
[0; 1, (2, 1, 1, 2, 3, 2, 1, 1, 2, 5, 1, 1, 14, 1, 1, 5)*]
|
1308
|
+
"""
|
1309
|
+
t1,t2 = self.continued_fraction_list()
|
1310
|
+
from sage.rings.continued_fraction import ContinuedFraction_periodic
|
1311
|
+
return ContinuedFraction_periodic(t1,t2)
|
1312
|
+
|
1313
|
+
#########################################################
|
1314
|
+
# Arithmetic
|
1315
|
+
#########################################################
|
1316
|
+
|
1317
|
+
cdef void _reduce_c_(self) noexcept:
|
1318
|
+
r"""
|
1319
|
+
Reduces into canonical form.
|
1320
|
+
|
1321
|
+
WARNING: this mutates ``self``.
|
1322
|
+
"""
|
1323
|
+
cdef mpz_t gcd
|
1324
|
+
# cancel out common factors
|
1325
|
+
mpz_init(gcd)
|
1326
|
+
mpz_gcd(gcd, self.a, self.denom)
|
1327
|
+
mpz_gcd(gcd, gcd, self.b)
|
1328
|
+
if mpz_cmp_si(gcd, 1): # != 0 (i.e. it is not 1)
|
1329
|
+
mpz_divexact(self.a, self.a, gcd)
|
1330
|
+
mpz_divexact(self.b, self.b, gcd)
|
1331
|
+
mpz_divexact(self.denom, self.denom, gcd)
|
1332
|
+
# make denominator positive
|
1333
|
+
if mpz_sgn(self.denom) < 0:
|
1334
|
+
mpz_neg(self.denom, self.denom)
|
1335
|
+
mpz_neg(self.a, self.a)
|
1336
|
+
mpz_neg(self.b, self.b)
|
1337
|
+
mpz_clear(gcd)
|
1338
|
+
|
1339
|
+
cpdef _add_(self, other_m):
|
1340
|
+
"""
|
1341
|
+
EXAMPLES::
|
1342
|
+
|
1343
|
+
sage: x = polygen(ZZ, 'x')
|
1344
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
1345
|
+
sage: K.discriminant()
|
1346
|
+
5
|
1347
|
+
sage: a+a # indirect doctest
|
1348
|
+
2*a
|
1349
|
+
sage: s = (a+2)/6; s
|
1350
|
+
1/6*a + 1/3
|
1351
|
+
sage: s+a
|
1352
|
+
7/6*a + 1/3
|
1353
|
+
sage: s+10
|
1354
|
+
1/6*a + 31/3
|
1355
|
+
sage: s+(2*a+5)/7
|
1356
|
+
19/42*a + 22/21
|
1357
|
+
sage: s+(1+a)/2
|
1358
|
+
2/3*a + 5/6
|
1359
|
+
sage: s+(1+a)/8
|
1360
|
+
7/24*a + 11/24
|
1361
|
+
sage: s+(a+5)/6
|
1362
|
+
1/3*a + 7/6
|
1363
|
+
sage: (a/3+2/3) + (2*a/3+1/3)
|
1364
|
+
a + 1
|
1365
|
+
"""
|
1366
|
+
cdef NumberFieldElement_quadratic other = <NumberFieldElement_quadratic>other_m
|
1367
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1368
|
+
cdef mpz_t gcd, tmp
|
1369
|
+
if mpz_cmp(self.denom, other.denom) == 0:
|
1370
|
+
mpz_add(res.a, self.a, other.a)
|
1371
|
+
mpz_add(res.b, self.b, other.b)
|
1372
|
+
mpz_set(res.denom, self.denom)
|
1373
|
+
else:
|
1374
|
+
mpz_init(gcd)
|
1375
|
+
mpz_gcd(gcd, self.denom, other.denom)
|
1376
|
+
if mpz_cmp_ui(gcd, 1) == 0:
|
1377
|
+
mpz_mul(res.a, self.a, other.denom)
|
1378
|
+
mpz_addmul(res.a, self.denom, other.a)
|
1379
|
+
mpz_mul(res.b, self.b, other.denom)
|
1380
|
+
mpz_addmul(res.b, self.denom, other.b)
|
1381
|
+
mpz_mul(res.denom, self.denom, other.denom)
|
1382
|
+
else:
|
1383
|
+
mpz_init(tmp)
|
1384
|
+
mpz_divexact(tmp, other.denom, gcd)
|
1385
|
+
mpz_mul(res.a, self.a, tmp)
|
1386
|
+
mpz_mul(res.b, self.b, tmp)
|
1387
|
+
mpz_divexact(tmp, self.denom, gcd)
|
1388
|
+
mpz_addmul(res.a, other.a, tmp)
|
1389
|
+
mpz_addmul(res.b, other.b, tmp)
|
1390
|
+
mpz_mul(res.denom, other.denom, tmp)
|
1391
|
+
mpz_clear(tmp)
|
1392
|
+
mpz_clear(gcd)
|
1393
|
+
res._reduce_c_()
|
1394
|
+
return res
|
1395
|
+
|
1396
|
+
cpdef _sub_(self, other_m):
|
1397
|
+
"""
|
1398
|
+
EXAMPLES::
|
1399
|
+
|
1400
|
+
sage: x = polygen(ZZ, 'x')
|
1401
|
+
sage: K.<a> = NumberField(x^2 - 13)
|
1402
|
+
sage: b = (a-3)/10; b # indirect doctest
|
1403
|
+
1/10*a - 3/10
|
1404
|
+
sage: b-1
|
1405
|
+
1/10*a - 13/10
|
1406
|
+
sage: b-a
|
1407
|
+
-9/10*a - 3/10
|
1408
|
+
sage: b-1/2
|
1409
|
+
1/10*a - 4/5
|
1410
|
+
sage: b-a/15
|
1411
|
+
1/30*a - 3/10
|
1412
|
+
"""
|
1413
|
+
cdef NumberFieldElement_quadratic other = <NumberFieldElement_quadratic>other_m
|
1414
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1415
|
+
cdef mpz_t gcd, tmp
|
1416
|
+
if mpz_cmp(self.denom, other.denom) == 0:
|
1417
|
+
mpz_sub(res.a, self.a, other.a)
|
1418
|
+
mpz_sub(res.b, self.b, other.b)
|
1419
|
+
mpz_set(res.denom, self.denom)
|
1420
|
+
else:
|
1421
|
+
mpz_init(gcd)
|
1422
|
+
mpz_gcd(gcd, self.denom, other.denom)
|
1423
|
+
if mpz_cmp_ui(gcd, 1) == 0:
|
1424
|
+
mpz_mul(res.a, self.a, other.denom)
|
1425
|
+
mpz_submul(res.a, self.denom, other.a)
|
1426
|
+
mpz_mul(res.b, self.b, other.denom)
|
1427
|
+
mpz_submul(res.b, self.denom, other.b)
|
1428
|
+
mpz_mul(res.denom, self.denom, other.denom)
|
1429
|
+
else:
|
1430
|
+
mpz_init(tmp)
|
1431
|
+
mpz_divexact(tmp, other.denom, gcd)
|
1432
|
+
mpz_mul(res.a, self.a, tmp)
|
1433
|
+
mpz_mul(res.b, self.b, tmp)
|
1434
|
+
mpz_divexact(tmp, self.denom, gcd)
|
1435
|
+
mpz_submul(res.a, other.a, tmp)
|
1436
|
+
mpz_submul(res.b, other.b, tmp)
|
1437
|
+
mpz_mul(res.denom, other.denom, tmp)
|
1438
|
+
mpz_clear(tmp)
|
1439
|
+
mpz_clear(gcd)
|
1440
|
+
res._reduce_c_()
|
1441
|
+
return res
|
1442
|
+
|
1443
|
+
def __neg__(self):
|
1444
|
+
"""
|
1445
|
+
EXAMPLES::
|
1446
|
+
|
1447
|
+
sage: x = polygen(ZZ, 'x')
|
1448
|
+
sage: K.<a> = NumberField(x^2 + 163)
|
1449
|
+
sage: -a
|
1450
|
+
-a
|
1451
|
+
sage: -(a+4)
|
1452
|
+
-a - 4
|
1453
|
+
sage: b = (a-3)/2
|
1454
|
+
sage: -b
|
1455
|
+
-1/2*a + 3/2
|
1456
|
+
"""
|
1457
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1458
|
+
mpz_neg(res.a, self.a)
|
1459
|
+
mpz_neg(res.b, self.b)
|
1460
|
+
mpz_set(res.denom, self.denom)
|
1461
|
+
return res
|
1462
|
+
|
1463
|
+
cpdef _mul_(self, other_m):
|
1464
|
+
"""
|
1465
|
+
EXAMPLES::
|
1466
|
+
|
1467
|
+
sage: x = polygen(ZZ, 'x')
|
1468
|
+
sage: K.<a> = NumberField(x^2 + 23)
|
1469
|
+
sage: a*a # indirect doctest
|
1470
|
+
-23
|
1471
|
+
sage: (a+1)*(a-1)
|
1472
|
+
-24
|
1473
|
+
sage: (a+1)*(a+2)
|
1474
|
+
3*a - 21
|
1475
|
+
sage: (a+1)/2 * (a+2)
|
1476
|
+
3/2*a - 21/2
|
1477
|
+
sage: (a+1)/2 * (a+2)/3
|
1478
|
+
1/2*a - 7/2
|
1479
|
+
sage: (2*a+4) * (3*a)/2
|
1480
|
+
6*a - 69
|
1481
|
+
|
1482
|
+
Verify Karatsuba::
|
1483
|
+
|
1484
|
+
sage: K.<a> = NumberField(x^2-41)
|
1485
|
+
sage: (10^1000 * (a+1)) * K(2+3*a) == 10^1000 * ((a+1) * K(2+3*a))
|
1486
|
+
True
|
1487
|
+
|
1488
|
+
TESTS:
|
1489
|
+
|
1490
|
+
Test that :issue:`30360` is fixed::
|
1491
|
+
|
1492
|
+
sage: K.<sqrt5> = QuadraticField(5, embedding=AA(5).sqrt())
|
1493
|
+
sage: sqrt5*vector([1,2])
|
1494
|
+
(sqrt5, 2*sqrt5)
|
1495
|
+
"""
|
1496
|
+
cdef NumberFieldElement_quadratic other = <NumberFieldElement_quadratic>other_m
|
1497
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1498
|
+
cdef mpz_t tmp
|
1499
|
+
|
1500
|
+
if mpz_size(self.a) + mpz_size(self.b) < 8: # could I use a macro instead?
|
1501
|
+
# Do it the traditional way
|
1502
|
+
mpz_mul(res.a, self.b, other.b)
|
1503
|
+
mpz_mul(res.a, res.a, self.D.value)
|
1504
|
+
mpz_addmul(res.a, self.a, other.a)
|
1505
|
+
|
1506
|
+
mpz_mul(res.b, self.a, other.b)
|
1507
|
+
mpz_addmul(res.b, self.b, other.a)
|
1508
|
+
|
1509
|
+
else:
|
1510
|
+
# Karatsuba
|
1511
|
+
sig_on()
|
1512
|
+
mpz_init(tmp)
|
1513
|
+
mpz_add(res.a, self.a, self.b) # using res.a as tmp
|
1514
|
+
mpz_add(tmp, other.a, other.b)
|
1515
|
+
mpz_mul(res.b, res.a, tmp) # res.b = (self.a + self.b)(other.a + other.b)
|
1516
|
+
|
1517
|
+
mpz_mul(res.a, self.a, other.a)
|
1518
|
+
mpz_sub(res.b, res.b, res.a)
|
1519
|
+
mpz_mul(tmp, self.b, other.b)
|
1520
|
+
mpz_sub(res.b, res.b, tmp)
|
1521
|
+
mpz_mul(tmp, tmp, self.D.value)
|
1522
|
+
mpz_add(res.a, res.a, tmp)
|
1523
|
+
mpz_clear(tmp)
|
1524
|
+
sig_off()
|
1525
|
+
|
1526
|
+
mpz_mul(res.denom, self.denom, other.denom)
|
1527
|
+
res._reduce_c_()
|
1528
|
+
return res
|
1529
|
+
|
1530
|
+
cpdef _rmul_(self, Element _c):
|
1531
|
+
"""
|
1532
|
+
EXAMPLES::
|
1533
|
+
|
1534
|
+
sage: x = polygen(ZZ, 'x')
|
1535
|
+
sage: K.<a> = NumberField(x^2 + 43)
|
1536
|
+
sage: (1+a)*3 # indirect doctest
|
1537
|
+
3*a + 3
|
1538
|
+
"""
|
1539
|
+
cdef Rational c = <Rational>_c
|
1540
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1541
|
+
mpz_mul(res.a, self.a, mpq_numref(c.value))
|
1542
|
+
mpz_mul(res.b, self.b, mpq_numref(c.value))
|
1543
|
+
mpz_mul(res.denom, self.denom, mpq_denref(c.value))
|
1544
|
+
res._reduce_c_()
|
1545
|
+
return res
|
1546
|
+
|
1547
|
+
cpdef _lmul_(self, Element _c):
|
1548
|
+
"""
|
1549
|
+
EXAMPLES::
|
1550
|
+
|
1551
|
+
sage: x = polygen(ZZ, 'x')
|
1552
|
+
sage: K.<a> = NumberField(x^2 + 43)
|
1553
|
+
sage: 5*(a-1/5) # indirect doctest
|
1554
|
+
5*a - 1
|
1555
|
+
"""
|
1556
|
+
cdef Rational c = <Rational>_c
|
1557
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1558
|
+
mpz_mul(res.a, self.a, mpq_numref(c.value))
|
1559
|
+
mpz_mul(res.b, self.b, mpq_numref(c.value))
|
1560
|
+
mpz_mul(res.denom, self.denom, mpq_denref(c.value))
|
1561
|
+
res._reduce_c_()
|
1562
|
+
return res
|
1563
|
+
|
1564
|
+
def __invert__(self):
|
1565
|
+
"""
|
1566
|
+
EXAMPLES::
|
1567
|
+
|
1568
|
+
sage: x = polygen(ZZ, 'x')
|
1569
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
1570
|
+
sage: ~a
|
1571
|
+
1/5*a
|
1572
|
+
sage: ~(a+1)
|
1573
|
+
1/4*a - 1/4
|
1574
|
+
sage: (a-1)*(a+1)
|
1575
|
+
4
|
1576
|
+
sage: b = ~(5*a-3); b
|
1577
|
+
5/116*a + 3/116
|
1578
|
+
sage: b*(5*a-3)
|
1579
|
+
1
|
1580
|
+
sage: b = ~((3*a-2)/7); b
|
1581
|
+
21/41*a + 14/41
|
1582
|
+
sage: (3*a-2)/7 * b
|
1583
|
+
1
|
1584
|
+
|
1585
|
+
This fixes issue :issue:`9357`::
|
1586
|
+
|
1587
|
+
sage: K.<a> = NumberField(x^2+1)
|
1588
|
+
sage: d = K(0)
|
1589
|
+
sage: ~d
|
1590
|
+
Traceback (most recent call last):
|
1591
|
+
...
|
1592
|
+
ZeroDivisionError: number field element division by zero
|
1593
|
+
sage: K.random_element() / d
|
1594
|
+
Traceback (most recent call last):
|
1595
|
+
...
|
1596
|
+
ZeroDivisionError: number field element division by zero
|
1597
|
+
"""
|
1598
|
+
if mpz_cmp_ui(self.a, 0) == 0 and mpz_cmp_ui(self.b, 0) == 0:
|
1599
|
+
raise ZeroDivisionError("number field element division by zero")
|
1600
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1601
|
+
cdef mpz_t tmp, gcd
|
1602
|
+
mpz_init(tmp)
|
1603
|
+
mpz_init(gcd)
|
1604
|
+
|
1605
|
+
mpz_gcd(gcd, self.a, self.b)
|
1606
|
+
if mpz_cmp_si(gcd, 1): # != 0 (i.e. it is not 1)
|
1607
|
+
# cancel out g (g(a'-b'd)) / (g^2 (a'^2-b'^2d^2))
|
1608
|
+
mpz_divexact(res.a, self.a, gcd)
|
1609
|
+
mpz_divexact(res.b, self.b, gcd)
|
1610
|
+
mpz_neg(res.b, res.b)
|
1611
|
+
else:
|
1612
|
+
mpz_set(res.a, self.a)
|
1613
|
+
mpz_neg(res.b, self.b)
|
1614
|
+
|
1615
|
+
mpz_pow_ui(res.denom, res.a, 2)
|
1616
|
+
mpz_pow_ui(tmp, res.b, 2)
|
1617
|
+
mpz_mul(tmp, tmp, self.D.value)
|
1618
|
+
mpz_sub(res.denom, res.denom, tmp)
|
1619
|
+
# need to multiply the leftover g back in
|
1620
|
+
mpz_mul(res.denom, res.denom, gcd)
|
1621
|
+
|
1622
|
+
mpz_mul(res.a, res.a, self.denom)
|
1623
|
+
mpz_mul(res.b, res.b, self.denom)
|
1624
|
+
|
1625
|
+
mpz_clear(tmp)
|
1626
|
+
mpz_clear(gcd)
|
1627
|
+
|
1628
|
+
res._reduce_c_()
|
1629
|
+
return res
|
1630
|
+
|
1631
|
+
cpdef NumberFieldElement galois_conjugate(self):
|
1632
|
+
"""
|
1633
|
+
Return the image of this element under action of the nontrivial
|
1634
|
+
element of the Galois group of this field.
|
1635
|
+
|
1636
|
+
EXAMPLES::
|
1637
|
+
|
1638
|
+
sage: K.<a> = QuadraticField(23)
|
1639
|
+
sage: a.galois_conjugate()
|
1640
|
+
-a
|
1641
|
+
|
1642
|
+
sage: x = polygen(ZZ, 'x')
|
1643
|
+
sage: K.<a> = NumberField(x^2 - 5*x + 1)
|
1644
|
+
sage: a.galois_conjugate()
|
1645
|
+
-a + 5
|
1646
|
+
sage: b = 5*a + 1/3
|
1647
|
+
sage: b.galois_conjugate()
|
1648
|
+
-5*a + 76/3
|
1649
|
+
sage: b.norm() == b * b.galois_conjugate()
|
1650
|
+
True
|
1651
|
+
sage: b.trace() == b + b.galois_conjugate()
|
1652
|
+
True
|
1653
|
+
"""
|
1654
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
1655
|
+
mpz_set(res.a, self.a)
|
1656
|
+
mpz_neg(res.b, self.b)
|
1657
|
+
mpz_set(res.denom, self.denom)
|
1658
|
+
return res
|
1659
|
+
|
1660
|
+
#################################################################################
|
1661
|
+
# We must override everything that makes uses of self._numerator/_denominator
|
1662
|
+
#################################################################################
|
1663
|
+
|
1664
|
+
def __hash__(self):
|
1665
|
+
r"""
|
1666
|
+
Return hash of this number field element.
|
1667
|
+
|
1668
|
+
For elements in `\ZZ` or `\QQ` the hash coincides with the one in the
|
1669
|
+
native `\ZZ` or `\QQ`.
|
1670
|
+
|
1671
|
+
EXAMPLES::
|
1672
|
+
|
1673
|
+
sage: L.<a> = QuadraticField(-7)
|
1674
|
+
sage: hash(a)
|
1675
|
+
42082631
|
1676
|
+
sage: hash(L(1))
|
1677
|
+
1
|
1678
|
+
sage: hash(L(-3))
|
1679
|
+
-3
|
1680
|
+
sage: hash(L(-32/118)) == hash(-32/118)
|
1681
|
+
True
|
1682
|
+
"""
|
1683
|
+
# 1. compute the hash of a/denom as if it was a rational
|
1684
|
+
# (see the corresponding code in sage/rings/rational.pyx)
|
1685
|
+
cdef Py_hash_t n = mpz_pythonhash(self.a)
|
1686
|
+
cdef Py_hash_t d = mpz_pythonhash(self.denom)
|
1687
|
+
cdef Py_hash_t h = n + (d - 1) * <Py_hash_t>(7461864723258187525)
|
1688
|
+
|
1689
|
+
# 2. mix the hash together with b
|
1690
|
+
h += 42082631 * mpz_pythonhash(self.b)
|
1691
|
+
return h
|
1692
|
+
|
1693
|
+
def __bool__(self):
|
1694
|
+
"""
|
1695
|
+
Check whether this element is not zero.
|
1696
|
+
|
1697
|
+
EXAMPLES::
|
1698
|
+
|
1699
|
+
sage: x = polygen(ZZ, 'x')
|
1700
|
+
sage: K.<a> = NumberField(x^2 + 163)
|
1701
|
+
sage: not a
|
1702
|
+
False
|
1703
|
+
sage: not (a-a)
|
1704
|
+
True
|
1705
|
+
"""
|
1706
|
+
return mpz_cmp_ui(self.a, 0) != 0 or mpz_cmp_ui(self.b, 0) != 0
|
1707
|
+
|
1708
|
+
def _integer_(self, Z=None):
|
1709
|
+
"""
|
1710
|
+
EXAMPLES::
|
1711
|
+
|
1712
|
+
sage: x = polygen(ZZ, 'x')
|
1713
|
+
sage: K.<a> = NumberField(x^2 + 163)
|
1714
|
+
sage: (a+1-a)._integer_()
|
1715
|
+
1
|
1716
|
+
sage: (a+1/2-a)._integer_()
|
1717
|
+
Traceback (most recent call last):
|
1718
|
+
...
|
1719
|
+
TypeError: Unable to coerce 1/2 to an integer
|
1720
|
+
"""
|
1721
|
+
cdef Integer res
|
1722
|
+
if mpz_cmp_ui(self.b, 0) != 0 or mpz_cmp_ui(self.denom, 1) != 0:
|
1723
|
+
raise TypeError("Unable to coerce %s to an integer" % self)
|
1724
|
+
else:
|
1725
|
+
res = Integer.__new__(Integer)
|
1726
|
+
mpz_set(res.value, self.a)
|
1727
|
+
return res
|
1728
|
+
|
1729
|
+
def _rational_(self):
|
1730
|
+
"""
|
1731
|
+
EXAMPLES::
|
1732
|
+
|
1733
|
+
sage: x = polygen(ZZ, 'x')
|
1734
|
+
sage: K.<a> = NumberField(x^2 + 163)
|
1735
|
+
sage: (a+1/2-a)._rational_()
|
1736
|
+
1/2
|
1737
|
+
sage: (a+1/2)._rational_()
|
1738
|
+
Traceback (most recent call last):
|
1739
|
+
...
|
1740
|
+
TypeError: Unable to coerce a + 1/2 to a rational
|
1741
|
+
"""
|
1742
|
+
cdef Rational res
|
1743
|
+
if mpz_cmp_ui(self.b, 0)!=0:
|
1744
|
+
raise TypeError("Unable to coerce %s to a rational" % self)
|
1745
|
+
else:
|
1746
|
+
res = <Rational>Rational.__new__(Rational)
|
1747
|
+
mpz_set(mpq_numref(res.value), self.a)
|
1748
|
+
mpz_set(mpq_denref(res.value), self.denom)
|
1749
|
+
mpq_canonicalize(res.value)
|
1750
|
+
return res
|
1751
|
+
|
1752
|
+
cpdef bint is_one(self) noexcept:
|
1753
|
+
r"""
|
1754
|
+
Check whether this number field element is `1`.
|
1755
|
+
|
1756
|
+
EXAMPLES::
|
1757
|
+
|
1758
|
+
sage: K = QuadraticField(-2)
|
1759
|
+
sage: K(1).is_one()
|
1760
|
+
True
|
1761
|
+
sage: K(-1).is_one()
|
1762
|
+
False
|
1763
|
+
sage: K(2).is_one()
|
1764
|
+
False
|
1765
|
+
sage: K(0).is_one()
|
1766
|
+
False
|
1767
|
+
sage: K(1/2).is_one()
|
1768
|
+
False
|
1769
|
+
sage: K.gen().is_one()
|
1770
|
+
False
|
1771
|
+
"""
|
1772
|
+
return (mpz_cmp_ui(self.a, 1) == 0 and
|
1773
|
+
mpz_cmp_ui(self.b, 0) == 0 and
|
1774
|
+
mpz_cmp_ui(self.denom, 1) == 0)
|
1775
|
+
|
1776
|
+
cpdef bint is_rational(self) noexcept:
|
1777
|
+
r"""
|
1778
|
+
Check whether this number field element is a rational number.
|
1779
|
+
|
1780
|
+
.. SEEALSO::
|
1781
|
+
|
1782
|
+
- :meth:`is_integer` to test if this element is an integer
|
1783
|
+
- :meth:`is_integral` to test if this element is an algebraic integer
|
1784
|
+
|
1785
|
+
EXAMPLES::
|
1786
|
+
|
1787
|
+
sage: K.<sqrt3> = QuadraticField(3)
|
1788
|
+
sage: sqrt3.is_rational()
|
1789
|
+
False
|
1790
|
+
sage: (sqrt3 - 1/2).is_rational()
|
1791
|
+
False
|
1792
|
+
sage: K(0).is_rational()
|
1793
|
+
True
|
1794
|
+
sage: K(-12).is_rational()
|
1795
|
+
True
|
1796
|
+
sage: K(1/3).is_rational()
|
1797
|
+
True
|
1798
|
+
"""
|
1799
|
+
return mpz_cmp_ui(self.b, 0) == 0
|
1800
|
+
|
1801
|
+
def is_integer(self):
|
1802
|
+
r"""
|
1803
|
+
Check whether this number field element is an integer.
|
1804
|
+
|
1805
|
+
.. SEEALSO::
|
1806
|
+
|
1807
|
+
- :meth:`is_rational` to test if this element is a rational number
|
1808
|
+
- :meth:`is_integral` to test if this element is an algebraic integer
|
1809
|
+
|
1810
|
+
EXAMPLES::
|
1811
|
+
|
1812
|
+
sage: K.<sqrt3> = QuadraticField(3)
|
1813
|
+
sage: sqrt3.is_integer()
|
1814
|
+
False
|
1815
|
+
sage: (sqrt3 - 1/2).is_integer()
|
1816
|
+
False
|
1817
|
+
sage: K(0).is_integer()
|
1818
|
+
True
|
1819
|
+
sage: K(-12).is_integer()
|
1820
|
+
True
|
1821
|
+
sage: K(1/3).is_integer()
|
1822
|
+
False
|
1823
|
+
"""
|
1824
|
+
return mpz_cmp_ui(self.b, 0) == mpz_cmp_ui(self.denom, 1) == 0
|
1825
|
+
|
1826
|
+
def real(self):
|
1827
|
+
r"""
|
1828
|
+
Return the real part of ``self``, which is either ``self`` (if
|
1829
|
+
``self`` lives in a totally real field) or a rational number.
|
1830
|
+
|
1831
|
+
EXAMPLES::
|
1832
|
+
|
1833
|
+
sage: K.<sqrt2> = QuadraticField(2)
|
1834
|
+
sage: sqrt2.real()
|
1835
|
+
sqrt2
|
1836
|
+
sage: K.<a> = QuadraticField(-3)
|
1837
|
+
sage: a.real()
|
1838
|
+
0
|
1839
|
+
sage: (a + 1/2).real()
|
1840
|
+
1/2
|
1841
|
+
sage: x = polygen(ZZ, 'x')
|
1842
|
+
sage: K.<a> = NumberField(x^2 + x + 1)
|
1843
|
+
sage: a.real()
|
1844
|
+
-1/2
|
1845
|
+
sage: parent(a.real())
|
1846
|
+
Rational Field
|
1847
|
+
sage: K.<i> = QuadraticField(-1)
|
1848
|
+
sage: i.real()
|
1849
|
+
0
|
1850
|
+
"""
|
1851
|
+
cdef Rational res
|
1852
|
+
if mpz_sgn(self.D.value) > 0:
|
1853
|
+
return self # totally real
|
1854
|
+
else:
|
1855
|
+
res = <Rational>Rational.__new__(Rational)
|
1856
|
+
mpz_set(mpq_numref(res.value), self.a)
|
1857
|
+
mpz_set(mpq_denref(res.value), self.denom)
|
1858
|
+
mpq_canonicalize(res.value)
|
1859
|
+
return res
|
1860
|
+
|
1861
|
+
def imag(self):
|
1862
|
+
r"""
|
1863
|
+
Return the imaginary part of ``self``.
|
1864
|
+
|
1865
|
+
EXAMPLES::
|
1866
|
+
|
1867
|
+
sage: K.<sqrt2> = QuadraticField(2)
|
1868
|
+
sage: sqrt2.imag()
|
1869
|
+
0
|
1870
|
+
sage: parent(sqrt2.imag())
|
1871
|
+
Rational Field
|
1872
|
+
|
1873
|
+
sage: K.<i> = QuadraticField(-1)
|
1874
|
+
sage: i.imag()
|
1875
|
+
1
|
1876
|
+
sage: parent(i.imag())
|
1877
|
+
Rational Field
|
1878
|
+
|
1879
|
+
sage: x = polygen(ZZ, 'x')
|
1880
|
+
sage: K.<a> = NumberField(x^2 + x + 1, embedding=CDF.0)
|
1881
|
+
sage: a.imag()
|
1882
|
+
1/2*sqrt3
|
1883
|
+
sage: a.real()
|
1884
|
+
-1/2
|
1885
|
+
sage: SR(a) # needs sage.symbolic
|
1886
|
+
1/2*I*sqrt(3) - 1/2
|
1887
|
+
sage: bool(QQbar(I)*QQbar(a.imag()) + QQbar(a.real()) == QQbar(a))
|
1888
|
+
True
|
1889
|
+
|
1890
|
+
TESTS::
|
1891
|
+
|
1892
|
+
sage: K.<a> = QuadraticField(-9, embedding=-CDF.0)
|
1893
|
+
sage: a.imag()
|
1894
|
+
-3
|
1895
|
+
sage: parent(a.imag())
|
1896
|
+
Rational Field
|
1897
|
+
|
1898
|
+
Check that :issue:`22095` is fixed::
|
1899
|
+
|
1900
|
+
sage: K.<a> = NumberField(x^2 + 2*x + 14, embedding=CC(-1,+3))
|
1901
|
+
sage: K13.<sqrt13> = QuadraticField(13)
|
1902
|
+
sage: K13.zero()
|
1903
|
+
0
|
1904
|
+
sage: a.imag()
|
1905
|
+
sqrt13
|
1906
|
+
sage: K13.zero()
|
1907
|
+
0
|
1908
|
+
"""
|
1909
|
+
if mpz_sgn(self.D.value) > 0:
|
1910
|
+
return Rational.__new__(Rational) # = 0
|
1911
|
+
cdef Integer negD = <Integer>Integer.__new__(Integer)
|
1912
|
+
mpz_neg(negD.value, self.D.value)
|
1913
|
+
cdef NumberFieldElement_quadratic q = <NumberFieldElement_quadratic>self._new()
|
1914
|
+
mpz_set_ui(q.b, 1)
|
1915
|
+
mpz_set_ui(q.denom, 1)
|
1916
|
+
cdef Rational res
|
1917
|
+
if mpz_cmp_ui(negD.value, 1) == 0 or mpz_perfect_square_p(negD.value):
|
1918
|
+
# D = -1 is the most common case we'll see here
|
1919
|
+
if self._parent._embedding is None:
|
1920
|
+
raise ValueError("Embedding must be specified.")
|
1921
|
+
res = <Rational>Rational.__new__(Rational)
|
1922
|
+
if mpz_cmp_ui(negD.value, 1) == 0:
|
1923
|
+
mpz_set(mpq_numref(res.value), self.b)
|
1924
|
+
else:
|
1925
|
+
mpz_sqrt(mpq_numref(res.value), negD.value)
|
1926
|
+
mpz_mul(mpq_numref(res.value), mpq_numref(res.value), self.b)
|
1927
|
+
mpz_set(mpq_denref(res.value), self.denom)
|
1928
|
+
mpq_canonicalize(res.value)
|
1929
|
+
if not self.standard_embedding:
|
1930
|
+
mpq_neg(res.value, res.value)
|
1931
|
+
return res
|
1932
|
+
else:
|
1933
|
+
# avoid circular import
|
1934
|
+
if self._parent._embedding is None:
|
1935
|
+
from sage.rings.number_field.number_field import NumberField
|
1936
|
+
K = NumberField(QQ['x'].gen()**2 - negD, 'sqrt%s' % negD)
|
1937
|
+
else:
|
1938
|
+
from sage.rings.number_field.number_field import QuadraticField
|
1939
|
+
K = QuadraticField(negD, 'sqrt%s' % negD)
|
1940
|
+
q = (<NumberFieldElement_quadratic> K._zero_element)._new()
|
1941
|
+
mpz_set(q.denom, self.denom)
|
1942
|
+
mpz_set_ui(q.a, 0)
|
1943
|
+
if self.standard_embedding:
|
1944
|
+
mpz_set(q.b, self.b)
|
1945
|
+
else:
|
1946
|
+
mpz_neg(q.b, self.b)
|
1947
|
+
return q
|
1948
|
+
|
1949
|
+
cpdef list _coefficients(self):
|
1950
|
+
"""
|
1951
|
+
EXAMPLES::
|
1952
|
+
|
1953
|
+
sage: x = polygen(ZZ, 'x')
|
1954
|
+
sage: F.<b> = NumberField(x^2 - x + 7)
|
1955
|
+
sage: b._coefficients()
|
1956
|
+
[0, 1]
|
1957
|
+
"""
|
1958
|
+
if not self:
|
1959
|
+
return []
|
1960
|
+
ad, bd = self.parts()
|
1961
|
+
if not bd:
|
1962
|
+
return [ad]
|
1963
|
+
|
1964
|
+
cdef NumberFieldElement_quadratic gen = self.number_field().gen() # should this be cached?
|
1965
|
+
alpha, beta = gen.parts()
|
1966
|
+
scale = bd/beta
|
1967
|
+
return [ad - scale*alpha, scale]
|
1968
|
+
|
1969
|
+
def denominator(self):
|
1970
|
+
r"""
|
1971
|
+
Return the denominator of ``self``.
|
1972
|
+
|
1973
|
+
This is the LCM of the denominators of the coefficients of ``self``, and
|
1974
|
+
thus it may well be `> 1` even when the element is an algebraic integer.
|
1975
|
+
|
1976
|
+
EXAMPLES::
|
1977
|
+
|
1978
|
+
sage: x = polygen(ZZ, 'x')
|
1979
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
1980
|
+
sage: b = (a + 1)/2
|
1981
|
+
sage: b.denominator()
|
1982
|
+
2
|
1983
|
+
sage: b.is_integral()
|
1984
|
+
True
|
1985
|
+
|
1986
|
+
sage: K.<c> = NumberField(x^2 - x + 7)
|
1987
|
+
sage: c.denominator()
|
1988
|
+
1
|
1989
|
+
"""
|
1990
|
+
c = self._coefficients()
|
1991
|
+
if len(c) == 2:
|
1992
|
+
const, lin = c
|
1993
|
+
elif len(c) == 1:
|
1994
|
+
const = c[0]
|
1995
|
+
lin = Rational(0)
|
1996
|
+
else:
|
1997
|
+
const = lin = Rational(0)
|
1998
|
+
return const.denominator().lcm(lin.denominator())
|
1999
|
+
|
2000
|
+
def numerator(self):
|
2001
|
+
r"""
|
2002
|
+
Return ``self * self.denominator()``.
|
2003
|
+
|
2004
|
+
EXAMPLES::
|
2005
|
+
|
2006
|
+
sage: x = polygen(ZZ, 'x')
|
2007
|
+
sage: K.<a> = NumberField(x^2 + x + 41)
|
2008
|
+
sage: b = (2*a+1)/6
|
2009
|
+
sage: b.denominator()
|
2010
|
+
6
|
2011
|
+
sage: b.numerator()
|
2012
|
+
2*a + 1
|
2013
|
+
"""
|
2014
|
+
return self * self.denominator()
|
2015
|
+
|
2016
|
+
#########################################################
|
2017
|
+
# Some things are so much easier to compute
|
2018
|
+
#########################################################
|
2019
|
+
|
2020
|
+
def trace(self):
|
2021
|
+
"""
|
2022
|
+
EXAMPLES::
|
2023
|
+
|
2024
|
+
sage: x = polygen(ZZ, 'x')
|
2025
|
+
sage: K.<a> = NumberField(x^2 + x + 41)
|
2026
|
+
sage: a.trace()
|
2027
|
+
-1
|
2028
|
+
sage: a.matrix()
|
2029
|
+
[ 0 1]
|
2030
|
+
[-41 -1]
|
2031
|
+
|
2032
|
+
The trace is additive::
|
2033
|
+
|
2034
|
+
sage: K.<a> = NumberField(x^2 + 7)
|
2035
|
+
sage: (a + 1).trace()
|
2036
|
+
2
|
2037
|
+
sage: K(3).trace()
|
2038
|
+
6
|
2039
|
+
sage: (a + 4).trace()
|
2040
|
+
8
|
2041
|
+
sage: (a/3 + 1).trace()
|
2042
|
+
2
|
2043
|
+
"""
|
2044
|
+
# trace = 2*self.a / self.denom
|
2045
|
+
cdef Rational res = <Rational>Rational.__new__(Rational)
|
2046
|
+
if mpz_odd_p(self.denom):
|
2047
|
+
mpz_mul_2exp(mpq_numref(res.value), self.a, 1)
|
2048
|
+
mpz_set(mpq_denref(res.value), self.denom)
|
2049
|
+
else:
|
2050
|
+
mpz_set(mpq_numref(res.value), self.a)
|
2051
|
+
mpz_divexact_ui(mpq_denref(res.value), self.denom, 2)
|
2052
|
+
mpq_canonicalize(res.value)
|
2053
|
+
return res
|
2054
|
+
|
2055
|
+
def norm(self, K=None):
|
2056
|
+
r"""
|
2057
|
+
Return the norm of ``self``.
|
2058
|
+
|
2059
|
+
If the second argument is ``None``, this is the
|
2060
|
+
norm down to `\QQ`. Otherwise, return the norm down to `K` (which had
|
2061
|
+
better be either `\QQ` or this number field).
|
2062
|
+
|
2063
|
+
EXAMPLES::
|
2064
|
+
|
2065
|
+
sage: x = polygen(ZZ, 'x')
|
2066
|
+
sage: K.<a> = NumberField(x^2 - x + 3)
|
2067
|
+
sage: a.norm()
|
2068
|
+
3
|
2069
|
+
sage: a.matrix()
|
2070
|
+
[ 0 1]
|
2071
|
+
[-3 1]
|
2072
|
+
sage: K.<a> = NumberField(x^2 + 5)
|
2073
|
+
sage: (1 + a).norm()
|
2074
|
+
6
|
2075
|
+
|
2076
|
+
The norm is multiplicative::
|
2077
|
+
|
2078
|
+
sage: K.<a> = NumberField(x^2 - 3)
|
2079
|
+
sage: a.norm()
|
2080
|
+
-3
|
2081
|
+
sage: K(3).norm()
|
2082
|
+
9
|
2083
|
+
sage: (3*a).norm()
|
2084
|
+
-27
|
2085
|
+
|
2086
|
+
We test that the optional argument is handled sensibly::
|
2087
|
+
|
2088
|
+
sage: (3*a).norm(QQ)
|
2089
|
+
-27
|
2090
|
+
sage: (3*a).norm(K)
|
2091
|
+
3*a
|
2092
|
+
sage: (3*a).norm(CyclotomicField(3))
|
2093
|
+
Traceback (most recent call last):
|
2094
|
+
...
|
2095
|
+
ValueError: no way to embed L into parent's base ring K
|
2096
|
+
"""
|
2097
|
+
cdef Rational res = <Rational>Rational.__new__(Rational)
|
2098
|
+
|
2099
|
+
if K is None or K == QQ:
|
2100
|
+
# norm = (a^2 - d b^2) / self.denom^2
|
2101
|
+
mpz_pow_ui(mpq_numref(res.value), self.a, 2)
|
2102
|
+
mpz_pow_ui(mpq_denref(res.value), self.b, 2) # use as temp
|
2103
|
+
mpz_mul(mpq_denref(res.value), mpq_denref(res.value), self.D.value)
|
2104
|
+
mpz_sub(mpq_numref(res.value), mpq_numref(res.value), mpq_denref(res.value))
|
2105
|
+
mpz_pow_ui(mpq_denref(res.value), self.denom, 2)
|
2106
|
+
mpq_canonicalize(res.value)
|
2107
|
+
return res
|
2108
|
+
else:
|
2109
|
+
return NumberFieldElement.norm(self, K)
|
2110
|
+
|
2111
|
+
def is_integral(self):
|
2112
|
+
r"""
|
2113
|
+
Return whether this element is an algebraic integer.
|
2114
|
+
|
2115
|
+
TESTS::
|
2116
|
+
|
2117
|
+
sage: K.<a> = QuadraticField(-1)
|
2118
|
+
sage: a.is_integral()
|
2119
|
+
True
|
2120
|
+
sage: K(1).is_integral()
|
2121
|
+
True
|
2122
|
+
sage: K(1/2).is_integral()
|
2123
|
+
False
|
2124
|
+
sage: (a/2).is_integral()
|
2125
|
+
False
|
2126
|
+
sage: ((a+1)/2).is_integral()
|
2127
|
+
False
|
2128
|
+
sage: ((a+1)/3).is_integral()
|
2129
|
+
False
|
2130
|
+
|
2131
|
+
sage: K.<a> = QuadraticField(-3)
|
2132
|
+
sage: a.is_integral()
|
2133
|
+
True
|
2134
|
+
sage: K(1).is_integral()
|
2135
|
+
True
|
2136
|
+
sage: K(1/2).is_integral()
|
2137
|
+
False
|
2138
|
+
sage: (a/2).is_integral()
|
2139
|
+
False
|
2140
|
+
sage: ((a+1)/2).is_integral()
|
2141
|
+
True
|
2142
|
+
sage: ((a+1)/3).is_integral()
|
2143
|
+
False
|
2144
|
+
|
2145
|
+
This works for order elements too, see :issue:`24077`::
|
2146
|
+
|
2147
|
+
sage: O.<w> = EisensteinIntegers()
|
2148
|
+
sage: w.is_integral()
|
2149
|
+
True
|
2150
|
+
sage: for _ in range(20):
|
2151
|
+
....: assert O.random_element().is_integral()
|
2152
|
+
|
2153
|
+
Check that :issue:`34800` is fixed::
|
2154
|
+
|
2155
|
+
sage: K.<t> = QuadraticField(-10007^2)
|
2156
|
+
sage: (t/10007).is_integral()
|
2157
|
+
True
|
2158
|
+
"""
|
2159
|
+
cdef mpz_t m, n, q, r, s, t, u
|
2160
|
+
cdef bint result = False
|
2161
|
+
|
2162
|
+
# Shortcut for "obviously integral" elements
|
2163
|
+
if mpz_cmp_ui(self.denom, 1) == 0:
|
2164
|
+
return True
|
2165
|
+
|
2166
|
+
# a + b*sqrt(D) is integral if and only if
|
2167
|
+
# denom | 2*a and denom^2 | a^2 - D*b^2.
|
2168
|
+
# Do division with remainder: 2*a = denom*m + n.
|
2169
|
+
mpz_init(t)
|
2170
|
+
mpz_init(m)
|
2171
|
+
mpz_init(n)
|
2172
|
+
mpz_mul_ui(t, self.a, 2)
|
2173
|
+
mpz_fdiv_qr(m, n, t, self.denom)
|
2174
|
+
if mpz_cmp_ui(n, 0) == 0:
|
2175
|
+
# Now 2*a = denom*m.
|
2176
|
+
# If m is even, then denom | a and gcd(denom, b) = 1, so
|
2177
|
+
# a + b*sqrt(D) is integral if and only if denom^2 | D.
|
2178
|
+
# If m is odd, then denom is even; put u = denom/2.
|
2179
|
+
# Then a + b*sqrt(D) is integral if and only if
|
2180
|
+
# b is odd, u^2 | D and D/u^2 is congruent to 1 mod 4.
|
2181
|
+
if mpz_even_p(m):
|
2182
|
+
mpz_init(s)
|
2183
|
+
mpz_mul(s, self.denom, self.denom)
|
2184
|
+
result = mpz_divisible_p(self.D.value, s)
|
2185
|
+
mpz_clear(s)
|
2186
|
+
elif mpz_odd_p(self.b):
|
2187
|
+
mpz_init(u)
|
2188
|
+
mpz_init(s)
|
2189
|
+
mpz_init(q)
|
2190
|
+
mpz_init(r)
|
2191
|
+
mpz_divexact_ui(u, self.denom, 2)
|
2192
|
+
mpz_mul(s, u, u)
|
2193
|
+
mpz_fdiv_qr(q, r, self.D.value, s)
|
2194
|
+
result = mpz_cmp_ui(r, 0) == 0 and mpz_fdiv_ui(q, 4) == 1
|
2195
|
+
mpz_clear(u)
|
2196
|
+
mpz_clear(s)
|
2197
|
+
mpz_clear(q)
|
2198
|
+
mpz_clear(r)
|
2199
|
+
mpz_clear(t)
|
2200
|
+
mpz_clear(m)
|
2201
|
+
mpz_clear(n)
|
2202
|
+
return result
|
2203
|
+
|
2204
|
+
def charpoly(self, var='x', algorithm=None):
|
2205
|
+
r"""
|
2206
|
+
The characteristic polynomial of this element over `\QQ`.
|
2207
|
+
|
2208
|
+
INPUT:
|
2209
|
+
|
2210
|
+
- ``var`` -- the minimal polynomial is defined over a polynomial ring
|
2211
|
+
in a variable with this name; if not specified, this defaults to ``'x'``
|
2212
|
+
- ``algorithm`` -- for compatibility with general number field
|
2213
|
+
elements; ignored
|
2214
|
+
|
2215
|
+
EXAMPLES::
|
2216
|
+
|
2217
|
+
sage: x = polygen(ZZ, 'x')
|
2218
|
+
sage: K.<a> = NumberField(x^2 - x + 13)
|
2219
|
+
sage: a.charpoly()
|
2220
|
+
x^2 - x + 13
|
2221
|
+
sage: b = 3 - a/2
|
2222
|
+
sage: f = b.charpoly(); f
|
2223
|
+
x^2 - 11/2*x + 43/4
|
2224
|
+
sage: f(b)
|
2225
|
+
0
|
2226
|
+
"""
|
2227
|
+
R = QQ[var]
|
2228
|
+
return R([self.norm(), -self.trace(), 1])
|
2229
|
+
|
2230
|
+
def minpoly(self, var='x', algorithm=None):
|
2231
|
+
r"""
|
2232
|
+
The minimal polynomial of this element over `\QQ`.
|
2233
|
+
|
2234
|
+
INPUT:
|
2235
|
+
|
2236
|
+
- ``var`` -- the minimal polynomial is defined over a polynomial ring
|
2237
|
+
in a variable with this name; if not specified, this defaults to ``'x'``
|
2238
|
+
- ``algorithm`` -- for compatibility with general number field
|
2239
|
+
elements; ignored
|
2240
|
+
|
2241
|
+
EXAMPLES::
|
2242
|
+
|
2243
|
+
sage: x = polygen(ZZ, 'x')
|
2244
|
+
sage: K.<a> = NumberField(x^2 + 13)
|
2245
|
+
sage: a.minpoly()
|
2246
|
+
x^2 + 13
|
2247
|
+
sage: a.minpoly('T')
|
2248
|
+
T^2 + 13
|
2249
|
+
sage: (a + 1/2 - a).minpoly()
|
2250
|
+
x - 1/2
|
2251
|
+
"""
|
2252
|
+
if self.is_rational():
|
2253
|
+
R = QQ[var]
|
2254
|
+
return R([-self._rational_(), 1])
|
2255
|
+
else:
|
2256
|
+
return self.charpoly(var)
|
2257
|
+
|
2258
|
+
def __abs__(self):
|
2259
|
+
"""
|
2260
|
+
EXAMPLES::
|
2261
|
+
|
2262
|
+
sage: K.<a> = QuadraticField(2, 'a', embedding=-1.4142)
|
2263
|
+
sage: abs(a) # indirect test
|
2264
|
+
-a
|
2265
|
+
sage: abs(a+1) # indirect test
|
2266
|
+
-a - 1
|
2267
|
+
sage: abs(a+2) # indirect test
|
2268
|
+
a + 2
|
2269
|
+
|
2270
|
+
sage: x = polygen(ZZ, 'x')
|
2271
|
+
sage: K.<a> = NumberField(x^2 + 1, embedding=CDF.gen())
|
2272
|
+
sage: abs(a+1) # needs sage.symbolic
|
2273
|
+
sqrt(2)
|
2274
|
+
"""
|
2275
|
+
if mpz_sgn(self.D.value) == 1:
|
2276
|
+
if self.sign() >= 0:
|
2277
|
+
return self
|
2278
|
+
return -self
|
2279
|
+
|
2280
|
+
# doing that way the parent is the symbolic ring (or IntegerRing if the
|
2281
|
+
# norm of self is a square). On the other hand, it is coherent with
|
2282
|
+
# sage.rings.integer.Integer.sqrt
|
2283
|
+
return (self.real()**2 + self.imag()**2).sqrt()
|
2284
|
+
|
2285
|
+
def floor(self):
|
2286
|
+
r"""
|
2287
|
+
Return the floor of ``self``.
|
2288
|
+
|
2289
|
+
EXAMPLES::
|
2290
|
+
|
2291
|
+
sage: K.<sqrt2> = QuadraticField(2, name='sqrt2')
|
2292
|
+
sage: sqrt2.floor()
|
2293
|
+
1
|
2294
|
+
sage: (-sqrt2).floor()
|
2295
|
+
-2
|
2296
|
+
sage: (13/197 + 3702/123*sqrt2).floor()
|
2297
|
+
42
|
2298
|
+
sage: (13/197 - 3702/123*sqrt2).floor()
|
2299
|
+
-43
|
2300
|
+
|
2301
|
+
TESTS::
|
2302
|
+
|
2303
|
+
sage: K2.<sqrt2> = QuadraticField(2)
|
2304
|
+
sage: K3.<sqrt3> = QuadraticField(3)
|
2305
|
+
sage: K5.<sqrt5> = QuadraticField(5)
|
2306
|
+
sage: for _ in range(100):
|
2307
|
+
....: a = QQ.random_element(1000,20)
|
2308
|
+
....: b = QQ.random_element(1000,20)
|
2309
|
+
....: assert floor(a+b*sqrt(2.)) == floor(a+b*sqrt2)
|
2310
|
+
....: assert floor(a+b*sqrt(3.)) == floor(a+b*sqrt3)
|
2311
|
+
....: assert floor(a+b*sqrt(5.)) == floor(a+b*sqrt5)
|
2312
|
+
|
2313
|
+
sage: K = QuadraticField(-2)
|
2314
|
+
sage: l = [K(52), K(-3), K(43/12), K(-43/12)]
|
2315
|
+
sage: [x.floor() for x in l]
|
2316
|
+
[52, -3, 3, -4]
|
2317
|
+
"""
|
2318
|
+
cdef mpz_t x
|
2319
|
+
cdef Integer result
|
2320
|
+
|
2321
|
+
if mpz_sgn(self.b) == 0:
|
2322
|
+
mpz_init_set(x,self.a)
|
2323
|
+
mpz_fdiv_q(x,x,self.denom)
|
2324
|
+
result = Integer.__new__(Integer)
|
2325
|
+
mpz_set(result.value,x)
|
2326
|
+
mpz_clear(x)
|
2327
|
+
return result
|
2328
|
+
|
2329
|
+
if not mpz_sgn(self.D.value) == 1:
|
2330
|
+
raise ValueError("floor is not defined for complex quadratic number field")
|
2331
|
+
|
2332
|
+
mpz_init(x)
|
2333
|
+
mpz_mul(x,self.b,self.b)
|
2334
|
+
mpz_mul(x,x,self.D.value)
|
2335
|
+
mpz_sqrt(x,x)
|
2336
|
+
if mpz_sgn(self.b) == -1:
|
2337
|
+
if self.standard_embedding:
|
2338
|
+
mpz_neg(x,x)
|
2339
|
+
mpz_sub_ui(x,x,1)
|
2340
|
+
elif not self.standard_embedding:
|
2341
|
+
mpz_neg(x,x)
|
2342
|
+
mpz_sub_ui(x,x,1)
|
2343
|
+
|
2344
|
+
mpz_add(x,x,self.a) # here x = a + floor(sqrt(b^2 D)) or a + floor(-sqrt(b^2 D))
|
2345
|
+
mpz_fdiv_q(x,x,self.denom)
|
2346
|
+
result = Integer.__new__(Integer)
|
2347
|
+
mpz_set(result.value,x)
|
2348
|
+
mpz_clear(x)
|
2349
|
+
return result
|
2350
|
+
|
2351
|
+
def ceil(self):
|
2352
|
+
r"""
|
2353
|
+
Return the ceil.
|
2354
|
+
|
2355
|
+
EXAMPLES::
|
2356
|
+
|
2357
|
+
sage: K.<sqrt7> = QuadraticField(7, name='sqrt7')
|
2358
|
+
sage: sqrt7.ceil()
|
2359
|
+
3
|
2360
|
+
sage: (-sqrt7).ceil()
|
2361
|
+
-2
|
2362
|
+
sage: (1022/313*sqrt7 - 14/23).ceil()
|
2363
|
+
9
|
2364
|
+
|
2365
|
+
TESTS::
|
2366
|
+
|
2367
|
+
sage: K2.<sqrt2> = QuadraticField(2)
|
2368
|
+
sage: K3.<sqrt3> = QuadraticField(3)
|
2369
|
+
sage: K5.<sqrt5> = QuadraticField(5)
|
2370
|
+
sage: for _ in range(100):
|
2371
|
+
....: a = QQ.random_element(1000,20)
|
2372
|
+
....: b = QQ.random_element(1000,20)
|
2373
|
+
....: assert ceil(a+b*sqrt(2.)) == ceil(a+b*sqrt2)
|
2374
|
+
....: assert ceil(a+b*sqrt(3.)) == ceil(a+b*sqrt3)
|
2375
|
+
....: assert ceil(a+b*sqrt(5.)) == ceil(a+b*sqrt5)
|
2376
|
+
|
2377
|
+
sage: K = QuadraticField(-2)
|
2378
|
+
sage: l = [K(52), K(-3), K(43/12), K(-43/12)]
|
2379
|
+
sage: [x.ceil() for x in l]
|
2380
|
+
[52, -3, 4, -3]
|
2381
|
+
"""
|
2382
|
+
x = self.floor()
|
2383
|
+
if mpz_sgn(self.b) == 0 and mpz_cmp_ui(self.denom,1) == 0:
|
2384
|
+
return x
|
2385
|
+
return x+1
|
2386
|
+
|
2387
|
+
def round(self):
|
2388
|
+
r"""
|
2389
|
+
Return the round (nearest integer) of this number field element. In case
|
2390
|
+
of ties, this relies on the default rounding for rational numbers.
|
2391
|
+
|
2392
|
+
EXAMPLES::
|
2393
|
+
|
2394
|
+
sage: K.<sqrt7> = QuadraticField(7, name='sqrt7')
|
2395
|
+
sage: sqrt7.round()
|
2396
|
+
3
|
2397
|
+
sage: (-sqrt7).round()
|
2398
|
+
-3
|
2399
|
+
sage: (12/313*sqrt7 - 1745917/2902921).round()
|
2400
|
+
0
|
2401
|
+
sage: (12/313*sqrt7 - 1745918/2902921).round()
|
2402
|
+
-1
|
2403
|
+
|
2404
|
+
TESTS::
|
2405
|
+
|
2406
|
+
sage: K2.<sqrt2> = QuadraticField(2)
|
2407
|
+
sage: K3.<sqrt3> = QuadraticField(3)
|
2408
|
+
sage: K5.<sqrt5> = QuadraticField(5)
|
2409
|
+
sage: for _ in range(100):
|
2410
|
+
....: a = QQ.random_element(1000,20)
|
2411
|
+
....: b = QQ.random_element(1000,20)
|
2412
|
+
....: assert a.round() == round(K2(a)), a
|
2413
|
+
....: assert a.round() == round(K3(a)), a
|
2414
|
+
....: assert a.round() == round(K5(a)), a
|
2415
|
+
....: assert round(a+b*sqrt(2.)) == round(a+b*sqrt2), (a, b)
|
2416
|
+
....: assert round(a+b*sqrt(3.)) == round(a+b*sqrt3), (a, b)
|
2417
|
+
....: assert round(a+b*sqrt(5.)) == round(a+b*sqrt5), (a, b)
|
2418
|
+
"""
|
2419
|
+
n = self.floor()
|
2420
|
+
test = 2 * (self - n)
|
2421
|
+
if test < 1:
|
2422
|
+
return n
|
2423
|
+
elif test > 1:
|
2424
|
+
return n + 1
|
2425
|
+
elif n % 2 == 0:
|
2426
|
+
return n
|
2427
|
+
else:
|
2428
|
+
return n + 1
|
2429
|
+
|
2430
|
+
|
2431
|
+
cdef class NumberFieldElement_quadratic_sqrt(NumberFieldElement_quadratic):
|
2432
|
+
r"""
|
2433
|
+
A :class:`NumberFieldElement_quadratic_sqrt` object gives an efficient representation of
|
2434
|
+
an element of a quadratic extension of `\QQ` for the case when
|
2435
|
+
:func:`is_sqrt_disc()` is ``True``.
|
2436
|
+
"""
|
2437
|
+
def denominator(self):
|
2438
|
+
r"""
|
2439
|
+
Return the denominator of ``self``.
|
2440
|
+
|
2441
|
+
This is the LCM of the denominators of the coefficients of ``self``, and
|
2442
|
+
thus it may well be `> 1` even when the element is an algebraic integer.
|
2443
|
+
|
2444
|
+
EXAMPLES::
|
2445
|
+
|
2446
|
+
sage: x = polygen(ZZ, 'x')
|
2447
|
+
sage: K.<a> = NumberField(x^2 + x + 41)
|
2448
|
+
sage: a.denominator()
|
2449
|
+
1
|
2450
|
+
sage: b = (2*a+1)/6
|
2451
|
+
sage: b.denominator()
|
2452
|
+
6
|
2453
|
+
sage: K(1).denominator()
|
2454
|
+
1
|
2455
|
+
sage: K(1/2).denominator()
|
2456
|
+
2
|
2457
|
+
sage: K(0).denominator()
|
2458
|
+
1
|
2459
|
+
|
2460
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
2461
|
+
sage: b = (a + 1)/2
|
2462
|
+
sage: b.denominator()
|
2463
|
+
2
|
2464
|
+
sage: b.is_integral()
|
2465
|
+
True
|
2466
|
+
"""
|
2467
|
+
cdef Integer denom
|
2468
|
+
denom = Integer.__new__(Integer)
|
2469
|
+
mpz_set(denom.value, self.denom)
|
2470
|
+
return denom
|
2471
|
+
|
2472
|
+
cpdef list _coefficients(self):
|
2473
|
+
"""
|
2474
|
+
EXAMPLES::
|
2475
|
+
|
2476
|
+
sage: x = polygen(ZZ, 'x')
|
2477
|
+
sage: K.<a> = NumberField(x^2 + 41)
|
2478
|
+
sage: a._coefficients()
|
2479
|
+
[0, 1]
|
2480
|
+
sage: K.zero()._coefficients()
|
2481
|
+
[]
|
2482
|
+
sage: (3/2*K.one())._coefficients()
|
2483
|
+
[3/2]
|
2484
|
+
"""
|
2485
|
+
if not self:
|
2486
|
+
return []
|
2487
|
+
cdef tuple parts = self.parts()
|
2488
|
+
if not <Rational> (parts[1]):
|
2489
|
+
return [parts[0]]
|
2490
|
+
return list(parts)
|
2491
|
+
|
2492
|
+
def __getitem__(self, n):
|
2493
|
+
"""
|
2494
|
+
Return the ``n``-th coefficient of this number field element,
|
2495
|
+
written as a polynomial in the generator.
|
2496
|
+
|
2497
|
+
Note that ``n`` must be either ``0`` or ``1``.
|
2498
|
+
|
2499
|
+
EXAMPLES::
|
2500
|
+
|
2501
|
+
sage: x = polygen(ZZ, 'x')
|
2502
|
+
sage: K.<a> = NumberField(x^2 - 13)
|
2503
|
+
sage: elt = a/4 + 1/3
|
2504
|
+
sage: elt[0]
|
2505
|
+
1/3
|
2506
|
+
sage: elt[1]
|
2507
|
+
1/4
|
2508
|
+
|
2509
|
+
sage: K.zero()[0]
|
2510
|
+
0
|
2511
|
+
sage: K.zero()[1]
|
2512
|
+
0
|
2513
|
+
|
2514
|
+
sage: K.one()[0]
|
2515
|
+
1
|
2516
|
+
sage: K.one()[1]
|
2517
|
+
0
|
2518
|
+
|
2519
|
+
sage: elt[2]
|
2520
|
+
Traceback (most recent call last):
|
2521
|
+
...
|
2522
|
+
IndexError: index must be either 0 or 1
|
2523
|
+
|
2524
|
+
sage: C.<z3> = CyclotomicField(3)
|
2525
|
+
sage: list(z3)
|
2526
|
+
[0, 1]
|
2527
|
+
"""
|
2528
|
+
try:
|
2529
|
+
return self.parts()[n]
|
2530
|
+
except IndexError: # So we have a better error message
|
2531
|
+
raise IndexError("index must be either 0 or 1")
|
2532
|
+
|
2533
|
+
cdef class NumberFieldElement_gaussian(NumberFieldElement_quadratic_sqrt):
|
2534
|
+
r"""
|
2535
|
+
An element of `\QQ[i]`.
|
2536
|
+
|
2537
|
+
Some methods of this class behave slightly differently than the
|
2538
|
+
corresponding methods of general elements of quadratic number fields,
|
2539
|
+
especially with regard to conversions to parents that can represent complex
|
2540
|
+
numbers in rectangular form.
|
2541
|
+
|
2542
|
+
In addition, this class provides some convenience methods similar to methods
|
2543
|
+
of symbolic expressions to make the behavior of ``a + I*b`` with rational
|
2544
|
+
``a``, ``b`` closer to that when ``a``, ``b`` are expressions.
|
2545
|
+
|
2546
|
+
EXAMPLES::
|
2547
|
+
|
2548
|
+
sage: type(I)
|
2549
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_gaussian'>
|
2550
|
+
|
2551
|
+
sage: mi = QuadraticField(-1, embedding=CC(0,-1)).gen()
|
2552
|
+
sage: type(mi)
|
2553
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.NumberFieldElement_gaussian'>
|
2554
|
+
sage: CC(mi)
|
2555
|
+
-1.00000000000000*I
|
2556
|
+
"""
|
2557
|
+
|
2558
|
+
def _symbolic_(self, SR):
|
2559
|
+
r"""
|
2560
|
+
EXAMPLES::
|
2561
|
+
|
2562
|
+
sage: SR(1 + 2*i) # needs sage.symbolic
|
2563
|
+
2*I + 1
|
2564
|
+
|
2565
|
+
sage: K.<mi> = QuadraticField(-1, embedding=CC(0,-1))
|
2566
|
+
sage: SR(1 + mi) # needs sage.symbolic
|
2567
|
+
-I + 1
|
2568
|
+
"""
|
2569
|
+
from sage.symbolic.constants import I
|
2570
|
+
return self[1]*(I if self.standard_embedding else -I) + self[0]
|
2571
|
+
|
2572
|
+
def _algebraic_(self, parent):
|
2573
|
+
r"""
|
2574
|
+
Convert this element to an algebraic number, if possible.
|
2575
|
+
|
2576
|
+
EXAMPLES::
|
2577
|
+
|
2578
|
+
sage: NF.<i> = QuadraticField(-1)
|
2579
|
+
sage: QQbar(i+2)
|
2580
|
+
I + 2
|
2581
|
+
sage: K.<ii> = QuadraticField(-1, embedding=CC(0,-1))
|
2582
|
+
sage: QQbar(ii+2)
|
2583
|
+
-I + 2
|
2584
|
+
sage: AA(i)
|
2585
|
+
Traceback (most recent call last):
|
2586
|
+
...
|
2587
|
+
ValueError: unable to convert i to an element of Algebraic Real Field
|
2588
|
+
|
2589
|
+
TESTS:
|
2590
|
+
|
2591
|
+
Check that :issue:`31808` is fixed::
|
2592
|
+
|
2593
|
+
sage: C.<I> = QuadraticField(-1)
|
2594
|
+
sage: AA(C.one())
|
2595
|
+
1
|
2596
|
+
sage: AA(C.zero())
|
2597
|
+
0
|
2598
|
+
"""
|
2599
|
+
import sage.rings.qqbar as qqbar
|
2600
|
+
cdef tuple coeffs
|
2601
|
+
if parent is qqbar.QQbar:
|
2602
|
+
# AlgebraicNumber.__init__ does a better job than
|
2603
|
+
# NumberFieldElement._algebraic_ in this case, but
|
2604
|
+
# QQbar._element_constructor_ calls the latter first.
|
2605
|
+
return qqbar.AlgebraicNumber(self)
|
2606
|
+
if parent is qqbar.AA:
|
2607
|
+
coeffs = self.parts()
|
2608
|
+
if coeffs[1].is_zero():
|
2609
|
+
return qqbar.AlgebraicReal(coeffs[0])
|
2610
|
+
raise ValueError(f"unable to convert {self!r} to an element of {parent!r}")
|
2611
|
+
|
2612
|
+
cpdef real_part(self):
|
2613
|
+
r"""
|
2614
|
+
Real part.
|
2615
|
+
|
2616
|
+
EXAMPLES::
|
2617
|
+
|
2618
|
+
sage: (1 + 2*I).real()
|
2619
|
+
1
|
2620
|
+
sage: (1 + 2*I).real().parent()
|
2621
|
+
Rational Field
|
2622
|
+
"""
|
2623
|
+
cdef Rational ad = <Rational> Rational.__new__(Rational)
|
2624
|
+
if mpz_cmp_ui(self.a, 0) == 0:
|
2625
|
+
mpq_set_ui(ad.value, 0, 1)
|
2626
|
+
else:
|
2627
|
+
mpz_set(mpq_numref(ad.value), self.a)
|
2628
|
+
mpz_set(mpq_denref(ad.value), self.denom)
|
2629
|
+
mpq_canonicalize(ad.value)
|
2630
|
+
return ad
|
2631
|
+
|
2632
|
+
real = real_part
|
2633
|
+
|
2634
|
+
cpdef imag_part(self):
|
2635
|
+
r"""
|
2636
|
+
Imaginary part.
|
2637
|
+
|
2638
|
+
EXAMPLES::
|
2639
|
+
|
2640
|
+
sage: (1 + 2*I).imag()
|
2641
|
+
2
|
2642
|
+
sage: (1 + 2*I).imag().parent()
|
2643
|
+
Rational Field
|
2644
|
+
|
2645
|
+
sage: K.<mi> = QuadraticField(-1, embedding=CC(0,-1))
|
2646
|
+
sage: (1 - mi).imag()
|
2647
|
+
1
|
2648
|
+
"""
|
2649
|
+
cdef Rational bd = <Rational> Rational.__new__(Rational)
|
2650
|
+
if mpz_cmp_ui(self.b, 0) == 0:
|
2651
|
+
# It is 0, so all we need to do is initialize the result
|
2652
|
+
mpq_set_ui(bd.value, 0, 1)
|
2653
|
+
return bd
|
2654
|
+
|
2655
|
+
mpz_set(mpq_numref(bd.value), self.b)
|
2656
|
+
mpz_set(mpq_denref(bd.value), self.denom)
|
2657
|
+
mpq_canonicalize(bd.value)
|
2658
|
+
if not self.standard_embedding:
|
2659
|
+
mpq_neg(bd.value, bd.value)
|
2660
|
+
return bd
|
2661
|
+
|
2662
|
+
imag = imag_part
|
2663
|
+
|
2664
|
+
# for compatibility with the old symbolic I
|
2665
|
+
|
2666
|
+
def log(self, *args, **kwds):
|
2667
|
+
r"""
|
2668
|
+
Complex logarithm (standard branch).
|
2669
|
+
|
2670
|
+
EXAMPLES::
|
2671
|
+
|
2672
|
+
sage: I.log() # needs sage.symbolic
|
2673
|
+
1/2*I*pi
|
2674
|
+
"""
|
2675
|
+
from sage.symbolic.ring import SR
|
2676
|
+
return SR(self).log(*args, **kwds)
|
2677
|
+
|
2678
|
+
cdef class OrderElement_quadratic(NumberFieldElement_quadratic):
|
2679
|
+
"""
|
2680
|
+
Element of an order in a quadratic field.
|
2681
|
+
|
2682
|
+
EXAMPLES::
|
2683
|
+
|
2684
|
+
sage: x = polygen(ZZ, 'x')
|
2685
|
+
sage: K.<a> = NumberField(x^2 + 1)
|
2686
|
+
sage: O2 = K.order(2*a)
|
2687
|
+
sage: w = O2.1; w
|
2688
|
+
2*a
|
2689
|
+
sage: parent(w)
|
2690
|
+
Order of conductor 2 generated by 2*a in Number Field in a with defining polynomial x^2 + 1
|
2691
|
+
"""
|
2692
|
+
def __init__(self, order, f):
|
2693
|
+
r"""
|
2694
|
+
Standard initialisation function.
|
2695
|
+
|
2696
|
+
EXAMPLES::
|
2697
|
+
|
2698
|
+
sage: x = polygen(ZZ, 'x')
|
2699
|
+
sage: OK.<y> = EquationOrder(x^2 + 5)
|
2700
|
+
sage: v = OK.1 # indirect doctest
|
2701
|
+
sage: type(v)
|
2702
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.OrderElement_quadratic'>
|
2703
|
+
"""
|
2704
|
+
K = order.number_field()
|
2705
|
+
NumberFieldElement_quadratic.__init__(self, K, f)
|
2706
|
+
(<Element>self)._parent = order
|
2707
|
+
|
2708
|
+
def norm(self):
|
2709
|
+
"""
|
2710
|
+
The norm of an element of the ring of integers is an Integer.
|
2711
|
+
|
2712
|
+
EXAMPLES::
|
2713
|
+
|
2714
|
+
sage: x = polygen(ZZ, 'x')
|
2715
|
+
sage: K.<a> = NumberField(x^2 + 3)
|
2716
|
+
sage: O2 = K.order(2*a)
|
2717
|
+
sage: w = O2.gen(1); w
|
2718
|
+
2*a
|
2719
|
+
sage: w.norm()
|
2720
|
+
12
|
2721
|
+
sage: parent(w.norm())
|
2722
|
+
Integer Ring
|
2723
|
+
"""
|
2724
|
+
return ZZ(NumberFieldElement_quadratic.norm(self))
|
2725
|
+
|
2726
|
+
def trace(self):
|
2727
|
+
"""
|
2728
|
+
The trace of an element of the ring of integers is an Integer.
|
2729
|
+
|
2730
|
+
EXAMPLES::
|
2731
|
+
|
2732
|
+
sage: x = polygen(ZZ, 'x')
|
2733
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
2734
|
+
sage: R = K.ring_of_integers()
|
2735
|
+
sage: b = R((1+a)/2)
|
2736
|
+
sage: b.trace()
|
2737
|
+
1
|
2738
|
+
sage: parent(b.trace())
|
2739
|
+
Integer Ring
|
2740
|
+
"""
|
2741
|
+
return ZZ(NumberFieldElement_quadratic.trace(self))
|
2742
|
+
|
2743
|
+
def charpoly(self, var='x', algorithm=None):
|
2744
|
+
r"""
|
2745
|
+
The characteristic polynomial of this element, which is over `\ZZ`
|
2746
|
+
because this element is an algebraic integer.
|
2747
|
+
|
2748
|
+
INPUT:
|
2749
|
+
|
2750
|
+
- ``var`` -- the minimal polynomial is defined over a polynomial ring
|
2751
|
+
in a variable with this name; if not specified, this defaults to ``'x'``
|
2752
|
+
- ``algorithm`` -- for compatibility with general number field
|
2753
|
+
elements; ignored
|
2754
|
+
|
2755
|
+
EXAMPLES::
|
2756
|
+
|
2757
|
+
sage: x = polygen(ZZ, 'x')
|
2758
|
+
sage: K.<a> = NumberField(x^2 - 5)
|
2759
|
+
sage: R = K.ring_of_integers()
|
2760
|
+
sage: b = R((5+a)/2)
|
2761
|
+
sage: f = b.charpoly('x'); f
|
2762
|
+
x^2 - 5*x + 5
|
2763
|
+
sage: f.parent()
|
2764
|
+
Univariate Polynomial Ring in x over Integer Ring
|
2765
|
+
sage: f(b)
|
2766
|
+
0
|
2767
|
+
"""
|
2768
|
+
R = ZZ[var]
|
2769
|
+
return R([self.norm(), -self.trace(), 1])
|
2770
|
+
|
2771
|
+
def minpoly(self, var='x', algorithm=None):
|
2772
|
+
r"""
|
2773
|
+
The minimal polynomial of this element over `\ZZ`.
|
2774
|
+
|
2775
|
+
INPUT:
|
2776
|
+
|
2777
|
+
- ``var`` -- the minimal polynomial is defined over a polynomial ring
|
2778
|
+
in a variable with this name; if not specified, this defaults to ``'x'``
|
2779
|
+
- ``algorithm`` -- for compatibility with general number field
|
2780
|
+
elements; ignored
|
2781
|
+
|
2782
|
+
EXAMPLES::
|
2783
|
+
|
2784
|
+
sage: x = polygen(ZZ, 'x')
|
2785
|
+
sage: K.<a> = NumberField(x^2 + 163)
|
2786
|
+
sage: R = K.ring_of_integers()
|
2787
|
+
sage: f = R(a).minpoly('x'); f
|
2788
|
+
x^2 + 163
|
2789
|
+
sage: f.parent()
|
2790
|
+
Univariate Polynomial Ring in x over Integer Ring
|
2791
|
+
sage: R(5).minpoly()
|
2792
|
+
x - 5
|
2793
|
+
"""
|
2794
|
+
if self.is_rational():
|
2795
|
+
R = ZZ[var]
|
2796
|
+
return R([-self._rational_(), 1])
|
2797
|
+
else:
|
2798
|
+
return self.charpoly()
|
2799
|
+
|
2800
|
+
cdef number_field(self):
|
2801
|
+
# So few functions actually use self.number_field() for quadratic elements, so
|
2802
|
+
# it is better *not* to return a cached value (since the call to _parent.number_field())
|
2803
|
+
# is expensive.
|
2804
|
+
return self._parent.number_field()
|
2805
|
+
|
2806
|
+
# We must override these since the basering is now ZZ not QQ.
|
2807
|
+
cpdef _rmul_(self, Element _c):
|
2808
|
+
"""
|
2809
|
+
EXAMPLES::
|
2810
|
+
|
2811
|
+
sage: x = polygen(ZZ, 'x')
|
2812
|
+
sage: K.<a> = NumberField(x^2 - 27)
|
2813
|
+
sage: R = K.ring_of_integers()
|
2814
|
+
sage: aa = R.gen(1); aa
|
2815
|
+
1/3*a
|
2816
|
+
sage: 5 * aa # indirect doctest
|
2817
|
+
5/3*a
|
2818
|
+
"""
|
2819
|
+
cdef Integer c = <Integer>_c
|
2820
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
2821
|
+
mpz_mul(res.a, self.a, c.value)
|
2822
|
+
mpz_mul(res.b, self.b, c.value)
|
2823
|
+
mpz_set(res.denom, self.denom)
|
2824
|
+
res._reduce_c_()
|
2825
|
+
return res
|
2826
|
+
|
2827
|
+
cpdef _lmul_(self, Element _c):
|
2828
|
+
"""
|
2829
|
+
EXAMPLES::
|
2830
|
+
|
2831
|
+
sage: x = polygen(ZZ, 'x')
|
2832
|
+
sage: K.<a> = NumberField(x^2 + 43)
|
2833
|
+
sage: R = K.ring_of_integers()
|
2834
|
+
sage: aa = R.gen(0); aa
|
2835
|
+
1/2*a + 1/2
|
2836
|
+
sage: aa*3 # indirect doctest
|
2837
|
+
3/2*a + 3/2
|
2838
|
+
"""
|
2839
|
+
cdef Integer c = <Integer>_c
|
2840
|
+
cdef NumberFieldElement_quadratic res = <NumberFieldElement_quadratic>self._new()
|
2841
|
+
mpz_mul(res.a, self.a, c.value)
|
2842
|
+
mpz_mul(res.b, self.b, c.value)
|
2843
|
+
mpz_set(res.denom, self.denom)
|
2844
|
+
res._reduce_c_()
|
2845
|
+
return res
|
2846
|
+
|
2847
|
+
def __invert__(self):
|
2848
|
+
r"""
|
2849
|
+
Implement inversion, checking that the return value has the right parent.
|
2850
|
+
See :issue:`4190`.
|
2851
|
+
|
2852
|
+
EXAMPLES::
|
2853
|
+
|
2854
|
+
sage: x = polygen(ZZ, 'x')
|
2855
|
+
sage: K = NumberField(x^2 - x + 2, 'a')
|
2856
|
+
sage: OK = K.ring_of_integers()
|
2857
|
+
sage: a = OK(K.gen())
|
2858
|
+
sage: (~a).parent() is K
|
2859
|
+
True
|
2860
|
+
sage: (~a) in OK
|
2861
|
+
False
|
2862
|
+
sage: a**(-1) in OK
|
2863
|
+
False
|
2864
|
+
"""
|
2865
|
+
return self._parent.number_field()(NumberFieldElement_quadratic.__invert__(self))
|
2866
|
+
|
2867
|
+
def inverse_mod(self, I):
|
2868
|
+
r"""
|
2869
|
+
Return an inverse of ``self`` modulo the given ideal.
|
2870
|
+
|
2871
|
+
INPUT:
|
2872
|
+
|
2873
|
+
- ``I`` -- may be an ideal of ``self.parent()``, or an
|
2874
|
+
element or list of elements of ``self.parent()`` generating a nonzero
|
2875
|
+
ideal. A :exc:`ValueError` is raised if `I` is non-integral or is zero.
|
2876
|
+
A :exc:`ZeroDivisionError` is raised if `I + (x) \neq (1)`.
|
2877
|
+
|
2878
|
+
EXAMPLES::
|
2879
|
+
|
2880
|
+
sage: x = polygen(ZZ, 'x')
|
2881
|
+
sage: OE.<w> = EquationOrder(x^2 - x + 2)
|
2882
|
+
sage: w.inverse_mod(13) == 6*w - 6
|
2883
|
+
True
|
2884
|
+
sage: w*(6*w - 6) - 1
|
2885
|
+
-13
|
2886
|
+
sage: w.inverse_mod(13).parent() == OE
|
2887
|
+
True
|
2888
|
+
sage: w.inverse_mod(2)
|
2889
|
+
Traceback (most recent call last):
|
2890
|
+
...
|
2891
|
+
ZeroDivisionError: w is not invertible modulo Fractional ideal (2)
|
2892
|
+
"""
|
2893
|
+
R = self.parent()
|
2894
|
+
return R(_inverse_mod_generic(self, I))
|
2895
|
+
|
2896
|
+
cpdef list _coefficients(self):
|
2897
|
+
"""
|
2898
|
+
EXAMPLES::
|
2899
|
+
|
2900
|
+
sage: x = polygen(ZZ, 'x')
|
2901
|
+
sage: K.<a> = NumberField(x^2 - 27)
|
2902
|
+
sage: R = K.ring_of_integers()
|
2903
|
+
sage: aa = R.gen(1)
|
2904
|
+
sage: aa._coefficients()
|
2905
|
+
[0, 1/3]
|
2906
|
+
"""
|
2907
|
+
if not self:
|
2908
|
+
return []
|
2909
|
+
ad, bd = self.parts()
|
2910
|
+
if not bd:
|
2911
|
+
return [ad]
|
2912
|
+
|
2913
|
+
cdef NumberFieldElement_quadratic gen = self.number_field().gen()
|
2914
|
+
alpha, beta = gen.parts()
|
2915
|
+
if is_sqrt_disc(alpha, beta):
|
2916
|
+
return [ad, bd]
|
2917
|
+
else:
|
2918
|
+
scale = bd / beta
|
2919
|
+
return [ad - scale*alpha, scale]
|
2920
|
+
|
2921
|
+
def denominator(self):
|
2922
|
+
r"""
|
2923
|
+
Return the denominator of ``self``.
|
2924
|
+
|
2925
|
+
This is the LCM of the denominators of the coefficients of ``self``, and
|
2926
|
+
thus it may well be `> 1` even when the element is an algebraic integer.
|
2927
|
+
|
2928
|
+
EXAMPLES::
|
2929
|
+
|
2930
|
+
sage: x = polygen(ZZ, 'x')
|
2931
|
+
sage: K.<a> = NumberField(x^2 - 27)
|
2932
|
+
sage: R = K.ring_of_integers()
|
2933
|
+
sage: aa = R.gen(1)
|
2934
|
+
sage: aa.denominator()
|
2935
|
+
3
|
2936
|
+
"""
|
2937
|
+
# In terms of the generator...
|
2938
|
+
cdef NumberFieldElement_quadratic gen = self.number_field().gen() # should this be cached?
|
2939
|
+
cdef Integer denom
|
2940
|
+
cdef tuple parts = gen.parts()
|
2941
|
+
cdef Rational alpha, beta, const, lin
|
2942
|
+
alpha = <Rational> (parts[0])
|
2943
|
+
beta = <Rational> (parts[1])
|
2944
|
+
if is_sqrt_disc(alpha, beta):
|
2945
|
+
denom = Integer.__new__(Integer)
|
2946
|
+
mpz_set(denom.value, self.denom)
|
2947
|
+
return denom
|
2948
|
+
else:
|
2949
|
+
parts = self.parts()
|
2950
|
+
const = <Rational> (parts[0])
|
2951
|
+
lin = <Rational> (parts[1])
|
2952
|
+
scale = lin / beta
|
2953
|
+
const = const - scale * alpha
|
2954
|
+
return const.denominator().lcm(scale.denominator())
|
2955
|
+
|
2956
|
+
cdef class Z_to_quadratic_field_element(Morphism):
|
2957
|
+
"""
|
2958
|
+
Morphism that coerces from integers to elements of a quadratic number
|
2959
|
+
field `K`.
|
2960
|
+
|
2961
|
+
EXAMPLES::
|
2962
|
+
|
2963
|
+
sage: K.<a> = QuadraticField(3)
|
2964
|
+
sage: phi = K.coerce_map_from(ZZ); phi
|
2965
|
+
Natural morphism:
|
2966
|
+
From: Integer Ring
|
2967
|
+
To: Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878?
|
2968
|
+
sage: phi(4)
|
2969
|
+
4
|
2970
|
+
sage: phi(5).parent() is K
|
2971
|
+
True
|
2972
|
+
"""
|
2973
|
+
# The zero element of K, lazily initialized
|
2974
|
+
cdef NumberFieldElement_quadratic zero_element
|
2975
|
+
|
2976
|
+
# TODO: implement __richcmp__ properly so we can have a loads/dumps doctest
|
2977
|
+
|
2978
|
+
def __init__(self, K):
|
2979
|
+
"""
|
2980
|
+
``K`` is the target quadratic field.
|
2981
|
+
|
2982
|
+
EXAMPLES::
|
2983
|
+
|
2984
|
+
sage: K.<a> = QuadraticField(3)
|
2985
|
+
sage: phi = K.coerce_map_from(ZZ) # indirect doctest
|
2986
|
+
sage: type(phi)
|
2987
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.Z_to_quadratic_field_element'>
|
2988
|
+
sage: phi == loads(dumps(phi)) # todo: comparison not implemented
|
2989
|
+
True
|
2990
|
+
|
2991
|
+
sage: R.<b> = CyclotomicField(6)
|
2992
|
+
sage: psi = R.coerce_map_from(ZZ) # indirect doctest
|
2993
|
+
sage: type(psi)
|
2994
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.Z_to_quadratic_field_element'>
|
2995
|
+
sage: psi == loads(dumps(psi)) # todo: comparison not implemented
|
2996
|
+
True
|
2997
|
+
"""
|
2998
|
+
import sage.categories.homset
|
2999
|
+
Morphism.__init__(self, sage.categories.homset.Hom(ZZ, K))
|
3000
|
+
|
3001
|
+
cpdef Element _call_(self, x):
|
3002
|
+
r"""
|
3003
|
+
Evaluate at an integer ``x``.
|
3004
|
+
|
3005
|
+
EXAMPLES::
|
3006
|
+
|
3007
|
+
sage: K.<a> = QuadraticField(3)
|
3008
|
+
sage: phi = K.coerce_map_from(ZZ)
|
3009
|
+
sage: a = phi(2); a # indirect doctest
|
3010
|
+
2
|
3011
|
+
sage: a.parent() is K
|
3012
|
+
True
|
3013
|
+
|
3014
|
+
sage: R.<b> = CyclotomicField(6)
|
3015
|
+
sage: psi = R.coerce_map_from(ZZ)
|
3016
|
+
sage: b = psi(-42); b # indirect doctest
|
3017
|
+
-42
|
3018
|
+
sage: b.parent() is R
|
3019
|
+
True
|
3020
|
+
"""
|
3021
|
+
cdef NumberFieldElement_quadratic y
|
3022
|
+
if self.zero_element is None:
|
3023
|
+
self.zero_element = self._codomain.zero()
|
3024
|
+
if mpz_sgn((<Integer> x).value) == 0:
|
3025
|
+
return self.zero_element
|
3026
|
+
y = self.zero_element._new()
|
3027
|
+
mpz_set(y.a, (<Integer> x).value)
|
3028
|
+
|
3029
|
+
# we need to set the denominator to 1 as it is 0 for
|
3030
|
+
# the zero element of K... (because gcd(0,0) = 0).
|
3031
|
+
mpz_set_ui(y.denom, 1)
|
3032
|
+
|
3033
|
+
return y
|
3034
|
+
|
3035
|
+
def _repr_type(self):
|
3036
|
+
r"""
|
3037
|
+
Return a short name for this morphism.
|
3038
|
+
|
3039
|
+
EXAMPLES::
|
3040
|
+
|
3041
|
+
sage: K.<a> = QuadraticField(3)
|
3042
|
+
sage: phi = K.coerce_map_from(ZZ)
|
3043
|
+
sage: phi # indirect doctest
|
3044
|
+
Natural morphism:
|
3045
|
+
From: Integer Ring
|
3046
|
+
To: Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878?
|
3047
|
+
|
3048
|
+
sage: R.<b> = CyclotomicField(6)
|
3049
|
+
sage: psi = R.coerce_map_from(ZZ)
|
3050
|
+
sage: psi # indirect doctest
|
3051
|
+
Natural morphism:
|
3052
|
+
From: Integer Ring
|
3053
|
+
To: Cyclotomic Field of order 6 and degree 2
|
3054
|
+
"""
|
3055
|
+
return "Natural"
|
3056
|
+
|
3057
|
+
|
3058
|
+
cdef class Q_to_quadratic_field_element(Morphism):
|
3059
|
+
"""
|
3060
|
+
Morphism that coerces from rationals to elements of a quadratic number
|
3061
|
+
field `K`.
|
3062
|
+
|
3063
|
+
EXAMPLES::
|
3064
|
+
|
3065
|
+
sage: K.<a> = QuadraticField(-3)
|
3066
|
+
sage: f = K.coerce_map_from(QQ); f
|
3067
|
+
Natural morphism:
|
3068
|
+
From: Rational Field
|
3069
|
+
To: Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
|
3070
|
+
sage: f(3/1)
|
3071
|
+
3
|
3072
|
+
sage: f(1/2).parent() is K
|
3073
|
+
True
|
3074
|
+
"""
|
3075
|
+
# The zero element of K, lazily initialized
|
3076
|
+
cdef NumberFieldElement_quadratic zero_element
|
3077
|
+
|
3078
|
+
# TODO: implement __richcmp__ properly so we can have a loads/dumps doctest
|
3079
|
+
|
3080
|
+
def __init__(self, K):
|
3081
|
+
"""
|
3082
|
+
INPUT:
|
3083
|
+
|
3084
|
+
- ``K`` -- the target quadratic field
|
3085
|
+
|
3086
|
+
EXAMPLES::
|
3087
|
+
|
3088
|
+
sage: K.<a> = QuadraticField(3)
|
3089
|
+
sage: phi = K.coerce_map_from(QQ) # indirect doctest
|
3090
|
+
sage: type(phi)
|
3091
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.Q_to_quadratic_field_element'>
|
3092
|
+
sage: phi == loads(dumps(phi)) # todo: comparison not implemented
|
3093
|
+
True
|
3094
|
+
|
3095
|
+
sage: R.<b> = CyclotomicField(6)
|
3096
|
+
sage: psi = R.coerce_map_from(QQ)
|
3097
|
+
sage: type(psi)
|
3098
|
+
<class 'sage.rings.number_field.number_field_element_quadratic.Q_to_quadratic_field_element'>
|
3099
|
+
sage: psi == loads(dumps(psi)) # todo: comparison not implemented
|
3100
|
+
True
|
3101
|
+
"""
|
3102
|
+
import sage.categories.homset
|
3103
|
+
Morphism.__init__(self, sage.categories.homset.Hom(QQ, K))
|
3104
|
+
|
3105
|
+
cpdef Element _call_(self, x):
|
3106
|
+
r"""
|
3107
|
+
Evaluate at a rational ``x``.
|
3108
|
+
|
3109
|
+
EXAMPLES::
|
3110
|
+
|
3111
|
+
sage: K.<a> = QuadraticField(3)
|
3112
|
+
sage: phi = K.coerce_map_from(QQ)
|
3113
|
+
sage: a = phi(2/3); a # indirect doctest
|
3114
|
+
2/3
|
3115
|
+
sage: a.parent() is K
|
3116
|
+
True
|
3117
|
+
|
3118
|
+
sage: R.<b> = CyclotomicField(6)
|
3119
|
+
sage: psi = R.coerce_map_from(QQ)
|
3120
|
+
sage: b = psi(-23/15); b # indirect doctest
|
3121
|
+
-23/15
|
3122
|
+
sage: b.parent() is R
|
3123
|
+
True
|
3124
|
+
"""
|
3125
|
+
if self.zero_element is None:
|
3126
|
+
self.zero_element = self._codomain.zero()
|
3127
|
+
cdef NumberFieldElement_quadratic y = self.zero_element._new()
|
3128
|
+
mpz_set(y.a, mpq_numref((<Rational>x).value))
|
3129
|
+
mpz_set(y.denom, mpq_denref((<Rational>x).value))
|
3130
|
+
return y
|
3131
|
+
|
3132
|
+
def _repr_type(self):
|
3133
|
+
r"""
|
3134
|
+
Return a short name for this morphism.
|
3135
|
+
|
3136
|
+
EXAMPLES::
|
3137
|
+
|
3138
|
+
sage: K.<a> = QuadraticField(3)
|
3139
|
+
sage: phi = K.coerce_map_from(QQ)
|
3140
|
+
sage: phi # indirect doctest
|
3141
|
+
Natural morphism:
|
3142
|
+
From: Rational Field
|
3143
|
+
To: Number Field in a with defining polynomial x^2 - 3 with a = 1.732050807568878?
|
3144
|
+
|
3145
|
+
sage: R.<b> = CyclotomicField(6)
|
3146
|
+
sage: psi = R.coerce_map_from(QQ)
|
3147
|
+
sage: psi # indirect doctest
|
3148
|
+
Natural morphism:
|
3149
|
+
From: Rational Field
|
3150
|
+
To: Cyclotomic Field of order 6 and degree 2
|
3151
|
+
"""
|
3152
|
+
return "Natural"
|
3153
|
+
|
3154
|
+
#####################################################################
|
3155
|
+
## Helper function
|
3156
|
+
|
3157
|
+
cpdef bint is_sqrt_disc(Rational ad, Rational bd) noexcept:
|
3158
|
+
r"""
|
3159
|
+
Return ``True`` if the pair ``(ad, bd)`` is `\sqrt{D}`.
|
3160
|
+
|
3161
|
+
EXAMPLES::
|
3162
|
+
|
3163
|
+
sage: x = polygen(ZZ, 'x')
|
3164
|
+
sage: F.<b> = NumberField(x^2 - x + 7)
|
3165
|
+
sage: b.denominator() # indirect doctest
|
3166
|
+
1
|
3167
|
+
"""
|
3168
|
+
cdef mpz_t a, b, denom
|
3169
|
+
mpz_init(a)
|
3170
|
+
mpz_init(b)
|
3171
|
+
mpz_init(denom)
|
3172
|
+
|
3173
|
+
mpz_lcm(denom, mpq_denref(ad.value), mpq_denref(bd.value))
|
3174
|
+
mpz_divexact(a, denom, mpq_denref(ad.value))
|
3175
|
+
mpz_mul(a, a, mpq_numref(ad.value))
|
3176
|
+
mpz_divexact(b, denom, mpq_denref(bd.value))
|
3177
|
+
mpz_mul(b, b, mpq_numref(bd.value))
|
3178
|
+
|
3179
|
+
cdef bint ret = mpz_cmp_ui(denom, 1) == 0 and mpz_cmp_ui(a, 0) == 0 and mpz_cmp_ui(b, 1) == 0
|
3180
|
+
|
3181
|
+
mpz_clear(a)
|
3182
|
+
mpz_clear(b)
|
3183
|
+
mpz_clear(denom)
|
3184
|
+
|
3185
|
+
return ret
|