diff --git a/VERSION.txt b/VERSION.txt index 4859548c745..f2eb6594da5 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 8.1.beta7, Release Date: 2017-10-03 +SageMath version 8.1.beta8, Release Date: 2017-10-16 diff --git a/build/pkgs/arb/checksums.ini b/build/pkgs/arb/checksums.ini index f572b72e7a8..78909d583ff 100644 --- a/build/pkgs/arb/checksums.ini +++ b/build/pkgs/arb/checksums.ini @@ -1,4 +1,4 @@ tarball=arb-VERSION.tar.gz -sha1=fcca9134006e77cde5f2024f36150e823bf731ae -md5=b6b94a39b71293b6811a191cb9542096 -cksum=248634837 +sha1=2f06bfb433cdaecde0e824c5e638094fd666a0d1 +md5=d63cdd1147104790826c93bc8651104f +cksum=2745482665 diff --git a/build/pkgs/arb/package-version.txt b/build/pkgs/arb/package-version.txt index e007c342d8c..99993ffae4c 100644 --- a/build/pkgs/arb/package-version.txt +++ b/build/pkgs/arb/package-version.txt @@ -1 +1 @@ -2.8.1.p1 +2.11.1.p0 diff --git a/build/pkgs/arb/patches/flint_includes.patch b/build/pkgs/arb/patches/flint_includes.patch deleted file mode 100644 index 083d87107af..00000000000 --- a/build/pkgs/arb/patches/flint_includes.patch +++ /dev/null @@ -1,1032 +0,0 @@ -Fix FLINT include paths - -See https://github.com/fredrik-johansson/arb/pull/55 - -diff -ru a/acb/test/t-rising2_ui_bs.c b/acb/test/t-rising2_ui_bs.c ---- a/acb/test/t-rising2_ui_bs.c 2015-12-30 11:06:48.862989805 +0100 -+++ b/acb/test/t-rising2_ui_bs.c 2015-12-30 11:13:35.255807240 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "acb_poly.h" - - int main() -diff -ru a/acb/test/t-rising2_ui.c b/acb/test/t-rising2_ui.c ---- a/acb/test/t-rising2_ui.c 2015-12-30 11:06:48.862989805 +0100 -+++ b/acb/test/t-rising2_ui.c 2015-12-30 11:13:35.256807251 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "acb_poly.h" - - int main() -diff -ru a/acb/test/t-rising2_ui_rs.c b/acb/test/t-rising2_ui_rs.c ---- a/acb/test/t-rising2_ui_rs.c 2015-12-30 11:06:48.863989817 +0100 -+++ b/acb/test/t-rising2_ui_rs.c 2015-12-30 11:13:35.256807251 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "acb_poly.h" - - int main() -diff -ru a/acb_hypgeom/airy.c b/acb_hypgeom/airy.c ---- a/acb_hypgeom/airy.c 2015-12-30 11:06:48.865989841 +0100 -+++ b/acb_hypgeom/airy.c 2015-12-30 11:19:50.205169366 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "acb_hypgeom.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - #define LOG2 0.69314718055994530942 - #define EXP1 2.7182818284590452354 -diff -ru a/acb_mat/exp.c b/acb_mat/exp.c ---- a/acb_mat/exp.c 2015-12-30 11:06:48.870989901 +0100 -+++ b/acb_mat/exp.c 2015-12-30 11:13:35.256807251 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "acb_mat.h" - - slong _arb_mat_exp_choose_N(const mag_t norm, slong prec); -diff -ru a/acb_mat.h b/acb_mat.h ---- a/acb_mat.h 2015-12-30 11:06:48.869989889 +0100 -+++ b/acb_mat.h 2015-12-30 11:13:35.256807251 +0100 -@@ -34,8 +34,8 @@ - - #include "arb.h" - #include "acb.h" --#include "fmpz_mat.h" --#include "fmpq_mat.h" -+#include "flint/fmpz_mat.h" -+#include "flint/fmpq_mat.h" - #include "arb_mat.h" - #include "acb_poly.h" - -diff -ru a/acb_modular/test/t-delta.c b/acb_modular/test/t-delta.c ---- a/acb_modular/test/t-delta.c 2015-12-30 11:06:48.872989925 +0100 -+++ b/acb_modular/test/t-delta.c 2015-12-30 11:13:35.256807251 +0100 -@@ -25,7 +25,7 @@ - - #include "acb_modular.h" - --#include "profiler.h" -+#include "flint/profiler.h" - - int main() - { -diff -ru a/acb_modular/test/t-epsilon_arg.c b/acb_modular/test/t-epsilon_arg.c ---- a/acb_modular/test/t-epsilon_arg.c 2015-12-30 11:06:48.873989937 +0100 -+++ b/acb_modular/test/t-epsilon_arg.c 2015-12-30 11:13:35.256807251 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "acb_modular.h" --#include "arith.h" -+#include "flint/arith.h" - - static void - acb_modular_epsilon_arg_naive(fmpq_t arg, const psl2z_t g) -diff -ru a/acb_modular/test/t-hilbert_class_poly.c b/acb_modular/test/t-hilbert_class_poly.c ---- a/acb_modular/test/t-hilbert_class_poly.c 2015-12-30 11:06:48.873989937 +0100 -+++ b/acb_modular/test/t-hilbert_class_poly.c 2015-12-30 11:29:32.413167018 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "fmpz_poly.h" -+#include "flint/fmpz_poly.h" - #include "acb_modular.h" - - /* reference values h_(-d)(2015) mod 31337 computed using sage */ -diff -ru a/arb/bell_fmpz.c b/arb/bell_fmpz.c ---- a/arb/bell_fmpz.c 2015-12-30 11:06:48.884990069 +0100 -+++ b/arb/bell_fmpz.c 2015-12-30 11:17:49.662745942 +0100 -@@ -24,8 +24,8 @@ - ******************************************************************************/ - - #include "arb.h" --#include "arith.h" --#include "double_extras.h" -+#include "flint/arith.h" -+#include "flint/double_extras.h" - - /* \sum_{k=0}^{a-1} \frac{k^n}{k!} */ - /* b = a * \frac{(a-1)^n}{(a-1)!} */ -diff -ru a/arb/digamma.c b/arb/digamma.c ---- a/arb/digamma.c 2015-12-30 11:06:48.886990093 +0100 -+++ b/arb/digamma.c 2015-12-30 11:13:35.256807251 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "arith.h" -+#include "flint/arith.h" - - void arb_gamma_stirling_choose_param(int * reflect, slong * r, slong * n, - const arb_t x, int use_reflect, int digamma, slong prec); -diff -ru a/arb/rising_ui_rs.c b/arb/rising_ui_rs.c ---- a/arb/rising_ui_rs.c 2015-12-30 11:06:48.890990141 +0100 -+++ b/arb/rising_ui_rs.c 2015-12-30 11:13:35.257807263 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb.h" - - void -diff -ru a/arb/sin_cos.c b/arb/sin_cos.c ---- a/arb/sin_cos.c 2015-12-30 11:06:48.891990153 +0100 -+++ b/arb/sin_cos.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - #define TMP_ALLOC_LIMBS(__n) TMP_ALLOC((__n) * sizeof(mp_limb_t)) - -diff -ru a/arb/sin_cos_pi_fmpq_algebraic.c b/arb/sin_cos_pi_fmpq_algebraic.c ---- a/arb/sin_cos_pi_fmpq_algebraic.c 2015-12-30 11:06:48.891990153 +0100 -+++ b/arb/sin_cos_pi_fmpq_algebraic.c 2015-12-30 11:13:35.257807263 +0100 -@@ -29,8 +29,8 @@ - - - /* include minpoly code here until it appears in a flint release */ --#include "fmpz_poly.h" --#include "ulong_extras.h" -+#include "flint/fmpz_poly.h" -+#include "flint/ulong_extras.h" - - /* Use a lookup table for small n. We skip 53, 59 and 61, as the - coefficients do not fit in 16 bits. */ -diff -ru a/arb/test/t-addmul_si.c b/arb/test/t-addmul_si.c ---- a/arb/test/t-addmul_si.c 2015-12-30 11:06:48.894990189 +0100 -+++ b/arb/test/t-addmul_si.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-addmul_ui.c b/arb/test/t-addmul_ui.c ---- a/arb/test/t-addmul_ui.c 2015-12-30 11:06:48.894990189 +0100 -+++ b/arb/test/t-addmul_ui.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-add_si.c b/arb/test/t-add_si.c ---- a/arb/test/t-add_si.c 2015-12-30 11:06:48.893990177 +0100 -+++ b/arb/test/t-add_si.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-add_ui.c b/arb/test/t-add_ui.c ---- a/arb/test/t-add_ui.c 2015-12-30 11:06:48.893990177 +0100 -+++ b/arb/test/t-add_ui.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-atan_taylor_rf.c b/arb/test/t-atan_taylor_rf.c ---- a/arb/test/t-atan_taylor_rf.c 2015-12-30 11:06:48.894990189 +0100 -+++ b/arb/test/t-atan_taylor_rf.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - int main() - { -diff -ru a/arb/test/t-div_si.c b/arb/test/t-div_si.c ---- a/arb/test/t-div_si.c 2015-12-30 11:06:48.896990213 +0100 -+++ b/arb/test/t-div_si.c 2015-12-30 11:13:35.257807263 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-div_ui.c b/arb/test/t-div_ui.c ---- a/arb/test/t-div_ui.c 2015-12-30 11:06:48.896990213 +0100 -+++ b/arb/test/t-div_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-exp_taylor_rf.c b/arb/test/t-exp_taylor_rf.c ---- a/arb/test/t-exp_taylor_rf.c 2015-12-30 11:06:48.896990213 +0100 -+++ b/arb/test/t-exp_taylor_rf.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - int main() - { -diff -ru a/arb/test/t-mul_si.c b/arb/test/t-mul_si.c ---- a/arb/test/t-mul_si.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-mul_si.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-mul_ui.c b/arb/test/t-mul_ui.c ---- a/arb/test/t-mul_ui.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-mul_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-rising2_ui_bs.c b/arb/test/t-rising2_ui_bs.c ---- a/arb/test/t-rising2_ui_bs.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-rising2_ui_bs.c 2015-12-30 11:13:35.258807274 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb_poly.h" - - int main() -diff -ru a/arb/test/t-rising2_ui.c b/arb/test/t-rising2_ui.c ---- a/arb/test/t-rising2_ui.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-rising2_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb_poly.h" - - int main() -diff -ru a/arb/test/t-rising2_ui_rs.c b/arb/test/t-rising2_ui_rs.c ---- a/arb/test/t-rising2_ui_rs.c 2015-12-30 11:06:48.897990225 +0100 -+++ b/arb/test/t-rising2_ui_rs.c 2015-12-30 11:13:35.258807274 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "arb_poly.h" - - int main() -diff -ru a/arb/test/t-sin_cos_taylor_rf.c b/arb/test/t-sin_cos_taylor_rf.c ---- a/arb/test/t-sin_cos_taylor_rf.c 2015-12-30 11:06:48.898990237 +0100 -+++ b/arb/test/t-sin_cos_taylor_rf.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - int main() - { -diff -ru a/arb/test/t-submul_si.c b/arb/test/t-submul_si.c ---- a/arb/test/t-submul_si.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-submul_si.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-submul_ui.c b/arb/test/t-submul_ui.c ---- a/arb/test/t-submul_ui.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-submul_ui.c 2015-12-30 11:13:35.258807274 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/test/t-sub_si.c b/arb/test/t-sub_si.c ---- a/arb/test/t-sub_si.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-sub_si.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/arb/test/t-sub_ui.c b/arb/test/t-sub_ui.c ---- a/arb/test/t-sub_ui.c 2015-12-30 11:06:48.899990249 +0100 -+++ b/arb/test/t-sub_ui.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arb.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int main() - { -diff -ru a/arb/zeta_ui.c b/arb/zeta_ui.c ---- a/arb/zeta_ui.c 2015-12-30 11:06:48.900990261 +0100 -+++ b/arb/zeta_ui.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include --#include "arith.h" -+#include "flint/arith.h" - #include "arb.h" - - void -diff -ru a/arb_mat/exp.c b/arb_mat/exp.c ---- a/arb_mat/exp.c 2015-12-30 11:06:48.901990273 +0100 -+++ b/arb_mat/exp.c 2015-12-30 11:13:35.259807285 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "arb_mat.h" - - #define LOG2_OVER_E 0.25499459743395350926 -diff -ru a/arb_mat.h b/arb_mat.h ---- a/arb_mat.h 2015-12-30 11:06:48.900990261 +0100 -+++ b/arb_mat.h 2015-12-30 11:13:35.259807285 +0100 -@@ -33,9 +33,9 @@ - #endif - - #include "arb.h" --#include "fmpz_mat.h" --#include "fmpq_mat.h" --#include "perm.h" -+#include "flint/fmpz_mat.h" -+#include "flint/fmpq_mat.h" -+#include "flint/perm.h" - #include "arb_poly.h" - - #ifdef __cplusplus -diff -ru a/arb_poly.h b/arb_poly.h ---- a/arb_poly.h 2015-12-30 11:06:48.903990297 +0100 -+++ b/arb_poly.h 2015-12-30 11:13:35.259807285 +0100 -@@ -34,8 +34,8 @@ - - #include "arb.h" - #include "acb.h" --#include "fmpz_poly.h" --#include "fmpq_poly.h" -+#include "flint/fmpz_poly.h" -+#include "flint/fmpq_poly.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/arf/div.c b/arf/div.c ---- a/arf/div.c 2015-12-30 11:06:48.912990405 +0100 -+++ b/arf/div.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "mpn_extras.h" -+#include "flint/mpn_extras.h" - - #if !defined(__MPIR_VERSION) - #define USE_GMP_DIV_Q 1 -diff -ru a/arf/get_d.c b/arf/get_d.c ---- a/arf/get_d.c 2015-12-30 11:06:48.912990405 +0100 -+++ b/arf/get_d.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - /* most double: (2^53-1) * 2^971 */ - /* least normal: 2^-1022 */ -diff -ru a/arf/set_d.c b/arf/set_d.c ---- a/arf/set_d.c 2015-12-30 11:06:48.913990417 +0100 -+++ b/arf/set_d.c 2015-12-30 11:13:35.259807285 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - void - arf_set_d(arf_t x, double v) -diff -ru a/arf/test/t-addmul_si.c b/arf/test/t-addmul_si.c ---- a/arf/test/t-addmul_si.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-addmul_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_addmul_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-add_si.c b/arf/test/t-add_si.c ---- a/arf/test/t-add_si.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-add_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_add_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-add_ui.c b/arf/test/t-add_ui.c ---- a/arf/test/t-add_ui.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-add_ui.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int - arf_add_ui_naive(arf_t z, const arf_t x, ulong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-mul_si.c b/arf/test/t-mul_si.c ---- a/arf/test/t-mul_si.c 2015-12-30 11:06:48.914990429 +0100 -+++ b/arf/test/t-mul_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_mul_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-mul_ui.c b/arf/test/t-mul_ui.c ---- a/arf/test/t-mul_ui.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-mul_ui.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int - arf_mul_ui_naive(arf_t z, const arf_t x, ulong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-submul_si.c b/arf/test/t-submul_si.c ---- a/arf/test/t-submul_si.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-submul_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_submul_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-sub_si.c b/arf/test/t-sub_si.c ---- a/arf/test/t-sub_si.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-sub_si.c 2015-12-30 11:13:35.260807297 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int - arf_sub_si_naive(arf_t z, const arf_t x, slong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf/test/t-sub_ui.c b/arf/test/t-sub_ui.c ---- a/arf/test/t-sub_ui.c 2015-12-30 11:06:48.915990441 +0100 -+++ b/arf/test/t-sub_ui.c 2015-12-30 11:13:35.261807308 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "arf.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - int - arf_sub_ui_naive(arf_t z, const arf_t x, ulong y, slong prec, arf_rnd_t rnd) -diff -ru a/arf.h b/arf.h ---- a/arf.h 2015-12-30 11:06:48.911990393 +0100 -+++ b/arf.h 2015-12-30 11:13:35.261807308 +0100 -@@ -36,7 +36,7 @@ - #endif - - #include --#include "flint.h" -+#include "flint/flint.h" - #include "fmpr.h" - #include "mag.h" - -diff -ru a/bernoulli/test/t-fmpq_ui.c b/bernoulli/test/t-fmpq_ui.c ---- a/bernoulli/test/t-fmpq_ui.c 2015-12-30 11:06:48.916990453 +0100 -+++ b/bernoulli/test/t-fmpq_ui.c 2015-12-30 11:13:35.261807308 +0100 -@@ -25,8 +25,8 @@ - - #include - #include --#include "fmpz_vec.h" --#include "arith.h" -+#include "flint/fmpz_vec.h" -+#include "flint/arith.h" - #include "bernoulli.h" - - int main() -diff -ru a/bernoulli/test/t-rev.c b/bernoulli/test/t-rev.c ---- a/bernoulli/test/t-rev.c 2015-12-30 11:06:48.916990453 +0100 -+++ b/bernoulli/test/t-rev.c 2015-12-30 11:13:35.261807308 +0100 -@@ -26,9 +26,9 @@ - #include - #include - #include "bernoulli.h" --#include "ulong_extras.h" --#include "nmod_poly.h" --#include "nmod_vec.h" -+#include "flint/ulong_extras.h" -+#include "flint/nmod_poly.h" -+#include "flint/nmod_vec.h" - - int main() - { -diff -ru a/bernoulli.h b/bernoulli.h ---- a/bernoulli.h 2015-12-30 11:06:48.915990441 +0100 -+++ b/bernoulli.h 2015-12-30 11:13:35.261807308 +0100 -@@ -27,11 +27,11 @@ - #define BERNOULLI_H - - #include --#include "flint.h" --#include "fmpz.h" --#include "fmpz_vec.h" --#include "fmpq.h" --#include "arith.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" -+#include "flint/fmpz_vec.h" -+#include "flint/fmpq.h" -+#include "flint/arith.h" - #include "fmprb.h" - #include "arb.h" - -diff -ru a/configure b/configure ---- a/configure 2015-12-30 11:06:48.916990453 +0100 -+++ b/configure 2015-12-30 11:13:35.261807308 +0100 -@@ -262,10 +262,6 @@ - exit 1 - fi - --if [ -d "${FLINT_INC_DIR}/flint" ]; then -- FLINT_INC_DIR="${FLINT_INC_DIR}/flint" --fi -- - LIB_DIRS="${LIB_DIRS} ${FLINT_LIB_DIR}" - INC_DIRS="${INC_DIRS} ${FLINT_INC_DIR}" - LIBS="${LIBS} flint" -diff -ru a/examples/hilbert_matrix.c b/examples/hilbert_matrix.c ---- a/examples/hilbert_matrix.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/hilbert_matrix.c 2015-12-30 11:13:35.261807308 +0100 -@@ -1,7 +1,7 @@ - /* This file is public domain. Author: Fredrik Johansson. */ - - #include "arb_mat.h" --#include "profiler.h" -+#include "flint/profiler.h" - - int main(int argc, char *argv[]) - { -diff -ru a/examples/integrals.c b/examples/integrals.c ---- a/examples/integrals.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/integrals.c 2015-12-30 11:13:35.262807319 +0100 -@@ -1,7 +1,7 @@ - /* This file is public domain. Author: Fredrik Johansson. */ - - #include "acb_calc.h" --#include "profiler.h" -+#include "flint/profiler.h" - - int - sinx(acb_ptr out, const acb_t inp, void * params, slong order, slong prec) -diff -ru a/examples/keiper_li.c b/examples/keiper_li.c ---- a/examples/keiper_li.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/keiper_li.c 2015-12-30 11:13:35.262807319 +0100 -@@ -4,7 +4,7 @@ - #include "arb.h" - #include "acb.h" - #include "arb_poly.h" --#include "profiler.h" -+#include "flint/profiler.h" - - void - keiper_li_series(arb_ptr z, slong len, slong prec) -diff -ru a/examples/pi.c b/examples/pi.c ---- a/examples/pi.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/pi.c 2015-12-30 11:13:35.262807319 +0100 -@@ -1,7 +1,7 @@ - /* This file is public domain. Author: Fredrik Johansson. */ - - #include "arb.h" --#include "profiler.h" -+#include "flint/profiler.h" - - int main(int argc, char *argv[]) - { -diff -ru a/examples/poly_roots.c b/examples/poly_roots.c ---- a/examples/poly_roots.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/poly_roots.c 2015-12-30 11:13:35.262807319 +0100 -@@ -3,8 +3,8 @@ - #include - #include "acb.h" - #include "acb_poly.h" --#include "arith.h" --#include "profiler.h" -+#include "flint/arith.h" -+#include "flint/profiler.h" - - int check_accuracy(acb_ptr vec, slong len, slong prec) - { -diff -ru a/examples/real_roots.c b/examples/real_roots.c ---- a/examples/real_roots.c 2015-12-30 11:06:48.920990501 +0100 -+++ b/examples/real_roots.c 2015-12-30 11:13:56.258045629 +0100 -@@ -3,7 +3,7 @@ - #include - #include "arb_calc.h" - #include "acb_hypgeom.h" --#include "profiler.h" -+#include "flint/profiler.h" - - slong eval_count = 0; - -diff -ru a/fmpr/test/t-mul_si.c b/fmpr/test/t-mul_si.c ---- a/fmpr/test/t-mul_si.c 2015-12-30 11:06:48.923990538 +0100 -+++ b/fmpr/test/t-mul_si.c 2015-12-30 11:13:35.262807319 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "fmpr.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - static slong - fmpr_mul_si_naive(fmpr_t z, const fmpr_t x, slong y, slong prec, fmpr_rnd_t rnd) -diff -ru a/fmpr/test/t-mul_ui.c b/fmpr/test/t-mul_ui.c ---- a/fmpr/test/t-mul_ui.c 2015-12-30 11:06:48.923990538 +0100 -+++ b/fmpr/test/t-mul_ui.c 2015-12-30 11:13:35.262807319 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "fmpr.h" --#include "ulong_extras.h" -+#include "flint/ulong_extras.h" - - static slong - fmpr_mul_ui_naive(fmpr_t z, const fmpr_t x, ulong y, slong prec, fmpr_rnd_t rnd) -diff -ru a/fmprb.h b/fmprb.h ---- a/fmprb.h 2015-12-30 11:06:48.924990550 +0100 -+++ b/fmprb.h 2015-12-30 11:13:35.263807331 +0100 -@@ -27,7 +27,7 @@ - #define FMPRB_H - - #include "fmpr.h" --#include "fmpz_poly.h" -+#include "flint/fmpz_poly.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/fmpr.h b/fmpr.h ---- a/fmpr.h 2015-12-30 11:06:48.920990501 +0100 -+++ b/fmpr.h 2015-12-30 11:13:35.263807331 +0100 -@@ -33,12 +33,12 @@ - #include - #include - #include --#include "flint.h" --#include "fmpz.h" --#include "fmpq.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" -+#include "flint/fmpq.h" - #include "fmpz_extras.h" - --#include "config.h" -+#include "flint/config.h" - #ifdef HAVE_TLS - #if HAVE_TLS - #define TLS_PREFIX __thread -diff -ru a/fmpz_extras.h b/fmpz_extras.h ---- a/fmpz_extras.h 2015-12-30 11:06:48.926990574 +0100 -+++ b/fmpz_extras.h 2015-12-30 11:13:35.263807331 +0100 -@@ -27,8 +27,8 @@ - #define FMPZ_EXTRAS_H - - #include --#include "flint.h" --#include "fmpz.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/hypgeom/bound.c b/hypgeom/bound.c ---- a/hypgeom/bound.c 2015-12-30 11:06:48.927990586 +0100 -+++ b/hypgeom/bound.c 2015-12-30 11:13:35.263807331 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "hypgeom.h" - - slong -diff -ru a/hypgeom/estimate_terms_d.c b/hypgeom/estimate_terms_d.c ---- a/hypgeom/estimate_terms_d.c 2015-12-30 11:06:48.927990586 +0100 -+++ b/hypgeom/estimate_terms_d.c 2015-12-30 11:13:35.263807331 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "hypgeom.h" - - #define LOG2 0.69314718055994530942 -diff -ru a/hypgeom.h b/hypgeom.h ---- a/hypgeom.h 2015-12-30 11:06:48.927990586 +0100 -+++ b/hypgeom.h 2015-12-30 11:13:35.263807331 +0100 -@@ -29,7 +29,7 @@ - #include "fmprb.h" - #include "arb.h" - #include "mag.h" --#include "fmpz_poly.h" -+#include "flint/fmpz_poly.h" - - #ifdef __cplusplus - extern "C" { -diff -ru a/mag/d_log.c b/mag/d_log.c ---- a/mag/d_log.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/d_log.c 2015-12-30 11:13:35.263807331 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - /* - This is a bad implementation the logarithm function, -diff -ru a/mag/exp.c b/mag/exp.c ---- a/mag/exp.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/exp.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - static const double inverse_factorials[] = { - 1.0, -diff -ru a/mag/get_d.c b/mag/get_d.c ---- a/mag/get_d.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/get_d.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - double -diff -ru a/mag/log1p.c b/mag/log1p.c ---- a/mag/log1p.c 2015-12-30 11:06:48.928990597 +0100 -+++ b/mag/log1p.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "double_extras.h" -+#include "flint/double_extras.h" - - void - mag_log1p(mag_t z, const mag_t x) -diff -ru a/mag/test/t-cmp_2exp_si.c b/mag/test/t-cmp_2exp_si.c ---- a/mag/test/t-cmp_2exp_si.c 2015-12-30 11:06:48.929990610 +0100 -+++ b/mag/test/t-cmp_2exp_si.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/mag/test/t-d_log_lower_bound.c b/mag/test/t-d_log_lower_bound.c ---- a/mag/test/t-d_log_lower_bound.c 2015-12-30 11:06:48.929990610 +0100 -+++ b/mag/test/t-d_log_lower_bound.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag/test/t-d_log_upper_bound.c b/mag/test/t-d_log_upper_bound.c ---- a/mag/test/t-d_log_upper_bound.c 2015-12-30 11:06:48.929990610 +0100 -+++ b/mag/test/t-d_log_upper_bound.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag/test/t-mul_2exp_si.c b/mag/test/t-mul_2exp_si.c ---- a/mag/test/t-mul_2exp_si.c 2015-12-30 11:06:48.930990622 +0100 -+++ b/mag/test/t-mul_2exp_si.c 2015-12-30 11:13:35.264807342 +0100 -@@ -24,7 +24,7 @@ - ******************************************************************************/ - - #include "mag.h" --#include "long_extras.h" -+#include "flint/long_extras.h" - - int main() - { -diff -ru a/mag/test/t-set_d_2exp_fmpz.c b/mag/test/t-set_d_2exp_fmpz.c ---- a/mag/test/t-set_d_2exp_fmpz.c 2015-12-30 11:06:48.930990622 +0100 -+++ b/mag/test/t-set_d_2exp_fmpz.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag/test/t-set_d.c b/mag/test/t-set_d.c ---- a/mag/test/t-set_d.c 2015-12-30 11:06:48.930990622 +0100 -+++ b/mag/test/t-set_d.c 2015-12-30 11:13:35.264807342 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "double_extras.h" -+#include "flint/double_extras.h" - #include "mag.h" - - /* XXX: d_randtest is not good enough */ -diff -ru a/mag.h b/mag.h ---- a/mag.h 2015-12-30 11:06:48.927990586 +0100 -+++ b/mag.h 2015-12-30 11:13:35.264807342 +0100 -@@ -33,8 +33,8 @@ - #endif - - #include --#include "flint.h" --#include "fmpz.h" -+#include "flint/flint.h" -+#include "flint/fmpz.h" - #include "fmpz_extras.h" - - #ifdef __cplusplus -diff -ru a/partitions/hrr_sum_arb.c b/partitions/hrr_sum_arb.c ---- a/partitions/hrr_sum_arb.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/hrr_sum_arb.c 2015-12-30 11:13:35.265807353 +0100 -@@ -25,7 +25,7 @@ - - #include "partitions.h" - --#include "arith.h" -+#include "flint/arith.h" - #include "arb.h" - #include "math.h" - -diff -ru a/partitions/test/t-partitions_fmpz_ui.c b/partitions/test/t-partitions_fmpz_ui.c ---- a/partitions/test/t-partitions_fmpz_ui.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/test/t-partitions_fmpz_ui.c 2015-12-30 11:13:35.265807353 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "partitions.h" - - /* Values mod 10^9 generated with Sage */ -diff -ru a/partitions/test/t-partitions_fmpz_ui_threaded.c b/partitions/test/t-partitions_fmpz_ui_threaded.c ---- a/partitions/test/t-partitions_fmpz_ui_threaded.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/test/t-partitions_fmpz_ui_threaded.c 2015-12-30 11:13:35.265807353 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "partitions.h" - - /* Values mod 10^9 */ -diff -ru a/partitions/test/t-partitions_fmpz_ui_using_doubles.c b/partitions/test/t-partitions_fmpz_ui_using_doubles.c ---- a/partitions/test/t-partitions_fmpz_ui_using_doubles.c 2015-12-30 11:06:48.931990634 +0100 -+++ b/partitions/test/t-partitions_fmpz_ui_using_doubles.c 2015-12-30 11:13:35.265807353 +0100 -@@ -23,7 +23,7 @@ - - ******************************************************************************/ - --#include "arith.h" -+#include "flint/arith.h" - #include "partitions.h" - - /* Values mod 10^9 generated with Sage */ -diff -ru a/partitions.h b/partitions.h ---- a/partitions.h 2015-12-30 11:06:48.930990622 +0100 -+++ b/partitions.h 2015-12-30 11:13:35.265807353 +0100 -@@ -27,8 +27,8 @@ - #define PARTITIONS_H - - #include --#include "flint.h" --#include "arith.h" -+#include "flint/flint.h" -+#include "flint/arith.h" - #include "arb.h" - - #ifdef __cplusplus diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 6a1829af070..b1bf07ff452 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=c0925b13727bea3cd55b1e257858f1efaebef736 -md5=47e2e7f83aa4a91552144e7637d5233b -cksum=613456504 +sha1=e3d622d2a2bb2269a80d329b24a8eb42482831fe +md5=66684bb9389e7d030bd6e16fd114ba29 +cksum=2091457177 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index b4249c475b8..eb08bc0b0bc 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -239 +240 diff --git a/build/pkgs/cypari/checksums.ini b/build/pkgs/cypari/checksums.ini index d1b898c428b..fa58aa5691e 100644 --- a/build/pkgs/cypari/checksums.ini +++ b/build/pkgs/cypari/checksums.ini @@ -1,4 +1,4 @@ tarball=cypari2-VERSION.tar.gz -sha1=3388af8a9c847e16348864ad58f9c033f5a91592 -md5=1fabc73b44d56ef222fb9e87628b3ecb -cksum=2221981199 +sha1=9e1848b5dc566133edad79437fd39e298e336642 +md5=f268f870d255bb98bd4e917f0d74a463 +cksum=3159551499 diff --git a/build/pkgs/cypari/package-version.txt b/build/pkgs/cypari/package-version.txt index 524cb55242b..781dcb07cd8 100644 --- a/build/pkgs/cypari/package-version.txt +++ b/build/pkgs/cypari/package-version.txt @@ -1 +1 @@ -1.1.1 +1.1.3 diff --git a/build/pkgs/dot2tex/package-version.txt b/build/pkgs/dot2tex/package-version.txt index 98a37394aba..4f194b20925 100644 --- a/build/pkgs/dot2tex/package-version.txt +++ b/build/pkgs/dot2tex/package-version.txt @@ -1 +1 @@ -2.9.0.p1 +2.9.0.p2 diff --git a/build/pkgs/dot2tex/spkg-install b/build/pkgs/dot2tex/spkg-install index 3a313a75ccc..8bf68e410e8 100644 --- a/build/pkgs/dot2tex/spkg-install +++ b/build/pkgs/dot2tex/spkg-install @@ -6,8 +6,15 @@ fi cd src -$PIP_INSTALL . +# Check that Graphviz is installed by running dot2tex from the source +# directory. +python -c "import sys; from dot2tex.dotparsing import find_graphviz; sys.exit(0 if find_graphviz() else 1)" +if [ $? -ne 0 ]; then + echo >&2 "Error: dot2tex requires Graphviz but Graphviz is not installed. You can download Graphviz at http://www.graphviz.org/Download..php" + exit 1 +fi +$PIP_INSTALL . if [ $? -ne 0 ]; then echo >&2 "Error installing dot2tex." exit 1 diff --git a/build/pkgs/eclib/SPKG.txt b/build/pkgs/eclib/SPKG.txt index 1de401d1e87..dfbd7424a9b 100644 --- a/build/pkgs/eclib/SPKG.txt +++ b/build/pkgs/eclib/SPKG.txt @@ -2,9 +2,16 @@ == Description == -John Cremona's programs for enumerating and computing with elliptic -curves defined over the rational numbers. This is the culmination of -over 25 years of hard work. +mwrank is a program written in C++ for computing Mordell-Weil groups of +elliptic curves over Q via 2-descent. It is available as source code in +the eclib package, which may be distributed under the GNU General Public +License, version 2, or any later version. + +mwrank is now only distributed as part of eclib. eclib is also included +in Sage, and for most potential users the easiest way to run mwrank is +to install Sage (which also of course gives you much much more). I no +longer provide a source code distribution of mwrank by itself: use eclib +instead. == License == @@ -14,13 +21,11 @@ eclib is licensed GPL v2+. * Author: John Cremona * Email: john.cremona@gmail.com - * Website: https://github.com/JohnCremona/eclib + * Website: http://homepages.warwick.ac.uk/staff/J.E.Cremona/mwrank/index.html + * Repository: https://github.com/JohnCremona/eclib == Dependencies == * PARI * NTL * FLINT - - - diff --git a/build/pkgs/eclib/checksums.ini b/build/pkgs/eclib/checksums.ini index b0e51d59f08..4527f4291fd 100644 --- a/build/pkgs/eclib/checksums.ini +++ b/build/pkgs/eclib/checksums.ini @@ -1,4 +1,4 @@ tarball=eclib-VERSION.tar.bz2 -sha1=2527c49624bb90619b4b185c38dc6c3bc9737b38 -md5=2c0557cecb1145b7df6ddc71332b0656 -cksum=1113684095 +sha1=abd277f71416966f36eb8e1b0a814d7028c56baa +md5=2c6e90c61f49cf9c38a5c9fd9a1ebcef +cksum=1683788031 diff --git a/build/pkgs/eclib/package-version.txt b/build/pkgs/eclib/package-version.txt index 6a141b04abd..8d66f7e048f 100644 --- a/build/pkgs/eclib/package-version.txt +++ b/build/pkgs/eclib/package-version.txt @@ -1 +1 @@ -20170330 +20171002 diff --git a/build/pkgs/gc/package-version.txt b/build/pkgs/gc/package-version.txt index a940330e279..e67c9d21592 100644 --- a/build/pkgs/gc/package-version.txt +++ b/build/pkgs/gc/package-version.txt @@ -1 +1 @@ -7.2f.p0 +7.2f.p1 diff --git a/build/pkgs/gc/patches/0001-On-Cygwin-use-mprotect-instead-of-mmap-to-set-PROT_N.patch b/build/pkgs/gc/patches/0001-On-Cygwin-use-mprotect-instead-of-mmap-to-set-PROT_N.patch new file mode 100644 index 00000000000..3161874f9fb --- /dev/null +++ b/build/pkgs/gc/patches/0001-On-Cygwin-use-mprotect-instead-of-mmap-to-set-PROT_N.patch @@ -0,0 +1,75 @@ +On Cygwin, use mprotect to set PROT_NONE on a memory-mapped region, instead +of trying to reuse mmap on an existing region, which breaks. Use the +allocation granularity for determining allocation sizes/offsets, rather +than the actual page size (as Cygwin itself does). See +https://trac.sagemath.org/ticket/23973 +diff --git a/os_dep.c b/os_dep.c +index e6283ac..a1bb9e4 100644 +--- a/os_dep.c ++++ b/os_dep.c +@@ -698,7 +698,11 @@ GC_INNER word GC_page_size = 0; + GC_INNER void GC_setpagesize(void) + { + GetSystemInfo(&GC_sysinfo); +- GC_page_size = GC_sysinfo.dwPageSize; ++# if defined(CYGWIN32) && defined(USE_MUNMAP) ++ GC_page_size = GC_sysinfo.dwAllocationGranularity; ++# else ++ GC_page_size = GC_sysinfo.dwPageSize; ++# endif + # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION) + { + OSVERSIONINFO verInfo; +@@ -2404,12 +2408,18 @@ GC_INNER void GC_unmap(ptr_t start, size_t bytes) + /* We immediately remap it to prevent an intervening mmap from */ + /* accidentally grabbing the same address space. */ + { +- void * result; +- result = mmap(start_addr, len, PROT_NONE, +- MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, +- zero_fd, 0/* offset */); +- if (result != (void *)start_addr) +- ABORT("mmap(PROT_NONE) failed"); ++# ifdef CYGWIN32 ++ if (mprotect(start_addr, len, PROT_NONE)) ++ ABORT("mprotect(PROT_NONE) failed"); ++# else ++ void * result; ++ ++ result = mmap(start_addr, len, PROT_NONE, ++ MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, ++ zero_fd, 0/* offset */); ++ if (result != (void *)start_addr) ++ ABORT("mmap(PROT_NONE) failed"); ++# endif + } + GC_unmapped_bytes += len; + # endif +@@ -2515,13 +2525,18 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, + } + # else + if (len != 0) { ++# ifdef CYGWIN32 ++ if (mprotect(start_addr, len, PROT_NONE)) ++ ABORT("mprotect(PROT_NONE) failed"); ++# else + /* Immediately remap as above. */ +- void * result; +- result = mmap(start_addr, len, PROT_NONE, +- MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, +- zero_fd, 0/* offset */); +- if (result != (void *)start_addr) +- ABORT("mmap(PROT_NONE) failed"); ++ void * result; ++ result = mmap(start_addr, len, PROT_NONE, ++ MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, ++ zero_fd, 0/* offset */); ++ if (result != (void *)start_addr) ++ ABORT("mmap(PROT_NONE) failed"); ++# endif + } + GC_unmapped_bytes += len; + # endif +-- +2.8.3 + diff --git a/build/pkgs/gc/spkg-install b/build/pkgs/gc/spkg-install index 8898abe8296..c6a955eecfc 100644 --- a/build/pkgs/gc/spkg-install +++ b/build/pkgs/gc/spkg-install @@ -22,6 +22,8 @@ CONFIGURE_FLAGS="--enable-large-config" if [ "$UNAME" = "CYGWIN" ]; then # See https://trac.sagemath.org/ticket/22694 CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-threads=posix --enable-handle-fork" + # Force use of mmap on Cygwin https://trac.sagemath.org/ticket/23973 + export CFLAGS="$CFLAGS -DUSE_MMAP -DUSE_MUNMAP" fi ./configure --prefix="$SAGE_LOCAL" --libdir="$SAGE_LOCAL/lib" $CONFIGURE_FLAGS diff --git a/build/pkgs/giacpy_sage/checksums.ini b/build/pkgs/giacpy_sage/checksums.ini index 62f3e872805..d2cab244fed 100644 --- a/build/pkgs/giacpy_sage/checksums.ini +++ b/build/pkgs/giacpy_sage/checksums.ini @@ -1,4 +1,4 @@ tarball=giacpy_sage-VERSION.tar.gz -sha1=1f4dcec697296d1cce88fa9a03c14df2a9ba71c5 -md5=515734bc266c15c69e195636f448cd97 -cksum=2454875195 +sha1=0d82ae71219d546532e1234fee4ea8b1b6f53ccf +md5=d8cc9fe590e808c2543b8fc712ea9481 +cksum=1760632879 diff --git a/build/pkgs/giacpy_sage/package-version.txt b/build/pkgs/giacpy_sage/package-version.txt index 5a2a5806df6..05e8a4593fa 100644 --- a/build/pkgs/giacpy_sage/package-version.txt +++ b/build/pkgs/giacpy_sage/package-version.txt @@ -1 +1 @@ -0.6 +0.6.6 diff --git a/build/pkgs/gmpy2/package-version.txt b/build/pkgs/gmpy2/package-version.txt index 815e68dd20e..6c28a87df9c 100644 --- a/build/pkgs/gmpy2/package-version.txt +++ b/build/pkgs/gmpy2/package-version.txt @@ -1 +1 @@ -2.0.8 +2.0.8.p0 diff --git a/build/pkgs/gmpy2/patches/no_set_memory_functions.patch b/build/pkgs/gmpy2/patches/no_set_memory_functions.patch new file mode 100644 index 00000000000..29fa9432293 --- /dev/null +++ b/build/pkgs/gmpy2/patches/no_set_memory_functions.patch @@ -0,0 +1,17 @@ +Remove call to mp_set_memory_functions() + +Merged upstream in 68bad31a7c636b77f20b064e1728b86f2386972d +as part of a much larger patch. + +diff -ru a/src/gmpy2.c b/src/gmpy2.c +--- a/src/gmpy2.c 2016-06-13 21:17:56.000000000 +0200 ++++ b/src/gmpy2.c 2017-10-04 14:14:23.925780258 +0200 +@@ -842,8 +842,6 @@ + PyObject *temp = NULL; + #endif + +- mp_set_memory_functions(gmpy_allocate, gmpy_reallocate, gmpy_free); +- + set_zcache(); + set_pympzcache(); + set_pympqcache(); diff --git a/build/pkgs/pari/checksums.ini b/build/pkgs/pari/checksums.ini index 9983fa901ed..8ae0dd5e0aa 100644 --- a/build/pkgs/pari/checksums.ini +++ b/build/pkgs/pari/checksums.ini @@ -1,4 +1,4 @@ tarball=pari-VERSION.tar.gz -sha1=99a8ecd47ee6cdd22098d8585db183e357fb7b71 -md5=ae178b3c984af32f2008d147e901aa76 -cksum=4215303198 +sha1=49958e45f5a198ef6462eda2b95af4994a7766eb +md5=1fb3ae3066c21baf6cd4f5fa77b190e4 +cksum=700493771 diff --git a/build/pkgs/pari/package-version.txt b/build/pkgs/pari/package-version.txt index 97f22211f46..6b404559f12 100644 --- a/build/pkgs/pari/package-version.txt +++ b/build/pkgs/pari/package-version.txt @@ -1 +1 @@ -2.9.3.p0 +2.10-1280-g88fb5b3.p0 diff --git a/build/pkgs/pari/patches/README.txt b/build/pkgs/pari/patches/README.txt index 39b66f0877a..c9b7fa89801 100644 --- a/build/pkgs/pari/patches/README.txt +++ b/build/pkgs/pari/patches/README.txt @@ -11,6 +11,3 @@ Patches to configuration files: C files: * stackwarn.patch (Jeroen Demeyer, #19883): do not display warnings regarding the stack size (unless DEBUGMEM is set). - -Bugfixes: -* polredabs.patch (Maarten Derickx, #23259): Fix bug in polredabs diff --git a/build/pkgs/pari/patches/config_graphic.patch b/build/pkgs/pari/patches/config_graphic.patch deleted file mode 100644 index 66881e37a6b..00000000000 --- a/build/pkgs/pari/patches/config_graphic.patch +++ /dev/null @@ -1,47 +0,0 @@ -commit d02e043959bd90e7354e7675633abb8de5f27857 -Author: Jeroen Demeyer -Date: Mon Jan 9 16:06:02 2017 +0100 - - Simplify handling of --graphic option and check validity - -diff --git a/config/Makefile.SH b/config/Makefile.SH -index def1a9c..bba22ff 100644 ---- a/config/Makefile.SH -+++ b/config/Makefile.SH -@@ -69,6 +69,7 @@ esac - PLOTCFLAGS= - PLOTLIBS= - postconfig=: -+plotrunpath= - case "$which_graphic_lib" in - none) - graph=plotnull;; -@@ -90,20 +91,18 @@ fltk) - win32) - PLOTLIBS="-lgdi32" - graph=plotWin32;; -+X11) -+ PLOTCFLAGS="$PLOTCFLAGS $X11_INC" -+ PLOTLIBS="$PLOTLIBS $X11_LIBS" -+ plotrunpath=$X11 -+ graph=plotX;; -+*) -+ echo >&2 "### Unrecognized graphic library '$which_graphic_lib'." -+ exit 1;; - esac - graph="plotport $graph" - libgraph="plottty" - --plotrunpath= --case "$which_graphic_lib" in -- *X11*) -- PLOTCFLAGS="$PLOTCFLAGS $X11_INC" -- PLOTLIBS="$PLOTLIBS $X11_LIBS" -- plotrunpath=$X11 -- graph="plotX $graph" -- ;; --esac -- - KERNOBJS= - for f in $kernel; do - KERNOBJS="$KERNOBJS $f\$(_O)" diff --git a/build/pkgs/pari/patches/pari_str_1.patch b/build/pkgs/pari/patches/pari_str_1.patch deleted file mode 100644 index f340d343b86..00000000000 --- a/build/pkgs/pari/patches/pari_str_1.patch +++ /dev/null @@ -1,597 +0,0 @@ -commit 723b30bbad0e9f6aa578c87a843ece37655b4cfd -Author: Karim Belabas -Date: Tue Jan 24 17:24:57 2017 +0100 - - 34- [libpari] str_init, str_printf, str_putc, str_puts - -diff --git a/doc/usersch5.tex b/doc/usersch5.tex -index 213ddec..02cdf94 100644 ---- a/doc/usersch5.tex -+++ b/doc/usersch5.tex -@@ -11744,6 +11744,35 @@ not a malloc'ed string. - \fun{GEN}{gvsprintf}{const char *fmt, va_list ap} variadic version of - \tet{gsprintf} - -+\subsec{Dynamic strings} -+ -+A \tet{pari_str} is a dynamic string which grows dynamically as needed. -+This structure contains private data and two public members \kbd{char *string}, -+which is the string itself and \kbd{use\_stack} which tells whether the -+string lives -+ -+\item on the PARI stack (value $1$), meaning that it will be destroyed by any -+manipulation of the stack, e.g. a \kbd{gerepile} call or resetting -+\kbd{avma}; -+ -+\item in malloc'ed memory (value $0$), in which case it is impervious to -+stack manipulation but will need to be explicitly freed by the user -+after use, via \kbd{pari\_free(s.string)}. -+ -+ -+\fun{void}{str_init}{pari_str *S, int use_stack} initializes a dynamic -+string; if \kbd{use\_stack} is 0, then the string is malloc'ed, else -+it lives on the PARI stack. -+ -+\fun{void}{str_printf}{pari_str *S, const char *fmt, ...} write to the end -+of $S$ the remaining arguments according to PARI format \kbd{fmt}. -+ -+\fun{void}{str_putc}{pari_str *S, char c} write the character $c$ to the end -+of $S$. -+ -+\fun{void}{str_puts}{pari_str *S, const char *s} write the string $s$ to the -+end of $S$. -+ - \section{Output} - - \subsec{Output contexts} -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index a0da6e6..391873d 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -2806,6 +2806,10 @@ void printtex(GEN g); - char* stack_sprintf(const char *fmt, ...); - char* stack_strcat(const char *s, const char *t); - char* stack_strdup(const char *s); -+void str_init(pari_str *S, int use_stack); -+void str_printf(pari_str *S, const char *fmt, ...); -+void str_putc(pari_str *S, char c); -+void str_puts(pari_str *S, char c); - void strftime_expand(const char *s, char *buf, long max); - GEN Strprintf(const char *fmt, GEN args); - FILE* switchin(const char *name); -diff --git a/src/headers/paristio.h b/src/headers/paristio.h -index 7abce5d..a4fec9e 100644 ---- a/src/headers/paristio.h -+++ b/src/headers/paristio.h -@@ -17,6 +17,14 @@ typedef struct { - long s, us; - } pari_timer; - -+typedef struct pari_str { -+ char *string; /* start of the output buffer */ -+ char *end; /* end of the output buffer */ -+ char *cur; /* current writing place in the output buffer */ -+ size_t size; /* buffer size */ -+ int use_stack; /* use stack_malloc instead of malloc ? */ -+} pari_str; -+ - typedef unsigned char *byteptr; - typedef ulong pari_sp; - -diff --git a/src/language/es.c b/src/language/es.c -index 90ce368..e1bfc8d 100644 ---- a/src/language/es.c -+++ b/src/language/es.c -@@ -41,23 +41,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - - static const char esc = (0x1f & '['); /* C-[ = escape */ - --typedef struct outString { -- char *string; /* start of the output buffer */ -- char *end; /* end of the output buffer */ -- char *cur; /* current writing place in the output buffer */ -- size_t size; /* buffer size */ -- int use_stack; /* use stack_malloc instead of malloc ? */ --} outString; -+typedef void (*OUT_FUN)(GEN, pariout_t *, pari_str *); - --typedef void (*OUT_FUN)(GEN, pariout_t *, outString *); -+static void bruti_sign(GEN g, pariout_t *T, pari_str *S, int addsign); -+static void matbruti(GEN g, pariout_t *T, pari_str *S); -+static void texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign); - --static void bruti_sign(GEN g, pariout_t *T, outString *S, int addsign); --static void matbruti(GEN g, pariout_t *T, outString *S); --static void texi_sign(GEN g, pariout_t *T, outString *S, int addsign); -- --static void bruti(GEN g, pariout_t *T, outString *S) -+static void bruti(GEN g, pariout_t *T, pari_str *S) - { bruti_sign(g,T,S,1); } --static void texi(GEN g, pariout_t *T, outString *S) -+static void texi(GEN g, pariout_t *T, pari_str *S) - { texi_sign(g,T,S,1); } - - void -@@ -877,7 +869,7 @@ absrtostr(GEN x, int sp, char FORMAT, long wanted_dec) - - /* l = old len, L = new len */ - static void --str_alloc0(outString *S, long l, long L) -+str_alloc0(pari_str *S, long l, long L) - { - char *s; - if (S->use_stack) -@@ -896,20 +888,21 @@ str_alloc0(outString *S, long l, long L) - * To avoid automatic extension in between av = avma / avma = av pairs - * [ would destroy S->string if (S->use_stack) ] */ - static void --str_alloc(outString *S, long l) -+str_alloc(pari_str *S, long l) - { - l *= 20; - if (S->end - S->cur <= l) - str_alloc0(S, S->cur - S->string, S->size + maxss(S->size, l)); - } --static void --str_putc(outString *S, char c) { -+void -+str_putc(pari_str *S, char c) -+{ - *S->cur++ = c; - if (S->cur == S->end) str_alloc0(S, S->size, S->size << 1); - } - --static void --str_init(outString *S, int use_stack) -+void -+str_init(pari_str *S, int use_stack) - { - char *s; - S->size = 1024; -@@ -918,14 +911,15 @@ str_init(outString *S, int use_stack) - s = (char*)stack_malloc(S->size); - else - s = (char*)pari_malloc(S->size); -+ *s = 0; - S->string = S->cur = s; - S->end = S->string + S->size; - } --static void --str_puts(outString *S, const char *s) { while (*s) str_putc(S, *s++); } -+void -+str_puts(pari_str *S, const char *s) { while (*s) str_putc(S, *s++); } - - static void --str_putscut(outString *S, const char *str, int cut) -+str_putscut(pari_str *S, const char *str, int cut) - { - if (cut < 0) str_puts(S, str); - else { -@@ -937,7 +931,7 @@ str_putscut(outString *S, const char *str, int cut) - static char * - stack_GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out) - { -- outString S; str_init(&S, 1); -+ pari_str S; str_init(&S, 1); - out(x, T, &S); *S.cur = 0; - return S.string; - } -@@ -951,14 +945,14 @@ static char * - GENtostr_fun(GEN x, pariout_t *T, OUT_FUN out) - { - pari_sp av = avma; -- outString S; str_init(&S, 0); -+ pari_str S; str_init(&S, 0); - out(x, T, &S); *S.cur = 0; - avma = av; return S.string; - } - - /* lbuf = strlen(buf), len < 0: unset */ - static void --outpad(outString *S, const char *buf, long lbuf, int sign, long ljust, long len, long zpad) -+outpad(pari_str *S, const char *buf, long lbuf, int sign, long ljust, long len, long zpad) - { - long padlen = len - lbuf; - if (padlen < 0) padlen = 0; -@@ -983,7 +977,7 @@ outpad(outString *S, const char *buf, long lbuf, int sign, long ljust, long len, - - /* len < 0 or maxwidth < 0: unset */ - static void --fmtstr(outString *S, const char *buf, int ljust, int len, int maxwidth) -+fmtstr(pari_str *S, const char *buf, int ljust, int len, int maxwidth) - { - int padlen, lbuf = strlen(buf); - -@@ -1000,9 +994,10 @@ fmtstr(outString *S, const char *buf, int ljust, int len, int maxwidth) - /* abs(base) is 8, 10, 16. If base < 0, some "alternate" form - * -- print hex in uppercase - * -- prefix octal with 0 -- * signvalue = -1: unsigned, otherwise ' ' or '+' */ -+ * signvalue = -1: unsigned, otherwise ' ' or '+'. Leaves a messy stack if -+ * S->use_stack */ - static void --fmtnum(outString *S, long lvalue, GEN gvalue, int base, int signvalue, -+fmtnum(pari_str *S, long lvalue, GEN gvalue, int base, int signvalue, - int ljust, int len, int zpad) - { - int caps; -@@ -1010,7 +1005,7 @@ fmtnum(outString *S, long lvalue, GEN gvalue, int base, int signvalue, - long lbuf, mxl; - GEN uvalue = NULL; - ulong ulvalue = 0; -- pari_sp av = avma; /* Assume !S->use_stack */ -+ pari_sp av = avma; - - if (gvalue) - { -@@ -1159,7 +1154,7 @@ fmtnum(outString *S, long lvalue, GEN gvalue, int base, int signvalue, - lbuf = (buf0 - buf) - 1; - END: - outpad(S, buf, lbuf, signvalue, ljust, len, zpad); -- avma = av; -+ if (!S->use_stack) avma = av; - } - - static GEN -@@ -1213,10 +1208,10 @@ get_sigd(GEN gvalue, char ch, int maxwidth) - } - - static void --fmtreal(outString *S, GEN gvalue, int space, int signvalue, int FORMAT, -+fmtreal(pari_str *S, GEN gvalue, int space, int signvalue, int FORMAT, - int maxwidth, int ljust, int len, int zpad) - { -- pari_sp av = avma; /* Assume !S->use_stack */ -+ pari_sp av = avma; - long sigd; - char *buf; - -@@ -1281,14 +1276,16 @@ fmtreal(outString *S, GEN gvalue, int space, int signvalue, int FORMAT, - buf = absrtostr(gvalue, space, FORMAT, sigd); - if (signe(gvalue) < 0) signvalue = '-'; - outpad(S, buf, strlen(buf), signvalue, ljust, len, zpad); -- avma = av; -+ if (!S->use_stack) avma = av; - } --/* format handling "inspired" by the standard draft at -+/* Format handling "inspired" by the standard draft at - -- http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf pages 274ff - * fmt is a standard printf format, except 'P' is a "length modifier" -- * allowing GEN arguments. Use either the arg_vector or (if NULL) the va_list */ --static char * --sm_dopr(const char *fmt, GEN arg_vector, va_list args) -+ * allowing GEN arguments. Use either the arg_vector or (if NULL) the va_list. -+ * Appent output to the pari_str S, which must be initialized; clean if -+ * !S->use_stack, else leaves objects of stack. */ -+static void -+str_arg_vprintf(pari_str *S, const char *fmt, GEN arg_vector, va_list args) - { - int GENflag = 0, longflag = 0, pointflag = 0; - int print_plus, print_blank, with_sharp, ch, ljust, len, maxwidth, zpad; -@@ -1296,9 +1293,6 @@ sm_dopr(const char *fmt, GEN arg_vector, va_list args) - int index = 1; - GEN gvalue; - const char *save_fmt = fmt; -- outString __S, *S = &__S; -- -- str_init(S, 0); - - while ((ch = *fmt++) != '\0') { - switch(ch) { -@@ -1453,7 +1447,8 @@ nextch: - } - if (gvalue) strvalue = GENtostr_unquoted(gvalue); - fmtstr(S, strvalue, ljust, len, maxwidth); -- avma = av; break; -+ if (!S->use_stack) avma = av; -+ break; - } - case 'c': - if (arg_vector) { -@@ -1489,7 +1484,8 @@ nextch: - } - fmtreal(S, gvalue, GP_DATA->fmt->sp, dosign(print_blank,print_plus), - ch, maxwidth, ljust, len, zpad); -- avma = av; break; -+ if (!S->use_stack) avma = av; -+ break; - } - default: - pari_err(e_MISC, "invalid conversion or specification %c in format `%s'", ch, save_fmt); -@@ -1501,7 +1497,6 @@ nextch: - } /* first switch on ch */ - } /* while loop on ch */ - *S->cur = 0; -- return S->string; - } - - void -@@ -1976,7 +1971,7 @@ itostr(GEN x) { - - /* x != 0 t_INT, write abs(x) to S */ - static void --str_absint(outString *S, GEN x) -+str_absint(pari_str *S, GEN x) - { - pari_sp av; - long l; -@@ -1993,7 +1988,7 @@ str_absint(outString *S, GEN x) - - /* print e to S (more efficient than sprintf) */ - static void --str_ulong(outString *S, ulong e) -+str_ulong(pari_str *S, ulong e) - { - if (e == 0) str_putc(S, '0'); - else -@@ -2010,14 +2005,14 @@ str_ulong(outString *S, ulong e) - } - } - static void --str_long(outString *S, long e) -+str_long(pari_str *S, long e) - { - if (e >= 0) str_ulong(S, (ulong)e); - else { str_putc(S, '-'); str_ulong(S, -(ulong)e); } - } - - static void --wr_vecsmall(pariout_t *T, outString *S, GEN g) -+wr_vecsmall(pariout_t *T, pari_str *S, GEN g) - { - long i, l; - str_puts(S, "Vecsmall(["); l = lg(g); -@@ -2103,7 +2098,7 @@ blancs(long nb) { while (nb-- > 0) pari_putc(' '); } - - /* write an "address" */ - static void --str_addr(outString *S, ulong x) -+str_addr(pari_str *S, ulong x) - { char s[128]; sprintf(s,"%0*lx", BITS_IN_LONG/4, x); str_puts(S, s); } - static void - dbg_addr(ulong x) { pari_printf("[&=%0*lx] ", BITS_IN_LONG/4, x); } -@@ -2578,7 +2573,7 @@ isdenom(GEN g) - /********************************************************************/ - /* ^e */ - static void --texexpo(outString *S, long e) -+texexpo(pari_str *S, long e) - { - if (e != 1) { - str_putc(S, '^'); -@@ -2591,27 +2586,27 @@ texexpo(outString *S, long e) - } - } - static void --wrexpo(outString *S, long e) -+wrexpo(pari_str *S, long e) - { if (e != 1) { str_putc(S, '^'); str_long(S, e); } } - - /* v^e */ - static void --VpowE(outString *S, const char *v, long e) { str_puts(S, v); wrexpo(S,e); } -+VpowE(pari_str *S, const char *v, long e) { str_puts(S, v); wrexpo(S,e); } - static void --texVpowE(outString *S, const char *v, long e) { str_puts(S, v); texexpo(S,e); } -+texVpowE(pari_str *S, const char *v, long e) { str_puts(S, v); texexpo(S,e); } - static void --monome(outString *S, const char *v, long e) -+monome(pari_str *S, const char *v, long e) - { if (e) VpowE(S, v, e); else str_putc(S, '1'); } - static void --texnome(outString *S, const char *v, long e) -+texnome(pari_str *S, const char *v, long e) - { if (e) texVpowE(S, v, e); else str_putc(S, '1'); } - - /* ( a ) */ - static void --paren(pariout_t *T, outString *S, GEN a) -+paren(pariout_t *T, pari_str *S, GEN a) - { str_putc(S, '('); bruti(a,T,S); str_putc(S, ')'); } - static void --texparen(pariout_t *T, outString *S, GEN a) -+texparen(pariout_t *T, pari_str *S, GEN a) - { - if (T->TeXstyle & TEXSTYLE_PAREN) - str_puts(S, " ("); -@@ -2626,15 +2621,15 @@ texparen(pariout_t *T, outString *S, GEN a) - - /* * v^d */ - static void --times_texnome(outString *S, const char *v, long d) -+times_texnome(pari_str *S, const char *v, long d) - { if (d) { str_puts(S, "\\*"); texnome(S,v,d); } } - static void --times_monome(outString *S, const char *v, long d) -+times_monome(pari_str *S, const char *v, long d) - { if (d) { str_putc(S, '*'); monome(S,v,d); } } - - /* write a * v^d */ - static void --wr_monome(pariout_t *T, outString *S, GEN a, const char *v, long d) -+wr_monome(pariout_t *T, pari_str *S, GEN a, const char *v, long d) - { - long sig = isone(a); - -@@ -2648,7 +2643,7 @@ wr_monome(pariout_t *T, outString *S, GEN a, const char *v, long d) - } - } - static void --wr_texnome(pariout_t *T, outString *S, GEN a, const char *v, long d) -+wr_texnome(pariout_t *T, pari_str *S, GEN a, const char *v, long d) - { - long sig = isone(a); - -@@ -2666,7 +2661,7 @@ wr_texnome(pariout_t *T, outString *S, GEN a, const char *v, long d) - } - - static void --wr_lead_monome(pariout_t *T, outString *S, GEN a,const char *v, long d, int addsign) -+wr_lead_monome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign) - { - long sig = isone(a); - if (sig) { -@@ -2679,7 +2674,7 @@ wr_lead_monome(pariout_t *T, outString *S, GEN a,const char *v, long d, int adds - } - } - static void --wr_lead_texnome(pariout_t *T, outString *S, GEN a,const char *v, long d, int addsign) -+wr_lead_texnome(pariout_t *T, pari_str *S, GEN a,const char *v, long d, int addsign) - { - long sig = isone(a); - if (sig) { -@@ -2693,11 +2688,11 @@ wr_lead_texnome(pariout_t *T, outString *S, GEN a,const char *v, long d, int add - } - - static void --prints(GEN g, pariout_t *T, outString *S) -+prints(GEN g, pariout_t *T, pari_str *S) - { (void)T; str_long(S, (long)g); } - - static void --quote_string(outString *S, char *s) -+quote_string(pari_str *S, char *s) - { - str_putc(S, '"'); - while (*s) -@@ -2720,7 +2715,7 @@ quote_string(outString *S, char *s) - } - - static int --print_0_or_pm1(GEN g, outString *S, int addsign) -+print_0_or_pm1(GEN g, pari_str *S, int addsign) - { - long r; - if (!g) { str_puts(S, "NULL"); return 1; } -@@ -2735,7 +2730,7 @@ print_0_or_pm1(GEN g, outString *S, int addsign) - } - - static void --print_precontext(GEN g, outString *S, long tex) -+print_precontext(GEN g, pari_str *S, long tex) - { - if (lg(g)<8 || lg(gel(g,7))==1) return; - else -@@ -2755,7 +2750,7 @@ print_precontext(GEN g, outString *S, long tex) - } - - static void --print_context(GEN g, pariout_t *T, outString *S, long tex) -+print_context(GEN g, pariout_t *T, pari_str *S, long tex) - { - GEN str = closure_get_text(g); - if (lg(g)<8 || lg(gel(g,7))==1) return; -@@ -2804,7 +2799,7 @@ print_context(GEN g, pariout_t *T, outString *S, long tex) - } - - static void --bruti_intern(GEN g, pariout_t *T, outString *S, int addsign) -+bruti_intern(GEN g, pariout_t *T, pari_str *S, int addsign) - { - long l,i,j,r, tg = typ(g); - GEN a,b; -@@ -3036,14 +3031,14 @@ bruti_intern(GEN g, pariout_t *T, outString *S, int addsign) - } - - static void --bruti_sign(GEN g, pariout_t *T, outString *S, int addsign) -+bruti_sign(GEN g, pariout_t *T, pari_str *S, int addsign) - { - if (!print_0_or_pm1(g, S, addsign)) - bruti_intern(g, T, S, addsign); - } - - static void --matbruti(GEN g, pariout_t *T, outString *S) -+matbruti(GEN g, pariout_t *T, pari_str *S) - { - long i, j, r, w, l, *pad = NULL; - pari_sp av; -@@ -3060,7 +3055,7 @@ matbruti(GEN g, pariout_t *T, outString *S) - { - long lgall = 2; /* opening [ and closing ] */ - pari_sp av2; -- outString scratchstr; -+ pari_str scratchstr; - pad = cgetg(l*r+1, t_VECSMALL); /* left on stack if (S->use_stack)*/ - av2 = avma; - str_init(&scratchstr, 1); -@@ -3106,7 +3101,7 @@ matbruti(GEN g, pariout_t *T, outString *S) - /********************************************************************/ - /* this follows bruti_sign */ - static void --texi_sign(GEN g, pariout_t *T, outString *S, int addsign) -+texi_sign(GEN g, pariout_t *T, pari_str *S, int addsign) - { - long tg,i,j,l,r; - GEN a,b; -@@ -4519,13 +4514,16 @@ out_print0(PariOUT *out, const char *sep, GEN g, long flag) - } - } - static void --str_print0(outString *S, GEN g, long flag) -+str_print0(pari_str *S, GEN g, long flag) - { - pari_sp av = avma; - OUT_FUN f = get_fun(flag); - long i, l = lg(g); -- for (i = 1; i < l; i++, avma = av) -+ for (i = 1; i < l; i++) -+ { - str_puts(S, stack_GENtostr_fun_unquoted(gel(g,i), GP_DATA->fmt, f)); -+ if (!S->use_stack) avma = av; -+ } - *(S->cur) = 0; - } - -@@ -4533,7 +4531,7 @@ str_print0(outString *S, GEN g, long flag) - char * - pari_sprint0(const char *s, GEN g, long flag) - { -- outString S; -+ pari_str S; - str_init(&S, 0); - str_puts(&S, s); - str_print0(&S, g, flag); -@@ -4544,7 +4542,7 @@ static void - print0_file(FILE *out, GEN g, long flag) - { - pari_sp av = avma; -- outString S; -+ pari_str S; - str_init(&S, 1); - str_print0(&S, g, flag); - fputs(S.string, out); -@@ -4559,7 +4557,16 @@ printsep(const char *s, GEN g) - void - printsep1(const char *s, GEN g) { out_print0(pariOut, s, g, f_RAW); pari_flush(); } - --/* dummy needed to pass a (empty!) va_list to sm_dopr */ -+static char * -+sm_dopr(const char *fmt, GEN arg_vector, va_list args) -+{ -+ pari_str s; -+ str_init(&s, 0); -+ str_arg_vprintf(&s, fmt, arg_vector, args); -+ return s.string; -+} -+ -+/* dummy needed to pass an empty va_list to sm_dopr */ - static char * - dopr_arg_vector(GEN arg_vector, const char* fmt, ...) - { -@@ -4625,6 +4632,14 @@ pari_sprintf(const char *fmt, ...) /* variadic version of Strprintf */ - va_end(ap); return s; - } - -+void -+str_printf(pari_str *S, const char *fmt, ...) -+{ -+ va_list ap; va_start(ap, fmt); -+ str_arg_vprintf(S, fmt, NULL, ap); -+ va_end(ap); -+} -+ - char * - stack_sprintf(const char *fmt, ...) - { diff --git a/build/pkgs/pari/patches/pari_str_2.patch b/build/pkgs/pari/patches/pari_str_2.patch deleted file mode 100644 index 424cdf600c8..00000000000 --- a/build/pkgs/pari/patches/pari_str_2.patch +++ /dev/null @@ -1,19 +0,0 @@ -commit 2383190eaceafc234980dfff973477edfa192875 -Author: Karim Belabas -Date: Tue Jan 24 17:29:33 2017 +0100 - - typo in previous patch - -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index 391873d..0cbcf02 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -2809,7 +2809,7 @@ char* stack_strdup(const char *s); - void str_init(pari_str *S, int use_stack); - void str_printf(pari_str *S, const char *fmt, ...); - void str_putc(pari_str *S, char c); --void str_puts(pari_str *S, char c); -+void str_puts(pari_str *S, const char *s); - void strftime_expand(const char *s, char *buf, long max); - GEN Strprintf(const char *fmt, GEN args); - FILE* switchin(const char *name); diff --git a/build/pkgs/pari/patches/plot_libpari.patch b/build/pkgs/pari/patches/plot_libpari.patch deleted file mode 100644 index 6c892f6de3f..00000000000 --- a/build/pkgs/pari/patches/plot_libpari.patch +++ /dev/null @@ -1,993 +0,0 @@ -commit bd96c260a028ece5b5a76b43182d839591eac2c9 -Author: Jeroen Demeyer -Date: Mon Jan 9 15:55:05 2017 +0100 - - Move plotting frontend to libpari; initial support for multiple plotting engines - -diff --git a/config/Makefile.SH b/config/Makefile.SH -index ddebdac..a28f9b9 100644 ---- a/config/Makefile.SH -+++ b/config/Makefile.SH -@@ -72,26 +72,32 @@ postconfig=: - plotrunpath= - case "$which_graphic_lib" in - none) -- graph=plotnull;; -+ graph="";; - ps) -+ enable_plot_ps=yes - graph=plotps;; - Qt) -+ enable_plot_qt=yes - PLOTCFLAGS='-D__FANCY_WIN__ -I$(QTDIR)/include' - PLOTLIBS="-L\$(QTDIR)/lib $QTLIB" - graph=plotQt;; - Qt4) -+ enable_plot_qt4=yes - PLOTCFLAGS='-D__FANCY_WIN__ -I$(QTDIR)/include' - PLOTLIBS="-L\$(QTDIR)/lib $QTLIB" - graph=plotQt4;; - fltk) -+ enable_plot_fltk=yes - PLOTCFLAGS= - PLOTLIBS="$FLTK_LIBS" - postconfig='fltk-config --post ' - graph=plotfltk;; - win32) -+ enable_plot_win32=yes - PLOTLIBS="-lgdi32" - graph=plotWin32;; - X11) -+ enable_plot_x=yes - PLOTCFLAGS="$PLOTCFLAGS $X11_INC" - PLOTLIBS="$PLOTLIBS $X11_LIBS" - plotrunpath=$X11 -@@ -100,8 +106,7 @@ win32) - echo >&2 "### Unrecognized graphic library '$which_graphic_lib'." - exit 1;; - esac --graph="plotport $graph" --libgraph="plottty" -+libgraph="plotport plottty" - - KERNOBJS= - for f in $kernel; do -@@ -736,10 +741,6 @@ for dir in basemath modules language gp graph systems mt; do - depend="./paricfg.h" - cflags="$cflags \$(DLCFLAGS)" - ;; -- plotport) -- cflags="$cflags -I$src/graph" -- depend="$RECT_H" -- ;; - plotQt) - cflags="$cflags \$(PLOTCFLAGS)" - depend="$RECT_H" -@@ -755,7 +756,7 @@ for dir in basemath modules language gp graph systems mt; do - depend="$RECT_H" - compile="\$(CXX)" - ;; -- plottty) -+ plotport|plottty) - depend="$RECT_H" - cflags="$cflags \$(DLCFLAGS)" - ;; -diff --git a/config/paricfg.h.SH b/config/paricfg.h.SH -index 6fb22fa..c0c9e04 100644 ---- a/config/paricfg.h.SH -+++ b/config/paricfg.h.SH -@@ -188,4 +188,28 @@ case $enable_tls in - yes) echo '#define ENABLE_TLS' >> $file;; - esac - -+case $enable_plot_ps in -+yes) echo '#define ENABLE_PLOT_PS' >> $file;; -+esac -+ -+case $enable_plot_qt in -+yes) echo '#define ENABLE_PLOT_QT' >> $file;; -+esac -+ -+case $enable_plot_qt4 in -+yes) echo '#define ENABLE_PLOT_QT4' >> $file;; -+esac -+ -+case $enable_plot_fltk in -+yes) echo '#define ENABLE_PLOT_FLTK' >> $file;; -+esac -+ -+case $enable_plot_win32 in -+yes) echo '#define ENABLE_PLOT_WIN32' >> $file;; -+esac -+ -+case $enable_plot_x in -+yes) echo '#define ENABLE_PLOT_X' >> $file;; -+esac -+ - echo '#endif' >> $file -diff --git a/src/functions/graphic/plotbox b/src/functions/graphic/plotbox -index 23622f3..f697015 100644 ---- a/src/functions/graphic/plotbox -+++ b/src/functions/graphic/plotbox -@@ -1,5 +1,4 @@ - Function: plotbox --Class: highlevel - Section: graphic - C-Name: rectbox - Prototype: vLGG -diff --git a/src/functions/graphic/plotclip b/src/functions/graphic/plotclip -index 367f25f..f0943e2 100644 ---- a/src/functions/graphic/plotclip -+++ b/src/functions/graphic/plotclip -@@ -1,5 +1,4 @@ - Function: plotclip --Class: highlevel - Section: graphic - C-Name: rectclip - Prototype: vL -diff --git a/src/functions/graphic/plotcolor b/src/functions/graphic/plotcolor -index 3754445..2350170 100644 ---- a/src/functions/graphic/plotcolor -+++ b/src/functions/graphic/plotcolor -@@ -1,5 +1,4 @@ - Function: plotcolor --Class: highlevel - Section: graphic - C-Name: rectcolor - Prototype: vLL -diff --git a/src/functions/graphic/plotcopy b/src/functions/graphic/plotcopy -index 2f32c64..2796f61 100644 ---- a/src/functions/graphic/plotcopy -+++ b/src/functions/graphic/plotcopy -@@ -1,5 +1,4 @@ - Function: plotcopy --Class: highlevel - Section: graphic - C-Name: rectcopy_gen - Prototype: vLLGGD0,L, -diff --git a/src/functions/graphic/plotcursor b/src/functions/graphic/plotcursor -index b685729..153527b 100644 ---- a/src/functions/graphic/plotcursor -+++ b/src/functions/graphic/plotcursor -@@ -1,5 +1,4 @@ - Function: plotcursor --Class: highlevel - Section: graphic - C-Name: rectcursor - Prototype: L -diff --git a/src/functions/graphic/plotdraw b/src/functions/graphic/plotdraw -index 0026d33..ced478c 100644 ---- a/src/functions/graphic/plotdraw -+++ b/src/functions/graphic/plotdraw -@@ -1,5 +1,4 @@ - Function: plotdraw --Class: highlevel - Section: graphic - C-Name: rectdraw_flag - Prototype: vGD0,L, -diff --git a/src/functions/graphic/ploth b/src/functions/graphic/ploth -index 63d4eca..28d2bca 100644 ---- a/src/functions/graphic/ploth -+++ b/src/functions/graphic/ploth -@@ -1,5 +1,4 @@ - Function: ploth --Class: highlevel - Section: graphic - C-Name: ploth - Prototype: V=GGEpD0,M,D0,L,\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 -@@ -112,3 +111,4 @@ Doc: high precision plot of the function $y=f(x)$ represented by the expression - ploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex") - @eprog\noindent will draw respectively a circle and a circle cut by the line - $y=x$. -+ %\syn{NO} -diff --git a/src/functions/graphic/plothraw b/src/functions/graphic/plothraw -index 03ceccd..79fed03 100644 ---- a/src/functions/graphic/plothraw -+++ b/src/functions/graphic/plothraw -@@ -1,5 +1,4 @@ - Function: plothraw --Class: highlevel - Section: graphic - C-Name: plothraw - Prototype: GGD0,L, -diff --git a/src/functions/graphic/plothsizes b/src/functions/graphic/plothsizes -index 8d96047..cc247d8 100644 ---- a/src/functions/graphic/plothsizes -+++ b/src/functions/graphic/plothsizes -@@ -1,5 +1,4 @@ - Function: plothsizes --Class: highlevel - Section: graphic - C-Name: plothsizes_flag - Prototype: D0,L, -diff --git a/src/functions/graphic/plotinit b/src/functions/graphic/plotinit -index 0c6c709..4d66be6 100644 ---- a/src/functions/graphic/plotinit -+++ b/src/functions/graphic/plotinit -@@ -1,5 +1,4 @@ - Function: plotinit --Class: highlevel - Section: graphic - C-Name: initrect_gen - Prototype: vLDGDGD0,L, -diff --git a/src/functions/graphic/plotkill b/src/functions/graphic/plotkill -index 182b53b..77699bd 100644 ---- a/src/functions/graphic/plotkill -+++ b/src/functions/graphic/plotkill -@@ -1,5 +1,4 @@ - Function: plotkill --Class: highlevel - Section: graphic - C-Name: killrect - Prototype: vL -diff --git a/src/functions/graphic/plotlines b/src/functions/graphic/plotlines -index 903b50c..d1ed9f6 100644 ---- a/src/functions/graphic/plotlines -+++ b/src/functions/graphic/plotlines -@@ -1,5 +1,4 @@ - Function: plotlines --Class: highlevel - Section: graphic - C-Name: rectlines - Prototype: vLGGD0,L, -diff --git a/src/functions/graphic/plotlinetype b/src/functions/graphic/plotlinetype -index 7f96cba..bc23419 100644 ---- a/src/functions/graphic/plotlinetype -+++ b/src/functions/graphic/plotlinetype -@@ -1,5 +1,4 @@ - Function: plotlinetype --Class: highlevel - Section: graphic - C-Name: rectlinetype - Prototype: vLL -diff --git a/src/functions/graphic/plotmove b/src/functions/graphic/plotmove -index 6bdd6a6..a689794 100644 ---- a/src/functions/graphic/plotmove -+++ b/src/functions/graphic/plotmove -@@ -1,5 +1,4 @@ - Function: plotmove --Class: highlevel - Section: graphic - C-Name: rectmove - Prototype: vLGG -diff --git a/src/functions/graphic/plotpoints b/src/functions/graphic/plotpoints -index cc6f01d..14e7ee2 100644 ---- a/src/functions/graphic/plotpoints -+++ b/src/functions/graphic/plotpoints -@@ -1,5 +1,4 @@ - Function: plotpoints --Class: highlevel - Section: graphic - C-Name: rectpoints - Prototype: vLGG -diff --git a/src/functions/graphic/plotpointsize b/src/functions/graphic/plotpointsize -index d8ae632..1cc8a2e 100644 ---- a/src/functions/graphic/plotpointsize -+++ b/src/functions/graphic/plotpointsize -@@ -1,5 +1,4 @@ - Function: plotpointsize --Class: highlevel - Section: graphic - C-Name: rectpointsize - Prototype: vLG -diff --git a/src/functions/graphic/plotpointtype b/src/functions/graphic/plotpointtype -index e0b4c39..1dc06de 100644 ---- a/src/functions/graphic/plotpointtype -+++ b/src/functions/graphic/plotpointtype -@@ -1,5 +1,4 @@ - Function: plotpointtype --Class: highlevel - Section: graphic - C-Name: rectpointtype - Prototype: vLL -diff --git a/src/functions/graphic/plotrbox b/src/functions/graphic/plotrbox -index 503695e..b55d149 100644 ---- a/src/functions/graphic/plotrbox -+++ b/src/functions/graphic/plotrbox -@@ -1,5 +1,4 @@ - Function: plotrbox --Class: highlevel - Section: graphic - C-Name: rectrbox - Prototype: vLGG -diff --git a/src/functions/graphic/plotrecth b/src/functions/graphic/plotrecth -index dcb1528..7f6c66d 100644 ---- a/src/functions/graphic/plotrecth -+++ b/src/functions/graphic/plotrecth -@@ -1,5 +1,4 @@ - Function: plotrecth --Class: highlevel - Section: graphic - C-Name: rectploth - Prototype: LV=GGEpD0,M,D0,L,\nParametric|1; Recursive|2; no_Rescale|4; no_X_axis|8; no_Y_axis|16; no_Frame|32; no_Lines|64; Points_too|128; Splines|256; no_X_ticks|512; no_Y_ticks|1024; Same_ticks|2048; Complex|4096 -@@ -8,3 +7,4 @@ Help: plotrecth(w,X=a,b,expr,{flag=0},{n=0}): - ploth(w,X=a,b,expr,flag,n). Returns a vector for the bounding box. - Doc: writes to rectwindow $w$ the curve output of - \kbd{ploth}$(w,X=a,b,\var{expr},\fl,n)$. Returns a vector for the bounding box. -+ %\syn{NO} -diff --git a/src/functions/graphic/plotrecthraw b/src/functions/graphic/plotrecthraw -index 305456c..cef2f48 100644 ---- a/src/functions/graphic/plotrecthraw -+++ b/src/functions/graphic/plotrecthraw -@@ -1,5 +1,4 @@ - Function: plotrecthraw --Class: highlevel - Section: graphic - C-Name: rectplothraw - Prototype: LGD0,L, -diff --git a/src/functions/graphic/plotrline b/src/functions/graphic/plotrline -index 0720718..86d5b77 100644 ---- a/src/functions/graphic/plotrline -+++ b/src/functions/graphic/plotrline -@@ -1,5 +1,4 @@ - Function: plotrline --Class: highlevel - Section: graphic - C-Name: rectrline - Prototype: vLGG -diff --git a/src/functions/graphic/plotrmove b/src/functions/graphic/plotrmove -index b83c493..6d4afbc 100644 ---- a/src/functions/graphic/plotrmove -+++ b/src/functions/graphic/plotrmove -@@ -1,5 +1,4 @@ - Function: plotrmove --Class: highlevel - Section: graphic - C-Name: rectrmove - Prototype: vLGG -diff --git a/src/functions/graphic/plotrpoint b/src/functions/graphic/plotrpoint -index 37648ff..707335a 100644 ---- a/src/functions/graphic/plotrpoint -+++ b/src/functions/graphic/plotrpoint -@@ -1,5 +1,4 @@ - Function: plotrpoint --Class: highlevel - Section: graphic - C-Name: rectrpoint - Prototype: vLGG -diff --git a/src/functions/graphic/plotscale b/src/functions/graphic/plotscale -index 3c81e3d..a8524c9 100644 ---- a/src/functions/graphic/plotscale -+++ b/src/functions/graphic/plotscale -@@ -1,5 +1,4 @@ - Function: plotscale --Class: highlevel - Section: graphic - C-Name: rectscale - Prototype: vLGGGG -diff --git a/src/functions/graphic/plotstring b/src/functions/graphic/plotstring -index 54792dd..ca79084 100644 ---- a/src/functions/graphic/plotstring -+++ b/src/functions/graphic/plotstring -@@ -1,5 +1,4 @@ - Function: plotstring --Class: highlevel - Section: graphic - C-Name: rectstring3 - Prototype: vLsD0,L, -diff --git a/src/functions/graphic/psdraw b/src/functions/graphic/psdraw -index 5d3f937..d2757db 100644 ---- a/src/functions/graphic/psdraw -+++ b/src/functions/graphic/psdraw -@@ -1,5 +1,4 @@ - Function: psdraw --Class: highlevel - Section: graphic - C-Name: postdraw_flag - Prototype: vGD0,L, -diff --git a/src/functions/graphic/psploth b/src/functions/graphic/psploth -index 0911e26..f6c1ffe 100644 ---- a/src/functions/graphic/psploth -+++ b/src/functions/graphic/psploth -@@ -1,5 +1,4 @@ - Function: psploth --Class: highlevel - Section: graphic - C-Name: postploth - Prototype: V=GGEpD0,L,D0,L, -diff --git a/src/functions/graphic/psplothraw b/src/functions/graphic/psplothraw -index e9b153d..4d99fe7 100644 ---- a/src/functions/graphic/psplothraw -+++ b/src/functions/graphic/psplothraw -@@ -1,5 +1,4 @@ - Function: psplothraw --Class: highlevel - Section: graphic - C-Name: postplothraw - Prototype: GGD0,L, -diff --git a/src/gp/gp.c b/src/gp/gp.c -index deaeec7..9f00381 100644 ---- a/src/gp/gp.c -+++ b/src/gp/gp.c -@@ -540,6 +540,26 @@ cyg_environment(int argc, char ** argv) - } - #endif - -+/* It's OK if none of the ENABLE_ macros are defined. This will give -+ * an error whenever ploth() is called. */ -+static void -+set_graphic_engine() -+{ -+#if defined(ENABLE_PLOT_X) -+ PARI_get_plot_X(); -+#elif defined(ENABLE_PLOT_FLTK) -+ PARI_get_plot_fltk(); -+#elif defined(ENABLE_PLOT_QT4) -+ PARI_get_plot_Qt4(); -+#elif defined(ENABLE_PLOT_QT) -+ PARI_get_plot_Qt(); -+#elif defined(ENABLE_PLOT_WIN32) -+ PARI_get_plot_Win32(); -+#elif defined(ENABLE_PLOT_PS) -+ PARI_get_plot_ps(); -+#endif -+} -+ - int - main(int argc, char **argv) - { -@@ -562,7 +582,7 @@ main(int argc, char **argv) - pari_init_defaults(); - pari_library_path = DL_DFLT_NAME; - pari_stack_init(&s_A,sizeof(*A),(void**)&A); -- pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm); -+ pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm | INIT_GRAPHm); - cb_pari_err_recover = gp_err_recover; - cb_pari_pre_recover = gp_pre_recover; - cb_pari_break_loop = break_loop; -@@ -576,7 +596,7 @@ main(int argc, char **argv) - pari_add_module(functions_gp); - pari_add_module(functions_highlevel); - -- init_graph(); -+ set_graphic_engine(); - cb_pari_quit = gp_quit; - cb_pari_whatnow = whatnow; - cb_pari_sigint = gp_sigint_fun; -@@ -643,8 +663,7 @@ dbg_up(long k) - void - gp_quit(long code) - { -- free_graph(); -- pari_close(); -+ pari_close_opts(INIT_JMPm | INIT_SIGm | INIT_DFTm | INIT_GRAPHm); - kill_buffers_upto(NULL); - if (!(GP_DATA->flags & gpd_QUIET)) pari_puts("Goodbye!\n"); - if (cb_pari_end_output) cb_pari_end_output(); -diff --git a/src/gp/gp.h b/src/gp/gp.h -index d89fdc9..6ee391f 100644 ---- a/src/gp/gp.h -+++ b/src/gp/gp.h -@@ -33,4 +33,14 @@ extern void (*cb_gp_output)(GEN z); - extern void (*cb_pari_end_output)(void); - - extern entree functions_highlevel[], functions_gp[]; -+ -+/* Architecture-dependent plot files (src/graph/plotX.c ...). -+ * Note that not all these might be compiled! */ -+void PARI_get_plot_X(void); -+void PARI_get_plot_fltk(void); -+void PARI_get_plot_Qt4(void); -+void PARI_get_plot_Qt(void); -+void PARI_get_plot_Win32(void); -+void PARI_get_plot_ps(void); -+ - ENDEXTERN -diff --git a/src/graph/plotQt.c b/src/graph/plotQt.c -index 9aa3a81..d8adebf 100644 ---- a/src/graph/plotQt.c -+++ b/src/graph/plotQt.c -@@ -566,20 +566,13 @@ void PlotWindow::save( int id) { - #endif // __FANCY_WIN__ - - -- --// --// Implementation of the two architecture-dependent functions --// (from rect.h) requested by pari's plotting routines --// -- -- --void --rectdraw0(long *w, long *x, long *y, long lw) -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - if (pari_daemon()) return; // parent process returns - - pari_close(); -- PARI_get_plot(); - - // launch Qt window - int argc = 1; char *argv[] = { "gp", "-qws"}; // set argc = 2 for cross -@@ -606,10 +599,9 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_Qt(void) - /* This function initialises the structure rect.h: pari_plot */ - { -- if (pari_plot.init) return; // pari_plot is already set - #ifdef __QPE__ - pari_plot.width = 240; // width and - pari_plot.height = 320; // height of plot window -@@ -621,5 +613,6 @@ PARI_get_plot(void) - pari_plot.vunit = 3; // - pari_plot.fwidth = 6; // font width - pari_plot.fheight = 9; // and height -+ pari_plot.draw = &draw; - pari_plot.init = 1; // flag: pari_plot is set now! - } -diff --git a/src/graph/plotQt4.c b/src/graph/plotQt4.c -index 1ef7c40..13c8905 100644 ---- a/src/graph/plotQt4.c -+++ b/src/graph/plotQt4.c -@@ -553,20 +553,13 @@ void PlotWindow::save( int id) - #endif // __FANCY_WIN__ - - -- --// --// Implementation of the two architecture-dependent functions --// (from rect.h) requested by pari's plotting routines --// -- -- --void --rectdraw0(long *w, long *x, long *y, long lw) -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - if (pari_daemon()) return; // parent process returns - - pari_close(); -- PARI_get_plot(); - - // launch Qt window - int argc = 1; // set argc = 2 for cross -@@ -593,10 +586,9 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_Qt4(void) - /* This function initialises the structure rect.h: pari_plot */ - { -- if (pari_plot.init) return; // pari_plot is already set - #ifdef __QPE__ - pari_plot.width = 240; // width and - pari_plot.height = 320; // height of plot window -@@ -608,5 +600,6 @@ PARI_get_plot(void) - pari_plot.vunit = 3; // - pari_plot.fwidth = 6; // font width - pari_plot.fheight = 9; // and height -+ pari_plot.draw = &draw; - pari_plot.init = 1; // flag: pari_plot is set now! - } -diff --git a/src/graph/plotWin32.c b/src/graph/plotWin32.c -index 8af4d66..6ca8b9b 100644 ---- a/src/graph/plotWin32.c -+++ b/src/graph/plotWin32.c -@@ -68,7 +68,10 @@ static void DrawString(void *data, long x, long y, char *text, long numtext) - TextOut((HDC)data, x, y, text, numtext); - } - --void rectdraw0(long *w, long *x, long *y, long lw) -+ -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - char tmppath[MAX_PATH], fname[MAX_PATH]; - struct plot_eng plotWin32; -@@ -102,13 +105,11 @@ void rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_Win32(void) - { - HDC hdc; - TEXTMETRIC tm; -- if (pari_plot.init) return; /* pari_plot is already set */ - -- pari_plot.init = 1; - pari_plot.width = GetSystemMetrics(SM_CXSCREEN)/2; - pari_plot.height = GetSystemMetrics(SM_CYSCREEN)/2; - pari_plot.hunit = pari_plot.width/100; -@@ -121,4 +122,6 @@ PARI_get_plot(void) - - pari_plot.fwidth = tm.tmAveCharWidth; - pari_plot.fheight = tm.tmHeight; -+ pari_plot.draw = &draw; -+ pari_plot.init = 1; - } -diff --git a/src/graph/plotX.c b/src/graph/plotX.c -index 13bf839..b0b6e4e 100644 ---- a/src/graph/plotX.c -+++ b/src/graph/plotX.c -@@ -154,8 +154,10 @@ PARI_ColorSetUp(Display *display, GEN colors) - } - } - --void --rectdraw0(long *w, long *x, long *y, long lw) -+ -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - long oldwidth,oldheight; - struct plot_eng plotX; -@@ -173,7 +175,6 @@ rectdraw0(long *w, long *x, long *y, long lw) - - if (pari_daemon()) return; /* parent process returns */ - -- PARI_get_plot(); - pari_close(); - - display = XOpenDisplay(NULL); -@@ -279,13 +280,12 @@ EXIT: - } - - void --PARI_get_plot(void) -+PARI_get_plot_X(void) - { - Display *display; - int screen; - -- if (pari_plot.init) return; -- if (!(display = XOpenDisplay(NULL))) pari_err(e_MISC, "no X server"); -+ if (!(display = XOpenDisplay(NULL))) {pari_warn(warner, "no X server"); return;} - screen = DefaultScreen(display); - pari_plot.width = DisplayWidth(display, screen) - 40; - pari_plot.height = DisplayHeight(display, screen) - 60; -@@ -293,6 +293,7 @@ PARI_get_plot(void) - pari_plot.fwidth = 9; - pari_plot.hunit = 5; - pari_plot.vunit = 5; -- pari_plot.init = 1; -+ pari_plot.draw = &draw; -+ pari_plot.init = 1; - XCloseDisplay(display); - } -diff --git a/src/graph/plotfltk.c b/src/graph/plotfltk.c -index 3879728..92abcbd 100644 ---- a/src/graph/plotfltk.c -+++ b/src/graph/plotfltk.c -@@ -189,20 +189,16 @@ int Plotter::handle(int event) - } - } - --// --// Implementation of the two architecture-dependent functions --// (from rect.h) requested by pari's plotting routines --// - --void --rectdraw0(long *w, long *x, long *y, long lw) -+/* Interface to PARI's plotting functions */ -+static void -+fltk_draw(long *w, long *x, long *y, long lw) - { - Plotter *win; - - if (pari_daemon()) return; // parent process returns - - pari_close(); -- PARI_get_plot(); - - Fl::visual(FL_DOUBLE|FL_INDEX); - win = new Plotter( w, x, y, lw); -@@ -215,15 +211,15 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_fltk(void) - /* This function initialises the structure rect.h: pari_plot */ - { -- if (pari_plot.init) return; // pari_plot is already set - pari_plot.width = 400; // width and - pari_plot.height = 300; // height of plot window - pari_plot.hunit = 3; // - pari_plot.vunit = 3; // - pari_plot.fwidth = 6; // font width - pari_plot.fheight = 9; // and height -+ pari_plot.draw = &fltk_draw; - pari_plot.init = 1; // flag: pari_plot is set now! - } -diff --git a/src/graph/plotnull.c b/src/graph/plotnull.c -deleted file mode 100644 -index fdf26e3..0000000 ---- a/src/graph/plotnull.c -+++ /dev/null -@@ -1,28 +0,0 @@ --/* Copyright (C) 2000 The PARI group. -- --This file is part of the PARI/GP package. -- --PARI/GP is free software; you can redistribute it and/or modify it under the --terms of the GNU General Public License as published by the Free Software --Foundation. It is distributed in the hope that it will be useful, but WITHOUT --ANY WARRANTY WHATSOEVER. -- --Check the License for details. You should have received a copy of it, along --with the package; see the file 'COPYING'. If not, write to the Free Software --Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -- --#include "pari.h" --#include "rect.h" -- --void --rectdraw0(long *w, long *x, long *y, long lw) --{ -- (void)w; -- (void)x; -- (void)y; -- (void)lw; --} -- --void --PARI_get_plot(void) --{ pari_err(e_MISC,"high resolution graphics disabled"); } -diff --git a/src/graph/plotport.c b/src/graph/plotport.c -index c6de38f..71eba71 100644 ---- a/src/graph/plotport.c -+++ b/src/graph/plotport.c -@@ -54,6 +54,13 @@ READ_EXPR(GEN code, GEN x) { - /** **/ - /********************************************************************/ - void -+PARI_get_plot(void) -+{ -+ if (!pari_plot.init) -+ pari_err(e_MISC, "high resolution graphics disabled"); -+} -+ -+void - init_graph(void) - { - long n; -@@ -1565,7 +1572,7 @@ rectplothrawin(long grect, dblPointList *data, long flags) - if (W) - { - if (W == &pari_plot) -- rectdraw0(w,wx,wy,2); -+ W->draw(w,wx,wy,2); - else - postdraw0(w,wx,wy,2, 0); - killrect(w[1]); -@@ -1704,6 +1711,7 @@ PARI_get_psplot(void) - pari_psplot.fwidth = 6; - pari_psplot.hunit = 5; - pari_psplot.vunit = 5; -+ pari_psplot.draw = NULL; /* Currently unused for ps plotting */ - } - - static void -@@ -1736,7 +1744,13 @@ gendraw(GEN list, long ps, long flag) - ne = itos(win); check_rect(ne); - w[i] = ne; - } -- if (ps) postdraw0(w,x,y,n,flag); else rectdraw0(w,x,y,n); -+ if (ps) -+ postdraw0(w,x,y,n,flag); -+ else -+ { -+ PARI_get_plot(); -+ pari_plot.draw(w,x,y,n); -+ } - pari_free(x); pari_free(y); pari_free(w); - } - -diff --git a/src/graph/plotps.c b/src/graph/plotps.c -index dcdecc1..bee35bf 100644 ---- a/src/graph/plotps.c -+++ b/src/graph/plotps.c -@@ -19,8 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "paripriv.h" - #include "rect.h" - --void --rectdraw0(long *w, long *x, long *y, long lw) -+ -+/* Interface to PARI's plotting functions */ -+static void -+draw(long *w, long *x, long *y, long lw) - { - struct plot_eng plot; - FILE *file; -@@ -44,14 +46,14 @@ rectdraw0(long *w, long *x, long *y, long lw) - } - - void --PARI_get_plot(void) -+PARI_get_plot_ps(void) - { -- if (pari_plot.init) return; - pari_plot.width = 400; - pari_plot.height = 300; - pari_plot.fheight = 9; - pari_plot.fwidth = 6; - pari_plot.hunit = 3; - pari_plot.vunit = 3; -- pari_plot.init = 1; -+ pari_plot.draw = &draw; -+ pari_plot.init = 1; - } -diff --git a/src/graph/rect.h b/src/graph/rect.h -index b8a3476..acc78a1 100644 ---- a/src/graph/rect.h -+++ b/src/graph/rect.h -@@ -23,6 +23,7 @@ typedef struct PARI_plot { - long fheight; - long init; - char name[PLOT_NAME_LEN+1]; -+ void (*draw)(long *w, long *x, long *y, long lw); - } PARI_plot; - - extern PARI_plot pari_plot, pari_psplot; -@@ -233,54 +234,12 @@ extern long rectline_itype; - /* plotport.c */ - typedef long (*col_counter)[ROt_MAX]; - --void color_to_rgb(GEN c, int *r, int *g, int *b); --void initrect(long ne, long x, long y); --void initrect_gen(long ne, GEN x, GEN y, long flag); --void killrect(long ne); - void plot_count(long *w, long lw, col_counter rcolcnt); --GEN ploth(GEN a, GEN b, GEN code, long prec, long flag, long numpoints); --GEN ploth2(GEN a, GEN b, GEN code, long prec); --GEN plothmult(GEN a, GEN b, GEN code, long prec); --GEN plothraw(GEN listx, GEN listy, long flag); --GEN plothsizes(void); --GEN plothsizes_flag(long flag); --void postdraw(GEN list); --void postdraw_flag(GEN list, long flag); --GEN postploth(GEN a,GEN b,GEN code,long prec,long flag,long numpoints); --GEN postploth2(GEN a,GEN b,GEN code,long prec,long numpoints); --GEN postplothraw(GEN listx, GEN listy, long flag); --void psplot_init(struct plot_eng *S, FILE *f, double xscale, double yscale, long fontsize); - void Printx(dblPointList *f); --void rectbox(long ne, GEN gx2, GEN gy2); --void rectcolor(long ne, long color); --void rectcopy(long source, long dest, long xoff, long yoff); --void rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag); --GEN rectcursor(long ne); --void rectdraw(GEN list); --void rectdraw_flag(GEN list, long flag); --void rectline(long ne, GEN gx2, GEN gy2); --void rectlines(long ne, GEN listx, GEN listy, long flag); --void rectlinetype(long ne, long t); --void rectmove(long ne, GEN x, GEN y); --GEN rectploth(long drawrect,GEN a, GEN b, GEN code, long prec, ulong flags, long testpoints); --GEN rectplothraw(long drawrect, GEN data, long flags); --void rectpoint(long ne, GEN x, GEN y); --void rectpoints(long ne, GEN listx, GEN listy); --void rectpointtype(long ne, long t); --void rectpointsize(long ne, GEN size); --void rectrbox(long ne, GEN gx2, GEN gy2); --void rectrline(long ne, GEN gx2, GEN gy2); --void rectrmove(long ne, GEN x, GEN y); --void rectrpoint(long ne, GEN x, GEN y); --void rectscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2); --void rectstring(long ne, char *x); --void rectstring3(long ne, char *x, long dir); --void rectclip(long rect); -- --void gen_rectdraw0(struct plot_eng *eng, long *w, long *x, long *y, long lw, double xs, double ys); -- --/* architecture-dependent plot file (plotX.c ...) */ -+void psplot_init(struct plot_eng *S, FILE *f, double xscale, double yscale, long fontsize); -+ -+void gen_rectdraw0(struct plot_eng *eng, long *w, long *x, long *y, long lw, double xs, double ys); -+ - void PARI_get_plot(void); --void rectdraw0(long *w, long *x, long *y, long lw); - - ENDEXTERN -diff --git a/src/headers/paricom.h b/src/headers/paricom.h -index 356ce51..85765c9 100644 ---- a/src/headers/paricom.h -+++ b/src/headers/paricom.h -@@ -99,7 +99,8 @@ enum { - INIT_DFTm = 4, - INIT_noPRIMEm = 8, - INIT_noIMTm = 16, -- INIT_noINTGMPm = 32 -+ INIT_noINTGMPm = 32, -+ INIT_GRAPHm = 64 - }; - - #ifndef HAS_EXP2 -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index 5565efe..98ee286 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -4054,6 +4054,53 @@ GEN polmodular(long L, long inv, GEN x, long yvar, long compute_derivs); - GEN polmodular_ZM(long L, long inv); - GEN polmodular_ZXX(long L, long inv, long xvar, long yvar); - -+/* plotport.c */ -+ -+void color_to_rgb(GEN c, int *r, int *g, int *b); -+void initrect(long ne, long x, long y); -+void initrect_gen(long ne, GEN x, GEN y, long flag); -+void killrect(long ne); -+GEN ploth(GEN a, GEN b, GEN code, long prec, long flag, long numpoints); -+GEN ploth2(GEN a, GEN b, GEN code, long prec); -+GEN plothmult(GEN a, GEN b, GEN code, long prec); -+GEN plothraw(GEN listx, GEN listy, long flag); -+GEN plothsizes(void); -+GEN plothsizes_flag(long flag); -+void postdraw(GEN list); -+void postdraw_flag(GEN list, long flag); -+GEN postploth(GEN a,GEN b,GEN code,long prec,long flag,long numpoints); -+GEN postploth2(GEN a,GEN b,GEN code,long prec,long numpoints); -+GEN postplothraw(GEN listx, GEN listy, long flag); -+void rectbox(long ne, GEN gx2, GEN gy2); -+void rectcolor(long ne, long color); -+void rectcopy(long source, long dest, long xoff, long yoff); -+void rectcopy_gen(long source, long dest, GEN xoff, GEN yoff, long flag); -+GEN rectcursor(long ne); -+void rectdraw(GEN list); -+void rectdraw_flag(GEN list, long flag); -+void rectline(long ne, GEN gx2, GEN gy2); -+void rectlines(long ne, GEN listx, GEN listy, long flag); -+void rectlinetype(long ne, long t); -+void rectmove(long ne, GEN x, GEN y); -+GEN rectploth(long drawrect,GEN a, GEN b, GEN code, long prec, ulong flags, long testpoints); -+GEN rectplothraw(long drawrect, GEN data, long flags); -+void rectpoint(long ne, GEN x, GEN y); -+void rectpoints(long ne, GEN listx, GEN listy); -+void rectpointtype(long ne, long t); -+void rectpointsize(long ne, GEN size); -+void rectrbox(long ne, GEN gx2, GEN gy2); -+void rectrline(long ne, GEN gx2, GEN gy2); -+void rectrmove(long ne, GEN x, GEN y); -+void rectrpoint(long ne, GEN x, GEN y); -+void rectscale(long ne, GEN x1, GEN x2, GEN y1, GEN y2); -+void rectstring(long ne, char *x); -+void rectstring3(long ne, char *x, long dir); -+void rectclip(long rect); -+ -+/* plottty.c */ -+ -+void pariplot(GEN a, GEN b, GEN code, GEN ysmlu, GEN ybigu, long prec); -+ - /* prime.c */ - - long BPSW_isprime(GEN x); -@@ -4161,7 +4208,6 @@ GEN derivfunk(void *E, GEN (*eval)(void *, GEN, long), GEN x, GEN ind0, long - int forvec_init(forvec_t *T, GEN x, long flag); - GEN forvec_next(forvec_t *T); - GEN limitnum(void *E, GEN (*f)(void *,GEN,long), long muli, GEN alpha, long prec); --void pariplot(GEN a, GEN b, GEN code, GEN ysmlu, GEN ybigu, long prec); - GEN polzag(long n, long m); - GEN prodeuler(void *E, GEN (*eval)(void *, GEN), GEN ga, GEN gb, long prec); - GEN prodinf(void *E, GEN (*eval)(void *, GEN), GEN a, long prec); -diff --git a/src/language/init.c b/src/language/init.c -index 1524531..7c8e7de 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -883,6 +883,7 @@ pari_init_opts(size_t parisize, ulong maxprime, ulong init_opts) - try_to_recover = 1; - if (!(init_opts&INIT_noIMTm)) pari_mt_init(); - if ((init_opts&INIT_SIGm)) pari_sig_init(pari_sighandler); -+ if ((init_opts&INIT_GRAPHm)) init_graph(); - } - - void -@@ -936,6 +937,7 @@ pari_close_opts(ulong init_opts) - free((void*)GP_DATA->prompt_cont); - free((void*)GP_DATA->histfile); - } -+ if (init_opts&INIT_GRAPHm) free_graph(); - BLOCK_SIGINT_END; - } - diff --git a/build/pkgs/pari/patches/plot_svg.patch b/build/pkgs/pari/patches/plot_svg.patch deleted file mode 100644 index 0d640051cd5..00000000000 --- a/build/pkgs/pari/patches/plot_svg.patch +++ /dev/null @@ -1,228 +0,0 @@ -commit 6ce728df0719490910a3f73cd075704af9e7b0e8 -Author: Jeroen Demeyer -Date: Wed Jan 11 09:56:02 2017 +0100 - - Implement SVG plotting - -diff --git a/config/Makefile.SH b/config/Makefile.SH -index a28f9b9..c50024e 100644 ---- a/config/Makefile.SH -+++ b/config/Makefile.SH -@@ -106,7 +106,7 @@ win32) - echo >&2 "### Unrecognized graphic library '$which_graphic_lib'." - exit 1;; - esac --libgraph="plotport plottty" -+libgraph="plotport plottty plotsvg" - - KERNOBJS= - for f in $kernel; do -@@ -756,7 +756,7 @@ for dir in basemath modules language gp graph systems mt; do - depend="$RECT_H" - compile="\$(CXX)" - ;; -- plotport|plottty) -+ plotport|plotsvg|plottty) - depend="$RECT_H" - cflags="$cflags \$(DLCFLAGS)" - ;; -diff --git a/src/graph/plotsvg.c b/src/graph/plotsvg.c -new file mode 100644 -index 0000000..844ef2e ---- /dev/null -+++ b/src/graph/plotsvg.c -@@ -0,0 +1,177 @@ -+/* Copyright (C) 2017 The PARI group. -+ -+This file is part of the PARI/GP package. -+ -+This program is free software; you can redistribute it and/or modify -+it under the terms of the GNU General Public License as published by -+the Free Software Foundation; either version 2 of the License, or -+(at your option) any later version. -+ -+This program is distributed in the hope that it will be useful, -+but WITHOUT ANY WARRANTY; without even the implied warranty of -+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+GNU General Public License for more details. -+ -+You should have received a copy of the GNU General Public License along -+with this program; if not, write to the Free Software Foundation, Inc., -+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+*/ -+ -+#include "pari.h" -+#include "paripriv.h" -+#include "rect.h" -+ -+/* Callback function to be called whenever an SVG plot is produced. -+ * The callback takes one argument, a const char* containing the text of -+ * the SVG file. */ -+cb_plot_svg_t cb_plot_svg = pari_puts; -+ -+struct svg_data { -+ pari_str str; -+ char hexcolor[8]; /* "#rrggbb\0" */ -+}; -+#define data_str(d) (&((struct svg_data*)(d))->str) -+#define data_hexcolor(d) (((struct svg_data*)(d))->hexcolor) -+ -+static const char hexdigit[16] = "0123456789abcdef"; -+ -+/* Work with precision 1/scale */ -+static const float scale = 1024.0; -+#define rescale(x) ((float)(x) / scale) -+ -+ -+static void -+svg_point(void *data, long x, long y) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_line(void *data, long x1, long y1, long x2, long y2) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_rect(void *data, long x, long y, long w, long h) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_points(void *data, long nb, struct plot_points *p) -+{ -+ long i; -+ for (i = 0; i < nb; i++) -+ svg_point(data, p[i].x, p[i].y); -+} -+ -+static void -+svg_color(void *data, long col) -+{ -+ int r, g, b; -+ char *hexcolor = data_hexcolor(data); -+ color_to_rgb(gel(GP_DATA->colormap, col+1), &r, &g, &b); -+ hexcolor[0] = '#'; -+ hexcolor[1] = hexdigit[r / 16]; -+ hexcolor[2] = hexdigit[r & 15]; -+ hexcolor[3] = hexdigit[g / 16]; -+ hexcolor[4] = hexdigit[g & 15]; -+ hexcolor[5] = hexdigit[b / 16]; -+ hexcolor[6] = hexdigit[b & 15]; -+ hexcolor[7] = '\0'; -+} -+ -+static void -+svg_lines(void *data, long nb, struct plot_points *p) -+{ -+ long i; -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "\n", data_hexcolor(data)); -+} -+ -+static void -+svg_text(void *data, long x, long y, char *text, long numtext) -+{ -+ pari_str *S = data_str(data); -+ -+ str_printf(S, "%s\n", -+ rescale(x), rescale(y), pari_plot.fheight, data_hexcolor(data), text); -+} -+ -+static void -+svg_head(pari_str *S) -+{ -+ str_printf(S, "\n", -+ pari_plot.width, pari_plot.height); -+} -+ -+static void -+svg_tail(pari_str *S) -+{ -+ str_printf(S, "\n"); -+} -+ -+ -+/* Interface to PARI's plotting functions */ -+static void -+svg_draw(long *w, long *x, long *y, long lw) -+{ -+ struct plot_eng pl; -+ struct svg_data data; -+ -+ /* Initialize data */ -+ str_init(&data.str, 0); -+ svg_color(&data, 0); -+ -+ /* Initialize pl */ -+ pl.data = &data; -+ pl.sc = &svg_color; -+ pl.pt = &svg_point; -+ pl.ln = &svg_line; -+ pl.bx = &svg_rect; -+ pl.mp = &svg_points; -+ pl.ml = &svg_lines; -+ pl.st = &svg_text; -+ pl.pl = &pari_plot; -+ -+ svg_head(&data.str); -+ gen_rectdraw0(&pl, w, x, y, lw, scale, scale); -+ svg_tail(&data.str); -+ -+ cb_plot_svg(data.str.string); -+ pari_free(data.str.string); -+} -+ -+void -+PARI_get_plot_svg() -+/* This function initialises the structure rect.h: pari_plot */ -+{ -+ pari_plot.width = 480; // width and -+ pari_plot.height = 320; // height of plot window -+ pari_plot.hunit = 3; // -+ pari_plot.vunit = 3; // -+ pari_plot.fwidth = 9; // font width -+ pari_plot.fheight = 12; // and height -+ pari_plot.draw = &svg_draw; -+ pari_plot.init = 1; // flag: pari_plot is set now! -+} -diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h -index 98ee286..293732f 100644 ---- a/src/headers/paridecl.h -+++ b/src/headers/paridecl.h -@@ -4097,6 +4097,12 @@ void rectstring(long ne, char *x); - void rectstring3(long ne, char *x, long dir); - void rectclip(long rect); - -+/* plotsvg.c */ -+ -+typedef void (*cb_plot_svg_t)(const char *svg); -+void PARI_get_plot_svg(); -+extern cb_plot_svg_t cb_plot_svg; -+ - /* plottty.c */ - - void pariplot(GEN a, GEN b, GEN code, GEN ysmlu, GEN ybigu, long prec); diff --git a/build/pkgs/pari/patches/prot_none_1.patch b/build/pkgs/pari/patches/prot_none_1.patch deleted file mode 100644 index 45d338f426e..00000000000 --- a/build/pkgs/pari/patches/prot_none_1.patch +++ /dev/null @@ -1,237 +0,0 @@ -commit f7d82845952ec92a5c3fa6f1b8b42236f9d80c21 -Author: Jeroen Demeyer -Date: Tue Nov 22 13:39:20 2016 +0100 - - Use PROT_NONE for unused virtual stack memory - -diff --git a/config/has_mmap.c b/config/has_mmap.c -index 87d93cf..fa79053 100644 ---- a/config/has_mmap.c -+++ b/config/has_mmap.c -@@ -3,15 +3,12 @@ - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif --#ifndef MAP_NORESERVE --#define MAP_NORESERVE 0 --#endif - int main(void) - { - size_t size = sysconf(_SC_PAGE_SIZE)*1000; - void *b = mmap(NULL, size, PROT_READ|PROT_WRITE, -- MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE,-1,0); -- madvise(b, size, MADV_DONTNEED); -+ MAP_PRIVATE|MAP_ANONYMOUS,-1,0); -+ mmap(b, size, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS,-1,0); - munmap(b, size); - return 0; - } -diff --git a/src/language/init.c b/src/language/init.c -index 1524531..c7a90f0 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -579,14 +579,11 @@ pari_add_defaults_module(entree *ep) - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif --#ifndef MAP_NORESERVE --#define MAP_NORESERVE 0 --#endif - static void * - pari_mainstack_malloc(size_t size) - { - void *b = mmap(NULL, size, PROT_READ|PROT_WRITE, -- MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE,-1,0); -+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - return (b == MAP_FAILED) ? NULL: b; - } - -@@ -596,10 +593,58 @@ pari_mainstack_mfree(void *s, size_t size) - munmap(s, size); - } - -+/* Completely discard the memory mapped between the addresses "from" -+ * and "to" (which must be page-aligned). -+ * -+ * We use mmap() with PROT_NONE, which means that the underlying memory -+ * is freed and that the kernel should not commit memory for it. We -+ * still keep the mapping such that we can change the flags to -+ * PROT_READ|PROT_WRITE later. -+ * -+ * NOTE: remapping with MAP_FIXED and PROT_NONE is not the same as -+ * calling mprotect(..., PROT_NONE) because the latter will keep the -+ * memory committed (this is in particular relevant on Linux with -+ * vm.overcommit = 2). This remains true even when calling -+ * madvise(..., MADV_DONTNEED). */ - static void --pari_mainstack_mreset(void *s, size_t size) -+pari_mainstack_mreset(pari_sp from, pari_sp to) - { -- madvise(s, size, MADV_DONTNEED); -+ size_t s = to - from; -+ mmap((void*)from, s, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -+} -+ -+/* Commit (make available) the virtual memory mapped between the -+ * addresses "from" and "to" (which must be page-aligned). -+ * Return 0 if successful, -1 if failed. */ -+static int -+pari_mainstack_mextend(pari_sp from, pari_sp to) -+{ -+ size_t s = to - from; -+ return mprotect((void*)from, s, PROT_READ|PROT_WRITE); -+} -+ -+/* Set actual stack size to the given size. This sets st->size and -+ * st->bot. If not enough system memory is available, this can fail. -+ * Return 1 if successful, 0 if failed (in that case, st->size is not -+ * changed) */ -+static int -+pari_mainstack_setsize(struct pari_mainstack *st, size_t size) -+{ -+ pari_sp newbot = st->top - size; -+ /* Align newbot to pagesize */ -+ pari_sp alignbot = newbot & ~(pari_sp)(PARI_STACK_ALIGN - 1); -+ if (pari_mainstack_mextend(alignbot, st->top)) -+ { -+ /* Making the memory available did not work: limit vsize to the -+ * current actual stack size. */ -+ st->vsize = st->size; -+ pari_warn(warnstack, st->vsize); -+ return 0; -+ } -+ pari_mainstack_mreset(st->vbot, alignbot); -+ st->bot = newbot; -+ st->size = size; -+ return 1; - } - - #else -@@ -614,7 +659,18 @@ static void - pari_mainstack_mfree(void *s, size_t size) { (void) size; free(s); } - - static void --pari_mainstack_mreset(void *s, size_t size) { (void) s; (void) size; } -+pari_mainstack_mreset(pari_sp from, pari_sp to) { (void) from; (void) to; } -+ -+static int -+pari_mainstack_mextend(pari_sp from, pari_sp to) { (void) from; (void) to; return 0; } -+ -+static int -+pari_mainstack_setsize(struct pari_mainstack *st, size_t size) -+{ -+ st->bot = st->top - size; -+ st->size = size; -+ return 1; -+} - - #endif - -@@ -643,9 +699,12 @@ pari_mainstack_alloc(struct pari_mainstack *st, size_t rsize, size_t vsize) - } - st->vsize = vsize ? s: 0; - st->rsize = minuu(rsize, s); -- st->size = st->rsize; - st->top = st->vbot+s; -- st->bot = st->top - st->size; -+ if (!pari_mainstack_setsize(st, st->rsize)) -+ { -+ /* This should never happen since we only decrease the allocated space */ -+ pari_err(e_MEM); -+ } - st->memused = 0; - } - -@@ -654,7 +713,7 @@ pari_mainstack_free(struct pari_mainstack *st) - { - pari_mainstack_mfree((void*)st->vbot, st->vsize ? st->vsize : fix_size(st->rsize)); - st->top = st->bot = st->vbot = 0; -- st->size = st->vsize =0; -+ st->size = st->vsize = 0; - } - - static void -@@ -719,31 +778,47 @@ paristack_newrsize(ulong newsize) - void - paristack_resize(ulong newsize) - { -- size_t vsize = pari_mainstack->vsize; - if (!newsize) -- newsize = pari_mainstack->size << 1; -- newsize = maxuu(minuu(newsize, vsize), pari_mainstack->size); -- pari_mainstack->size = newsize; -- pari_mainstack->bot = pari_mainstack->top - pari_mainstack->size; -- pari_warn(warner,"increasing stack size to %lu",newsize); -+ newsize = 2 * pari_mainstack->size; -+ newsize = minuu(newsize, pari_mainstack->vsize); -+ if (newsize <= pari_mainstack->size) return; -+ if (pari_mainstack_setsize(pari_mainstack, newsize)) -+ { -+ pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size); -+ } - } - - void - parivstack_reset(void) - { -- pari_mainstack->size = pari_mainstack->rsize; -- pari_mainstack->bot = pari_mainstack->top - pari_mainstack->size; -- pari_mainstack_mreset((void *)pari_mainstack->vbot, -- pari_mainstack->bot-pari_mainstack->vbot); -+ pari_mainstack_setsize(pari_mainstack, pari_mainstack->rsize); - } - -+/* Enlarge the stack if needed such that the unused portion of the stack -+ * (between bot and avma) is large enough to contain x longs. */ - void - new_chunk_resize(size_t x) - { -- if (pari_mainstack->vsize==0 -- || x > (avma-pari_mainstack->vbot) / sizeof(long)) pari_err(e_STACK); -- while (x > (avma-pari_mainstack->bot) / sizeof(long)) -- paristack_resize(0); -+ ulong size, newsize, avail; -+ avail = (avma - pari_mainstack->bot) / sizeof(long); -+ if (avail >= x) return; -+ -+ /* We need to enlarge the stack. We try to at least double the -+ * stack, to avoid increasing the stack a lot of times by a small -+ * amount. */ -+ size = pari_mainstack->size; -+ newsize = size + maxuu((x - avail) * sizeof(long), size); -+ paristack_resize(newsize); -+ -+ /* Verify that we have enough space. Using a division here instead -+ * of a multiplication is safe against overflow. */ -+ avail = (avma - pari_mainstack->bot) / sizeof(long); -+ if (avail < x) -+ { -+ /* Restore old size and error out */ -+ pari_mainstack_setsize(pari_mainstack, size); -+ pari_err(e_STACK); -+ } - } - - /*********************************************************************/ -diff --git a/src/test/32/memory b/src/test/32/memory -new file mode 100644 -index 0000000..e865a17 ---- /dev/null -+++ b/src/test/32/memory -@@ -0,0 +1,8 @@ -+ *** Warning: new stack size = 1048576 (1.000 Mbytes). -+ *** at top-level: vector(100000,k,k) -+ *** ^-- -+ *** the PARI stack overflows ! -+ current stack size: 1048576 (1.000 Mbytes) -+ [hint] set 'parisizemax' to a non-zero value in your GPRC -+ -+Total time spent: 10 -diff --git a/src/test/in/memory b/src/test/in/memory -new file mode 100644 -index 0000000..2a36a9b ---- /dev/null -+++ b/src/test/in/memory -@@ -0,0 +1,2 @@ -+default(parisize, 2^20); -+vector(100000, k, k); \\ #1881 diff --git a/build/pkgs/pari/patches/prot_none_2.patch b/build/pkgs/pari/patches/prot_none_2.patch deleted file mode 100644 index 6eb3a1b829e..00000000000 --- a/build/pkgs/pari/patches/prot_none_2.patch +++ /dev/null @@ -1,25 +0,0 @@ -commit 6942fab48aeb5aa5f4ea283b04951240a3139728 -Author: Karim Belabas -Date: Mon Jan 16 16:00:37 2017 +0100 - - remove useless definitions when ! HAS_MMAP - - pari_mainstack_mreset + pari_mainstack_mextend - -diff --git a/src/language/init.c b/src/language/init.c -index c7a90f0..64783be 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -658,12 +658,6 @@ pari_mainstack_malloc(size_t s) - static void - pari_mainstack_mfree(void *s, size_t size) { (void) size; free(s); } - --static void --pari_mainstack_mreset(pari_sp from, pari_sp to) { (void) from; (void) to; } -- --static int --pari_mainstack_mextend(pari_sp from, pari_sp to) { (void) from; (void) to; return 0; } -- - static int - pari_mainstack_setsize(struct pari_mainstack *st, size_t size) - { diff --git a/build/pkgs/pari/patches/prot_none_3.patch b/build/pkgs/pari/patches/prot_none_3.patch deleted file mode 100644 index 941dbf5edc2..00000000000 --- a/build/pkgs/pari/patches/prot_none_3.patch +++ /dev/null @@ -1,59 +0,0 @@ -commit 845c0adf2be189702825a60304b79f21831cc7e0 -Author: Jeroen Demeyer -Date: Wed Jan 18 13:45:39 2017 +0000 - - Reset avma before calling parivstack_reset - -diff --git a/doc/usersch5.tex b/doc/usersch5.tex -index 58c7d04..6dc868c 100644 ---- a/doc/usersch5.tex -+++ b/doc/usersch5.tex -@@ -193,9 +193,12 @@ at most \kbd{parisizemax}. The stack content is not affected - by this operation. - - \fun{void}{parivstack_reset}{void} --resets the current stack to its default size \kbd{parisize}, --destroying its content. Used to recover memory after a --computation that enlarged the stack. -+resets the current stack to its default size \kbd{parisize}. This is -+used to recover memory after a computation that enlarged the stack. -+This function destroys the content of the enlarged stack (between -+the old and the new bottom of the stack). -+Before calling this function, you must ensure that \kbd{avma} lies -+within the new smaller stack. - - \fun{void}{paristack_newrsize}{ulong newsize} - \emph{(does not return)}. Library version of -diff --git a/src/gp/gp.c b/src/gp/gp.c -index deaeec7..3463a2d 100644 ---- a/src/gp/gp.c -+++ b/src/gp/gp.c -@@ -360,7 +360,6 @@ gp_main_loop(long ismain) - if (ismain) continue; - pop_buffer(); return z; - } -- avma = av; - if (ismain) - { - reset_ctrlc(); -@@ -384,6 +383,7 @@ gp_main_loop(long ismain) - if (GP_DATA->simplify) z = simplify_shallow(z); - pari_add_hist(z, t); - if (z != gnil && ! is_silent(b->buf) ) gp_output(z); -+ avma = av; - parivstack_reset(); - } - } -diff --git a/src/language/init.c b/src/language/init.c -index 64783be..6c69c8e 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -786,6 +786,8 @@ void - parivstack_reset(void) - { - pari_mainstack_setsize(pari_mainstack, pari_mainstack->rsize); -+ if (avma < pari_mainstack->bot) -+ pari_err_BUG("parivstack_reset [avma < bot]"); - } - - /* Enlarge the stack if needed such that the unused portion of the stack diff --git a/build/pkgs/pari/patches/prot_none_4.patch b/build/pkgs/pari/patches/prot_none_4.patch deleted file mode 100644 index 36e952855a2..00000000000 --- a/build/pkgs/pari/patches/prot_none_4.patch +++ /dev/null @@ -1,53 +0,0 @@ -commit c3dc1546580eda3bff6243cf563801c8a26ec67f -Author: Jeroen Demeyer -Date: Mon Apr 3 16:11:54 2017 +0200 - - mmap the PARI stack with MAP_NORESERVE - -diff --git a/src/language/init.c b/src/language/init.c -index 34cce31..acebe2f 100644 ---- a/src/language/init.c -+++ b/src/language/init.c -@@ -597,12 +597,26 @@ pari_add_defaults_module(entree *ep) - #ifndef MAP_ANONYMOUS - #define MAP_ANONYMOUS MAP_ANON - #endif -+#ifndef MAP_NORESERVE -+#define MAP_NORESERVE 0 -+#endif - static void * - pari_mainstack_malloc(size_t size) - { -+ /* Check that the system allows reserving "size" bytes. This is just -+ * a check, we immediately free the memory. */ - void *b = mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -- return (b == MAP_FAILED) ? NULL: b; -+ if (b == MAP_FAILED) return NULL; -+ munmap(b, size); -+ -+ /* Map again, this time with MAP_NORESERVE. On some operating systems -+ * like Cygwin, this is needed because remapping with PROT_NONE and -+ * MAP_NORESERVE does not work as expected. */ -+ b = mmap(NULL, size, PROT_READ|PROT_WRITE, -+ MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); -+ if (b == MAP_FAILED) return NULL; -+ return b; - } - - static void -@@ -628,7 +642,13 @@ static void - pari_mainstack_mreset(pari_sp from, pari_sp to) - { - size_t s = to - from; -- mmap((void*)from, s, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -+ void *addr, *res; -+ if (!s) return; -+ -+ addr = (void*)from; -+ res = mmap(addr, s, PROT_NONE, -+ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); -+ if (res != addr) pari_err(e_MEM); - } - - /* Commit (make available) the virtual memory mapped between the diff --git a/build/pkgs/pari/patches/stackwarn.patch b/build/pkgs/pari/patches/stackwarn.patch index 718592bd205..c3df5f81566 100644 --- a/build/pkgs/pari/patches/stackwarn.patch +++ b/build/pkgs/pari/patches/stackwarn.patch @@ -4,10 +4,10 @@ Date: Fri Nov 4 12:37:38 2016 +0100 Use DEBUGMEM for stack size warnings -diff -ru src/src/gp/gp.c b/src/gp/gp.c ---- src/src/gp/gp.c 2017-01-30 17:36:54.045921458 +0100 -+++ b/src/gp/gp.c 2017-01-30 17:37:07.225921164 +0100 -@@ -559,6 +559,7 @@ +diff -ru a/src/gp/gp.c b/src/gp/gp.c +--- a/src/gp/gp.c 2017-07-27 12:12:00.636618453 +0200 ++++ b/src/gp/gp.c 2017-07-27 12:12:09.913617857 +0200 +@@ -553,6 +553,7 @@ #endif stdin_isatty = pari_stdin_isatty(); pari_init_defaults(); @@ -15,10 +15,10 @@ diff -ru src/src/gp/gp.c b/src/gp/gp.c pari_library_path = DL_DFLT_NAME; pari_stack_init(&s_A,sizeof(*A),(void**)&A); pari_init_opts(1000000 * sizeof(long), 0, INIT_SIGm | INIT_noPRIMEm | INIT_noIMTm); -diff -ru src/src/language/init.c b/src/language/init.c ---- src/src/language/init.c 2017-01-30 17:36:54.046921458 +0100 -+++ b/src/language/init.c 2017-01-30 17:37:07.227921164 +0100 -@@ -793,7 +793,8 @@ +diff -ru a/src/language/init.c b/src/language/init.c +--- a/src/language/init.c 2017-07-27 12:12:00.637618452 +0200 ++++ b/src/language/init.c 2017-07-27 12:12:57.035614831 +0200 +@@ -797,7 +797,8 @@ evalstate_reset(); paristack_setsize(pari_mainstack->rsize, newsize); s = pari_mainstack->vsize ? pari_mainstack->vsize : pari_mainstack->rsize; @@ -28,7 +28,7 @@ diff -ru src/src/language/init.c b/src/language/init.c pari_init_errcatch(); cb_pari_err_recover(-1); } -@@ -807,7 +808,8 @@ +@@ -811,7 +812,8 @@ pari_mainstack_resize(pari_mainstack, newsize, vsize); evalstate_reset(); s = pari_mainstack->rsize; @@ -38,13 +38,15 @@ diff -ru src/src/language/init.c b/src/language/init.c pari_init_errcatch(); cb_pari_err_recover(-1); } -@@ -821,7 +823,8 @@ +@@ -825,7 +827,10 @@ + newsize = minuu(newsize, pari_mainstack->vsize); if (newsize <= pari_mainstack->size) return; if (pari_mainstack_setsize(pari_mainstack, newsize)) - { - pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size); ++ { + if (DEBUGMEM > 0) + pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size); - } - } - ++ } + else + { + pari_mainstack_setsize(pari_mainstack, size); diff --git a/build/pkgs/pari/spkg-install b/build/pkgs/pari/spkg-install index 2c177be4f81..823c264d7f3 100644 --- a/build/pkgs/pari/spkg-install +++ b/build/pkgs/pari/spkg-install @@ -179,13 +179,6 @@ install() exit 1 fi - # Copy anal.h - cp -f "src/language/anal.h" "$SAGE_LOCAL/include/pari/anal.h" - if [ $? -ne 0 ]; then - echo >&2 "Error copying anal.h" - exit 1 - fi - cd "$CUR" } diff --git a/build/pkgs/python2/checksums.ini b/build/pkgs/python2/checksums.ini index bbdd7d43c6b..44d5f9f5f40 100644 --- a/build/pkgs/python2/checksums.ini +++ b/build/pkgs/python2/checksums.ini @@ -1,4 +1,4 @@ tarball=Python-VERSION.tgz -sha1=dce2b862a30099ee48c19a7c34e2d7c2eeff5670 -md5=17add4bf0ad0ec2f08e0cae6d205c700 -cksum=2666254648 +sha1=e29c3fa7865895e0f01299e0358b59bfd0462766 +md5=cee2e4b33ad3750da77b2e85f2f8b724 +cksum=937191707 diff --git a/build/pkgs/python2/package-version.txt b/build/pkgs/python2/package-version.txt index ccf883e0dde..a682fe232c8 100644 --- a/build/pkgs/python2/package-version.txt +++ b/build/pkgs/python2/package-version.txt @@ -1 +1 @@ -2.7.13.p1 +2.7.14.p0 diff --git a/build/pkgs/rst2ipynb/checksums.ini b/build/pkgs/rst2ipynb/checksums.ini index f59f4b55950..a9b05c6a268 100644 --- a/build/pkgs/rst2ipynb/checksums.ini +++ b/build/pkgs/rst2ipynb/checksums.ini @@ -1,4 +1,4 @@ tarball=rst2ipynb-VERSION.tar.gz -sha1=660df59d66a052a9337517ed55e018307d3549ce -md5=8d85aa294c25ccaf3bb080bc6eb50e59 -cksum=1127236178 +sha1=3c90b88061b436c54da5f960fa191892dfef709f +md5=100596c9eed3e22483e86061a88722db +cksum=4025690464 diff --git a/build/pkgs/rst2ipynb/package-version.txt b/build/pkgs/rst2ipynb/package-version.txt index 0c62199f16a..e31ae824d82 100644 --- a/build/pkgs/rst2ipynb/package-version.txt +++ b/build/pkgs/rst2ipynb/package-version.txt @@ -1 +1 @@ -0.2.1 +0.2.2.p0 diff --git a/build/pkgs/rst2ipynb/patches/check-pandoc.patch b/build/pkgs/rst2ipynb/patches/check-pandoc.patch new file mode 100644 index 00000000000..72e0b7bb5e1 --- /dev/null +++ b/build/pkgs/rst2ipynb/patches/check-pandoc.patch @@ -0,0 +1,58 @@ +See https://github.com/nthiery/rst-to-ipynb/pull/4 + +commit 08fbca3f57607f49bd40e9254106aecc1ac0dbe7 +Author: Jeroen Demeyer +Date: Mon Oct 9 12:38:19 2017 +0200 + + Check pandoc dependency + +diff --git a/setup.py b/setup.py +index e2e2ed3..5afaa33 100644 +--- a/setup.py ++++ b/setup.py +@@ -4,17 +4,35 @@ reST to Jupyter notebook converter + """ + + # Always prefer setuptools over distutils +-from setuptools import setup, find_packages ++from setuptools import setup ++from setuptools.command.install import install ++from distutils.errors import DistutilsExecError + # To use a consistent encoding + from codecs import open +-from os import path ++import os + +-here = path.abspath(path.dirname(__file__)) ++ ++here = os.path.dirname(__file__) + + # Get the long description from the README file +-with open(path.join(here, 'README.rst'), encoding='utf-8') as f: ++with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + ++ ++class check_install(install): ++ "Check that pandoc is installed on the system" ++ def run(self): ++ import subprocess ++ try: ++ # Hide stdout but allow stderr ++ subprocess.check_call(["pandoc", "-v"], stdout=open(os.devnull)) ++ except subprocess.CalledProcessError: ++ raise DistutilsExecError("rst2ipynb requires the Haskell program 'pandoc'. It seems to be installed, but it did not work properly.") ++ except OSError: ++ raise DistutilsExecError("rst2ipynb requires the Haskell program 'pandoc'. You need to install it on your system.") ++ install.run(self) ++ ++ + setup( + name='rst2ipynb', + version='0.2.2', +@@ -35,4 +53,5 @@ setup( + install_requires=['notedown', 'pandocfilters'], + #setup_requires=['pytest-runner'], + #tests_require=['pytest'], ++ cmdclass=dict(install=check_install) + ) diff --git a/build/sage_bootstrap/uncompress/action.py b/build/sage_bootstrap/uncompress/action.py index fef21579b33..bc265edafa6 100644 --- a/build/sage_bootstrap/uncompress/action.py +++ b/build/sage_bootstrap/uncompress/action.py @@ -15,11 +15,11 @@ import os -from sage_bootstrap.uncompress.tar_file import SageTarFile +from sage_bootstrap.uncompress.tar_file import SageTarFile, SageTarXZFile from sage_bootstrap.uncompress.zip_file import SageZipFile from sage_bootstrap.util import retry -ARCHIVE_TYPES = [SageTarFile, SageZipFile] +ARCHIVE_TYPES = [SageTarFile, SageZipFile, SageTarXZFile] diff --git a/build/sage_bootstrap/uncompress/tar_file.py b/build/sage_bootstrap/uncompress/tar_file.py index b13a03f4936..e4fc6eb1b22 100644 --- a/build/sage_bootstrap/uncompress/tar_file.py +++ b/build/sage_bootstrap/uncompress/tar_file.py @@ -18,11 +18,13 @@ import copy import tarfile import stat +import subprocess +from io import BytesIO from sage_bootstrap.uncompress.filter_os_files import filter_os_files -class SageTarFile(tarfile.TarFile): +class SageBaseTarFile(tarfile.TarFile): """ Sage as tarfile.TarFile, but applies the user's current umask to the permissions of all extracted files and directories. @@ -31,29 +33,13 @@ class SageTarFile(tarfile.TarFile): See http://trac.sagemath.org/ticket/20218#comment:16 for more background. """ - - def __new__(cls, *args, **kwargs): - # This is is that SageTarFile() is equivalent to TarFile.open() which - # is more flexible than the basic TarFile.__init__ - inst = tarfile.TarFile.open(*args, **kwargs) - inst.__class__ = cls - return inst - def __init__(self, *args, **kwargs): # Unfortunately the only way to get the current umask is to set it # and then restore it + super(SageBaseTarFile, self).__init__(*args, **kwargs) self.umask = os.umask(0o777) os.umask(self.umask) - @classmethod - def can_read(cls, filename): - """ - Given an archive filename, returns True if this class can read and - process the archive format of that file. - """ - - return tarfile.is_tarfile(filename) - @property def names(self): """ @@ -69,7 +55,7 @@ def chmod(self, tarinfo, target): tarinfo = copy.copy(tarinfo) tarinfo.mode &= ~self.umask tarinfo.mode &= ~(stat.S_ISUID | stat.S_ISGID) - return super(SageTarFile, self).chmod(tarinfo, target) + return super(SageBaseTarFile, self).chmod(tarinfo, target) def extractall(self, path='.', members=None): """ @@ -81,7 +67,7 @@ def extractall(self, path='.', members=None): members = [m if isinstance(m, tarfile.TarInfo) else name_to_member[m] for m in members] - return super(SageTarFile, self).extractall(path=path, members=members) + return super(SageBaseTarFile, self).extractall(path=path, members=members) def extractbytes(self, member): """ @@ -95,3 +81,43 @@ def extractbytes(self, member): return reader.read() +class SageTarFile(SageBaseTarFile): + """ + A wrapper around SageBaseTarFile such that SageTarFile(filename) is + essentially equivalent to TarFile.open(filename) which is more + flexible than the basic TarFile.__init__ + """ + def __new__(cls, filename): + return SageBaseTarFile.open(filename) + + @staticmethod + def can_read(filename): + """ + Given an archive filename, returns True if this class can read and + process the archive format of that file. + """ + return tarfile.is_tarfile(filename) + + +class SageTarXZFile(SageBaseTarFile): + """ + A ``.tar.xz`` file which is uncompressed in memory. + """ + def __new__(cls, filename): + # Read uncompressed data through a pipe + proc = subprocess.Popen(["xz", "-d", "-c", filename], stdout=subprocess.PIPE) + data, _ = proc.communicate() + return SageBaseTarFile(mode="r", fileobj=BytesIO(data)) + + @staticmethod + def can_read(filename): + """ + Given an archive filename, returns True if this class can read and + process the archive format of that file. + """ + devnull = open(os.devnull, 'w') + try: + subprocess.check_call(["xz", "-l", filename], stdout=devnull, stderr=devnull) + except Exception: + return False + return True diff --git a/src/bin/sage-banner b/src/bin/sage-banner index d0195817910..95e8263b802 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath version 8.1.beta7, Release Date: 2017-10-03 │ +│ SageMath version 8.1.beta8, Release Date: 2017-10-16 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ diff --git a/src/bin/sage-location b/src/bin/sage-location index caeb9a6cf63..306cb33fdbf 100755 --- a/src/bin/sage-location +++ b/src/bin/sage-location @@ -62,23 +62,6 @@ SINGULAR %s f.close() -def remove_files(path, remove_extensions): - """ - Walk the tree starting at ``path``, and remove all files with - extensions in ``remove_extensions``. - The extensions in ``remove_extensions`` should start with a period, i.e., - e.g. use ``remove_files(path, ('.pyc', '.pyo'))``. - """ - for root, dirs, files in os.walk(path): - for file in files: - filename = os.path.join(root, file) - if os.path.splitext(filename)[1] in remove_extensions: - try: - os.unlink(filename) - except OSError as msg: - print(msg) - - def sage_relocate(): """ High-level function which calls various functions to handle @@ -90,10 +73,6 @@ def sage_relocate(): """ write_config_files() - # Compiled python files need to be regenerated, so we remove them: - for dir in glob.glob(os.path.join(SAGE_LOCAL, 'lib', 'python*')): - remove_files(dir, remove_extensions=('.pyc', '.pyo')) - # Write the new location file as last thing in this script, # so that it only gets written if there were no exceptions. write_location_file() diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 09b8aa24be9..405c3f637d4 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -106,11 +106,19 @@ if __name__ == "__main__": import resource lim, hard = resource.getrlimit(resource.RLIMIT_AS) if lim == resource.RLIM_INFINITY or lim > memlimit: - resource.setrlimit(resource.RLIMIT_AS, (memlimit, hard)) - - # Limit the number of OMP threads to 2 to save system resources - # See Trac #23892 + try: + resource.setrlimit(resource.RLIMIT_AS, (memlimit, hard)) + except ValueError: + if sys.platform != 'cygwin': + # RLIMIT_AS is not currently supported on Cygwin so + # this will probably fail there: + # https://trac.sagemath.org/ticket/23979 + raise + + # Limit the number of threads to 2 to save system resources. + # See Trac #23713 and #23892 os.environ["OMP_NUM_THREADS"] = "2" + os.environ["SAGE_NUM_THREADS"] = "2" from sage.doctest.control import DocTestController DC = DocTestController(options, args) diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 4efafd3f623..9bcde786eb3 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,4 +1,4 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='8.1.beta7' -SAGE_RELEASE_DATE='2017-10-03' +SAGE_VERSION='8.1.beta8' +SAGE_RELEASE_DATE='2017-10-16' diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index fb0a2b7e46e..204c3ccfc76 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -20,6 +20,18 @@ Groups sage/groups/raag sage/groups/group_exp sage/groups/group_semidirect_product + sage/groups/misc_gps/misc_groups + sage/groups/semimonomial_transformations/semimonomial_transformation_group + sage/groups/semimonomial_transformations/semimonomial_transformation + sage/groups/class_function + sage/groups/conjugacy_classes + +Abelian Groups +-------------- + +.. toctree:: + :maxdepth: 2 + sage/groups/abelian_gps/abelian_group sage/groups/abelian_gps/values sage/groups/abelian_gps/dual_abelian_group @@ -29,6 +41,13 @@ Groups sage/groups/abelian_gps/abelian_group_morphism sage/groups/additive_abelian/additive_abelian_group sage/groups/additive_abelian/additive_abelian_wrapper + +Permutation Groups +------------------ + +.. toctree:: + :maxdepth: 2 + sage/groups/perm_gps/permutation_groups_catalog sage/groups/perm_gps/permgroup sage/groups/perm_gps/permgroup_named @@ -36,6 +55,13 @@ Groups sage/groups/perm_gps/permgroup_morphism sage/groups/perm_gps/cubegroup sage/groups/perm_gps/symgp_conjugacy_class + +Matrix and Affine Groups +------------------------ + +.. toctree:: + :maxdepth: 2 + sage/groups/matrix_gps/catalog sage/groups/matrix_gps/matrix_group sage/groups/matrix_gps/group_element @@ -52,13 +78,17 @@ Groups sage/groups/affine_gps/affine_group sage/groups/affine_gps/euclidean_group sage/groups/affine_gps/group_element - sage/groups/misc_gps/misc_groups - sage/groups/semimonomial_transformations/semimonomial_transformation_group - sage/groups/semimonomial_transformations/semimonomial_transformation - sage/groups/class_function - sage/groups/conjugacy_classes - sage/groups/perm_gps/partn_ref - sage/groups/perm_gps/partn_ref2 + +Partition Refinement +-------------------- + +.. toctree:: + :maxdepth: 2 + + sage/groups/perm_gps/partn_ref/canonical_augmentation + sage/groups/perm_gps/partn_ref/data_structures + sage/groups/perm_gps/partn_ref/refinement_lists + sage/groups/perm_gps/partn_ref/refinement_matrices Internals --------- diff --git a/src/doc/en/reference/manifolds/diff_manifold.rst b/src/doc/en/reference/manifolds/diff_manifold.rst index f064e855782..f358d30d6b8 100644 --- a/src/doc/en/reference/manifolds/diff_manifold.rst +++ b/src/doc/en/reference/manifolds/diff_manifold.rst @@ -22,4 +22,6 @@ Differentiable Manifolds diff_form + multivector + sage/manifolds/differentiable/affine_connection diff --git a/src/doc/en/reference/manifolds/multivector.rst b/src/doc/en/reference/manifolds/multivector.rst new file mode 100644 index 00000000000..fe2c90815cb --- /dev/null +++ b/src/doc/en/reference/manifolds/multivector.rst @@ -0,0 +1,9 @@ +Alternating Multivector Fields +============================== + +.. toctree:: + :maxdepth: 2 + + sage/manifolds/differentiable/multivector_module + + sage/manifolds/differentiable/multivectorfield diff --git a/src/doc/en/reference/modmisc/index.rst b/src/doc/en/reference/modmisc/index.rst index 574e5796bcb..5158bd3248f 100644 --- a/src/doc/en/reference/modmisc/index.rst +++ b/src/doc/en/reference/modmisc/index.rst @@ -23,5 +23,6 @@ Miscellaneous Modular-Form-Related Modules sage/modular/cusps_nf + sage/modular/hypergeometric_motive .. include:: ../footer.txt diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 7e7e491c683..ab4fa99e785 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -248,6 +248,10 @@ REFERENCES: and Applications - FQ9, volume 518 of Contemporary Mathematics, pages 33–42. AMS, 2010. +.. [BeCoMe] Frits Beukers, Henri Cohen, Anton Mellit, + *Finite hypergeometric functions*, + :arxiv:`1505.02900` + .. [Bee] Robert A. Beezer, *A First Course in Linear Algebra*, http://linear.ups.edu/. Accessed 15 July 2010. @@ -255,6 +259,9 @@ REFERENCES: *Information technologies. Data protection. Cryptograpic algorithms for encryption and integrity control*; in STB 34.101.31-2011, (2011). +.. [Benasque2009] Fernando Rodriguez Villegas, *The L-function of the quintic*, + http://users.ictp.it/~villegas/hgm/benasque-2009-report.pdf + .. [Ber2008] \W. Bertram : *Differential Geometry, Lie Groups and Symmetric Spaces over General Base Fields and Rings*, Memoirs of the American Mathematical Society, vol. 192 @@ -263,6 +270,10 @@ REFERENCES: .. [Ber1991] \C. Berger, "Une version effective du théorème de Hurewicz", https://tel.archives-ouvertes.fr/tel-00339314/en/. +.. [BeukersHeckman] \F. Beukers and \G. Heckman, + *Monodromy for the hypergeometric function `{}_n F_{n-1}`*, + Invent. Math. 95 (1989) + .. [BF1999] Thomas Britz, Sergey Fomin, *Finite posets and Ferrers shapes*, Advances in Mathematics 158, pp. 86-127 (2001), @@ -272,6 +283,9 @@ REFERENCES: algebras. III. Upper bounds and double Bruhat cells*, Duke Math. J. 126 (2005), no. 1, 1–52. +.. [BG1980] \R. L. Bishop and S. L. Goldberg, *Tensor analysis on + Manifolds*, Dover (New York) (1980) + .. [BG1985] \M. Blum and S. Goldwasser. An Efficient Probabilistic Public-Key Encryption Scheme Which Hides All Partial Information. In *Proceedings of CRYPTO 84 on Advances in @@ -849,6 +863,10 @@ REFERENCES: **F** +.. [Fedorov2015] Roman Fedorov, *Variations of Hodge structures for hypergeometric + differential operators and parabolic Higgs bundles*, + :arxiv:`1505.01704` + .. [Fe1997] Stefan Felsner, "On the Number of Arrangements of Pseudolines", Proceedings SoCG 96, 30-37. Discrete & Computational Geometry 18 (1997), @@ -917,6 +935,11 @@ REFERENCES: *Quantization of Lie Groups and Lie Algebras*. Leningrad Math. J. vol. **1** (1990), no. 1. +.. [FS2009] Philippe Flajolet and Robert Sedgewick, + `Analytic combinatorics `_. + Cambridge University Press, Cambridge, 2009. + See also the `Errata list `_. + .. [FST2012] \A. Felikson, \M. Shapiro, and \P. Tumarkin, *Cluster Algebras of Finite Mutation Type Via Unfoldings*, Int Math Res Notices (2012) 2012 (8): 1768-1804. @@ -1256,6 +1279,9 @@ REFERENCES: .. [Kan1958] \D. M. Kan, *A combinatorial definition of homotopy groups*, Ann. Math. (2) 67 (1958), 282-312. +.. [Kat1991] Nicholas M. Katz, *Exponential sums and differential equations*, + Princeton University Press, Princeton NJ, 1991. + .. [Kaw2009] Kawahira, Tomoki. *An algorithm to draw external rays of the Mandelbrot set*, Nagoya University, 23 Apr. 2009. math.titech.ac.jp/~kawahira/programs/mandel-exray.pdf @@ -1347,11 +1373,15 @@ REFERENCES: 1998), Advanced Studies in Pure Mathematics, 30, 177-196, 2000. -.. [Koh2007] \A. Kohnert, Constructing two-weight codes with prescribed - groups of automorphisms, Discrete applied mathematics 155, +.. [Koh2007] \A. Kohnert, *Constructing two-weight codes with prescribed + groups of automorphisms*, Discrete applied mathematics 155, no. 11 (2007): 1451-1457. http://linearcodes.uni-bayreuth.de/twoweight/ +.. [Kos1985] \J.-L. Koszul, *Crochet de Schouten-Nijenhuis et + cohomologie*, in *Élie Cartan et les mathématiques + d'aujourd'hui*, Astérisque hors série (1985), p. 257 + .. [KP2002] Volker Kaibel and Marc E. Pfetsch, "Computing the Face Lattice of a Polytope from its Vertex-Facet Incidences", Computational Geometry: Theory and Applications, Volume @@ -1473,6 +1503,10 @@ REFERENCES: .. [Li1995] Peter Littelmann, Crystal graphs and Young tableaux, J. Algebra 175 (1995), no. 1, 65--87. +.. [Lic1977] \A. Lichnerowicz, *Les variétés de Poisson et leurs + algèbres de Lie associées*, Journal of Differential + Geometry **12**, 253 (1977); :doi:`10.4310/jdg/1214433987` + .. [Lic1997] William B. Raymond Lickorish. An Introduction to Knot Theory, volume 175 of Graduate Texts in Mathematics. Springer-Verlag, New York, 1997. ISBN @@ -1485,8 +1519,7 @@ REFERENCES: .. [Lim2001] \C. H. Lim, *A Revised Version of CRYPTON: CRYPTON V1.0*; in FSE'01, pp. 31--45. - -.. [Lin1999] J. van Lint, Introduction to coding theory, 3rd ed., +.. [Lin1999] \J. van Lint, Introduction to coding theory, 3rd ed., Springer-Verlag GTM, 86, 1999. .. [Liv2006] \M. Livernet, *A rigidity theorem for pre-Lie algebras*, J. Pure Appl. @@ -1587,6 +1620,9 @@ REFERENCES: **M** +.. [MagmaHGM] *Hypergeometric motives* in Magma, + http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + .. [Mas94] James L. Massey, *SAFER K-64: A byte-oriented block-ciphering algorithm*; in FSE’93, Volume 809 of LNCS, pages 1-17. @@ -1609,6 +1645,10 @@ REFERENCES: Notes in Computer Science, volume 5856, pp 272-278, Springer, Berlin (2009). +.. [Mar1997] \C.-M. Marle, *The Schouten-Nijenhuis bracket and interior + products*, Journal of Geometry and Physics **23**, 350 + (1997); :doi:`10.1016/S0393-0440(97)80009-5` + .. [Mas1969] James L. Massey, "Shift-Register Synthesis and BCH Decoding." IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127, Jan 1969. @@ -1709,6 +1749,10 @@ REFERENCES: .. [Nie] Johan S. R. Nielsen, Codinglib, https://bitbucket.org/jsrn/codinglib/. +.. [Nij1955] \A. Nijenhuis, *Jacobi-type identities for bilinear + differential concomitants of certain tensor fields. I*, + Indagationes Mathematicae (Proceedings) **58**, 390 (1955). + .. [NN2007] Nisan, Noam, et al., eds. *Algorithmic game theory.* Cambridge University Press, 2007. @@ -1905,6 +1949,12 @@ REFERENCES: to differential posets". Ph.D. Thesis, M.I.T., Cambridge, Massachusetts, 1991. +.. [Roberts2015] David P. Roberts, *Hypergeometric Motives I*, https://icerm.brown.edu/materials/Slides/sp-f15-offweeks/Hypergeomteric_Motives,_I_]_David_Roberts,_University_of_Minnesota_-_Morris.pdf + +.. [Roberts2017] David P. Roberts, *Hypergeometric motives and an unusual + application of the Guinand-Weil-Mestre explicit formula*, + https://www.matrix-inst.org.au/wp_Matrix2016/wp-content/uploads/2016/04/Roberts-2.pdf + .. [Roc1970] \R.T. Rockafellar, *Convex Analysis*. Princeton University Press, Princeton, 1970. @@ -2184,6 +2234,10 @@ REFERENCES: **V** +.. [Vai1994] \I. Vaisman, *Lectures on the Geometry of Poisson + Manifolds*, Springer Basel AG (Basel) (1994); + :doi:`10.1007/978-3-0348-8495-2` + .. [Vat2008] \D. Vatne, *The mutation class of `D_n` quivers*, :arxiv:`0810.4789v1`. .. [VB1996] \E. Viterbo, E. Biglieri. *Computing the Voronoi Cell of a @@ -2241,6 +2295,10 @@ REFERENCES: .. [Was1997] \L. C. Washington, *Cyclotomic Fields*, Springer-Verlag, GTM volume 83, 1997. +.. [Watkins] Mark Watkins, + *Hypergeometric motives over Q and their L-functions*, + http://magma.maths.usyd.edu.au/~watkins/papers/known.pdf + .. [Wat2003] Joel Watson. *Strategy: an introduction to game theory*. WW Norton, 2002. diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 3b124e8d744..09b78706963 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -1552,6 +1552,7 @@ Here are the tests that form the test suite of quotient fields:: '_test_elements_eq_transitive', '_test_elements_neq', '_test_euclidean_degree', + '_test_fraction_field', '_test_gcd_vs_xgcd', '_test_one', '_test_prod', '_test_quo_rem', @@ -1606,6 +1607,7 @@ Let us see what tests are actually performed:: running ._test_elements_neq() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass @@ -1778,6 +1780,7 @@ interesting. running ._test_elements_neq() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass diff --git a/src/sage/categories/commutative_additive_groups.py b/src/sage/categories/commutative_additive_groups.py index cfeddc64b93..c1383022833 100644 --- a/src/sage/categories/commutative_additive_groups.py +++ b/src/sage/categories/commutative_additive_groups.py @@ -95,4 +95,3 @@ def additive_order(self): class Algebras(AlgebrasCategory): pass - diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index fc07327923c..a7a44bb6537 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -236,14 +236,14 @@ def Hom(X, Y, category=None, check=True): sage: U1 = FreeModule(ZZ,2) sage: U2 = FreeModule(ZZ,2,inner_product_matrix=matrix([[1,0],[0,-1]])) sage: U1 == U2, U1 is U2 - (True, False) + (False, False) sage: V = ZZ^3 sage: H1 = Hom(U1, V); H2 = Hom(U2, V) sage: H1 == H2, H1 is H2 - (True, False) + (False, False) sage: H1 = Hom(V, U1); H2 = Hom(V, U2) sage: H1 == H2, H1 is H2 - (True, False) + (False, False) Since :trac:`11900`, the meet of the categories of the given arguments is used to determine the default category of the homset. This can also be a @@ -508,6 +508,7 @@ def end(X, f): """ return End(X)(f) + class Homset(Set_generic): """ The class for collections of morphisms in a category. @@ -708,74 +709,6 @@ def __bool__(self): __nonzero__ = __bool__ - def _generic_convert_map(self, S, category=None): - """ - Return a generic map from a given homset to ``self``. - - INPUT: - - - ``S`` -- a homset - - - ``category`` -- a category - - OUTPUT: - - A map (by default: a Call morphism) from ``S`` to ``self``. - - EXAMPLES: - - By :trac:`14711`, conversion and coerce maps should be copied - before using them outside of the coercion system:: - - sage: H = Hom(ZZ,QQ['t'], CommutativeAdditiveGroups()) - sage: P. = ZZ[] - sage: f = P.hom([2*t]) - sage: phi = H._generic_convert_map(f.parent()); phi - Call morphism: - From: Set of Homomorphisms from Univariate Polynomial Ring in t over Integer Ring to Univariate Polynomial Ring in t over Integer Ring - To: Set of Morphisms from Integer Ring to Univariate Polynomial Ring in t over Rational Field in Category of commutative additive groups - sage: H._generic_convert_map(f.parent())(f) - Composite map: - From: Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - Defn: (map internal to coercion system -- copy before use) - Polynomial base injection morphism: - From: Integer Ring - To: Univariate Polynomial Ring in t over Integer Ring - then - Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring - Defn: t |--> 2*t - then - (map internal to coercion system -- copy before use) - Ring morphism: - From: Univariate Polynomial Ring in t over Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - sage: copy(H._generic_convert_map(f.parent())(f)) - Composite map: - From: Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - Defn: Polynomial base injection morphism: - From: Integer Ring - To: Univariate Polynomial Ring in t over Integer Ring - then - Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring - Defn: t |--> 2*t - then - Ring morphism: - From: Univariate Polynomial Ring in t over Integer Ring - To: Univariate Polynomial Ring in t over Rational Field - Defn: Induced from base ring by - Natural morphism: - From: Integer Ring - To: Rational Field - """ - if self._element_constructor is None: - from sage.categories.morphism import CallMorphism - from sage.categories.homset import Hom - return CallMorphism(Hom(S, self)) - else: - return Parent._generic_convert_map(self, S, category) - def homset_category(self): """ Return the category that this is a Hom in, i.e., this is typically @@ -789,7 +722,7 @@ def homset_category(self): """ return self.__category - def __call__(self, x=None, y=None, check=True, **options): + def _element_constructor_(self, x, check=None, **options): r""" Construct a morphism in this homset from ``x`` if possible. @@ -827,8 +760,8 @@ def __call__(self, x=None, y=None, check=True, **options): From: Symmetric group of order 6! as a permutation group To: Symmetric group of order 7! as a permutation group - Also note that making a copy of the resulting map will automatically - make strengthened copies of the composed maps:: + Also note that making a copy of the resulting map will automatically + make strengthened copies of the composed maps:: sage: copy(H(phi)) Composite map: @@ -869,6 +802,70 @@ def __call__(self, x=None, y=None, check=True, **options): sage: f(1), f(2), f(3) (2/3, 2/3, 2/3) + By :trac:`14711`, conversion and coerce maps should be copied + before using them outside of the coercion system:: + + sage: H = Hom(ZZ,QQ['t'], CommutativeAdditiveGroups()) + sage: P. = ZZ[] + sage: f = P.hom([2*t]) + sage: phi = H._generic_convert_map(f.parent()); phi + Conversion map: + From: Set of Homomorphisms from Univariate Polynomial Ring in t over Integer Ring to Univariate Polynomial Ring in t over Integer Ring + To: Set of Morphisms from Integer Ring to Univariate Polynomial Ring in t over Rational Field in Category of commutative additive groups + sage: H._generic_convert_map(f.parent())(f) + Composite map: + From: Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + Defn: (map internal to coercion system -- copy before use) + Polynomial base injection morphism: + From: Integer Ring + To: Univariate Polynomial Ring in t over Integer Ring + then + Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring + Defn: t |--> 2*t + then + (map internal to coercion system -- copy before use) + Ring morphism: + From: Univariate Polynomial Ring in t over Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + sage: copy(H._generic_convert_map(f.parent())(f)) + Composite map: + From: Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + Defn: Polynomial base injection morphism: + From: Integer Ring + To: Univariate Polynomial Ring in t over Integer Ring + then + Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring + Defn: t |--> 2*t + then + Ring morphism: + From: Univariate Polynomial Ring in t over Integer Ring + To: Univariate Polynomial Ring in t over Rational Field + Defn: Induced from base ring by + Natural morphism: + From: Integer Ring + To: Rational Field + + TESTS:: + + sage: G. = FreeGroup() + sage: H = Hom(G, G) + sage: H(H.identity()) + Identity endomorphism of Free Group on generators {x, y, z} + sage: H() + Traceback (most recent call last): + ... + TypeError: unable to convert 0 to an element of Set of Morphisms from Free Group on generators {x, y, z} to Free Group on generators {x, y, z} in Category of groups + sage: H("whatever") + Traceback (most recent call last): + ... + TypeError: unable to convert 'whatever' to an element of Set of Morphisms from Free Group on generators {x, y, z} to Free Group on generators {x, y, z} in Category of groups + sage: H(H.identity(), foo="bar") + Traceback (most recent call last): + ... + NotImplementedError: no keywords are implemented for constructing elements of Set of Morphisms from Free Group on generators {x, y, z} to Free Group on generators {x, y, z} in Category of groups + AUTHORS: - Robert Bradshaw, with changes by Nicolas M. Thiery @@ -877,36 +874,30 @@ def __call__(self, x=None, y=None, check=True, **options): # TODO: this is specific for ModulesWithBasis; generalize # this to allow homsets and categories to provide more # morphism constructors (on_algebra_generators, ...) - if 'on_basis' or 'diagonal' in options: - return self.__call_on_basis__(category = self.homset_category(), - **options) - else: - raise NotImplementedError + try: + call_with_keywords = self.__call_on_basis__ + except AttributeError: + raise NotImplementedError("no keywords are implemented for constructing elements of {}".format(self)) + options.setdefault("category", self.homset_category()) + return call_with_keywords(**options) - assert x is not None if isinstance(x, morphism.Morphism): - if x.parent() is self: - return x - elif x.parent() == self: - x._set_parent(self) # needed due to non-uniqueness of homsets - return x - else: - if x.domain() != self.domain(): - mor = x.domain()._internal_coerce_map_from(self.domain()) - if mor is None: - raise TypeError("Incompatible domains: x (=%s) cannot be an element of %s"%(x,self)) - x = x * mor - if x.codomain() != self.codomain(): - mor = self.codomain()._internal_coerce_map_from(x.codomain()) - if mor is None: - raise TypeError("Incompatible codomains: x (=%s) cannot be an element of %s"%(x,self)) - x = mor * x - return x - - if isinstance(x, (types.FunctionType, types.MethodType, ConstantFunction)): + if x.domain() != self.domain(): + mor = x.domain()._internal_coerce_map_from(self.domain()) + if mor is None: + raise TypeError("Incompatible domains: x (=%s) cannot be an element of %s"%(x,self)) + x = x * mor + if x.codomain() != self.codomain(): + mor = self.codomain()._internal_coerce_map_from(x.codomain()) + if mor is None: + raise TypeError("Incompatible codomains: x (=%s) cannot be an element of %s"%(x,self)) + x = mor * x + return x + + if callable(x): return self.element_class_set_morphism(self, x) - raise TypeError("Unable to coerce x (=%s) to a morphism in %s"%(x,self)) + raise TypeError("unable to convert {!r} to an element of {}".format(x, self)) @lazy_attribute def _abstract_element_class(self): diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 2587f37b221..3ecf218e21b 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -107,5 +107,31 @@ def is_integral_domain(self): """ return True + def _test_fraction_field(self, **options): + r""" + Test that the fraction field, if it is implemented, works + correctly. + + EXAMPLES:: + + sage: ZZ._test_fraction_field() + + """ + tester = self._tester(**options) + try: + fraction_field = self.fraction_field() + except Exception: + # some integral domains do not implement fraction_field() yet + if self in Fields(): + raise + return + + for x in tester.some_elements(): + # check that we can coerce into the fraction field + y = fraction_field.coerce(x) + # and convert back from it + z = self(x) + tester.assertEqual(x, z) + class ElementMethods: pass diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 8d2476ca03f..2e27f9fe2d7 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1887,7 +1887,7 @@ def _apply_functor_to_morphism(self, f): def __eq__(self, other): """ - Only the rank of the to-be-created modules is compared, *not* the inner product matrix. + The rank and the inner product matrix are compared. TESTS:: @@ -1895,16 +1895,14 @@ def __eq__(self, other): sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) sage: F2 = (ZZ^3).construction()[0] sage: F1 == F2 - True + False sage: F1(QQ) == F2(QQ) - True - sage: F1(QQ).inner_product_matrix() == F2(QQ).inner_product_matrix() False sage: F1 == loads(dumps(F1)) True """ if isinstance(other, VectorFunctor): - return self.n == other.n + return (self.n == other.n and self.inner_product_matrix==other.inner_product_matrix) return False def __ne__(self, other): @@ -1917,9 +1915,9 @@ def __ne__(self, other): sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) sage: F2 = (ZZ^3).construction()[0] sage: F1 != F2 - False + True sage: F1(QQ) != F2(QQ) - False + True sage: F1 != loads(dumps(F1)) False """ @@ -1927,7 +1925,7 @@ def __ne__(self, other): def merge(self, other): """ - Two constructors of free modules merge, if the module ranks coincide. If both + Two constructors of free modules merge, if the module ranks and the inner products coincide. If both have explicitly given inner product matrices, they must coincide as well. EXAMPLES: @@ -1976,7 +1974,7 @@ def merge(self, other): [6 7 8]' """ - if self != other: + if not isinstance(other, VectorFunctor): return None if self.inner_product_matrix is None: return VectorFunctor(self.n, self.is_sparse and other.is_sparse, other.inner_product_matrix) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index b8a8525bea4..ba0f70d1a8f 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -128,6 +128,12 @@ def is_injective(self): sage: f.is_injective() True + A coercion to the fraction field is injective:: + + sage: R = ZpFM(3) + sage: R.fraction_field().coerce_map_from(R).is_injective() + True + """ if self.domain().is_zero(): return True @@ -155,6 +161,15 @@ def is_injective(self): if self.domain().fraction_field() in NumberFields(): return True + if self._is_coercion: + try: + K = self.domain().fraction_field() + except (TypeError, AttributeError, ValueError): + pass + else: + if K is self.codomain(): + return True + if self.domain().cardinality() > self.codomain().cardinality(): return False diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 208d00051c8..9c2841d505a 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -695,6 +695,10 @@ def conjugate(self): the growth diagram with the filling reflected over the main diagonal. + The sequence of labels along the boundary on the side of the + origin is the reversal of the corresponding sequence of the + original growth diagram. + When the filling is a permutation, the conjugate filling corresponds to its inverse. @@ -705,14 +709,33 @@ def conjugate(self): sage: Gc = G.conjugate() sage: (Gc.P_symbol(), Gc.Q_symbol()) == (G.Q_symbol(), G.P_symbol()) True + + TESTS: + + Check that labels and shape are handled correctly:: + + sage: o = [[2,1],[2,2],[3,2],[4,2],[4,1],[4,1,1],[3,1,1],[3,1],[3,2],[3,1],[2,1]] + sage: l = [o[i//2] if is_even(i) else min(o[(i-1)//2],o[(i+1)//2]) + ....: for i in range(2*len(o)-1)] + sage: la = list(range(len(o)-2, 0, -1)) + sage: G = RuleRSK(labels=l[1:-1], shape=la) + sage: G.out_labels() == G.conjugate().out_labels()[::-1] + True """ F = {(j,i): v for (i,j),v in self._filling.items()} - return GrowthDiagram(self.rule, filling=F) + return GrowthDiagram(self.rule, + filling=F, + shape=self.shape().conjugate(), + labels=self.in_labels()[::-1]) def rotate(self): r""" Return the growth diagram with the filling rotated by 180 degrees. + The rotated growth diagram is initialized with + ``labels=None``, that is, all labels along the boundary on + the side of the origin are set to ``rule.zero``. + For RSK-growth diagrams and rectangular fillings, this corresponds to evacuation of the `P`- and the `Q`-symbol. @@ -729,11 +752,35 @@ def rotate(self): ....: for t in [G.P_symbol(), G.Q_symbol()]]) [ 1 1 1 1 1 2 ] [ 2 , 3 ] + + TESTS: + + Check that shape is handled correctly:: + + sage: RuleRSK = GrowthDiagram.rules.RSK() + sage: G = GrowthDiagram(RuleRSK, + ....: filling={(0,2):1, (3,1):2, (2,1):3}, + ....: shape=SkewPartition([[5,5,5,3],[3,1]])) + sage: G + . . . 0 0 + . 0 3 2 0 + 1 0 0 0 0 + 0 0 0 + sage: G.rotate() + . . 0 0 0 + 0 0 0 0 1 + 0 2 3 0 + 0 0 """ - max_row = max(i for i, _ in self._filling) - max_col = max(j for _, j in self._filling) - F = {(max_row-i,max_col-j): v for (i,j),v in self._filling.items()} - return GrowthDiagram(self.rule, filling=F) + l = self._lambda[0] + h = len(self._lambda) + shape_lambda = [l-p for p in self._mu] + [l]*(h-len(self._mu)) + shape_mu = [l-p for p in self._lambda] + shape = SkewPartition([shape_lambda[::-1], shape_mu[::-1]]) + F = {(l-i-1, h-j-1): v for (i,j),v in self._filling.items()} + return GrowthDiagram(self.rule, + filling=F, + shape=shape) def half_perimeter(self): r""" diff --git a/src/sage/combinat/integer_matrices.py b/src/sage/combinat/integer_matrices.py index 1467d50ebcb..88287488fed 100644 --- a/src/sage/combinat/integer_matrices.py +++ b/src/sage/combinat/integer_matrices.py @@ -321,18 +321,18 @@ def integer_matrices_generator(row_sums, column_sums): [[0, 3], [2, 0], [0, 2]] [[0, 3], [1, 1], [1, 1]] [[0, 3], [0, 2], [2, 0]] - """ - row_sums = list(row_sums) column_sums = list(column_sums) if sum(row_sums) != sum(column_sums): raise StopIteration - if len(row_sums) == 0: + if not row_sums: yield [] elif len(row_sums) == 1: yield [column_sums] else: - for comp in IntegerListsLex(n=row_sums[0], length=len(column_sums), ceiling=column_sums): + I = IntegerListsLex(n=row_sums[0], length=len(column_sums), ceiling=column_sums) + for comp in I.backend._iter(): t = [column_sums[i]-ci for (i, ci) in enumerate(comp)] for mat in integer_matrices_generator(row_sums[1:], t): yield [list(comp)] + mat + diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index feb04f7e17c..3f58c11ca12 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -539,11 +539,17 @@ def __init__(self, parent, mu): CombinatorialElement.__init__(self, parent, mu._list) return - elif len(mu)==0 or (all(mu[i] in NN and mu[i]>=mu[i+1] for i in range(len(mu)-1)) \ + elif not mu: + CombinatorialElement.__init__(self, parent, mu) + + elif (all(mu[i] in NN and mu[i] >= mu[i+1] for i in range(len(mu)-1)) and mu[-1] in NN): - if 0 in mu: + if mu[-1] == 0: # From the above checks, the last value must be == 0 or > 0 # strip all trailing zeros - CombinatorialElement.__init__(self, parent, mu[:mu.index(0)]) + temp = len(mu) - 1 + while temp > 0 and mu[temp-1] == 0: + temp -= 1 + CombinatorialElement.__init__(self, parent, mu[:temp]) else: CombinatorialElement.__init__(self, parent, mu) @@ -4211,17 +4217,6 @@ def k_conjugate(self, k): """ return Partition(self.k_skew(k).conjugate().row_lengths()) -# def parent(self): -# """ -# Returns the combinatorial class of partitions of ``sum(self)``. -# -# EXAMPLES:: -# -# sage: Partition([3,2,1]).parent() -# Partitions of the integer 6 -# """ -# return Partitions(sum(self[:])) - def arms_legs_coeff(self, i, j): r""" This is a statistic on a cell `c = (i,j)` in the diagram of partition diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index fc632a1c92a..a3c849e02db 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -260,7 +260,8 @@ from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.rsk import RSK, RSK_inverse from sage.combinat.permutation_cython import (left_action_product, - right_action_product, left_action_same_n, right_action_same_n) + right_action_product, left_action_same_n, right_action_same_n, + map_to_list, next_perm) class Permutation(CombinatorialElement): r""" @@ -5419,8 +5420,7 @@ def _repr_(self): def __iter__(self): r""" - Algorithm based on: - http://marknelson.us/2002/03/01/next-permutation/ + Iterate over ``self``. EXAMPLES:: @@ -5435,50 +5435,18 @@ def __iter__(self): [[]] """ mset = self.mset - n = len(self.mset) - lmset = list(mset) - mset_list = sorted((lmset.index(x) for x in lmset)) + n = len(mset) + from array import array + mset_list = array('I', sorted(mset.index(x) for x in mset)) - yield self.element_class(self, [lmset[x] for x in mset_list]) + yield self.element_class(self, map_to_list(mset_list, mset, n), check=False) if n <= 1: return - while True: - one = n - 2 - two = n - 1 - j = n - 1 - - #starting from the end, find the first o such that - #mset_list[o] < mset_list[o+1] - while two > 0 and mset_list[one] >= mset_list[two]: - one -= 1 - two -= 1 - - if two == 0: - return - - #starting from the end, find the first j such that - #mset_list[j] > mset_list[one] - while mset_list[j] <= mset_list[one]: - j -= 1 - - #Swap positions one and j - t = mset_list[one] - mset_list[one] = mset_list[j] - mset_list[j] = t - - #Reverse the list between two and last - i = int((n - two)/2)-1 - #mset_list = mset_list[:two] + [x for x in reversed(mset_list[two:])] - while i >= 0: - t = mset_list[ i + two ] - mset_list[ i + two ] = mset_list[n-1 - i] - mset_list[n-1 - i] = t - i -= 1 - + while next_perm(mset_list): #Yield the permutation - yield self.element_class(self, [lmset[x] for x in mset_list]) + yield self.element_class(self, map_to_list(mset_list, mset, n), check=False) def cardinality(self): """ diff --git a/src/sage/combinat/permutation_cython.pxd b/src/sage/combinat/permutation_cython.pxd index acf5b074c4b..b8b503765f4 100644 --- a/src/sage/combinat/permutation_cython.pxd +++ b/src/sage/combinat/permutation_cython.pxd @@ -1,5 +1,10 @@ +from cpython cimport array +import array + cdef void reset_swap(int n, int *c, int *o) cdef int next_swap(int n, int *c, int *o) +cpdef bint next_perm(array.array l) +cpdef list map_to_list(array.array l, values, int n) cpdef list left_action_same_n(list l, list r) cpdef list right_action_same_n(list l, list r) cpdef list left_action_product(list l, list r) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index d784ec937c8..918c14b7e45 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -22,17 +22,33 @@ speed, we provide a class that wraps our struct. """ - -# Free for any use. -# Unfit for any purpose. +#***************************************************************************** +# Copyright (C) 2010 Tom Boothby +# Copyright (C) 2017 Travis Scrimshaw +# Copyright (C) 2017 Vincent Delecroix <20100.delecroix@gmail.com> # -# Copyright 2010, Tom Boothby +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + from __future__ import print_function -from cpython.list cimport * +cimport cython + +from cpython.object cimport PyObject + from cysignals.memory cimport sig_malloc, sig_free -########################################################## +cdef extern from "Python.h": + void Py_INCREF(PyObject *) + PyObject * PyInt_FromLong(long ival) + list PyList_New(Py_ssize_t size) + void PyList_SET_ITEM(list l, Py_ssize_t, PyObject *) + PyObject * PyTuple_GET_ITEM(PyObject *op, Py_ssize_t i) + +######################################################### # # The next two functions, reset_swap and next_swap do the # real work. They've been implemented separately because @@ -176,13 +192,132 @@ def permutation_iterator_transposition_list(int n): reset_swap(n,c,o) for m in range(N-1): - PyList_SET_ITEM(T, m, next_swap(n,c,o)) + PyList_SET_ITEM(T, m, PyInt_FromLong(next_swap(n,c,o))) sig_free(c) return T +##################################################################### +## iterator-type method for getting the next permutation + +@cython.wraparound(False) +@cython.boundscheck(False) +cpdef bint next_perm(array.array l): + """ + Obtain the next permutation under lex order of ``l`` + by mutating ``l``. + + Algorithm based on: + http://marknelson.us/2002/03/01/next-permutation/ + + INPUT: + + - ``l`` -- array of unsigned int (i.e., type ``'I'``) + + .. WARNING:: + + This method mutates the array ``l``. + + OUTPUT: + + boolean; whether another permutation was obtained + + EXAMPLES:: + sage: from sage.combinat.permutation_cython import next_perm + sage: from array import array + sage: L = array('I', [1, 1, 2, 3]) + sage: while next_perm(L): + ....: print(L) + array('I', [1L, 1L, 3L, 2L]) + array('I', [1L, 2L, 1L, 3L]) + array('I', [1L, 2L, 3L, 1L]) + array('I', [1L, 3L, 1L, 2L]) + array('I', [1L, 3L, 2L, 1L]) + array('I', [2L, 1L, 1L, 3L]) + array('I', [2L, 1L, 3L, 1L]) + array('I', [2L, 3L, 1L, 1L]) + array('I', [3L, 1L, 1L, 2L]) + array('I', [3L, 1L, 2L, 1L]) + array('I', [3L, 2L, 1L, 1L]) + """ + cdef Py_ssize_t n = len(l) + + if n <= 1: + return False + + cdef Py_ssize_t one = n - 2 + cdef Py_ssize_t two = n - 1 + cdef Py_ssize_t j = n - 1 + cdef unsigned int t + + # Starting from the end, find the first o such that + # l[o] < l[o+1] + while two > 0 and l.data.as_uints[one] >= l.data.as_uints[two]: + one -= 1 + two -= 1 + + if two == 0: + return False + + #starting from the end, find the first j such that + #l[j] > l[one] + while l.data.as_uints[j] <= l.data.as_uints[one]: + j -= 1 + + #Swap positions one and j + t = l.data.as_uints[one] + l.data.as_uints[one] = l.data.as_uints[j] + l.data.as_uints[j] = t + + #Reverse the list between two and last + #mset_list = mset_list[:two] + [x for x in reversed(mset_list[two:])] + n -= 1 # In the loop, we only need n-1, so just do it once here + cdef Py_ssize_t i + for i in xrange((n+1 - two) // 2 - 1, -1, -1): + t = l.data.as_uints[i + two] + l.data.as_uints[i + two] = l.data.as_uints[n - i] + l.data.as_uints[n - i] = t + + return True + +cpdef list map_to_list(array.array l, values, int n): + """ + Build a list by mapping the array ``l`` using ``values``. + + .. WARNING:: + + There is no check of the input data at any point. Using wrong + types or values with wrong length is likely to result in a Sage + crash. + + INPUT: + + - ``l`` -- array of unsigned int (i.e., type ``'I'``) + - ``values`` -- tuple; the values of the permutation + - ``n`` -- int; the length of the array ``l`` + + OUTPUT: + + A list representing the permutation. + + EXAMPLES:: + + sage: from array import array + sage: from sage.combinat.permutation_cython import map_to_list + sage: l = array('I', [0, 1, 0, 3, 3, 0, 1]) + sage: map_to_list(l, ('a', 'b', 'c', 'd'), 7) + ['a', 'b', 'a', 'd', 'd', 'a', 'b'] + """ + cdef int i + cdef list ret = PyList_New(n) + cdef PyObject * t + for i in range(n): + t = PyTuple_GET_ITEM( values, l.data.as_uints[i]) + Py_INCREF(t) + PyList_SET_ITEM(ret, i, t) + return ret ##################################################################### ## Multiplication functions for permutations diff --git a/src/sage/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index 874163abcdf..df76569af73 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -19,6 +19,7 @@ from __future__ import division, print_function, absolute_import from sage.structure.parent import Parent +from sage.structure.element import parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets @@ -33,6 +34,7 @@ from . import permutation import functools +from sage.combinat.permutation import to_standard class RibbonTableau(SkewTableau): r""" @@ -597,27 +599,26 @@ def spin_rec(t, nexts, current, part, weight, length): sage: spin_rec(t, [[t^5], [t^4], [t^6 + t^4 + t^2]], [[[2, 2, 2, 2, 1], [0, 0, 3]], [[3, 3, 1, 1, 1], [0, 3, 0]], [[3, 3, 3], [3, 0, 0]]], sp([[3, 3, 3, 2, 1], []]), [2, 1, 1], 3) [2*t^7 + 2*t^5 + t^3] """ - from sage.combinat.words.word import Word - R = ZZ['t'] - if current == []: - return [R(0)] + if not current: + return [parent(t).zero()] tmp = [] partp = part[0].conjugate() + ell = len(partp) #compute the contribution of the ribbons added at #the current node - for perms in [current[i][1] for i in range(len(current))]: - perm = [partp[i] + len(partp) - (i + 1) - perms[i] - for i in range(len(partp))] - perm.reverse() - perm = Word(perm).standard_permutation() - tmp.append( (weight[-1]*(length-1)-perm.number_of_inversions()) ) - - if nexts != []: - return [sum([sum([t**tmp[i]*nexts[i][j] for j in range(len(nexts[i]))]) for i in range(len(tmp))])] + for val in current: + perms = val[1] + perm = [partp[i] + ell - (i + 1) - perms[i] for i in reversed(range(ell))] + perm = to_standard(perm) + tmp.append( weight[-1]*(length-1) - perm.number_of_inversions() ) + + if nexts: + return [ sum(sum(t**tval * nval for nval in nexts[i]) + for i, tval in enumerate(tmp)) ] else: - return [sum([t**tmp[i] for i in range(len(tmp))])] + return [ sum(t**val for val in tmp) ] def spin_polynomial_square(part, weight, length): @@ -644,7 +645,6 @@ def spin_polynomial_square(part, weight, length): 3*t^18 + 5*t^16 + 9*t^14 + 6*t^12 + 3*t^10 """ R = ZZ['t'] - t = R.gen() if part in _Partitions: part = SkewPartition([part,_Partitions([])]) @@ -652,8 +652,9 @@ def spin_polynomial_square(part, weight, length): part = SkewPartition(part) if part == [[],[]] and weight == []: - return t.parent()(1) + return R.one() + t = R.gen() return R(graph_implementation_rec(part, weight, length, functools.partial(spin_rec,t))[0]) def spin_polynomial(part, weight, length): @@ -680,10 +681,10 @@ def spin_polynomial(part, weight, length): 3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5 """ from sage.symbolic.ring import SR - sp = spin_polynomial_square(part,weight,length) + sp = spin_polynomial_square(part, weight, length) t = SR.var('t') - c = sp.coefficients(sparse=False) - return sum([c[i]*t**(QQ(i)/2) for i in range(len(c))]) + coeffs = sp.list() + return sum(c * t**(QQ(i)/2) for i,c in enumerate(coeffs)) def cospin_polynomial(part, weight, length): """ @@ -709,20 +710,18 @@ def cospin_polynomial(part, weight, length): 3*t^4 + 6*t^3 + 9*t^2 + 5*t + 3 """ R = ZZ['t'] - t = R.gen() # The power in the spin polynomial are all half integers # or all integers. Manipulation of expressions need to # separate cases sp = spin_polynomial_square(part, weight, length) if sp == 0: - return R(0) - - coeffs = [c for c in sp.coefficients(sparse=False) if c != 0] - d = len(coeffs)-1 - exponents = [d-e for e in range(len(coeffs))] + return R.zero() - return R(sum([ coeffs[i]*t**exponents[i] for i in range(len(coeffs))])) + coeffs = [c for c in sp.list() if c != 0] + d = len(coeffs) - 1 + t = R.gen() + return R( sum(c * t**(d-i) for i,c in enumerate(coeffs)) ) ## ////////////////////////////////////////////////////////////////////////////////////////// @@ -753,6 +752,9 @@ def graph_implementation_rec(skp, weight, length, function): weight = [] partp = skp[0].conjugate() + ell = len(partp) + outer = skp[1] + outer_len = len(outer) ## Some tests in order to know if the shape and the weight are compatible. if weight != [] and weight[-1] <= len(partp): @@ -763,22 +765,22 @@ def graph_implementation_rec(skp, weight, length, function): selection = [] for j in range(len(perms)): - retire = [(partp[i]+ len(partp) - (i+1) - perms[j][i]) for i in range(len(partp))] + retire = [(val + ell - (i+1) - perms[j][i]) for i,val in enumerate(partp)] retire.sort(reverse=True) - retire = [ retire[i] - len(partp) + (i+1) for i in range(len(retire))] + retire = [val - ell + (i+1) for i,val in enumerate(retire)] - if retire[-1] >= 0 and retire == [i for i in reversed(sorted(retire))]: - retire = Partition([x for x in retire if x != 0]).conjugate() + if retire[-1] >= 0 and retire == sorted(retire, reverse=True): + retire = Partition(retire).conjugate() # Cutting branches if the retired partition has a line strictly included into the inner one - append = True - padded_retire = retire + [0]*(len(skp[1])-len(retire)) - for k in range(len(skp[1])): - if padded_retire[k] - skp[1][k] < 0: - append = False - break - if append: - selection.append([retire, perms[j]]) + if len(retire) >= outer_len: + append = True + for k in range(outer_len): + if retire[k] - outer[k] < 0: + append = False + break + if append: + selection.append([retire, perms[j]]) #selection contains the list of current nodes @@ -787,10 +789,10 @@ def graph_implementation_rec(skp, weight, length, function): else: #The recursive calls permit us to construct the list of the sons #of all current nodes in selection - a = [graph_implementation_rec([p[0], skp[1]], weight[:-1], length, function) for p in selection] + a = [graph_implementation_rec([p[0], outer], weight[:-1], length, function) + for p in selection] return function(a, selection, skp, weight, length) - ############################################################## diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index e3c52459519..5306e57e69a 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -35,7 +35,7 @@ import sage.combinat.ribbon_tableau as ribbon_tableau import sage.combinat.skew_partition from sage.rings.all import ZZ -import sage.combinat.partition +from sage.combinat.partition import Partition, Partitions, _Partitions from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom from sage.rings.rational_field import QQ @@ -247,22 +247,22 @@ def _llt_generic(self, skp, stat): sage: L3._llt_generic([[[2,2],[1]],[[2,1],[]]],f) m[1, 1, 1, 1] + m[2, 1, 1] + m[2, 2] + m[3, 1] + m[4] """ - if skp in sage.combinat.partition.Partitions(): + if skp in _Partitions: m = (sum(skp) / self.level()).floor() if m == 0: raise ValueError("level (%=) must divide %s "%(sum(skp), self.level())) - mu = sage.combinat.partition.Partitions( ZZ(sum(skp) / self.level()) ) + mu = Partitions( ZZ(sum(skp) / self.level()) ) elif isinstance(skp, list) and skp[0] in sage.combinat.skew_partition.SkewPartitions(): #skp is a list of skew partitions - skp2 = [sage.combinat.partition.Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])] - skp2 += [sage.combinat.partition.Partition(core=[], quotient=[skp[i][1] for i in range(len(skp))])] - mu = sage.combinat.partition.Partitions(ZZ((skp2[0].size()-skp2[1].size()) / self.level())) + skp2 = [Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])] + skp2 += [Partition(core=[], quotient=[skp[i][1] for i in range(len(skp))])] + mu = Partitions(ZZ((skp2[0].size()-skp2[1].size()) / self.level())) skp = skp2 - elif isinstance(skp, list) and skp[0] in sage.combinat.partition.Partitions(): + elif isinstance(skp, list) and skp[0] in _Partitions: #skp is a list of partitions - skp = sage.combinat.partition.Partition(core=[], quotient=skp) - mu = sage.combinat.partition.Partitions( ZZ(sum(skp) / self.level() )) + skp = Partition(core=[], quotient=skp) + mu = Partitions( ZZ(sum(skp) / self.level()) ) else: raise ValueError("LLT polynomials not defined for %s"%skp) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 52ed8db849d..70be7683386 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1084,18 +1084,18 @@ def to_sign_matrix(self, max_entry = None): r""" Return the sign matrix of ``self``. - A sign matrix is an `m \times n` matrix of 0's, 1's and -1's such that the - partial sums of each column is either 0 or 1 and the partial sums of + A sign matrix is an `m \times n` matrix of 0's, 1's and -1's such that the + partial sums of each column is either 0 or 1 and the partial sums of each row is non-negative. [Aval2008]_ - - INPUT: - - ``max_entry`` -- A non-negative integer, the maximum allowable number in + INPUT: + + - ``max_entry`` -- A non-negative integer, the maximum allowable number in the tableau. Defaults to the largest entry in the tableau if not specified. - EXAMPLES:: - + EXAMPLES:: + sage: t = SemistandardTableau([[1,1,1,2,4],[3,3,4],[4,5],[6,6]]) sage: t.to_sign_matrix(6) [ 0 0 0 1 0 0] @@ -1125,7 +1125,7 @@ def to_sign_matrix(self, max_entry = None): .. [Aval2008] Jean-Christope Aval. *Keys and Alternating Sign Matrices*, - Seminaire Lotharingien de Combinatoire 59 (2008) B59f + Seminaire Lotharingien de Combinatoire 59 (2008) B59f :arxiv:`0711.2150` """ from sage.rings.all import ZZ @@ -1133,7 +1133,7 @@ def to_sign_matrix(self, max_entry = None): PI = PositiveIntegers() for row in self: if any(c not in PI for c in row): - raise ValueError("the entries must be non-negative integers") + raise ValueError("the entries must be non-negative integers") from sage.matrix.matrix_space import MatrixSpace if max_entry is None: max_entry=max([max(c) for c in self]) @@ -3508,8 +3508,8 @@ def is_key_tableau(self): sage: t.is_key_tableau() False """ - itr = enumerate(self.conjugate()[1:],1) - return all(x in self.conjugate()[i-1] for i, col in itr for x in col) + T_conj = self.conjugate() + return all(x in T_conj[i-1] for i in range(1, len(T_conj)) for x in T_conj[i]) def right_key_tableau(self): """ @@ -3555,9 +3555,6 @@ def right_key_tableau(self): sage: t.right_key_tableau() == t True """ - if self.is_key_tableau(): - return self - cols_list = self.conjugate() key = [[] for row in cols_list] @@ -3619,9 +3616,6 @@ def left_key_tableau(self): sage: t.left_key_tableau() == t True """ - if self.is_key_tableau(): - return self - cols_list = self.conjugate() key = [[] for row in cols_list] key[0] = list(cols_list[0]) @@ -3903,7 +3897,7 @@ def degree(self, e, multicharge=(0,)): deg = self.shape()._initial_degree(e,multicharge) res = self.shape().initial_tableau().residue_sequence(e, multicharge) for r in self.reduced_row_word(): - if res[r] == res[r+1]: + if res[r] == res[r+1]: deg -= 2 elif res[r] == res[r+1] + 1 or res[r] == res[r+1] - 1: deg += (e == 2 and 2 or 1) @@ -3993,7 +3987,7 @@ def first_row_descent(self): def first_column_descent(self): r""" - Return the first cell where ``self`` is not column standard. + Return the first cell where ``self`` is not column standard. Cells are ordered left to right along the rows and then top to bottom. That is, the cell `(r, c)` with `r` and `c` minimal such that diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 1ffbbe0b4cb..6ac96e78380 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2205,6 +2205,111 @@ def is_cadence(self, seq): return False return True + def longest_forward_extension(self, x, y): + r""" + Compute the length of the longest factor of ``self`` that + starts at ``x`` and that matches a factor that starts at ``y``. + + INPUT: + + - ``x``, ``y`` -- positions in ``self`` + + EXAMPLES:: + + sage: w = Word('0011001') + sage: w.longest_forward_extension(0, 4) + 3 + sage: w.longest_forward_extension(0, 2) + 0 + + The method also accepts negative positions indicating the distance from + the end of the word (in order to be consist with how negative indices + work with lists). For instance, for a word of length `7`, using + positions `-3` and `2` is the same as using positions `4` and `2`:: + + sage: w.longest_forward_extension(1, -2) + 2 + sage: w.longest_forward_extension(4, -3) + 3 + + TESTS:: + + sage: w = Word('0011001') + sage: w.longest_forward_extension(-10, 2) + Traceback (most recent call last): + ... + ValueError: x and y must be valid positions in self + + """ + length = self.length() + if not (-length <= x < length and -length <= y < length): + raise ValueError("x and y must be valid positions in self") + if x < 0: + x = x + length + if y < 0: + y = y + length + l = 0 + while x < length and y < length and self[x] == self[y]: + l += 1 + x += 1 + y += 1 + return l + + def longest_backward_extension(self, x, y): + r""" + Compute the length of the longest factor of ``self`` that + ends at ``x`` and that matches a factor that ends at ``y``. + + INPUT: + + - ``x``, ``y`` -- positions in ``self`` + + EXAMPLES:: + + sage: w = Word('0011001') + sage: w.longest_backward_extension(6, 2) + 3 + sage: w.longest_backward_extension(1, 4) + 1 + sage: w.longest_backward_extension(1, 3) + 0 + + The method also accepts negative positions indicating the distance from + the end of the word (in order to be consist with how negative indices + work with lists). For instance, for a word of length `7`, using + positions `6` and `-5` is the same as using positions `6` and `2`:: + + sage: w.longest_backward_extension(6, -5) + 3 + sage: w.longest_backward_extension(-6, 4) + 1 + + TESTS:: + + sage: w = Word('0011001') + sage: w.longest_backward_extension(4, 23) + Traceback (most recent call last): + ... + ValueError: x and y must be valid positions in self + sage: w.longest_backward_extension(-9, 4) + Traceback (most recent call last): + ... + ValueError: x and y must be valid positions in self + """ + length = self.length() + if not (-length <= x < length and -length <= y < length): + raise ValueError("x and y must be valid positions in self") + if x < 0: + x = x + length + if y < 0: + y = y + length + l = 0 + while x >= 0 and y >= 0 and self[x] == self[y]: + l += 1 + x -= 1 + y -= 1 + return l + def longest_common_suffix(self, other): r""" Return the longest common suffix of ``self`` and ``other``. diff --git a/src/sage/cpython/cython_metaclass.pxd b/src/sage/cpython/cython_metaclass.pxd index b9bacfa67c5..189eb04f1c4 100644 --- a/src/sage/cpython/cython_metaclass.pxd +++ b/src/sage/cpython/cython_metaclass.pxd @@ -1,2 +1,2 @@ -cdef extern from "sage/cpython/cython_metaclass.h": +cdef extern from "cython_metaclass.h": PyMethodDescr_CallSelf(desc, self) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index dd23d7b75cf..33bdf51e4ad 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -179,6 +179,7 @@ def increasing_tree_shape(elt, compare=min): from sage.categories.sets_cat import Sets from sage.structure.sage_object import SageObject +from sage.structure.richcmp import richcmp from sage.misc.misc import verbose from sage.rings.integer import Integer @@ -1924,7 +1925,7 @@ def __reduce__(self): """ return (FindStatCollection, (self.id(),)) - def __cmp__(self, other): + def _richcmp_(self, other, op): """ TESTS:: @@ -1950,7 +1951,7 @@ def __cmp__(self, other): sage: sorted(c for c in FindStatCollections())[0] # optional -- internet Cc0001: Permutations """ - return self.id().__cmp__(other.id()) + return richchmp(self.id(), other.id(), op) def is_supported(self): """ @@ -2646,7 +2647,7 @@ def _repr_(self): """ return "%s: %s" %(self.id_str(), self._map[FINDSTAT_MAP_NAME]) - def __cmp__(self, other): + def _richcmp_(self, other, op): """ TESTS:: @@ -2672,7 +2673,7 @@ def __cmp__(self, other): sage: sorted(c for c in FindStatMaps())[0] # optional -- internet Mp00001: to semistandard tableau """ - return self.id().__cmp__(other.id()) + return richcmp(self.id(), other.id(), op) def name(self): r""" diff --git a/src/sage/env.py b/src/sage/env.py index 6135c67c0de..b002e0ba44c 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -71,8 +71,8 @@ def _add_variable_or_fallback(key, fallback, force=False): Test that :trac:`23758` has been resolved:: sage: sage.env._add_variable_or_fallback('SAGE_BA', '---hello---') - sage: sage.env._add_variable_or_fallback('TEMP', '$SAGE_BAR') - sage: sage.env.SAGE_ENV['TEMP'] + sage: sage.env._add_variable_or_fallback('SAGE_QUX', '$SAGE_BAR') + sage: sage.env.SAGE_ENV['SAGE_QUX'] '---foo---' """ global SAGE_ENV diff --git a/src/sage/ext/ccobject.h b/src/sage/ext/ccobject.h index 7d06fa4c54a..6753a0adcb0 100644 --- a/src/sage/ext/ccobject.h +++ b/src/sage/ext/ccobject.h @@ -59,12 +59,6 @@ T* Construct_ppp(void* mem, const P &d, const Q &e, const R &f){ return new(mem) T(d, e, f); } -/* Construct with four parameters */ -template -T* Construct_pppp(void* mem, const P &d, const Q &e, const R &f, const S &g){ - return new(mem) T(d, e, f, g); -} - /* Destruct */ template void Destruct(T* mem){ @@ -77,27 +71,47 @@ void Delete(T* mem){ delete mem; } -template -void _from_str(T* dest, const char* src){ - std::istringstream out(src); - out >> *dest; -} template -void _from_str_len(T* dest, const char* src, unsigned int len){ - std::istringstream out(std::string(src, len)); - out >> *dest; +static CYTHON_INLINE int ccreadstr(T& x, PyObject* b) +{ + PyObject* converted = NULL; + +#if PY_MAJOR_VERSION >= 3 + // Accept "str" input on Python 3 + if (PyUnicode_Check(b)) + { + converted = PyUnicode_EncodeFSDefault(b); + if (!converted) {return -1;} + b = converted; + } +#endif + + char* buffer; + Py_ssize_t length; + + if (PyBytes_AsStringAndSize(b, &buffer, &length) == -1) + {Py_XDECREF(converted); return -1;} + std::istringstream input(std::string(buffer, length)); + Py_XDECREF(converted); + + input >> x; + + return 0; } + template -PyObject* _to_PyString(const T *x) +static CYTHON_INLINE PyObject* ccrepr(const T& x) { - std::ostringstream instore; - instore << (*x); - std::string instr = instore.str(); - // using PyString_FromString truncates the output if whitespace is - // encountered so we use Py_BuildValue and specify the length - return Py_BuildValue("s#",instr.c_str(), instr.size()); + std::ostringstream instore; + instore << x; + std::string instr = instore.str(); +#if PY_MAJOR_VERSION <= 2 + return PyString_FromStringAndSize(instr.c_str(), instr.size()); +#else + return PyUnicode_DecodeFSDefaultAndSize(instr.c_str(), instr.size()); +#endif } /* Arrays */ diff --git a/src/sage/ext/cplusplus.pxd b/src/sage/ext/cplusplus.pxd new file mode 100644 index 00000000000..66c562c2cac --- /dev/null +++ b/src/sage/ext/cplusplus.pxd @@ -0,0 +1,16 @@ +#***************************************************************************** +# Copyright (C) 2017 Jeroen Demeyer +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +cdef extern from "sage/ext/ccobject.h": + # Print representation of any C++ object + str ccrepr[T](T x) + + # Read a Python bytes/str into a C++ object + int ccreadstr[T](T x, object b) except -1 diff --git a/src/sage/ext/mod_int.pxd b/src/sage/ext/mod_int.pxd index 763fa69f068..f2ef6fe5527 100644 --- a/src/sage/ext/mod_int.pxd +++ b/src/sage/ext/mod_int.pxd @@ -17,7 +17,7 @@ The `mod_int` Data Type #***************************************************************************** -cdef extern from "sage/ext/mod_int.h": +cdef extern from "mod_int.h": ctypedef long mod_int mod_int MOD_INT_MAX mod_int MOD_INT_OVERFLOW diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index e86d86c9251..023e734ae32 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -442,9 +442,25 @@ def __init__(self): sage: polylog(2.0, 1) 1.64493406684823 sage: polylog(2, 1.0) - NaN + 1.64493406684823 sage: polylog(2.0, 1.0) - NaN + 1.64493406684823 + + sage: BF = RealBallField(100) + sage: polylog(2, BF(1/3)) + [0.36621322997706348761674629766 +/- 4.51e-30] + sage: polylog(2, BF(4/3)) + nan + sage: parent(_) + Real ball field with 100 bits precision + sage: polylog(2, CBF(1/3)) + [0.366213229977063 +/- 5.85e-16] + sage: parent(_) + Complex ball field with 53 bits precision + sage: polylog(2, CBF(1)) + [1.644934066848226 +/- 6.59e-16] + sage: parent(_) + Complex ball field with 53 bits precision """ GinacFunction.__init__(self, "polylog", nargs=2) @@ -495,10 +511,16 @@ def __init__(self): dilog(x^2 + 1) sage: dilog(-1) -1/12*pi^2 + sage: dilog(-1.0) + -0.822467033424113 sage: dilog(-1.1) -0.890838090262283 - sage: float(dilog(1)) - 1.6449340668482262 + sage: dilog(1/2) + 1/12*pi^2 - 1/2*log(2)^2 + sage: dilog(.5) + 0.582240526465012 + sage: dilog(1/2).n() + 0.582240526465012 sage: var('z') z sage: dilog(z).diff(z, 2) @@ -509,7 +531,19 @@ def __init__(self): sage: latex(dilog(z)) {\rm Li}_2\left(z\right) - TESTS: + Dilog has a branch point at `1`. Sage's floating point libraries + may handle this differently from the symbolic package:: + + sage: dilog(1) + 1/6*pi^2 + sage: dilog(1.) + 1.64493406684823 + sage: dilog(1).n() + 1.64493406684823 + sage: float(dilog(1)) + 1.6449340668482262 + + TESTS: ``conjugate(dilog(x))==dilog(conjugate(x))`` unless on the branch cuts which run along the positive real axis beginning at 1.:: @@ -528,6 +562,21 @@ def __init__(self): dilog(-1/2*I) sage: conjugate(dilog(2)) conjugate(dilog(2)) + + Check that return type matches argument type where possible + (:trac:`18386`):: + + sage: dilog(0.5) + 0.582240526465012 + sage: dilog(-1.0) + -0.822467033424113 + sage: y = dilog(RealField(13)(0.5)) + sage: parent(y) + Real Field with 13 bits of precision + sage: dilog(RealField(13)(1.1)) + 1.96 - 0.300*I + sage: parent(_) + Complex Field with 13 bits of precision """ GinacFunction.__init__(self, 'dilog', conversions=dict(maxima='li[2]')) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 3e27e93a510..45d9ce0ab15 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1500,7 +1500,7 @@ def __init__(self): sage: RBF=RealBallField(53) sage: factorial(RBF(4.2)) - [32.5780960503313 +/- 6.71e-14] + [32.5780960503313 +/- 6.72e-14] Test pickling:: diff --git a/src/sage/geometry/triangulation/data.h b/src/sage/geometry/triangulation/data.h index 246ae48ceea..3e18c9d00a7 100644 --- a/src/sage/geometry/triangulation/data.h +++ b/src/sage/geometry/triangulation/data.h @@ -1,5 +1,5 @@ -#ifndef __DATA_H__ -#define __DATA_H__ +#ifndef __TRIANGULATION_DATA_H__ +#define __TRIANGULATION_DATA_H__ #include #include diff --git a/src/sage/geometry/triangulation/data.pxd b/src/sage/geometry/triangulation/data.pxd index eeac175a259..779c77f0a8d 100644 --- a/src/sage/geometry/triangulation/data.pxd +++ b/src/sage/geometry/triangulation/data.pxd @@ -1,3 +1,3 @@ -cdef extern from "sage/geometry/triangulation/data.h": +cdef extern from "data.h": cdef cppclass compact_simplices(object): void push_back(int encoded_simplex) diff --git a/src/sage/geometry/triangulation/functions.pxd b/src/sage/geometry/triangulation/functions.pxd index 3088e757dfd..fa981e5215b 100644 --- a/src/sage/geometry/triangulation/functions.pxd +++ b/src/sage/geometry/triangulation/functions.pxd @@ -1,3 +1,3 @@ -cdef extern from "sage/geometry/triangulation/functions.h": +cdef extern from "functions.h": int factorial(int n) int binomial(int n, int D) diff --git a/src/sage/geometry/triangulation/triangulations.pxd b/src/sage/geometry/triangulation/triangulations.pxd index 057b8226ec3..0111fb0dd5f 100644 --- a/src/sage/geometry/triangulation/triangulations.pxd +++ b/src/sage/geometry/triangulation/triangulations.pxd @@ -1,4 +1,4 @@ -cdef extern from "sage/geometry/triangulation/triangulations.h": +cdef extern from "triangulations.h": ctypedef void* triangulations_ptr cdef triangulations_ptr init_triangulations \ (int n, int d, int star, bint fine, object seed, object flips) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 2ba07c75e75..b1a4469d595 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -18355,10 +18355,10 @@ def layout(self, layout = None, pos = None, dim = 2, save_pos = False, **options sage: g = digraphs.ButterflyGraph(1) sage: g.layout() - {('0', 0): [2.22..., 0.832...], - ('0', 1): [0.833..., 0.543...], - ('1', 0): [1.12..., -0.830...], - ('1', 1): [2.50..., -0.545...]} + {('0', 0): [2.69..., 0.43...], + ('0', 1): [1.35..., 0.86...], + ('1', 0): [0.89..., -0.42...], + ('1', 1): [2.26..., -0.87...]} sage: g.layout(layout="acyclic_dummy", save_pos=True) {('0', 0): [0.3..., 0], @@ -18367,10 +18367,10 @@ def layout(self, layout = None, pos = None, dim = 2, save_pos = False, **options ('1', 1): [0.6..., 1]} sage: g.layout(dim = 3) - {('0', 0): [2.02..., 0.528..., 0.343...], - ('0', 1): [1.61..., 0.260..., -0.927...], - ('1', 0): [0.674..., -0.528..., -0.343...], - ('1', 1): [1.07..., -0.260..., 0.927...]} + {('0', 0): [0.68..., 0.50..., -0.24...], + ('0', 1): [1.02..., -0.02..., 0.93...], + ('1', 0): [2.06..., -0.49..., 0.23...], + ('1', 1): [1.74..., 0.01..., -0.92...]} Here is the list of all the available layout options:: @@ -18448,12 +18448,12 @@ def layout_spring(self, by_component = True, **options): sage: g = graphs.LadderGraph(3) #TODO!!!! sage: g.layout_spring() - {0: [1.28..., -0.94...], - 1: [1.57..., -0.10...], - 2: [1.83..., 0.74...], - 3: [0.53..., -0.75...], - 4: [0.79..., 0.10...], - 5: [1.08..., 0.94...]} + {0: [0.73..., -0.29...], + 1: [1.37..., 0.30...], + 2: [2.08..., 0.89...], + 3: [1.23..., -0.83...], + 4: [1.88..., -0.30...], + 5: [2.53..., 0.22...]} sage: g = graphs.LadderGraph(7) sage: g.plot(layout = "spring") Graphics object consisting of 34 graphics primitives @@ -18462,13 +18462,6 @@ def layout_spring(self, by_component = True, **options): layout_default = layout_spring -# if not isinstance(graph.get_pos(), dict): -# if graph.is_planar(): -# graph.set_planar_positions() -# else: -# import sage.graphs.generic_graph_pyx as ggp -# graph.set_pos(ggp.spring_layout_fast_split(graph, iterations=1000)) - def layout_ranked(self, heights = None, dim = 2, spring = False, **options): """ Computes a ranked layout for this graph diff --git a/src/sage/graphs/generic_graph_pyx.pxd b/src/sage/graphs/generic_graph_pyx.pxd index 29bfaf91275..e25d08f023e 100644 --- a/src/sage/graphs/generic_graph_pyx.pxd +++ b/src/sage/graphs/generic_graph_pyx.pxd @@ -1,7 +1,13 @@ from sage.structure.sage_object cimport SageObject from sage.graphs.base.dense_graph cimport DenseGraph -cdef run_spring(int, int, double*, int*, int, bint) +ctypedef int * D_TWO +ctypedef char * D_THREE +ctypedef fused dimension_t: + D_TWO + D_THREE + +cdef run_spring(int, dimension_t, double*, int*, int, int, bint) cdef class GenericGraph_pyx(SageObject): pass diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 0605ee7203c..22f7815e52a 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -22,11 +22,13 @@ AUTHORS: from __future__ import absolute_import, print_function -from cysignals.memory cimport check_allocarray, sig_free +from cysignals.memory cimport check_allocarray, check_calloc, sig_free from cysignals.signals cimport sig_on, sig_off +import cython + include "sage/data_structures/binary_matrix.pxi" -from libc.math cimport sqrt +from libc.math cimport sqrt, fabs from libc.string cimport memset from sage.libs.gmp.mpz cimport * @@ -61,7 +63,9 @@ def spring_layout_fast_split(G, **options): sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast_split sage: spring_layout_fast_split(G) - {0: [0.452..., 0.247...], ..., 502: [25.7..., 0.505...]} + {0: [0.77..., 0.06...], + ... + 902: [3.13..., 0.22...]} AUTHOR: @@ -73,11 +77,11 @@ def spring_layout_fast_split(G, **options): buffer = 1/sqrt(len(G)) for g in Gs: cur_pos = spring_layout_fast(g, **options) - xmin = min([x[0] for x in cur_pos.values()]) - xmax = max([x[0] for x in cur_pos.values()]) + xmin = min(x[0] for x in cur_pos.values()) + xmax = max(x[0] for x in cur_pos.values()) if len(g) > 1: buffer = (xmax - xmin)/sqrt(len(g)) - for v, loc in cur_pos.iteritems(): + for v, loc in cur_pos.items(): loc[0] += left - xmin + buffer pos[v] = loc left += xmax - xmin + buffer @@ -103,8 +107,13 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: G = graphs.DodecahedralGraph() sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast - sage: spring_layout_fast(G) - {0: [-0.0733..., 0.157...], ..., 502: [-0.551..., 0.682...]} + sage: pos = spring_layout_fast(G) + sage: pos[0] # abs tol 0.1 + [0.00..., 0.03...] + sage: pos[902] # abs tol 0.1 + [-0.48..., -0.10...] + sage: len(pos) == G.order() + True With ``split=True``, each component of G is layed out separately, placing them adjacent to each other. This is done because on a @@ -119,8 +128,13 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True sage: G = graphs.DodecahedralGraph() sage: for i in range(10): G.add_cycle(list(range(100*i, 100*i+3))) sage: from sage.graphs.generic_graph_pyx import spring_layout_fast - sage: spring_layout_fast(G, by_component = True) - {0: [2.12..., -0.321...], ..., 502: [26.0..., -0.812...]} + sage: pos = spring_layout_fast(G, by_component = True) + sage: pos[0] # abs tol 0.1 + [2.21..., -0.00...] + sage: pos[902] # abs tol 0.1 + [3.07..., 0.86...] + sage: len(pos) == G.order() + True """ if by_component: @@ -136,32 +150,34 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True if n == 0: return {} - cdef double* pos = check_allocarray(n, dim * sizeof(double)) + cdef double* pos # position of each vertex (for dim=2: x1,y1,x2,y2,...) + cdef int* elist # lexicographically ordered list of edges (u1,v1,u2,v2,...) + cdef double* cen # array of 'dim' doubles + try: + elist = check_allocarray(2 * G.size() + 2, sizeof(int)) + pos = check_allocarray( n*dim , sizeof(double)) + cen = check_calloc(dim, sizeof(double)) + except: + sig_free(pos) + sig_free(elist) + sig_free(cen) + raise - # convert or create the starting positions as a flat list of doubles - if vpos is None: # set the initial positions randomly in 1x1 box - for i from 0 <= i < n*dim: - pos[i] = random() + # Initialize the starting positions + if vpos is None: + for i in range(n*dim): + pos[i] = random() # random in 1x1 box else: - for i from 0 <= i < n: + for i in range(n): loc = vpos[vlist[i]] - for x from 0 <= x check_allocarray(2 * len(G.edges()) + 2, sizeof(int)) - except MemoryError: - sig_free(pos) - raise - + # Lexicographically ordered list of edges cdef int cur_edge = 0 - for i from 0 <= i < n: - for j from i < j < n: + for i in range(n): + for j in range(i+1, n): if G.has_edge(vlist[i], vlist[j]): elist[cur_edge] = i elist[cur_edge+1] = j @@ -169,52 +185,51 @@ def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True # finish the list with -1, -1 which never gets matched # but does get compared against when looking for the "next" edge - elist[cur_edge] = -1 + elist[cur_edge] = -1 elist[cur_edge+1] = -1 - run_spring(iterations, dim, pos, elist, n, height) + if dim == 2: + run_spring( iterations, NULL, pos, elist, n, G.size(), height) + elif dim == 3: + run_spring( iterations, NULL, pos, elist, n, G.size(), height) + else: + raise ValueError("'dim' must be equal to 2 or 3") # recenter - cdef double* cen cdef double r, r2, max_r2 = 0 if rescale: - try: - cen = check_allocarray(dim, sizeof(double)) - except MemoryError: - sig_free(elist) - sig_free(pos) - raise - for x from 0 <= x < dim: cen[x] = 0 - for i from 0 <= i < n: - for x from 0 <= x < dim: + for i in range(n): + for x in range(dim): cen[x] += pos[i*dim + x] - for x from 0 <= x < dim: cen[x] /= n - for i from 0 <= i < n: + for x in range(dim): + cen[x] /= n + for i in range(n): r2 = 0 - for x from 0 <= x < dim: + for x in range(dim): pos[i*dim + x] -= cen[x] r2 += pos[i*dim + x] * pos[i*dim + x] if r2 > max_r2: max_r2 = r2 r = 1 if max_r2 == 0 else sqrt(max_r2) - for i from 0 <= i < n: - for x from 0 <= x < dim: + for i in range(n): + for x in range(dim): pos[i*dim + x] /= r - sig_free(cen) # put the data back into a position dictionary vpos = {} - for i from 0 <= i < n: - vpos[vlist[i]] = [pos[i*dim+x] for x from 0 <= x < dim] + for i in range(n): + vpos[vlist[i]] = [pos[i*dim+x] for x in range(dim)] sig_free(pos) sig_free(elist) + sig_free(cen) return vpos -cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint height): - """ +@cython.cdivision(True) +cdef run_spring(int iterations, dimension_t _dim, double* pos, int* edges, int n, int m, bint height): + r""" Find a locally optimal layout for this graph, according to the constraints that neighboring nodes want to be a fixed distance from each other, and non-neighboring nodes always repel. @@ -229,7 +244,10 @@ cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint he INPUT: iterations -- number of steps to take - dim -- number of dimensions of freedom + _dim -- number of dimensions of freedom. Provide a value of type + `D_TWO` for 2 dimensions, or type `D_THREE` for three + dimensions. The actual value does not matter: only its + type is important. pos -- already initialized initial positions Each vertex is stored as [dim] consecutive doubles. These doubles are then placed consecutively in the array. @@ -249,18 +267,25 @@ cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint he Robert Bradshaw """ + cdef int dim cdef int cur_iter, cur_edge cdef int i, j, x + if dimension_t is D_TWO: + dim = 2 + else: + dim = 3 + # k -- the equilibrium distance between two adjacent nodes cdef double t = 1, dt = t/(1e-20 + iterations), k = sqrt(1.0/n) - cdef double square_dist, force, scale + cdef double square_dist, dist, force, scale cdef double* disp_i cdef double* disp_j - cdef double* delta + cdef double delta[3] + cdef double d_tmp + cdef double xx,yy,zz - cdef double* disp = check_allocarray(n+1, dim * sizeof(double)) - delta = &disp[n*dim] + cdef double* disp = check_allocarray(n, dim * sizeof(double)) if height: update_dim = dim-1 @@ -269,57 +294,92 @@ cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint he sig_on() - for cur_iter from 0 <= cur_iter < iterations: + for cur_iter in range(iterations): cur_edge = 1 # offset by one for fast checking against 2nd element first # zero out the disp vectors memset(disp, 0, n * dim * sizeof(double)) - for i from 0 <= i < n: + for i in range(n): disp_i = disp + (i*dim) - for j from i < j < n: + for j in range(i+1, n): disp_j = disp + (j*dim) - for x from 0 <= x < dim: + for x in range(dim): delta[x] = pos[i*dim+x] - pos[j*dim+x] - square_dist = delta[0] * delta[0] - for x from 1 <= x < dim: - square_dist += delta[x] * delta[x] + xx = delta[0] * delta[0] + yy = delta[1] * delta[1] + if dim == 2: + square_dist = xx+yy + else: + zz = delta[2] * delta[2] + square_dist = xx+yy+zz - if square_dist < 0.01: - square_dist = 0.01 + if square_dist < 0.0001: + square_dist = 0.0001 # they repel according to the (capped) inverse square law - force = k*k/square_dist + force = (k*k)/square_dist # and if they are neighbors, attract according Hooke's law if edges[cur_edge] == j and edges[cur_edge-1] == i: - force -= sqrt(square_dist)/k + if dim == 2: + dist = sqrt_approx(delta[0],delta[1],xx,yy) + else: + dist = sqrt(square_dist) + force -= dist/k cur_edge += 2 # add this factor into each of the involved points - for x from 0 <= x < dim: - disp_i[x] += delta[x] * force - disp_j[x] -= delta[x] * force + for x in range(dim): + d_tmp = delta[x] * force + disp_i[x] += d_tmp + disp_j[x] -= d_tmp # now update the positions - for i from 0 <= i < n: + for i in range(n): disp_i = disp + (i*dim) square_dist = disp_i[0] * disp_i[0] - for x from 1 <= x < dim: + for x in range(1, dim): square_dist += disp_i[x] * disp_i[x] - scale = t / (1 if square_dist < 0.01 else sqrt(square_dist)) + if square_dist < 0.0001: + scale = 1 + else: + scale = t/sqrt(square_dist) - for x from 0 <= x < update_dim: + for x in range(update_dim): pos[i*dim+x] += disp_i[x] * scale t -= dt sig_off() - sig_free(disp) +@cython.cdivision(True) +cdef inline double sqrt_approx(double x,double y,double xx,double yy): + r""" + Approximation of `\sqrt(x^2+y^2)`. + + Assuming that `x > y > 0`, it is a taylor expansion at `x^2`. To see how + 'bad' the approximation is:: + + sage: def dist(x,y): + ....: x = abs(x) + ....: y = abs(y) + ....: return max(x,y) + min(x,y)**2/(2*max(x,y)) + + sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*pi)) + Graphics object consisting of 2 graphics primitives + """ + if xx +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.rings.all import ZZ, QQ +from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups +from .qmodnz_element import QmodnZ_Element + +class QmodnZ(Parent, UniqueRepresentation): + r""" + The ``QmodnZ`` class represents the abelian group `\Q/n\Z`. + + INPUT: + + The constructor may be called in any of the following ways. + + #. ``QmodnZ(n)``, where + + - `n` -- a rational number (including 0 or negative rational numbers). + + #. ``QQ/(n*ZZ)``, where + + - `n` -- an integer (including 0 or negative integers). + + + OUTPUT: + + The abelian group `\Q/n\Z`. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: QQ/(19*ZZ) + Q/19Z + + sage: QmodnZ(19) + Q/19Z + + sage: QmodnZ(2/3) + Q/(2/3)Z + """ + + Element = QmodnZ_Element + def __init__(self, n=1): + r""" + Initialization. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(2) + sage: G + Q/2Z + + TESTS:: + + sage: G = QQ/(19*ZZ) + sage: TestSuite(G).run() + """ + self.n = QQ(n).abs() + category = CommutativeAdditiveGroups().Infinite() + Parent.__init__(self, base=ZZ, category=category) + self._populate_coercion_lists_(coerce_list=[QQ]) + + def _repr_(self): + r""" + Display the group. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(1); G + Q/Z + + sage: G = QQ/(3*ZZ); G + Q/3Z + + sage: G = QmodnZ(1/5); G + Q/(1/5)Z + """ + if self.n == 1: + return "Q/Z" + elif self.n in ZZ: + return "Q/%sZ"%(self.n) + else: + return "Q/(%s)Z"%(self.n) + + def _coerce_map_from_(self, S): + r""" + Coercion from a parent ``S``. + + There is a coercion from ``S`` if ``S`` has a coerce map to `\Q` + or if `S = \Q/m\Z` for `m` a multiple of `n`. + + TESTS:: + + sage: G2 = QQ/(2*ZZ) + sage: G3 = QQ/(3*ZZ) + sage: G4 = QQ/(4*ZZ) + sage: G2.has_coerce_map_from(QQ) + True + sage: G2.has_coerce_map_from(ZZ) + True + sage: G2.has_coerce_map_from(ZZ['x']) + False + sage: G2.has_coerce_map_from(G3) + False + sage: G2.has_coerce_map_from(G4) + True + sage: G4.has_coerce_map_from(G2) + False + """ + if QQ.has_coerce_map_from(S): + return True + if isinstance(S, QmodnZ) and (S.n / self.n in ZZ): + return True + + #TODO: Disallow order comparisons between different Q/nZ's + # e.g., sage: QmodnZ(10/3) > QmodnZ(5/3) + # returns False. + + def _element_constructor_(self, x): + r""" + Construct an element in `\Q/n\Z`. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(2/3) + sage: G(5/6) + 1/6 + """ + return self.element_class(self, QQ(x)) + + def an_element(self): + """ + Return an element, for use in coercion system. + + TESTS:: + + sage: (QQ/ZZ).an_element() + 0 + """ + return self(0) + + def some_elements(self): + """ + Return some elements, for use in testing. + + TESTS:: + + sage: L = (QQ/ZZ).some_elements() + sage: len(L) + 92 + """ + return sorted(list(set([self(x) for x in QQ.some_elements()]))) + + def random_element(self): + r""" + Return a random element of `\Q/n\Z`. The denominator is selected + using the ``1/n`` distribution on integers, modified to return + a positive value. The numerator is then selected uniformly. + + EXAMPLES:: + + sage: G = QQ/(6*ZZ) + sage: G.random_element() + 47/16 + sage: G.random_element() + 1 + sage: G.random_element() + 3/5 + """ + if self.n == 0: + return self(QQ.random_element()) + d = ZZ.random_element() + if d >= 0: + d = 2*d + 1 + else: + d = -2*d + n = ZZ.random_element((self.n * d).ceil()) + return self(n/d) + + def __iter__(self): + r""" + Creates an iterator that generates the elements of `\Q/n\Z` without + repetition, organized by increasing denominator; for a fixed denominator + elements are listed by increasing numerator. + + EXAMPLES: + + The first 19 elements of `\Q/5\Z`:: + + sage: import itertools + sage: list(itertools.islice(QQ/(5*ZZ),19)) + [0, 1, 2, 3, 4, 1/2, 3/2, 5/2, 7/2, 9/2, 1/3, 2/3, 4/3, 5/3, 7/3, 8/3, 10/3, 11/3, 13/3] + """ + + if self.n == 0: + for x in QQ: + yield self(x) + else: + yield self(0) + d = ZZ(1) + while True: + for a in d.coprime_integers((d*self.n).floor()): + yield self(a/d) + d += 1 diff --git a/src/sage/groups/additive_abelian/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py new file mode 100644 index 00000000000..c674fb66f75 --- /dev/null +++ b/src/sage/groups/additive_abelian/qmodnz_element.py @@ -0,0 +1,349 @@ +r""" +Elements of `\Q/n\Z`. + +EXAMPLES:: + + sage: A = QQ / (3*ZZ) + sage: x = A(11/3); x + 2/3 + sage: x*14 + 1/3 + sage: x.additive_order() + 9 + sage: x / 3 + 2/9 +""" + +#***************************************************************************** +# Copyright (C) 2017 David Roe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.structure.element import AdditiveGroupElement +from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity +from sage.structure.richcmp import richcmp, op_EQ, op_NE + +class QmodnZ_Element(AdditiveGroupElement): + r""" + The ``QmodnZ_Element`` class represents an element of the abelian group `\Q/n\Z`. + + INPUT: + + - ``q`` -- a rational number. + + - ``parent`` -- the parent abelian group `\Q/n\Z`. + + OUTPUT: + + The element `q` of abelian group `\Q/n\Z`, in standard form. + + EXAMPLES:: + + sage: G = QQ/(19*ZZ) + sage: G(400/19) + 39/19 + """ + def __init__(self, parent, x, construct=False): + r""" + Create an element of `\Q/n\Z`. + + EXAMPLES:: + + sage: G = QQ/(3*ZZ) + sage: G.random_element() + 47/16 + """ + + AdditiveGroupElement.__init__(self, parent) + # x = (a/b) = q(n/m) + r/mb + # am = q(nb) + r + # r < nb so r/mb < n/m + if construct: + self._x = x + return + n = parent.n.numerator() + if n == 0: + self._x = x + else: + m = parent.n.denominator() + a = x.numerator() + b = x.denominator() + q, r = (a*m).quo_rem(n*b) + self._x = r/(m*b) + + def lift(self): + r""" + Return the smallest non-negative rational number reducing to this element. + + EXAMPLES:: + + sage: G = QQ/(5*ZZ) + sage: g = G(2/4); g + 1/2 + sage: q = lift(g); q + 1/2 + + TESTS:: + + sage: q.parent() is QQ + True + """ + return self._x + + def _rational_(self): + r""" + Lift to `\Q`. + + TESTS:: + + sage: QQ((QQ/ZZ)(4/3)) # indirect doctest + 1/3 + """ + return self._x + + def _integer_(self, Z): + r""" + Lift to `\Z`. + + This is the smallest non-negative integer reducing to this element, + or a ``ValueError`` if none exists. + + TESTS:: + + sage: G = QQ/(2*ZZ) + sage: ZZ(G(3)) + 1 + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(8/3) + sage: ZZ(G(1/3)) + 3 + + sage: all(ZZ(G(i)) == i for i in range(8)) + True + + sage: G = QmodnZ(101/34) + sage: all(ZZ(G(i)) == i for i in range(101)) + True + """ + QZ = self.parent() + b = self._x.denominator() + n = QZ.n.numerator() + m = QZ.n.denominator() + if not b.divides(m): + raise ValueError("No integral lift") + a = self._x.numerator() * (m // b) + # a/m + q*(n/m) = (a + qn)/m = km/m so a + qn = km, + # k = a*m^(-1) mod n. + return (a * m.inverse_mod(n)) % n + + def __neg__(self): + r""" + Return the additive inverse of this element in `\Q/n\Z`. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(5/7) + sage: g = G(13/21) + sage: -g + 2/21 + + TESTS:: + + sage: G = QmodnZ(19/23) + sage: g = G(15/23) + sage: -g + 4/23 + sage: g + -g == G(0) + True + """ + if self._x == 0: + return self + else: + QZ = self.parent() + return QZ.element_class(QZ, QZ.n - self._x, True) + + def _add_(self, other): + r""" + Return the sum of two elements in `\Q/n\Z`. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(9/10) + sage: g = G(5) + sage: h = G(1/2) + sage: g + h + 1/10 + sage: g + h == G(1/10) + True + + TESTS:: + + sage: h + g == G(1/10) + True + """ + QZ = self.parent() + ans = self._x + other._x + if ans >= QZ.n: + ans -= QZ.n + return QZ.element_class(QZ, ans, True) + + def _sub_(self, other): + r""" + Returns the difference of two elements in `\Q/n\Z`. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(9/10) + sage: g = G(4) + sage: h = G(1/2) + sage: g - h + 4/5 + sage: h - g + 1/10 + sage: g - h == G(4/5) + True + sage: h - g == G(1/10) + True + """ + QZ = self.parent() + ans = self._x - other._x + if ans < 0: + ans += QZ.n + return QZ.element_class(QZ, ans, True) + + def _rmul_(self, c): + r""" + Returns the (right) scalar product of this element by ``c`` in `\Q/n\Z`. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(5/7) + sage: g = G(13/21) + sage: g*6 + 1/7 + """ + QZ = self.parent() + return QZ.element_class(QZ, self._x * c) + + def _lmul_(self, c): + r""" + Returns the (left) scalar product of this element by ``c`` in `\Q/n\Z`. + + EXAMPLES:: + + sage: from sage.groups.additive_abelian.qmodnz import QmodnZ + sage: G = QmodnZ(5/7) + sage: g = G(13/21) + sage: 6*g + 1/7 + + TESTS:: + + sage: 6*g == g*6 + True + sage: 6*g == 5*g + False + """ + return self._rmul_(c) + + def __div__(self, other): + r""" + Division. + + .. WARNING:: + + Division of `x` by `m` does not yield a well defined + result, since there are `m` elements `y` of `\Q/n\Z` + with the property that `x = my`. We return the one + with the smallest non-negative lift. + + EXAMPLES:: + + sage: G = QQ/(4*ZZ) + sage: x = G(3/8) + sage: x / 4 + 3/32 + """ + QZ = self.parent() + other = ZZ(other) + return QZ.element_class(QZ, self._x / other, True) + + def _repr_(self): + r""" + Display the element. + + EXAMPLES:: + + sage: G = QQ/(8*ZZ) + sage: g = G(25/7); g + 25/7 + """ + return repr(self._x) + + def __hash__(self): + r""" + Hashing. + + TESTS:: + + sage: G = QQ/(4*ZZ) + sage: g = G(4/5) + sage: hash(g) + 2135587864 # 32-bit + -7046029254386353128 # 64-bit + sage: hash(G(3/4)) + 527949074 # 32-bit + 3938850096065010962 # 64-bit + sage: hash(G(1)) + 1 + """ + return hash(self._x) + + def _richcmp_(self, right, op): + r""" + Compare two elements. + + EXAMPLES:: + + sage: G = QQ/(4*ZZ) + sage: g = G(4/5) + sage: h = G(6/7) + sage: g == h + False + sage: g == g + True + """ + if op == op_EQ or op == op_NE: + return richcmp(self._x, right._x, op) + else: + return NotImplemented + + def additive_order(self): + r""" + Returns the order of this element in the abelian group `\Q/n\Z`. + + EXAMPLES:: + + sage: G = QQ/(12*ZZ) + sage: g = G(5/3) + sage: g.additive_order() + 36 + sage: (-g).additive_order() + 36 + """ + # a/b * k = n/m * r + QZ = self.parent() + if QZ.n == 0: + if self._x == 0: + return ZZ(1) + return infinity + return (self._x / QZ.n).denominator() diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 32bafe93dfd..bb4d308b1e7 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -426,7 +426,7 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): sage: F. = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: P = E.lift_x(a); P - (a : 28*a^4 + 15*a^3 + 14*a^2 + 7 : 1) + (a : 9*a^4 + 22*a^3 + 23*a^2 + 30 : 1) This will return a multiple of the order of P:: @@ -860,7 +860,7 @@ def discrete_log_lambda(a, base, bounds, operation='*', hash_function=hash): sage: F. = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: P = E.lift_x(a); P - (a : 9*a^4 + 22*a^3 + 23*a^2 + 30 : 1) + (a : 28*a^4 + 15*a^3 + 14*a^2 + 7 : 1) This will return a multiple of the order of P:: diff --git a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd index 7f6ac82c1e6..e9c99789df1 100644 --- a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd +++ b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pxd @@ -10,7 +10,7 @@ from sage.groups.perm_gps.partn_ref.data_structures cimport OrbitPartition, PartitionStack from sage.libs.gap.element cimport GapElement, GapElement_Permutation -cdef extern from "sage/groups/perm_gps/partn_ref2/refinement_generic.h": +cdef extern from "refinement_generic.h": cdef long *global_refine_vals_array cdef int my_comp_func(void *a, void *b) cdef int BACKTRACK_WITHLATEX_DEBUG diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index aefe15563ae..77ffb10f5fc 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -23,6 +23,9 @@ - Simon King (2014-05-02): Let simplicial complexes be objects of the category of simplicial complexes. +- Jeremy Martin (2016-06-02): added cone_vertices, decone, is_balanced, + is_partitionable, intersection methods + This module implements the basic structure of finite simplicial complexes. Given a set `V` of "vertices", a simplicial complex on `V` is a collection `K` of subsets of `V` satisfying the condition that if @@ -2856,12 +2859,9 @@ def is_cohen_macaulay(self, base_ring=QQ, ncpus=0): """ from sage.parallel.decorate import parallel - if ncpus == 0: - import os - try: - ncpus = int(os.environ['SAGE_NUM_THREADS']) - except KeyError: - ncpus = 1 + if not ncpus: + from sage.parallel.ncpus import ncpus as get_ncpus + ncpus = get_ncpus() facs = [ x for x in self.face_iterator() ] n = len(facs) @@ -4354,6 +4354,207 @@ def is_immutable(self): """ return not self._is_mutable + def cone_vertices(self): + r""" + Return the list of cone vertices of ``self``. + + A vertex is a cone vertex if and only if it appears in every facet. + + EXAMPLES:: + + sage: SimplicialComplex([[1,2,3]]).cone_vertices() + [1, 2, 3] + sage: SimplicialComplex([[1,2,3], [1,3,4], [1,5,6]]).cone_vertices() + [1] + sage: SimplicialComplex([[1,2,3], [1,3,4], [2,5,6]]).cone_vertices() + [] + """ + F = self.facets() + C = set(self.vertices()) + for f in F: + C = C.intersection(list(f)) + if not C: + break + return sorted(C) + + def decone(self): + r""" + Return the subcomplex of ``self`` induced by the non-cone vertices. + + EXAMPLES:: + + sage: SimplicialComplex([[1,2,3]]).decone() + Simplicial complex with vertex set () and facets {()} + sage: SimplicialComplex([[1,2,3], [1,3,4], [1,5,6]]).decone() + Simplicial complex with vertex set (2, 3, 4, 5, 6) and facets {(3, 4), (2, 3), (5, 6)} + sage: X = SimplicialComplex([[1,2,3], [1,3,4], [2,5,6]]) + sage: X.decone() == X + True + """ + V = set(self.vertices()).difference(self.cone_vertices()) + return self.generated_subcomplex(V) + + def is_balanced(self, check_purity=False, certificate=False): + r""" + Determine whether ``self`` is balanced. + + A simplicial complex `X` of dimension `d-1` is balanced if and + only if its vertices can be colored with `d` colors such that + every face contains at most one vertex of each color. An + equivalent condition is that the 1-skeleton of `X` is + `d`-colorable. In some contexts, it is also required that `X` + be pure (i.e., that all maximal faces of `X` have the same + dimension). + + INPUT: + + - ``check_purity`` -- (default: ``False``) if this is ``True``, + require that ``self`` be pure as well as balanced + + - ``certificate`` -- (default: ``False``) if this is ``True`` and + ``self`` is balanced, then return a `d`-coloring of the 1-skeleton. + + EXAMPLES: + + A 1-dim simplicial complex is balanced iff it is bipartite:: + + sage: X = SimplicialComplex([[1,2],[1,4],[3,4],[2,5]]) + sage: X.is_balanced() + True + sage: X.is_balanced(certificate=True) + [[2, 4], [1, 3, 5]] + sage: X = SimplicialComplex([[1,2],[1,4],[3,4],[2,4]]) + sage: X.is_balanced() + False + + Any barycentric division is balanced:: + + sage: X = SimplicialComplex([[1,2,3],[1,2,4],[2,3,4]]) + sage: X.is_balanced() + False + sage: X.barycentric_subdivision().is_balanced() + True + + A non-pure balanced complex:: + + sage: X=SimplicialComplex([[1,2,3],[3,4]]) + sage: X.is_balanced(check_purity=True) + False + sage: X.is_balanced(certificate=True) + [[2], [1, 4], [3]] + """ + d = 1 + self.dimension() + if check_purity and not self.is_pure(): + return False + Skel = self.graph() + if certificate: + C = Skel.coloring() + C = C if len(C) == d else False + return C + else: + return Skel.chromatic_number() == d + + def is_partitionable(self, certificate=False): + r""" + Determine whether ``self`` is partitionable. + + A partitioning of a simplicial complex `X` is a decomposition + of its face poset into disjoint Boolean intervals `[R,F]`, + where `F` ranges over all facets of `X`. + + The method sets up an integer program with: + + - a variable `y_i` for each pair `(R,F)`, where `F` is a facet of `X` + and `R` is a subface of `F` + + - a constraint `y_i+y_j \leq 1` for each pair `(R_i,F_i)`, `(R_j,F_j)` + whose Boolean intervals intersect nontrivially (equivalent to + `(R_i\subseteq F_j and R_j\subseteq F_i))` + + - objective function equal to the sum of all `y_i` + + INPUT: + + - ``certificate`` -- (default: ``False``) If ``True``, + and ``self`` is partitionable, then return a list of pairs `(R,F)` + that form a partitioning. + + EXAMPLES: + + Simplices are trivially partitionable:: + + sage: X = SimplicialComplex([ [1,2,3,4] ]) + sage: X.is_partitionable() + True + sage: X.is_partitionable(certificate=True) + [((), (1, 2, 3, 4), 4)] + + Shellable complexes are partitionable:: + + sage: X = SimplicialComplex([ [1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5] ]) + sage: X.is_partitionable() + True + sage: P = X.is_partitionable(certificate=True) + sage: n_intervals_containing = lambda f: len([ RF for RF in P if RF[0].is_face(f) and f.is_face(RF[1]) ]) + sage: all( n_intervals_containing(f)==1 for k in X.faces().keys() for f in X.faces()[k] ) + True + + A non-shellable, non-Cohen-Macaulay, partitionable example, constructed by Björner:: + + sage: X = SimplicialComplex([ [1,2,3],[1,2,4],[1,3,4],[2,3,4],[1,5,6] ]) + sage: X.is_partitionable() + True + + The bowtie complex is not partitionable:: + + sage: X = SimplicialComplex([ [1,2,3],[1,4,5] ]) + sage: X.is_partitionable() + False + """ + from sage.numerical.mip import MixedIntegerLinearProgram + Facets = self.facets() + RFPairs = [(Simplex(r), f, f.dimension() - len(r) + 1) + for f in self.facets() for r in Set(f).subsets()] + n = len(RFPairs) + IP = MixedIntegerLinearProgram() + y = IP.new_variable(binary=True) + for i0, pair0 in enumerate(RFPairs): + for i1, pair1 in enumerate(RFPairs): + if (i0 < i1 and pair0[0].is_face(pair1[1]) and + pair1[0].is_face(pair0[1])): + IP.add_constraint(y[i0] + y[i1] <= 1) + IP.set_objective(sum(2**RFPairs[i][2] * y[i] for i in range(n))) + sol = round(IP.solve()) + if sol < sum(self.f_vector()): + return False + elif not certificate: + return True + else: + x = IP.get_values(y) + return [RFPairs[i] for i in range(n) if x[i] == 1] + + def intersection(self,other): + r""" + Calculate the intersection of two simplicial complexes. + + EXAMPLES: + + sage: X = SimplicialComplex([[1,2,3],[1,2,4]]) + sage: Y = SimplicialComplex([[1,2,3],[1,4,5]]) + sage: Z = SimplicialComplex([[1,2,3],[1,4],[2,4]]) + sage: X.intersection(Y).facets() + {(1, 4), (1, 2, 3)} + sage: X.intersection(X) == X + True + sage: X.intersection(Z) == X + False + sage: X.intersection(Z) == Z + True + """ + F = [] + for k in range(1 + min(self.dimension(), other.dimension())): + F = F + [s for s in self.faces()[k] if s in other.faces()[k]] + return SimplicialComplex(F) # Miscellaneous utility functions. diff --git a/src/sage/libs/coxeter3/coxeter.pxd b/src/sage/libs/coxeter3/coxeter.pxd index a234ab78e53..cffa2505e39 100644 --- a/src/sage/libs/coxeter3/coxeter.pxd +++ b/src/sage/libs/coxeter3/coxeter.pxd @@ -6,7 +6,7 @@ #***************************************************************************** from sage.structure.sage_object cimport SageObject -include "decl.pxd" +from .decl cimport * cdef class String: cdef c_String x diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 8924293a7e4..c7ca311ad52 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -466,6 +466,29 @@ cdef class GapElement(RingElement): """ return self.deepcopy(0) + def __contains__(self, other): + r""" + TESTS:: + + sage: libgap(1) in libgap.eval('Integers') + True + sage: 1 in libgap.eval('Integers') + True + + sage: 3 in libgap([1,5,3,2]) + True + sage: -5 in libgap([1,5,3,2]) + False + + sage: libgap.eval('Integers') in libgap(1) + Traceback (most recent call last): + ... + ValueError: libGAP: Error, no method found! Error, no 1st choice method found for `in' on 2 arguments + """ + from sage.libs.gap.libgap import libgap + GAP_IN = libgap.eval(r'\in') + return GAP_IN(other, self).sage() + cpdef _type_number(self): """ Return the GAP internal type number. diff --git a/src/sage/libs/lcalc/lcalc_Lfunction.pxd b/src/sage/libs/lcalc/lcalc_Lfunction.pxd index c9f5a9241cd..56224a1bc36 100644 --- a/src/sage/libs/lcalc/lcalc_Lfunction.pxd +++ b/src/sage/libs/lcalc/lcalc_Lfunction.pxd @@ -1,4 +1,4 @@ -cdef extern from "sage/libs/lcalc/lcalc_sage.h": +cdef extern from "lcalc_sage.h": ctypedef struct doublevec "std::vector": int (*size)() diff --git a/src/sage/libs/ntl/GF2.pxd b/src/sage/libs/ntl/GF2.pxd index e4e1757bb91..e8963258649 100644 --- a/src/sage/libs/ntl/GF2.pxd +++ b/src/sage/libs/ntl/GF2.pxd @@ -1,10 +1,7 @@ from .types cimport GF2_c -cdef extern from "ccobject.h": - void GF2_from_str "_from_str"(GF2_c* dest, char* s) - object GF2_to_PyString "_to_PyString"(GF2_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": int GF2_IsOne "IsOne"(GF2_c x) int GF2_IsZero "IsZero"(GF2_c x) diff --git a/src/sage/libs/ntl/GF2E.pxd b/src/sage/libs/ntl/GF2E.pxd index 443439ecb20..1f70e6635f1 100644 --- a/src/sage/libs/ntl/GF2E.pxd +++ b/src/sage/libs/ntl/GF2E.pxd @@ -1,10 +1,7 @@ from .types cimport GF2E_c, GF2X_c, GF2_c, GF2XModulus_c, ZZ_c -cdef extern from "ccobject.h": - void GF2E_from_str "_from_str"(GF2E_c* dest, char* s) - object GF2E_to_PyString "_to_PyString"(GF2E_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void GF2E_init "GF2E::init"(GF2X_c x) long GF2E_degree "GF2E::degree"() GF2XModulus_c GF2E_modulus "GF2E::modulus"() diff --git a/src/sage/libs/ntl/GF2EX.pxd b/src/sage/libs/ntl/GF2EX.pxd index f4a66485c57..eee748d28b8 100644 --- a/src/sage/libs/ntl/GF2EX.pxd +++ b/src/sage/libs/ntl/GF2EX.pxd @@ -1,10 +1,7 @@ from .types cimport GF2EX_c -cdef extern from "ccobject.h": - void GF2EX_from_str "_from_str"(GF2EX_c* dest, char* s) - object GF2EX_to_PyString "_to_PyString"(GF2EX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void GF2EX_add "add"( GF2EX_c x, GF2EX_c a, GF2EX_c b) void GF2EX_sub "sub"( GF2EX_c x, GF2EX_c a, GF2EX_c b) void GF2EX_mul "mul"( GF2EX_c x, GF2EX_c a, GF2EX_c b) diff --git a/src/sage/libs/ntl/GF2X.pxd b/src/sage/libs/ntl/GF2X.pxd index a1930acc158..795b33f48dd 100644 --- a/src/sage/libs/ntl/GF2X.pxd +++ b/src/sage/libs/ntl/GF2X.pxd @@ -1,10 +1,7 @@ from .types cimport GF2X_c, GF2_c, GF2XModulus_c, vec_GF2_c, ZZ_c -cdef extern from "ccobject.h": - void GF2X_from_str "_from_str"(GF2X_c* dest, char* s) - object GF2X_to_PyString "_to_PyString"(GF2X_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long *GF2XHexOutput_c "(&GF2X::HexOutput)" # work-around for Cython bug int GF2X_IsOne "IsOne"(GF2X_c x) @@ -57,7 +54,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void GF2X_BuildIrred "BuildIrred" (GF2X_c f, long n) #### GF2XModulus_c - void GF2XModulus_from_str "_from_str"(GF2XModulus_c* dest, char* s) void GF2XModulus_build "build"(GF2XModulus_c F, GF2X_c f) # MUST be called before using the modulus long GF2XModulus_deg "deg"(GF2XModulus_c F) diff --git a/src/sage/libs/ntl/ZZ.pxd b/src/sage/libs/ntl/ZZ.pxd index 618c6f26214..d22655c655d 100644 --- a/src/sage/libs/ntl/ZZ.pxd +++ b/src/sage/libs/ntl/ZZ.pxd @@ -2,11 +2,8 @@ from .types cimport ZZ_c -cdef extern from "ccobject.h": - void ZZ_from_str "_from_str"(ZZ_c* dest, char* s) - object ZZ_to_PyString "_to_PyString"(ZZ_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void ZZ_conv_from_int "conv"(ZZ_c x, int i) void ZZ_conv_to_int "conv"(int i, ZZ_c x) void ZZ_conv_from_long "conv"(ZZ_c x, long l) diff --git a/src/sage/libs/ntl/ZZX.pxd b/src/sage/libs/ntl/ZZX.pxd index 9d83a7d2f10..f0d59559d72 100644 --- a/src/sage/libs/ntl/ZZX.pxd +++ b/src/sage/libs/ntl/ZZX.pxd @@ -5,10 +5,9 @@ from .types cimport ZZ_c, vec_ZZ_c, ZZX_c cdef extern from "ccobject.h": void ZZX_swap "swap"(ZZX_c x, ZZX_c y) - void ZZX_from_str "_from_str"(ZZX_c* dest, char* s) - object ZZX_to_PyString "_to_PyString"(ZZX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": + +cdef extern from "ntlwrap.cpp": ctypedef struct pair_ZZX_long_c "pair_ZZX_long": ZZX_c a long b diff --git a/src/sage/libs/ntl/ZZ_p.pxd b/src/sage/libs/ntl/ZZ_p.pxd index 8b66c7bd673..253f7d417dc 100644 --- a/src/sage/libs/ntl/ZZ_p.pxd +++ b/src/sage/libs/ntl/ZZ_p.pxd @@ -2,11 +2,8 @@ from .types cimport ZZ_c, ZZ_p_c -cdef extern from "ccobject.h": - void ZZ_p_from_str "_from_str"(ZZ_p_c* dest, char* s) - object ZZ_p_to_PyString "_to_PyString"(ZZ_p_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": char* ZZ_p_to_str(ZZ_p_c* x) void ZZ_p_add "add"( ZZ_p_c x, ZZ_p_c a, ZZ_p_c b) void ZZ_p_sub "sub"( ZZ_p_c x, ZZ_p_c a, ZZ_p_c b) diff --git a/src/sage/libs/ntl/ZZ_pE.pxd b/src/sage/libs/ntl/ZZ_pE.pxd index 26018eb1ffa..c42b00e3d6d 100644 --- a/src/sage/libs/ntl/ZZ_pE.pxd +++ b/src/sage/libs/ntl/ZZ_pE.pxd @@ -2,11 +2,8 @@ from .types cimport ZZ_c, ZZ_p_c, ZZ_pX_c, ZZ_pE_c -cdef extern from "ccobject.h": - void ZZ_pE_from_str "_from_str"(ZZ_pE_c* dest, char* s) - object ZZ_pE_to_PyString "_to_PyString"(ZZ_pE_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void ZZ_pE_add "add"( ZZ_pE_c x, ZZ_pE_c a, ZZ_pE_c b) void ZZ_pE_add_long "add"( ZZ_pE_c x, ZZ_pE_c a, long b) void ZZ_pE_add_ZZ_p "add"( ZZ_pE_c x, ZZ_pE_c a, ZZ_p_c b) diff --git a/src/sage/libs/ntl/ZZ_pEX.pxd b/src/sage/libs/ntl/ZZ_pEX.pxd index c68ebe87ea0..f125808a07f 100644 --- a/src/sage/libs/ntl/ZZ_pEX.pxd +++ b/src/sage/libs/ntl/ZZ_pEX.pxd @@ -3,11 +3,8 @@ from .types cimport (ZZ_c, ZZ_p_c, ZZ_pContext_c, ZZ_pE_c, vec_ZZ_p_c, vec_ZZ_pE_c, ZZ_pEX_c, ZZ_pEX_Modulus_c) -cdef extern from "ccobject.h": - void ZZ_pEX_from_str "_from_str"(ZZ_pEX_c* dest, char* s) - object ZZ_pEX_to_PyString "_to_PyString"(ZZ_pEX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long ZZ_pEX_IsZero "IsZero"(ZZ_pEX_c a) long ZZ_pEX_IsOne "IsOne"(ZZ_pEX_c a) @@ -72,7 +69,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_pEX_InvMod "InvMod"(ZZ_pEX_c x, ZZ_pEX_c a, ZZ_pEX_c f) long ZZ_pEX_InvModStatus "InvModStatus"(ZZ_pEX_c x, ZZ_pEX_c a, ZZ_pEX_c f) - void ZZ_pEX_Modulus_from_str "_from_str"(ZZ_pEX_Modulus_c* dest, char* s) void ZZ_pEX_Modulus_build "build"(ZZ_pEX_Modulus_c F, ZZ_pEX_c f) long ZZ_pEX_Modulus_deg "deg"(ZZ_pEX_Modulus_c F) diff --git a/src/sage/libs/ntl/ZZ_pX.pxd b/src/sage/libs/ntl/ZZ_pX.pxd index 2e43f9a524f..5f18fb0940a 100644 --- a/src/sage/libs/ntl/ZZ_pX.pxd +++ b/src/sage/libs/ntl/ZZ_pX.pxd @@ -3,11 +3,8 @@ from .types cimport (ZZ_c, ZZX_c, ZZ_p_c, vec_ZZ_p_c, ZZ_pContext_c, ZZ_pX_c, ZZ_pX_Modulus_c, ZZ_pX_Multiplier_c) -cdef extern from "ccobject.h": - void ZZ_pX_from_str "_from_str"(ZZ_pX_c* dest, char* s) - object ZZ_pX_to_PyString "_to_PyString"(ZZ_pX_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long ZZ_pX_IsZero "IsZero"(ZZ_pX_c a) long ZZ_pX_IsOne "IsOne"(ZZ_pX_c a) @@ -69,7 +66,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_pX_InvMod "InvMod"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_c f) long ZZ_pX_InvModStatus "InvModStatus"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_c f) - void ZZ_pX_Modulus_from_str "_from_str"(ZZ_pX_Modulus_c* dest, char* s) void ZZ_pX_Modulus_build "build"(ZZ_pX_Modulus_c F, ZZ_pX_c f) # MUST be called before using the modulus long ZZ_pX_Modulus_deg "deg"(ZZ_pX_Modulus_c F) @@ -86,7 +82,6 @@ cdef extern from "sage/libs/ntl/ntlwrap.cpp": void ZZ_pX_div_pre "div"(ZZ_pX_c q, ZZ_pX_c a, ZZ_pX_Modulus_c F) void ZZ_pX_InvMod_pre "InvMod"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Modulus_c F) - void ZZ_pX_Multiplier_from_str "_from_str"(ZZ_pX_Multiplier_c* dest, char* s) void ZZ_pX_Multiplier_build "build"(ZZ_pX_Multiplier_c F, ZZ_pX_c b, ZZ_pX_Modulus_c F) # MUST be called before using the multiplier void ZZ_pX_MulMod_premul "MulMod"(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Multiplier_c B, ZZ_pX_Modulus_c F) diff --git a/src/sage/libs/ntl/lzz_p.pxd b/src/sage/libs/ntl/lzz_p.pxd index e8db69d3a32..aadea27231d 100644 --- a/src/sage/libs/ntl/lzz_p.pxd +++ b/src/sage/libs/ntl/lzz_p.pxd @@ -2,7 +2,7 @@ from .types cimport zz_p_c -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": long zz_p_rep "rep"(zz_p_c x) long zz_p_isZero "IsZero"(zz_p_c x) void zz_p_add "add"(zz_p_c x, zz_p_c a, zz_p_c b) diff --git a/src/sage/libs/ntl/lzz_pX.pxd b/src/sage/libs/ntl/lzz_pX.pxd index afe3c7f3e18..0c39f5f0c4e 100644 --- a/src/sage/libs/ntl/lzz_pX.pxd +++ b/src/sage/libs/ntl/lzz_pX.pxd @@ -2,10 +2,8 @@ from .types cimport ZZ_c, zz_p_c, zz_pX_c, zz_pX_Modulus_c -cdef extern from "ccobject.h": - void zz_pX_Modulus_from_str "_from_str"(zz_pX_Modulus_c* dest, char* s) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": char* zz_pX_repr(zz_pX_c* x) void zz_pX_SetCoeff_long "SetCoeff"(zz_pX_c x, long i, long a) zz_p_c zz_pX_GetCoeff "coeff"(zz_pX_c x, long i) diff --git a/src/sage/libs/ntl/mat_GF2.pxd b/src/sage/libs/ntl/mat_GF2.pxd index 182887963d4..d89c57adbcb 100644 --- a/src/sage/libs/ntl/mat_GF2.pxd +++ b/src/sage/libs/ntl/mat_GF2.pxd @@ -1,10 +1,7 @@ from .types cimport mat_GF2_c, vec_GF2_c, GF2_c -cdef extern from "ccobject.h": - void mat_GF2_from_str "_from_str"(mat_GF2_c* dest, char* s) - object mat_GF2_to_PyString "_to_PyString"(mat_GF2_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void mat_GF2_add "add"( mat_GF2_c x, mat_GF2_c a, mat_GF2_c b) void mat_GF2_sub "sub"( mat_GF2_c x, mat_GF2_c a, mat_GF2_c b) void mat_GF2_mul "mul"( mat_GF2_c x, mat_GF2_c a, mat_GF2_c b) diff --git a/src/sage/libs/ntl/mat_GF2E.pxd b/src/sage/libs/ntl/mat_GF2E.pxd index ade3dd11f25..229fba9c70c 100644 --- a/src/sage/libs/ntl/mat_GF2E.pxd +++ b/src/sage/libs/ntl/mat_GF2E.pxd @@ -1,10 +1,7 @@ from .types cimport mat_GF2E_c, vec_GF2E_c, GF2E_c -cdef extern from "ccobject.h": - void mat_GF2E_from_str "_from_str"(mat_GF2E_c* dest, char* s) - object mat_GF2E_to_PyString "_to_PyString"(mat_GF2E_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void mat_GF2E_add "add"( mat_GF2E_c x, mat_GF2E_c a, mat_GF2E_c b) void mat_GF2E_sub "sub"( mat_GF2E_c x, mat_GF2E_c a, mat_GF2E_c b) void mat_GF2E_mul "mul"( mat_GF2E_c x, mat_GF2E_c a, mat_GF2E_c b) diff --git a/src/sage/libs/ntl/mat_ZZ.pxd b/src/sage/libs/ntl/mat_ZZ.pxd index b86929ab547..54f5729bdb6 100644 --- a/src/sage/libs/ntl/mat_ZZ.pxd +++ b/src/sage/libs/ntl/mat_ZZ.pxd @@ -1,9 +1,7 @@ from .types cimport mat_ZZ_c, ZZ_c, ZZX_c -cdef extern from "ccobject.h": - object mat_ZZ_to_PyString "_to_PyString"(mat_ZZ_c *x) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": void mat_ZZ_mul "mul"( mat_ZZ_c x, mat_ZZ_c a, mat_ZZ_c b) void mat_ZZ_add "add"( mat_ZZ_c x, mat_ZZ_c a, mat_ZZ_c b) void mat_ZZ_sub "sub"( mat_ZZ_c x, mat_ZZ_c a, mat_ZZ_c b) diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index 5dea4c05533..a86990e5f77 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -16,6 +16,7 @@ from __future__ import division from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -52,10 +53,7 @@ cdef class ntl_GF2(object): elif isinstance(v, int) or isinstance(v, long) or isinstance(v, Integer): GF2_conv_long(self.x, int(v) % 2) elif v is not None: - v = str(v) - sig_on() - GF2_from_str(&self.x, v) - sig_off() + ccreadstr(self.x, str(v)) def __repr__(self): """ @@ -65,7 +63,7 @@ cdef class ntl_GF2(object): sage: str(ntl.GF2(1)) # indirect doctest '1' """ - return GF2_to_PyString(&self.x) + return ccrepr(self.x) def __reduce__(self): """ diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index 645252604d7..ab15f89c692 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -16,6 +16,8 @@ from __future__ import absolute_import, division +from sage.ext.cplusplus cimport ccrepr + include 'misc.pxi' include 'decl.pxi' @@ -187,7 +189,7 @@ cdef class ntl_GF2E(object): [1 1 0 1] """ self.c.restore_c() - return GF2E_to_PyString(&self.x) + return ccrepr(self.x) def __copy__(self): """ diff --git a/src/sage/libs/ntl/ntl_GF2EX.pyx b/src/sage/libs/ntl/ntl_GF2EX.pyx index a8b4d8918e5..b902ca3f117 100644 --- a/src/sage/libs/ntl/ntl_GF2EX.pyx +++ b/src/sage/libs/ntl/ntl_GF2EX.pyx @@ -15,6 +15,7 @@ from __future__ import absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -50,10 +51,7 @@ cdef class ntl_GF2EX(object): if modulus is None: raise ValueError("You must specify a modulus when creating a GF2E.") - s = str(x) - sig_on() - GF2EX_from_str(&self.x, s) - sig_off() + ccreadstr(self.x, str(x)) def __cinit__(self, modulus=None, x=[]): #################### WARNING ################### @@ -147,7 +145,7 @@ cdef class ntl_GF2EX(object): sage: ntl.GF2EX(ctx, '[[1 0] [2 1]]').__repr__() '[[1] [0 1]]' """ - return GF2EX_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_GF2EX self, other): """ diff --git a/src/sage/libs/ntl/ntl_GF2X.pyx b/src/sage/libs/ntl/ntl_GF2X.pyx index cab8a2ad673..5c3fc79d689 100644 --- a/src/sage/libs/ntl/ntl_GF2X.pyx +++ b/src/sage/libs/ntl/ntl_GF2X.pyx @@ -17,6 +17,7 @@ from __future__ import absolute_import, division from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -153,10 +154,8 @@ cdef class ntl_GF2X(object): elif isinstance(x, FiniteField_ntl_gf2eElement): x = x.polynomial().list() s = str(x).replace(","," ") - sig_on() # TODO: this is very slow, but we wait until somebody complains - GF2X_from_str(&self.x, s) - sig_off() + ccreadstr(self.x, s) def __reduce__(self): """ @@ -178,7 +177,7 @@ cdef class ntl_GF2X(object): sage: ntl.GF2X(ntl.ZZ_pX([1,1,3],2)).__repr__() '[1 1 1]' """ - return GF2X_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_GF2X self, other): """ @@ -478,7 +477,7 @@ cdef class ntl_GF2X(object): """ cdef long _hex = GF2XHexOutput_c[0] GF2XHexOutput_c[0] = 0 - s = GF2X_to_PyString(&self.x) + s = ccrepr(self.x) GF2XHexOutput_c[0] = _hex return s @@ -501,7 +500,7 @@ cdef class ntl_GF2X(object): """ cdef long _hex = GF2XHexOutput_c[0] GF2XHexOutput_c[0] = 1 - s = GF2X_to_PyString(&self.x) + s = ccrepr(self.x) GF2XHexOutput_c[0] = _hex return s diff --git a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi index 2e4768317e7..77d66c16983 100644 --- a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi +++ b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi @@ -71,7 +71,6 @@ cdef object celement_repr(GF2X_c *e, long parent): sage: x x """ - #return GF2X_to_PyString(e) raise NotImplementedError cdef inline int celement_set(GF2X_c* res, GF2X_c* a, long parent) except -2: diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 320d97b6c2e..4697562c432 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -15,6 +15,7 @@ from __future__ import print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -95,9 +96,7 @@ cdef class ntl_ZZ(object): (v[1:-1].isdigit() or (len(v) <= 2)) and \ (v[-1].isdigit() or (v[-1].lower() in ['l','r']))): raise ValueError("invalid integer: %s" % v) - sig_on() - ZZ_from_str(&self.x, v) - sig_off() + ccreadstr(self.x, v) def __repr__(self): """ @@ -107,7 +106,7 @@ cdef class ntl_ZZ(object): sage: ntl.ZZ(5).__repr__() '5' """ - return ZZ_to_PyString(&self.x) + return ccrepr(self.x) def __reduce__(self): """ diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index e07b642a798..836d5cd4223 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -15,6 +15,7 @@ from __future__ import division, print_function, absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccreadstr include "decl.pxi" include 'misc.pxi' @@ -129,8 +130,7 @@ cdef class ntl_ZZX(object): cc = x ZZX_SetCoeff(self.x, i, cc.x) else: - v = str(v) - ZZX_from_str(&self.x, v) + ccreadstr(self.x, str(v)) def __reduce__(self): """ diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index 1193b1b90ac..0ee8d5bd214 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -15,6 +15,7 @@ from __future__ import print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -105,7 +106,6 @@ cdef class ntl_ZZ_p(object): cdef ZZ_c temp, num, den cdef long failed if v is not None: - sig_on() if isinstance(v, ntl_ZZ_p): self.x = (v).x elif isinstance(v, int): @@ -121,9 +121,7 @@ cdef class ntl_ZZ_p(object): (v.denominator())._to_ZZ(&den) ZZ_p_div(self.x, ZZ_to_ZZ_p(num), ZZ_to_ZZ_p(den)) else: - v = str(v) - ZZ_p_from_str(&self.x, v) - sig_off() + ccreadstr(self.x, str(v)) def __cinit__(self, v=None, modulus=None): #################### WARNING ################### @@ -189,7 +187,7 @@ cdef class ntl_ZZ_p(object): '7' """ self.c.restore_c() - return ZZ_p_to_PyString(&self.x) + return ccrepr(self.x) def __richcmp__(ntl_ZZ_p self, other, int op): r""" diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index 77499da8f3a..1ede04efadb 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -16,6 +16,7 @@ from __future__ import absolute_import, print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -126,8 +127,7 @@ cdef class ntl_ZZ_pE(object): (v)._to_ZZ(&temp) self.x = ZZ_to_ZZ_pE(temp) else: - v = str(v) - ZZ_pE_from_str(&self.x, v) + ccreadstr(self.x, str(v)) def __cinit__(ntl_ZZ_pE self, v=None, modulus=None): #################### WARNING ################### @@ -171,11 +171,8 @@ cdef class ntl_ZZ_pE(object): return self.c def __repr__(self): - #return self.get_as_ZZ_pX().__repr__() self.c.restore_c() - #sig_on() - return ZZ_pE_to_PyString(&self.x) - #return string_delete(ans) + return ccrepr(self.x) def __richcmp__(ntl_ZZ_pE self, other, int op): r""" diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index 3e0095e9299..9842b46b28e 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -23,6 +23,7 @@ AUTHORS: from __future__ import division, absolute_import, print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -160,8 +161,7 @@ cdef class ntl_ZZ_pEX(object): [[3 2] [1 2] [1 2]] """ self.c.restore_c() - return ZZ_pEX_to_PyString(&self.x) - #return string_delete(ZZ_pEX_to_str(&self.x)) + return ccrepr(self.x) def __copy__(self): """ diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi b/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi index c6c50f554bd..ae325adc330 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi +++ b/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi @@ -22,7 +22,6 @@ from cysignals.signals cimport sig_on, sig_off from sage.libs.ntl.ntl_ZZ_pEContext cimport ntl_ZZ_pEContext_class from sage.libs.ntl.ZZ_pEX cimport * -from sage.libs.ntl.ZZ_pE cimport ZZ_pE_from_str from sage.libs.ntl.ntl_ZZ_pE cimport ntl_ZZ_pE from sage.libs.ntl.types cimport ZZ_pX_c, ZZ_pEX_c diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index 7fa70db4441..33493b161b3 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -16,6 +16,7 @@ from __future__ import absolute_import, division, print_function from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include 'misc.pxi' include 'decl.pxi' @@ -102,9 +103,7 @@ cdef class ntl_ZZ_pX(object): ZZ_pX_SetCoeff(self.x, i, cc.x) elif v is not None: s = str(v).replace(',',' ').replace('L','') - sig_on() - ZZ_pX_from_str(&self.x, s) - sig_off() + ccreadstr(self.x, s) def __cinit__(self, v=None, modulus=None): #################### WARNING ################### @@ -160,11 +159,7 @@ cdef class ntl_ZZ_pX(object): '[1 0 3]' """ self.c.restore_c() - #cdef char* s = ZZ_pX_repr(&self.x) - #t = str(s) - #sig_free(s) - return ZZ_pX_to_PyString(&self.x) - #return t + return ccrepr(self.x) def __copy__(self): """ diff --git a/src/sage/libs/ntl/ntl_mat_GF2.pyx b/src/sage/libs/ntl/ntl_mat_GF2.pyx index 3a6c91ac392..efc3fb09953 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2.pyx @@ -27,6 +27,7 @@ AUTHORS: #***************************************************************************** from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -145,7 +146,7 @@ cdef class ntl_mat_GF2(object): [0 1 1 0] ] """ - return mat_GF2_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_mat_GF2 self, other): """ diff --git a/src/sage/libs/ntl/ntl_mat_GF2E.pyx b/src/sage/libs/ntl/ntl_mat_GF2E.pyx index 6f28cfff21f..007f8281878 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2E.pyx @@ -25,6 +25,7 @@ from __future__ import absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -188,7 +189,7 @@ cdef class ntl_mat_GF2E(object): '[[[] [1]]\n[[] [1]]\n]' """ self.c.restore_c() - return mat_GF2E_to_PyString(&self.x) + return ccrepr(self.x) def __mul__(ntl_mat_GF2E self, other): """ diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index 97fc8187eb1..60d3b467c59 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -14,6 +14,7 @@ #***************************************************************************** from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include 'misc.pxi' include 'decl.pxi' @@ -126,7 +127,7 @@ cdef class ntl_mat_ZZ(object): sage: M = ntl.mat_ZZ(2,3,[5..10]) ; M.__repr__() '[\n[5 6 7]\n[8 9 10]\n]' """ - return mat_ZZ_to_PyString(&self.x).replace('[[','[\n[',1) + return ccrepr(self.x).replace('[[','[\n[',1) def __mul__(ntl_mat_ZZ self, other): """ diff --git a/src/sage/libs/ntl/ntlwrap.cpp b/src/sage/libs/ntl/ntlwrap.cpp index 0ad51983f59..38c9cfebf6c 100644 --- a/src/sage/libs/ntl/ntlwrap.cpp +++ b/src/sage/libs/ntl/ntlwrap.cpp @@ -1,3 +1,5 @@ +#ifndef _SAGE_NTLWRAP_CPP +#define _SAGE_NTLWRAP_CPP #include "ntlwrap.h" #ifdef __cplusplus @@ -832,3 +834,4 @@ static void ZZ_pX_InvMod_newton_ram(struct ZZ_pX &x, const struct ZZ_pX &a, cons } #endif /* #ifdef __cplusplus */ +#endif /* #ifndef _SAGE_NTLWRAP_CPP */ diff --git a/src/sage/libs/ntl/types.pxd b/src/sage/libs/ntl/types.pxd index b52bc0f0d68..1c8f74d1bc5 100644 --- a/src/sage/libs/ntl/types.pxd +++ b/src/sage/libs/ntl/types.pxd @@ -1,6 +1,6 @@ # distutils: depends = NTL/ZZ.h -cdef extern from "sage/libs/ntl/ntlwrap.h": +cdef extern from "ntlwrap.h": long NTL_OVFBND, NTL_SP_BOUND cdef cppclass ZZ_c "ZZ": diff --git a/src/sage/libs/ntl/vec_GF2.pxd b/src/sage/libs/ntl/vec_GF2.pxd index 0630893b65a..b54e489c2a7 100644 --- a/src/sage/libs/ntl/vec_GF2.pxd +++ b/src/sage/libs/ntl/vec_GF2.pxd @@ -1,11 +1,7 @@ from .types cimport vec_GF2_c, GF2_c -cdef extern from "ccobject.h": - void vec_GF2_from_str "_from_str"(vec_GF2_c* dest, char* s) - object vec_GF2_to_PyString "_to_PyString"(vec_GF2_c *x) - void vec_GF2_swap "swap"(vec_GF2_c x, vec_GF2_c y) -cdef extern from "sage/libs/ntl/ntlwrap.cpp": +cdef extern from "ntlwrap.cpp": int vec_GF2_IsZero "IsZero"(vec_GF2_c x) void vec_GF2_append_GF2 "append"(vec_GF2_c v, GF2_c a) diff --git a/src/sage/libs/ntl/vec_GF2E.pxd b/src/sage/libs/ntl/vec_GF2E.pxd index 20f88979f0b..1cfdd7109fa 100644 --- a/src/sage/libs/ntl/vec_GF2E.pxd +++ b/src/sage/libs/ntl/vec_GF2E.pxd @@ -1,5 +1 @@ from .types cimport vec_GF2E_c - -cdef extern from "ccobject.h": - void vec_GF2E_from_str "_from_str"(vec_GF2E_c* dest, char* s) - object vec_GF2E_to_PyString "_to_PyString"(vec_GF2E_c *x) diff --git a/src/sage/libs/pari/tests.py b/src/sage/libs/pari/tests.py index 1f56bd2c264..cd336d2f5be 100644 --- a/src/sage/libs/pari/tests.py +++ b/src/sage/libs/pari/tests.py @@ -948,7 +948,7 @@ sage: pari('[1,2,3;4,5,6;7,8,9]').matker() [1; -2; 1] sage: pari('[1,2,3;4,5,6;7,8,9]').matker(1) - [3; -6; 3] + [1; -2; 1] sage: pari('matrix(3,3,i,j,i)').matker() [-1, -1; 1, 0; 0, 1] sage: pari('[1,2,3;4,5,6;7,8,9]*Mod(1,2)').matker() @@ -1601,7 +1601,7 @@ sage: nf = F.__pari__() sage: I = pari('[1, -1, 2]~') sage: nf.idealstar(I) - [[[43, 9, 5; 0, 1, 0; 0, 0, 1], [0]], [42, [42]], Mat([[43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]], 1]), [[[[[42], [3], [3], [Vecsmall([])], 1, [43, 9, 5; 0, 1, 0; 0, 0, 1]]]], [[], [], [], Vecsmall([])], Vecsmall([0])], Mat(1)] + [[[43, 9, 5; 0, 1, 0; 0, 0, 1], [0]], [42, [42]], [Mat([[43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]], 1]), Mat([[43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]], 1])], [[[[42], [3], [43, 9, 5; 0, 1, 0; 0, 0, 1], [[[-14, -8, 20]~, [1, 34, 38], [43, [9, 1, 0]~, 1, 1, [-5, 2, -18; -9, -5, 2; 1, -9, -5]]]~, 3, [42, [2, 1; 3, 1; 7, 1]]]]], [[], Vecsmall([])]], [Mat(1)]] sage: x = polygen(QQ) sage: K. = NumberField(x^3 - 17) @@ -1675,7 +1675,7 @@ [[1, [7605, 4]~, [5610, 5]~, [7913, -6]~; 0, 1, 0, -1; 0, 0, 1, 0; 0, 0, 0, 1], [[19320, 13720; 0, 56], [2, 1; 0, 1], 1, 1]] sage: pari('x^3 - 17').nfinit() - [x^3 - 17, [1, 1], -867, 3, [[1, 1.68006914259990, 2.57128159065824; 1, -0.340034571299952 - 2.65083754153991*I, -1.28564079532912 + 2.22679517779329*I], [1, 1.68006914259990, 2.57128159065824; 1, -2.99087211283986, 0.941154382464174; 1, 2.31080297023995, -3.51243597312241], [1, 2, 3; 1, -3, 1; 1, 2, -4], [3, 1, 0; 1, -11, 17; 0, 17, 0], [51, 0, 16; 0, 17, 3; 0, 0, 1], [17, 0, -1; 0, 0, 3; -1, 3, 2], [51, [-17, 6, -1; 0, -18, 3; 1, 0, -16]], [3, 17]], [2.57128159065824, -1.28564079532912 + 2.22679517779329*I], [1, 1/3*x^2 - 1/3*x + 1/3, x], [1, 0, -1; 0, 0, 3; 0, 1, 1], [1, 0, 0, 0, -4, 6, 0, 6, -1; 0, 1, 0, 1, 1, -1, 0, -1, 3; 0, 0, 1, 0, 2, 0, 1, 0, 1]] + [x^3 - 17, [1, 1], -867, 3, [[1, 1.68006914259990, 2.57128159065824; 1, -0.340034571299952 - 2.65083754153991*I, -1.28564079532912 + 2.22679517779329*I], [1, 1.68006914259990, 2.57128159065824; 1, -2.99087211283986, 0.941154382464174; 1, 2.31080297023995, -3.51243597312241], [1, 2, 3; 1, -3, 1; 1, 2, -4], [3, 1, 0; 1, -11, 17; 0, 17, 0], [51, 0, 16; 0, 17, 3; 0, 0, 1], [17, 0, -1; 0, 0, 3; -1, 3, 2], [51, [-17, 6, -1; 0, -18, 3; 1, 0, -16]], [3, 17]], [2.57128159065824, -1.28564079532912 + 2.22679517779329*I], [3, x^2 - x + 1, 3*x], [1, 0, -1; 0, 0, 3; 0, 1, 1], [1, 0, 0, 0, -4, 6, 0, 6, -1; 0, 1, 0, 1, 1, -1, 0, -1, 3; 0, 0, 1, 0, 2, 0, 1, 0, 1]] sage: pari('x^2 + 10^100 + 1').nfinit() [...] sage: pari('1.0').nfinit() diff --git a/src/sage/libs/polybori/decl.pxd b/src/sage/libs/polybori/decl.pxd index e7703c14291..e71fa0d95ef 100644 --- a/src/sage/libs/polybori/decl.pxd +++ b/src/sage/libs/polybori/decl.pxd @@ -1,6 +1,6 @@ # distutils: language = c++ -cdef extern from "sage/libs/polybori/pb_wrap.h": +cdef extern from "pb_wrap.h": ctypedef struct std_string "std::string": char *(* c_str)() @@ -57,10 +57,10 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": int (*lastBlockStart)() bint isDegreeOrder() - ctypedef struct PBSet "DefaultRinged" - ctypedef struct PBPoly "DefaultRinged" + ctypedef struct PBSet "DefaultRinged " + ctypedef struct PBPoly "DefaultRinged " - ctypedef struct PBVar "DefaultRinged": + ctypedef struct PBVar "DefaultRinged ": int (* index "index")() bint (* is_equal "operator==")(PBVar right) @@ -102,7 +102,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBMonomVarIter_destruct "Destruct" \ (PBMonomVarIter *mem) - ctypedef struct PBMonom "DefaultRinged": + ctypedef struct PBMonom "DefaultRinged ": bint (* reducibleBy)(PBMonom rhs) int (* deg)() size_t (* hash)() @@ -122,8 +122,6 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBMonom (* GCD)(PBMonom rhs) PBRing (* ring)() - object PBMonom_to_str "_to_PyString"(PBMonom *p) - # Wrapping constructors PBMonom PBMonom_Constructor "BooleMonomial" (PBRing r) PBMonom PBMonom_Constructor_var "BooleMonomial" (PBVar m) @@ -141,7 +139,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBSetIter_destruct "Destruct"(PBSetIter *mem) - ctypedef struct PBSet "DefaultRinged": + ctypedef struct PBSet "DefaultRinged ": bint (* owns)(PBMonom val) int (* nNodes)() int (* nSupport)() @@ -169,8 +167,6 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBSet pb_include_divisors "include_divisors" (PBSet p) PBSet pb_minimal_elements "minimal_elements" (PBSet p) - object PBSet_to_str "_to_PyString"(PBSet *p) - # non-allocating versions PBSet PBSet_Constructor_ring "BooleSet"(PBRing r) PBSet PBSet_Constructor_poly "BooleSet"(PBPoly p) @@ -186,7 +182,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBPolyIter_destruct "Destruct"(PBPolyIter *mem) - ctypedef struct PBPoly "DefaultRinged": + ctypedef struct PBPoly "DefaultRinged ": int (* deg)() int (* leadDeg)() int (* lexLeadDeg)() @@ -240,8 +236,6 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBPoly PBPoly_Constructor_var "BoolePolynomial" (PBVar d) PBPoly PBPoly_Constructor_int_ring "BoolePolynomial" (int d, PBRing r) - object PBPoly_to_str "_to_PyString >"(PBPoly *p) - ctypedef struct PBPolyVectorIter \ "std::vector::iterator ": PBPoly (* value "operator*")() @@ -251,7 +245,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": void PBPolyVectorIter_destruct "Destruct::iterator>"(PBPolyVectorIter *mem) - ctypedef struct PBPolyVector "std::vector": + ctypedef struct PBPolyVector "std::vector ": int (* size)() PBPoly (* get "operator[]")(int) PBPolyVectorIter (* begin)() @@ -291,7 +285,7 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": int (* size)() PBPolyEntry (* get "operator[]")(int) - ctypedef struct PBFglmStrategy "PBWrappedPtr": + ctypedef struct PBFglmStrategy "PBWrappedPtr ": PBPolyVector (* main "operator->()->main")() PBFglmStrategy PBFglmStrategy_Constructor "PBWrappedPtr" \ @@ -451,13 +445,13 @@ cdef extern from "sage/libs/polybori/pb_wrap.h": PBConstant* PBConstant_construct "Construct_p" \ (void* mem, int val) - ctypedef struct PBVarFactory "DefaultRinged": + ctypedef struct PBVarFactory "DefaultRinged ": PBVar (* call "operator()")(int index) - ctypedef struct PBMonomFactory "DefaultRinged": + ctypedef struct PBMonomFactory "DefaultRinged ": PBMonom (* call "operator()")() - ctypedef struct PBPolyFactory "DefaultRinged": + ctypedef struct PBPolyFactory "DefaultRinged ": PBPoly (* call_int "operator()")(int) PBPoly (* call_poly "operator()")(PBPoly) PBPoly (* call_monom "operator()")(PBMonom) diff --git a/src/sage/libs/polybori/pb_wrap.h b/src/sage/libs/polybori/pb_wrap.h index 2ba1cc524f1..d4f3922e733 100644 --- a/src/sage/libs/polybori/pb_wrap.h +++ b/src/sage/libs/polybori/pb_wrap.h @@ -170,12 +170,6 @@ base(ring_singleton::instance(), ring_singleton::instance(), PolynomialVector()) { } -template -PyObject* preallocated_to_PyString(const DefaultRinged *wrapped) { - return _to_PyString(wrapped) ; -} - - template class PBWrappedPtr: public boost::shared_ptr { diff --git a/src/sage/libs/pynac/pynac.pxd b/src/sage/libs/pynac/pynac.pxd index 3fe92c4548c..c80550373b5 100644 --- a/src/sage/libs/pynac/pynac.pxd +++ b/src/sage/libs/pynac/pynac.pxd @@ -7,7 +7,7 @@ Declarations for pynac, a Python frontend for ginac Check that we can externally cimport this (:trac:`18825`):: - sage: cython( # long time + sage: cython( # long time; random compiler warnings ....: ''' ....: #clang c++ ....: #clib pynac @@ -34,7 +34,7 @@ from libcpp.pair cimport pair from libcpp.string cimport string as stdstring from sage.libs.gmp.types cimport mpz_t, mpq_t, mpz_ptr, mpq_ptr -cdef extern from "sage/libs/pynac/wrap.h": +cdef extern from "pynac_wrap.h": void ginac_pyinit_Integer(object) void ginac_pyinit_Float(object) void ginac_pyinit_I(object) @@ -258,7 +258,6 @@ cdef extern from "sage/libs/pynac/wrap.h": # Conversions double GEx_to_double(GEx e, int* success) except + - GEx_to_str "_to_PyString"(GEx *s) except + GEx_to_str_latex "_to_PyString_latex"(GEx *s) except + bint is_a_symbol "is_a" (GEx e) @@ -329,10 +328,6 @@ cdef extern from "sage/libs/pynac/wrap.h": GEx unarchive_ex(GExList sym_lst, unsigned ind) except + void printraw "printraw(std::cout); " (int t) - GArchive_to_str "_to_PyString"(GArchive *s) - void GArchive_from_str "_from_str_len"(GArchive *ar, char* s, - unsigned int l) - GEx g_abs "GiNaC::abs" (GEx x) except + # absolute value GEx g_step "GiNaC::unit_step" (GEx x) except + # step function diff --git a/src/sage/libs/pynac/pynac.pyx b/src/sage/libs/pynac/pynac.pyx index c456afabb1f..b5f08fa3159 100644 --- a/src/sage/libs/pynac/pynac.pyx +++ b/src/sage/libs/pynac/pynac.pyx @@ -1815,7 +1815,7 @@ cdef py_atan2(x, y): sage: atan2(CC(I), CC(I+1)) 0.553574358897045 + 0.402359478108525*I sage: atan2(CBF(I), CBF(I+1)) - [0.55357435889705 +/- 5.75e-15] + [0.40235947810852 +/- 6.01e-15]*I + [0.55357435889705 +/- 5.58e-15] + [0.402359478108525 +/- 7.11e-16]*I Check that :trac:`23776` is fixed and RDF input gives real output:: diff --git a/src/sage/libs/pynac/wrap.h b/src/sage/libs/pynac/pynac_wrap.h similarity index 96% rename from src/sage/libs/pynac/wrap.h rename to src/sage/libs/pynac/pynac_wrap.h index da6a9142065..041b72fc653 100644 --- a/src/sage/libs/pynac/wrap.h +++ b/src/sage/libs/pynac/pynac_wrap.h @@ -7,6 +7,9 @@ http://www.gnu.org/licenses/ *******************************************************************************/ +#ifndef _SAGE_PYNAC_WRAP_H +#define _SAGE_PYNAC_WRAP_H + #include "ccobject.h" #include #include @@ -115,3 +118,5 @@ namespace GiNaC { extern const ex _ex1_2; } + +#endif /* ifndef __SAGE_PYNAC_WRAP_H */ diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index 87e27f5722b..de6ec294abf 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -454,7 +454,8 @@ cdef class ring_wrapper_Py(object): def __cmp__(ring_wrapper_Py left, ring_wrapper_Py right): """ - Compare ``left`` and ``right`` so that instances can be used as dictionary keys. + Compare ``left`` and ``right`` so that instances can be used + as dictionary keys. INPUT: @@ -469,8 +470,8 @@ cdef class ring_wrapper_Py(object): sage: from sage.libs.singular.ring import ring_wrapper_Py sage: t = ring_wrapper_Py() - sage: t.__cmp__(t) - 0 + sage: t == t + True """ if left._ring < right._ring: return -1 diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 754dafce0a8..89319184cd5 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -42,7 +42,7 @@ class AffineConnection(SageObject): or `K=\CC`), let `C^\infty(M)` be the algebra of smooth functions `M\rightarrow K` (cf. :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`) - and let `\mathcal{X}(M)` be the `C^\infty(M)`-module of vector fields on + and let `\mathfrak{X}(M)` be the `C^\infty(M)`-module of vector fields on `M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). An *affine connection* on `M` is an operator @@ -50,14 +50,14 @@ class AffineConnection(SageObject): .. MATH:: \begin{array}{cccc} - \nabla: & \mathcal{X}(M)\times \mathcal{X}(M) & \longrightarrow & - \mathcal{X}(M) \\ + \nabla: & \mathfrak{X}(M)\times \mathfrak{X}(M) & \longrightarrow & + \mathfrak{X}(M) \\ & (u,v) & \longmapsto & \nabla_u v \end{array} that - - is `K`-bilinear, i.e. is bilinear when considering `\mathcal{X}(M)` as a + - is `K`-bilinear, i.e. is bilinear when considering `\mathfrak{X}(M)` as a vector space over `K` - is `C^\infty(M)`-linear w.r.t. the first argument: `\forall f\in C^\infty(M),\ \nabla_{fu} v = f\nabla_u v` @@ -83,13 +83,13 @@ class AffineConnection(SageObject): .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u v = \nabla v(., u) + \forall u \in\mathfrak{X}(M), \ \nabla_u v = \nabla v(., u) More generally for any tensor field `t\in T^{(k,l)}(M)`, we have .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u t = \nabla t(\ldots, u) + \forall u \in\mathfrak{X}(M), \ \nabla_u t = \nabla t(\ldots, u) .. NOTE:: diff --git a/src/sage/manifolds/differentiable/automorphismfield.py b/src/sage/manifolds/differentiable/automorphismfield.py index 29e146deb47..590ee5b82a3 100644 --- a/src/sage/manifolds/differentiable/automorphismfield.py +++ b/src/sage/manifolds/differentiable/automorphismfield.py @@ -66,7 +66,7 @@ class AutomorphismField(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``name`` -- (default: ``None``) name given to the field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the field; @@ -785,7 +785,7 @@ class AutomorphismFieldParal(FreeModuleAutomorphism, TensorFieldParal): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``name`` -- (default: ``None``) name given to the field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the field; diff --git a/src/sage/manifolds/differentiable/automorphismfield_group.py b/src/sage/manifolds/differentiable/automorphismfield_group.py index 00c8e182a03..7b8a66b01b1 100644 --- a/src/sage/manifolds/differentiable/automorphismfield_group.py +++ b/src/sage/manifolds/differentiable/automorphismfield_group.py @@ -5,15 +5,15 @@ `\Phi: U \rightarrow M` to a differentiable manifold `M` (possibly `U = M` and `\Phi=\mathrm{Id}_M`), the *group of tangent-space automorphism fields* associated with `U` and `\Phi` is the general linear group -`\mathrm{GL}(\mathcal{X}(U,\Phi))` of the module `\mathcal{X}(U,\Phi)` of +`\mathrm{GL}(\mathfrak{X}(U,\Phi))` of the module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M\supset \Phi(U)` (see :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). -Note that `\mathcal{X}(U, \Phi)` is a module over +Note that `\mathfrak{X}(U, \Phi)` is a module over `C^k(U)`, the algebra of differentiable scalar fields on `U`. -Elements of `\mathrm{GL}(\mathcal{X}(U, \Phi))` are fields along `U` +Elements of `\mathrm{GL}(\mathfrak{X}(U, \Phi))` are fields along `U` of automorphisms of tangent spaces to `M`. -Two classes implement `\mathrm{GL}(\mathcal{X}(U, \Phi))` depending +Two classes implement `\mathrm{GL}(\mathfrak{X}(U, \Phi))` depending whether `M` is parallelizable or not: :class:`AutomorphismFieldParalGroup` and :class:`AutomorphismFieldGroup`. @@ -57,12 +57,12 @@ class AutomorphismFieldGroup(UniqueRepresentation, Parent): `\Phi: U \rightarrow M` to a differentiable manifold `M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`), the *group of tangent-space automorphism fields* associated with `U` and `\Phi` is the general linear group - `\mathrm{GL}(\mathcal{X}(U,\Phi))` of the module `\mathcal{X}(U,\Phi)` of + `\mathrm{GL}(\mathfrak{X}(U,\Phi))` of the module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M \supset \Phi(U)` (see :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). - Note that `\mathcal{X}(U,\Phi)` is a module over + Note that `\mathfrak{X}(U,\Phi)` is a module over `C^k(U)`, the algebra of differentiable scalar fields on `U`. - Elements of `\mathrm{GL}(\mathcal{X}(U,\Phi))` are fields along `U` of + Elements of `\mathrm{GL}(\mathfrak{X}(U,\Phi))` are fields along `U` of automorphisms of tangent spaces to `M`. .. NOTE:: @@ -74,7 +74,7 @@ class AutomorphismFieldGroup(UniqueRepresentation, Parent): - ``vector_field_module`` -- :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`; - module `\mathcal{X}(U,\Phi)` of vector fields along `U` with values on `M` + module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` EXAMPLES: @@ -95,7 +95,7 @@ class AutomorphismFieldGroup(UniqueRepresentation, Parent): 2-dimensional differentiable manifold M ``G`` is the general linear group of the vector field module - `\mathcal{X}(M)`:: + `\mathfrak{X}(M)`:: sage: XM = M.vector_field_module() ; XM Module X(M) of vector fields on the 2-dimensional differentiable @@ -334,9 +334,9 @@ def _latex_(self): sage: M = Manifold(2, 'M') sage: G = M.automorphism_field_group() sage: G._latex_() - \mathrm{GL}\left( \mathcal{X}\left(M\right) \right) + \mathrm{GL}\left( \mathfrak{X}\left(M\right) \right) sage: latex(G) # indirect doctest - \mathrm{GL}\left( \mathcal{X}\left(M\right) \right) + \mathrm{GL}\left( \mathfrak{X}\left(M\right) \right) """ from sage.misc.latex import latex @@ -388,12 +388,12 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): `\Phi: U \rightarrow M` to a parallelizable manifold `M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`), the *group of tangent-space automorphism fields* associated with `U` and `\Phi` is the general linear group - `\mathrm{GL}(\mathcal{X}(U, \Phi))` of the module `\mathcal{X}(U, \Phi)` + `\mathrm{GL}(\mathfrak{X}(U, \Phi))` of the module `\mathfrak{X}(U, \Phi)` of vector fields along `U` with values on `M \supset \Phi(U)` (see :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`). - Note that `\mathcal{X}(U, \Phi)` is a free module over `C^k(U)`, + Note that `\mathfrak{X}(U, \Phi)` is a free module over `C^k(U)`, the algebra of differentiable scalar fields on `U`. - Elements of `\mathrm{GL}(\mathcal{X}(U, \Phi))` are fields along `U` of + Elements of `\mathrm{GL}(\mathfrak{X}(U, \Phi))` are fields along `U` of automorphisms of tangent spaces to `M`. .. NOTE:: @@ -405,7 +405,7 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): - ``vector_field_module`` -- :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`; - free module `\mathcal{X}(U,\Phi)` of vector fields along `U` + free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` EXAMPLES: @@ -422,10 +422,10 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): General linear group of the Free module X(M) of vector fields on the 2-dimensional differentiable manifold M sage: latex(G) - \mathrm{GL}\left( \mathcal{X}\left(M\right) \right) + \mathrm{GL}\left( \mathfrak{X}\left(M\right) \right) ``G`` is nothing but the general linear group of the module - `\mathcal{X}(M)`:: + `\mathfrak{X}(M)`:: sage: G is XM.general_linear_group() True @@ -452,7 +452,7 @@ class AutomorphismFieldParalGroup(FreeModuleLinearGroup): sage: a.parent() is G True - As automorphisms of `\mathcal{X}(M)`, the elements of ``G`` map a vector + As automorphisms of `\mathfrak{X}(M)`, the elements of ``G`` map a vector field to a vector field:: sage: v = XM.an_element() ; v diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index db84642f52c..666cf2a295b 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -3,7 +3,7 @@ Let `U` and `M` be two differentiable manifolds. Given a positive integer `p` and a differentiable map `\Phi: U \rightarrow M`, -a *differential form of degree* `p`, or *p-form*, +a *differential form of degree* `p`, or `p`-*form*, *along* `U` *with values on* `M` is a field along `U` of alternating multilinear forms of degree `p` in the tangent spaces to `M`. The standard case of a differential form *on* a differentiable manifold @@ -72,22 +72,24 @@ class DiffForm(TensorField): Given a differentiable manifold `U`, a differentiable map `\Phi: U \rightarrow M` to a differentiable manifold `M` and a positive - integer `p`, a *differential form of degree* `p` (or *p-form*) + integer `p`, a *differential form of degree* `p` (or `p`-*form*) *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map .. MATH:: a:\ U \longrightarrow T^{(0,p)}M - (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such - that + (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such that .. MATH:: - a(x) \in \Lambda^p(T_{\Phi(x)} M) + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)}^* M) , - for all `x \in U`, i.e. `a(x)` is an alternating multilinear form - of degree `p` of the tangent space to `M` at the point `\Phi(x)`. + where `T_{\Phi(x)}^* M` is the dual of the tangent space to `M` at + `\Phi(x)` and `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`). + In other words, `a(x)` is an alternating multilinear form of degree `p` of + the tangent vector space `T_{\Phi(x)} M`. The standard case of a differential form *on* a manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other @@ -101,7 +103,7 @@ class DiffForm(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``degree`` -- the degree of the differential form (i.e. its tensor rank) - ``name`` -- (default: ``None``) name given to the differential form @@ -126,7 +128,7 @@ class DiffForm(TensorField): sage: a = M.diff_form(2, name='a') ; a 2-form a on the 2-dimensional differentiable manifold M sage: a.parent() - Module /\^2(M) of 2-forms on the 2-dimensional differentiable + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: a.degree() 2 @@ -146,7 +148,7 @@ class DiffForm(TensorField): sage: a = M.one_form('a') ; a 1-form a on the 2-dimensional differentiable manifold M sage: a.parent() - Module /\^1(M) of 1-forms on the 2-dimensional differentiable + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M sage: a.degree() 1 @@ -398,7 +400,8 @@ def wedge(self, other): OUTPUT: - - a :class:`DiffForm` of the exterior product ``self/\other`` + - instance of :class:`DiffForm` representing the exterior product + ``self/\other`` EXAMPLES: @@ -429,7 +432,6 @@ def wedge(self, other): a/\b = -(v^2 - u)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du/\dv """ - from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm from sage.tensor.modules.format_utilities import is_atomic if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): @@ -596,6 +598,155 @@ def hodge_dual(self, metric): """ return metric.hodge_star(self) + def interior_product(self, qvect): + r""" + Interior product with a multivector field. + + If ``self`` is a differential form `A` of degree `p` and `B` is a + multivector field of degree `q\geq p` on the same manifold, the + interior product of `A` by `B` is the multivector field `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p} + B^{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract` + + INPUT: + + - ``qvect`` -- multivector field `B` (instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField`); + the degree of `B` must be at least equal to the degree of ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + (case `p = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South + sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), + ....: intersection_name='W', restrictions1= x^2+y^2!=0, + ....: restrictions2= u^2+v^2!=0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.one_form(name='a') + sage: a[e_xy,:] = y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.multivector_field(2, name='b') + sage: b[e_xy,1,2] = x*y + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: s = a.interior_product(b); s + Vector field i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display(e_xy) + i_a b = -x^2*y d/dx + x*y^2 d/dy + sage: s.display(e_uv) + i_a b = (u^4*v - 3*u^2*v^3)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) d/du + + (3*u^3*v^2 - u*v^4)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) d/dv + sage: s == a.contract(b) + True + + Interior product of a 2-form with a 2-vector field:: + + sage: a = M.diff_form(2, name='a') + sage: a[e_xy,1,2] = 4/(x^2+y^2+1)^2 # the standard area 2-form + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: s = a.interior_product(b); s + Scalar field i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display() + i_a b: S^2 --> R + on U: (x, y) |--> 8*x*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) + on V: (u, v) |--> 8*u*v/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) + + Some checks:: + + sage: s == a.contract(0, 1, b, 0, 1) + True + sage: s.restrict(U) == 2 * a[[e_xy,1,2]] * b[[e_xy,1,2]] + True + sage: s.restrict(V) == 2 * a[[e_uv,1,2]] * b[[e_uv,1,2]] + True + + """ + from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(qvect._domain): + if not self._ambient_domain.is_subset(qvect._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + elif qvect._domain.is_subset(self._domain): + if not qvect._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + dom_resu = self._domain.intersection(qvect._domain) + ambient_dom_resu = self._ambient_domain.intersection(qvect._ambient_domain) + self_r = self.restrict(dom_resu) + qvect_r = qvect.restrict(dom_resu) + if ambient_dom_resu.is_manifestly_parallelizable(): + # call of the AlternatingContrTensor version: + return AlternatingContrTensor.interior_product(self_r, qvect_r) + # Otherwise, the result is created here: + # Name of the result + resu_name = None + if self._name is not None and qvect._name is not None: + sname = self._name + oname = qvect._name + if not is_atomic(sname): + sname = '(' + sname + ')' + if not is_atomic(oname): + oname = '(' + oname + ')' + resu_name = 'i_' + sname + ' ' + oname + resu_latex_name = None + if self._latex_name is not None and qvect._latex_name is not None: + slname = self._latex_name + olname = qvect._latex_name + if not is_atomic(olname): + olname = r'\left(' + olname + r'\right)' + resu_latex_name = r'\iota_{' + slname + '} ' + olname + # Domain and computation of the result + dest_map = self._vmodule._dest_map + dest_map_resu = dest_map.restrict(dom_resu, + subcodomain=ambient_dom_resu) + vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) + resu_degree = qvect._tensor_rank - self._tensor_rank + resu = vmodule.alternating_contravariant_tensor(resu_degree, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in qvect_r._restrictions: + resu._restrictions[dom] = \ + self_r._restrictions[dom].interior_product( + qvect_r._restrictions[dom]) + if resu_degree == 0: + if not resu._express: # only the restrictions to subdomains have + # been initialized + for chart in dom_resu.top_charts(): + resu._express[chart] = \ + resu.restrict(chart.domain()).coord_function(chart) + return resu #****************************************************************************** @@ -605,22 +756,24 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): Given a differentiable manifold `U`, a differentiable map `\Phi: U \rightarrow M` to a parallelizable manifold `M` and a positive - integer `p`, a *differential form of degree* `p` (or *p-form*) + integer `p`, a *differential form of degree* `p` (or `p`-*form*) *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map .. MATH:: a:\ U \longrightarrow T^{(0,p)}M - (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such - that + (`T^{(0,p)}M` being the tensor bundle of type `(0,p)` over `M`) such that .. MATH:: - a(x) \in \Lambda^p(T_{\Phi(x)} M) + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)}^* M) , - for all `x \in U`, i.e. `a(x)` is an alternating multilinear form - of degree `p` of the tangent space to `M` at the point `\Phi(x)`. + where `T_{\Phi(x)}^* M` is the dual of the tangent space to `M` at + `\Phi(x)` and `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`). + In other words, `a(x)` is an alternating multilinear form of degree `p` of + the tangent vector space `T_{\Phi(x)} M`. The standard case of a differential form *on* a manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` @@ -634,7 +787,7 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M` via the map `\Phi` - ``degree`` -- the degree of the differential form (i.e. its tensor rank) - ``name`` -- (default: ``None``) name given to the differential form @@ -651,7 +804,7 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): sage: a = M.diff_form(2, 'a') ; a 2-form a on the 4-dimensional differentiable manifold M sage: a.parent() - Free module /\^2(M) of 2-forms on the 4-dimensional differentiable + Free module Omega^2(M) of 2-forms on the 4-dimensional differentiable manifold M A differential form is a tensor field of purely covariant type:: @@ -762,18 +915,24 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): A/\B = (x*y*z*sin(x) + x*z*cos(z)) dx/\dy + (x*y*z*cos(y) - y*z*cos(z)) dx/\dz - (x*cos(y) + y*sin(x))*z dy/\dz + Let us check the formula relating the exterior product to the tensor + product for 1-forms:: + + sage: a.wedge(b) == a*b - b*a + True + The tensor product of a 1-form and a 2-form is not a 3-form but a tensor field of type `(0,3)` with less symmetries:: sage: c = a*ab ; c Tensor field A*(A/\B) of type (0,3) on the 3-dimensional differentiable manifold R3 - sage: c.symmetries() # the antisymmetry is only w.r.t. the last two arguments: + sage: c.symmetries() # the antisymmetry is only w.r.t. the last 2 arguments: no symmetry; antisymmetry: (1, 2) sage: d = ab*a ; d Tensor field (A/\B)*A of type (0,3) on the 3-dimensional differentiable manifold R3 - sage: d.symmetries() # the antisymmetry is only w.r.t. the first two arguments: + sage: d.symmetries() # the antisymmetry is only w.r.t. the first 2 arguments: no symmetry; antisymmetry: (0, 1) The exterior derivative of a differential form is obtained by means @@ -825,7 +984,7 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): sage: isinstance(om, sage.manifolds.differentiable.diff_form.DiffFormParal) True sage: om.parent() - Free module /\^1(R3) of 1-forms on the 3-dimensional differentiable + Free module Omega^1(R3) of 1-forms on the 3-dimensional differentiable manifold R3 sage: om.tensor_type() (0, 1) @@ -868,23 +1027,6 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal): sage: c.symmetries() # c has no symmetries: no symmetry; no antisymmetry - The exterior product of two 1-forms is a 2-form:: - - sage: d = a.wedge(b) ; d - 2-form A/\B on the 3-dimensional differentiable manifold R3 - sage: d[:] - [ 0 -7 -14] - [ 7 0 -7] - [ 14 7 0] - sage: d.symmetries() - no symmetry; antisymmetry: (0, 1) - - We can check the standard formula relating the exterior product to the - tensor product:: - - sage: a.wedge(b) == a*b - b*a - True - """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): @@ -1027,7 +1169,7 @@ def __call__(self, *args): sage: s.display() a(u,v): M --> R (x, y) |--> -x*y^3 + 2*x*y^2 + (x^3 + x^2)*y - sage: s == a[[0,1]]*(u[[0]]*v[[1]] -u[[1]]*v[[0]]) + sage: s == a[[0,1]]*(u[[0]]*v[[1]] - u[[1]]*v[[0]]) True sage: s == a(u,v) # indirect doctest True @@ -1189,13 +1331,14 @@ def wedge(self, other): True """ - from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): - raise ValueError("incompatible ambient domains for exterior product") + raise ValueError("incompatible ambient domains for exterior " + + "product") elif other._domain.is_subset(self._domain): if not other._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for exterior product") + raise ValueError("incompatible ambient domains for exterior " + + "product") dom_resu = self._domain.intersection(other._domain) self_r = self.restrict(dom_resu) other_r = other.restrict(dom_resu) @@ -1267,3 +1410,92 @@ def hodge_dual(self, metric): """ return metric.hodge_star(self) + + def interior_product(self, qvect): + r""" + Interior product with a multivector field. + + If ``self`` is a differential form `A` of degree `p` and `B` is a + multivector field of degree `q\geq p` on the same manifold, the + interior product of `A` by `B` is the multivector field `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p} + B^{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract` + + INPUT: + + - ``qvect`` -- multivector field `B` (instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`); + the degree of `B` must be at least equal to the degree of + ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal` + (case `p = M.chart() + sage: a = M.one_form(name='a') + sage: a[:] = [2, 1+x, y*z] + sage: b = M.multivector_field(2, name='b') + sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, -z^2 + sage: s = a.interior_product(b); s + Vector field i_a b on the 3-dimensional differentiable + manifold M + sage: s.display() + i_a b = (-(x + 1)*y^2 - x*y*z - y*z^2) d/dx + + (y*z^3 + 2*y^2) d/dy + (-(x + 1)*z^2 + 2*x + 2*z) d/dz + sage: s == a.contract(b) + True + + Interior product of a 2-form with a 2-vector field:: + + sage: a = M.diff_form(2, name='a') + sage: a[1,2], a[1,3], a[2,3] = x*y, -3, z + sage: s = a.interior_product(b); s + Scalar field i_a b on the 3-dimensional differentiable manifold M + sage: s.display() + i_a b: M --> R + (x, y, z) |--> 2*x*y^3 - 2*z^3 - 6*x - 6*z + sage: s == a.contract(0,1,b,0,1) + True + + """ + if self._domain.is_subset(qvect._domain): + if not self._ambient_domain.is_subset(qvect._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + elif qvect._domain.is_subset(self._domain): + if not qvect._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + dom_resu = self._domain.intersection(qvect._domain) + self_r = self.restrict(dom_resu) + qvect_r = qvect.restrict(dom_resu) + return FreeModuleAltForm.interior_product(self_r, qvect_r) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index 28119a01693..e04fbe78015 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -1,12 +1,12 @@ r""" Differential Form Modules -The set `\Lambda^p(U, \Phi)` of `p`-forms along a differentiable manifold `U` +The set `\Omega^p(U, \Phi)` of `p`-forms along a differentiable manifold `U` with values on a differentiable manifold `M` via a differentiable map `\Phi:\ U \rightarrow M` (possibly `U = M` and `\Phi = \mathrm{Id}_M`) is a module over the algebra `C^k(U)` of differentiable scalar fields on `U`. It is a free module if and only if `M` is parallelizable. Accordingly, -two classes implement `\Lambda^p(U, \Phi)`: +two classes implement `\Omega^p(U, \Phi)`: - :class:`DiffFormModule` for differential forms with values on a generic (in practice, not parallelizable) differentiable manifold `M` @@ -51,7 +51,7 @@ class DiffFormModule(UniqueRepresentation, Parent): Given a differentiable manifold `U` and a differentiable map `\Phi: U \rightarrow M` to a differentiable manifold `M`, the set - `\Lambda^p(U, \Phi)` of `p`-forms along `U` with values on `M` is + `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `M` is a module over `C^k(U)`, the commutative algebra of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). @@ -62,14 +62,14 @@ class DiffFormModule(UniqueRepresentation, Parent): .. NOTE:: - This class implements `\Lambda^p(U,\Phi)` in the case where `M` is - not assumed to be parallelizable; the module `\Lambda^p(U, \Phi)` + This class implements `\Omega^p(U,\Phi)` in the case where `M` is + not assumed to be parallelizable; the module `\Omega^p(U, \Phi)` is then not necessarily free. If `M` is parallelizable, the class :class:`DiffFormFreeModule` must be used instead. INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U, \Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U, \Phi)` of vector fields along `U` with values on `M` via the map `\Phi: U \rightarrow M` - ``degree`` -- positive integer; the degree `p` of the differential forms @@ -90,16 +90,23 @@ class DiffFormModule(UniqueRepresentation, Parent): Module X(M) of vector fields on the 2-dimensional differentiable manifold M sage: A = M.diff_form_module(2) ; A - Module /\^2(M) of 2-forms on the 2-dimensional differentiable manifold M + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable + manifold M sage: latex(A) - \Lambda^{2}\left(M\right) + \Omega^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of the dual of ``XM``, i.e. + we have `\Omega^{2}(M) = \Lambda^2(\mathfrak{X}(M)^*)`:: + + sage: A is XM.dual_exterior_power(2) + True Modules of differential forms are unique:: sage: A is M.diff_form_module(2) True - `\Lambda^2(M)` is a module over the algebra `C^k(M)` of (differentiable) + `\Omega^2(M)` is a module over the algebra `C^k(M)` of (differentiable) scalar fields on `M`:: sage: A.category() @@ -135,7 +142,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: a = A([[0,3*x],[-3*x,0]], frame=eU, name='a') ; a 2-form a on the 2-dimensional differentiable manifold M - sage: a.add_comp_by_continuation(eV, W, c_uv) # finishes the initialization of a + sage: a.add_comp_by_continuation(eV, W, c_uv) # finishes initializ. of a sage: a.display(eU) a = 3*x dx/\dy sage: a.display(eV) @@ -152,16 +159,17 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: a.display(eV) a = (-3/4*u - 3/4*v) du/\dv - The module `\Lambda^1(M)` is nothing but the dual of `\mathcal{X}(M)` + The module `\Omega^1(M)` is nothing but the dual of `\mathfrak{X}(M)` (the module of vector fields on `M`):: sage: L1 = M.diff_form_module(1) ; L1 - Module /\^1(M) of 1-forms on the 2-dimensional differentiable manifold M + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable + manifold M sage: L1 is XM.dual() True Since any tensor field of type `(0,1)` is a 1-form, there is a coercion - map from the set `T^{(0,1)}(M)` of such tensors to `\Lambda^1(M)`:: + map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 Module T^(0,1)(M) of type-(0,1) tensors fields on the 2-dimensional @@ -175,7 +183,7 @@ class DiffFormModule(UniqueRepresentation, Parent): True For a degree `p \geq 2`, the coercion holds only in the direction - `\Lambda^p(M)\rightarrow T^{(0,p)}(M)`:: + `\Omega^p(M)\rightarrow T^{(0,p)}(M)`:: sage: T02 = M.tensor_field_module((0,2)) ; T02 Module T^(0,2)(M) of type-(0,2) tensors fields on the 2-dimensional @@ -185,7 +193,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: A.has_coerce_map_from(T02) False - The coercion map `T^{(0,1)}(M) \rightarrow \Lambda^1(M)` in action:: + The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: sage: b = T01([y,x], frame=eU, name='b') ; b Tensor field b of type (0,1) on the 2-dimensional differentiable @@ -202,7 +210,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: lb.display(eV) b = 1/2*u du - 1/2*v dv - The coercion map `\Lambda^1(M) \rightarrow T^{(0,1)}(M)` in action:: + The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: sage: tlb = T01(lb) ; tlb Tensor field b of type (0,1) on the 2-dimensional differentiable @@ -214,7 +222,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: tlb == b True - The coercion map `\Lambda^2(M) \rightarrow T^{(0,2)}(M)` in action:: + The coercion map `\Omega^2(M) \rightarrow T^{(0,2)}(M)` in action:: sage: ta = T02(a) ; ta Tensor field a of type (0,2) on the 2-dimensional differentiable @@ -232,7 +240,7 @@ class DiffFormModule(UniqueRepresentation, Parent): of the differential form to some subset of its domain:: sage: L2U = U.diff_form_module(2) ; L2U - Free module /\^2(U) of 2-forms on the Open subset U of the + Free module Omega^2(U) of 2-forms on the Open subset U of the 2-dimensional differentiable manifold M sage: L2U.has_coerce_map_from(A) True @@ -264,7 +272,7 @@ def __init__(self, vector_field_module, degree): sage: from sage.manifolds.differentiable.diff_form_module import \ ....: DiffFormModule sage: A = DiffFormModule(M.vector_field_module(), 2) ; A - Module /\^2(M) of 2-forms on the 2-dimensional differentiable + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: TestSuite(A).run(skip='_test_elements') @@ -275,8 +283,8 @@ def __init__(self, vector_field_module, degree): """ domain = vector_field_module._domain dest_map = vector_field_module._dest_map - name = "/\^{}(".format(degree) + domain._name - latex_name = r"\Lambda^{{{}}}\left({}".format(degree, domain._latex_name) + name = "Omega^{}(".format(degree) + domain._name + latex_name = r"\Omega^{{{}}}\left({}".format(degree, domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -372,7 +380,8 @@ def _an_element_(self): if open_covers != []: oc = open_covers[0] # the first non-trivial open cover is selected for dom in oc: - vmodule_dom = dom.vector_field_module(dest_map=self._dest_map.restrict(dom)) + vmodule_dom = dom.vector_field_module( + dest_map=self._dest_map.restrict(dom)) dmodule_dom = vmodule_dom.dual_exterior_power(self._degree) resu.set_restriction(dmodule_dom._an_element_()) return resu @@ -445,7 +454,7 @@ def _repr_(self): sage: M = Manifold(3, 'M') sage: A2 = M.diff_form_module(2) sage: A2 - Module /\^2(M) of 2-forms on + Module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M """ @@ -469,9 +478,9 @@ def _latex_(self): sage: M = Manifold(3, 'M', latex_name=r'\mathcal{M}') sage: A2 = M.diff_form_module(2) sage: A2._latex_() - '\\Lambda^{2}\\left(\\mathcal{M}\\right)' + '\\Omega^{2}\\left(\\mathcal{M}\\right)' sage: latex(A2) # indirect doctest - \Lambda^{2}\left(\mathcal{M}\right) + \Omega^{2}\left(\mathcal{M}\right) """ if self._latex_name is None: @@ -482,20 +491,19 @@ def _latex_(self): def base_module(self): r""" Return the vector field module on which the differential form module - is constructed. + ``self`` is constructed. OUTPUT: - a :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule` - representing the module on which the differential form module is - defined + representing the module on which ``self`` is defined EXAMPLES:: sage: M = Manifold(3, 'M') sage: A2 = M.diff_form_module(2) ; A2 - Module /\^2(M) of 2-forms on the 3-dimensional differentiable + Module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M sage: A2.base_module() Module X(M) of vector fields on the 3-dimensional differentiable @@ -504,8 +512,8 @@ def base_module(self): True sage: U = M.open_subset('U') sage: A2U = U.diff_form_module(2) ; A2U - Module /\^2(U) of 2-forms on the Open subset U of the 3-dimensional - differentiable manifold M + Module Omega^2(U) of 2-forms on the Open subset U of the + 3-dimensional differentiable manifold M sage: A2U.base_module() Module X(U) of vector fields on the Open subset U of the 3-dimensional differentiable manifold M @@ -515,11 +523,11 @@ def base_module(self): def degree(self): r""" - Return the degree of the differential forms in the module. + Return the degree of the differential forms in ``self``. OUTPUT: - - integer `p` such that the module is a set of `p`-forms + - integer `p` such that ``self`` is a set of `p`-forms EXAMPLES:: @@ -542,26 +550,26 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): a differentiable manifold `U` with values on a parallelizable manifold `M`. Given a differentiable manifold `U` and a differentiable map - `\Phi:\; U \rightarrow M` to a parallelizable manifold `M`, the set - `\Lambda^p(U, \Phi)` of `p`-forms along `U` with values on `M` is a - free module over `C^k(U)`, the commutative algebra of differentiable - scalar fields on `U` (see + `\Phi:\; U \rightarrow M` to a parallelizable manifold `M` of dimension + `n`, the set `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `M` + is a free module of rank `\binom{n}{p}` over `C^k(U)`, the commutative + algebra of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). The standard case of `p`-forms *on* a differentiable manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open interval of `\RR`). - This class implements `\Lambda^p(U, \Phi)` in the case where `M` is - parallelizable; `\Lambda^p(U, \Phi)` is then a *free* module. If `M` is not - parallelizable, the class :class:`DiffFormModule` must be used instead. + .. NOTE:: - This is a Sage *parent* class, whose *element* class is - :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal`. + This class implements `\Omega^p(U, \Phi)` in the case where `M` is + parallelizable; `\Omega^p(U, \Phi)` is then a *free* module. If `M` + is not parallelizable, the class :class:`DiffFormModule` must be used + instead. INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow V` - ``degree`` -- positive integer; the degree `p` of the differential forms @@ -575,12 +583,19 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): Free module X(M) of vector fields on the 3-dimensional differentiable manifold M sage: A = M.diff_form_module(2) ; A - Free module /\^2(M) of 2-forms on the 3-dimensional differentiable + Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M sage: latex(A) - \Lambda^{2}\left(M\right) + \Omega^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of the dual of ``XM``, i.e. + we have `\Omega^{2}(M) = \Lambda^2(\mathfrak{X}(M)^*)` (see + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`):: + + sage: A is XM.dual_exterior_power(2) + True - `A` is a module over the algebra `C^k(M)` of (differentiable) + `\Omega^{2}(M)` is a module over the algebra `C^k(M)` of (differentiable) scalar fields on `M`:: sage: A.category() @@ -629,17 +644,17 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: a.display() a = 3*x dx/\dy - z dx/\dz + 4 dy/\dz - The module `\Lambda^1(M)` is nothing but the dual of `\mathcal{X}(M)` + The module `\Omega^1(M)` is nothing but the dual of `\mathfrak{X}(M)` (the free module of vector fields on `M`):: sage: L1 = M.diff_form_module(1) ; L1 - Free module /\^1(M) of 1-forms on the 3-dimensional differentiable + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M sage: L1 is XM.dual() True Since any tensor field of type `(0,1)` is a 1-form, there is a coercion - map from the set `T^{(0,1)}(M)` of such tensors to `\Lambda^1(M)`:: + map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 Free module T^(0,1)(M) of type-(0,1) tensors fields on the @@ -653,7 +668,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): True For a degree `p \geq 2`, the coercion holds only in the direction - `\Lambda^p(M) \rightarrow T^{(0,p)}(M)`:: + `\Omega^p(M) \rightarrow T^{(0,p)}(M)`:: sage: T02 = M.tensor_field_module((0,2)); T02 Free module T^(0,2)(M) of type-(0,2) tensors fields on the @@ -663,7 +678,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: A.has_coerce_map_from(T02) False - The coercion map `T^{(0,1)}(M) \rightarrow \Lambda^1(M)` in action:: + The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: sage: b = T01([-x,2,3*y], name='b'); b Tensor field b of type (0,1) on the 3-dimensional differentiable @@ -675,7 +690,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: lb.display() b = -x dx + 2 dy + 3*y dz - The coercion map `\Lambda^1(M) \rightarrow T^{(0,1)}(M)` in action:: + The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: sage: tlb = T01(lb); tlb Tensor field b of type (0,1) on @@ -683,7 +698,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: tlb == b True - The coercion map `\Lambda^2(M) \rightarrow T^{(0,2)}(M)` in action:: + The coercion map `\Omega^2(M) \rightarrow T^{(0,2)}(M)` in action:: sage: T02 = M.tensor_field_module((0,2)) ; T02 Free module T^(0,2)(M) of type-(0,2) tensors fields on the @@ -699,11 +714,11 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): no symmetry; antisymmetry: (0, 1) There is also coercion to subdomains, which is nothing but the - restrictionof the differential form to some subset of its domain:: + restriction of the differential form to some subset of its domain:: sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}) sage: B = U.diff_form_module(2) ; B - Free module /\^2(U) of 2-forms on the Open subset U of the + Free module Omega^2(U) of 2-forms on the Open subset U of the 3-dimensional differentiable manifold M sage: B.has_coerce_map_from(A) True @@ -727,15 +742,15 @@ def __init__(self, vector_field_module, degree): sage: X. = M.chart() sage: from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule sage: A = DiffFormFreeModule(M.vector_field_module(), 2) ; A - Free module /\^2(M) of 2-forms on + Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M sage: TestSuite(A).run() """ domain = vector_field_module._domain dest_map = vector_field_module._dest_map - name = "/\^{}(".format(degree) + domain._name - latex_name = r"\Lambda^{{{}}}\left({}".format(degree, domain._latex_name) + name = "Omega^{}(".format(degree) + domain._name + latex_name = r"\Omega^{{{}}}\left({}".format(degree, domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -849,7 +864,7 @@ def _repr_(self): sage: X. = M.chart() sage: A = M.diff_form_module(2) sage: A - Free module /\^2(M) of 2-forms on + Free module Omega^2(M) of 2-forms on the 3-dimensional differentiable manifold M """ diff --git a/src/sage/manifolds/differentiable/diff_map.py b/src/sage/manifolds/differentiable/diff_map.py index 4e897f48b66..366a6c0518a 100644 --- a/src/sage/manifolds/differentiable/diff_map.py +++ b/src/sage/manifolds/differentiable/diff_map.py @@ -928,7 +928,8 @@ def _pullback_chart(diff_map, tensor): dom1 = diff_map._domain dom2 = diff_map._codomain ncov = tensor._tensor_type[1] - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if diff_map._name is not None and tensor._name is not None: resu_name = diff_map._name + '_*(' + tensor._name + ')' if (diff_map._latex_name is not None and @@ -1001,7 +1002,8 @@ def _pullback_chart(diff_map, tensor): if ncon != 0: raise TypeError("the pullback cannot be taken on a tensor " + "with some contravariant part") - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if self._name is not None and tensor._name is not None: resu_name = self._name + '_*(' + tensor._name + ')' if self._latex_name is not None and tensor._latex_name is not None: @@ -1214,7 +1216,8 @@ def pushforward(self, tensor): res += t ptcomp[ind_new] = res # Name of the result: - resu_name = None ; resu_latex_name = None + resu_name = None + resu_latex_name = None if self._name is not None and tensor._name is not None: resu_name = self._name + '^*(' + tensor._name + ')' if self._latex_name is not None and tensor._latex_name is not None: diff --git a/src/sage/manifolds/differentiable/levi_civita_connection.py b/src/sage/manifolds/differentiable/levi_civita_connection.py index 332ed94dc51..2abc51be5f3 100644 --- a/src/sage/manifolds/differentiable/levi_civita_connection.py +++ b/src/sage/manifolds/differentiable/levi_civita_connection.py @@ -42,7 +42,7 @@ class LeviCivitaConnection(AffineConnection): Let `C^\infty(M)` be the algebra of smooth functions `M\rightarrow \RR` (cf. :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`) - and let `\mathcal{X}(M)` be the `C^\infty(M)`-module of vector fields on + and let `\mathfrak{X}(M)` be the `C^\infty(M)`-module of vector fields on `M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`). The *Levi-Civita connection associated with* `g` is the unique operator @@ -50,14 +50,14 @@ class LeviCivitaConnection(AffineConnection): .. MATH:: \begin{array}{cccc} - \nabla: & \mathcal{X}(M)\times \mathcal{X}(M) & \longrightarrow & - \mathcal{X}(M) \\ + \nabla: & \mathfrak{X}(M)\times \mathfrak{X}(M) & \longrightarrow & + \mathfrak{X}(M) \\ & (u,v) & \longmapsto & \nabla_u v \end{array} that - - is `\RR`-bilinear, i.e. is bilinear when considering `\mathcal{X}(M)` as + - is `\RR`-bilinear, i.e. is bilinear when considering `\mathfrak{X}(M)` as a vector space over `\RR` - is `C^\infty(M)`-linear w.r.t. the first argument: `\forall f\in C^\infty(M),\ \nabla_{fu} v = f\nabla_u v` @@ -65,7 +65,7 @@ class LeviCivitaConnection(AffineConnection): `\forall f\in C^\infty(M),\ \nabla_u (f v) = \mathrm{d}f(u)\, v + f \nabla_u v` - is torsion-free - is compatible with `g`: - `\forall (u,v,w)\in \mathcal{X}(M)^3,\ u(g(v,w)) = g(\nabla_u v, w) + g(v, \nabla_u w)` + `\forall (u,v,w)\in \mathfrak{X}(M)^3,\ u(g(v,w)) = g(\nabla_u v, w) + g(v, \nabla_u w)` The Levi-Civita connection `\nabla` gives birth to the *covariant derivative operator* acting on tensor fields, denoted by the same symbol: @@ -86,13 +86,13 @@ class LeviCivitaConnection(AffineConnection): .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u v = \nabla v(., u) + \forall u \in\mathfrak{X}(M), \ \nabla_u v = \nabla v(., u) More generally for any tensor field `t\in T^{(k,l)}(M)`, we have .. MATH:: - \forall u \in\mathcal{X}(M), \ \nabla_u t = \nabla t(\ldots, u) + \forall u \in\mathfrak{X}(M), \ \nabla_u t = \nabla t(\ldots, u) .. NOTE:: diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index e470a39e42f..21fff90374c 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -253,7 +253,8 @@ sage: df.display(stereoS.frame()) df = -2*u/(u^4 + 2*u^2*v^2 + v^4 + 1) du - 2*v/(u^4 + 2*u^2*v^2 + v^4 + 1) dv sage: df.parent() - Module /\^1(S^2) of 1-forms on the 2-dimensional differentiable manifold S^2 + Module Omega^1(S^2) of 1-forms on the 2-dimensional differentiable + manifold S^2 sage: df.parent().category() Category of modules over Algebra of differentiable scalar fields on the 2-dimensional differentiable manifold S^2 @@ -1096,12 +1097,12 @@ def vector_field_module(self, dest_map=None, force_free=False): :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule` (or if `N` is parallelizable, a :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`) - representing the module `\mathcal{X}(M,\Phi)` of vector fields on + representing the module `\mathfrak{X}(M,\Phi)` of vector fields on `M` taking values on `\Phi(M)\subset N` EXAMPLES: - Vector field module `\mathcal{X}(U) := \mathcal{X}(U,\mathrm{Id}_U)` + Vector field module `\mathfrak{X}(U) := \mathfrak{X}(U,\mathrm{Id}_U)` of the complement `U` of the two poles on the sphere `\mathbb{S}^2`:: sage: S2 = Manifold(2, 'S^2') @@ -1120,7 +1121,7 @@ def vector_field_module(self, dest_map=None, force_free=False): sage: XU.base_ring() is U.scalar_field_algebra() True - `\mathcal{X}(U)` is a free module because `U` is parallelizable + `\mathfrak{X}(U)` is a free module because `U` is parallelizable (being a chart domain):: sage: U.is_manifestly_parallelizable() @@ -1131,7 +1132,7 @@ def vector_field_module(self, dest_map=None, force_free=False): sage: XU.rank() 2 - The elements of `\mathcal{X}(U)` are vector fields on `U`:: + The elements of `\mathfrak{X}(U)` are vector fields on `U`:: sage: XU.an_element() Vector field on the Open subset U of the 2-dimensional @@ -1139,7 +1140,7 @@ def vector_field_module(self, dest_map=None, force_free=False): sage: XU.an_element().display() 2 d/dth + 2 d/dph - Vector field module `\mathcal{X}(U,\Phi)` of the + Vector field module `\mathfrak{X}(U,\Phi)` of the `\RR^3`-valued vector fields along `U`, associated with the embedding `\Phi` of `\mathbb{S}^2` into `\RR^3`:: @@ -1155,7 +1156,7 @@ def vector_field_module(self, dest_map=None, force_free=False): Algebra of differentiable scalar fields on the Open subset U of the 2-dimensional differentiable manifold S^2 - `\mathcal{X}(U,\Phi)` is a free module because `\RR^3` + `\mathfrak{X}(U,\Phi)` is a free module because `\RR^3` is parallelizable and its rank is 3:: sage: XU_R3.rank() @@ -1266,7 +1267,7 @@ def diff_form_module(self, degree, dest_map=None): :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormModule` (or if `N` is parallelizable, a :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormFreeModule`) - representing the module `\Lambda^p(M,\Phi)` of `p`-forms on `M` + representing the module `\Omega^p(M,\Phi)` of `p`-forms on `M` taking values on `\Phi(M)\subset N` EXAMPLES: @@ -1276,12 +1277,12 @@ def diff_form_module(self, degree, dest_map=None): sage: M = Manifold(3, 'M') sage: X. = M.chart() sage: M.diff_form_module(2) - Free module /\^2(M) of 2-forms on the 3-dimensional differentiable - manifold M + Free module Omega^2(M) of 2-forms on the 3-dimensional + differentiable manifold M sage: M.diff_form_module(2).category() Category of finite dimensional modules over Algebra of - differentiable scalar fields on the 3-dimensional differentiable - manifold M + differentiable scalar fields on the 3-dimensional + differentiable manifold M sage: M.diff_form_module(2).base_ring() Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold M @@ -1296,6 +1297,66 @@ def diff_form_module(self, degree, dest_map=None): """ return self.vector_field_module(dest_map=dest_map).dual_exterior_power(degree) + def multivector_module(self, degree, dest_map=None): + r""" + Return the set of multivector fields of a given degree defined + on ``self``, possibly with values in another manifold, as a + module over the algebra of scalar fields defined on ``self``. + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + for complete documentation. + + INPUT: + + - ``degree`` -- positive integer; the degree `p` of the + multivector fields + - ``dest_map`` -- (default: ``None``) destination map, i.e. a + differentiable map `\Phi:\ M \rightarrow N`, where `M` is the + current manifold and `N` a differentiable manifold; + if ``None``, it is assumed that `N = M` and that `\Phi` is the + identity map (case of multivector fields *on* `M`), otherwise + ``dest_map`` must be a + :class:`~sage.manifolds.differentiable.diff_map.DiffMap` + + OUTPUT: + + - a + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + (or if `N` is parallelizable, a + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorFreeModule`) + representing the module `\Omega^p(M,\Phi)` of `p`-forms on `M` + taking values on `\Phi(M)\subset N` + + EXAMPLES: + + Module of 2-vector fields on a 3-dimensional parallelizable + manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: M.multivector_module(2) + Free module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + sage: M.multivector_module(2).category() + Category of finite dimensional modules over Algebra of + differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: M.multivector_module(2).base_ring() + Algebra of differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: M.multivector_module(2).rank() + 3 + + The outcome is cached:: + + sage: M.multivector_module(2) is M.multivector_module(2) + True + + """ + return self.vector_field_module(dest_map=dest_map).exterior_power(degree) + def automorphism_field_group(self, dest_map=None): r""" Return the group of tangent-space automorphism fields defined on @@ -1305,8 +1366,8 @@ def automorphism_field_group(self, dest_map=None): If `M` is the current manifold and `\Phi` a differentiable map `\Phi: M \rightarrow N`, where `N` is a differentiable manifold, this method called with ``dest_map`` being `\Phi` returns the - general linear group `\mathrm{GL}(\mathcal{X}(M, \Phi))` of the module - `\mathcal{X}(M, \Phi)` of vector fields along `M` with values in + general linear group `\mathrm{GL}(\mathfrak{X}(M, \Phi))` of the module + `\mathfrak{X}(M, \Phi)` of vector fields along `M` with values in `\Phi(M) \subset N`. INPUT: @@ -1325,7 +1386,7 @@ def automorphism_field_group(self, dest_map=None): (if `N` is parallelizable) or a :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldGroup` (if `N` is not parallelizable) representing - `\mathrm{GL}(\mathcal{X}(U, \Phi))` + `\mathrm{GL}(\mathfrak{X}(U, \Phi))` EXAMPLES: @@ -1411,7 +1472,7 @@ def vector_field(self, name=None, latex_name=None, dest_map=None): Vector field v on the Open subset U of the 3-dimensional differentiable manifold M - The vector fields on `U` form the set `\mathcal{X}(U)`, which is a + The vector fields on `U` form the set `\mathfrak{X}(U)`, which is a module over the algebra `C^k(U)` of differentiable scalar fields on `U`:: @@ -1688,6 +1749,91 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` return self.tensor_field(0, 2, name=name, latex_name=latex_name, sym=(0,1)) + def multivector_field(self, degree, name=None, latex_name=None, + dest_map=None): + r""" + Define a multivector field on ``self``. + + Via the argument ``dest_map``, it is possible to let the + multivector field take its values on another manifold. More + precisely, if `M` is the current manifold, `N` a differentiable + manifold, `\Phi:\ M \rightarrow N` a differentiable map and `p` + a non-negative integer, a *multivector field of degree* `p` (or + `p`-*vector field*) *along* `M` *with values on* `N` is a + differentiable map + + .. MATH:: + + t:\ M \longrightarrow T^{(p,0)} N + + (`T^{(p,0)} N` being the tensor bundle of type `(p,0)` over `N`) + such that + + .. MATH:: + + \forall x \in M,\quad t(x) \in \Lambda^p(T_{\Phi(x)} N), + + where `\Lambda^p(T_{\Phi(x)} N)` is the `p`-th exterior power + of the tangent vector space `T_{\Phi(x)} N`. + + The standard case of a `p`-vector field *on* `M` corresponds + to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are + `\Phi` being an immersion and `\Phi` being a curve in `N` (`M` + is then an open interval of `\RR`). + + For `p = 1`, one can use the method + :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.vector_field` + instead. + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + for complete documentation. + + INPUT: + + - ``degree`` -- the degree `p` of the multivector field (i.e. + its tensor rank) + - ``name`` -- (default: ``None``) name given to the multivector + field + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote + the multivector field; if none is provided, the LaTeX symbol + is set to ``name`` + - ``dest_map`` -- (default: ``None``) the destination map + `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that + `N = M` and that `\Phi` is the identity map (case of a + multivector field *on* `M`), otherwise ``dest_map`` must be a + :class:`~sage.manifolds.differentiable.diff_map.DiffMap` + + OUTPUT: + + - the `p`-vector field as a + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + (or if `N` is parallelizable, a + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal`) + + EXAMPLES: + + A 2-vector field on a open subset of a 4-dimensional + differentiable manifold:: + + sage: M = Manifold(4, 'M') + sage: A = M.open_subset('A', latex_name=r'\mathcal{A}'); A + Open subset A of the 4-dimensional differentiable manifold M + sage: c_xyzt. = A.chart() + sage: h = A.multivector_field(2, 'H'); h + 2-vector field H on the Open subset A of the 4-dimensional + differentiable manifold M + + See the documentation of class + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + for more examples. + + """ + vmodule = self.vector_field_module(dest_map) + return vmodule.alternating_contravariant_tensor(degree, + name=name, latex_name=latex_name) + def diff_form(self, degree, name=None, latex_name=None, dest_map=None): r""" @@ -1698,7 +1844,8 @@ def diff_form(self, degree, name=None, latex_name=None, precisely, if `M` is the current manifold, `N` a differentiable manifold, `\Phi:\ M \rightarrow N` a differentiable map and `p` a non-negative integer, a *differential form of degree* `p` (or - `p`-form) *along* `M` *with values on* `N` is a differentiable map + `p`-*form*) *along* `M` *with values on* `N` is a differentiable + map .. MATH:: @@ -1709,15 +1856,15 @@ def diff_form(self, degree, name=None, latex_name=None, .. MATH:: - \forall p \in M,\ t(p) \in \Lambda^p(T^*_{\Phi(p)} N), + \forall x \in M,\quad t(x) \in \Lambda^p(T^*_{\Phi(x)} N), - where `\Lambda^p(T^*_{\Phi(p)} N)` is the `p`-th exterior power - of the dual of the tangent space `T_{\Phi(p)} N`. + where `\Lambda^p(T^*_{\Phi(x)} N)` is the `p`-th exterior power + of the dual of the tangent space `T_{\Phi(x)} N`. The standard case of a differential form *on* `M` corresponds - to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` - being an immersion and `\Phi` being a curve in `N` (`M` is then - an open interval of `\RR`). + to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are + `\Phi` being an immersion and `\Phi` being a curve in `N` (`M` + is then an open interval of `\RR`). For `p = 1`, one can use the method :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.one_form` @@ -1725,21 +1872,22 @@ def diff_form(self, degree, name=None, latex_name=None, .. SEEALSO:: - :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for - complete documentation. + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + for complete documentation. INPUT: - - ``degree`` -- the degree `p` of the differential form (i.e. its - tensor rank) - - ``name`` -- (default: ``None``) name given to the differential form - - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the - differential form; if none is provided, the LaTeX symbol is set to - ``name`` + - ``degree`` -- the degree `p` of the differential form (i.e. + its tensor rank) + - ``name`` -- (default: ``None``) name given to the differential + form + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote + the differential form; if none is provided, the LaTeX symbol + is set to ``name`` - ``dest_map`` -- (default: ``None``) the destination map - `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that `N = M` - and that `\Phi` is the identity map (case of a differential - form *on* `M`), otherwise ``dest_map`` must be a + `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that + `N = M` and that `\Phi` is the identity map (case of a + differential form *on* `M`), otherwise ``dest_map`` must be a :class:`~sage.manifolds.differentiable.diff_map.DiffMap` OUTPUT: @@ -1751,19 +1899,20 @@ def diff_form(self, degree, name=None, latex_name=None, EXAMPLES: - A 2-form on a open subset of a 4-dimensional differentiable manifold:: + A 2-form on a open subset of a 4-dimensional differentiable + manifold:: sage: M = Manifold(4, 'M') sage: A = M.open_subset('A', latex_name=r'\mathcal{A}'); A Open subset A of the 4-dimensional differentiable manifold M sage: c_xyzt. = A.chart() sage: f = A.diff_form(2, 'F'); f - 2-form F on the Open subset A of the 4-dimensional differentiable - manifold M + 2-form F on the Open subset A of the 4-dimensional + differentiable manifold M See the documentation of class - :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for more - examples. + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for + more examples. """ vmodule = self.vector_field_module(dest_map) @@ -1778,7 +1927,8 @@ def one_form(self, name=None, latex_name=None, dest_map=None): 1-form take its values on another manifold. More precisely, if `M` is the current manifold, `N` a differentiable manifold and `\Phi:\ M \rightarrow N` a differentiable map, - a *1-form along* `M` *with values on* `N` is a differentiable map + a *1-form along* `M` *with values on* `N` is a differentiable + map .. MATH:: @@ -1788,9 +1938,10 @@ def one_form(self, name=None, latex_name=None, dest_map=None): .. MATH:: - \forall p \in M,\ t(p) \in T^*_{\Phi(p)}N, + \forall p \in M,\quad t(p) \in T^*_{\Phi(p)}N, - where `T^*_{\Phi(p)}` is the dual of the tangent space `T_{\Phi(p)} N`. + where `T^*_{\Phi(p)}` is the dual of the tangent space + `T_{\Phi(p)} N`. The standard case of a 1-form *on* `M` corresponds to `N = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` @@ -1799,18 +1950,19 @@ def one_form(self, name=None, latex_name=None, dest_map=None): .. SEEALSO:: - :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for - complete documentation. + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + for complete documentation. INPUT: - ``name`` -- (default: ``None``) name given to the 1-form - - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the - 1-form; if none is provided, the LaTeX symbol is set to ``name`` + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote + the 1-form; if none is provided, the LaTeX symbol is set to + ``name`` - ``dest_map`` -- (default: ``None``) the destination map - `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that `N = M` - and that `\Phi` is the identity map (case of a 1-form *on* `M`), - otherwise ``dest_map`` must be a + `\Phi:\ M \rightarrow N`; if ``None``, it is assumed that + `N = M` and that `\Phi` is the identity map (case of a 1-form + *on* `M`), otherwise ``dest_map`` must be a :class:`~sage.manifolds.differentiable.diff_map.DiffMap` OUTPUT: @@ -1831,8 +1983,8 @@ def one_form(self, name=None, latex_name=None, dest_map=None): 1-form omega on the Open subset A of the 3-dimensional differentiable manifold M sage: om.parent() - Free module /\^1(A) of 1-forms on the Open subset A of the - 3-dimensional differentiable manifold M + Free module Omega^1(A) of 1-forms on the Open subset A of + the 3-dimensional differentiable manifold M .. SEEALSO:: @@ -1843,7 +1995,8 @@ def one_form(self, name=None, latex_name=None, dest_map=None): vmodule = self.vector_field_module(dest_map) return vmodule.linear_form(name=name, latex_name=latex_name) - def automorphism_field(self, name=None, latex_name=None, dest_map=None): + def automorphism_field(self, name=None, latex_name=None, + dest_map=None): r""" Define a field of automorphisms (invertible endomorphisms in each tangent space) on ``self``. @@ -1920,7 +2073,8 @@ def automorphism_field(self, name=None, latex_name=None, dest_map=None): vmodule = self.vector_field_module(dest_map) return vmodule.automorphism(name=name, latex_name=latex_name) - def tangent_identity_field(self, name='Id', latex_name=None, dest_map=None): + def tangent_identity_field(self, name='Id', latex_name=None, + dest_map=None): r""" Return the field of identity maps in the tangent spaces on ``self``. diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 7d98cf60163..3cd6ad32357 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -69,7 +69,7 @@ class PseudoRiemannianMetric(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `\Phi(U)\subset M` - ``name`` -- name given to the metric - ``signature`` -- (default: ``None``) signature `S` of the metric as a @@ -1597,7 +1597,6 @@ def volume_form(self, contra=0): sage: latex(eps) \epsilon_{g} - The tensor field of components `\epsilon^i_{\ \, jk}` (``contra=1``):: sage: eps1 = g.volume_form(1) ; eps1 @@ -1625,8 +1624,10 @@ def volume_form(self, contra=0): The tensor field of components `\epsilon^{ijk}` (``contra=3``):: sage: eps3 = g.volume_form(3) ; eps3 - Tensor field of type (3,0) on the Open subset U of the - 3-dimensional differentiable manifold M + 3-vector field on the Open subset U of the 3-dimensional + differentiable manifold M + sage: eps3.tensor_type() + (3, 0) sage: eps3.symmetries() no symmetry; antisymmetry: (0, 1, 2) sage: eps3[:] @@ -1881,7 +1882,7 @@ class PseudoRiemannianMetricParal(PseudoRiemannianMetric, TensorFieldParal): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `\Phi(U)\subset M` - ``name`` -- name given to the metric - ``signature`` -- (default: ``None``) signature `S` of the metric as a diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py new file mode 100644 index 00000000000..699d2c48be7 --- /dev/null +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -0,0 +1,795 @@ +r""" +Multivector Field Modules + +The set `A^p(U, \Phi)` of `p`-vector fields along a differentiable +manifold `U` with values on a differentiable manifold `M` via a +differentiable map `\Phi:\ U \rightarrow M` (possibly `U = M` and +`\Phi = \mathrm{Id}_M`) is a module over the algebra `C^k(U)` of +differentiable scalar fields on `U`. It is a free module if and only if +`M` is parallelizable. Accordingly, two classes implement +`A^p(U,\Phi)`: + +- :class:`MultivectorModule` for `p`-vector fields with values on a + generic (in practice, not parallelizable) differentiable manifold `M` +- :class:`MultivectorFreeModule` for `p`-vector fields with values on a + parallelizable manifold `M` + +AUTHORS: + +- Eric Gourgoulhon (2017): initial version + +REFERENCES: + +- \R. L. Bishop and S. L. Goldberg (1980) [BG1980]_ +- \C.-M. Marle (1997) [Mar1997]_ + +""" +#****************************************************************************** +# Copyright (C) 2017 Eric Gourgoulhon +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.rings.integer import Integer +from sage.categories.modules import Modules +from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, MultivectorFieldParal) + +class MultivectorModule(UniqueRepresentation, Parent): + r""" + Module of multivector fields of a given degree `p` (`p`-vector + fields) along a differentiable manifold `U` with values on a + differentiable manifold `M`. + + Given a differentiable manifold `U` and a differentiable map + `\Phi: U \rightarrow M` to a differentiable manifold `M`, the set + `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor fields + of type `(p,0)`) along `U` with values on `M` is a module over + `C^k(U)`, the commutative algebra of differentiable scalar fields on + `U` (see + :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). + The standard case of `p`-vector fields *on* a differentiable + manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. + Other common cases are `\Phi` being an immersion and `\Phi` being a + curve in `M` (`U` is then an open interval of `\RR`). + + .. NOTE:: + + This class implements `A^p(U,\Phi)` in the case where `M` is + not assumed to be parallelizable; the module `A^p(U, \Phi)` + is then not necessarily free. If `M` is parallelizable, the + class :class:`MultivectorFreeModule` must be used instead. + + INPUT: + + - ``vector_field_module`` -- module `\mathfrak{X}(U, \Phi)` of vector + fields along `U` with values on `M` via the map + `\Phi: U \rightarrow M` + - ``degree`` -- positive integer; the degree `p` of the multivector + fields + + EXAMPLES: + + Module of 2-vector fields on a non-parallelizable 2-dimensional + manifold:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # M is the union of U and V + sage: c_xy. = U.chart() ; c_uv. = V.chart() + sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), + ....: intersection_name='W', restrictions1= x>0, + ....: restrictions2= u+v>0) + sage: inv = transf.inverse() + sage: W = U.intersection(V) + sage: eU = c_xy.frame() ; eV = c_uv.frame() + sage: XM = M.vector_field_module() ; XM + Module X(M) of vector fields on the 2-dimensional differentiable + manifold M + sage: A = M.multivector_module(2) ; A + Module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M + sage: latex(A) + A^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of of ``XM``, i.e. + we have `A^{2}(M) = \Lambda^2(\mathfrak{X}(M))`:: + + sage: A is XM.exterior_power(2) + True + + Modules of multivector fields are unique:: + + sage: A is M.multivector_module(2) + True + + `A^2(M)` is a module over the algebra `C^k(M)` of (differentiable) + scalar fields on `M`:: + + sage: A.category() + Category of modules over Algebra of differentiable scalar fields + on the 2-dimensional differentiable manifold M + sage: CM = M.scalar_field_algebra() ; CM + Algebra of differentiable scalar fields on the 2-dimensional + differentiable manifold M + sage: A in Modules(CM) + True + sage: A.base_ring() is CM + True + sage: A.base_module() + Module X(M) of vector fields on the 2-dimensional differentiable + manifold M + sage: A.base_module() is XM + True + + Elements can be constructed from ``A()``. In particular, ``0`` + yields the zero element of ``A``:: + + sage: z = A(0) ; z + 2-vector field zero on the 2-dimensional differentiable + manifold M + sage: z.display(eU) + zero = 0 + sage: z.display(eV) + zero = 0 + sage: z is A.zero() + True + + while non-zero elements are constructed by providing their + components in a given vector frame:: + + sage: a = A([[0,3*x],[-3*x,0]], frame=eU, name='a') ; a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a.add_comp_by_continuation(eV, W, c_uv) # finishes initializ. of a + sage: a.display(eU) + a = 3*x d/dx/\d/dy + sage: a.display(eV) + a = (-3*u - 3*v) d/du/\d/dv + + An alternative is to construct the 2-vector field from an empty list + of components and to set the nonzero nonredundant components + afterwards:: + + sage: a = A([], name='a') + sage: a[eU,0,1] = 3*x + sage: a.add_comp_by_continuation(eV, W, c_uv) + sage: a.display(eU) + a = 3*x d/dx/\d/dy + sage: a.display(eV) + a = (-3*u - 3*v) d/du/\d/dv + + The module `A^1(M)` is nothing but the dual of `\mathfrak{X}(M)` + (the module of vector fields on `M`):: + + sage: A1 = M.multivector_module(1) ; A1 + Module X(M) of vector fields on the 2-dimensional differentiable + manifold M + sage: A1 is XM + True + + There is a coercion map `A^p(M)\rightarrow T^{(p,0)}(M)`:: + + sage: T20 = M.tensor_field_module((2,0)) ; T20 + Module T^(2,0)(M) of type-(2,0) tensors fields on the + 2-dimensional differentiable manifold M + sage: T20.has_coerce_map_from(A) + True + + but of course not in the reverse direction, since not all contravariant + tensor field is alternating:: + + sage: A.has_coerce_map_from(T20) + False + + The coercion map `A^2(M) \rightarrow T^{(2,0)}(M)` in action:: + + sage: ta = T20(a) ; ta + Tensor field a of type (2,0) on the 2-dimensional differentiable + manifold M + sage: ta.display(eU) + a = 3*x d/dx*d/dy - 3*x d/dy*d/dx + sage: a.display(eU) + a = 3*x d/dx/\d/dy + sage: ta.display(eV) + a = (-3*u - 3*v) d/du*d/dv + (3*u + 3*v) d/dv*d/du + sage: a.display(eV) + a = (-3*u - 3*v) d/du/\d/dv + + There is also coercion to subdomains, which is nothing but the + restriction of the multivector field to some subset of its domain:: + + sage: A2U = U.multivector_module(2) ; A2U + Free module A^2(U) of 2-vector fields on the Open subset U of + the 2-dimensional differentiable manifold M + sage: A2U.has_coerce_map_from(A) + True + sage: a_U = A2U(a) ; a_U + 2-vector field a on the Open subset U of the 2-dimensional + differentiable manifold M + sage: a_U.display(eU) + a = 3*x d/dx/\d/dy + + """ + Element = MultivectorField + + def __init__(self, vector_field_module, degree): + r""" + Construction a module of multivector fields. + + TESTS: + + Module of 2-vector fields on a non-parallelizable 2-dimensional + manifold:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # M is the union of U and V + sage: c_xy. = U.chart() ; c_uv. = V.chart() + sage: transf = c_xy.transition_map(c_uv, (x+y, x-y), + ....: intersection_name='W', restrictions1= x>0, + ....: restrictions2= u+v>0) + sage: inv = transf.inverse() + sage: from sage.manifolds.differentiable.multivector_module import \ + ....: MultivectorModule + sage: A = MultivectorModule(M.vector_field_module(), 2) ; A + Module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M + sage: TestSuite(A).run(skip='_test_elements') + + In the above test suite, ``_test_elements`` is skipped because + of the ``_test_pickling`` error of the elements (to be fixed in + :class:`sage.manifolds.differentialbe.tensorfield.TensorField`) + + """ + domain = vector_field_module._domain + dest_map = vector_field_module._dest_map + name = "A^{}(".format(degree) + domain._name + latex_name = r"A^{{{}}}\left({}".format(degree, + domain._latex_name) + if dest_map is domain.identity_map(): + name += ")" + latex_name += r"\right)" + else: + name += "," + dest_map._name + ")" + latex_name += "," + dest_map._latex_name + r"\right)" + self._vmodule = vector_field_module + self._degree = degree + self._name = name + self._latex_name = latex_name + # the member self._ring is created for efficiency (to avoid + # calls to self.base_ring()): + self._ring = domain.scalar_field_algebra() + Parent.__init__(self, base=self._ring, + category=Modules(self._ring)) + self._domain = domain + self._dest_map = dest_map + self._ambient_domain = vector_field_module._ambient_domain + # NB: self._zero_element is not constructed here, since no + # element can be constructed here, to avoid some infinite + # recursion. + + #### Parent methods + + def _element_constructor_(self, comp=[], frame=None, name=None, + latex_name=None): + r""" + Construct a multivector field. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U'); V = M.open_subset('V') + sage: c_xy. = U.chart(); c_uv. = V.chart() + sage: M.declare_union(U,V) + sage: A = M.multivector_module(2) + sage: a = A([[0, x*y], [-x*y, 0]], name='a'); a + 2-vector field a on the 2-dimensional differentiable + manifold M + sage: a.display(c_xy.frame()) + a = x*y d/dx/\d/dy + sage: A(0) is A.zero() + True + + """ + if isinstance(comp, (int, Integer)) and comp == 0: + return self.zero() + if isinstance(comp, (MultivectorField, MultivectorFieldParal)): + # coercion by domain restriction + if (self._degree == comp._tensor_type[0] + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset( + comp._ambient_domain)): + return comp.restrict(self._domain) + else: + raise TypeError("cannot convert the {} ".format(comp) + + "to an element of {}".format(self)) + # standard construction + resu = self.element_class(self._vmodule, self._degree, + name=name, latex_name=latex_name) + if comp: + resu.set_comp(frame)[:] = comp + return resu + + def _an_element_(self): + r""" + Construct some (unnamed) multivector field. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U'); V = M.open_subset('V') + sage: c_xy. = U.chart(); c_uv. = V.chart() + sage: M.declare_union(U,V) + sage: A = M.multivector_module(2) + sage: A._an_element_() + 2-vector field on the 2-dimensional differentiable + manifold M + + """ + resu = self.element_class(self._vmodule, self._degree) + # Non-trivial open covers of the domain: + open_covers = self._domain.open_covers()[1:] # the open cover 0 + # is trivial + if open_covers != []: + oc = open_covers[0] # the first non-trivial open cover is + # selected + for dom in oc: + vmodule_dom = dom.vector_field_module( + dest_map=self._dest_map.restrict(dom)) + dmodule_dom = vmodule_dom.exterior_power(self._degree) + resu.set_restriction(dmodule_dom._an_element_()) + return resu + + def _coerce_map_from_(self, other): + r""" + Determine whether coercion to ``self`` exists from other parent. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: A2 = M.multivector_module(2) + sage: A2._coerce_map_from_(M.tensor_field_module((2,0))) + False + sage: U = M.open_subset('U') + sage: A2U = U.multivector_module(2) + sage: A2U._coerce_map_from_(A2) + True + sage: A2._coerce_map_from_(A2U) + False + + """ + if isinstance(other, (MultivectorModule, MultivectorFreeModule)): + # coercion by domain restriction + return (self._degree == other._degree + and self._domain.is_subset(other._domain) + and self._ambient_domain.is_subset( + other._ambient_domain)) + return False + + @cached_method + def zero(self): + """ + Return the zero of ``self``. + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: A2 = M.multivector_module(2) + sage: A2.zero() + 2-vector field zero on the 3-dimensional differentiable + manifold M + + """ + zero = self.element_class(self._vmodule, self._degree, + name='zero', latex_name='0') + zero = self._element_constructor_(name='zero', latex_name='0') + for frame in self._domain._frames: + if self._dest_map.restrict(frame._domain) == frame._dest_map: + zero.add_comp(frame) + # (since new components are initialized to zero) + return zero + + #### End of Parent methods + + def _repr_(self): + r""" + Return a string representation of the object. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: A2 = M.multivector_module(2) + sage: A2 + Module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + + """ + description = "Module " + if self._name is not None: + description += self._name + " " + description += "of {}-vector fields ".format(self._degree) + if self._dest_map is self._domain.identity_map(): + description += "on the {}".format(self._domain) + else: + description += "along the {} mapped into the {}".format( + elf._domain, self._ambient_domain) + return description + + def _latex_(self): + r""" + Return a LaTeX representation of the object. + + TESTS:: + + sage: M = Manifold(3, 'M', latex_name=r'\mathcal{M}') + sage: A2 = M.multivector_module(2) + sage: A2._latex_() + 'A^{2}\\left(\\mathcal{M}\\right)' + sage: latex(A2) # indirect doctest + A^{2}\left(\mathcal{M}\right) + + """ + if self._latex_name is None: + return r'\mbox{' + str(self) + r'}' + else: + return self._latex_name + + def base_module(self): + r""" + Return the vector field module on which the multivector field + module ``self`` is constructed. + + OUTPUT: + + - a + :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule` + representing the module on which ``self`` is defined + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: A2 = M.multivector_module(2) ; A2 + Module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + sage: A2.base_module() + Module X(M) of vector fields on the 3-dimensional + differentiable manifold M + sage: A2.base_module() is M.vector_field_module() + True + sage: U = M.open_subset('U') + sage: A2U = U.multivector_module(2) ; A2U + Module A^2(U) of 2-vector fields on the Open subset U of the + 3-dimensional differentiable manifold M + sage: A2U.base_module() + Module X(U) of vector fields on the Open subset U of the + 3-dimensional differentiable manifold M + + """ + return self._vmodule + + def degree(self): + r""" + Return the degree of the multivector fields in ``self``. + + OUTPUT: + + - integer `p` such that ``self`` is a set of `p`-vector fields + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: M.multivector_module(2).degree() + 2 + sage: M.multivector_module(3).degree() + 3 + + """ + return self._degree + +#*********************************************************************** + +class MultivectorFreeModule(ExtPowerFreeModule): + r""" + Free module of multivector fields of a given degree `p` (`p`-vector + fields) along a differentiable manifold `U` with values on a + parallelizable manifold `M`. + + Given a differentiable manifold `U` and a differentiable map + `\Phi:\; U \rightarrow M` to a parallelizable manifold `M` of dimension + `n`, the set `A^p(U, \Phi)` of `p`-vector fields (i.e. alternating tensor + fields of type `(p,0)`) along `U` with values on `M` is a free module + of rank `\binom{n}{p}` over `C^k(U)`, the commutative algebra of + differentiable scalar fields on `U` (see + :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). + The standard case of `p`-vector fields *on* a differentiable + manifold `M` corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. + Other common cases are `\Phi` being an immersion and `\Phi` being a + curve in `M` (`U` is then an open interval of `\RR`). + + .. NOTE:: + + This class implements `A^p(U, \Phi)` in the case where `M` is + parallelizable; `A^p(U, \Phi)` is then a *free* module. If `M` + is not parallelizable, the class :class:`MultivectorModule` must + be used instead. + + INPUT: + + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of + vector fields along `U` associated with the map + `\Phi: U \rightarrow V` + - ``degree`` -- positive integer; the degree `p` of the multivector + fields + + EXAMPLES: + + Free module of 2-vector fields on a parallelizable 3-dimensional + manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: XM = M.vector_field_module() ; XM + Free module X(M) of vector fields on the 3-dimensional + differentiable manifold M + sage: A = M.multivector_module(2) ; A + Free module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + sage: latex(A) + A^{2}\left(M\right) + + ``A`` is nothing but the second exterior power of ``XM``, i.e. we + have `A^{2}(M) = \Lambda^2(\mathfrak{X}(M))` (see + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`):: + + sage: A is XM.exterior_power(2) + True + + `A^{2}(M)` is a module over the algebra `C^k(M)` of (differentiable) + scalar fields on `M`:: + + sage: A.category() + Category of finite dimensional modules over Algebra of + differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: CM = M.scalar_field_algebra() ; CM + Algebra of differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: A in Modules(CM) + True + sage: A.base_ring() + Algebra of differentiable scalar fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() + Free module X(M) of vector fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() is XM + True + sage: A.rank() + 3 + + Elements can be constructed from `A`. In particular, ``0`` yields + the zero element of `A`:: + + sage: A(0) + 2-vector field zero on the 3-dimensional differentiable + manifold M + sage: A(0) is A.zero() + True + + while non-zero elements are constructed by providing their + components in a given vector frame:: + + sage: comp = [[0,3*x,-z],[-3*x,0,4],[z,-4,0]] + sage: a = A(comp, frame=X.frame(), name='a') ; a + 2-vector field a on the 3-dimensional differentiable manifold M + sage: a.display() + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz + + An alternative is to construct the 2-vector field from an empty list + of components and to set the nonzero nonredundant components + afterwards:: + + sage: a = A([], name='a') + sage: a[0,1] = 3*x # component in the manifold's default frame + sage: a[0,2] = -z + sage: a[1,2] = 4 + sage: a.display() + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz + + The module `A^1(M)` is nothing but `\mathfrak{X}(M)` (the free module + of vector fields on `M`):: + + sage: A1 = M.multivector_module(1) ; A1 + Free module X(M) of vector fields on the 3-dimensional + differentiable manifold M + sage: A1 is XM + True + + There is a coercion map `A^p(M) \rightarrow T^{(p,0)}(M)`:: + + sage: T20 = M.tensor_field_module((2,0)); T20 + Free module T^(2,0)(M) of type-(2,0) tensors fields on the + 3-dimensional differentiable manifold M + sage: T20.has_coerce_map_from(A) + True + + but of course not in the reverse direction, since not all contravariant + tensor field is alternating:: + + sage: A.has_coerce_map_from(T20) + False + + The coercion map `A^2(M) \rightarrow T^{(2,0)}(M)` in action:: + + sage: T20 = M.tensor_field_module((2,0)) ; T20 + Free module T^(2,0)(M) of type-(2,0) tensors fields on the + 3-dimensional differentiable manifold M + sage: ta = T20(a) ; ta + Tensor field a of type (2,0) on the 3-dimensional differentiable + manifold M + sage: ta.display() + a = 3*x d/dx*d/dy - z d/dx*d/dz - 3*x d/dy*d/dx + 4 d/dy*d/dz + + z d/dz*d/dx - 4 d/dz*d/dy + sage: a.display() + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz + sage: ta.symmetries() # the antisymmetry is preserved + no symmetry; antisymmetry: (0, 1) + + There is also coercion to subdomains, which is nothing but the + restriction of the multivector field to some subset of its domain:: + + sage: U = M.open_subset('U', coord_def={X: x^2+y^2<1}) + sage: B = U.multivector_module(2) ; B + Free module A^2(U) of 2-vector fields on the Open subset U of the + 3-dimensional differentiable manifold M + sage: B.has_coerce_map_from(A) + True + sage: a_U = B(a) ; a_U + 2-vector field a on the Open subset U of the 3-dimensional + differentiable manifold M + sage: a_U.display() + a = 3*x d/dx/\d/dy - z d/dx/\d/dz + 4 d/dy/\d/dz + + """ + + Element = MultivectorFieldParal + + def __init__(self, vector_field_module, degree): + r""" + Construct a free module of multivector fields. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: from sage.manifolds.differentiable.multivector_module \ + ....: import MultivectorFreeModule + sage: A = MultivectorFreeModule(M.vector_field_module(), 2) + sage: A + Free module A^2(M) of 2-vector fields on the 3-dimensional + differentiable manifold M + sage: TestSuite(A).run() + + """ + domain = vector_field_module._domain + dest_map = vector_field_module._dest_map + name = "A^{}(".format(degree) + domain._name + latex_name = r"A^{{{}}}\left({}".format(degree, + domain._latex_name) + if dest_map is domain.identity_map(): + name += ")" + latex_name += r"\right)" + else: + name += "," + dest_map._name + ")" + latex_name += "," + dest_map._latex_name + r"\right)" + ExtPowerFreeModule.__init__(self, vector_field_module, degree, + name=name, latex_name=latex_name) + self._domain = domain + self._dest_map = dest_map + self._ambient_domain = vector_field_module._ambient_domain + + #### Parent methods + + def _element_constructor_(self, comp=[], frame=None, name=None, + latex_name=None): + r""" + Construct a multivector field. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: A = M.multivector_module(2) + sage: a = A([[0, x], [-x, 0]], name='a'); a + 2-vector field a on the 2-dimensional differentiable + manifold M + sage: a.display() + a = x d/dx/\d/dy + sage: A(0) is A.zero() + True + + """ + if isinstance(comp, (int, Integer)) and comp == 0: + return self.zero() + if isinstance(comp, (MultivectorField, MultivectorFieldParal)): + # coercion by domain restriction + if (self._degree == comp._tensor_type[0] + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset( + comp._ambient_domain)): + return comp.restrict(self._domain) + else: + raise TypeError("cannot convert the {} ".format(comp) + + "to a multivector field in {}".format(self)) + # standard construction + resu = self.element_class(self._fmodule, self._degree, name=name, + latex_name=latex_name) + if comp: + resu.set_comp(frame)[:] = comp + return resu + + # Rem: _an_element_ is declared in the superclass ExtPowerFreeModule + + def _coerce_map_from_(self, other): + r""" + Determine whether coercion to ``self`` exists from other parent. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: A2 = M.multivector_module(2) + sage: U = M.open_subset('U', coord_def = {X: z<0}) + sage: A2U = U.multivector_module(2) + sage: A2U._coerce_map_from_(A2) + True + sage: A2._coerce_map_from_(A2U) + False + sage: A1 = M.multivector_module(1) + sage: A2U._coerce_map_from_(A1) + False + sage: A2._coerce_map_from_(M.tensor_field_module((2,0))) + False + + """ + if isinstance(other, (MultivectorModule, MultivectorFreeModule)): + # coercion by domain restriction + return (self._degree == other._degree + and self._domain.is_subset(other._domain) + and self._ambient_domain.is_subset( + other._ambient_domain)) + return False + + #### End of Parent methods + + def _repr_(self): + r""" + Return a string representation of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: A = M.multivector_module(2) + sage: A + Free module A^2(M) of 2-vector fields on + the 3-dimensional differentiable manifold M + + """ + description = "Free module " + if self._name is not None: + description += self._name + " " + description += "of {}-vector fields ".format(self._degree) + if self._dest_map is self._domain.identity_map(): + description += "on the {}".format(self._domain) + else: + description += "along the {} mapped into the {}".format( + self._domain, self._ambient_domain) + return description diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py new file mode 100644 index 00000000000..84446569caa --- /dev/null +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -0,0 +1,1501 @@ +r""" +Multivector Fields + +Let `U` and `M` be two differentiable manifolds. +Given a positive integer `p` and a differentiable map `\Phi: U \rightarrow M`, +a *multivector field of degree* `p`, or `p`-*vector field*, +*along* `U` *with values on* `M` is a field along `U` of alternating +contravariant tensors of rank `p` in the tangent spaces to `M`. +The standard case of a multivector field *on* a differentiable manifold +corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are +`\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open +interval of `\RR`). + +Two classes implement multivector fields, depending whether the manifold +`M` is parallelizable: + +* :class:`MultivectorFieldParal` when `M` is parallelizable +* :class:`MultivectorField` when `M` is not assumed parallelizable. + +AUTHORS: + +- Eric Gourgoulhon (2017): initial version + +REFERENCES: + +- \R. L. Bishop and S. L. Goldberg (1980) [BG1980]_ +- \C.-M. Marle (1997) [Mar1997]_ + +""" + +#****************************************************************************** +# Copyright (C) 2017 Eric Gourgoulhon +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor +from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal + +class MultivectorField(TensorField): + r""" + Multivector field with values on a generic (i.e. a priori not + parallelizable) differentiable manifold. + + Given a differentiable manifold `U`, a differentiable map + `\Phi: U \rightarrow M` to a differentiable manifold `M` and a positive + integer `p`, a *multivector field of degree* `p` (or `p`-*vector field*) + *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map + + .. MATH:: + + a:\ U \longrightarrow T^{(p,0)}M + + (`T^{(p,0)}M` being the tensor bundle of type `(p,0)` over `M`) such that + + .. MATH:: + + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)} M) , + + where `T_{\Phi(x)} M` is the vector space tangent to `M` at `\Phi(x)` and + `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`). + In other words, `a(x)` is an alternating contravariant tensor of degree `p` + of the tangent vector space `T_{\Phi(x)} M`. + + The standard case of a multivector field *on* a manifold `M` corresponds to + `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an + immersion and `\Phi` being a curve in `M` (`U` is then an open interval of + `\RR`). + + .. NOTE:: + + If `M` is parallelizable, the class :class:`MultivectorFieldParal` + must be used instead. + + INPUT: + + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields + along `U` with values on `M` via the map `\Phi` + - ``degree`` -- the degree of the multivector field (i.e. its tensor rank) + - ``name`` -- (default: ``None``) name given to the multivector field + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + multivector field; if none is provided, the LaTeX symbol is set to + ``name`` + + EXAMPLES: + + Multivector field of degree 2 on a non-parallelizable 2-dimensional + manifold:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # M is the union of U and V + sage: c_xy. = U.chart() ; c_uv. = V.chart() + sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), + ....: intersection_name='W', + ....: restrictions1= x>0, restrictions2= u+v>0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) + sage: eU = c_xy.frame() ; eV = c_uv.frame() + sage: a = M.multivector_field(2, name='a') ; a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a.parent() + Module A^2(M) of 2-vector fields on the 2-dimensional differentiable + manifold M + sage: a.degree() + 2 + + Setting the components of ``a``:: + + sage: a[eU,0,1] = x*y^2 + 2*x + sage: a.add_comp_by_continuation(eV, W, c_uv) + sage: a.display(eU) + a = (x*y^2 + 2*x) d/dx/\d/dy + sage: a.display(eV) + a = (-1/4*u^3 + 1/4*u*v^2 - 1/4*v^3 + 1/4*(u^2 - 8)*v - 2*u) d/du/\d/dv + + The exterior product of two vector fields is a 2-vector field:: + + sage: a = M.vector_field(name='a') + sage: a[eU,:] = [-y, x] + sage: a.add_comp_by_continuation(eV, W, c_uv) + sage: b = M.vector_field(name='b') + sage: b[eU,:] = [1+x*y, x^2] + sage: b.add_comp_by_continuation(eV, W, c_uv) + sage: s = a.wedge(b) ; s + 2-vector field a/\b on the 2-dimensional differentiable manifold M + sage: s.display(eU) + a/\b = (-2*x^2*y - x) d/dx/\d/dy + sage: s.display(eV) + a/\b = (1/2*u^3 - 1/2*u*v^2 - 1/2*v^3 + 1/2*(u^2 + 2)*v + u) d/du/\d/dv + + Multiplying a 2-vector field by a scalar field results in another + 2-vector field:: + + sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') + sage: s = f*s ; s + 2-vector field on the 2-dimensional differentiable manifold M + sage: s.display(eU) + (-2*x^2*y^3 - x^3 - (4*x^3 + x)*y^2 - 2*(x^4 + x^2)*y) d/dx/\d/dy + sage: s.display(eV) + (1/2*u^5 - 1/2*u^3*v^2 - 1/2*u^2*v^3 + u^3 + 1/2*(u^4 + 2*u^2)*v) + d/du/\d/dv + + """ + def __init__(self, vector_field_module, degree, name=None, latex_name=None): + r""" + Construct a multivector field. + + TESTS: + + Construction via ``parent.element_class``, and not via a direct call + to ``MultivectorField`, to fit with the category framework:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # M is the union of U and V + sage: c_xy. = U.chart() ; c_uv. = V.chart() + sage: xy_to_uv = c_xy.transition_map(c_uv, (x+y, x-y), + ....: intersection_name='W', restrictions1= x>0, + ....: restrictions2= u+v>0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: A = M.multivector_module(2) + sage: XM = M.vector_field_module() + sage: a = A.element_class(XM, 2, name='a'); a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a[e_xy,0,1] = x+y + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: TestSuite(a).run(skip='_test_pickling') + + Construction with ``DifferentiableManifold.multivector_field``:: + + sage: a1 = M.multivector_field(2, name='a'); a1 + 2-vector field a on the 2-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + .. TODO:: + + Fix ``_test_pickling`` (in the superclass :class:`TensorField`). + + """ + TensorField.__init__(self, vector_field_module, (degree, 0), name=name, + latex_name=latex_name, antisym=range(degree), + parent=vector_field_module.exterior_power(degree)) + self._init_derived() # initialization of derived quantities + + def _repr_(self): + r""" + String representation of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: a = M.multivector_field(2, name='a') + sage: a._repr_() + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: repr(a) # indirect doctest + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: a # indirect doctest + 2-vector field a on the 3-dimensional differentiable manifold M + sage: b = M.multivector_field(2) + sage: b._repr_() + '2-vector field on the 3-dimensional differentiable manifold M' + + """ + description = "{}-vector field ".format(self._tensor_rank) + if self._name is not None: + description += self._name + " " + return self._final_repr(description) + + def _new_instance(self): + r""" + Create an instance of the same class, of the same degree and on the + same domain. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: a = M.multivector_field(2, name='a') + sage: a1 = a._new_instance(); a1 + 2-vector field on the 3-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + """ + return type(self)(self._vmodule, self._tensor_rank) + + def degree(self): + r""" + Return the degree of ``self``. + + OUTPUT: + + - integer `p` such that ``self`` is a `p`-vector field + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: a = M.multivector_field(2); a + 2-vector field on the 3-dimensional differentiable manifold M + sage: a.degree() + 2 + sage: b = M.vector_field(); b + Vector field on the 3-dimensional differentiable manifold M + sage: b.degree() + 1 + + """ + return self._tensor_rank + + def wedge(self, other): + r""" + Exterior product with another multivector field. + + INPUT: + + - ``other`` -- another multivector field (on the same manifold) + + OUTPUT: + + - instance of :class:`MultivectorField` representing the exterior + product ``self/\other`` + + EXAMPLES: + + Exterior product of two vector fields on the 2-sphere:: + + sage: M = Manifold(2, 'S^2', start_index=1) # the sphere S^2 + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # S^2 is the union of U and V + sage: c_xy. = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South + sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), + ....: intersection_name='W', restrictions1= x^2+y^2!=0, + ....: restrictions2= u^2+v^2!=0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.vector_field(name='a') + sage: a[e_xy,:] = y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.vector_field(name='b') + sage: b[e_xy,:] = x^2 + y^2, y + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: c = a.wedge(b); c + 2-vector field a/\b on the 2-dimensional differentiable + manifold S^2 + sage: c.display(e_xy) + a/\b = (-x^3 - (x - 1)*y^2) d/dx/\d/dy + sage: c.display(e_uv) + a/\b = (-v^2 + u) d/du/\d/dv + + """ + from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(other._domain): + if not self._ambient_domain.is_subset(other._ambient_domain): + raise ValueError("incompatible ambient domains for exterior " + + "product") + elif other._domain.is_subset(self._domain): + if not other._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for exterior " + + "product") + dom_resu = self._domain.intersection(other._domain) + ambient_dom_resu = self._ambient_domain.intersection(other._ambient_domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + if ambient_dom_resu.is_manifestly_parallelizable(): + # call of the AlternatingContrTensor version: + return AlternatingContrTensor.wedge(self_r, other_r) + # otherwise, the result is created here: + if self._name is not None and other._name is not None: + sname = self._name + oname = other._name + if not is_atomic(sname): + sname = '(' + sname + ')' + if not is_atomic(oname): + oname = '(' + oname + ')' + resu_name = sname + '/\\' + oname + if self._latex_name is not None and other._latex_name is not None: + slname = self._latex_name + olname = other._latex_name + if not is_atomic(slname): + slname = '(' + slname + ')' + if not is_atomic(olname): + olname = '(' + olname + ')' + resu_latex_name = slname + r'\wedge ' + olname + dest_map = self._vmodule._dest_map + dest_map_resu = dest_map.restrict(dom_resu, + subcodomain=ambient_dom_resu) + vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) + resu_degree = self._tensor_rank + other._tensor_rank + resu = vmodule.alternating_contravariant_tensor(resu_degree, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in other_r._restrictions: + resu._restrictions[dom] = self_r._restrictions[dom].wedge( + other_r._restrictions[dom]) + return resu + + def interior_product(self, form): + r""" + Interior product with a differential form. + + If ``self`` is a multivector field `A` of degree `p` and `B` is a + differential form of degree `q\geq p` on the same manifold as `A`, the + interior product of `A` by `B` is the differential form `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)_{i_1\ldots i_{q-p}} = A^{k_1\ldots k_p} + B_{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield.TensorField.contract` + + INPUT: + + - ``form`` -- differential form `B` (instance of + :class:`~sage.manifolds.differentiable.diff_form.DiffForm`); + the degree of `B` must be at least equal to the degree of ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + (case `p = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South + sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), + ....: intersection_name='W', restrictions1= x^2+y^2!=0, + ....: restrictions2= u^2+v^2!=0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.vector_field(name='a') + sage: a[e_xy,:] = -y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.diff_form(2, name='b') + sage: b[e_xy,1,2] = 4/(x^2+y^2+1)^2 # the standard area 2-form + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: b.display(e_xy) + b = 4/(x^2 + y^2 + 1)^2 dx/\dy + sage: b.display(e_uv) + b = -4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du/\dv + sage: s = a.interior_product(b); s + 1-form i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display(e_xy) + i_a b = -4*x/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx + - 4*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dy + sage: s.display(e_uv) + i_a b = 4*u/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du + + 4*v/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) dv + sage: s == a.contract(b) + True + + Example with `p=2` and `q=2`:: + + sage: a = M.multivector_field(2, name='a') + sage: a[e_xy,1,2] = x*y + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: a.display(e_xy) + a = x*y d/dx/\d/dy + sage: a.display(e_uv) + a = -u*v d/du/\d/dv + sage: s = a.interior_product(b); s + Scalar field i_a b on the 2-dimensional differentiable manifold S^2 + sage: s.display() + i_a b: S^2 --> R + on U: (x, y) |--> 8*x*y/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) + on V: (u, v) |--> 8*u*v/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) + + Some checks:: + + sage: s == a.contract(0, 1, b, 0, 1) + True + sage: s.restrict(U) == 2 * a[[e_xy,1,2]] * b[[e_xy,1,2]] + True + sage: s.restrict(V) == 2 * a[[e_uv,1,2]] * b[[e_uv,1,2]] + True + + """ + from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(form._domain): + if not self._ambient_domain.is_subset(form._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + elif form._domain.is_subset(self._domain): + if not form._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + dom_resu = self._domain.intersection(form._domain) + ambient_dom_resu = self._ambient_domain.intersection(form._ambient_domain) + self_r = self.restrict(dom_resu) + form_r = form.restrict(dom_resu) + if ambient_dom_resu.is_manifestly_parallelizable(): + # call of the AlternatingContrTensor version: + return AlternatingContrTensor.interior_product(self_r, form_r) + # Otherwise, the result is created here: + # Name of the result + resu_name = None + if self._name is not None and form._name is not None: + sname = self._name + oname = form._name + if not is_atomic(sname): + sname = '(' + sname + ')' + if not is_atomic(oname): + oname = '(' + oname + ')' + resu_name = 'i_' + sname + ' ' + oname + resu_latex_name = None + if self._latex_name is not None and form._latex_name is not None: + slname = self._latex_name + olname = form._latex_name + if not is_atomic(olname): + olname = r'\left(' + olname + r'\right)' + resu_latex_name = r'\iota_{' + slname + '} ' + olname + # Domain and computation of the result + dest_map = self._vmodule._dest_map + dest_map_resu = dest_map.restrict(dom_resu, + subcodomain=ambient_dom_resu) + vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) + resu_degree = form._tensor_rank - self._tensor_rank + resu = vmodule.alternating_form(resu_degree, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in form_r._restrictions: + resu._restrictions[dom] = \ + self_r._restrictions[dom].interior_product( + form_r._restrictions[dom]) + if resu_degree == 0: + if not resu._express: # only the restrictions to subdomains have + # been initialized + for chart in dom_resu.top_charts(): + resu._express[chart] = \ + resu.restrict(chart.domain()).coord_function(chart) + return resu + + def bracket(self, other): + r""" + Return the Schouten-Nijenhuis bracket of ``self`` with another + multivector field. + + The Schouten-Nijenhuis bracket extends the Lie bracket of + vector fields (cf. + :meth:`~sage.manifolds.differentiable.vectorfield.VectorField.bracket`) + to multivector fields. + + Denoting by `A^p(M)` the `C^k(M)`-module of `p`-vector fields on the + `C^k`-differentiable manifold `M` over the field `K` (cf. + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule`), + the *Schouten-Nijenhuis bracket* is a `K`-bilinear map + + .. MATH:: + + \begin{array}{ccc} + A^p(M)\times A^q(M) & \longrightarrow & A^{p+q-1}(M) \\ + (a,b) & \longmapsto & [a,b] + \end{array} + + which obeys the following properties: + + - if `p=0` and `q=0`, (i.e. `a` and `b` are two scalar fields), `[a,b]=0` + - if `p=0` (i.e. `a` is a scalar field) and `q\geq 1`, + `[a,b] = - \iota_{\mathrm{d}a} b` (minus the interior product of + the differential of `a` by `b`) + - if `p=1` (i.e. `a` is a vector field), `[a,b] = \mathcal{L}_a b` + (the Lie derivative of `b` along `a`) + - `[a,b] = -(-1)^{(p-1)(q-1)} [b,a]` + - for any multivector field `c` and `(a,b) \in A^p(M)\times A^q(M)`, + `[a,.]` obeys the *graded Leibniz rule* + + .. MATH:: + + [a,b\wedge c] = [a,b]\wedge c + (-1)^{(p-1)q} b\wedge [a,c] + + - for `(a,b,c) \in A^p(M)\times A^q(M)\times A^r(M)`, the *graded + Jacobi identity* holds: + + .. MATH:: + + (-1)^{(p-1)(r-1)}[a,[b,c]] + (-1)^{(q-1)(p-1)}[b,[c,a]] + + (-1)^{(r-1)(q-1)}[c,[a,b]] = 0 + + .. NOTE:: + + There are two definitions of the Schouten-Nijenhuis bracket in + the literature, which differ from each other when `p` is even + by an overall sign. The definition adopted here is that of + [Mar1997]_, [Kos1985]_ and :wikipedia:`Schouten-Nijenhuis_bracket`. + The other definition, adopted e.g. by [Nij1955]_, [Lic1977]_ + and [Vai1994]_, is `[a,b]' = (-1)^{p+1} [a,b]`. + + INPUT: + + - ``other`` -- a multivector field + + OUTPUT: + + - instance of :class:`MultivectorField` (or of + :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField` + if `p=1` and `q=0`) representing the + Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` and `b` is + ``other`` + + EXAMPLES: + + Bracket of two vector fields on the 2-sphere:: + + sage: M = Manifold(2, 'S^2', start_index=1) # the sphere S^2 + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # S^2 is the union of U and V + sage: c_xy. = U.chart() # stereographic coord. North + sage: c_uv. = V.chart() # stereographic coord. South + sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), + ....: intersection_name='W', restrictions1= x^2+y^2!=0, + ....: restrictions2= u^2+v^2!=0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: W = U.intersection(V) # The complement of the two poles + sage: e_xy = c_xy.frame() ; e_uv = c_uv.frame() + sage: a = M.vector_field(name='a') + sage: a[e_xy,:] = y, x + sage: a.add_comp_by_continuation(e_uv, W, c_uv) + sage: b = M.vector_field(name='b') + sage: b[e_xy,:] = x*y, x-y + sage: b.add_comp_by_continuation(e_uv, W, c_uv) + sage: s = a.bracket(b); s + Vector field [a,b] on the 2-dimensional differentiable manifold S^2 + sage: s.display(e_xy) + [a,b] = (x^2 + y^2 - x + y) d/dx + (-(x - 1)*y - x) d/dy + + For two vector fields, the bracket coincides with the Lie derivative:: + + sage: s == b.lie_derivative(a) + True + + Schouten-Nijenhuis bracket of a 2-vector field and a 1-vector field:: + + sage: c = a.wedge(b); c + 2-vector field a/\b on the 2-dimensional differentiable + manifold S^2 + sage: s = c.bracket(a); s + 2-vector field [a/\b,a] on the 2-dimensional differentiable + manifold S^2 + sage: s.display(e_xy) + [a/\b,a] = (x^3 + (2*x - 1)*y^2 - x^2 + 2*x*y) d/dx/\d/dy + + Since `a` is a vector field, we have in this case:: + + sage: s == - c.lie_derivative(a) + True + + .. SEEALSO:: + + :meth:`MultivectorFieldParal.bracket` for more examples and check + of standards identities involving the Schouten-Nijenhuis bracket + + """ + from sage.manifolds.differentiable.scalarfield import DiffScalarField + pp = self._tensor_rank + mp1 = (-1)**(pp+1) + if isinstance(other, DiffScalarField): + resu = other.differential().interior_product(self) + if mp1 == 1: + return resu + return - resu + # Some checks: + if not isinstance(other, (MultivectorField, MultivectorFieldParal)): + raise TypeError("{} is not a multivector field".format(other)) + if (self._vmodule.destination_map() is not self._domain.identity_map() + or other._vmodule.destination_map() is not + other._domain.identity_map()): + raise ValueError("the Schouten-Nijenhuis bracket is defined " + + "only for fields with a trivial destination map") + # Search for a common domain + dom_resu = self._domain.intersection(other._domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + if dom_resu.is_manifestly_parallelizable(): + # call of the MultivectorFieldParal version: + return MultivectorFieldParal.bracket(self_r, other_r) + # otherwise, the result is created here: + # Name of the result: + resu_name = None + resu_latex_name = None + if self._name is not None and other._name is not None: + resu_name = '[' + self._name + ',' + other._name + ']' + if self._latex_name is not None and other._latex_name is not None: + resu_latex_name = r'\left[' + self._latex_name + ',' + \ + other._latex_name + r'\right]' + vmodule = dom_resu.vector_field_module() + deg_resu = pp + other._tensor_rank - 1 # degree of the result + resu = vmodule.alternating_contravariant_tensor(deg_resu, + name=resu_name, latex_name=resu_latex_name) + for dom in self_r._restrictions: + if dom in other_r._restrictions: + resu._restrictions[dom] = self_r._restrictions[dom].bracket( + other_r._restrictions[dom]) + return resu + + +#****************************************************************************** + +class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): + r""" + Multivector field with values on a parallelizable manifold. + + Given a differentiable manifold `U`, a differentiable map + `\Phi: U \rightarrow M` to a parallelizable manifold `M` and a positive + integer `p`, a *multivector field of degree* `p` (or `p`-*vector field*) + *along* `U` *with values on* `M\supset\Phi(U)` is a differentiable map + + .. MATH:: + + a:\ U \longrightarrow T^{(p,0)}M + + (`T^{(p,0)}M` being the tensor bundle of type `(p,0)` over `M`) such that + + .. MATH:: + + \forall x \in U,\quad a(x) \in \Lambda^p(T_{\Phi(x)} M) , + + where `T_{\Phi(x)} M` is the vector space tangent to `M` at `\Phi(x)` and + `\Lambda^p` stands for the exterior power of degree `p` (cf. + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`). + In other words, `a(x)` is an alternating contravariant tensor of degree `p` + of the tangent vector space `T_{\Phi(x)} M`. + + The standard case of a multivector field *on* a manifold `M` corresponds to + `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi` being an + immersion and `\Phi` being a curve in `M` (`U` is then an open interval of + `\RR`). + + .. NOTE:: + + If `M` is not parallelizable, the class :class:`MultivectorField` must + be used instead. + + INPUT: + + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector + fields along `U` with values on `M` via the map `\Phi` + - ``degree`` -- the degree of the multivector field (i.e. its tensor rank) + - ``name`` -- (default: ``None``) name given to the multivector field + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + multivector field; if none is provided, the LaTeX symbol is set to + ``name`` + + EXAMPLES: + + A 2-vector field on a 4-dimensional manifold:: + + sage: M = Manifold(4, 'M') + sage: c_txyz. = M.chart() + sage: a = M.multivector_field(2, 'a') ; a + 2-vector field a on the 4-dimensional differentiable manifold M + sage: a.parent() + Free module A^2(M) of 2-vector fields on the 4-dimensional + differentiable manifold M + + A multivector field is a tensor field of purely contravariant type:: + + sage: a.tensor_type() + (2, 0) + + It is antisymmetric, its components being + :class:`~sage.tensor.modules.comp.CompFullyAntiSym`:: + + sage: a.symmetries() + no symmetry; antisymmetry: (0, 1) + sage: a[0,1] = 2*x + sage: a[1,0] + -2*x + sage: a.comp() + Fully antisymmetric 2-indices components w.r.t. Coordinate frame + (M, (d/dt,d/dx,d/dy,d/dz)) + sage: type(a.comp()) + + + Setting a component with repeated indices to a non-zero value results in + an error:: + + sage: a[1,1] = 3 + Traceback (most recent call last): + ... + ValueError: by antisymmetry, the component cannot have a nonzero value + for the indices (1, 1) + sage: a[1,1] = 0 # OK, albeit useless + sage: a[1,2] = 3 # OK + + The expansion of a multivector field with respect to a given frame is + displayed via the method + :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.display`:: + + sage: a.display() # expansion w.r.t. the default frame + a = 2*x d/dt/\d/dx + 3 d/dx/\d/dy + sage: latex(a.display()) # output for the notebook + a = 2 \, x \frac{\partial}{\partial t }\wedge \frac{\partial}{\partial x } + + 3 \frac{\partial}{\partial x }\wedge \frac{\partial}{\partial y } + + Multivector fields can be added or subtracted:: + + sage: b = M.multivector_field(2) + sage: b[0,1], b[0,2], b[0,3] = y, 2, x+z + sage: s = a + b ; s + 2-vector field on the 4-dimensional differentiable manifold M + sage: s.display() + (2*x + y) d/dt/\d/dx + 2 d/dt/\d/dy + (x + z) d/dt/\d/dz + 3 d/dx/\d/dy + sage: s = a - b ; s + 2-vector field on the 4-dimensional differentiable manifold M + sage: s.display() + (2*x - y) d/dt/\d/dx - 2 d/dt/\d/dy + (-x - z) d/dt/\d/dz + 3 d/dx/\d/dy + + An example of 3-vector field in `\RR^3` with Cartesian coordinates:: + + sage: M = Manifold(3, 'R3', '\RR^3', start_index=1) + sage: c_cart. = M.chart() + sage: a = M.multivector_field(3, name='a') + sage: a[1,2,3] = x^2+y^2+z^2 # the only independent component + sage: a[:] # all the components are set from the previous line: + [[[0, 0, 0], [0, 0, x^2 + y^2 + z^2], [0, -x^2 - y^2 - z^2, 0]], + [[0, 0, -x^2 - y^2 - z^2], [0, 0, 0], [x^2 + y^2 + z^2, 0, 0]], + [[0, x^2 + y^2 + z^2, 0], [-x^2 - y^2 - z^2, 0, 0], [0, 0, 0]]] + sage: a.display() + a = (x^2 + y^2 + z^2) d/dx/\d/dy/\d/dz + + Spherical components from the tensorial change-of-frame formula:: + + sage: c_spher. = M.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi') + sage: spher_to_cart = c_spher.transition_map(c_cart, + ....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)]) + sage: cart_to_spher = spher_to_cart.set_inverse(sqrt(x^2+y^2+z^2), + ....: atan2(sqrt(x^2+y^2),z), atan2(y, x)) + sage: a.comp(c_spher.frame()) # computation of components w.r.t. spherical frame + Fully antisymmetric 3-indices components w.r.t. Coordinate frame + (R3, (d/dr,d/dth,d/dph)) + sage: a.comp(c_spher.frame())[1,2,3, c_spher] + 1/sin(th) + sage: a.display(c_spher.frame()) + a = sqrt(x^2 + y^2 + z^2)/sqrt(x^2 + y^2) d/dr/\d/dth/\d/dph + sage: a.display(c_spher.frame(), c_spher) + a = 1/sin(th) d/dr/\d/dth/\d/dph + + The exterior product of two multivector fields is performed via the method + :meth:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor.wedge`:: + + sage: a = M.vector_field(name='A') + sage: a[:] = (x*y, -z*x, y) + sage: b = M.vector_field(name='B') + sage: b[:] = (y, z+y, x^2-z^2) + sage: ab = a.wedge(b) ; ab + 2-vector field A/\B on the 3-dimensional differentiable manifold R3 + sage: ab.display() + A/\B = (x*y^2 + 2*x*y*z) d/dx/\d/dy + (x^3*y - x*y*z^2 - y^2) d/dx/\d/dz + + (x*z^3 - y^2 - (x^3 + y)*z) d/dy/\d/dz + + Let us check the formula relating the exterior product to the tensor + product for vector fields:: + + sage: a.wedge(b) == a*b - b*a + True + + The tensor product of a vector field and a 2-vector field is not a 3-vector + field but a tensor field of type `(3,0)` with less symmetries:: + + sage: c = a*ab ; c + Tensor field A*(A/\B) of type (3,0) on the 3-dimensional differentiable + manifold R3 + sage: c.symmetries() # the antisymmetry is only w.r.t. the last 2 arguments: + no symmetry; antisymmetry: (1, 2) + + The Lie derivative of a 2-vector field is a 2-vector field:: + + sage: ab.lie_der(a) + 2-vector field on the 3-dimensional differentiable manifold R3 + + """ + def __init__(self, vector_field_module, degree, name=None, + latex_name=None): + r""" + Construct a multivector field. + + TESTS: + + Construction via ``parent.element_class``, and not via a direct call + to ``MultivectorFieldParal``, to fit with the category framework:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: A = M.multivector_module(2) + sage: XM = M.vector_field_module() + sage: a = A.element_class(XM, 2, name='a'); a + 2-vector field a on the 2-dimensional differentiable manifold M + sage: a[0,1] = x*y + sage: TestSuite(a).run() + + Construction via ``DifferentiableManifold.multivector_field``:: + + sage: a1 = M.multivector_field(2, name='a'); a1 + 2-vector field a on the 2-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + """ + AlternatingContrTensor.__init__(self, vector_field_module, degree, + name=name, latex_name=latex_name) + # TensorFieldParal attributes: + self._vmodule = vector_field_module + self._domain = vector_field_module._domain + self._ambient_domain = vector_field_module._ambient_domain + # initialization of derived quantities: + self._init_derived() + + def _repr_(self): + r""" + String representation of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a._repr_() + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: repr(a) # indirect doctest + '2-vector field a on the 3-dimensional differentiable manifold M' + sage: a # indirect doctest + 2-vector field a on the 3-dimensional differentiable manifold M + sage: b = M.multivector_field(2) + sage: b._repr_() + '2-vector field on the 3-dimensional differentiable manifold M' + + """ + description = "{}-vector field ".format(self._tensor_rank) + if self._name is not None: + description += self._name + " " + return self._final_repr(description) + + def _new_instance(self): + r""" + Create an instance of the same class, of the same degree and on the + same domain. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a1 = a._new_instance(); a1 + 2-vector field on the 3-dimensional differentiable manifold M + sage: type(a1) == type(a) + True + sage: a1.parent() is a.parent() + True + + """ + return type(self)(self._fmodule, self._tensor_rank) + + # This method is needed to redirect to the correct class (TensorFieldParal) + def _init_derived(self): + r""" + Initialize the derived quantities of ``self``. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a._init_derived() + + """ + TensorFieldParal._init_derived(self) + + def _del_derived(self, del_restrictions=True): + r""" + Delete the derived quantities. + + INPUT: + + - ``del_restrictions`` -- (default: ``True``) determines whether the + restrictions of ``self`` to subdomains are deleted + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: a = M.multivector_field(2, name='a') + sage: a._del_derived() + + """ + TensorFieldParal._del_derived(self, del_restrictions=del_restrictions) + + def __call__(self, *args): + r""" + Redefinition of + :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.__call__` + to allow for domain treatment. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: a = M.multivector_field(2, name='a') + sage: a[0,1] = x*y + sage: a.display() + a = x*y d/dx/\d/dy + sage: b = M.one_form(name='b') + sage: b[:] = [1+x, 2-y] + sage: c = M.one_form(name='c') + sage: c[:] = [-y, x] + sage: s = a.__call__(b,c); s + Scalar field a(b,c) on the 2-dimensional differentiable manifold M + sage: s.display() + a(b,c): M --> R + (x, y) |--> -x*y^3 + 2*x*y^2 + (x^3 + x^2)*y + sage: s == a[[0,1]]*(b[[0]]*c[[1]] - b[[1]]*c[[0]]) + True + sage: s == a(b,c) # indirect doctest + True + + """ + return TensorFieldParal.__call__(self, *args) + + def wedge(self, other): + r""" + Exterior product of ``self`` with another multivector field. + + INPUT: + + - ``other`` -- another multivector field + + OUTPUT: + + - instance of :class:`MultivectorFieldParal` representing the + exterior product ``self/\other`` + + EXAMPLES: + + Exterior product of a vector field and a 2-vector field on a + 3-dimensional manifold:: + + sage: M = Manifold(3, 'M', start_index=1) + sage: X. = M.chart() + sage: a = M.vector_field(name='a') + sage: a[:] = [2, 1+x, y*z] + sage: b = M.multivector_field(2, name='b') + sage: b[1,2], b[1,3], b[2,3] = y^2, z+x, z^2 + sage: a.display() + a = 2 d/dx + (x + 1) d/dy + y*z d/dz + sage: b.display() + b = y^2 d/dx/\d/dy + (x + z) d/dx/\d/dz + z^2 d/dy/\d/dz + sage: s = a.wedge(b); s + 3-vector field a/\b on the 3-dimensional differentiable + manifold M + sage: s.display() + a/\b = (-x^2 + (y^3 - x - 1)*z + 2*z^2 - x) d/dx/\d/dy/\d/dz + + Check:: + + sage: s[1,2,3] == a[1]*b[2,3] + a[2]*b[3,1] + a[3]*b[1,2] + True + + """ + if self._domain.is_subset(other._domain): + if not self._ambient_domain.is_subset(other._ambient_domain): + raise ValueError("incompatible ambient domains for exterior " + + "product") + elif other._domain.is_subset(self._domain): + if not other._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for exterior " + + "product") + dom_resu = self._domain.intersection(other._domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + return AlternatingContrTensor.wedge(self_r, other_r) + + def interior_product(self, form): + r""" + Interior product with a differential form. + + If ``self`` is a multivector field `A` of degree `p` and `B` is a + differential form of degree `q\geq p` on the same manifold as `A`, the + interior product of `A` by `B` is the differential form `\iota_A B` of + degree `q-p` defined by + + .. MATH:: + + (\iota_A B)_{i_1\ldots i_{q-p}} = A^{k_1\ldots k_p} + B_{k_1\ldots k_p i_1\ldots i_{q-p}} + + .. NOTE:: + + ``A.interior_product(B)`` yields the same result as + ``A.contract(0,..., p-1, B, 0,..., p-1)`` (cf. + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract`), + but ``interior_product`` is more efficient, the alternating + character of `A` being not used to reduce the computation in + :meth:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal.contract` + + INPUT: + + - ``form`` -- differential form `B` (instance of + :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal`); + the degree of `B` must be at least equal to the degree of ``self`` + + OUTPUT: + + - scalar field (case `p=q`) or + :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal` + (case `p = M.chart() + sage: a = M.vector_field(name='a') + sage: a[:] = [x, 1+t^2, x*z, y-3] + sage: b = M.one_form(name='b') + sage: b[:] = [-z^2, 2, x, x-y] + sage: s = a.interior_product(b); s + Scalar field i_a b on the 4-dimensional differentiable manifold M + sage: s.display() + i_a b: M --> R + (t, x, y, z) |--> x^2*z - x*z^2 + 2*t^2 + (x + 3)*y - y^2 + - 3*x + 2 + + In this case, we have `\iota_a b = a^i b_i = a(b) = b(a)`:: + + sage: all([s == a.contract(b), s == a(b), s == b(a)]) + True + + Case `p=1` and `q=3`:: + + sage: c = M.diff_form(3, name='c') + sage: c[0,1,2], c[0,1,3] = x*y - z, -3*t + sage: c[0,2,3], c[1,2,3] = t+x, y + sage: s = a.interior_product(c); s + 2-form i_a c on the 4-dimensional differentiable manifold M + sage: s.display() + i_a c = (x^2*y*z - x*z^2 - 3*t*y + 9*t) dt/\dx + + (-(t^2*x - t)*y + (t^2 + 1)*z - 3*t - 3*x) dt/\dy + + (3*t^3 - (t*x + x^2)*z + 3*t) dt/\dz + + ((x^2 - 3)*y + y^2 - x*z) dx/\dy + + (-x*y*z - 3*t*x) dx/\dz + (t*x + x^2 + (t^2 + 1)*y) dy/\dz + sage: s == a.contract(c) + True + + Case `p=2` and `q=3`:: + + sage: d = M.multivector_field(2, name='d') + sage: d[0,1], d[0,2], d[0,3] = t-x, 2*z, y-1 + sage: d[1,2], d[1,3], d[2,3] = z, y+t, 4 + sage: s = d.interior_product(c); s + 1-form i_d c on the 4-dimensional differentiable manifold M + sage: s.display() + i_d c = (2*x*y*z - 6*t^2 - 6*t*y - 2*z^2 + 8*t + 8*x) dt + + (-4*x*y*z + 2*(3*t + 4)*y + 4*z^2 - 6*t) dx + + (2*((t - 1)*x - x^2 - 2*t)*y - 2*y^2 - 2*(t - x)*z + 2*t + + 2*x) dy + (-6*t^2 + 6*t*x + 2*(2*t + 2*x + y)*z) dz + sage: s == d.contract(0, 1, c, 0, 1) + True + + """ + if self._domain.is_subset(form._domain): + if not self._ambient_domain.is_subset(form._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + elif form._domain.is_subset(self._domain): + if not form._ambient_domain.is_subset(self._ambient_domain): + raise ValueError("incompatible ambient domains for interior " + + "product") + dom_resu = self._domain.intersection(form._domain) + self_r = self.restrict(dom_resu) + form_r = form.restrict(dom_resu) + return AlternatingContrTensor.interior_product(self_r, form_r) + + def bracket(self, other): + r""" + Return the Schouten-Nijenhuis bracket of ``self`` with another + multivector field. + + The Schouten-Nijenhuis bracket extends the Lie bracket of + vector fields (cf. + :meth:`~sage.manifolds.differentiable.vectorfield.VectorField.bracket`) + to multivector fields. + + Denoting by `A^p(M)` the `C^k(M)`-module of `p`-vector fields on the + `C^k`-differentiable manifold `M` over the field `K` (cf. + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule`), + the *Schouten-Nijenhuis bracket* is a `K`-bilinear map + + .. MATH:: + + \begin{array}{ccc} + A^p(M)\times A^q(M) & \longrightarrow & A^{p+q-1}(M) \\ + (a,b) & \longmapsto & [a,b] + \end{array} + + which obeys the following properties: + + - if `p=0` and `q=0`, (i.e. `a` and `b` are two scalar fields), `[a,b]=0` + - if `p=0` (i.e. `a` is a scalar field) and `q\geq 1`, + `[a,b] = - \iota_{\mathrm{d}a} b` (minus the interior product of + the differential of `a` by `b`) + - if `p=1` (i.e. `a` is a vector field), `[a,b] = \mathcal{L}_a b` + (the Lie derivative of `b` along `a`) + - `[a,b] = -(-1)^{(p-1)(q-1)} [b,a]` + - for any multivector field `c` and `(a,b) \in A^p(M)\times A^q(M)`, + `[a,.]` obeys the *graded Leibniz rule* + + .. MATH:: + + [a,b\wedge c] = [a,b]\wedge c + (-1)^{(p-1)q} b\wedge [a,c] + + - for `(a,b,c) \in A^p(M)\times A^q(M)\times A^r(M)`, the *graded + Jacobi identity* holds: + + .. MATH:: + + (-1)^{(p-1)(r-1)}[a,[b,c]] + (-1)^{(q-1)(p-1)}[b,[c,a]] + + (-1)^{(r-1)(q-1)}[c,[a,b]] = 0 + + .. NOTE:: + + There are two definitions of the Schouten-Nijenhuis bracket in + the literature, which differ from each other when `p` is even + by an overall sign. The definition adopted here is that of + [Mar1997]_, [Kos1985]_ and :wikipedia:`Schouten-Nijenhuis_bracket`. + The other definition, adopted e.g. by [Nij1955]_, [Lic1977]_ + and [Vai1994]_, is `[a,b]' = (-1)^{p+1} [a,b]`. + + INPUT: + + - ``other`` -- a multivector field + + OUTPUT: + + - instance of :class:`MultivectorFieldParal` (or of + :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField` + if `p=1` and `q=0`) representing the + Schouten-Nijenhuis bracket `[a,b]`, where `a` is ``self`` and `b` is + ``other`` + + EXAMPLES: + + Let us consider two vector fields on a 3-dimensional manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: a = M.vector_field(name='a') + sage: a[:] = x*y+z, x+y-z, z-2*x+y + sage: b = M.vector_field(name='b') + sage: b[:] = y+2*z-x, x^2-y+z, z-x + + and form their Schouten-Nijenhuis bracket:: + + sage: s = a.bracket(b); s + Vector field [a,b] on the 3-dimensional differentiable manifold M + sage: s.display() + [a,b] = (-x^3 + (x + 3)*y - y^2 - (x + 2*y + 1)*z - 2*x) d/dx + + (2*x^2*y - x^2 + 2*x*z - 3*x) d/dy + + (-x^2 - (x - 4)*y - 3*x + 2*z) d/dz + + Check that `[a,b]` is actually the Lie bracket:: + + sage: f = M.scalar_field({X: x+y*z}, name='f') + sage: s(f) == a(b(f)) - b(a(f)) + True + + Check that `[a,b]` coincides with the Lie derivative of `b` along `a`:: + + sage: s == b.lie_derivative(a) + True + + Schouten-Nijenhuis bracket for `p=0` and `q=1`:: + + sage: s = f.bracket(a); s + Scalar field -i_df a on the 3-dimensional differentiable manifold M + sage: s.display() + -i_df a: M --> R + (x, y, z) |--> x*y - y^2 - (x + 2*y + 1)*z + z^2 + + Check that `[f,a] = - \iota_{\mathrm{d}f} a = - \mathrm{d}f(a)`:: + + sage: s == - f.differential()(a) + True + + Schouten-Nijenhuis bracket for `p=0` and `q=2`:: + + sage: c = M.multivector_field(2, name='c') + sage: c[0,1], c[0,2], c[1,2] = x+z+1, x*y+z, x-y + sage: s = f.bracket(c); s + Vector field -i_df c on the 3-dimensional differentiable manifold M + sage: s.display() + -i_df c = (x*y^2 + (x + y + 1)*z + z^2) d/dx + + (x*y - y^2 - x - z - 1) d/dy + (-x*y - (x - y + 1)*z) d/dz + + Check that `[f,c] = - \iota_{\mathrm{d}f} c`:: + + sage: s == - f.differential().interior_product(c) + True + + Schouten-Nijenhuis bracket for `p=1` and `q=2`:: + + sage: s = a.bracket(c); s + 2-vector field [a,c] on the 3-dimensional differentiable manifold M + sage: s.display() + [a,c] = ((x - 1)*y - (y - 2)*z - 2*x - 1) d/dx/\d/dy + + ((x + 1)*y - (x + 1)*z - 3*x - 1) d/dx/\d/dz + + (-5*x + y - z - 2) d/dy/\d/dz + + Again, since `a` is a vector field, the Schouten-Nijenhuis bracket + coincides with the Lie derivative:: + + sage: s == c.lie_derivative(a) + True + + Schouten-Nijenhuis bracket for `p=2` and `q=2`:: + + sage: d = M.multivector_field(2, name='d') + sage: d[0,1], d[0,2], d[1,2] = x-y^2, x+z, z-x-1 + sage: s = c.bracket(d); s + 3-vector field [c,d] on the 3-dimensional differentiable manifold M + sage: s.display() + [c,d] = (-y^3 + (3*x + 1)*y - y^2 - x - z + 2) d/dx/\d/dy/\d/dz + + Let us check the component formula (with respect to the manifold's + default coordinate chart, i.e. ``X``) for `p=q=2`, taking into + account the tensor antisymmetries:: + + sage: s[0,1,2] == - sum(c[i,0]*d[1,2].diff(i) + ....: + c[i,1]*d[2,0].diff(i) + c[i,2]*d[0,1].diff(i) + ....: + d[i,0]*c[1,2].diff(i) + d[i,1]*c[2,0].diff(i) + ....: + d[i,2]*c[0,1].diff(i) for i in M.irange()) + True + + Schouten-Nijenhuis bracket for `p=1` and `q=3`:: + + sage: e = M.multivector_field(3, name='e') + sage: e[0,1,2] = x+y*z+1 + sage: s = a.bracket(e); s + 3-vector field [a,e] on the 3-dimensional differentiable manifold M + sage: s.display() + [a,e] = (-(2*x + 1)*y + y^2 - (y^2 - x - 1)*z - z^2 + - 2*x - 2) d/dx/\d/dy/\d/dz + + Again, since `p=1`, the bracket coincides with the Lie derivative:: + + sage: s == e.lie_derivative(a) + True + + Schouten-Nijenhuis bracket for `p=2` and `q=3`:: + + sage: s = c.bracket(e); s + 4-vector field [c,e] on the 3-dimensional differentiable manifold M + + Since on a 3-dimensional manifold, any 4-vector field is zero, we have:: + + sage: s.display() + [c,e] = 0 + + Let us check the graded commutation law + `[a,b] = -(-1)^{(p-1)(q-1)} [b,a]` for various values of `p` and `q`:: + + sage: f.bracket(a) == - a.bracket(f) # p=0 and q=1 + True + sage: f.bracket(c) == c.bracket(f) # p=0 and q=2 + True + sage: a.bracket(b) == - b.bracket(a) # p=1 and q=1 + True + sage: a.bracket(c) == - c.bracket(a) # p=1 and q=2 + True + sage: c.bracket(d) == d.bracket(c) # p=2 and q=2 + True + + Let us check the graded Leibniz rule for `p=1` and `q=1`:: + + sage: a.bracket(b.wedge(c)) == a.bracket(b).wedge(c) + b.wedge(a.bracket(c)) + True + + as well as for `p=2` and `q=1`:: + + sage: c.bracket(a.wedge(b)) == c.bracket(a).wedge(b) - a.wedge(c.bracket(b)) + True + + Finally let us check the graded Jacobi identity for `p=1`, `q=1` and + `r=2`:: + + sage: a.bracket(b.bracket(c)) + b.bracket(c.bracket(a)) \ + ....: + c.bracket(a.bracket(b)) == 0 + True + + as well as for `p=1`, `q=2` and `r=2`:: + + sage: a.bracket(c.bracket(d)) + c.bracket(d.bracket(a)) \ + ....: - d.bracket(a.bracket(c)) == 0 + True + + """ + from itertools import combinations + from sage.combinat.permutation import Permutation + from sage.tensor.modules.comp import (Components, CompWithSym, + CompFullyAntiSym) + from sage.manifolds.differentiable.scalarfield import DiffScalarField + pp = self._tensor_rank + mp1 = (-1)**(pp+1) + if isinstance(other, DiffScalarField): + resu = other.differential().interior_product(self) + if mp1 == 1: + return resu + return - resu + # Some checks: + if not isinstance(other, (MultivectorField, MultivectorFieldParal)): + raise TypeError("{} is not a multivector field".format(other)) + if (self._vmodule.destination_map() is not self._domain.identity_map() + or other._vmodule.destination_map() is not + other._domain.identity_map()): + raise ValueError("the Schouten-Nijenhuis bracket is defined " + + "only for fields with a trivial destination map") + # Search for a common domain + dom_resu = self._domain.intersection(other._domain) + self_r = self.restrict(dom_resu) + other_r = other.restrict(dom_resu) + # Search for a common coordinate frame: + coord_frame = self_r._common_coord_frame(other_r) + if coord_frame is None: + raise ValueError("no common coordinate frame found") + chart = coord_frame.chart() + dom_resu = chart.domain() + fmodule = dom_resu.vector_field_module() + ring = fmodule.base_ring() # same as dom_resu.scalar_field_algebra() + aa = self_r.comp(coord_frame) # components A^{i_1...i_p} + bb = other_r.comp(coord_frame) # components B^{j_1...j_q} + qq = other._tensor_rank + deg_resu = pp + qq - 1 # degree of the result + nn = dom_resu.dim() + if deg_resu == 1: + resuc = Components(ring, coord_frame, 1, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + else: + resuc = CompFullyAntiSym(ring, coord_frame, deg_resu, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + # Partial derivatives of the components of self: + if pp == 1: + daa = Components(ring, coord_frame, 2, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + else: + daa = CompWithSym(ring, coord_frame, pp+1, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter, + antisym=range(pp)) + for ind, val in aa._comp.items(): + for k in fmodule.irange(): + daa[[ind+(k,)]] = val.coord_function(chart).diff(k) + # Partial derivatives of the components of other: + if qq == 1: + dbb = Components(ring, coord_frame, 2, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + else: + dbb = CompWithSym(ring, coord_frame, qq+1, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter, + antisym=range(qq)) + for ind, val in bb._comp.items(): + for k in fmodule.irange(): + dbb[[ind+(k,)]] = val.coord_function(chart).diff(k) + # Computation + for ind in resuc.non_redundant_index_generator(): + sind = set(ind) # {i_1, i_2, ..., i_{p+q-1}} + # Term a^{l j_2 ... j_p} \partial_l b^{k_1 ... k_q} + # with (j_2,...,j_p,k_1,...,k_q) spanning all permutations of + # (i_1, i_2, ..., i_{p+q-1}) + for sind_a in combinations(sind, pp-1): + sind_b = sind.difference(sind_a) + ind_a = tuple(sorted(sind_a)) + ind_b = tuple(sorted(sind_b)) + sum = 0 + for l in fmodule.irange(): + sum += aa[[(l,) + ind_a]] * dbb[[ind_b + (l,)]] + ind_ab = ind_a + ind_b + sign = Permutation([ind_ab.index(i) + 1 for i in ind]).signature() + if mp1*sign == 1: + resuc[[ind]] += sum + else: + resuc[[ind]] -= sum + # Term b^{l k_2 ... k_q} \partial_l a^{j_1 ... j_p} + # with (j_1,...,j_p,k_2,...,k_q) spanning all permutations of + # (i_1, i_2, ..., i_{p+q-1}) + for sind_b in combinations(sind, qq-1): + sind_a = sind.difference(sind_b) + ind_a = tuple(sorted(sind_a)) + ind_b = tuple(sorted(sind_b)) + sum = 0 + for l in fmodule.irange(): + sum += bb[[(l,) + ind_b]] * daa[[ind_a + (l,)]] + ind_ab = ind_a + ind_b + sign = Permutation([ind_ab.index(i) + 1 for i in ind]).signature() + if sign == 1: + resuc[[ind]] -= sum + else: + resuc[[ind]] += sum + # Name of the result: + resu_name = None + resu_latex_name = None + if self._name is not None and other._name is not None: + resu_name = '[' + self._name + ',' + other._name + ']' + if self._latex_name is not None and other._latex_name is not None: + resu_latex_name = r'\left[' + self._latex_name + ',' + \ + other._latex_name + r'\right]' + # Creation of the multivector with the components obtained above: + resu = fmodule.tensor_from_comp((deg_resu, 0), resuc, name=resu_name, + latex_name=resu_latex_name) + return resu diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index d7f47c031e1..3303434c78a 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -725,8 +725,8 @@ def differential(self): sage: latex(df) \mathrm{d}f sage: df.parent() - Free module /\^1(M) of 1-forms on the 3-dimensional differentiable - manifold M + Free module Omega^1(M) of 1-forms on the 3-dimensional + differentiable manifold M The result is cached, i.e. is not recomputed unless ``f`` is changed:: @@ -929,3 +929,127 @@ def hodge_dual(self, metric): """ return metric.hodge_star(self) + + def bracket(self, other): + r""" + Return the Schouten-Nijenhuis bracket of ``self``, considered as a + multivector field of degree 0, with a multivector field. + + See + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.bracket` + for details. + + INPUT: + + - ``other`` -- a multivector field of degree `p` + + OUTPUT: + + - if `p=0`, a zero scalar field + - if `p=1`, an instance of :class:`DiffScalarField` representing + the Schouten-Nijenhuis bracket ``[self,other]`` + - if `p\geq 2`, an instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + representing the Schouten-Nijenhuis bracket ``[self,other]`` + + EXAMPLES: + + The Schouten-Nijenhuis bracket of two scalar fields is identically + zero:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: f = M.scalar_field({X: x+y^2}, name='f') + sage: g = M.scalar_field({X: y-x}, name='g') + sage: s = f.bracket(g); s + Scalar field zero on the 2-dimensional differentiable manifold M + sage: s.display() + zero: M --> R + (x, y) |--> 0 + + while the Schouten-Nijenhuis bracket of a scalar field `f` with a + multivector field `a` is equal to minus the interior product of the + differential of `f` with `a`:: + + sage: a = M.multivector_field(2, name='a') + sage: a[0,1] = x*y ; a.display() + a = x*y d/dx/\d/dy + sage: s = f.bracket(a); s + Vector field -i_df a on the 2-dimensional differentiable manifold M + sage: s.display() + -i_df a = 2*x*y^2 d/dx - x*y d/dy + + See + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.bracket` + for other examples. + + """ + if isinstance(other, DiffScalarField): + return self._domain.intersection(other._domain).zero_scalar_field() + return - self.differential().interior_product(other) + + def wedge(self, other): + r""" + Return the exterior product of ``self``, considered as a differential + form of degree 0 or a multivector field of degree 0, with ``other``. + + See + :meth:`~sage.manifolds.differentiable.diff_form.DiffFormParal.wedge` + (exterior product of differential forms) or + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal.wedge` + (exterior product of multivector fields) for details. + + For a scalar field `f` and a `p`-form (or `p`-vector field) `a`, the + exterior product reduces to the standard product on the left by an + element of the base ring of the module of `p`-forms (or `p`-vector + fields): `f\wedge a = f a`. + + INPUT: + + - ``other`` -- a differential form or a multivector field `a` + + OUTPUT: + + - the product `f a`, where `f` is ``self`` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: f = M.scalar_field({X: x+y^2}, name='f') + sage: a = M.diff_form(2, name='a') + sage: a[0,1] = x*y + sage: s = f.wedge(a); s + 2-form on the 2-dimensional differentiable manifold M + sage: s.display() + (x*y^3 + x^2*y) dx/\dy + + """ + return self*other + + def degree(self): + r""" + Return the degree of ``self``, considered as a differential + form or a multivector field, i.e. zero. + + This trivial method is provided for consistency with the exterior + calculus scheme, cf. the methods + :meth:`~sage.manifolds.differentiable.diff_form.DiffForm.degree` + (differential forms) and + :meth:`~sage.manifolds.differentiable.multivectorfield.MultivectorField.degree` + (multivector fields). + + OUTPUT: + + - 0 + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: f = M.scalar_field({X: x+y^2}) + sage: f.degree() + 0 + + """ + return 0 diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 3cdbf70dd24..77214b42ac5 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -105,7 +105,7 @@ class TensorField(ModuleElement): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldModule`) - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank @@ -2238,7 +2238,7 @@ def __call__(self, *args): resu_rr = self_rr(*args_rr) if resu_rr.is_trivial_zero(): for chart in resu_rr._domain._atlas: - resu._express[chart] = chart._zero_function + resu._express[chart] = chart.zero_function() else: for chart, expr in resu_rr._express.items(): resu._express[chart] = expr diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 04f62826bab..90dd1b556f1 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -45,7 +45,10 @@ from sage.tensor.modules.tensor_free_module import TensorFreeModule from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal -from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal +from sage.manifolds.differentiable.diff_form import (DiffForm, + DiffFormParal) +from sage.manifolds.differentiable.multivectorfield import (MultivectorField, + MultivectorFieldParal) from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, AutomorphismFieldParal) @@ -94,7 +97,7 @@ class TensorFieldModule(UniqueRepresentation, Parent): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank and `l` the covariant rank @@ -310,26 +313,49 @@ def _element_constructor_(self, comp=[], frame=None, name=None, # coercion of a p-form to a type-(0,p) tensor field: form = comp # for readability p = form.degree() - if self._tensor_type != (0,p) or self._vmodule != form.base_module(): + if (self._tensor_type != (0,p) or + self._vmodule != form.base_module()): raise TypeError("cannot convert the {}".format(form) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._vmodule, (0,p), name=form._name, + resu = self.element_class(self._vmodule, (0,p), + name=form._name, latex_name=form._latex_name, antisym=asym) for dom, rst in form._restrictions.items(): resu._restrictions[dom] = dom.tensor_field_module((0,p))(rst) return resu + if isinstance(comp, MultivectorField): + # coercion of a p-vector field to a type-(p,0) tensor: + pvect = comp # for readability + p = pvect.degree() + if (self._tensor_type != (p,0) or + self._vmodule != pvect.base_module()): + raise TypeError("cannot convert the {}".format(pvect) + + " to an element of {}".format(self)) + if p == 1: + asym = None + else: + asym = range(p) + resu = self.element_class(self._vmodule, (p,0), + name=pvect._name, + latex_name=pvect._latex_name, + antisym=asym) + for dom, rst in pvect._restrictions.items(): + resu._restrictions[dom] = dom.tensor_field_module((p,0))(rst) + return resu if isinstance(comp, AutomorphismField): # coercion of an automorphism to a type-(1,1) tensor: autom = comp # for readability - if self._tensor_type != (1,1) or self._vmodule != autom.base_module(): + if (self._tensor_type != (1,1) or + self._vmodule != autom.base_module()): raise TypeError("cannot convert the {}".format(autom) + " to an element of {}".format(self)) - resu = self.element_class(self._vmodule, (1,1), name=autom._name, + resu = self.element_class(self._vmodule, (1,1), + name=autom._name, latex_name=autom._latex_name) for dom, rest in autom._restrictions.items(): resu._restrictions[dom] = dom.tensor_field_module((1,1))(rest) @@ -337,17 +363,17 @@ def _element_constructor_(self, comp=[], frame=None, name=None, if isinstance(comp, TensorField): # coercion by domain restriction if (self._tensor_type == comp._tensor_type - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset(comp._ambient_domain)): return comp.restrict(self._domain) else: raise TypeError("cannot convert the {}".format(comp) + " to an element of {}".format(self)) # standard construction - resu = self.element_class(self._vmodule, self._tensor_type, name=name, - latex_name=latex_name, sym=sym, - antisym=antisym) + resu = self.element_class(self._vmodule, self._tensor_type, + name=name, latex_name=latex_name, + sym=sym, antisym=antisym) if comp != []: resu.set_comp(frame)[:] = comp return resu @@ -395,13 +421,20 @@ def _coerce_map_from_(self, other): False sage: T02._coerce_map_from_(M.diff_form_module(2)) True + sage: T20 = M.tensor_field_module((2,0)) + sage: T20._coerce_map_from_(M.multivector_module(2)) + True sage: T11 = M.tensor_field_module((1,1)) sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import DiffFormModule - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldGroup + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormModule + from sage.manifolds.differentiable.multivector_module import \ + MultivectorModule + from sage.manifolds.differentiable.automorphismfield_group \ + import AutomorphismFieldGroup if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type @@ -411,6 +444,10 @@ def _coerce_map_from_(self, other): # coercion of p-forms to type-(0,p) tensor fields return (self._vmodule is other.base_module() and self._tensor_type == (0, other.degree())) + if isinstance(other, MultivectorModule): + # coercion of p-vector fields to type-(p,0) tensor fields + return (self._vmodule is other.base_module() + and self._tensor_type == (other.degree(),0)) if isinstance(other, AutomorphismFieldGroup): # coercion of automorphism fields to type-(1,1) tensor fields return (self._vmodule is other.base_module() @@ -541,7 +578,7 @@ def zero(self): # (since new components are initialized to zero) return resu -#****************************************************************************** +#*********************************************************************** class TensorFieldFreeModule(TensorFreeModule): r""" @@ -589,7 +626,7 @@ class TensorFieldFreeModule(TensorFreeModule): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank and `l` the covariant rank @@ -711,7 +748,8 @@ def __init__(self, vector_field_module, tensor_type): kcon = tensor_type[0] lcov = tensor_type[1] name = "T^({},{})({}".format(kcon, lcov, domain._name) - latex_name = r"\mathcal{{T}}^{{({}, {})}}\left(".format(kcon, lcov, domain._latex_name) + latex_name = r"\mathcal{{T}}^{{({}, {})}}\left(".format(kcon, + lcov, domain._latex_name) if dest_map is domain.identity_map(): name += ")" latex_name += r"\right)" @@ -738,8 +776,8 @@ def _element_constructor_(self, comp=[], frame=None, name=None, sage: T12 = M.tensor_field_module((1,2)) sage: t = T12([[[x,-y], [2,y]], [[1+x,y^2], [x^2,3]], ....: [[x*y, 1-x], [y^2, x]]], name='t'); t - Tensor field t of type (1,2) on the 2-dimensional differentiable - manifold M + Tensor field t of type (1,2) on the 2-dimensional + differentiable manifold M sage: t.display() t = x d/dx*dx*dx - y d/dx*dx*dy + 2 d/dx*dy*dx + y d/dx*dy*dy + (x + 1) d/dy*dx*dx + y^2 d/dy*dx*dy + x^2 d/dy*dy*dx @@ -754,26 +792,49 @@ def _element_constructor_(self, comp=[], frame=None, name=None, # coercion of a p-form to a type-(0,p) tensor field: form = comp # for readability p = form.degree() - if self._tensor_type != (0,p) or self._fmodule != form.base_module(): + if (self._tensor_type != (0,p) or + self._fmodule != form.base_module()): raise TypeError("cannot convert the {}".format(form) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._fmodule, (0,p), name=form._name, + resu = self.element_class(self._fmodule, (0,p), + name=form._name, latex_name=form._latex_name, antisym=asym) for frame, cp in form._components.items(): resu._components[frame] = cp.copy() return resu + if isinstance(comp, MultivectorFieldParal): + # coercion of a p-vector field to a type-(p,0) tensor field: + pvect = comp # for readability + p = pvect.degree() + if (self._tensor_type != (p,0) or + self._fmodule != pvect.base_module()): + raise TypeError("cannot convert the {}".format(pvect) + + " to an element of {}".format(self)) + if p == 1: + asym = None + else: + asym = range(p) + resu = self.element_class(self._fmodule, (p,0), + name=pvect._name, + latex_name=pvect._latex_name, + antisym=asym) + for frame, cp in pvect._components.items(): + resu._components[frame] = cp.copy() + return resu if isinstance(comp, AutomorphismFieldParal): # coercion of an automorphism to a type-(1,1) tensor: autom = comp # for readability - if self._tensor_type != (1,1) or self._fmodule != autom.base_module(): + if (self._tensor_type != (1,1) or + self._fmodule != autom.base_module()): raise TypeError("cannot convert the {}".format(autom) + " to an element of {}".format(self)) - resu = self.element_class(self._fmodule, (1,1), name=autom._name, + resu = self.element_class(self._fmodule, (1,1), + name=autom._name, latex_name=autom._latex_name) for basis, comp in autom._components.items(): resu._components[basis] = comp.copy() @@ -781,16 +842,17 @@ def _element_constructor_(self, comp=[], frame=None, name=None, if isinstance(comp, TensorField): # coercion by domain restriction if (self._tensor_type == comp._tensor_type - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + and self._domain.is_subset(comp._domain) + and self._ambient_domain.is_subset( + comp._ambient_domain)): return comp.restrict(self._domain) else: raise TypeError("cannot convert the {}".format(comp) + " to an element of {}".format(self)) # Standard construction - resu = self.element_class(self._fmodule, self._tensor_type, name=name, - latex_name=latex_name, sym=sym, - antisym=antisym) + resu = self.element_class(self._fmodule, self._tensor_type, + name=name, latex_name=latex_name, + sym=sym, antisym=antisym) if comp != []: resu.set_comp(frame)[:] = comp return resu @@ -814,13 +876,20 @@ def _coerce_map_from_(self, other): False sage: T02._coerce_map_from_(M.diff_form_module(2)) True + sage: T20 = M.tensor_field_module((2,0)) + sage: T20._coerce_map_from_(M.multivector_module(2)) + True sage: T11 = M.tensor_field_module((1,1)) sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldParalGroup + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormFreeModule + from sage.manifolds.differentiable.multivector_module import \ + MultivectorFreeModule + from sage.manifolds.differentiable.automorphismfield_group \ + import AutomorphismFieldParalGroup if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type @@ -830,6 +899,10 @@ def _coerce_map_from_(self, other): # coercion of p-forms to type-(0,p) tensor fields return (self._fmodule is other.base_module() and self._tensor_type == (0, other.degree())) + if isinstance(other, MultivectorFreeModule): + # coercion of p-vector fields to type-(p,0) tensor fields + return (self._fmodule is other.base_module() + and self._tensor_type == (other.degree(),0)) if isinstance(other, AutomorphismFieldParalGroup): # coercion of automorphism fields to type-(1,1) tensor fields return (self._fmodule is other.base_module() diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index 7e4a9b6e50c..a0df9bc757f 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -342,7 +342,7 @@ class TensorFieldParal(FreeModuleTensor, TensorField): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` associated with the map `\Phi: U \rightarrow M` (cf. :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`) - ``tensor_type`` -- pair `(k,l)` with `k` being the contravariant rank diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index d0709bc5ce2..56647f32fd3 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -36,6 +36,7 @@ - Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version - Marco Mancini (2015): parallelization of vector field plots - Travis Scrimshaw (2016): review tweaks +- Eric Gourgoulhon (2017): vector fields inherit from multivector fields REFERENCES: @@ -47,7 +48,7 @@ """ #****************************************************************************** -# Copyright (C) 2015 Eric Gourgoulhon +# Copyright (C) 2015, 2017 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # Copyright (C) 2015 Marco Mancini # Copyright (C) 2016 Travis Scrimshaw @@ -59,11 +60,11 @@ #****************************************************************************** from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement -from sage.manifolds.differentiable.tensorfield import TensorField -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, MultivectorFieldParal) from sage.misc.decorators import options -class VectorField(TensorField): +class VectorField(MultivectorField): r""" Vector field along a differentiable manifold. @@ -101,7 +102,7 @@ class VectorField(TensorField): INPUT: - - ``vector_field_module`` -- module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M\supset\Phi(U)` - ``name`` -- (default: ``None``) name given to the vector field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector @@ -229,10 +230,10 @@ def __init__(self, vector_field_module, name=None, latex_name=None): Fix ``_test_pickling`` (in the superclass :class:`TensorField`). """ - TensorField.__init__(self, vector_field_module, (1,0), name=name, - latex_name=latex_name) + MultivectorField.__init__(self, vector_field_module, 1, name=name, + latex_name=latex_name) # Initialization of derived quantities: - TensorField._init_derived(self) + MultivectorField._init_derived(self) # Initialization of list of quantities depending on self: self._init_dependencies() @@ -360,7 +361,8 @@ def __call__(self, scalar): else: resu_name = None if self._latex_name is not None and scalar._latex_name is not None: - resu_latex = r"{}\left({}\right)".format(self._latex_name , scalar._latex_name) + resu_latex = r"{}\left({}\right)".format(self._latex_name , + scalar._latex_name) else: resu_latex = None resu = dom_resu.scalar_field(name=resu_name, latex_name=resu_latex) @@ -919,9 +921,17 @@ def bracket(self, other): """ Return the Lie bracket ``[self, other]``. + INPUT: + + - ``other`` -- a :class:`VectorField` + + OUTPUT: + + - the :class:`VectorField` ``[self, other]`` + EXAMPLES:: - sage: M = Manifold(3, 'M', structure='smooth') + sage: M = Manifold(3, 'M') sage: X. = M.chart() sage: v = -X.frame()[0] + 2*X.frame()[1] - (x^2 - y)*X.frame()[2] sage: w = (z + y) * X.frame()[1] - X.frame()[2] @@ -929,12 +939,25 @@ def bracket(self, other): Vector field on the 3-dimensional differentiable manifold M sage: vw.display() (-x^2 + y + 2) d/dy + (-y - z) d/dz + + Some checks:: + + sage: vw == - w.bracket(v) + True + sage: f = M.scalar_field({X: x+y*z}) + sage: vw(f) == v(w(f)) - w(v(f)) + True + sage: vw == w.lie_derivative(v) + True + """ - return other.lie_der(self) + # Call of the Schouten-Nijenhuis bracket + return MultivectorField.bracket(self, other) #****************************************************************************** -class VectorFieldParal(FiniteRankFreeModuleElement, TensorFieldParal, VectorField): +class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal, + VectorField): r""" Vector field along a differentiable manifold, with values on a parallelizable manifold. @@ -973,7 +996,7 @@ class VectorFieldParal(FiniteRankFreeModuleElement, TensorFieldParal, VectorFiel INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U,\Phi)` of vector + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector fields along `U` with values on `M\supset\Phi(U)` - ``name`` -- (default: ``None``) name given to the vector field - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector @@ -1146,13 +1169,13 @@ def __init__(self, vector_field_module, name=None, latex_name=None): """ FiniteRankFreeModuleElement.__init__(self, vector_field_module, name=name, latex_name=latex_name) - # TensorFieldParal attributes: + # MultivectorFieldParal attributes: self._domain = vector_field_module._domain self._ambient_domain = vector_field_module._ambient_domain # VectorField attributes: self._vmodule = vector_field_module # Initialization of derived quantities: - TensorFieldParal._init_derived(self) + MultivectorFieldParal._init_derived(self) VectorField._init_derived(self) # Initialization of list of quantities depending on self: self._init_dependencies() @@ -1210,7 +1233,8 @@ def _del_derived(self, del_restrictions=True): sage: v._del_derived() """ - TensorFieldParal._del_derived(self, del_restrictions=del_restrictions) + MultivectorFieldParal._del_derived(self, + del_restrictions=del_restrictions) VectorField._del_derived(self) self._del_dependencies() diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 9dd2719ca45..2f13188cc0b 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -44,7 +44,8 @@ from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule -from sage.manifolds.differentiable.vectorfield import (VectorField, VectorFieldParal) +from sage.manifolds.differentiable.vectorfield import (VectorField, + VectorFieldParal) class VectorFieldModule(UniqueRepresentation, Parent): r""" @@ -58,7 +59,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): \Phi:\ U \longrightarrow M, - the *vector field module* `\mathcal{X}(U,\Phi)` is the set of + the *vector field module* `\mathfrak{X}(U,\Phi)` is the set of all vector fields of the type .. MATH:: @@ -73,7 +74,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): where `T_{\Phi(p)}M` is the tangent space to `M` at the point `\Phi(p)`. - The set `\mathcal{X}(U,\Phi)` is a module over `C^k(U)`, the ring + The set `\mathfrak{X}(U,\Phi)` is a module over `C^k(U)`, the ring (algebra) of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). Furthermore, it is a Lie algebroid under the Lie bracket (cf. @@ -89,7 +90,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): The standard case of vector fields *on* a differentiable manifold corresponds to `U = M` and `\Phi = \mathrm{Id}_M`; we then denote - `\mathcal{X}(M,\mathrm{Id}_M)` by merely `\mathcal{X}(M)`. Other common + `\mathfrak{X}(M,\mathrm{Id}_M)` by merely `\mathfrak{X}(M)`. Other common cases are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open interval of `\RR`). @@ -114,9 +115,9 @@ class VectorFieldModule(UniqueRepresentation, Parent): sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole - sage: c_xy. = U.chart() # stereographic coordinates from the North pole + sage: c_xy. = U.chart() # stereographic coordinates from North pole sage: V = M.open_subset('V') # complement of the South pole - sage: c_uv. = V.chart() # stereographic coordinates from the South pole + sage: c_uv. = V.chart() # stereographic coordinates from South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), ....: intersection_name='W', restrictions1= x^2+y^2!=0, @@ -126,7 +127,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): Module X(M) of vector fields on the 2-dimensional differentiable manifold M - `\mathcal{X}(M)` is a module over the algebra `C^k(M)`:: + `\mathfrak{X}(M)` is a module over the algebra `C^k(M)`:: sage: XM.category() Category of modules over Algebra of differentiable scalar fields on the @@ -134,7 +135,7 @@ class VectorFieldModule(UniqueRepresentation, Parent): sage: XM.base_ring() is M.scalar_field_algebra() True - `\mathcal{X}(M)` is not a free module:: + `\mathfrak{X}(M)` is not a free module:: sage: isinstance(XM, FiniteRankFreeModule) False @@ -162,15 +163,17 @@ class VectorFieldModule(UniqueRepresentation, Parent): sage: z.display(c_uv.frame()) zero = 0 - The module `\mathcal{X}(M)` coerces to any module of vector fields defined - on a subdomain of `M`, for instance `\mathcal{X}(U)`:: + The module `\mathfrak{X}(M)` coerces to any module of vector fields defined + on a subdomain of `M`, for instance `\mathfrak{X}(U)`:: sage: XU.has_coerce_map_from(XM) True sage: XU.coerce_map_from(XM) Coercion map: - From: Module X(M) of vector fields on the 2-dimensional differentiable manifold M - To: Free module X(U) of vector fields on the Open subset U of the 2-dimensional differentiable manifold M + From: Module X(M) of vector fields on the 2-dimensional + differentiable manifold M + To: Free module X(U) of vector fields on the Open subset U of the + 2-dimensional differentiable manifold M The conversion map is actually the restriction of vector fields defined on `M` to `U`. @@ -187,9 +190,9 @@ def __init__(self, domain, dest_map=None): sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole - sage: c_xy. = U.chart() # stereographic coordinates from the North pole + sage: c_xy. = U.chart() # stereographic coordinates from North pole sage: V = M.open_subset('V') # complement of the South pole - sage: c_uv. = V.chart() # stereographic coordinates from the South pole + sage: c_uv. = V.chart() # stereographic coordinates from South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: xy_to_uv = c_xy.transition_map(c_uv, (x/(x^2+y^2), y/(x^2+y^2)), ....: intersection_name='W', restrictions1= x^2+y^2!=0, @@ -209,7 +212,7 @@ def __init__(self, domain, dest_map=None): """ self._domain = domain name = "X(" + domain._name - latex_name = r"\mathcal{X}\left(" + domain._latex_name + latex_name = r"\mathfrak{X}\left(" + domain._latex_name if dest_map is None: dest_map = domain.identity_map() self._dest_map = dest_map @@ -222,16 +225,21 @@ def __init__(self, domain, dest_map=None): self._ambient_domain = self._dest_map._codomain self._name = name self._latex_name = latex_name - # the member self._ring is created for efficiency (to avoid calls to - # self.base_ring()): + # The member self._ring is created for efficiency (to avoid + # calls to self.base_ring()): self._ring = domain.scalar_field_algebra() - Parent.__init__(self, base=self._ring, category=Modules(self._ring)) + Parent.__init__(self, base=self._ring, + category=Modules(self._ring)) # Dictionary of the tensor modules built on self - # (dict. keys = (k,l) --the tensor type) - self._tensor_modules = {(1,0): self} # self is considered as the set of - # tensors of type (1,0) - # Dictionary of exterior powers of the dual of self - # (keys = p --the power degree) : + # (keys = (k,l) --the tensor type) + # This dictionary is to be extended on need by the method tensor_module + self._tensor_modules = {(1,0): self} # self is considered as the set + # of tensors of type (1,0) + # Dictionaries of exterior powers of self and of its dual + # (keys = p --the power degree) + # These dictionaries are to be extended on need by the methods + # exterior_power and dual_exterior_power + self._exterior_powers = {1: self} self._dual_exterior_powers = {} #### Parent methods @@ -358,9 +366,9 @@ def _latex_(self): sage: M = Manifold(2, 'M') sage: XM = M.vector_field_module() sage: XM._latex_() - '\\mathcal{X}\\left(M\\right)' + '\\mathfrak{X}\\left(M\\right)' sage: latex(XM) # indirect doctest - \mathcal{X}\left(M\right) + \mathfrak{X}\left(M\right) """ if self._latex_name is None: @@ -372,7 +380,7 @@ def domain(self): r""" Return the domain of the vector fields in this module. - If the module is `\mathcal{X}(U,\Phi)`, returns the domain `U` of + If the module is `\mathfrak{X}(U,\Phi)`, returns the domain `U` of `\Phi`. OUTPUT: @@ -402,7 +410,7 @@ def ambient_domain(self): Return the manifold in which the vector fields of this module take their values. - If the module is `\mathcal{X}(U,\Phi)`, returns the codomain `M` of + If the module is `\mathfrak{X}(U,\Phi)`, returns the codomain `M` of `\Phi`. OUTPUT: @@ -437,7 +445,7 @@ def destination_map(self): \Phi:\ U \longrightarrow M - such that this module is the set `\mathcal{X}(U,\Phi)` of all + such that this module is the set `\mathfrak{X}(U,\Phi)` of all vector fields of the type .. MATH:: @@ -521,18 +529,74 @@ def tensor_module(self, k, l): for more examples and documentation. """ - from sage.manifolds.differentiable.tensorfield_module import TensorFieldModule + from sage.manifolds.differentiable.tensorfield_module import \ + TensorFieldModule if (k,l) not in self._tensor_modules: self._tensor_modules[(k,l)] = TensorFieldModule(self, (k,l)) return self._tensor_modules[(k,l)] + def exterior_power(self, p): + r""" + Return the `p`-th exterior power of ``self``. + + If the vector field module ``self`` is `\mathfrak{X}(U,\Phi)`, + its `p`-th exterior power is the set `A^p(U, \Phi)` of + `p`-vector fields along `U` with values on `\Phi(U)`. It is a + module over `C^k(U)`, the ring (algebra) of differentiable + scalar fields on `U`. + + INPUT: + + - ``p`` -- non-negative integer + + OUTPUT: + + - for `p=0`, the base ring, i.e. `C^k(U)` + - for `p=1`, the vector field module ``self``, since + `A^1(U, \Phi) = \mathfrak{X}(U,\Phi)` + - for `p \geq 2`, instance of + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + representing the module `A^p(U,\Phi)` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: XM = M.vector_field_module() + sage: XM.exterior_power(2) + Module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) + Module X(M) of vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) is XM + True + sage: XM.exterior_power(0) + Algebra of differentiable scalar fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(0) is M.scalar_field_algebra() + True + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorModule` + for more examples and documentation. + + """ + from sage.manifolds.differentiable.multivector_module import \ + MultivectorModule + if p == 0: + return self._ring + if p not in self._exterior_powers: + self._exterior_powers[p] = MultivectorModule(self, p) + return self._exterior_powers[p] + def dual_exterior_power(self, p): r""" Return the `p`-th exterior power of the dual of the vector field module. - If the vector field module is `\mathcal{X}(U,\Phi)`, the - `p`-th exterior power of its dual is the set `\Lambda^p(U, \Phi)` + If the vector field module is `\mathfrak{X}(U,\Phi)`, the + `p`-th exterior power of its dual is the set `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on `\Phi(U)`. It is a module over `C^k(U)`, the ring (algebra) of differentiable scalar fields on `U`. @@ -543,20 +607,20 @@ def dual_exterior_power(self, p): OUTPUT: + - for `p=0`, the base ring, i.e. `C^k(U)` - for `p \geq 1`, instance of :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormModule` - representing the module `\Lambda^p(U,\Phi)`; for `p=0`, the - base ring, i.e. `C^k(U)`, is returned instead + representing the module `\Omega^p(U,\Phi)` EXAMPLES:: sage: M = Manifold(2, 'M') sage: XM = M.vector_field_module() sage: XM.dual_exterior_power(2) - Module /\^2(M) of 2-forms on the 2-dimensional differentiable + Module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) - Module /\^1(M) of 1-forms on the 2-dimensional differentiable + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) is XM.dual() True @@ -572,7 +636,8 @@ def dual_exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.diff_form_module import DiffFormModule + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormModule if p == 0: return self._ring if p not in self._dual_exterior_powers: @@ -588,7 +653,7 @@ def dual(self): sage: M = Manifold(2, 'M') sage: XM = M.vector_field_module() sage: XM.dual() - Module /\^1(M) of 1-forms on the 2-dimensional differentiable + Module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M """ @@ -598,17 +663,17 @@ def general_linear_group(self): r""" Return the general linear group of ``self``. - If the vector field module is `\mathcal{X}(U,\Phi)`, the *general - linear group* is the group `\mathrm{GL}(\mathcal{X}(U,\Phi))` of - automorphisms of `\mathcal{X}(U, \Phi)`. Note that an automorphism - of `\mathcal{X}(U,\Phi)` can also be viewed as a *field* along `U` + If the vector field module is `\mathfrak{X}(U,\Phi)`, the *general + linear group* is the group `\mathrm{GL}(\mathfrak{X}(U,\Phi))` of + automorphisms of `\mathfrak{X}(U, \Phi)`. Note that an automorphism + of `\mathfrak{X}(U,\Phi)` can also be viewed as a *field* along `U` of automorphisms of the tangent spaces of `M \supset \Phi(U)`. OUTPUT: - instance of class :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldGroup` - representing `\mathrm{GL}(\mathcal{X}(U,\Phi))` + representing `\mathrm{GL}(\mathfrak{X}(U,\Phi))` EXAMPLES:: @@ -624,7 +689,8 @@ def general_linear_group(self): for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldGroup + from sage.manifolds.differentiable.automorphismfield_group import \ + AutomorphismFieldGroup return AutomorphismFieldGroup(self) def tensor(self, tensor_type, name=None, latex_name=None, sym=None, @@ -684,17 +750,23 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, """ from sage.manifolds.differentiable.automorphismfield import \ - AutomorphismField - from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + AutomorphismField + from sage.manifolds.differentiable.metric import \ + PseudoRiemannianMetric if tensor_type==(1,0): - return self.element_class(self, name=name, latex_name=latex_name) + return self.element_class(self, name=name, + latex_name=latex_name) elif tensor_type == (0,1): return self.linear_form(name=name, latex_name=latex_name) elif tensor_type == (1,1) and specific_type is not None: if issubclass(specific_type, AutomorphismField): - return self.automorphism(name=name, latex_name=latex_name) - elif (tensor_type[0] == 0 and tensor_type[1] > 1 - and antisym is not None and antisym != []): + return self.automorphism(name=name, + latex_name=latex_name) + elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] if isinstance(antisym, list): antisym0 = antisym[0] else: @@ -702,35 +774,100 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, if len(antisym0) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] + if isinstance(antisym, list): + antisym0 = antisym[0] else: - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + antisym0 = antisym + if len(antisym0) == tensor_type[0]: + return self.alternating_contravariant_tensor( + tensor_type[0], name=name, + latex_name=latex_name) elif tensor_type==(0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated # Generic case return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, sym=sym, - antisym=antisym) + tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) + + def alternating_contravariant_tensor(self, degree, name=None, + latex_name=None): + r""" + Construct an alternating contravariant tensor on the vector + field module ``self``. + + An alternating contravariant tensor on ``self`` is actually a + multivector field along the differentiable manifold `U` over + which ``self`` is defined. + + INPUT: + + - ``degree`` -- degree of the alternating contravariant tensor + (i.e. its tensor rank) + - ``name`` -- (default: ``None``) string; name given to the + alternating contravariant tensor + - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to + denote the alternating contravariant tensor; if none is + provided, the LaTeX symbol is set to ``name`` + + OUTPUT: + + - instance of + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: XM = M.vector_field_module() + sage: XM.alternating_contravariant_tensor(2, name='a') + 2-vector field a on the 2-dimensional differentiable + manifold M + + An alternating contravariant tensor of degree 1 is simply + a vector field:: + + sage: XM.alternating_contravariant_tensor(1, name='a') + Vector field a on the 2-dimensional differentiable + manifold M + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivectorfield.MultivectorField` + for more examples and documentation. + + """ + if degree == 0: + return self._domain.scalar_field(name=name, latex_name=latex_name) + if degree == 1: + return self.element_class(self, name=name, + latex_name=latex_name) + return self.exterior_power(degree).element_class(self, degree, + name=name, latex_name=latex_name) def alternating_form(self, degree, name=None, latex_name=None): r""" - Construct an alternating form on the vector field module. + Construct an alternating form on the vector field module + ``self``. - An alternating form on the vector field module is actually a - differential form along the differentiable manifold `U` over which - the vector field module is defined. + An alternating form on ``self`` is actually a differential form + along the differentiable manifold `U` over which ``self`` is + defined. INPUT: - ``degree`` -- the degree of the alternating form (i.e. its tensor rank) - - ``name`` -- (string; optional) name given to the alternating form + - ``name`` -- (string; optional) name given to the alternating + form - ``latex_name`` -- (string; optional) LaTeX symbol to denote - the alternating form; if none is provided, the - LaTeX symbol is set to ``name`` + the alternating form; if none is provided, the LaTeX symbol is + set to ``name`` OUTPUT: @@ -752,16 +889,18 @@ def alternating_form(self, degree, name=None, latex_name=None): for more examples and documentation. """ - return self.dual_exterior_power(degree).element_class(self, degree, - name=name, latex_name=latex_name) + if degree == 0: + return self._domain.scalar_field(name=name, latex_name=latex_name) + return self.dual_exterior_power(degree).element_class(self, + degree, name=name, latex_name=latex_name) def linear_form(self, name=None, latex_name=None): r""" Construct a linear form on the vector field module. A linear form on the vector field module is actually a field - of linear forms (i.e. a 1-form) along the differentiable manifold `U` - over which the vector field module is defined. + of linear forms (i.e. a 1-form) along the differentiable + manifold `U` over which the vector field module is defined. INPUT: @@ -790,16 +929,16 @@ def linear_form(self, name=None, latex_name=None): for more examples and documentation. """ - return self.dual_exterior_power(1).element_class(self, 1, name=name, - latex_name=latex_name) + return self.dual_exterior_power(1).element_class(self, 1, + name=name, latex_name=latex_name) def automorphism(self, name=None, latex_name=None): r""" Construct an automorphism of the vector field module. An automorphism of the vector field module is actually a field - of tangent-space automorphisms along the differentiable manifold `U` - over which the vector field module is defined. + of tangent-space automorphisms along the differentiable manifold + `U` over which the vector field module is defined. INPUT: @@ -830,8 +969,8 @@ def automorphism(self, name=None, latex_name=None): for more examples and documentation. """ - return self.general_linear_group().element_class(self, name=name, - latex_name=latex_name) + return self.general_linear_group().element_class(self, + name=name, latex_name=latex_name) @cached_method def identity_map(self, name='Id', latex_name=None): @@ -839,8 +978,8 @@ def identity_map(self, name='Id', latex_name=None): Construct the identity map on the vector field module. The identity map on the vector field module is actually a field - of tangent-space identity maps along the differentiable manifold `U` - over which the vector field module is defined. + of tangent-space identity maps along the differentiable manifold + `U` over which the vector field module is defined. INPUT: @@ -882,7 +1021,8 @@ def zero(self): sage: X. = M.chart() # makes M parallelizable sage: XM = M.vector_field_module() sage: XM.zero() - Vector field zero on the 2-dimensional differentiable manifold M + Vector field zero on the 2-dimensional differentiable + manifold M """ elt = self.element_class(self, name='zero', latex_name='0') for frame in self._domain._frames: @@ -951,7 +1091,7 @@ class VectorFieldFreeModule(FiniteRankFreeModule): \Phi:\ U \longrightarrow M - the *vector field module* `\mathcal{X}(U,\Phi)` is the set of all vector + the *vector field module* `\mathfrak{X}(U,\Phi)` is the set of all vector fields of the type .. MATH:: @@ -966,7 +1106,7 @@ class VectorFieldFreeModule(FiniteRankFreeModule): where `T_{\Phi(p)} M` is the tangent space to `M` at the point `\Phi(p)`. - Since `M` is parallelizable, the set `\mathcal{X}(U,\Phi)` is a + Since `M` is parallelizable, the set `\mathfrak{X}(U,\Phi)` is a free module over `C^k(U)`, the ring (algebra) of differentiable scalar fields on `U` (see :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). @@ -975,14 +1115,14 @@ class VectorFieldFreeModule(FiniteRankFreeModule): The standard case of vector fields *on* a differentiable manifold corresponds to `U=M` and `\Phi = \mathrm{Id}_M`; we then denote - `\mathcal{X}(M,\mathrm{Id}_M)` by merely `\mathcal{X}(M)`. Other common + `\mathfrak{X}(M,\mathrm{Id}_M)` by merely `\mathfrak{X}(M)`. Other common cases are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an open interval of `\RR`). .. NOTE:: If `M` is not parallelizable, the class :class:`VectorFieldModule` - should be used instead, for `\mathcal{X}(U,\Phi)` is no longer a + should be used instead, for `\mathfrak{X}(U,\Phi)` is no longer a free module. INPUT: @@ -1049,7 +1189,7 @@ class VectorFieldFreeModule(FiniteRankFreeModule): over Algebra of differentiable scalar fields on the 1-dimensional differentiable manifold I - The rank of the free module `\mathcal{X}(I,\Phi)` is the dimension + The rank of the free module `\mathfrak{X}(I,\Phi)` is the dimension of the manifold `\RR^2`, namely two:: sage: XIM.rank() @@ -1141,8 +1281,8 @@ class VectorFieldFreeModule(FiniteRankFreeModule): sage: z.display(c_t.frame()) zero = 0 - The module `\mathcal{X}(S^1)` coerces to any module of vector fields - defined on a subdomain of `S^1`, for instance `\mathcal{X}(U)`:: + The module `\mathfrak{X}(S^1)` coerces to any module of vector fields + defined on a subdomain of `S^1`, for instance `\mathfrak{X}(U)`:: sage: XU = U.vector_field_module() ; XU Free module X(U) of vector fields on the Open subset U of the @@ -1151,8 +1291,10 @@ class VectorFieldFreeModule(FiniteRankFreeModule): True sage: XU.coerce_map_from(XM) Coercion map: - From: Free module X(S^1) of vector fields on the 1-dimensional differentiable manifold S^1 - To: Free module X(U) of vector fields on the Open subset U of the 1-dimensional differentiable manifold S^1 + From: Free module X(S^1) of vector fields on the 1-dimensional + differentiable manifold S^1 + To: Free module X(U) of vector fields on the Open subset U of the + 1-dimensional differentiable manifold S^1 The conversion map is actually the restriction of vector fields defined on `S^1` to `U`. @@ -1191,7 +1333,7 @@ def __init__(self, domain, dest_map=None): self._dest_map = dest_map self._ambient_domain = self._dest_map._codomain name = "X(" + domain._name - latex_name = r"\mathcal{X}\left(" + domain._latex_name + latex_name = r"\mathfrak{X}\left(" + domain._latex_name if self._dest_map == domain.identity_map(): name += ")" latex_name += r"\right)" @@ -1318,7 +1460,7 @@ def domain(self): r""" Return the domain of the vector fields in ``self``. - If the module is `\mathcal{X}(U, \Phi)`, returns the domain `U` + If the module is `\mathfrak{X}(U, \Phi)`, returns the domain `U` of `\Phi`. OUTPUT: @@ -1350,7 +1492,7 @@ def ambient_domain(self): Return the manifold in which the vector fields of ``self`` take their values. - If the module is `\mathcal{X}(U, \Phi)`, returns the codomain `M` + If the module is `\mathfrak{X}(U, \Phi)`, returns the codomain `M` of `\Phi`. OUTPUT: @@ -1387,7 +1529,7 @@ def destination_map(self): \Phi:\ U \longrightarrow M - such that this module is the set `\mathcal{X}(U,\Phi)` of all vector + such that this module is the set `\mathfrak{X}(U,\Phi)` of all vector fields of the type .. MATH:: @@ -1475,20 +1617,77 @@ def tensor_module(self, k, l): for more examples and documentation. """ - from sage.manifolds.differentiable.tensorfield_module import TensorFieldFreeModule + from sage.manifolds.differentiable.tensorfield_module import \ + TensorFieldFreeModule if (k,l) not in self._tensor_modules: self._tensor_modules[(k,l)] = TensorFieldFreeModule(self, (k,l)) return self._tensor_modules[(k,l)] + def exterior_power(self, p): + r""" + Return the `p`-th exterior power of ``self``. + + If the vector field module ``self`` is `\mathfrak{X}(U,\Phi)`, + its `p`-th exterior power is the set `A^p(U, \Phi)` of + `p`-vector fields along `U` with values on `\Phi(U)`. It is a + free module over `C^k(U)`, the ring (algebra) of differentiable + scalar fields on `U`. + + INPUT: + + - ``p`` -- non-negative integer + + OUTPUT: + + - for `p=0`, the base ring, i.e. `C^k(U)` + - for `p=1`, the vector field free module ``self``, since + `A^1(U, \Phi) = \mathfrak{X}(U,\Phi)` + - for `p \geq 2`, instance of + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorFreeModule` + representing the module `A^p(U,\Phi)` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() # makes M parallelizable + sage: XM = M.vector_field_module() + sage: XM.exterior_power(2) + Free module A^2(M) of 2-vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) + Free module X(M) of vector fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(1) is XM + True + sage: XM.exterior_power(0) + Algebra of differentiable scalar fields on the 2-dimensional + differentiable manifold M + sage: XM.exterior_power(0) is M.scalar_field_algebra() + True + + .. SEEALSO:: + + :class:`~sage.manifolds.differentiable.multivector_module.MultivectorFreeModule` + for more examples and documentation. + + """ + from sage.manifolds.differentiable.multivector_module import \ + MultivectorFreeModule + if p == 0: + return self._ring + if p not in self._exterior_powers: + self._exterior_powers[p] = MultivectorFreeModule(self, p) + return self._exterior_powers[p] + def dual_exterior_power(self, p): r""" Return the `p`-th exterior power of the dual of ``self``. - If the vector field module is `\mathcal{X}(U,\Phi)`, the - `p`-th exterior power of its dual is the set `\Lambda^p(U, \Phi)` - of `p`-forms along `U` with values on `\Phi(U)`. It is a module - over `C^k(U)`, the ring (algebra) of differentiable scalar - fields on `U`. + If the vector field module ``self`` is `\mathfrak{X}(U,\Phi)`, + the `p`-th exterior power of its dual is the set + `\Omega^p(U, \Phi)` of `p`-forms along `U` with values on + `\Phi(U)`. It is a free module over `C^k(U)`, the ring (algebra) + of differentiable scalar fields on `U`. INPUT: @@ -1496,10 +1695,10 @@ def dual_exterior_power(self, p): OUTPUT: + - for `p=0`, the base ring, i.e. `C^k(U)` - for `p \geq 1`, a :class:`~sage.manifolds.differentiable.diff_form_module.DiffFormFreeModule` - representing the module `\Lambda^p(U,\Phi)`; for `p=0`, the - base ring, i.e. `C^k(U)`, is returned instead + representing the module `\Omega^p(U,\Phi)` EXAMPLES:: @@ -1507,11 +1706,11 @@ def dual_exterior_power(self, p): sage: X. = M.chart() # makes M parallelizable sage: XM = M.vector_field_module() sage: XM.dual_exterior_power(2) - Free module /\^2(M) of 2-forms on the 2-dimensional differentiable - manifold M + Free module Omega^2(M) of 2-forms on the 2-dimensional + differentiable manifold M sage: XM.dual_exterior_power(1) - Free module /\^1(M) of 1-forms on the 2-dimensional differentiable - manifold M + Free module Omega^1(M) of 1-forms on the 2-dimensional + differentiable manifold M sage: XM.dual_exterior_power(1) is XM.dual() True sage: XM.dual_exterior_power(0) @@ -1526,7 +1725,8 @@ def dual_exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule + from sage.manifolds.differentiable.diff_form_module import \ + DiffFormFreeModule if p == 0: return self._ring if p not in self._dual_exterior_powers: @@ -1537,17 +1737,17 @@ def general_linear_group(self): r""" Return the general linear group of ``self``. - If the vector field module is `\mathcal{X}(U,\Phi)`, the *general - linear group* is the group `\mathrm{GL}(\mathcal{X}(U,\Phi))` of - automorphisms of `\mathcal{X}(U,\Phi)`. Note that an automorphism of - `\mathcal{X}(U,\Phi)` can also be viewed as a *field* along `U` of + If the vector field module is `\mathfrak{X}(U,\Phi)`, the *general + linear group* is the group `\mathrm{GL}(\mathfrak{X}(U,\Phi))` of + automorphisms of `\mathfrak{X}(U,\Phi)`. Note that an automorphism of + `\mathfrak{X}(U,\Phi)` can also be viewed as a *field* along `U` of automorphisms of the tangent spaces of `V=\Phi(U)`. OUTPUT: - a :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldParalGroup` - representing `\mathrm{GL}(\mathcal{X}(U,\Phi))` + representing `\mathrm{GL}(\mathfrak{X}(U,\Phi))` EXAMPLES:: @@ -1564,7 +1764,8 @@ def general_linear_group(self): for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield_group import AutomorphismFieldParalGroup + from sage.manifolds.differentiable.automorphismfield_group import \ + AutomorphismFieldParalGroup return AutomorphismFieldParalGroup(self) def basis(self, symbol=None, latex_symbol=None, from_frame=None): @@ -1666,31 +1867,40 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, sage: X. = M.chart() # makes M parallelizable sage: XM = M.vector_field_module() sage: XM.tensor((1,2), name='t') - Tensor field t of type (1,2) on the 2-dimensional differentiable - manifold M + Tensor field t of type (1,2) on the 2-dimensional + differentiable manifold M sage: XM.tensor((1,0), name='a') - Vector field a on the 2-dimensional differentiable manifold M + Vector field a on the 2-dimensional differentiable + manifold M sage: XM.tensor((0,2), name='a', antisym=(0,1)) 2-form a on the 2-dimensional differentiable manifold M + sage: XM.tensor((2,0), name='a', antisym=(0,1)) + 2-vector field a on the 2-dimensional differentiable + manifold M See :class:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal` for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, - AutomorphismFieldParal) - from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismField, AutomorphismFieldParal) + from sage.manifolds.differentiable.metric import \ + PseudoRiemannianMetric if tensor_type == (1,0): - return self.element_class(self, name=name, latex_name=latex_name) + return self.element_class(self, name=name, + latex_name=latex_name) elif tensor_type == (0,1): return self.linear_form(name=name, latex_name=latex_name) elif tensor_type == (1,1) and specific_type is not None: if issubclass(specific_type, (AutomorphismField, AutomorphismFieldParal)): return self.automorphism(name=name, latex_name=latex_name) - elif (tensor_type[0] == 0 and tensor_type[1] > 1 - and antisym is not None and antisym != []): + elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] if isinstance(antisym, list): antisym0 = antisym[0] else: @@ -1698,20 +1908,30 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, if len(antisym0) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: + if isinstance(antisym[0], (int, Integer)): + # a single antisymmetry is provided as a tuple or a + # range object; it is converted to a 1-item list: + antisym = [tuple(antisym)] + if isinstance(antisym, list): + antisym0 = antisym[0] else: - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + antisym0 = antisym + if len(antisym0) == tensor_type[0]: + return self.alternating_contravariant_tensor( + tensor_type[0], name=name, + latex_name=latex_name) elif tensor_type==(0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated # Generic case return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, sym=sym, - antisym=antisym) + tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) - def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): + def tensor_from_comp(self, tensor_type, comp, name=None, + latex_name=None): r""" Construct a tensor on ``self`` from a set of components. @@ -1764,36 +1984,42 @@ def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): t = (x + 1) dx*dx - y dx*dy + x*y dy*dx + (-y^2 + 2) dy*dy """ - from sage.tensor.modules.comp import CompWithSym, CompFullySym, CompFullyAntiSym + from sage.tensor.modules.comp import (CompWithSym, CompFullySym, + CompFullyAntiSym) # 0/ Compatibility checks: if comp._ring is not self._ring: - raise ValueError("the components are not defined on the same " + - "ring as the module") + raise ValueError("the components are not defined on the " + + "same ring as the module") if comp._frame not in self._known_bases: - raise ValueError("the components are not defined on a basis of " + - "the module") + raise ValueError("the components are not defined on a " + + "basis of the module") if comp._nid != tensor_type[0] + tensor_type[1]: - raise ValueError("number of component indices not compatible " + - "with the tensor type") + raise ValueError("number of component indices not " + + "compatible with the tensor type") # # 1/ Construction of the tensor: if tensor_type == (1,0): - resu = self.element_class(self, name=name, latex_name=latex_name) + resu = self.element_class(self, name=name, + latex_name=latex_name) elif tensor_type == (0,1): resu = self.linear_form(name=name, latex_name=latex_name) elif (tensor_type[0] == 0 and tensor_type[1] > 1 and isinstance(comp, CompFullyAntiSym)): resu = self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif (tensor_type[0] > 1 and tensor_type[1] == 0 + and isinstance(comp, CompFullyAntiSym)): + resu = self.alternating_contravariant_tensor(tensor_type[0], + name=name, latex_name=latex_name) else: resu = self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name) + tensor_type, name=name, latex_name=latex_name) # Tensor symmetries deduced from those of comp: if isinstance(comp, CompWithSym): resu._sym = comp._sym resu._antisym = comp._antisym - + # # 2/ Tensor components set to comp: resu._components[comp._frame] = comp # @@ -1811,9 +2037,10 @@ def sym_bilinear_form(self, name=None, latex_name=None): INPUT: - ``name`` -- string (default: ``None``); name given to the - automorphism - - ``latex_name`` -- string (default: ``None``); LaTeX symbol to denote - the automorphism; if ``None``, the LaTeX symbol is set to ``name`` + symmetric bilinear bilinear form + - ``latex_name`` -- string (default: ``None``); LaTeX symbol to + denote the symmetric bilinear form; if ``None``, the LaTeX + symbol is set to ``name`` OUTPUT: @@ -1836,7 +2063,8 @@ def sym_bilinear_form(self, name=None, latex_name=None): for more examples and documentation. """ - return self.tensor((0,2), name=name, latex_name=latex_name, sym=(0,1)) + return self.tensor((0,2), name=name, latex_name=latex_name, + sym=(0,1)) #### End of methods to be redefined by derived classes of FiniteRankFreeModule #### @@ -1882,6 +2110,7 @@ def metric(self, name, signature=None, latex_name=None): for more documentation. """ - from sage.manifolds.differentiable.metric import PseudoRiemannianMetricParal + from sage.manifolds.differentiable.metric import \ + PseudoRiemannianMetricParal return PseudoRiemannianMetricParal(self, name, signature=signature, latex_name=latex_name) diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 8cb44524e26..fa26407ff68 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -199,7 +199,7 @@ class VectorFrame(FreeModuleBasis): INPUT: - - ``vector_field_module`` -- free module `\mathcal{X}(U, \Phi)` + - ``vector_field_module`` -- free module `\mathfrak{X}(U, \Phi)` of vector fields along `U` with values on `M \supset \Phi(U)` - ``symbol`` -- a letter (of a few letters) to denote a generic vector of the frame; can be set to None if the parameter diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 3cdfcfcfe4d..b313269b882 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -20,13 +20,14 @@ import os import sys -import platform - +import re +import shutil +import pkgconfig -from sage.env import SAGE_LOCAL, SAGE_SRC -from .misc import SPYX_TMP +from sage.env import (SAGE_LOCAL, SAGE_SRC, cython_aliases, + sage_include_directories) +from sage.misc.misc import SPYX_TMP, sage_makedirs from .temporary_file import tmp_filename -import pkgconfig # CBLAS can be one of multiple implementations @@ -254,8 +255,6 @@ def pyx_preparse(s): sage: module.evaluate_at_power_of_gen(x^3 + x - 7, 5) # long time x^15 + x^5 - 7 """ - from sage.env import sage_include_directories - lang, s = parse_keywords('clang', s) if lang: lang = lang[0].lower() # this allows both C++ and c++ @@ -296,7 +295,7 @@ def pyx_preparse(s): sequence_number = {} -def cython(filename, verbose=False, compile_message=False, +def cython(filename, verbose=0, compile_message=False, use_cache=False, create_local_c_file=False, annotate=True, sage_namespace=True, create_local_so_file=False): r""" @@ -306,32 +305,31 @@ def cython(filename, verbose=False, compile_message=False, INPUT: - - ``filename`` - the name of the file to be compiled. Should end with + - ``filename`` -- the name of the file to be compiled. Should end with 'pyx'. - - ``verbose`` (bool, default False) - if True, print debugging - information. + - ``verbose`` (integer, default 0) -- level of verbosity. - - ``compile_message`` (bool, default False) - if True, print + - ``compile_message`` (bool, default False) -- if True, print ``'Compiling ...'`` to the standard error. - - ``use_cache`` (bool, default False) - if True, check the + - ``use_cache`` (bool, default False) -- if True, check the temporary build directory to see if there is already a corresponding .so file. If so, and if the .so file is newer than the Cython file, don't recompile, just reuse the .so file. - - ``create_local_c_file`` (bool, default False) - if True, save a + - ``create_local_c_file`` (bool, default False) -- if True, save a copy of the ``.c`` or ``.cpp`` file in the current directory. - - ``annotate`` (bool, default True) - if True, create an html file which + - ``annotate`` (bool, default True) -- if True, create an html file which annotates the conversion from .pyx to .c. By default this is only created in the temporary directory, but if ``create_local_c_file`` is also True, then save a copy of the .html file in the current directory. - - ``sage_namespace`` (bool, default True) - if True, import + - ``sage_namespace`` (bool, default True) -- if True, import ``sage.all``. - - ``create_local_so_file`` (bool, default False) - if True, save a + - ``create_local_so_file`` (bool, default False) -- if True, save a copy of the compiled .so file in the current directory. TESTS: @@ -342,12 +340,8 @@ def cython(filename, verbose=False, compile_message=False, work around while waiting for :trac:`22461` which will offer a better solution:: - sage: import pkgconfig - sage: singular_pc = pkgconfig.parse('Singular') sage: code = [ ....: "#clang C++", - ....: "#clib " + " ".join(singular_pc['libraries']), - ....: "#cargs " + pkgconfig.cflags('Singular'), ....: "from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular", ....: "from sage.libs.singular.polynomial cimport singular_polynomial_pow", ....: "def test(MPolynomial_libsingular p):", @@ -389,8 +383,7 @@ def cython(filename, verbose=False, compile_message=False, sage: cython("sig_malloc(0)") Traceback (most recent call last): ... - RuntimeError: Error converting ... to C: - ... + RuntimeError: Error converting ... to C NOTE: Sage no longer automatically includes the deprecated files "cdefs.pxi", "signals.pxi" and "stdsage.pxi" in Cython files. You can fix your code by adding "from cysignals.memory cimport sig_malloc". @@ -411,57 +404,37 @@ def cython(filename, verbose=False, compile_message=False, else: base = sanitize(os.path.abspath(filename)) - # This is the *temporary* directory where we build the pyx file. - # This is deleted when sage exits, which means pyx files must be + # This is the *temporary* directory where we store the pyx file. + # This is deleted when Sage exits, which means pyx files must be # rebuilt every time Sage is restarted at present. - build_dir = os.path.join(SPYX_TMP, base) + target_dir = os.path.join(SPYX_TMP, base) - if os.path.exists(build_dir): + # Build directory for Cython/distutils + build_dir = os.path.join(target_dir, "build") + + if os.path.exists(target_dir): # There is already a module here. Maybe we do not have to rebuild? # Find the name. if use_cache: from sage.misc.sageinspect import loadable_module_extension - prev_so = [F for F in os.listdir(build_dir) if F.endswith(loadable_module_extension())] + prev_so = [F for F in os.listdir(target_dir) if F.endswith(loadable_module_extension())] if len(prev_so) > 0: prev_so = prev_so[0] # should have length 1 because of deletes below - if os.path.getmtime(filename) <= os.path.getmtime('%s/%s'%(build_dir, prev_so)): + if os.path.getmtime(filename) <= os.path.getmtime('%s/%s'%(target_dir, prev_so)): # We do not have to rebuild. - return prev_so[:-len(loadable_module_extension())], build_dir - else: - os.makedirs(build_dir) - for F in os.listdir(build_dir): - G = '%s/%s'%(build_dir,F) - try: - if not os.path.isdir(G): + return prev_so[:-len(loadable_module_extension())], target_dir + + # Delete all ordinary files in target_dir + for F in os.listdir(target_dir): + G = os.path.join(target_dir, F) + if os.path.isdir(G): + continue + try: os.unlink(G) - except OSError: - pass - - # Get the absolute path to the directory that contains the pyx file. - # We will use this only to make some convenient symbolic links. - abs_base = os.path.split(os.path.abspath(filename))[0] - - # bad things happen if the current directory is SAGE_SRC - if not os.path.exists("%s/sage" % abs_base): - cmd = 'cd "%s"; ln -sf "%s"/* .'%(build_dir, abs_base) - os.system(cmd) - if os.path.exists("%s/setup.py" % build_dir): - os.unlink("%s/setup.py" % build_dir) - - if compile_message: - print("Compiling {}...".format(filename), file=sys.stderr) - - F = open(filename).read() - - F, libs, includes, language, additional_source_files, extra_args, libdirs = pyx_preparse(F) - - # add the working directory to the includes so custom headers etc. work - includes.append(os.path.split(os.path.splitext(filename)[0])[0]) - - if language == 'c++': - extension = "cpp" + except OSError: + pass else: - extension = "c" + sage_makedirs(target_dir) if create_local_so_file: name = base @@ -474,97 +447,86 @@ def cython(filename, verbose=False, compile_message=False, # increment the sequence number so will use a different one next time. sequence_number[base] += 1 - file_list = [] + if compile_message: + print("Compiling {}...".format(filename), file=sys.stderr) + + with open(filename) as f: + (preparsed, libs, includes, language, additional_source_files, + extra_args, libdirs) = pyx_preparse(f.read()) + + # New filename with preparsed code. + # NOTE: if we ever stop preparsing, we should still copy the + # original file to the target directory. + pyxfile = os.path.join(target_dir, name + ".pyx") + with open(pyxfile, 'w') as f: + f.write(preparsed) + + extra_sources = [] for fname in additional_source_files: fname = fname.replace("$SAGE_SRC", SAGE_SRC) fname = fname.replace("$SAGE_LOCAL", SAGE_LOCAL) - if fname.startswith(os.path.sep): - file_list.append("'"+fname+"'") - else: - file_list.append("'"+os.path.abspath(os.curdir)+"/"+fname+"'") - additional_source_files = ",".join(file_list) - - pyx = '%s/%s.pyx'%(build_dir, name) - open(pyx,'w').write(F) - setup=""" -# Build using 'python setup.py' -import distutils.sysconfig, os, sys -from distutils.core import setup, Extension - -from sage.env import SAGE_LOCAL - -extra_compile_args = %s - -ext_modules = [Extension('%s', sources=['%s.%s', %s], - libraries=%s, - library_dirs=[SAGE_LOCAL + '/lib/'] + %s, - extra_compile_args = extra_compile_args, - language = '%s' )] - -setup(ext_modules = ext_modules, - include_dirs = %s) - """%(extra_args, name, name, extension, additional_source_files, libs, libdirs, language, includes) - open('%s/setup.py'%build_dir,'w').write(setup) - cython_include = ' '.join(["-I '%s'"%x for x in includes if len(x.strip()) > 0 ]) - - options = ['-p'] - if annotate: - options.append('-a') - if sage_namespace: - options.append('--pre-import sage.all') - - cmd = "cd '{DIR}' && cython {OPT} {INC} {LANG} '{NAME}.pyx' 1>log 2>err ".format( - DIR=build_dir, - OPT=' '.join(options), - INC=cython_include, - LANG='--cplus' if language=='c++' else '', - NAME=name) - - if create_local_c_file: - target_c = '%s/_%s.%s'%(os.path.abspath(os.curdir), base, extension) - cmd += " && cp '%s.%s' '%s'"%(name, extension, target_c) - if annotate: - target_html = '%s/_%s.html'%(os.path.abspath(os.curdir), base) - cmd += " && cp '%s.html' '%s'"%(name, target_html) - - if verbose: - print(cmd) - if os.system(cmd): - log = open('%s/log'%build_dir).read() - err = open('%s/err'%build_dir).read() + extra_sources.append(fname) + + # Now do the actual build, directly calling Cython and distutils + from Cython.Build import cythonize + from Cython.Compiler.Errors import CompileError + import Cython.Compiler.Options + from distutils.dist import Distribution + from distutils.core import Extension + from distutils.log import set_verbosity + set_verbosity(verbose) + + Cython.Compiler.Options.annotate = annotate + Cython.Compiler.Options.embed_pos_in_docstring = True + Cython.Compiler.Options.pre_import = "sage.all" if sage_namespace else None + + ext = Extension(name, + sources=[pyxfile] + extra_sources, + libraries=libs, + library_dirs=[os.path.join(SAGE_LOCAL, "lib")] + libdirs, + extra_compile_args=extra_args, + language=language) + + try: + ext, = cythonize([ext], + aliases=cython_aliases(), + include_path=includes, + quiet=not verbose) + except CompileError: + msg = "Error converting {} to C".format(filename) + # Check for names in old_pxi_names for pxd, names in old_pxi_names.items(): for name in names: - if ("undeclared name not builtin: " + name) in err: - err += '\nNOTE: Sage no longer automatically includes the deprecated files\n' \ + if re.search(r"\b{}\b".format(name), preparsed): + msg += '\nNOTE: Sage no longer automatically includes the deprecated files\n' \ '"cdefs.pxi", "signals.pxi" and "stdsage.pxi" in Cython files.\n' \ 'You can fix your code by adding "from %s cimport %s".' % \ (pxd, name) - raise RuntimeError("Error converting {} to C:\n{}\n{}".format(filename, log, err)) + raise RuntimeError(msg) - cmd = 'cd %s && python setup.py build 1>log 2>err'%build_dir - if verbose: - print(cmd) - if os.system(cmd): - log = open('%s/log'%build_dir).read() - err = open('%s/err'%build_dir).read() - raise RuntimeError("Error compiling {}:\n{}\n{}".format(filename, log, err)) - - # Move from lib directory. - cmd = 'mv %s/build/lib.*/* %s'%(build_dir, build_dir) - if verbose: - print(cmd) - if os.system(cmd): - raise RuntimeError("Error copying extension module for {}".format(filename)) + if create_local_c_file: + shutil.copy(os.path.join(target_dir, ext.sources[0]), + os.curdir) + if annotate: + shutil.copy(os.path.join(target_dir, name + ".html"), + os.curdir) + + # This emulates running "setup.py build" with the correct options + dist = Distribution() + dist.ext_modules = [ext] + dist.include_dirs = includes + buildcmd = dist.get_command_obj("build") + buildcmd.build_base = build_dir + buildcmd.build_lib = target_dir + dist.run_command("build") if create_local_so_file: - # Copy from lib directory into local directory + # Copy module to current directory from sage.misc.sageinspect import loadable_module_extension - cmd = 'cp %s/%s%s %s'%(build_dir, name, loadable_module_extension(), os.path.abspath(os.curdir)) - if os.system(cmd): - raise RuntimeError("Error making local copy of shared object library for {}".format(filename)) - - return name, build_dir + shutil.copy(os.path.join(target_dir, name + loadable_module_extension()), + os.curdir) + return name, target_dir def subtract_from_line_numbers(s, n): diff --git a/src/sage/misc/cython_c.pyx b/src/sage/misc/cython_c.pyx index c2a9c4167bd..177a659a1a2 100644 --- a/src/sage/misc/cython_c.pyx +++ b/src/sage/misc/cython_c.pyx @@ -60,7 +60,7 @@ def cython_compile(code, Need to create a clever caching system so code only gets compiled once. """ - tmpfile = tmp_filename(ext=".spyx") + tmpfile = tmp_filename(ext=".pyx") open(tmpfile,'w').write(code) cython_import_all(tmpfile, get_globals(), verbose=verbose, compile_message=compile_message, diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index 29bacd43f7b..7c32126246e 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -305,9 +305,7 @@ class Singleton(WithEqualityById, metaclass=ClasscallMetaclass): sage: loads(dumps(c)) Traceback (most recent call last): ... - AssertionError: ((" is not a direct - subclass of ",), - , ()) + AssertionError: is not a direct subclass of """ @staticmethod def __classcall__(cls): diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index afc3b146984..ba518eb395d 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -983,7 +983,7 @@ def log(x, b=None): 4 sage: log(3.) 1.09861228866811 - sage: log(float(3)) + sage: log(float(3)) # abs tol 1e-15 1.0986122886681098 """ deprecation(19444, 'use .log() or log() from sage.functions.log instead') diff --git a/src/sage/misc/inherit_comparison.pyx b/src/sage/misc/inherit_comparison.pyx index 7c9bd1a0342..fc360533cad 100644 --- a/src/sage/misc/inherit_comparison.pyx +++ b/src/sage/misc/inherit_comparison.pyx @@ -85,5 +85,15 @@ cdef class InheritComparisonMetaclass(type): inherit_comparison(t, b) super(InheritComparisonMetaclass, self).__init__(*args) -class InheritComparisonClasscallMetaclass(InheritComparisonMetaclass, ClasscallMetaclass): - pass + +class InheritComparisonClasscallMetaclass(ClasscallMetaclass, InheritComparisonMetaclass): + """ + Combine :class:`ClasscallMetaclass` with + :class:`InheritComparisonMetaclass`. + + TESTS:: + + sage: from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass as M + sage: M.__new__(M, "myclass", (object,), {}) + + """ diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index e7b96d40353..6242d2d357a 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -281,11 +281,14 @@ def installed_packages(exclude_pip=True): :func:`sage.misc.package.list_packages` """ from sage.env import SAGE_SPKG_INST - installed = dict(pkgname_split(pkgname) for pkgname in os.listdir(SAGE_SPKG_INST)) + installed = {} if not exclude_pip: installed.update(pip_installed_packages()) + # Sage packages should override pip packages (Trac #23997) + installed.update(pkgname_split(pkgname) for pkgname in os.listdir(SAGE_SPKG_INST)) return installed + def is_package_installed(package, exclude_pip=True): """ Return whether (any version of) ``package`` is installed. diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index 40e8f5dbebb..f6f30c65955 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -35,16 +35,10 @@ value that is being garbage collected:: sage: len(D) 10 sage: del ValList, v - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - Exception KeyError: (<__main__.Keys instance at ...>,) in ignored - ... sage: len(D) > 1 True -Hence, there are scary error messages, and moreover the defunct items have not -been removed from the dictionary. +Hence, the defunct items have not been removed from the dictionary. Therefore, Sage provides an alternative implementation :class:`sage.misc.weak_dict.WeakValueDictionary`, using a callback that diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 0c40a6ed2b6..baf29afced1 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -41,7 +41,7 @@ sage: alpha.ideal() Fractional ideal (7, a + 3) sage: alpha.ABmatrix() - [a + 10, -3*a + 1, 7, -2*a] + [a + 10, 2*a + 6, 7, a + 5] sage: alpha.apply([0, 1, -1,0]) Cusp [7: -a - 10] of Number Field in a with defining polynomial x^2 + 5 diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index 5c74cd92042..9d31e5a4e6a 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -508,13 +508,6 @@ def __init__(self, base_ring, level, weight, category=None): HeckeModule_generic.__init__(self, base_ring, level, category=category) self.__weight = weight -# def __cmp__(self, other): -# if not isinstance(other, HeckeModule_free_module): -# return -1 -# c = HeckeModule_generic.__cmp__(self, other) -# if c: return c -# return cmp(self.__weight, other.__weight) - # def __contains__(self, x): # r""" # Return True if x is an element of self. diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py new file mode 100644 index 00000000000..fd0ff831ea3 --- /dev/null +++ b/src/sage/modular/hypergeometric_motive.py @@ -0,0 +1,1248 @@ +# -*- coding: utf-8 -*- +""" +Hypergeometric motives + +This is largely a port of the corresponding package in Magma. One +important conventional difference: the motivic parameter `t` has been replaced +with `1/t` to match the classical literature on hypergeometric series. +(E.g., see [BeukersHeckman]_) + +The computation of Euler factors is currently only supported for primes `p` +of good reduction. That is, it is required that `v_p(t) = v_p(t-1) = 0`. + +AUTHORS: + +- Frédéric Chapoton +- Kiran S. Kedlaya + +EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(cyclotomic=([30], [1,2,3,5])) + sage: H.alpha_beta() + ([1/30, 7/30, 11/30, 13/30, 17/30, 19/30, 23/30, 29/30], + [0, 1/5, 1/3, 2/5, 1/2, 3/5, 2/3, 4/5]) + sage: H.M_value() == 30**30 / (15**15 * 10**10 * 6**6) + True + sage: H.euler_factor(2, 7) + T^8 + T^5 + T^3 + 1 + +REFERENCES: + +- [BeukersHeckman]_ + +- [Benasque2009]_ + +- [Kat1991]_ + +- [MagmaHGM]_ + +- [Fedorov2015]_ + +- [Roberts2017]_ + +- [Roberts2015]_ + +- [BeCoMe]_ + +- [Watkins]_ + +""" +#***************************************************************************** +# Copyright (C) 2017 Frédéric Chapoton +# Kiran S. Kedlaya +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from collections import defaultdict + +from sage.arith.misc import divisors, gcd, euler_phi, moebius, is_prime +from sage.arith.misc import gauss_sum, kronecker_symbol +from sage.combinat.integer_vector_weighted import WeightedIntegerVectors +from sage.functions.generalized import sgn +from sage.functions.other import floor +from sage.misc.cachefunc import cached_method +from sage.misc.functional import cyclotomic_polynomial +from sage.misc.misc_c import prod +from sage.rings.fraction_field import FractionField +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer_ring import ZZ +from sage.rings.padics.factory import Zp +from sage.rings.padics.misc import gauss_sum as padic_gauss_sum +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ +from sage.schemes.generic.spec import Spec +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + + +def characteristic_polynomial_from_traces(traces, d, q, i, sign): + r""" + Given a sequence of traces `t_1, \dots, t_k`, return the + corresponding characteristic polynomial with Weil numbers as roots. + + The characteristic polynomial is defined by the generating series + + .. MATH:: + + P(T) = \exp\left(- \sum_{k\geq 1} t_k \frac{T^k}{k}\right) + + and should have the property that reciprocals of all roots have + absolute value `q^{i/2}`. + + INPUT: + + - ``traces`` -- a list of integers `t_1, \dots, t_k` + + - ``d`` -- the degree of the characteristic polynomial + + - ``q`` -- power of a prime number + + - ``i`` -- integer, the weight in the motivic sense + + - ``sign`` -- integer, the sign + + OUTPUT: + + a polynomial + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import characteristic_polynomial_from_traces + sage: characteristic_polynomial_from_traces([1, 1], 1, 3, 0, -1) + -T + 1 + sage: characteristic_polynomial_from_traces([25], 1, 5, 4, -1) + -25*T + 1 + + sage: characteristic_polynomial_from_traces([3], 2, 5, 1, 1) + 5*T^2 - 3*T + 1 + sage: characteristic_polynomial_from_traces([1], 2, 7, 1, 1) + 7*T^2 - T + 1 + + sage: characteristic_polynomial_from_traces([20], 3, 29, 2, 1) + 24389*T^3 - 580*T^2 - 20*T + 1 + sage: characteristic_polynomial_from_traces([12], 3, 13, 2, -1) + -2197*T^3 + 156*T^2 - 12*T + 1 + + sage: characteristic_polynomial_from_traces([36,7620], 4, 17, 3, 1) + 24137569*T^4 - 176868*T^3 - 3162*T^2 - 36*T + 1 + sage: characteristic_polynomial_from_traces([-4,276], 4, 5, 3, 1) + 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 + sage: characteristic_polynomial_from_traces([4,-276], 4, 5, 3, 1) + 15625*T^4 - 500*T^3 + 146*T^2 - 4*T + 1 + sage: characteristic_polynomial_from_traces([22, 484], 4, 31, 2, -1) + -923521*T^4 + 21142*T^3 - 22*T + 1 + + TESTS:: + + sage: characteristic_polynomial_from_traces([-36], 4, 17, 3, 1) + Traceback (most recent call last): + ... + ValueError: not enough traces were given + """ + if len(traces) < d // 2: + raise ValueError('not enough traces were given') + if i % 2 and d % 2: + raise ValueError('i and d may not both be odd') + t = PowerSeriesRing(QQ, 't').gen() + ring = PolynomialRing(ZZ, 'T') + + series = sum(- api * t**(i + 1) / (i + 1) for i, api in enumerate(traces)) + series = series.O(d // 2 + 1).exp() + coeffs = list(series) + coeffs += [0] * max(0, d // 2 + 1 - len(coeffs)) + + data = [0 for _ in range(d + 1)] + for k in range(d // 2 + 1): + data[k] = coeffs[k] + for k in range(d // 2 + 1, d + 1): + data[k] = sign * coeffs[d - k] * q**(i * (k - d / 2)) + return ring(data) + + +def possible_hypergeometric_data(d, weight=None): + """ + Return the list of possible parameters of hypergeometric motives. + + INPUT: + + - ``d`` -- the degree + + - ``weight`` -- optional integer, to specify the motivic weight + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import possible_hypergeometric_data + sage: P = possible_hypergeometric_data + sage: [len(P(i,weight=2)) for i in range(1, 7)] + [0, 0, 10, 30, 93, 234] + """ + bound = 2 * d * d # to make sure that phi(n) <= d + possible = [(i, euler_phi(i)) for i in range(1, bound + 1) + if euler_phi(i) <= d] + poids = [z[1] for z in possible] + N = len(poids) + vectors = list(WeightedIntegerVectors(d, poids)) + + def iterator(): + for i, u in enumerate(vectors): + supp_u = [j for j in range(N) if u[j]] + for v in vectors[i + 1:]: + if not any(v[j] for j in supp_u): + yield (u, v) + + def formule(u): + return [possible[j][0] for j in range(N) for _ in range(u[j])] + + data = [HypergeometricData(cyclotomic=(formule(a), formule(b))) + for a, b in iterator()] + if weight is None: + return data + else: + return [H for H in data if H.weight() == weight] + + +def cyclotomic_to_alpha(cyclo): + """ + Convert a list of indices of cyclotomic polynomials + to a list of rational numbers. + + The input represents a product of cyclotomic polynomials. + + The output is the list of arguments of the roots of the + given product of cyclotomic polynomials. + + This is the inverse of :func:`alpha_to_cyclotomic`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import cyclotomic_to_alpha + sage: cyclotomic_to_alpha([1]) + [0] + sage: cyclotomic_to_alpha([2]) + [1/2] + sage: cyclotomic_to_alpha([5]) + [1/5, 2/5, 3/5, 4/5] + sage: cyclotomic_to_alpha([1,2,3,6]) + [0, 1/6, 1/3, 1/2, 2/3, 5/6] + sage: cyclotomic_to_alpha([2,3]) + [1/3, 1/2, 2/3] + """ + alpha = [] + for d in cyclo: + if d == 1: + alpha.append(QQ.zero()) + else: + for k in ZZ(d).coprime_integers(d): + alpha.append(QQ((k, d))) + return sorted(alpha) + + +def alpha_to_cyclotomic(alpha): + """ + Convert from a list of rationals arguments to a list of integers. + + The input represents arguments of some roots of unity. + + The output represent a product of cyclotomic polynomials with exactly + the given roots. Note that the multiplicity of `r/s` in the list + must be independent of `r`; otherwise, a ``ValueError`` will be raised. + + This is the inverse of :func:`cyclotomic_to_alpha`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import alpha_to_cyclotomic + sage: alpha_to_cyclotomic([0]) + [1] + sage: alpha_to_cyclotomic([1/2]) + [2] + sage: alpha_to_cyclotomic([1/5,2/5,3/5,4/5]) + [5] + sage: alpha_to_cyclotomic([1/6, 1/3, 1/2, 2/3, 5/6, 1]) + [1, 2, 3, 6] + sage: alpha_to_cyclotomic([1/3,2/3,1/2]) + [2, 3] + """ + cyclo = [] + Alpha = list(alpha) + while Alpha: + q = QQ(Alpha.pop()) + n = q.numerator() + d = q.denominator() + for k in d.coprime_integers(d): + if k != n: + try: + Alpha.remove(QQ((k, d))) + except ValueError: + raise ValueError("multiplicities not balanced") + cyclo.append(d) + return sorted(cyclo) + + +def capital_M(n): + """ + Auxiliary function, used to describe the canonical scheme. + + INPUT: + + - ``n`` -- an integer + + OUTPUT: + + a rational + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import capital_M + sage: [capital_M(i) for i in range(1,8)] + [1, 4, 27, 64, 3125, 432, 823543] + """ + n = ZZ(n) + return QQ.prod(d ** (d * moebius(n / d)) for d in divisors(n)) + + +def cyclotomic_to_gamma(cyclo_up, cyclo_down): + """ + Convert a quotient of products of cyclotomic polynomials + to a quotient of products of polynomials `x^n - 1`. + + INPUT: + + - ``cyclo_up`` -- list of indices of cyclotomic polynomials in the numerator + - ``cyclo_down`` -- list of indices of cyclotomic polynomials in the denominator + + OUTPUT: + + a dictionary mapping an integer `n` to the power of `x^n - 1` that + appears in the given product + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import cyclotomic_to_gamma + sage: cyclotomic_to_gamma([6], [1]) + {2: -1, 3: -1, 6: 1} + """ + dico = defaultdict(int) + for d in cyclo_up: + dico[d] += 1 + for d in cyclo_down: + dico[d] -= 1 + + resu = defaultdict(int) + for n in dico: + for d in divisors(n): + resu[d] += moebius(n / d) * dico[n] + + return {d: resu[d] for d in resu if resu[d]} + + +def gamma_list_to_cyclotomic(galist): + r""" + Convert a quotient of products of polynomials `x^n - 1` + to a quotient of products of cyclotomic polynomials. + + INPUT: + + - ``galist`` -- a list of integers, where an integer `n` represents + the power `(x^{|n|} - 1)^{\operatorname{sgn}(n)}` + + OUTPUT: + + a pair of list of integers, where `k` represents the cyclotomic + polynomial `\Phi_k` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import gamma_list_to_cyclotomic + sage: gamma_list_to_cyclotomic([-1, -1, 2]) + ([2], [1]) + + sage: gamma_list_to_cyclotomic([-1, -1, -1, -3, 6]) + ([2, 6], [1, 1, 1]) + + sage: gamma_list_to_cyclotomic([-1, 2, 3, -4]) + ([3], [4]) + + sage: gamma_list_to_cyclotomic([8,2,2,2,-6,-4,-3,-1]) + ([2, 2, 8], [3, 3, 6]) + """ + resu = defaultdict(int) + for n in galist: + eps = sgn(n) + for d in divisors(abs(n)): + resu[d] += eps + + return (sorted(d for d in resu for k in range(resu[d])), + sorted(d for d in resu for k in range(-resu[d]))) + + +class HypergeometricData(object): + def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): + r""" + Creation of hypergeometric motives. + + INPUT: + + three possibilities are offered, each describing a quotient + of products of cyclotomic polynomials. + + - ``cyclotomic`` -- a pair of lists of nonnegative integers, + each integer `k` represents a cyclotomic polynomial `\Phi_k` + + - ``alpha_beta`` -- a pair of lists of rationals, + each rational represents a root of unity + + - ``gamma_list`` -- a pair of lists of nonnegative integers, + each integer `n` represents a polynomial `x^n - 1` + + In the last case, it is also allowed to send just one list of signed + integers where signs indicate to which part the integer belongs to. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(cyclotomic=([2],[1])) + Hypergeometric data for [1/2] and [0] + + sage: Hyp(alpha_beta=([1/2],[0])) + Hypergeometric data for [1/2] and [0] + sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0])) + Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + + sage: Hyp(gamma_list=([5],[1,1,1,1,1])) + Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + sage: Hyp(gamma_list=([5,-1,-1,-1,-1,-1])) + Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0] + """ + if gamma_list is not None: + if isinstance(gamma_list[0], (list, tuple)): + pos, neg = gamma_list + gamma_list = pos + [-u for u in neg] + cyclotomic = gamma_list_to_cyclotomic(gamma_list) + if cyclotomic is not None: + cyclo_up, cyclo_down = cyclotomic + if any(x in cyclo_up for x in cyclo_down): + raise ValueError('overlapping parameters not allowed') + deg = sum(euler_phi(x) for x in cyclo_down) + up_deg = sum(euler_phi(x) for x in cyclo_up) + if up_deg != deg: + msg = 'not the same degree: {} != {}'.format(up_deg, deg) + raise ValueError(msg) + cyclo_up.sort() + cyclo_down.sort() + alpha = cyclotomic_to_alpha(cyclo_up) + beta = cyclotomic_to_alpha(cyclo_down) + elif alpha_beta is not None: + alpha, beta = alpha_beta + if len(alpha) != len(beta): + raise ValueError('alpha and beta not of the same length') + alpha = sorted(u - floor(u) for u in alpha) + beta = sorted(u - floor(u) for u in beta) + cyclo_up = alpha_to_cyclotomic(alpha) + cyclo_down = alpha_to_cyclotomic(beta) + deg = sum(euler_phi(x) for x in cyclo_down) + + self._cyclo_up = cyclo_up + self._cyclo_down = cyclo_down + self._alpha = alpha + self._beta = beta + self._deg = deg + if self.weight() % 2: + self._sign_param = 1 + else: + if deg % 2: + self._sign_param = prod(cyclotomic_polynomial(v).disc() + for v in cyclo_down) + else: + self._sign_param = prod(cyclotomic_polynomial(v).disc() + for v in cyclo_up) + + def __repr__(self): + """ + Return the string representation. + + This displays the rational arguments of the roots of unity. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/2],[0])) + Hypergeometric data for [1/2] and [0] + """ + txt = "Hypergeometric data for {} and {}" + return txt.format(self._alpha, self._beta) + + def twist(self): + r""" + Return the twist of this data. + + This is defined by adding `1/2` to each rational in `\alpha` + and `\beta`. + + This is an involution. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/2],[0])) + sage: H.twist() + Hypergeometric data for [0] and [1/2] + + sage: Hyp(cyclotomic=([6],[1,2])).twist().cyclotomic_data() + ([3], [1, 2]) + """ + alpha = [x + QQ((1, 2)) for x in self._alpha] + beta = [x + QQ((1, 2)) for x in self._beta] + return HypergeometricData(alpha_beta=(alpha, beta)) + + def swap_alpha_beta(self): + """ + Return the hypergeometric data with ``alpha`` and ``beta`` exchanged. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/2],[0])) + sage: H.swap_alpha_beta() + Hypergeometric data for [0] and [1/2] + """ + alpha, beta = self.alpha_beta() + return HypergeometricData(alpha_beta=(beta, alpha)) + + def primitive_data(self): + """ + Return a primitive version. + + .. SEEALSO:: + + :meth:`is_primitive`, :meth:`primitive_index`, + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(cyclotomic=([3],[4])) + sage: H2 = Hyp(gamma_list=[-2, 4, 6, -8]) + sage: H2.primitive_data() == H + True + """ + g = self.gamma_list() + d = gcd(g) + return HypergeometricData(gamma_list=[x / d for x in g]) + + def zigzag(self, x, flip_beta=False): + r""" + Count ``alpha``'s at most ``x`` minus ``beta``'s at most ``x``. + + This function is used to compute the weight and the Hodge numbers. + With `flip_beta` set to True, replace each `b` in `\beta` with `1-b`. + + .. SEEALSO:: + + :meth:`weight`, :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: [H.zigzag(x) for x in [0, 1/3, 1/2]] + [0, 1, 0] + sage: H = Hyp(cyclotomic=([5],[1,1,1,1])) + sage: [H.zigzag(x) for x in [0,1/6,1/4,1/2,3/4,5/6]] + [-4, -4, -3, -2, -1, 0] + + """ + alpha = self._alpha + beta = self._beta + if flip_beta: + return(sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if 1 - b <= x)) + else: + return(sum(1 for a in alpha if a <= x) - + sum(1 for b in beta if b <= x)) + + def weight(self): + """ + Return the motivic weight of this motivic data. + + EXAMPLES: + + With rational inputs:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).weight() + 0 + sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).weight() + 1 + sage: Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[0,0,1/4,3/4])).weight() + 1 + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: H.weight() + 1 + + With cyclotomic inputs:: + + sage: Hyp(cyclotomic=([6,2],[1,1,1])).weight() + 2 + sage: Hyp(cyclotomic=([6],[1,2])).weight() + 0 + sage: Hyp(cyclotomic=([8],[1,2,3])).weight() + 0 + sage: Hyp(cyclotomic=([5],[1,1,1,1])).weight() + 3 + sage: Hyp(cyclotomic=([5,6],[1,1,2,2,3])).weight() + 1 + sage: Hyp(cyclotomic=([3,8],[1,1,1,2,6])).weight() + 2 + sage: Hyp(cyclotomic=([3,3],[2,2,4])).weight() + 1 + + With gamma list input:: + + sage: Hyp(gamma_list=([8,2,2,2],[6,4,3,1])).weight() + 3 + """ + alpha = self._alpha + beta = self._beta + D = [self.zigzag(x) for x in alpha + beta] + return ZZ(max(D) - min(D) - 1) + + def degree(self): + """ + Return the degree. + + This is the sum of the Hodge numbers. + + .. SEEALSO:: + + :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).degree() + 1 + sage: Hyp(gamma_list=([2,2,4],[8])).degree() + 4 + sage: Hyp(cyclotomic=([5,6],[1,1,2,2,3])).degree() + 6 + sage: Hyp(cyclotomic=([3,8],[1,1,1,2,6])).degree() + 6 + sage: Hyp(cyclotomic=([3,3],[2,2,4])).degree() + 4 + """ + return self._deg + + def defining_polynomials(self): + """ + Return the pair of products of cyclotomic polynomials. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).defining_polynomials() + (x^2 + 1, x^2 - 2*x + 1) + """ + up = prod(cyclotomic_polynomial(d) for d in self._cyclo_up) + down = prod(cyclotomic_polynomial(d) for d in self._cyclo_down) + return (up, down) + + def cyclotomic_data(self): + """ + Return the pair of lists of indices of cyclotomic polynomials. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).cyclotomic_data() + ([2], [1]) + """ + return (self._cyclo_up, self._cyclo_down) + + def alpha_beta(self): + """ + Return the pair of lists of rational arguments. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).alpha_beta() + ([1/2], [0]) + """ + return (self._alpha, self._beta) + + def M_value(self): + """ + Return the `M` coefficient that appears in the trace formula. + + OUTPUT: + + a rational + + .. SEEALSO:: :meth:`canonical_scheme` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) + sage: H.M_value() + 729/4096 + sage: Hyp(alpha_beta=(([1/2,1/2,1/2,1/2],[0,0,0,0]))).M_value() + 256 + sage: Hyp(cyclotomic=([5],[1,1,1,1])).M_value() + 3125 + """ + up = QQ.prod(capital_M(d) for d in self._cyclo_up) + down = QQ.prod(capital_M(d) for d in self._cyclo_down) + return up / down + + def gamma_array(self): + r""" + Return the dictionary `\{v: \gamma_v\}` for the expression + + .. MATH:: + + \prod_v (T^v - 1)^{\gamma_v} + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).gamma_array() + {1: -2, 2: 1} + sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_array() + {1: -3, 3: -1, 6: 1} + """ + return cyclotomic_to_gamma(self._cyclo_up, self._cyclo_down) + + def gamma_list(self): + r""" + Return a list of integers describing the `x^n - 1` factors. + + Each integer `n` stands for `(x^{|n|} - 1)^{\operatorname{sgn}(n)}`. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=([1/2],[0])).gamma_list() + [-1, -1, 2] + + sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_list() + [-1, -1, -1, -3, 6] + + sage: Hyp(cyclotomic=([3],[4])).gamma_list() + [-1, 2, 3, -4] + """ + gamma = self.gamma_array() + resu = [] + for v, n in gamma.items(): + resu += [sgn(n) * v] * abs(n) + return resu + + def __eq__(self, other): + """ + Return whether two data are equal. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H1 = Hyp(alpha_beta=([1/2],[0])) + sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H1 == H1 + True + sage: H1 == H2 + False + """ + return (self._alpha == other._alpha and + self._beta == other._beta) + + def __ne__(self, other): + """ + Return whether two data are unequal. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H1 = Hyp(alpha_beta=([1/2],[0])) + sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H1 != H1 + False + sage: H1 != H2 + True + """ + return not (self == other) + + def is_primitive(self): + """ + Return whether this data is primitive. + + .. SEEALSO:: + + :meth:`primitive_index`, :meth:`primitive_data` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(cyclotomic=([3],[4])).is_primitive() + True + sage: Hyp(gamma_list=[-2, 4, 6, -8]).is_primitive() + False + sage: Hyp(gamma_list=[-3, 6, 9, -12]).is_primitive() + False + """ + return self.primitive_index() == 1 + + def primitive_index(self): + """ + Return the primitive index. + + .. SEEALSO:: + + :meth:`is_primitive`, :meth:`primitive_data` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(cyclotomic=([3],[4])).primitive_index() + 1 + sage: Hyp(gamma_list=[-2, 4, 6, -8]).primitive_index() + 2 + sage: Hyp(gamma_list=[-3, 6, 9, -12]).primitive_index() + 3 + """ + return gcd(self.gamma_list()) + + def has_symmetry_at_one(self): + """ + If ``True``, the motive H(t=1) is a direct sum of two motives. + + Note that simultaneous exchange of (t,1/t) and (alpha,beta) + always gives the same motive. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(alpha_beta=[[1/2]*16,[0]*16]).has_symmetry_at_one() + True + + REFERENCES: + + - [Roberts2017]_ + """ + _, beta_twist = self.twist().alpha_beta() + return self.degree() % 2 == 0 and self._alpha == beta_twist + + def hodge_numbers(self): + """ + Return the Hodge numbers. + + .. SEEALSO:: + + :meth:`degree`, :meth:`hodge_polynomial` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(cyclotomic=([3],[6])) + sage: H.hodge_numbers() + [1, 1] + + sage: H = Hyp(cyclotomic=([4],[1,2])) + sage: H.hodge_numbers() + [2] + + sage: H = Hyp(gamma_list=([8,2,2,2],[6,4,3,1])) + sage: H.hodge_numbers() + [1, 2, 2, 1] + + sage: H = Hyp(gamma_list=([5],[1,1,1,1,1])) + sage: H.hodge_numbers() + [1, 1, 1, 1] + + sage: H = Hyp(gamma_list=[6,1,-4,-3]) + sage: H.hodge_numbers() + [1, 1] + + sage: H = Hyp(gamma_list=[-3]*4 + [1]*12) + sage: H.hodge_numbers() + [1, 1, 1, 1, 1, 1, 1, 1] + + REFERENCES: + + - [Fedorov2015]_ + """ + alpha = [(x, 'a') for x in self._alpha] + beta = [(x, 'b') for x in self._beta] + height = 0 + hodge = defaultdict(int) + for x, letter in sorted(alpha + beta): + if letter == 'a': + hodge[height] += 1 + height += 1 + else: + height -= 1 + return [hodge[i] for i in sorted(hodge)] + + def hodge_polynomial(self): + """ + Return the Hodge polynomial. + + .. SEEALSO:: + + :meth:`hodge_numbers` + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(cyclotomic=([6,10],[3,12])) + sage: H.hodge_polynomial() + (T^3 + 2*T^2 + 2*T + 1)/T^2 + sage: H = Hyp(cyclotomic=([2,2,2,2,3,3,3,6,6],[1,1,4,5,9])) + sage: H.hodge_polynomial() + (T^5 + 3*T^4 + 3*T^3 + 3*T^2 + 3*T + 1)/T^2 + """ + alpha = self._alpha + + def z(x): + return alpha.count(x) + + T = polygen(ZZ, 'T') + return sum(T ** (self.zigzag(a, flip_beta=True) - z(a)) * + (T**z(a) - 1) // (T - 1) + for a in set(alpha)) + + @cached_method + def padic_H_value(self, p, f, t, prec=20): + """ + Return the `p`-adic trace of Frobenius, computed using the + Gross-Koblitz formula. + + INPUT: + + - `p` -- a prime number + + - `f` -- an integer such that `q = p^f` + + - `t` -- a rational parameter + + - ``prec`` -- precision (optional, default 20) + + OUTPUT: + + an integer + + EXAMPLES: + + From Benasque report [Benasque2009]_, page 8:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] + [0, -12] + sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] + [-4, 276] + sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] + [0, -476] + sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] + [0, -4972] + + From [Roberts2015]_ (but note conventions regarding `t`):: + + sage: H = Hyp(gamma_list=[-6,-1,4,3]) + sage: t = 189/125 + sage: H.padic_H_value(13,1,1/t) + 0 + + REFERENCES: + + - [MagmaHGM]_ + """ + alpha = self._alpha + beta = self._beta + if 0 in alpha: + H = self.swap_alpha_beta() + return(H.padic_H_value(p, f, ~t, prec)) + t = QQ(t) + gamma = self.gamma_array() + q = p ** f + + m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} + M = self.M_value() + D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) + # also: D = (self.weight() + 1 - m[0]) // 2 + + gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1)] + + p_ring = Zp(p, prec=prec) + teich = p_ring.teichmuller(M / t) + sigma = sum(q**(D + m[0] - m[r]) * + (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv + for v, gv in gamma.items()) // (p - 1)) * + prod(gauss_table[(v * r) % (q - 1)][1] ** gv + for v, gv in gamma.items()) * + teich ** r + for r in range(q - 1)) + resu = ZZ(-1) ** m[0] / (1 - q) * sigma + return IntegerModRing(p**prec)(resu).lift_centered() + + @cached_method + def H_value(self, p, f, t, ring=None): + """ + Return the trace of the Frobenius, computed in terms of Gauss sums + using the hypergeometric trace formula. + + INPUT: + + - `p` -- a prime number + + - `f` -- an integer such that `q = p^f` + + - `t` -- a rational parameter + + - ``ring`` -- optional (default ``UniversalCyclotomicfield``) + + The ring could be also ``ComplexField(n)`` or ``QQbar``. + + OUTPUT: + + an integer + + .. WARNING:: + + This is apparently working correctly as can be tested + using ComplexField(70) as value ring. + + Using instead UniversalCyclotomicfield, this is much + slower than the `p`-adic version :meth:`padic_H_value`. + + EXAMPLES: + + With values in the UniversalCyclotomicField (slow):: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: [H.H_value(3,i,-1) for i in range(1,3)] + [0, -12] + sage: [H.H_value(5,i,-1) for i in range(1,3)] + [-4, 276] + sage: [H.H_value(7,i,-1) for i in range(1,3)] # not tested + [0, -476] + sage: [H.H_value(11,i,-1) for i in range(1,3)] # not tested + [0, -4972] + sage: [H.H_value(13,i,-1) for i in range(1,3)] # not tested + [-84, -1420] + + With values in ComplexField:: + + sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)] + [-4, 276] + + REFERENCES: + + - [BeCoMe]_ (Theorem 1.3) + - [Benasque2009]_ + """ + alpha = self._alpha + beta = self._beta + if 0 in alpha: + H = self.swap_alpha_beta() + return(H.H_value(p, f, ~t, ring)) + if ring is None: + ring = UniversalCyclotomicField() + t = QQ(t) + gamma = self.gamma_array() + q = p ** f + + m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} + D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) + # also: D = (self.weight() + 1 - m[0]) // 2 + M = self.M_value() + + Fq = GF(q) + gen = Fq.multiplicative_generator() + zeta_q = ring.zeta(q - 1) + + tM = Fq(M / t) + for k in range(q - 1): + if gen ** k == tM: + teich = zeta_q ** k + break + + gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)] + + sigma = sum(q**(D + m[0] - m[r]) * + prod(gauss_table[(-v * r) % (q - 1)] ** gv + for v, gv in gamma.items()) * + teich ** r + for r in range(q - 1)) + resu = ZZ(-1) ** m[0] / (1 - q) * sigma + if not ring.is_exact(): + resu = resu.real_part().round() + return resu + + @cached_method + def euler_factor(self, t, p, degree=0): + """ + Return the Euler factor of the motive `H_t` at prime `p`. + + INPUT: + + - `t` -- rational number, not 0 or 1 + + - `p` -- prime number of good reduction + + - ``degree`` -- optional integer (default 0) + + OUTPUT: + + a polynomial + + See [Benasque2009]_ for explicit examples of Euler factors. + + For odd weight, the sign of the functional equation is +1. For even + weight, the sign is computed by a recipe found in 11.1 of [Watkins]_. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) + sage: H.euler_factor(-1, 5) + 15625*T^4 + 500*T^3 - 130*T^2 + 4*T + 1 + + sage: H = Hyp(gamma_list=[-6,-1,4,3]) + sage: H.weight(), H.degree() + (1, 2) + sage: t = 189/125 + sage: [H.euler_factor(1/t,p) for p in [11,13,17,19,23,29]] + [11*T^2 + 4*T + 1, + 13*T^2 + 1, + 17*T^2 + 1, + 19*T^2 + 1, + 23*T^2 + 8*T + 1, + 29*T^2 + 2*T + 1] + + sage: H = Hyp(cyclotomic=([6,2],[1,1,1])) + sage: H.weight(), H.degree() + (2, 3) + sage: [H.euler_factor(1/4,p) for p in [5,7,11,13,17,19]] + [125*T^3 + 20*T^2 + 4*T + 1, + 343*T^3 - 42*T^2 - 6*T + 1, + -1331*T^3 - 22*T^2 + 2*T + 1, + -2197*T^3 - 156*T^2 + 12*T + 1, + 4913*T^3 + 323*T^2 + 19*T + 1, + 6859*T^3 - 57*T^2 - 3*T + 1] + + sage: H = Hyp(alpha_beta=([1/12,5/12,7/12,11/12],[0,1/2,1/2,1/2])) + sage: H.weight(), H.degree() + (2, 4) + sage: t = -5 + sage: [H.euler_factor(1/t,p) for p in [11,13,17,19,23,29]] + [-14641*T^4 - 1210*T^3 + 10*T + 1, + -28561*T^4 - 2704*T^3 + 16*T + 1, + -83521*T^4 - 4046*T^3 + 14*T + 1, + 130321*T^4 + 14440*T^3 + 969*T^2 + 40*T + 1, + 279841*T^4 - 25392*T^3 + 1242*T^2 - 48*T + 1, + 707281*T^4 - 7569*T^3 + 696*T^2 - 9*T + 1] + + TESTS:: + + sage: H1 = Hyp(alpha_beta=([1,1,1],[1/2,1/2,1/2])) + sage: H2 = H1.swap_alpha_beta() + sage: H1.euler_factor(-1, 3) + 27*T^3 + 3*T^2 + T + 1 + sage: H2.euler_factor(-1, 3) + 27*T^3 + 3*T^2 + T + 1 + sage: H = Hyp(alpha_beta=([0,0,0,1/3,2/3],[1/2,1/5,2/5,3/5,4/5])) + sage: H.euler_factor(5,7) + 16807*T^5 - 686*T^4 - 105*T^3 - 15*T^2 - 2*T + 1 + + REFERENCES: + + - [Roberts2015]_ + - [Watkins]_ + """ + alpha = self._alpha + if 0 in alpha: + H = self.swap_alpha_beta() + return(H.euler_factor(~t, p, degree)) + + if t not in QQ or t in [0, 1]: + raise ValueError('wrong t') + if not is_prime(p): + raise ValueError('p not prime') + if not all(x.denominator() % p for x in self._alpha + self._beta): + raise NotImplementedError('p is wild') + if (t.valuation(p) or (t - 1).valuation(p) > 0): + raise NotImplementedError('p is tame') + # now p is good + if degree == 0: + d = self.degree() + bound = d // 2 + traces = [self.padic_H_value(p, i + 1, t) for i in range(bound)] + + w = self.weight() + + if w % 2: # sign is always +1 for odd weight + sign = 1 + elif d % 2: + sign = -kronecker_symbol((1 - t) * self._sign_param, p) + else: + sign = kronecker_symbol(t * (t - 1) * self._sign_param, p) + + return characteristic_polynomial_from_traces(traces, d, p, w, sign) + + def canonical_scheme(self, t=None): + """ + Return the canonical scheme. + + This is a scheme that contains this hypergeometric motive in its cohomology. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H = Hyp(cyclotomic=([3],[4])) + sage: H.gamma_list() + [-1, 2, 3, -4] + sage: H.canonical_scheme() + Spectrum of Quotient of Multivariate Polynomial Ring + in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring + in t over Rational Field by the ideal + (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^2*X1^3 + 27/64*Y0*Y1^4) + + sage: H = Hyp(gamma_list=[-2, 3, 4, -5]) + sage: H.canonical_scheme() + Spectrum of Quotient of Multivariate Polynomial Ring + in X0, X1, Y0, Y1 over Fraction Field of Univariate Polynomial Ring + in t over Rational Field by the ideal + (X0 + X1 - 1, Y0 + Y1 - 1, (-t)*X0^3*X1^4 + 1728/3125*Y0^2*Y1^5) + + REFERENCES: + + [Kat1991]_, section 5.4 + """ + if t is None: + t = FractionField(QQ['t']).gen() + basering = t.parent() + gamma_pos = [u for u in self.gamma_list() if u > 0] + gamma_neg = [u for u in self.gamma_list() if u < 0] + N_pos = len(gamma_pos) + N_neg = len(gamma_neg) + varX = ['X{}'.format(i) for i in range(N_pos)] + varY = ['Y{}'.format(i) for i in range(N_neg)] + ring = PolynomialRing(basering, varX + varY) + gens = ring.gens() + X = gens[:N_pos] + Y = gens[N_pos:] + eq0 = ring.sum(X) - 1 + eq1 = ring.sum(Y) - 1 + eq2_pos = ring.prod(X[i] ** gamma_pos[i] for i in range(N_pos)) + eq2_neg = ring.prod(Y[j] ** -gamma_neg[j] for j in range(N_neg)) + + ideal = ring.ideal([eq0, eq1, self.M_value() * eq2_neg - t * eq2_pos]) + return Spec(ring.quotient(ideal)) diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index a37c7362640..b59ee45d971 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -1601,8 +1601,8 @@ def discrete_log(self, level, x): sage: G = SmoothCharacterGroupRamifiedQuadratic(3, 1, QQ) sage: s = G.number_field().gen() sage: G.discrete_log(4, 3 + 2*s) - [5, 2, 1, 1] - sage: gs = G.unit_gens(4); gs[0]^5 * gs[1]^2 * gs[2] * gs[3] - (3 + 2*s) in G.ideal(4) + [5, 1, 1, 1] + sage: gs = G.unit_gens(4); gs[0]^5 * gs[1] * gs[2] * gs[3] - (3 + 2*s) in G.ideal(4) True """ x = self.number_field().coerce(x) diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index a269b623775..1370070da37 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -15,6 +15,7 @@ from sage.structure.sage_object import SageObject from sage.structure.sequence import Sequence +from sage.structure.richcmp import richcmp_method, richcmp from sage.modular.modsym.all import ModularSymbols from sage.modular.arithgroup.all import Gamma0 from sage.modules.all import vector @@ -27,6 +28,7 @@ # This variable controls importing the SciPy library sparingly scipy=None +@richcmp_method class NumericalEigenforms(SageObject): """ numerical_eigenforms(group, weight=2, eps=1e-20, delta=1e-2, tp=[2,3,5]) @@ -108,24 +110,22 @@ def __init__(self, group, weight=2, eps=1e-20, self._eps = eps self._delta = delta - def __cmp__(self, other): + def __richcmp__(self, other, op): """ - Compare two spaces of numerical eigenforms. Currently - returns 0 if they come from the same space of modular - symbols, and -1 otherwise. + Compare two spaces of numerical eigenforms. + + They are considered equal if and only if they come from the + same space of modular symbols. EXAMPLES:: sage: n = numerical_eigenforms(23) - sage: n.__cmp__(loads(dumps(n))) - 0 + sage: n == loads(dumps(n)) + True """ - if not isinstance( other, NumericalEigenforms ): - raise ValueError("%s is not a space of numerical eigenforms"%other) - if self.modular_symbols() == other.modular_symbols(): - return 0 - else: - return -1 + if not isinstance(other, NumericalEigenforms): + return NotImplemented + return richcmp(self.modular_symbols(), other.modular_symbols(), op) def level(self): """ diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index 1b310deb9ac..f3e119c8988 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -58,7 +58,7 @@ sage: alpha = MSymbol(N, a + 2, 3*a^2) sage: alpha.lift_to_sl2_Ok() - [1, -4*a^2 + 9*a - 21, a + 2, a^2 - 3*a + 3] + [-3*a^2 + a + 12, 25*a^2 - 50*a + 100, a + 2, a^2 - 3*a + 3] sage: Ok = k.ring_of_integers() sage: M = Matrix(Ok, 2, alpha.lift_to_sl2_Ok()) sage: det(M) @@ -804,7 +804,7 @@ def lift_to_sl2_Ok(self, i): sage: P[5] M-symbol (1/2*a + 1/2: -a) of level Fractional ideal (3) sage: P.lift_to_sl2_Ok(5) - [1, -2, 1/2*a + 1/2, -a] + [-a, 2*a - 2, 1/2*a + 1/2, -a] :: diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 483daf15ba7..233710764d2 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -310,6 +310,18 @@ class FGP_Module_class(Module): Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: type(Q) + + TESTS:: + + Make sure that the problems in + http://trac.sagemath.org/sage_trac/ticket/7516 are fixed:: + + sage: V = FreeModule(QQ, 2) + sage: W = V.submodule([V([1,1])]) + sage: Z = W.submodule([]) + sage: WmodZ = W / Z + sage: loads(dumps(WmodZ))==WmodZ + True """ # The class to be used for creating elements of this @@ -1589,9 +1601,17 @@ def annihilator(self): Finitely generated module V/W over Integer Ring with invariants (0, 0) sage: Q.annihilator() Principal ideal (0) of Integer Ring + + We check that :trac:`22720` is resolved:: + + sage: H=AdditiveAbelianGroup([]) + sage: H.annihilator() + Principal ideal (1) of Integer Ring """ if not self.is_finite(): g = 0 + elif self.cardinality() == 1: + g = 1 else: g = reduce(lcm, self.invariants()) return self.base_ring().ideal(g) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 05bb3729b37..acd3d709a83 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -4408,7 +4408,15 @@ def __richcmp__(self, other, op): lx = self.base_ring() rx = other.base_ring() if lx == rx: - return rich_to_bool(op, 0) + #We do not want to create an inner product matrix in memory if + #self and other use the dot product + if self._inner_product_is_dot_product() and other._inner_product_is_dot_product(): + return rich_to_bool(op, 0) + else: + #this only affects free_quadratic_modules + lx = self.inner_product_matrix() + rx = other.inner_product_matrix() + return richcmp(lx,rx,op) try: if self.base_ring().is_subring(other.base_ring()): return rich_to_bool(op, -1) diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index bbf31f7db31..6f5aa673b1e 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -284,11 +284,18 @@ class FreeQuadraticModule_generic(free_module.FreeModule_generic): sage: Q3 < V False - Beware: currently, the inner_product_matrix is not part of the comparison:: + The inner_product_matrix is part of the comparison:: sage: Q3zero = FreeQuadraticModule(QQ,3,matrix.zero(3)) sage: Q3zero == Q3 - True + False + + We test that :trac:`23915` is fixed:: + + sage: M1 = FreeQuadraticModule(ZZ,1,matrix.identity(1)) + sage: M2 = FreeQuadraticModule(ZZ,1,matrix.identity(1)*2) + sage: M1 == M2 + False """ def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False): """ @@ -803,6 +810,7 @@ def __init__(self, base_ring, rank, inner_product_matrix, sparse=False): sage: FreeModule(ZZ, 4) Ambient free module of rank 4 over the principal ideal domain Integer Ring + """ free_module.FreeModule_ambient.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse) #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py new file mode 100644 index 00000000000..cfa09b2bff4 --- /dev/null +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -0,0 +1,442 @@ +#***************************************************************************** +# Copyright (C) 2017 Simon Brandhorst +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.modules.free_quadratic_module import FreeQuadraticModule_submodule_with_basis_pid, FreeQuadraticModule +from sage.matrix.constructor import matrix +from sage.arith.misc import gcd + +############################################################################### +# +# Constructor functions +# +############################################################################### + +def IntegralLattice(inner_product_matrix, basis=None): + r""" + Return the integral lattice spanned by ``basis`` in the ambient space. + + A lattice is a finitely generated free abelian group `L \cong \Z^r` equipped + with a non-degenerate, symmetric bilinear form `L \times L \colon \rightarrow \Z`. + Here, lattices have an ambient quadratic space `\Q^n` and a distinguished basis. + + INPUT: + + - ``inner_product_matrix`` -- a symmetric matrix over the rationals + + - ``basis`` -- a list of elements of ambient or a matrix + + Output: + + A lattice in the ambient space defined by the inner_product_matrix. + Unless specified, the basis of the lattice is the standard basis. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [0 1] + [1 0] + + We can specify a basis as well:: + + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] + """ + if basis is None: + basis = matrix.identity(ZZ, inner_product_matrix.ncols()) + if inner_product_matrix != inner_product_matrix.transpose(): + raise ValueError("Argument inner_product_matrix must be symmetric\n%s" % inner_product_matrix) + + A = FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), + inner_product_matrix=inner_product_matrix) + return FreeQuadraticModule_integer_symmetric(ambient=A, basis=basis, + inner_product_matrix=inner_product_matrix, + already_echelonized=False) + +############################################################################### +# +# Base class for Lattices +# +############################################################################### + +class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_basis_pid): + r""" + This class represents non-degenerate, integral, symmetric free quadratic `\Z`-modules. + + INPUT: + + - ``ambient`` -- an ambient free quadratic module + + - ``basis`` -- a list of elements of ambient or a matrix + + - ``inner_product_matrix`` -- a symmetric matrix over the rationals + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0]),basis=[vector([1,1])]) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] + """ + def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): + r""" + Create the integral lattice spanned by ``basis`` in the ambient space. + + TESTS:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: TestSuite(L).run() + """ + FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=check, already_echelonized=already_echelonized) + if self.determinant() == 0: + raise ValueError("Lattices must be nondegenerate. Use FreeQuadraticModule instead") + if self.gram_matrix().base_ring() is not ZZ: + if self.gram_matrix().denominator() != 1: + raise ValueError("Lattices must be integral. Use FreeQuadraticModule instead") + + def _repr_(self): + r""" + The print representation of this lattice. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A2 = IntegralLattice(matrix(ZZ,2,2,[2,-1,-1,2])) + sage: A2 + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [ 2 -1] + [-1 2] + """ + if self.is_sparse(): + s = "Sparse lattice of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%s\n" % self.basis_matrix() + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + else: + s = "Lattice of degree %s and rank %s over %s\n"%( + self.degree(), self.rank(), self.base_ring()) + \ + "Basis matrix:\n%s\n" % self.basis_matrix() + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + return s + + def is_even(self): + r""" + Return whether the diagonal entries of the Gram matrix are even. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[-1,1,1,2])) + sage: L.is_even() + False + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: L.is_even() + True + """ + return all(d % 2 == 0 for d in self.gram_matrix().diagonal()) + + def dual_lattice(self): + r""" + Return the dual lattice as a :class:`FreeQuadraticModule` + + Let `L` be a lattice. Its dual lattice is + + .. MATH:: + + L^\vee = \{x \in L \otimes \QQ : \langle x, l \rangle \forall y \in L \}. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: Ldual=L.dual_lattice() + sage: Ldual + Free module of degree 2 and rank 2 over Integer Ring + Echelon basis matrix: + [1/3 2/3] + [ 0 1] + + Since our lattices are always integral, a lattice is contained in its dual:: + + sage: L.is_submodule(Ldual) + True + """ + return self.span(self.gram_matrix().inverse()*self.basis_matrix()) + + def discriminant_group(self, s=0): + r""" + Return the discriminant group `L^\vee / L` of this lattice. + + INPUT: + + - ``s`` -- an integer (default: 0) + + OUTPUT: + + The `s` primary part of the discriminant group. + If `s=0`, returns the whole discriminant group. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])*2) + sage: L.discriminant_group() + Finitely generated module V/W over Integer Ring with invariants (2, 10) + sage: L.discriminant_group(2) + Finitely generated module V/W over Integer Ring with invariants (2, 2) + sage: L.discriminant_group(5) + Finitely generated module V/W over Integer Ring with invariants (5) + + TESTS:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L.discriminant_group() + Finitely generated module V/W over Integer Ring with invariants () + """ + D = self.dual_lattice() / self + d = D.annihilator().gen() + a = d.prime_to_m_part(s) + Dp_gens = [a*g for g in D.gens()] + return D.submodule(Dp_gens) + + def signature(self): + r""" + Return the signature of this lattice, which is defined as + the difference between the number of positive eigenvalues and + the number of negative eigenvalues in the Gram matrix. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: U.signature() + 0 + """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + return QuadraticForm(QQ, self.gram_matrix()).signature() + + def signature_pair(self): + r""" + Return the signature tuple `(n_+,n_-)` of this lattice. + + Here `n_+` (resp. `n_-`) is the number of positive (resp. negative) + eigenvalues of the Gram matrix. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A2 = IntegralLattice(Matrix(ZZ,2,2,[2,-1,-1,2])) + sage: A2.signature_pair() + (2, 0) + """ + from sage.quadratic_forms.quadratic_form import QuadraticForm + return QuadraticForm(QQ, self.gram_matrix()).signature_vector()[:2] + + def direct_sum(self, M): + r""" + Return the direct sum of this lattice with ``M``. + + INPUT: + + - ``M`` -- a module over `\Z` + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: A = IntegralLattice(matrix([1])) + sage: A.direct_sum(A) + Lattice of degree 2 and rank 2 over Integer Ring + Basis matrix: + [1 0] + [0 1] + Inner product matrix: + [1|0] + [-+-] + [0|1] + """ + IM = matrix.block_diagonal([self.inner_product_matrix(), M.inner_product_matrix()]) + ambient = FreeQuadraticModule(ZZ, self.degree() + M.degree(), inner_product_matrix=IM) + smzero = matrix.zero(self.rank(), M.degree()) + mszero = matrix.zero(M.rank(), self.degree()) + basis = self.basis_matrix().augment(smzero).stack(mszero.augment(M.basis_matrix())) + ipm = ambient.inner_product_matrix() + return FreeQuadraticModule_integer_symmetric( + ambient=ambient, basis=basis, inner_product_matrix=ipm, already_echelonized=False) + + def is_primitive(self, M): + r""" + Return whether ``M`` is a primitive submodule of this lattice. + + A `\Z`-submodule ``M`` of a `\Z`-module ``L`` is called primitive if + the quotient ``L/M`` is torsion free. + + INPUT: + + - ``M`` -- a submodule of this lattice + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L1 = U.span([vector([1,1])]) + sage: L2 = U.span([vector([1,-1])]) + sage: U.is_primitive(L1) + True + sage: U.is_primitive(L2) + True + sage: U.is_primitive(L1+L2) + False + + We can also compute the index:: + + sage: (L1+L2).index_in(U) + 2 + """ + return (gcd((self/M).invariants()) == 0) + + def orthogonal_complement(self, M): + r""" + Return the orthogonal complement of ``M`` in this lattice. + + INPUT: + + - ``M`` -- a module in the same ambient space or + a list of elements of the ambient space + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,1,1,-2])) + sage: S = L.span([vector([1,1])]) + sage: L.orthogonal_complement(S) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 3] + Inner product matrix: + [ 2 1] + [ 1 -2] + + sage: L = IntegralLattice(matrix.identity(2)) + sage: L.orthogonal_complement([vector(ZZ,[1,0])]) + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [0 1] + Inner product matrix: + [1 0] + [0 1] + """ + from sage.modules.free_module import FreeModule_generic + if not isinstance(M,FreeModule_generic): + M = self.span(M) + elif M.ambient_vector_space()!=self.ambient_vector_space(): + raise ValueError("M must have the same ambient vector space as this lattice.") + + K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() + K = self.span( K.basis() ) + K = K.base_extend(QQ) + return self.sublattice(self.intersection(K).basis()) + + def sublattice(self, basis): + r""" + Return the sublattice spanned by ``basis``. + + INPUT: + + - ``basis`` -- A list of elements of this lattice. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: U = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: S = U.sublattice([vector([1,1])]) + sage: S + Lattice of degree 2 and rank 1 over Integer Ring + Basis matrix: + [1 1] + Inner product matrix: + [0 1] + [1 0] + sage: U.sublattice([vector([1,-1])/2]) + Traceback (most recent call last): + ... + ValueError: Lattices must be integral. Use FreeQuadraticModule instead + + sage: S.sublattice([vector([1,-1])]) + Traceback (most recent call last): + ... + ValueError: Argument basis (= [(1, -1)]) does not span a submodule of this lattice + """ + M = FreeQuadraticModule_integer_symmetric( + ambient=self.ambient_module(), basis=basis, + inner_product_matrix=self.inner_product_matrix(), + already_echelonized=False) + if not M.is_submodule(self): + raise ValueError("Argument basis (= %s) does not span a submodule of this lattice" % basis) + return M + + def overlattice(self, gens): + r""" + Return the lattice spanned by this lattice and ``gens``. + + INPUT: + + - ``gens`` -- a list of elements of this lattice, or a rational matrix + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[2,0,0,2])) + sage: M = L.overlattice([vector([1,1])/2]) + sage: M.gram_matrix() + [1 1] + [1 2] + """ + basis = (self + self.span(gens)).basis() + return FreeQuadraticModule_integer_symmetric( + ambient=self.ambient_module(), basis=basis, + inner_product_matrix=self.inner_product_matrix(), + already_echelonized=False) + + def genus(self): + r""" + Return the genus of this lattice. + + EXAMPLES:: + + sage: from sage.modules.free_quadratic_module_integer_symmetric import IntegralLattice + sage: L = IntegralLattice(Matrix(ZZ,2,2,[0,1,1,0])) + sage: L.genus() + Genus of [0 1] + [1 0] + """ + from sage.quadratic_forms.genera.genus import Genus + return Genus(self.gram_matrix()) diff --git a/src/sage/numerical/backends/coin_backend.pyx b/src/sage/numerical/backends/coin_backend.pyx index 504183b4abd..da527137d21 100644 --- a/src/sage/numerical/backends/coin_backend.pyx +++ b/src/sage/numerical/backends/coin_backend.pyx @@ -28,6 +28,9 @@ from cysignals.signals cimport sig_on, sig_off from sage.numerical.mip import MIPSolverException from copy import copy +from sage.parallel.ncpus import ncpus + + cdef class CoinBackend(GenericBackend): """ @@ -760,7 +763,7 @@ cdef class CoinBackend(GenericBackend): # multithreading import multiprocessing - model.setNumberThreads(multiprocessing.cpu_count()) + model.setNumberThreads(ncpus()) model.branchAndBound() @@ -1413,7 +1416,7 @@ cdef class CoinBackend(GenericBackend): # multithreading import multiprocessing - model.setNumberThreads(multiprocessing.cpu_count()) + model.setNumberThreads(ncpus()) if n != self.model.solver().getNumCols() or m != self.model.solver().getNumRows(): raise ValueError("Must provide the status of every column and row variables") diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index 1b1d2d95503..db790673780 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -202,8 +202,10 @@ passing parameters to the :meth:`RESetMapReduce.run` method. One can use the three following parameters: -- ``max_proc`` -- maximum number of process used. - default: number of processor on the machine +- ``max_proc`` -- (integer, default: ``None``) if given, the + maximum number of worker processors to use. The actual number + is also bounded by the value of the environment variable + ``SAGE_NUM_THREADS`` (the number of cores by default). - ``timeout`` -- a timeout on the computation (default: ``None``) - ``reduce_locally`` -- whether the workers should reduce locally their work or sends results to the master as soon as possible. @@ -501,7 +503,7 @@ """ from __future__ import print_function, absolute_import -from multiprocessing import Process, Value, Semaphore, Lock, cpu_count +from multiprocessing import Process, Value, Semaphore, Lock from multiprocessing.queues import Pipe, SimpleQueue from multiprocessing.sharedctypes import RawArray from threading import Thread @@ -509,6 +511,7 @@ from sage.misc.lazy_attribute import lazy_attribute import collections import copy +import os import sys import random import ctypes @@ -537,13 +540,14 @@ -def proc_number(max_proc = None): +def proc_number(max_proc=None): r""" - Computing the number of process used + Return the number of processes to use INPUT: - - ``max_proc`` -- the maximum number of process used + - ``max_proc`` -- an upper bound on the number of processes or + ``None``. EXAMPLES:: @@ -555,10 +559,12 @@ def proc_number(max_proc = None): sage: proc_number(max_proc=2) in (1, 2) True """ + from sage.parallel.ncpus import ncpus + n = ncpus() if max_proc is None: - return max(cpu_count(), 1) + return n else: - return min(max_proc, max(cpu_count(), 2)) + return min(max_proc, n) class AbortError(Exception): @@ -1036,14 +1042,14 @@ def reduce_init(self): """ return copy.copy(self._reduce_init) - - def setup_workers(self, max_proc = None, reduce_locally=True): + def setup_workers(self, max_proc=None, reduce_locally=True): r""" Setup the communication channels INPUT: - - ``mac_proc`` -- an integer: the maximum number of workers + - ``max_proc`` -- (integer) an upper bound on the number of + worker processes. - ``reduce_locally`` -- whether the workers should reduce locally their work or sends results to the master as soon as possible. @@ -1337,8 +1343,8 @@ def random_worker(self): return self._workers[victim] def run(self, - max_proc = None, - reduce_locally = True, + max_proc=None, + reduce_locally=True, timeout=None, profile=None): r""" @@ -1346,8 +1352,10 @@ def run(self, INPUT: - - ``max_proc`` -- maximum number of process used. - default: number of processor on the machine + - ``max_proc`` -- (integer, default: ``None``) if given, the + maximum number of worker processors to use. The actual number + is also bounded by the value of the environment variable + ``SAGE_NUM_THREADS`` (the number of cores by default). - ``reduce_locally`` -- See :class:`RESetMapReduceWorker` (default: ``True``) - ``timeout`` -- a timeout on the computation (default: ``None``) - ``profile`` -- directory/filename prefix for profiling, or ``None`` diff --git a/src/sage/parallel/ncpus.py b/src/sage/parallel/ncpus.py index 88882528c69..7222e0a5d69 100644 --- a/src/sage/parallel/ncpus.py +++ b/src/sage/parallel/ncpus.py @@ -43,6 +43,16 @@ def ncpus(): sage: sage.parallel.ncpus.ncpus() # random output -- depends on machine. 2 """ + # Support Sage environment variable SAGE_NUM_THREADS + # NOTE: while doctesting, this is forced to be 2 by the + # sage-runtests script + try: + n = os.environ["SAGE_NUM_THREADS"] + except KeyError: + pass + else: + return int(n) + #for Linux, Unix and MacOS if hasattr(os, "sysconf"): if "SC_NPROCESSORS_ONLN" in os.sysconf_names: diff --git a/src/sage/parallel/use_fork.py b/src/sage/parallel/use_fork.py index 02ff810336b..228bf9d987d 100644 --- a/src/sage/parallel/use_fork.py +++ b/src/sage/parallel/use_fork.py @@ -145,7 +145,7 @@ def __call__(self, f, inputs): sage: L = list(Polygen([QQ])) sage: L [(((Rational Field,), {}), - "INVALID DATA ('__init__() takes at most 2 positional arguments (4 given)', , (Univariate Polynomial Ring in x over Rational Field, [0, 1], False, True))")] + 'INVALID DATA __init__() takes at most 2 positional arguments (4 given)')] Fix the unpickling:: diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 7d0961ad572..5399d98bcd2 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -17,7 +17,7 @@ from sage.rings.rational_field import RationalField from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import FiniteField - +import copy def Genus(A): r""" @@ -101,6 +101,14 @@ def is_GlobalGenus(G): sage: G = Genus(A) sage: is_GlobalGenus(G) True + + sage: from sage.quadratic_forms.genera.genus import Genus,is_GlobalGenus + sage: G=Genus(matrix.diagonal([2,2,2,2])) + sage: G._local_symbols[0]._symbol=[[0,2,3,0,0],[1,2,5,1,0]] + sage: G._representative=None + sage: is_GlobalGenus(G) + False + """ D = G.determinant() r, s = G.signature_pair_of_matrix() @@ -179,10 +187,10 @@ def is_2_adic_genus(genus_symbol_quintuple_list): if s[3] == 0 or s[2] != s[4]: return False if s[1] == 2 and s[3] == 1: - if s[2] in (1,-1): + if s[2]%8 in (1,7): if not s[4] in (0,2,6): return False - if s[2] in (3,-3): + if s[2]%8 in (3,5): if not s[4] in (2,4,6): return False if (s[1] - s[4])% 2 == 1: @@ -423,6 +431,8 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): Add an example where sign walking occurs! """ + # Protect the input from unwanted modification + genus_symbol_quintuple_list = copy.deepcopy(genus_symbol_quintuple_list) canonical_symbol = genus_symbol_quintuple_list # Canonical determinants: for i in range(len(genus_symbol_quintuple_list)): @@ -1597,7 +1607,17 @@ def __eq__(self, other): sage: GS2 == GS2 True - + + TESTS:: + + sage: D4=QuadraticForm(Matrix(ZZ,4,4,[2,0,0,-1,0,2,0,-1,0,0,2,-1,-1,-1,-1,2])) + sage: G=D4.global_genus_symbol() + sage: sage.quadratic_forms.genera.genus.is_GlobalGenus(G) + True + sage: G==deepcopy(G) + True + sage: sage.quadratic_forms.genera.genus.is_GlobalGenus(G) + True """ if self is other: return True diff --git a/src/sage/quivers/morphism.py b/src/sage/quivers/morphism.py index a0ed5e77aa7..b6cd04e27bd 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -591,7 +591,7 @@ def _assert_valid_hom(self): sage: f = S.hom(maps2, S) # indirect doctest Traceback (most recent call last): ... - TypeError: Unable to coerce x (={...}) to a morphism in Dimension 2 QuiverHomSpace + TypeError: unable to convert {2: [1, -1], 3: 1} to an element of Dimension 2 QuiverHomSpace """ # Check that the domain and codomains dimensions add correctly totaldim = 0 diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 0b87be89c8b..c52c8696327 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -43,6 +43,15 @@ * - :meth:`~AsymptoticExpansionGenerators.SingularityAnalysis` - an asymptotic expansion obtained by singularity analysis + * - :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion` + - the singular expansion of a function `y(z)` satisfying `y(z) = z \Phi(y(z))` + + * - :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart` + - the singular expansion of the periodic part of a function `y(z)` satisfying `y(z) = z\Phi(y(z))` + + * - :meth:`~AsymptoticExpansionGenerators.InverseFunctionAnalysis` + - coefficient growth of a function `y(z)` defined implicitly by `y(z) = z \Phi(y(z))` + AUTHORS: @@ -74,7 +83,9 @@ from __future__ import print_function from __future__ import absolute_import +from sage.misc.superseded import experimental from sage.structure.sage_object import SageObject +from sage.misc.defaults import series_precision class AsymptoticExpansionGenerators(SageObject): @@ -92,6 +103,9 @@ class AsymptoticExpansionGenerators(SageObject): - :meth:`~log_Stirling` - :meth:`~Binomial_kn_over_n` - :meth:`~SingularityAnalysis` + - :meth:`~ImplicitExpansion` + - :meth:`~ImplicitExpansionPeriodicPart` + - :meth:`~InverseFunctionAnalysis` """ @staticmethod @@ -271,7 +285,7 @@ def log_Stirling(var, precision=None, skip_constant_summand=False): n = A.gen() if precision is None: - precision = AsymptoticRing.__default_prec__ + precision = series_precision() from sage.functions.log import log result = A.zero() @@ -426,7 +440,7 @@ def HarmonicNumber(var, precision=None, skip_constant_summand=False): n = A.gen() if precision is None: - precision = A.default_prec + precision = series_precision() from sage.functions.log import log result = A.zero() @@ -716,14 +730,8 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, ALGORITHM: - See [FS2009]_ together with the - `errata list `_. + See [FS2009]_. - REFERENCES: - - .. [FS2009] Philippe Flajolet and Robert Sedgewick, - `Analytic combinatorics `_. - Cambridge University Press, Cambridge, 2009. TESTS:: @@ -920,7 +928,7 @@ def inverse_gamma_derivative(shift, r): delta = ZZ(delta) if precision is None: - precision = AsymptoticRing.__default_prec__ + precision = series_precision() if not normalized and not (beta in ZZ and delta in ZZ): @@ -992,6 +1000,418 @@ def inverse_gamma_derivative(shift, r): return result + @staticmethod + @experimental(20050) + def ImplicitExpansion(var, phi, tau=None, precision=None): + r""" + Return the singular expansion for a function `y(z)` defined + implicitly by `y(z) = z \Phi(y(z))`. + + The function `\Phi` is assumed to be analytic around `0`. Furthermore, + `\Phi` is not allowed to be an affine-linear function and we require + `\Phi(0) \neq 0`. + + Furthermore, it is assumed that there is a unique positive solution `\tau` + of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + + All details are given in Chapter VI.7 of [FS2009]_. + + INPUT: + + - ``var`` -- a string for the variable name. + + - ``phi`` -- the function `\Phi`. See the extended description for + assumptions on `\Phi`. + + - ``tau`` -- (default: ``None``) the fundamental constant described + in the extended description. If ``None``, then `\tau` is determined + automatically if possible. + + - ``precision`` -- (default: ``None``) an integer. If ``None``, then + the default precision of the asymptotic ring is used. + + + OUTPUT: + + An asymptotic expansion. + + + .. NOTE:: + + In the given case, the radius of convergence of the function of + interest is known to be `\rho = \tau/\Phi(\tau)`. Until :trac:`20050` + is implemented, the variable in the returned asymptotic expansion + represents a singular element of the form `(1 - z/\rho)^{-1}`, + for the variable `z\to\rho`. + + + EXAMPLES: + + We can, for example, determine the singular expansion of the well-known + tree function `T` (which satisfies `T(z) = z \exp(T(z))`):: + + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=exp, precision=8) + doctest:warning + ... + FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + See http://trac.sagemath.org/20050 for details. + 1 - sqrt(2)*Z^(-1/2) + 2/3*Z^(-1) - 11/36*sqrt(2)*Z^(-3/2) + + 43/135*Z^(-2) - 769/4320*sqrt(2)*Z^(-5/2) + 1768/8505*Z^(-3) + O(Z^(-7/2)) + + Another classical example in this context is the generating function `B(z)` + enumerating binary trees with respect to the number of inner nodes. The + function satisfies `B(z) = z (1 + 2B(z) + B(z)^2)`, which can also be + solved explicitly, yielding `B(z) = \frac{1 - \sqrt{1 - 4z}}{2z} - 1`. We + compare the expansions from both approaches:: + + sage: def B(z): + ....: return (1 - sqrt(1 - 4*z))/(2*z) - 1 + sage: A. = AsymptoticRing('Z^QQ', QQ, default_prec=3) + sage: B((1-1/Z)/4) + 1 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) + - 2*Z^(-5/2) + O(Z^(-3)) + sage: asymptotic_expansions.ImplicitExpansion(Z, phi=lambda u: 1 + 2*u + u^2, precision=7) + 1 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) + - 2*Z^(-5/2) + O(Z^(-3)) + + Neither `\tau` nor `\Phi` have to be known explicitly, they can + also be passed symbolically:: + + sage: tau = var('tau') + sage: phi = function('phi') + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=phi, tau=tau, precision=3) # long time + tau + (-sqrt(2)*sqrt(-tau*phi(tau)^2/(2*tau*diff(phi(tau), tau)^2 + - tau*phi(tau)*diff(phi(tau), tau, tau) + - 2*phi(tau)*diff(phi(tau), tau))))*Z^(-1/2) + O(Z^(-1)) + + Note that we do not check whether a passed `\tau` actually + satisfies the requirements. Only the first of the following + expansions is correct:: + + sage: asymptotic_expansions.ImplicitExpansion('Z', + ....: phi=lambda u: 1 + 2*u + u^2, precision=5) # correct expansion + 1 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + O(Z^(-2)) + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=2, precision=5) + Traceback (most recent call last): + ... + ZeroDivisionError: Symbolic division by zero + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=3, precision=5) + 3 - 4*I*sqrt(3)*Z^(-1/2) + 6*I*sqrt(3)*Z^(-3/2) + O(Z^(-2)) + + .. SEEALSO:: + + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart`, + :meth:`~AsymptoticExpansionGenerators.InverseFunctionAnalysis`. + + TESTS:: + + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 42*u, precision=5) + Traceback (most recent call last): + ... + ValueError: The function phi does not satisfy the requirements + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 42*u + u^2, precision=5) + Traceback (most recent call last): + ... + ValueError: The function phi does not satisfy the requirements + sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + u^2 + u^42, precision=5) + Traceback (most recent call last): + ... + ValueError: Fundamental constant tau could not be determined + + """ + from sage.symbolic.ring import SR + from sage.rings.rational_field import QQ + from sage.rings.integer_ring import ZZ + from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing + from sage.arith.srange import srange + y, u = SR('y'), SR('u') + one_half = QQ(1)/2 + + if phi(QQ(0)).is_zero() or phi(u) == phi(0) + u*phi(u).diff(u)(u=0): + raise ValueError('The function phi does not satisfy the requirements') + + if tau is None: + tau = _fundamental_constant_implicit_function_(phi=phi) + + def H(y): + return tau/phi(tau) - y/phi(y) + + A = AsymptoticRing(growth_group='{Z}^QQ'.format(Z=var), + coefficient_ring=SR, + default_prec=precision) + if precision is None: + precision = ZZ(A.default_prec) + Z = A.gen() + + def ansatz(prec=precision): + if prec < 1: + return A(1).O() + if prec == 1: + return ((1/Z)**one_half).O() + return (-(2*tau/phi(tau)/H(y).diff(y, 2)(y=tau)).sqrt() * (1/Z)**one_half + + sum(SR("d{}".format(j)) * (1/Z)**(j * one_half) for j in srange(2, prec)) + + ((1/Z)**(prec * one_half)).O()) + + # we compare coefficients between a "single" Z and the + # following expansion, this allows us to compute the constants d_j + z = SR('z') + z_expansion = sum(H(z).diff(z, k)(z=tau)/k.factorial() * + ansatz(prec=precision+2-k)**k + for k in srange(2, precision)) + ((1/Z)**(precision * one_half)).O() + + solution_dict = dict() + for k in srange(2, precision-1): + coef = z_expansion.monomial_coefficient((1/Z)**((k+1) * one_half)) + current_var = SR('d{k}'.format(k=k)) + solution_dict[current_var] = coef.subs(solution_dict).solve(current_var)[0].rhs() + + return A(tau) + ansatz(prec=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) + + + @staticmethod + @experimental(20050) + def ImplicitExpansionPeriodicPart(var, phi, period, tau=None, precision=None): + r""" + Return the singular expansion for the periodic part of a function `y(z)` + defined implicitly by `y(z) = z \Phi(y(z))`. + + The function `\Phi` is assumed to be analytic around `0`. Furthermore, + `\Phi` is not allowed to be an affine-linear function and we require + `\Phi(0) \neq 0`. For an integer `p`, `\Phi` is called `p`-periodic + if we have `\Psi(u^p) = \Phi(u)` for a power series `\Psi` + where `p` is maximal. + + Furthermore, it is assumed that there is a unique positive solution `\tau` + of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + + If `\Phi` is `p`-periodic, then we have `y(z) = z g(z^p)`. This method + returns the singular expansion of `g(z)`. + + INPUT: + + - ``var`` -- a string for the variable name. + + - ``phi`` -- the function `\Phi`. See the extended description for + assumptions on `\Phi`. + + - ``period`` -- the period of the function `\Phi`. See the + extended description for details. + + - ``tau`` -- (default: ``None``) the fundamental constant described + in the extended description. If ``None``, then `\tau` is determined + automatically if possible. + + - ``precision`` -- (default: ``None``) an integer. If ``None``, then + the default precision of the asymptotic ring is used. + + + OUTPUT: + + An asymptotic expansion. + + + .. NOTE:: + + In the given case, the radius of convergence of the function of + interest is known to be `\rho = \tau/\Phi(\tau)`. Until :trac:`20050` + is implemented, the variable in the returned asymptotic expansion + represents a singular element of the form `(1 - z/\rho)^{-1}`, + for the variable `z\to\rho`. + + .. SEEALSO:: + + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, + :meth:`~AsymptoticExpansionGenerators.InverseFunctionAnalysis`. + + EXAMPLES: + + The generating function enumerating binary trees with respect to + tree size satisfies `B(z) = z (1 + B(z)^2)`. This function can be + written as `B(z) = z g(z^2)`, and as `B(z)` can be determined + explicitly we have `g(z) = \frac{1 - \sqrt{1 - 4z}}{2z}`. We + compare the corresponding expansions:: + + sage: asymptotic_expansions.ImplicitExpansionPeriodicPart('Z', phi=lambda u: 1 + u^2, + ....: period=2, precision=7) + doctest:warning + ... + FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation. + See http://trac.sagemath.org/20050 for details. + 2 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) - 2*Z^(-5/2) + O(Z^(-3)) + sage: def g(z): + ....: return (1 - sqrt(1 - 4*z))/(2*z) + sage: A. = AsymptoticRing('Z^QQ', QQ, default_prec=3) + sage: g((1 - 1/Z)/4) + 2 - 2*Z^(-1/2) + 2*Z^(-1) - 2*Z^(-3/2) + 2*Z^(-2) - 2*Z^(-5/2) + O(Z^(-3)) + + """ + from sage.symbolic.ring import SR + u = SR('u') + + if tau is None: + tau = _fundamental_constant_implicit_function_(phi=phi) + + tau_p = tau**period + aperiodic_expansion = asymptotic_expansions.ImplicitExpansion(var, + phi=lambda u: phi(u**(1/period))**period, + tau=tau_p, precision=precision) + + rho = tau/phi(tau) + Z = aperiodic_expansion.parent().gen() + return 1/rho * (aperiodic_expansion/(1 - 1/Z))**(1/period) + + + @staticmethod + def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): + r""" + Return the coefficient growth of a function `y(z)` defined implicitly + by `y(z) = z \Phi(y(z))`. + + The function `\Phi` is assumed to be analytic around `0`. Furthermore, + `\Phi` is not allowed to be an affine-linear function and we require + `\Phi(0) \neq 0`. For an integer `p`, `\Phi` is called `p`-periodic + if we have `\Psi(u^p) = \Phi(u)` for a power series `\Psi` + where `p` is maximal. + + Furthermore, it is assumed that there is a unique positive solution `\tau` + of `\Phi(\tau) - \tau\Phi'(\tau) = 0`. + + INPUT: + + - ``var`` -- a string for the variable name. + + - ``phi`` -- the function `\Phi`. See the extended description for + assumptions on `\Phi`. + + - ``tau`` -- (default: ``None``) the fundamental constant described + in the extended description. If ``None``, then `\tau` is determined + automatically if possible. + + - ``period`` -- (default: `1`) the period of the function `\Phi`. See + the extended description for details. + + - ``precision`` -- (default: ``None``) an integer. If ``None``, then + the default precision of the asymptotic ring is used. + + + OUTPUT: + + An asymptotic expansion. + + + .. NOTE:: + + It is not checked that the passed period actually fits to + the passed function `\Phi`. + + The resulting asymptotic expansion is only valid + for `n \equiv 1 \mod p`, where `p` is the period. All other + coefficients are `0`. + + + EXAMPLES: + + There are `C_n` (the `n`-th Catalan number) different binary trees + of size `2n+1`, and there are no binary trees with an even number of + nodes. The corresponding generating function satisfies + `B(z) = z (1 + B(z)^2)`, which allows us to compare the asymptotic + expansions for the number of binary trees of size `n` obtained via + `C_n` and obtained via the analysis of `B(z)`:: + + sage: A. = AsymptoticRing('QQ^n * n^QQ', SR) + sage: binomial_expansion = asymptotic_expansions.Binomial_kn_over_n(n, k=2, precision=3) + sage: catalan_expansion = binomial_expansion / (n+1) + sage: catalan_expansion.subs(n=(n-1)/2) + 2*sqrt(1/2)/sqrt(pi)*2^n*n^(-3/2) - 3/2*sqrt(1/2)/sqrt(pi)*2^n*n^(-5/2) + + 25/16*sqrt(1/2)/sqrt(pi)*2^n*n^(-7/2) + O(2^n*n^(-9/2)) + sage: asymptotic_expansions.InverseFunctionAnalysis(n, phi=lambda u: 1 + u^2, period=2, + ....: tau=1, precision=8) + 2*sqrt(1/2)/sqrt(pi)*2^n*n^(-3/2) - 3/2*sqrt(1/2)/sqrt(pi)*2^n*n^(-5/2) + + 25/16*sqrt(1/2)/sqrt(pi)*2^n*n^(-7/2) + O(2^n*n^(-9/2)) + + The code in the aperiodic case is more efficient, however. Therefore, + it is recommended to use combinatorial identities to reduce to the + aperiodic case. In the example above, this is well-known: we now count + binary trees with `n` internal nodes. The corresponding generating function + satisfies `B(z) = z (1 + 2B(z) + B(z)^2)`:: + + sage: catalan_expansion + 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + + 145/128/sqrt(pi)*4^n*n^(-7/2) + O(4^n*n^(-9/2)) + sage: asymptotic_expansions.InverseFunctionAnalysis(n, phi=lambda u: 1 + 2*u + u^2, + ....: tau=1, precision=8) + 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + + 145/128/sqrt(pi)*4^n*n^(-7/2) + O(4^n*n^(-9/2)) + + .. SEEALSO:: + + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart`. + + + TESTS:: + + Omitting the precision parameter does not lead to an error (per default, + the default series precision is a python integer, which led to an error + in an earlier version of the code):: + + sage: set_series_precision(int(5)) + sage: asymptotic_expansions.InverseFunctionAnalysis('n', phi=lambda u: 1 + 2*u + u^2, + ....: tau=1) + 1/sqrt(pi)*4^n*n^(-3/2) - 9/8/sqrt(pi)*4^n*n^(-5/2) + O(4^n*n^(-3)) + """ + if tau is None: + tau = _fundamental_constant_implicit_function_(phi=phi) + + rho = tau/phi(tau) + + if period == 1: + expansion = asymptotic_expansions.ImplicitExpansion(var=var, phi=phi, + tau=tau, precision=precision) + return expansion._singularity_analysis_(var, zeta=rho, precision=precision) + expansion = asymptotic_expansions.ImplicitExpansionPeriodicPart(var=var, phi=phi, + period=period, tau=tau, precision=precision) + growth = expansion._singularity_analysis_(var, zeta=rho**period, precision=precision) + n = growth.parent().gen() + return growth.subs({n: (n-1)/period}) + +def _fundamental_constant_implicit_function_(phi): + r""" + Return the fundamental constant `\tau` occurring in the analysis of + implicitly defined functions. + + For a function `y(z)` satisfying `y(z) = z \Phi(y(z))`, the fundamental + constant `\tau` is the unique positive solution of the equation + `\Phi(\tau) - \tau \Phi'(\tau) = 0`. + + INPUT: + + - ``phi`` -- the function `\Phi`. + + .. SEEALSO:: + + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansion`, + :meth:`~AsymptoticExpansionGenerators.ImplicitExpansionPeriodicPart`. + + TESTS:: + + sage: from sage.rings.asymptotic.asymptotic_expansion_generators \ + ....: import _fundamental_constant_implicit_function_ + sage: _fundamental_constant_implicit_function_(phi=exp) + 1 + sage: _fundamental_constant_implicit_function_(phi=lambda u: 1 + u^2) + 1 + sage: _fundamental_constant_implicit_function_(phi=lambda u: 1 + 2*u + 2*u^2) + 1/2*sqrt(2) + + """ + from sage.symbolic.ring import SR + u = SR('u') + positive_solution = filter(lambda s: s.rhs() > 0, (phi(u) - u*phi(u).diff(u)).solve(u)) + if len(positive_solution) == 1: + return positive_solution[0].rhs() + raise ValueError('Fundamental constant tau could not be determined') + def _sa_coefficients_lambda_(K, beta=0): r""" Return the coefficients `\lambda_{k, \ell}(\beta)` used in singularity analysis. diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 9de56a6db81..2a1d58484cc 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -3347,9 +3347,6 @@ class AsymptoticRing(Algebra, UniqueRepresentation): Element = AsymptoticExpansion - __default_prec__ = series_precision() # default default-precision - - @staticmethod def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, category=None, default_prec=None): @@ -3469,7 +3466,7 @@ def format_names(N): category = CommutativeAlgebras(Rings()) if default_prec is None: - default_prec = cls.__default_prec__ + default_prec = series_precision() return super(AsymptoticRing, cls).__classcall__(cls, growth_group, coefficient_ring, diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index dfa7be2b651..ee048fb28cf 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -1969,7 +1969,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(-2, 1)/CBF(1, 1/3) - [-1.50000000000000 +/- 1.27e-15] + [1.500000000000000 +/- 8.94e-16]*I + [-1.500000000000000 +/- 8.83e-16] + [1.500000000000000 +/- 5.64e-16]*I sage: CBF(2+I)/CBF(0) [+/- inf] + [+/- inf]*I sage: CBF(1)/CBF(0) @@ -2115,7 +2115,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1).rising_factorial(5) 120.0000000000000 sage: CBF(1/3, 1/2).rising_factorial(300) - [-3.87949484514e+612 +/- 5.24e+600] + [-3.52042209763e+612 +/- 5.56e+600]*I + [-3.87949484514e+612 +/- 5.23e+600] + [-3.52042209763e+612 +/- 5.55e+600]*I sage: CBF(1).rising_factorial(-1) nan @@ -2124,7 +2124,7 @@ cdef class ComplexBall(RingElement): sage: ComplexBallField(128)(1).rising_factorial(2**64) [2.343691126796861348e+347382171305201285713 +/- 4.71e+347382171305201285694] sage: CBF(1/2).rising_factorial(CBF(2,3)) - [-0.123060451458124 +/- 4.46e-16] + [0.040641263167655 +/- 3.75e-16]*I + [-0.123060451458124 +/- 4.43e-16] + [0.040641263167655 +/- 3.72e-16]*I """ cdef ComplexBall result = self._new() @@ -2265,7 +2265,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(pi/2, 1/10).tan() - [+/- 2.87e-14] + [10.0333111322540 +/- 3.16e-14]*I + [+/- 2.87e-14] + [10.0333111322540 +/- 2.36e-14]*I sage: CBF(pi/2).tan() [+/- inf] """ @@ -2282,7 +2282,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(pi, 1/10).cot() - [+/- 5.74e-14] + [-10.0333111322540 +/- 4.05e-14]*I + [+/- 5.74e-14] + [-10.0333111322540 +/- 2.81e-14]*I sage: CBF(pi).cot() [+/- inf] """ @@ -2394,15 +2394,15 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).gamma() - [0.49801566811836 +/- 4.98e-15] + [-0.154949828301811 +/- 7.67e-16]*I + [0.498015668118356 +/- 9.16e-16] + [-0.154949828301811 +/- 7.08e-16]*I sage: CBF(-1).gamma() nan sage: CBF(1, 1).gamma(0) - [0.49801566811836 +/- 4.98e-15] + [-0.154949828301811 +/- 7.67e-16]*I + [0.498015668118356 +/- 9.16e-16] + [-0.154949828301811 +/- 7.08e-16]*I sage: CBF(1, 1).gamma(100) - [-3.6143867454139e-45 +/- 7.26e-59] + [-3.7022961377791e-44 +/- 4.71e-58]*I + [-3.6143867454139e-45 +/- 6.88e-59] + [-3.7022961377791e-44 +/- 4.41e-58]*I sage: CBF(1, 1).gamma(CLF(i)) - [0.32886684193500 +/- 5.49e-15] + [-0.18974945045621 +/- 1.49e-15]*I + [0.32886684193500 +/- 5.04e-15] + [-0.18974945045621 +/- 1.26e-15]*I """ cdef ComplexBall my_z cdef ComplexBall res = self._new() @@ -2468,7 +2468,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).psi() - [0.0946503206224770 +/- 7.34e-17] + [1.076674047468581 +/- 2.63e-16]*I + [0.0946503206224770 +/- 7.74e-17] + [1.076674047468581 +/- 2.58e-16]*I sage: CBF(-1).psi() nan sage: CBF(1,1).psi(10) @@ -2497,9 +2497,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).zeta() - [0.5821580597520036 +/- 5.27e-17] + [-0.9268485643308071 +/- 2.81e-17]*I + [0.5821580597520036 +/- 5.26e-17] + [-0.9268485643308071 +/- 2.80e-17]*I sage: CBF(1, 1).zeta(1) - [0.5821580597520036 +/- 5.27e-17] + [-0.9268485643308071 +/- 2.81e-17]*I + [0.5821580597520036 +/- 5.26e-17] + [-0.9268485643308071 +/- 2.80e-17]*I sage: CBF(1, 1).zeta(1/2) [1.497919876084167 +/- 2.91e-16] + [0.2448655353684164 +/- 4.22e-17]*I sage: CBF(1, 1).zeta(CBF(1, 1)) @@ -2529,7 +2529,7 @@ cdef class ComplexBall(RingElement): sage: CBF(2).polylog(1) [+/- 4.65e-15] + [-3.14159265358979 +/- 8.15e-15]*I sage: CBF(1, 1).polylog(CBF(1, 1)) - [0.3708160030469 +/- 2.38e-14] + [2.7238016577979 +/- 4.22e-14]*I + [0.3708160030469 +/- 2.38e-14] + [2.7238016577979 +/- 4.20e-14]*I TESTS:: @@ -2565,7 +2565,7 @@ cdef class ComplexBall(RingElement): sage: CBF(8).barnes_g() 24883200.00000000 sage: CBF(500,10).barnes_g() - [4.54078781e+254873 +/- 5.43e+254864] + [8.65835455e+254873 +/- 7.27e+254864]*I + [4.54078781e+254873 +/- 5.43e+254864] + [8.65835455e+254873 +/- 7.28e+254864]*I """ cdef ComplexBall res = self._new() if _do_sig(prec(self)): sig_on() @@ -2603,7 +2603,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(0, -1).agm1() - [0.5990701173678 +/- 1.14e-14] + [-0.5990701173678 +/- 1.22e-14]*I + [0.5990701173678 +/- 1.15e-14] + [-0.5990701173678 +/- 1.19e-14]*I """ cdef ComplexBall res = self._new() if _do_sig(prec(self)): sig_on() @@ -2654,15 +2654,15 @@ cdef class ComplexBall(RingElement): [+/- 7.72e-16] + [2.71828182845904 +/- 6.45e-15]*I sage: CBF(1, pi).hypergeometric([1/4], [1/4]) - [-2.7182818284590 +/- 8.63e-14] + [+/- 3.69e-14]*I + [-2.7182818284590 +/- 7.11e-14] + [+/- 2.25e-14]*I sage: CBF(1000, 1000).hypergeometric([10], [AA(sqrt(2))]) - [9.79300951360e+454 +/- 4.83e+442] + [5.522579106816e+455 +/- 3.39e+442]*I + [9.79300951360e+454 +/- 5.01e+442] + [5.522579106816e+455 +/- 3.56e+442]*I sage: CBF(1000, 1000).hypergeometric([100], [AA(sqrt(2))]) - [+/- 8.88e+596] + [+/- 8.88e+596]*I + [1.27967355557e+590 +/- 8.60e+578] + [-9.32333491987e+590 +/- 8.18e+578]*I sage: CBF(0, 1).hypergeometric([], [1/2, 1/3, 1/4]) - [-3.7991962344383 +/- 4.98e-14] + [23.8780971778049 +/- 5.40e-14]*I + [-3.7991962344383 +/- 8.78e-14] + [23.878097177805 +/- 3.87e-13]*I sage: CBF(0).hypergeometric([1], []) 1.000000000000000 @@ -2670,9 +2670,9 @@ cdef class ComplexBall(RingElement): 1.000000000000000*I sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2]) - [0.7871684267473 +/- 3.57e-14] + [0.2749254173721 +/- 6.45e-14]*I + [0.7871684267473 +/- 7.34e-14] + [0.2749254173721 +/- 9.23e-14]*I sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2],regularized=True) - [0.4441122268685 +/- 1.83e-14] + [0.1551100567338 +/- 4.07e-14]*I + [0.4441122268685 +/- 3.96e-14] + [0.1551100567338 +/- 5.75e-14]*I sage: CBF(5).hypergeometric([2,3], [-5]) nan + nan*I @@ -2680,7 +2680,7 @@ cdef class ComplexBall(RingElement): [5106.925964355 +/- 5.41e-10] sage: CBF(2016).hypergeometric([], [2/3]) - [2.0256426923278e+38 +/- 8.90e+24] + [2.025642692328e+38 +/- 3.00e+25] sage: CBF(-2016).hypergeometric([], [2/3], regularized=True) [-0.0005428550847 +/- 5.00e-14] @@ -2688,12 +2688,12 @@ cdef class ComplexBall(RingElement): 0.0002441406250000000 sage: CBF(0, 3).hypergeometric([CBF(1,1)], [-4], regularized=True) - [239.5140007528 +/- 5.01e-11] + [105.1751573490 +/- 2.36e-11]*I + [239.514000752841 +/- 8.03e-13] + [105.175157349015 +/- 6.28e-13]*I TESTS:: sage: CBF(0, 1).hypergeometric([QQbar(sqrt(2)), RLF(pi)], [1r, 1/2]) - [-8.7029449215408 +/- 6.89e-14] + [-0.8499070546106 +/- 4.98e-14]*I + [-8.7029449215408 +/- 6.17e-14] + [-0.8499070546106 +/- 5.21e-14]*I """ cdef ComplexBall tmp, my_a, my_b, my_c @@ -2767,7 +2767,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1000, 1000).hypergeometric_U(RLF(pi), -100) - [-7.261605907166e-11 +/- 4.89e-24] + [-7.928136216391e-11 +/- 5.36e-24]*I + [-7.261605907166e-11 +/- 5.04e-24] + [-7.928136216391e-11 +/- 5.52e-24]*I sage: CBF(1000, 1000).hypergeometric_U(0, -100) 1.000000000000000 """ @@ -2786,7 +2786,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).erf() - [1.31615128169795 +/- 8.80e-15] + [0.19045346923783 +/- 9.19e-15]*I + [1.316151281697947 +/- 7.26e-16] + [0.1904534692378347 +/- 6.03e-17]*I """ cdef ComplexBall result = self._new() @@ -2802,9 +2802,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(20).erfc() - [5.3958656116079e-176 +/- 1.08e-190] + [5.39586561160790e-176 +/- 6.73e-191] sage: CBF(100, 100).erfc() - [0.00065234366376858 +/- 6.52e-18] + [-0.00393572636292141 +/- 5.16e-18]*I + [0.00065234366376858 +/- 8.37e-18] + [-0.00393572636292141 +/- 7.21e-18]*I """ cdef ComplexBall result = self._new() if _do_sig(prec(self)): sig_on() @@ -2906,9 +2906,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).bessel_J(1) - [0.614160334922903 +/- 8.48e-16] + [0.365028028827088 +/- 6.62e-16]*I + [0.614160334922903 +/- 6.38e-16] + [0.365028028827088 +/- 3.96e-16]*I sage: CBF(100, -100).bessel_J(1/3) - [1.108431870251e+41 +/- 5.53e+28] + [-8.952577603125e+41 +/- 2.91e+28]*I + [1.108431870251e+41 +/- 5.53e+28] + [-8.952577603125e+41 +/- 2.93e+28]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -2926,9 +2926,9 @@ cdef class ComplexBall(RingElement): sage: J, Y = CBF(1, 1).bessel_J_Y(1) sage: J - CBF(1, 1).bessel_J(1) - [+/- 7.95e-16] + [+/- 6.84e-16]*I + [+/- 3.75e-16] + [+/- 2.64e-16]*I sage: Y - CBF(1, 1).bessel_Y(1) - [+/- 2.31e-14] + [+/- 2.26e-14]*I + [+/- 1.64e-14] + [+/- 1.62e-14]*I """ cdef ComplexBall result1 = self._new() @@ -2948,9 +2948,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).bessel_Y(1) - [-0.6576945355913 +/- 5.62e-14] + [0.6298010039929 +/- 2.77e-14]*I + [-0.6576945355913 +/- 5.29e-14] + [0.6298010039929 +/- 2.45e-14]*I sage: CBF(100, -100).bessel_Y(1/3) - [-8.952577603125e+41 +/- 4.65e+28] + [-1.108431870251e+41 +/- 6.29e+28]*I + [-8.952577603125e+41 +/- 4.66e+28] + [-1.108431870251e+41 +/- 6.31e+28]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -2967,9 +2967,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).bessel_I(1) - [0.365028028827088 +/- 6.62e-16] + [0.614160334922903 +/- 8.48e-16]*I + [0.365028028827088 +/- 3.96e-16] + [0.614160334922903 +/- 6.38e-16]*I sage: CBF(100, -100).bessel_I(1/3) - [5.4362189595644e+41 +/- 6.48e+27] + [7.1989436985321e+41 +/- 2.69e+27]*I + [5.4362189595644e+41 +/- 6.40e+27] + [7.1989436985321e+41 +/- 2.92e+27]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -2988,9 +2988,9 @@ cdef class ComplexBall(RingElement): sage: CBF(1, 1).bessel_K(0) [0.08019772694652 +/- 3.19e-15] + [-0.35727745928533 +/- 1.08e-15]*I sage: CBF(1, 1).bessel_K(1) - [0.02456830552374 +/- 6.22e-15] + [-0.45971947380119 +/- 6.74e-15]*I + [0.02456830552374 +/- 4.84e-15] + [-0.45971947380119 +/- 5.35e-15]*I sage: CBF(100, 100).bessel_K(QQbar(i)) - [3.8693896656383e-45 +/- 2.38e-59] + [5.5071004234177e-46 +/- 5.86e-60]*I + [3.8693896656383e-45 +/- 2.76e-59] + [5.507100423418e-46 +/- 4.01e-59]*I """ cdef ComplexBall result = self._new() cdef ComplexBall my_nu = self._parent.coerce(nu) @@ -3007,9 +3007,9 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1+i).exp_integral_e(1) - [0.00028162445198 +/- 2.78e-15] + [-0.17932453503936 +/- 2.56e-15]*I + [0.00028162445198 +/- 2.79e-15] + [-0.17932453503936 +/- 2.12e-15]*I sage: CBF(1+i).exp_integral_e(QQbar(i)) - [-0.10396361883964 +/- 4.92e-15] + [-0.16268401277783 +/- 4.78e-15]*I + [-0.10396361883964 +/- 3.78e-15] + [-0.16268401277783 +/- 3.69e-15]*I """ cdef ComplexBall res = self._new() cdef ComplexBall my_s = self._parent.coerce(s) @@ -3025,7 +3025,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).ei() - [1.76462598556385 +/- 6.65e-15] + [2.38776985151052 +/- 4.34e-15]*I + [1.76462598556385 +/- 5.82e-15] + [2.38776985151052 +/- 4.29e-15]*I sage: CBF(0).ei() nan """ @@ -3042,7 +3042,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).si() - [1.10422265823558 +/- 2.16e-15] + [0.88245380500792 +/- 3.15e-15]*I + [1.10422265823558 +/- 2.48e-15] + [0.88245380500792 +/- 3.36e-15]*I sage: CBF(0).si() 0 """ @@ -3059,7 +3059,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).ci() - [0.882172180555936 +/- 4.85e-16] + [0.287249133519956 +/- 3.47e-16]*I + [0.882172180555936 +/- 4.85e-16] + [0.287249133519956 +/- 3.92e-16]*I sage: CBF(0).ci() nan + nan*I """ @@ -3076,7 +3076,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).shi() - [0.88245380500792 +/- 3.15e-15] + [1.10422265823558 +/- 2.16e-15]*I + [0.88245380500792 +/- 3.36e-15] + [1.10422265823558 +/- 2.48e-15]*I sage: CBF(0).shi() 0 """ @@ -3094,7 +3094,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).chi() - [0.882172180555936 +/- 4.85e-16] + [1.28354719327494 +/- 1.05e-15]*I + [0.882172180555936 +/- 4.85e-16] + [1.28354719327494 +/- 1.07e-15]*I sage: CBF(0).chi() nan + nan*I """ @@ -3113,7 +3113,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1, 1).li() - [0.61391166922119 +/- 7.03e-15] + [2.05958421419258 +/- 8.25e-15]*I + [0.61391166922120 +/- 6.40e-15] + [2.05958421419258 +/- 5.61e-15]*I sage: CBF(0).li() 0 sage: CBF(0).li(offset=True) @@ -3159,10 +3159,7 @@ cdef class ComplexBall(RingElement): [0.969386075665498 +/- 4.65e-16] + [-0.030613917822067 +/- 1.89e-16]*I) sage: CBF(3,-1/2).jacobi_theta(CBF(1/4,-2)) - ([+/- inf] + [+/- inf]*I, - [+/- inf] + [+/- inf]*I, - [+/- inf] + [+/- inf]*I, - [+/- inf] + [+/- inf]*I) + (nan + nan*I, nan + nan*I, nan + nan*I, nan + nan*I) sage: CBF(0).jacobi_theta(CBF(0,1)) (0, @@ -3225,11 +3222,11 @@ cdef class ComplexBall(RingElement): sage: tau = CBF(sqrt(2),pi) sage: tau.modular_lambda() - [-0.00022005123884157 +/- 6.64e-18] + [-0.0007978734645994 +/- 5.23e-17]*I + [-0.00022005123884157 +/- 6.41e-18] + [-0.0007978734645994 +/- 5.15e-17]*I sage: (tau + 2).modular_lambda() - [-0.00022005123884157 +/- 6.64e-18] + [-0.0007978734645994 +/- 5.23e-17]*I + [-0.00022005123884157 +/- 6.41e-18] + [-0.0007978734645994 +/- 5.15e-17]*I sage: (tau / (1 - 2*tau)).modular_lambda() - [-0.00022005123884 +/- 2.75e-15] + [-0.00079787346460 +/- 3.34e-15]*I + [-0.00022005123884 +/- 2.53e-15] + [-0.00079787346460 +/- 2.85e-15]*I """ cdef ComplexBall result = self._new() @@ -3249,7 +3246,7 @@ cdef class ComplexBall(RingElement): sage: a, b, c, d = 2, 5, 1, 3 sage: tau = CBF(1,3) sage: ((a*tau+b)/(c*tau+d)).modular_delta() - [0.20921376655 +/- 6.94e-12] + [1.5761192552 +/- 3.49e-11]*I + [0.20921376655 +/- 6.94e-12] + [1.5761192552 +/- 3.47e-11]*I sage: (c*tau+d)^12 * tau.modular_delta() [0.20921376654986 +/- 4.89e-15] + [1.5761192552253 +/- 4.45e-14]*I @@ -3276,7 +3273,7 @@ cdef class ComplexBall(RingElement): [2.0081609898081 +/- 3.67e-14], [2.0019857082706 +/- 4.60e-14]] sage: ((a*tau+b)/(c*tau+d)).eisenstein(3)[2] - [331011.200433 +/- 1.36e-7] + [-711178.165575 +/- 5.18e-7]*I + [331011.2004330 +/- 9.33e-8] + [-711178.1655746 +/- 7.51e-8]*I sage: (c*tau+d)^8 * tau.eisenstein(3)[2] [331011.20043304 +/- 7.62e-9] + [-711178.1655746 +/- 1.34e-8]*I @@ -3310,20 +3307,20 @@ cdef class ComplexBall(RingElement): sage: tau = CBF(1,4) sage: z = CBF(sqrt(2), sqrt(3)) sage: z.elliptic_p(tau) - [-3.28920996772709 +/- 7.68e-15] + [-0.000367376730293 +/- 3.58e-16]*I + [-3.28920996772709 +/- 7.63e-15] + [-0.0003673767302933 +/- 6.04e-17]*I sage: (z + tau).elliptic_p(tau) - [-3.28920996772709 +/- 8.87e-15] + [-0.00036737673029 +/- 4.37e-15]*I + [-3.28920996772709 +/- 7.97e-15] + [-0.000367376730293 +/- 6.51e-16]*I sage: (z + 1).elliptic_p(tau) - [-3.28920996772709 +/- 7.68e-15] + [-0.000367376730293 +/- 3.58e-16]*I + [-3.28920996772709 +/- 7.63e-15] + [-0.0003673767302933 +/- 6.04e-17]*I sage: z.elliptic_p(tau, 3) - [[-3.28920996772709 +/- 7.66e-15] + [-0.000367376730293 +/- 3.45e-16]*I, - [0.00247305579431 +/- 2.06e-15] + [0.00385955404027 +/- 4.07e-15]*I, - [-0.0129908756171 +/- 2.12e-14] + [0.0072502752191 +/- 6.05e-14]*I] + [[-3.28920996772709 +/- 7.62e-15] + [-0.0003673767302933 +/- 5.40e-17]*I, + [0.002473055794309 +/- 5.01e-16] + [0.003859554040267 +/- 4.45e-16]*I, + [-0.01299087561709 +/- 4.72e-15] + [0.00725027521915 +/- 4.32e-15]*I] sage: (z + 3 + 4*tau).elliptic_p(tau, 3) - [[-3.2892099677271 +/- 3.40e-14] + [-0.0003673767303 +/- 2.49e-14]*I, - [0.00247305579 +/- 6.04e-12] + [0.00385955404 +/- 1.86e-12]*I, - [-0.012990876 +/- 4.77e-10] + [0.007250275 +/- 3.20e-10]*I] + [[-3.2892099677271 +/- 2.29e-14] + [-0.00036737673029 +/- 8.58e-15]*I, + [0.002473055794 +/- 6.59e-13] + [0.003859554040 +/- 6.17e-13]*I, + [-0.0129908756 +/- 3.39e-11] + [0.0072502752 +/- 3.60e-11]*I] """ cdef ComplexBall my_tau = self._parent.coerce(tau) @@ -3359,7 +3356,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(2,3).elliptic_k() - [1.0429132919285 +/- 5.77e-14] + [0.6296824723086 +/- 7.16e-14]*I + [1.0429132919285 +/- 3.65e-14] + [0.6296824723086 +/- 6.15e-14]*I """ cdef ComplexBall result = self._new() @@ -3376,7 +3373,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(2,3).elliptic_e() - [1.472797144959 +/- 5.13e-13] + [-1.231604783936 +/- 1.61e-13]*I + [1.472797144959 +/- 4.82e-13] + [-1.231604783936 +/- 1.25e-13]*I """ cdef ComplexBall result = self._new() @@ -3433,7 +3430,7 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(5,-6).jacobi_P(8, CBF(1,2), CBF(2,3)) - [-920983000.460 +/- 7.60e-4] + [6069919969.93 +/- 2.03e-3]*I + [-920983000.45982 +/- 2.22e-6] + [6069919969.92857 +/- 4.77e-6]*I """ cdef ComplexBall my_n = self._parent.coerce(n) @@ -3478,7 +3475,7 @@ cdef class ComplexBall(RingElement): sage: CBF(10).laguerre_L(3, 2) [-6.666666666667 +/- 4.15e-13] sage: CBF(5,7).laguerre_L(CBF(2,3), CBF(1,-2)) - [5515.31503027 +/- 7.93e-9] + [-12386.94284527 +/- 8.00e-9]*I + [5515.315030271 +/- 4.37e-10] + [-12386.942845271 +/- 5.47e-10]*I """ cdef ComplexBall my_n = self._parent.coerce(n) @@ -3500,7 +3497,7 @@ cdef class ComplexBall(RingElement): sage: CBF(10).hermite_H(1) 20.00000000000000 sage: CBF(10).hermite_H(30) - [8.05746709617e+37 +/- 1.32e+25] + [8.0574670961707e+37 +/- 3.28e+23] """ cdef ComplexBall my_n = self._parent.coerce(n) @@ -3525,7 +3522,7 @@ cdef class ComplexBall(RingElement): sage: CBF(1/2).legendre_P(5) 0.08984375000000000 sage: CBF(1,2).legendre_P(CBF(2,3), CBF(0,1)) - [0.10996180744 +/- 4.71e-12] + [0.14312767804 +/- 1.62e-12]*I + [0.10996180744364 +/- 7.45e-15] + [0.14312767804055 +/- 8.38e-15]*I sage: CBF(-10).legendre_P(5, 325/100) [-22104403.487377 +/- 6.81e-7] + [53364750.687392 +/- 7.25e-7]*I sage: CBF(-10).legendre_P(5, 325/100, type=3) @@ -3557,13 +3554,13 @@ cdef class ComplexBall(RingElement): EXAMPLES:: sage: CBF(1/2).legendre_Q(5) - [0.55508089057168 +/- 5.32e-15] + [0.55508089057168 +/- 2.79e-15] sage: CBF(1,2).legendre_Q(CBF(2,3), CBF(0,1)) - [0.167678710 +/- 5.89e-10] + [-0.161558598 +/- 8.76e-10]*I + [0.167678710 +/- 4.60e-10] + [-0.161558598 +/- 7.47e-10]*I sage: CBF(-10).legendre_Q(5, 325/100) - [-83825154.36008 +/- 4.95e-6] + [-34721515.80396 +/- 5.40e-6]*I + [-83825154.36008 +/- 4.94e-6] + [-34721515.80396 +/- 5.40e-6]*I sage: CBF(-10).legendre_Q(5, 325/100, type=3) - [-4.797306921692e-6 +/- 6.92e-19] + [-4.797306921692e-6 +/- 6.68e-19]*I + [-4.797306921692e-6 +/- 6.82e-19] + [-4.797306921692e-6 +/- 6.57e-19]*I """ cdef ComplexBall my_n = self._parent.coerce(n) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index d9e5af767d3..c52a86b5805 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -397,6 +397,20 @@ def __eq__(self, other): return False return self._prec == other._prec + def __hash__(self): + """ + Return the hash. + + EXAMPLES:: + + sage: C = ComplexIntervalField(200) + sage: from sage.rings.complex_interval_field import ComplexIntervalField_class + sage: D = ComplexIntervalField_class(200) + sage: hash(C) == hash(D) + True + """ + return hash((self.__class__, self._prec)) + def __ne__(self, other): """ Test whether ``self`` is not equal to ``other``. diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index a8bf8fac72d..693fc139735 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -22,6 +22,7 @@ from __future__ import absolute_import from cysignals.memory cimport check_malloc, sig_free from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr include "sage/libs/ntl/decl.pxi" from cypari2.paridecl cimport * @@ -179,7 +180,7 @@ cdef class Cache_ntl_gf2e(SageObject): GF2E_conv_long((self._one_element).x,1) if k > 1: self._gen = self._new() - GF2E_from_str(&self._gen.x, "[0 1]") + ccreadstr(self._gen.x, b"[0 1]") elif modulus[0]: self._gen = self._one_element else: @@ -221,7 +222,7 @@ cdef class Cache_ntl_gf2e(SageObject): # Print the current modulus. cdef GF2XModulus_c modulus = GF2E_modulus() cdef GF2X_c mod_poly = GF2XModulus_GF2X(modulus) - print(GF2X_to_PyString(&mod_poly)) + print(ccrepr(mod_poly)) # do another garbage collection gc.collect() @@ -229,7 +230,7 @@ cdef class Cache_ntl_gf2e(SageObject): # and print the modulus again modulus = GF2E_modulus() mod_poly = GF2XModulus_GF2X(modulus) - print(GF2X_to_PyString(&mod_poly)) + print(ccrepr(mod_poly)) cdef FiniteField_ntl_gf2eElement _new(self): """ diff --git a/src/sage/rings/finite_rings/stdint.h b/src/sage/rings/finite_rings/integer_mod_limits.h similarity index 66% rename from src/sage/rings/finite_rings/stdint.h rename to src/sage/rings/finite_rings/integer_mod_limits.h index d54ad4c1799..5c635b65838 100644 --- a/src/sage/rings/finite_rings/stdint.h +++ b/src/sage/rings/finite_rings/integer_mod_limits.h @@ -1,6 +1,9 @@ +#ifndef _SAGE_FINITE_RINGS_INTEGER_MOD_LIMITS_H +#define _SAGE_FINITE_RINGS_INTEGER_MOD_LIMITS_H #include #define INTEGER_MOD_INT32_LIMIT 46341 // = ceil(sqrt(2^31-1)) #define INTEGER_MOD_INT64_LIMIT 2147483647 // = 2^31-1 for now, should be 3037000500LL = ceil(sqrt(2^63-1)) +#endif diff --git a/src/sage/rings/finite_rings/stdint.pxd b/src/sage/rings/finite_rings/stdint.pxd index 52e07fc1911..b2b96a90c39 100644 --- a/src/sage/rings/finite_rings/stdint.pxd +++ b/src/sage/rings/finite_rings/stdint.pxd @@ -11,11 +11,9 @@ C Integer Types Used in Finite Rings # http://www.gnu.org/licenses/ #***************************************************************************** -cimport libc.stdint +from libc.stdint cimport int_fast32_t, int_fast64_t -cdef extern from "sage/rings/finite_rings/stdint.h": - ctypedef libc.stdint.int_fast32_t int_fast32_t - ctypedef libc.stdint.int_fast64_t int_fast64_t +cdef extern from "integer_mod_limits.h": int_fast32_t INTEGER_MOD_INT32_LIMIT int_fast64_t INTEGER_MOD_INT64_LIMIT diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index adc290c744e..37ceab27f80 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -853,6 +853,25 @@ def class_number(self): """ return 1 + def _factor_univariate_polynomial(self, f): + r""" + Return the factorization of ``f`` over this field. + + EXAMPLES:: + + sage: k. = GF(9) + sage: K = k['t'].fraction_field() + sage: R. = K[] + sage: f = x^3 + a + sage: f.factor() + (x + 2*a + 1)^3 + + """ + # The default implementation would try to convert this element to singular and factor there. + # This fails silently over some base fields, see #23642, so we convert + # to the function field and factor there. + return f.change_ring(self.function_field()).factor().base_change(f.parent()) + def function_field(self): r""" Return the isomorphic function field. diff --git a/src/sage/rings/function_field/function_field_ideal.py b/src/sage/rings/function_field/function_field_ideal.py index eb477ac222b..f24a25986b5 100644 --- a/src/sage/rings/function_field/function_field_ideal.py +++ b/src/sage/rings/function_field/function_field_ideal.py @@ -50,6 +50,8 @@ #***************************************************************************** from sage.rings.ideal import Ideal_generic +from sage.structure.richcmp import richcmp + class FunctionFieldIdeal(Ideal_generic): """ @@ -203,7 +205,7 @@ def intersection(self, other): raise ValueError("rings must be the same") return FunctionFieldIdeal_module(self.ring(), self.module().intersection(other.module())) - def __cmp__(self, other): + def __richcmp__(self, other, op): """ Compare self and ``other``. @@ -226,7 +228,7 @@ def __cmp__(self, other): other = self.ring().ideal(other) if self.ring() != other.ring(): raise ValueError("rings must be the same") - return cmp(self.module(), other.module()) + return richcmp(self.module(), other.module(), op) def __invert__(self): """ diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index fd29a61c027..447c3bdcb1b 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -691,6 +691,28 @@ cdef class LaurentSeries(AlgebraElement): u = self.__u.add_bigoh(prec - self.__n) return type(self)(P, u, self.__n) + def O(self, prec): + r""" + Return the Laurent series of precision at most ``prec`` obtained by + adding `O(q^\text{prec})`, where `q` is the variable. + + The precision of ``self`` and the integer ``prec`` can be arbitrary. The + resulting Laurent series will have precision equal to the minimum of + the precision of ``self`` and ``prec``. The term `O(q^\text{prec})` is the + zero series with precision ``prec``. + + EXAMPLES:: + + sage: R. = LaurentSeriesRing(QQ) + sage: f = t^-5 + t^-4 + t^3 + O(t^10); f + t^-5 + t^-4 + t^3 + O(t^10) + sage: f.O(-4) + t^-5 + O(t^-4) + sage: f.O(15) + t^-5 + t^-4 + t^3 + O(t^10) + """ + return self.add_bigoh(prec) + def degree(self): """ Return the degree of a polynomial equivalent to this power series @@ -978,7 +1000,7 @@ cdef class LaurentSeries(AlgebraElement): cpdef _richcmp_(self, right_r, int op): r""" - Comparison of self and right. + Comparison of ``self`` and ``right``. We say two approximate Laurent series are equal, if they agree for all coefficients up to the *minimum* of the precisions of each. @@ -987,7 +1009,7 @@ cdef class LaurentSeries(AlgebraElement): but consistent with the idea that the variable of a Laurent series is considered to be "very small". - See power_series_ring_element.__cmp__() for more + See :meth:`power_series_ring_element._richcmp_` for more information. EXAMPLES:: diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index c1aee75e608..70fdaea0351 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -3775,7 +3775,7 @@ def pari_nf(self, important=True): sage: k. = NumberField(x^4 - 3/2*x + 5/3); k Number Field in a with defining polynomial x^4 - 3/2*x + 5/3 sage: k.pari_nf() - [y^4 - 324*y + 2160, [0, 2], 48918708, 216, ..., [1, y, 1/36*y^3 + 1/6*y^2 - 7, 1/6*y^2], [1, 0, 0, 252; 0, 1, 0, 0; 0, 0, 0, 36; 0, 0, 6, -36], [1, 0, 0, 0, 0, 0, -18, 42, 0, -18, -46, -60, 0, 42, -60, -60; 0, 1, 0, 0, 1, 0, 2, 0, 0, 2, -11, -1, 0, 0, -1, 9; 0, 0, 1, 0, 0, 0, 6, 6, 1, 6, -5, 0, 0, 6, 0, 0; 0, 0, 0, 1, 0, 6, -6, -6, 0, -6, -1, 2, 1, -6, 2, 0]] + [y^4 - 324*y + 2160, [0, 2], 48918708, 216, ..., [36, 36*y, y^3 + 6*y^2 - 252, 6*y^2], [1, 0, 0, 252; 0, 1, 0, 0; 0, 0, 0, 36; 0, 0, 6, -36], [1, 0, 0, 0, 0, 0, -18, 42, 0, -18, -46, -60, 0, 42, -60, -60; 0, 1, 0, 0, 1, 0, 2, 0, 0, 2, -11, -1, 0, 0, -1, 9; 0, 0, 1, 0, 0, 0, 6, 6, 1, 6, -5, 0, 0, 6, 0, 0; 0, 0, 0, 1, 0, 6, -6, -6, 0, -6, -1, 2, 1, -6, 2, 0]] sage: pari(k) [y^4 - 324*y + 2160, [0, 2], 48918708, 216, ...] sage: gp(k) @@ -7356,7 +7356,7 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): Number Field in b with defining polynomial x^8 + 40*x^6 + 352*x^4 + 960*x^2 + 576 sage: L = K.optimized_subfields(name='b') sage: L[0][0] - Number Field in b0 with defining polynomial x - 1 + Number Field in b0 with defining polynomial x sage: L[1][0] Number Field in b1 with defining polynomial x^2 - 3*x + 3 sage: [z[0] for z in L] # random -- since algorithm is random @@ -7400,10 +7400,10 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): sage: K. = NumberField(2*x^4 + 6*x^2 + 1/2) sage: K.optimized_subfields() [ - (Number Field in a0 with defining polynomial x - 1, Ring morphism: - From: Number Field in a0 with defining polynomial x - 1 + (Number Field in a0 with defining polynomial x, Ring morphism: + From: Number Field in a0 with defining polynomial x To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: 1 |--> 1, None), + Defn: 0 |--> 0, None), (Number Field in a1 with defining polynomial x^2 - 2*x + 2, Ring morphism: From: Number Field in a1 with defining polynomial x^2 - 2*x + 2 To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 099203edba3..5b30b21869a 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -2726,7 +2726,7 @@ def element_1_mod(self, other): Fractional ideal (a^2 - 4*a + 2) 68 sage: r = A.element_1_mod(B); r - -a^2 + 4*a - 1 + -33 sage: r in A True sage: 1-r in B diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index 3e5069b168b..df69957c9fe 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -1561,7 +1561,7 @@ def _pari_relative_structure(self): sage: L._pari_relative_structure() (x^2 + Mod(-y, y^2 + 1), Mod(Mod(1/2*y - 1/2, y^2 + 1)*x, x^2 + Mod(-y, y^2 + 1)), - Mod(Mod(-y - 1, y^2 + 1)*x, x^2 + Mod(-1/2, y^2 + 1))) + Mod(Mod(-y - 1, y^2 + 1)*x, Mod(1, y^2 + 1)*x^2 + Mod(-1/2, y^2 + 1))) An example where both fields are defined by non-integral or non-monic polynomials:: @@ -1571,7 +1571,7 @@ def _pari_relative_structure(self): sage: L._pari_relative_structure() (x^2 + Mod(y, y^2 + 2)*x + 1, Mod(Mod(-1/3*y, y^2 + 2)*x + Mod(1/3, y^2 + 2), x^2 + Mod(y, y^2 + 2)*x + 1), - Mod(Mod(3/2*y, y^2 + 2)*x + Mod(-1/2*y, y^2 + 2), x^2 + Mod(-1/3, y^2 + 2))) + Mod(Mod(3/2*y, y^2 + 2)*x + Mod(-1/2*y, y^2 + 2), Mod(1, y^2 + 2)*x^2 + Mod(-1/3, y^2 + 2))) Note that in the last example, the *absolute* defining polynomials is the same for Sage and PARI, even though this is diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index 69b527bf80b..616a0d639ca 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -100,29 +100,29 @@ sage: UL.zeta_order() 24 sage: UL.roots_of_unity() - [b*a + b, - b^2*a, - -b^3, + [-b^3*a - b^3, + -b^2*a, + b, a + 1, - b*a, - -b^2, - -b^3*a - b^3, - a, - -b, - -b^2*a - b^2, -b^3*a, - -1, - -b*a - b, - -b^2*a, - b^3, - -a - 1, - -b*a, b^2, - b^3*a + b^3, - -a, - b, + b*a + b, + a, + b^3, b^2*a + b^2, + b*a, + -1, + b^3*a + b^3, + b^2*a, + -b, + -a - 1, b^3*a, + -b^2, + -b*a - b, + -a, + -b^3, + -b^2*a - b^2, + -b*a, 1] A relative extension example, which worked thanks to the code review by F.W.Clarke:: diff --git a/src/sage/rings/padics/CA_template.pxi b/src/sage/rings/padics/CA_template.pxi index b5fc4a20556..1108e03fcff 100644 --- a/src/sage/rings/padics/CA_template.pxi +++ b/src/sage/rings/padics/CA_template.pxi @@ -1301,6 +1301,7 @@ cdef class pAdicCoercion_CA_frac_field(RingHomomorphism): TESTS:: sage: TestSuite(f).run() + """ def __init__(self, R, K): """ diff --git a/src/sage/rings/padics/CR_template.pxi b/src/sage/rings/padics/CR_template.pxi index c8fd1c30884..5c7256a57d7 100644 --- a/src/sage/rings/padics/CR_template.pxi +++ b/src/sage/rings/padics/CR_template.pxi @@ -2059,6 +2059,7 @@ cdef class pAdicCoercion_CR_frac_field(RingHomomorphism): TESTS:: sage: TestSuite(f).run() + """ def __init__(self, R, K): """ diff --git a/src/sage/rings/padics/FM_template.pxi b/src/sage/rings/padics/FM_template.pxi index 3b81cfc746b..ab50aa3472e 100644 --- a/src/sage/rings/padics/FM_template.pxi +++ b/src/sage/rings/padics/FM_template.pxi @@ -437,9 +437,7 @@ cdef class FMElement(pAdicTemplateElement): sage: a.add_bigoh(2^1000) 7 + O(7^4) sage: a.add_bigoh(-2^1000) - Traceback (most recent call last): - ... - ValueError: absprec must be at least 0 + 0 """ cdef long aprec @@ -451,14 +449,14 @@ cdef class FMElement(pAdicTemplateElement): if not isinstance(absprec, Integer): absprec = Integer(absprec) if mpz_sgn((absprec).value) == -1: - aprec = -1 + return self.parent().fraction_field()(0) elif mpz_fits_slong_p((absprec).value) == 0: - aprec = self.prime_pow.ram_prec_cap + return self else: aprec = mpz_get_si((absprec).value) if aprec < 0: - raise ValueError("absprec must be at least 0") - if aprec >= self.prime_pow.prec_cap: + return self.parent().fraction_field()(self, absprec) + elif aprec >= self.prime_pow.prec_cap: return self cdef FMElement ans = self._new_c() creduce(ans.value, self.value, aprec, ans.prime_pow) @@ -1106,9 +1104,361 @@ cdef class pAdicConvert_QQ_FM(Morphism): cconv_mpq_t(ans.value, (x).value, ans.prime_pow.prec_cap, True, ans.prime_pow) return ans +cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): + """ + The canonical inclusion of Zq into its fraction field. + + EXAMPLES:: + + sage: R. = ZqFM(27, implementation='FLINT') + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R); f + Ring morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + To: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + + TESTS:: + + sage: TestSuite(f).run() + + """ + def __init__(self, R, K): + """ + Initialization. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R); type(f) + + """ + RingHomomorphism.__init__(self, R.Hom(K)) + self._zero = K(0) + self._section = pAdicConvert_FM_frac_field(K, R) + + cpdef Element _call_(self, _x): + """ + Evaluation. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f(a) + a + """ + cdef FMElement x = _x + if ciszero(x.value, x.prime_pow): + return self._zero + cdef FPElement ans = self._zero._new_c() + ans.ordp = cremove(ans.unit, x.value, x.prime_pow.ram_prec_cap, x.prime_pow) + return ans + + cpdef Element _call_with_args(self, _x, args=(), kwds={}): + """ + This function is used when some precision cap is passed in + (relative or absolute or both). + + See the documentation for + :meth:`pAdicCappedAbsoluteElement.__init__` for more details. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f(a, 3) + a + sage: b = 117*a + sage: f(b, 3) + a*3^2 + sage: f(b, 4, 1) + a*3^2 + sage: f(b, 4, 3) + a*3^2 + a*3^3 + sage: f(b, absprec=4) + a*3^2 + a*3^3 + sage: f(b, relprec=3) + a*3^2 + a*3^3 + a*3^4 + sage: f(b, absprec=1) + 0 + sage: f(R(0)) + 0 + """ + cdef long aprec, rprec + cdef FMElement x = _x + if ciszero(x.value, x.prime_pow): + return self._zero + cdef FPElement ans = self._zero._new_c() + cdef bint reduce = False + _process_args_and_kwds(&aprec, &rprec, args, kwds, False, x.prime_pow) + ans.ordp = cremove(ans.unit, x.value, aprec, x.prime_pow) + if aprec < ans.ordp + rprec: + rprec = aprec - ans.ordp + if rprec <= 0: + return self._zero + creduce(ans.unit, ans.unit, rprec, x.prime_pow) + return ans + + def section(self): + """ + Returns a map back to the ring that converts elements of + non-negative valuation. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f.section()(K.gen()) + a + O(3^20) + """ + from sage.misc.constant_function import ConstantFunction + if not isinstance(self._section.domain, ConstantFunction): + import copy + self._section = copy.copy(self._section) + return self._section + + cdef dict _extra_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: g = copy(f) # indirect doctest + sage: g + Ring morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + To: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + sage: g == f + True + sage: g is f + False + sage: g(a) + a + sage: g(a) == f(a) + True + + """ + _slots['_zero'] = self._zero + _slots['_section'] = self.section() # use method since it copies coercion-internal sections. + return RingHomomorphism._extra_slots(self, _slots) + + cdef _update_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: g = copy(f) # indirect doctest + sage: g + Ring morphism: + From: Unramified Extension in a defined by x^2 + 2*x + 2 of fixed modulus 3^20 over 3-adic Ring + To: Unramified Extension in a defined by x^2 + 2*x + 2 with floating precision 20 over 3-adic Field + sage: g == f + True + sage: g is f + False + sage: g(a) + a + sage: g(a) == f(a) + True + + """ + self._zero = _slots['_zero'] + self._section = _slots['_section'] + RingHomomorphism._update_slots(self, _slots) + + def is_injective(self): + r""" + Return whether this map is injective. + + EXAMPLES:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f.is_injective() + True + + """ + return True + + def is_surjective(self): + r""" + Return whether this map is surjective. + + EXAMPLES:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = K.coerce_map_from(R) + sage: f.is_surjective() + False + + """ + return False + + +cdef class pAdicConvert_FM_frac_field(Morphism): + """ + The section of the inclusion from `\ZZ_q`` to its fraction field. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K); f + Generic morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + To: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + """ + def __init__(self, K, R): + """ + Initialization. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K); type(f) + + """ + Morphism.__init__(self, Hom(K, R, SetsWithPartialMaps())) + self._zero = R(0) + + cpdef Element _call_(self, _x): + """ + Evaluation. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K) + sage: f(K.gen()) + a + O(3^20) + """ + cdef FPElement x = _x + if x.ordp < 0: raise ValueError("negative valuation") + if x.ordp >= self._zero.prime_pow.ram_prec_cap: + return self._zero + cdef FMElement ans = self._zero._new_c() + cshift(ans.value, x.unit, x.ordp, ans.prime_pow.ram_prec_cap, ans.prime_pow, x.ordp > 0) + return ans + + cpdef Element _call_with_args(self, _x, args=(), kwds={}): + """ + This function is used when some precision cap is passed in + (relative or absolute or both). + + See the documentation for + :meth:`pAdicCappedAbsoluteElement.__init__` for more details. + + EXAMPLES:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K); a = K(a) + sage: f(a, 3) + a + O(3^20) + sage: b = 117*a + sage: f(b, 3) + a*3^2 + O(3^20) + sage: f(b, 4, 1) + a*3^2 + O(3^20) + sage: f(b, 4, 3) + a*3^2 + a*3^3 + O(3^20) + sage: f(b, absprec=4) + a*3^2 + a*3^3 + O(3^20) + sage: f(b, relprec=3) + a*3^2 + a*3^3 + a*3^4 + O(3^20) + sage: f(b, absprec=1) + O(3^20) + sage: f(K(0)) + O(3^20) + """ + cdef long aprec, rprec + cdef FPElement x = _x + if x.ordp < 0: raise ValueError("negative valuation") + if x.ordp >= self._zero.prime_pow.ram_prec_cap: + return self._zero + cdef FMElement ans = self._zero._new_c() + _process_args_and_kwds(&aprec, &rprec, args, kwds, True, ans.prime_pow) + if rprec < aprec - x.ordp: + aprec = x.ordp + rprec + sig_on() + cshift(ans.value, x.unit, x.ordp, aprec, ans.prime_pow, x.ordp > 0) + sig_off() + return ans + + cdef dict _extra_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(27) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K) + sage: a = K(a) + sage: g = copy(f) # indirect doctest + sage: g + Generic morphism: + From: Unramified Extension in a defined by x^3 + 2*x + 1 with floating precision 20 over 3-adic Field + To: Unramified Extension in a defined by x^3 + 2*x + 1 of fixed modulus 3^20 over 3-adic Ring + sage: g == f + True + sage: g is f + False + sage: g(a) + a + O(3^20) + sage: g(a) == f(a) + True + + """ + _slots['_zero'] = self._zero + return Morphism._extra_slots(self, _slots) + + cdef _update_slots(self, dict _slots): + """ + Helper for copying and pickling. + + TESTS:: + + sage: R. = ZqFM(9) + sage: K = R.fraction_field() + sage: f = R.convert_map_from(K) + sage: a = f(a) + sage: g = copy(f) # indirect doctest + sage: g + Generic morphism: + From: Unramified Extension in a defined by x^2 + 2*x + 2 with floating precision 20 over 3-adic Field + To: Unramified Extension in a defined by x^2 + 2*x + 2 of fixed modulus 3^20 over 3-adic Ring + sage: g == f + True + sage: g is f + False + sage: g(a) + a + O(3^20) + sage: g(a) == f(a) + True + + """ + self._zero = _slots['_zero'] + Morphism._update_slots(self, _slots) + def unpickle_fme_v2(cls, parent, value): """ - Unpickles a capped relative element. + Unpickles a fixed-mod element. EXAMPLES:: diff --git a/src/sage/rings/padics/FM_template_header.pxi b/src/sage/rings/padics/FM_template_header.pxi index a2439686a86..bd651167622 100644 --- a/src/sage/rings/padics/FM_template_header.pxi +++ b/src/sage/rings/padics/FM_template_header.pxi @@ -41,3 +41,9 @@ cdef class pAdicConvert_FM_ZZ(RingMap): cdef class pAdicConvert_QQ_FM(Morphism): cdef FMElement _zero cdef RingMap _section +# There should also be a pAdicConvert_CA_QQ for extension rings.... +cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): + cdef FPElement _zero + cdef Morphism _section +cdef class pAdicConvert_FM_frac_field(Morphism): + cdef FMElement _zero diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi index fb05e02cc05..75eb345a6cc 100644 --- a/src/sage/rings/padics/FP_template.pxi +++ b/src/sage/rings/padics/FP_template.pxi @@ -97,15 +97,13 @@ cdef class FPElement(pAdicTemplateElement): - ``x`` -- data defining a `p`-adic element: int, long, Integer, Rational, other `p`-adic element... - - ``val`` -- the valuation of the resulting element (unused; - for compatibility with other `p`-adic precision modes) + - ``val`` -- the valuation of the resulting element - - ``xprec -- an inherent precision of ``x`` (unused; for - compatibility with other `p`-adic precision modes) + - ``xprec -- an inherent precision of ``x``, if ``val`` + is larger then the result will be zero. - - ``absprec`` -- an absolute precision cap for this element - (unused; for compatibility with other `p`-adic precision - modes) + - ``absprec`` -- an absolute precision cap for this element, + if ``val`` is larger then the result will be zero. - ``relprec`` -- a relative precision cap for this element (unused; for compatibility with other `p`-adic precision @@ -126,9 +124,16 @@ cdef class FPElement(pAdicTemplateElement): True sage: R(5) - R(5) 0 + + We check that :trac:`23966` is resolved:: + + sage: R = ZpFM(2) + sage: K = R.fraction_field() + sage: K(R.zero()) + 0 """ cconstruct(self.unit, self.prime_pow) - if very_pos_val(val): + if val >= xprec or val >= absprec: self._set_exact_zero() elif very_neg_val(val): self._set_infinity() @@ -1694,6 +1699,7 @@ cdef class pAdicCoercion_FP_frac_field(RingHomomorphism): TESTS:: sage: TestSuite(f).run() + """ def __init__(self, R, K): r""" diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index a6674cb2e27..40a85b49979 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -365,6 +365,13 @@ def get_unramified_modulus(q, res_name): (functor_dict['print_mode'].get('mode') == 'digits' and p > getattr(functor, "p", p))): from .padic_printing import _printer_defaults kwds['alphabet'] = _printer_defaults.alphabet()[:p] + # For fraction fields of fixed-mod rings, we need to explicitly set show_prec = False + if 'field' in kwds and 'type' not in kwds: + if self._prec_type() == 'capped-abs': + kwds['type'] = 'capped-rel' + elif self._prec_type() == 'fixed-mod': + kwds['type'] = 'floating-point' + kwds['show_prec'] = False # This can be removed once printing of fixed mod elements is changed. # There are two kinds of functors possible: # CompletionFunctor and AlgebraicExtensionFunctor @@ -378,11 +385,6 @@ def get_unramified_modulus(q, res_name): field = kwds.pop('field') if field: ring = ring.fraction_field() - if 'type' not in kwds: - if self._prec_type() == 'capped-abs': - kwds['type'] = 'capped-rel' - elif self._prec_type() == 'fixed-mod': - raise TypeError('You must specify the type explicitly') elif ring.is_field(): ring = ring.ring_of_integers() for atr in ('p', 'prec', 'type'): @@ -866,14 +868,10 @@ def _test_add_bigoh(self, **options): raise NotImplementedError # if absprec < 0, then the result is in the fraction field (see #13591) - try: - y = x.add_bigoh(-1) - except ValueError: - tester.assertTrue(self.is_fixed_mod()) - else: - tester.assertIs(y.parent(), self.fraction_field()) - if not self.is_floating_point(): - tester.assertLessEqual(y.precision_absolute(), -1) + y = x.add_bigoh(-1) + tester.assertIs(y.parent(), self.fraction_field()) + if not self.is_floating_point() and not self.is_fixed_mod(): + tester.assertLessEqual(y.precision_absolute(), -1) # make sure that we handle very large values correctly absprec = Integer(2)**1000 diff --git a/src/sage/rings/padics/local_generic_element.pyx b/src/sage/rings/padics/local_generic_element.pyx index 0edaa2e4a1b..50944831fdd 100644 --- a/src/sage/rings/padics/local_generic_element.pyx +++ b/src/sage/rings/padics/local_generic_element.pyx @@ -432,13 +432,10 @@ cdef class LocalGenericElement(CommutativeRingElement): sage: R(3).add_bigoh(5) 3 + O(3^4) - However, a negative value for ``absprec`` leads to an error, since - there is no fraction field for fixed-mod elements:: + A negative value for ``absprec`` returns an element in the fraction field:: - sage: R(3).add_bigoh(-1) - Traceback (most recent call last): - ... - ValueError: absprec must be at least 0 + sage: R(3).add_bigoh(-1).parent() + 3-adic Field with floating precision 4 TESTS: diff --git a/src/sage/rings/padics/padic_base_generic.py b/src/sage/rings/padics/padic_base_generic.py index eebbc4652c7..b7bc4bbf10d 100644 --- a/src/sage/rings/padics/padic_base_generic.py +++ b/src/sage/rings/padics/padic_base_generic.py @@ -101,63 +101,6 @@ def _repr_(self, do_latex=False): return r"\ZZ_{%s}" % self.prime() return "%s-adic %s %s"%(self.prime(), "Field" if self.is_field() else "Ring", precprint(self._prec_type(), self.precision_cap(), self.prime())) - def fraction_field(self, print_mode=None): - r""" - Returns the fraction field of ``self``. - - INPUT: - - - ``print_mode`` - a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - the fraction field of ``self``. - - EXAMPLES:: - - sage: R = Zp(5, print_mode='digits') - sage: K = R.fraction_field(); repr(K(1/3))[3:] - '31313131313131313132' - sage: L = R.fraction_field({'max_ram_terms':4}); repr(L(1/3))[3:] - '3132' - """ - if self.is_field() and print_mode is None: - return self - from sage.rings.padics.factory import Qp - if self.is_floating_point(): - mode = 'floating-point' - else: - mode = 'capped-rel' - return Qp(self.prime(), self.precision_cap(), mode, print_mode=self._modified_print_mode(print_mode), names=self._uniformizer_print()) - - def integer_ring(self, print_mode=None): - r""" - Returns the integer ring of ``self``, possibly with - ``print_mode`` changed. - - INPUT: - - - ``print_mode`` - a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - The ring of integral elements in ``self``. - - EXAMPLES:: - - sage: K = Qp(5, print_mode='digits') - sage: R = K.integer_ring(); repr(R(1/3))[3:] - '31313131313131313132' - sage: S = K.integer_ring({'max_ram_terms':4}); repr(S(1/3))[3:] - '3132' - """ - if not self.is_field() and print_mode is None: - return self - from sage.rings.padics.factory import Zp - return Zp(self.prime(), self.precision_cap(), self._prec_type(), print_mode=self._modified_print_mode(print_mode), names=self._uniformizer_print()) - def exact_field(self): """ Returns the rational field. diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 702991a0c8e..0cfc9252554 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -472,6 +472,14 @@ def __init__(self, p, prec, print_mode, names): sage: TestSuite(R).run(skip='_test_log') sage: TestSuite(R).run(elements = [R.random_element() for i in range(2^4)], max_runs = 2^6, skip='_test_log') # long time sage: R._test_log(max_runs=2, elements=[R.random_element() for i in range(4)]) + + Fraction fields work after :trac:`23510`:: + + sage: R = ZpFM(5) + sage: K = R.fraction_field(); K + 5-adic Field with floating precision 20 + sage: K(R(90)) + 3*5 + 3*5^2 """ pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFixedModElement) @@ -510,27 +518,6 @@ def _coerce_map_from_(self, R): self._printer.richcmp_modes(R._printer, op_LE)): return True - def fraction_field(self, print_mode = None): - r""" - Would normally return `\mathbb{Q}_p`, but there is no - implementation of `\mathbb{Q}_p` matching this ring so this - raises an error - - If you want to be able to divide with elements of a fixed - modulus `p`-adic ring, you must cast explicitly. - - EXAMPLES:: - - sage: ZpFM(5).fraction_field() - Traceback (most recent call last): - ... - TypeError: This implementation of the p-adic ring does not support fields of fractions. - - sage: a = ZpFM(5)(4); b = ZpFM(5)(5) - """ - raise TypeError("This implementation of the p-adic ring does not support fields of fractions.") - - class pAdicFieldCappedRelative(pAdicFieldBaseGeneric, pAdicCappedRelativeFieldGeneric): r""" An implementation of `p`-adic fields with capped relative precision. @@ -714,7 +701,7 @@ def _coerce_map_from_(self, R): sage: K.has_coerce_map_from(ZpCA(17,40)) False """ - if isinstance(R, (pAdicRingFloatingPoint, pAdicFieldFloatingPoint)) and R.prime() == self.prime(): + if isinstance(R, (pAdicRingFixedMod, pAdicRingFloatingPoint, pAdicFieldFloatingPoint)) and R.prime() == self.prime(): if R.precision_cap() > self.precision_cap(): return True elif R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index b39a2e98a99..6fb1710eea7 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -138,7 +138,7 @@ cdef class pAdicCappedAbsoluteElement(CAElement): [&=...] PADIC(lg=5):... (precp=0,valp=5):... ... ... ... p : [&=...] INT(lg=3):... (+,lgefint=3):... ... p^l : [&=...] INT(lg=3):... (+,lgefint=3):... ... - I : [&=...] INT(lg=2):... (0,lgefint=2):... + I : gen_0 """ cdef long val # Let val be the valuation of self, holder (defined in the diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index bc12e07408e..dd6cdd291fb 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -226,7 +226,7 @@ cdef class pAdicCappedRelativeElement(CRElement): [&=...] PADIC(lg=5):... (precp=0,valp=5):... ... ... ... p : [&=...] INT(lg=3):... (+,lgefint=3):... ... p^l : [&=...] INT(lg=3):... (+,lgefint=3):... ... - I : [&=...] INT(lg=2):... (0,lgefint=2):... + I : gen_0 """ if exactzero(self.ordp): return pari.zero() diff --git a/src/sage/rings/padics/padic_extension_generic.py b/src/sage/rings/padics/padic_extension_generic.py index 39270fbf751..69aa6763ee5 100644 --- a/src/sage/rings/padics/padic_extension_generic.py +++ b/src/sage/rings/padics/padic_extension_generic.py @@ -90,6 +90,8 @@ def _coerce_map_from_(self, R): from sage.rings.padics.qadic_flint_CR import pAdicCoercion_CR_frac_field as coerce_map elif R._prec_type() == 'floating-point': from sage.rings.padics.qadic_flint_FP import pAdicCoercion_FP_frac_field as coerce_map + elif R._prec_type() == 'fixed-mod': + from sage.rings.padics.qadic_flint_FM import pAdicCoercion_FM_frac_field as coerce_map return coerce_map(R, self) def _convert_map_from_(self, R): @@ -400,67 +402,6 @@ def construction(self): implementation=self._implementation), self.base_ring()) - def fraction_field(self, print_mode=None): - r""" - Returns the fraction field of this extension, which is just - the extension of base.fraction_field() determined by the - same polynomial. - - INPUT: - - - print_mode -- a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - the fraction field of self. - - EXAMPLES:: - - sage: U. = Zq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) - sage: U.fraction_field() - Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Field - sage: U.fraction_field({"pos":False}) == U.fraction_field() - False - """ - if self.is_field() and print_mode is None: - return self - if print_mode is None: - return self.change(field=True) - else: - return self.change(field=True, **print_mode) - - def integer_ring(self, print_mode=None): - r""" - Returns the ring of integers of self, which is just the - extension of base.integer_ring() determined by the same - polynomial. - - INPUT: - - - print_mode -- a dictionary containing print options. - Defaults to the same options as this ring. - - OUTPUT: - - - the ring of elements of self with nonnegative valuation. - - EXAMPLES:: - - sage: U. = Qq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) - sage: U.integer_ring() - Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Ring - sage: U.fraction_field({"pos":False}) == U.fraction_field() - False - """ - #Currently does not support fields with non integral defining polynomials. This should change when the padic_general_extension framework gets worked out. - if not self.is_field() and print_mode is None: - return self - if print_mode is None: - return self.change(field=False) - else: - return self.change(field=False, **print_mode) - #def hasGNB(self): # raise NotImplementedError diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index fdff7d13ea2..3fa062bd3ef 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -650,6 +650,21 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._implementation = implementation EisensteinExtensionGeneric.__init__(self, poly, prec, print_mode, names, pAdicZZpXFMElement) + def fraction_field(self): + """ + Eisenstein extensions with fixed modulus do not support fraction fields. + + EXAMPLES:: + + sage: S. = ZZ[] + sage: R. = ZpFM(5).extension(x^2 - 5) + sage: R.fraction_field() + Traceback (most recent call last): + ... + TypeError: This implementation of the p-adic ring does not support fields of fractions. + """ + raise TypeError("This implementation of the p-adic ring does not support fields of fractions.") + #def coerce_map_explicit(self, S): # from sage.rings.padics.morphism import Morphism_ZZ_EisFM, Morphism_ZpFM_EisFM # if S is ZZ: diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pxd b/src/sage/rings/padics/padic_fixed_mod_element.pxd index d82f89cd65f..cd619a1bcb2 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pxd +++ b/src/sage/rings/padics/padic_fixed_mod_element.pxd @@ -1,5 +1,6 @@ from sage.libs.gmp.types cimport mpz_t from cypari2.gen cimport Gen as pari_gen +from sage.rings.padics.padic_floating_point_element cimport FPElement ctypedef mpz_t celement include "FM_template_header.pxi" diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index 7516e45ea17..5fce3545e05 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -204,7 +204,7 @@ cdef class pAdicFixedModElement(FMElement): [&=...] PADIC(lg=5):... (precp=0,valp=10):... ... ... ... p : [&=...] INT(lg=3):... (+,lgefint=3):... ... p^l : [&=...] INT(lg=3):... (+,lgefint=3):... ... - I : [&=...] INT(lg=2):... (0,lgefint=2):... + I : gen_0 This checks that :trac:`15653` is fixed:: diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 7e3a142c54b..7e3a4f61389 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -358,6 +358,84 @@ def residue_system(self): """ return [self(i) for i in self.residue_class_field()] + def fraction_field(self, print_mode=None): + r""" + Returns the fraction field of this ring or field. + + For `\ZZ_p`, this is the `p`-adic field with the same options, + and for extensions, it is just the extension of the fraction + field of the base determined by the same polynomial. + + The fraction field of a capped absolute ring is capped relative, + and that of a fixed modulus ring is floating point. + + INPUT: + + - ``print_mode`` -- a dictionary containing print options. + Defaults to the same options as this ring. + + OUTPUT: + + - the fraction field of this ring. + + EXAMPLES:: + + sage: R = Zp(5, print_mode='digits') + sage: K = R.fraction_field(); repr(K(1/3))[3:] + '31313131313131313132' + sage: L = R.fraction_field({'max_ram_terms':4}); repr(L(1/3))[3:] + '3132' + sage: U. = Zq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) + sage: U.fraction_field() + Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Field + sage: U.fraction_field({"pos":False}) == U.fraction_field() + False + """ + if self.is_field() and print_mode is None: + return self + if print_mode is None: + return self.change(field=True) + else: + return self.change(field=True, **print_mode) + + def integer_ring(self, print_mode=None): + r""" + Returns the ring of integers of this ring or field. + + For `\QQ_p`, this is the `p`-adic ring with the same options, + and for extensions, it is just the extension of the ring + of integers of the base determined by the same polynomial. + + INPUT: + + - ``print_mode`` -- a dictionary containing print options. + Defaults to the same options as this ring. + + OUTPUT: + + - the ring of elements of this field with nonnegative valuation. + + EXAMPLES:: + + sage: K = Qp(5, print_mode='digits') + sage: R = K.integer_ring(); repr(R(1/3))[3:] + '31313131313131313132' + sage: S = K.integer_ring({'max_ram_terms':4}); repr(S(1/3))[3:] + '3132' + sage: U. = Qq(17^4, 6, print_mode='val-unit', print_max_terse_terms=3) + sage: U.integer_ring() + Unramified Extension in a defined by x^4 + 7*x^2 + 10*x + 3 with capped relative precision 6 over 17-adic Ring + sage: U.fraction_field({"pos":False}) == U.fraction_field() + False + """ + #Currently does not support fields with non integral defining polynomials. This should change when the padic_general_extension framework gets worked out. + if not self.is_field() and print_mode is None: + return self + if print_mode is None: + return self.change(field=False) + else: + return self.change(field=False, **print_mode) + def teichmuller(self, x, prec = None): r""" Returns the teichmuller representative of x. diff --git a/src/sage/rings/padics/qadic_flint_FM.pxd b/src/sage/rings/padics/qadic_flint_FM.pxd index c063afef3fa..7c2facd3aaa 100644 --- a/src/sage/rings/padics/qadic_flint_FM.pxd +++ b/src/sage/rings/padics/qadic_flint_FM.pxd @@ -1,5 +1,6 @@ from cypari2.gen cimport Gen as pari_gen from sage.libs.flint.types cimport fmpz_poly_t +from sage.rings.padics.qadic_flint_FP cimport FPElement from sage.rings.padics.pow_computer_flint cimport PowComputer_flint_unram cdef class PowComputer_(PowComputer_flint_unram): diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index d7085f3a19a..bde2707d436 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2953,7 +2953,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): INPUT: - - ``R`` - (default: ``None``) PolynomialRing + - ``R`` - (default: ``None``) a univariate Laurent polynomial ring If this polynomial is not in at most one variable, then a ``ValueError`` exception is raised. The new polynomial is over @@ -2992,13 +2992,14 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): elif len(v) == 1: x = v[0] i = self._parent.gens().index(x) + x = str(x) else: x = 'x' i = 0 #construct ring if none if R is None: - R = LaurentPolynomialRing(self.base_ring(),x) + R = LaurentPolynomialRing(self.base_ring(), x) return R(dict((m[i],c) for m,c in self.dict().items())) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 3b234e82321..b21135219e4 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -50,8 +50,7 @@ from sage.rings.ring import is_Ring from sage.rings.infinity import infinity from sage.rings.integer import Integer -from sage.rings.polynomial.polynomial_ring_constructor import _single_variate as _single_variate_poly -from sage.rings.polynomial.polynomial_ring_constructor import _multi_variate as _multi_variate_poly +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.latex import latex from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair, LaurentPolynomial_univariate from sage.rings.ring import CommutativeRing @@ -74,7 +73,8 @@ def is_LaurentPolynomialRing(R): """ return isinstance(R, LaurentPolynomialRing_generic) -def LaurentPolynomialRing(base_ring, arg1=None, arg2=None, sparse = False, order='degrevlex', names = None, name=None): +_cache = {} +def LaurentPolynomialRing(base_ring, *args, **kwds): r""" Return the globally unique univariate or multivariate Laurent polynomial ring with given properties and variable name or names. @@ -155,7 +155,7 @@ def LaurentPolynomialRing(base_ring, arg1=None, arg2=None, sparse = False, order sage: LaurentPolynomialRing(QQ) Traceback (most recent call last): ... - TypeError: You must specify the names of the variables. + TypeError: you must specify the names of the variables sage: R. = LaurentPolynomialRing(QQ, sparse=True); R Univariate Laurent Polynomial Ring in abc over Rational Field @@ -227,166 +227,21 @@ def LaurentPolynomialRing(base_ring, arg1=None, arg2=None, sparse = False, order sage: (w0 + 2*w8 + w13)^2 w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2 """ - if is_Element(arg1) and not isinstance(arg1, integer_types + (Integer,)): - arg1 = repr(arg1) - if is_Element(arg2) and not isinstance(arg2, integer_types + (Integer,)): - arg2 = repr(arg2) - - if isinstance(arg1, integer_types + (Integer,)): - arg1, arg2 = arg2, arg1 - - if not names is None: - arg1 = names - elif not name is None: - arg1 = name - - if not is_Ring(base_ring): - raise TypeError('base_ring must be a ring') - - if arg1 is None: - raise TypeError("You must specify the names of the variables.") - - R = None - if isinstance(arg1, (list, tuple)): - arg1 = [str(x) for x in arg1] - if isinstance(arg2, (list, tuple)): - arg2 = [str(x) for x in arg2] - if isinstance(arg2, integer_types + (Integer,)): - # 3. LaurentPolynomialRing(base_ring, names, n, order='degrevlex'): - if not isinstance(arg1, (list, tuple, str)): - raise TypeError("You *must* specify the names of the variables.") - n = int(arg2) - names = arg1 - R = _multi_variate(base_ring, names, n, sparse, order) - - elif isinstance(arg1, str) or (isinstance(arg1, (list,tuple)) and len(arg1) == 1) and isinstance(arg1[0], str): - if isinstance(arg1, (list,tuple)): - arg1 = arg1[0] - if not ',' in arg1: - # 1. LaurentPolynomialRing(base_ring, name, sparse=False): - if not arg2 is None: - raise TypeError("if second arguments is a string with no commas, then there must be no other non-optional arguments") - name = arg1 - R = _single_variate(base_ring, name, sparse) - else: - # 2-4. LaurentPolynomialRing(base_ring, names, order='degrevlex'): - if not arg2 is None: - raise TypeError("invalid input to LaurentPolynomialRing function; please see the docstring for that function") - names = arg1.split(',') - n = len(names) - R = _multi_variate(base_ring, names, n, sparse, order) - elif isinstance(arg1, (list, tuple)): - # LaurentPolynomialRing(base_ring, names (list or tuple), order='degrevlex'): - names = arg1 - n = len(names) - R = _multi_variate(base_ring, names, n, sparse, order) - - if arg1 is None and arg2 is None: - raise TypeError("you *must* specify the indeterminates (as not None).") - if R is None: - raise TypeError("invalid input (%s, %s, %s) to PolynomialRing function; please see the docstring for that function"%(base_ring, arg1, arg2)) - - return R - -_cache = {} -def _get_from_cache(key): - """ - EXAMPLES:: - - sage: from sage.rings.polynomial.laurent_polynomial_ring import _get_from_cache - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: L2 = _get_from_cache( (QQ,('x0','x1'),2,False,TermOrder('degrevlex')) ); L2 - Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field - sage: L is L2 - True - """ - try: - if key in _cache: - return _cache[key] # put () here to re-enable weakrefs - except TypeError as msg: - raise TypeError('key = %s\n%s'%(key,msg)) - return None + from sage.rings.polynomial.polynomial_ring import is_PolynomialRing + from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing -def _save_in_cache(key, R): - """ - EXAMPLES:: + R = PolynomialRing(base_ring, *args, **kwds) + if R in _cache: + return _cache[R] # put () here to re-enable weakrefs - sage: from sage.rings.polynomial.laurent_polynomial_ring import _save_in_cache, _get_from_cache - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: _save_in_cache('testkey', L) - sage: _get_from_cache('testkey') - Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field - sage: _ is L - True - """ - try: - # We disable weakrefs since they cause segfault at the end of doctesting. - #weakref.ref(R) - _cache[key] = R - except TypeError as msg: - raise TypeError('key = %s\n%s'%(key,msg)) - -def _single_variate(base_ring, names, sparse): - """ - EXAMPLES:: - - sage: from sage.rings.polynomial.laurent_polynomial_ring import _single_variate - sage: _single_variate(QQ, ('x',), False) - Univariate Laurent Polynomial Ring in x over Rational Field - """ - names = normalize_names(1, names) - key = (base_ring, names, sparse) - P = _get_from_cache(key) - if P is not None: - return P - prepend_string = "qk" - while True: - if prepend_string in names: - prepend_string += 'k' - else: - break - R = _single_variate_poly(base_ring, names, sparse, None) - P = LaurentPolynomialRing_univariate(R, names) - _save_in_cache(key, P) - return P - -def _multi_variate(base_ring, names, n, sparse, order): - """ - EXAMPLES:: + if is_PolynomialRing(R): + # univariate case + P = LaurentPolynomialRing_univariate(R) + else: + assert is_MPolynomialRing(R) + P = LaurentPolynomialRing_mpair(R) - sage: from sage.rings.polynomial.laurent_polynomial_ring import _multi_variate - sage: _multi_variate(QQ, ('x','y'), 2, False, 'degrevlex') - Multivariate Laurent Polynomial Ring in x, y over Rational Field - """ - # We need to come up with a name for the inverse that is easy to search - # for in a string *and* doesn't overlap with the name that we already have. - # For now, I'm going to use a name mangling with checking method. - names = normalize_names(n, names) - - from .term_order import TermOrder - order = TermOrder(order, n) - - if isinstance(names, list): - names = tuple(names) - elif isinstance(names, str): - if ',' in names: - names = tuple(names.split(',')) - - key = (base_ring, names, n, sparse, order) - P = _get_from_cache(key) - if P is not None: - return P - prepend_string = "qk" - while True: - for a in names: - if prepend_string in a: - prepend_string += 'k' - break - else: - break - R = _multi_variate_poly(base_ring, names, sparse, order) - P = LaurentPolynomialRing_mpair(R, prepend_string, names) - _save_in_cache(key, P) + _cache[R] = P return P def _split_dict_(D, indices, group_by=None): @@ -545,7 +400,7 @@ class LaurentPolynomialRing_generic(CommutativeRing, ParentWithGens): sage: TestSuite(R).run() """ - def __init__(self, R, prepend_string, names): + def __init__(self, R): """ EXAMPLES:: @@ -555,26 +410,11 @@ def __init__(self, R, prepend_string, names): """ self._n = R.ngens() self._R = R - self._prepend_string = prepend_string + names = R.variable_names() CommutativeRing.__init__(self, R.base_ring(), names=names) self._populate_coercion_lists_(element_constructor=self._element_constructor_, init_no_parent=True) - - def __repr__(self): - """ - TESTS:: - - sage: LaurentPolynomialRing(QQ,2,'x').__repr__() - 'Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field' - sage: LaurentPolynomialRing(QQ,1,'x').__repr__() - 'Univariate Laurent Polynomial Ring in x over Rational Field' - """ - if self._n == 1: - return "Univariate Laurent Polynomial Ring in %s over %s"%(self._R.variable_name(), self._R.base_ring()) - else: - return "Multivariate Laurent Polynomial Ring in %s over %s"%(", ".join(self._R.variable_names()), self._R.base_ring()) - def ngens(self): """ Returns the number of generators of self. @@ -1001,7 +841,7 @@ def fraction_field(self): return self.polynomial_ring().fraction_field() class LaurentPolynomialRing_univariate(LaurentPolynomialRing_generic): - def __init__(self, R, names): + def __init__(self, R): """ EXAMPLES:: @@ -1015,7 +855,16 @@ def __init__(self, R, names): raise ValueError("must be 1 generator") if not R.base_ring().is_integral_domain(): raise ValueError("base ring must be an integral domain") - LaurentPolynomialRing_generic.__init__(self, R, '', names) + LaurentPolynomialRing_generic.__init__(self, R) + + def _repr_(self): + """ + TESTS:: + + sage: LaurentPolynomialRing(QQ,'x') # indirect doctest + Univariate Laurent Polynomial Ring in x over Rational Field + """ + return "Univariate Laurent Polynomial Ring in %s over %s"%(self._R.variable_name(), self._R.base_ring()) def _element_constructor_(self, x): """ @@ -1103,10 +952,10 @@ def __reduce__(self): sage: loads(dumps(L)) == L True """ - return LaurentPolynomialRing_univariate, (self._R, self._names) + return LaurentPolynomialRing_univariate, (self._R,) class LaurentPolynomialRing_mpair(LaurentPolynomialRing_generic): - def __init__(self, R, prepend_string, names): + def __init__(self, R): """ EXAMPLES:: @@ -1121,7 +970,18 @@ def __init__(self, R, prepend_string, names): raise ValueError("n must be positive") if not R.base_ring().is_integral_domain(): raise ValueError("base ring must be an integral domain") - LaurentPolynomialRing_generic.__init__(self, R, prepend_string, names) + LaurentPolynomialRing_generic.__init__(self, R) + + def _repr_(self): + """ + TESTS:: + + sage: LaurentPolynomialRing(QQ,2,'x').__repr__() + 'Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field' + sage: LaurentPolynomialRing(QQ,1,'x').__repr__() + 'Multivariate Laurent Polynomial Ring in x over Rational Field' + """ + return "Multivariate Laurent Polynomial Ring in %s over %s"%(", ".join(self._R.variable_names()), self._R.base_ring()) def monomial(self, *args): r""" @@ -1292,6 +1152,6 @@ def __reduce__(self): sage: loads(dumps(L)) == L True """ - return LaurentPolynomialRing_mpair, (self._R, self._prepend_string, self._names) + return LaurentPolynomialRing_mpair, (self._R,) diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 733abef14c6..80813b856e4 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -550,7 +550,9 @@ def Omega_ge(a, exponents): TESTS:: - sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # long time + sage: Omega_ge(0, (2, 2, 1, 1, 1, -1, -1))[0].number_of_terms() # long time + 1695 + sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # not tested (too long, 1 min) 27837 :: diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index 232bec764a1..d9fb1942d6e 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -186,6 +186,7 @@ from __future__ import print_function, absolute_import from cpython.object cimport Py_EQ, Py_NE from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr import operator @@ -2297,7 +2298,7 @@ cdef class BooleanMonomial(MonoidElement): sage: M(x*y) x*y """ - return PBMonom_to_str(&self._pbmonom) + return ccrepr(self._pbmonom) def _eval(self, d): """ @@ -2947,7 +2948,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: repr(a+b+z^2+1) # indirect doctest 'a + b + z + 1' """ - return PBPoly_to_str(&self._pbpoly) + return ccrepr(self._pbpoly) def _repr_with_changed_varnames(self, varnames): r""" @@ -2987,7 +2988,7 @@ cdef class BooleanPolynomial(MPolynomial): for i from 0 <= i < N: P._pbring.setVariableName(i, orig_varnames[i]) raise TypeError("varnames has entries with wrong type.") - s = PBPoly_to_str(&self._pbpoly) + s = ccrepr(self._pbpoly) for i from 0 <= i < N: P._pbring.setVariableName(i, orig_varnames[i]) return s @@ -5405,7 +5406,7 @@ cdef class BooleSet: sage: repr(BS) # indirect doctest '{}' """ - return PBSet_to_str(&self._pbset) + return ccrepr(self._pbset) def set(self): """ diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pyx b/src/sage/rings/polynomial/polynomial_complex_arb.pyx index 7332dc213ea..37383c41aa2 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pyx +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pyx @@ -334,10 +334,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol. = CBF[] sage: (x^3/7 - CBF(i)).quo_rem(x + CBF(pi)) - (([0.1428571428571428 +/- 7.70e-17])*x^2 + - ([-0.448798950512828 +/- 6.74e-16])*x - + [1.40994348586991 +/- 3.34e-15], - [-4.42946809718569 +/- 9.00e-15] - I) + (([0.1428571428571428 +/- 7.70e-17])*x^2 + ([-0.448798950512828 +/- 6.74e-16])*x + [1.40994348586991 +/- 3.04e-15], [-4.42946809718569 +/- 7.86e-15] - I) sage: Pol(0).quo_rem(x + 1) (0, 0) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index b2b6b0075d9..cabf3072135 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -24,6 +24,8 @@ AUTHORS: - Edgar Costa (2017-07): Added rational reconstruction. +- Kiran Kedlaya (2017-09): Added reciprocal transform, trace polynomial. + TESTS:: sage: R. = ZZ[] @@ -3994,9 +3996,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: factor(x) x sage: factor(x^2 - q^2) - (-1) * (-x + q) * (x + q) + (x - q) * (x + q) sage: factor(x^2 - q^-2) - (1/q^2) * (q*x - 1) * (q*x + 1) + (x - 1/q) * (x + 1/q) sage: P. = PolynomialRing(ZZ) sage: R. = PolynomialRing(FractionField(P)) @@ -7844,6 +7846,131 @@ cdef class Polynomial(CommutativeAlgebraElement): """ return self.all_roots_in_interval() + def reciprocal_transform(self, R=1, q=1): + r""" + Transform a general polynomial into a self-reciprocal polynomial. + + The input `Q` and output `P` satisfy the relation + + .. MATH:: + + P(x) = Q(x + q/x) x^{\deg(Q)} R(x). + + In this relation, `Q` has all roots in the real interval + `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the + circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. + + .. SEEALSO:: + + The inverse operation is :meth:`trace_polynomial`. + + INPUT: + + - ``R`` -- polynomial + - ``q`` -- scalar (default: `1`) + + EXAMPLES:: + + sage: pol. = PolynomialRing(Rationals()) + sage: u = x^2+x-1 + sage: u.reciprocal_transform() + x^4 + x^3 + x^2 + x + 1 + sage: u.reciprocal_transform(R=x-1) + x^5 - 1 + sage: u.reciprocal_transform(q=3) + x^4 + x^3 + 5*x^2 + 3*x + 9 + """ + S = self.parent() + x = S.gen() + return S(x**(self.degree()) * self(x + q/x)) * R + + def trace_polynomial(self): + r""" + Compute the trace polynomial and cofactor. + + The input `P` and output `Q` satisfy the relation + + .. MATH:: + + P(x) = Q(x + q/x) x^{\deg(Q)} R(x). + + In this relation, `Q` has all roots in the real interval + `[-2\sqrt{q}, 2\sqrt{q}]` if and only if `P` has all roots on the + circle `|x| = \sqrt{q}` and `R` divides `x^2-q`. We thus require + that the base ring of this polynomial have a coercion to the real + numbers. + + .. SEEALSO:: + + The inverse operation is :meth:`reciprocal_transform`. + + OUTPUT: + + - ``Q`` -- trace polynomial + - ``R`` -- cofactor + - ``q`` -- scaling factor + + EXAMPLES:: + + sage: pol. = PolynomialRing(Rationals()) + sage: u = x^5 - 1; u.trace_polynomial() + (x^2 + x - 1, x - 1, 1) + sage: u = x^4 + x^3 + 5*x^2 + 3*x + 9 + sage: u.trace_polynomial() + (x^2 + x - 1, 1, 3) + + We check that this function works for rings + that have a coercion to the reals:: + + sage: K. = NumberField(x^2-2,embedding=1.4) + sage: u = x^4 + a*x^3 + 3*x^2 + 2*a*x + 4 + sage: u.trace_polynomial() + (x^2 + a*x - 1, 1, 2) + sage: (u*(x^2-2)).trace_polynomial() + (x^2 + a*x - 1, x^2 - 2, 2) + sage: (u*(x^2-2)^2).trace_polynomial() + (x^4 + a*x^3 - 9*x^2 - 8*a*x + 8, 1, 2) + sage: (u*(x^2-2)^3).trace_polynomial() + (x^4 + a*x^3 - 9*x^2 - 8*a*x + 8, x^2 - 2, 2) + sage: u = x^4 + a*x^3 + 3*x^2 + 4*a*x + 16 + sage: u.trace_polynomial() + (x^2 + a*x - 5, 1, 4) + sage: (u*(x-2)).trace_polynomial() + (x^2 + a*x - 5, x - 2, 4) + sage: (u*(x+2)).trace_polynomial() + (x^2 + a*x - 5, x + 2, 4) + """ + S = self.parent() + A = S.base_ring() + x = S.gen() + if self[0] == 0: + raise ValueError("Polynomial not self-reciprocal") + d = self.degree() + sg = (self[0]/self[d]).sign() + try: + q = A(abs(self[0]/self[d])**(2/d)) + except (TypeError, ValueError): + raise ValueError("Polynomial not self-reciprocal") + for i in range(d/2+1): + if self[d-i] != sg*self[i]/q**(d/2-i): + raise ValueError("Polynomial not self-reciprocal") + Q = self + if sg == -1 and Q.degree() % 2 == 0: + cofactor = x**2 - q + elif sg == -1: + cofactor = x - q.sqrt() + elif Q.degree() % 2 == 1: + cofactor = x + q.sqrt() + else: + cofactor = S(1) + Q //= cofactor + coeffs = [] + m = Q.degree() // 2 + for i in reversed(range(m+1)): + coeffs.insert(0, Q.leading_coefficient()) + Q = (Q % (x**2 + q)**i) // x + return S(coeffs), cofactor, q + def variable_name(self): """ Return name of variable used in this polynomial as a string. diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx index 7b610e9b01a..d0985591d68 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx @@ -36,6 +36,7 @@ from __future__ import absolute_import, print_function from cysignals.memory cimport sig_free from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr include "sage/libs/ntl/decl.pxi" @@ -381,10 +382,10 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): if sign: if sign > 0: sign_str = '+' - coeff_str = ZZ_to_PyString(&self.__poly.rep.elts()[i]) + coeff_str = ccrepr(self.__poly.rep.elts()[i]) else: sign_str = '-' - coeff_str = ZZ_to_PyString(&self.__poly.rep.elts()[i])[1:] + coeff_str = ccrepr(self.__poly.rep.elts()[i])[1:] if i > 0: if coeff_str == '1': coeff_str = '' diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pyx b/src/sage/rings/polynomial/polynomial_zz_pex.pyx index 0e22e15679e..be9e9c6bd3a 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pyx +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pyx @@ -10,12 +10,9 @@ from sage.rings.integer_ring import ZZ from sage.rings.integer_ring cimport IntegerRing_class from sage.libs.ntl.ntl_ZZ_pEContext cimport ntl_ZZ_pEContext_class -from sage.libs.ntl.ZZ_pE cimport ZZ_pE_to_PyString from sage.libs.ntl.ZZ_pE cimport ZZ_pE_to_ZZ_pX -from sage.libs.ntl.ZZ_pX cimport ZZ_pX_to_PyString from sage.libs.ntl.ZZ_pX cimport ZZ_pX_deg, ZZ_pX_coeff from sage.libs.ntl.ntl_ZZ_pX cimport ntl_ZZ_pX -from sage.libs.ntl.ZZ_p cimport ZZ_p_to_PyString from sage.libs.ntl.ZZ_p cimport ZZ_p_rep from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 639afc14a44..593d3fff7d3 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -285,7 +285,7 @@ sage: lhs - rhs 0 sage: lhs._exact_value() - 10648699402510886229334132989629606002223831*a^9 + 23174560249100286133718183712802529035435800*a^8 + 27259790692625442252605558473646959458901265*a^7 + 21416469499004652376912957054411004410158065*a^6 + 14543082864016871805545108986578337637140321*a^5 + 6458050008796664339372667222902512216589785*a^4 - 3052219053800078449122081871454923124998263*a^3 - 14238966128623353681821644902045640915516176*a^2 - 16749022728952328254673732618939204392161001*a - 9052854758155114957837247156588012516273410 where a^10 + a^9 - a^7 - a^6 - a^5 - a^4 - a^3 + a + 1 = 0 and a in 1.176280818259918? + -10648699402510886229334132989629606002223831*a^9 + 23174560249100286133718183712802529035435800*a^8 - 27259790692625442252605558473646959458901265*a^7 + 21416469499004652376912957054411004410158065*a^6 - 14543082864016871805545108986578337637140321*a^5 + 6458050008796664339372667222902512216589785*a^4 + 3052219053800078449122081871454923124998263*a^3 - 14238966128623353681821644902045640915516176*a^2 + 16749022728952328254673732618939204392161001*a - 9052854758155114957837247156588012516273410 where a^10 - a^9 + a^7 - a^6 + a^5 - a^4 + a^3 - a + 1 = 0 and a in -1.176280818259918? Given an algebraic number, we can produce a string that will reproduce that algebraic number if you type the string into Sage. We can see @@ -519,7 +519,7 @@ from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method from sage.structure.sage_object import SageObject -from sage.structure.richcmp import (richcmp, +from sage.structure.richcmp import (richcmp, richcmp_method, rich_to_bool, richcmp_not_equal, op_EQ, op_NE, op_LE, op_LT, op_GE, op_GT) @@ -1752,7 +1752,7 @@ def do_polred(poly): sage: do_polred(x^2 - x - 11) (1/3*x + 1/3, 3*x - 1, x^2 - x - 1) sage: do_polred(x^3 + 123456) - (1/4*x, 4*x, x^3 + 1929) + (-1/4*x, -4*x, x^3 - 1929) This shows that :trac:`13054` has been fixed:: @@ -2197,6 +2197,8 @@ def __init__(self, child1, child1_poly, child2, child2_poly, parent): algebraic_generator_counter = 0 + +@richcmp_method class AlgebraicGenerator(SageObject): r""" An ``AlgebraicGenerator`` represents both an algebraic number `\alpha` and @@ -2278,9 +2280,9 @@ def __hash__(self): """ return self._index - def __cmp__(self, other): + def __richcmp__(self, other, op): r""" - Compare self with another AlgebraicGenerator object. + Compare ``self`` with another ``AlgebraicGenerator`` object. EXAMPLES:: @@ -2290,16 +2292,10 @@ def __cmp__(self, other): sage: nf = NumberField(y^2 - y - 1, name='a', check=False) sage: root = ANRoot(x^2 - x - 1, RIF(1, 2)) sage: gen = AlgebraicGenerator(nf, root) - sage: gen.__cmp__(qq_generator) - 1 + sage: gen > qq_generator + True """ - si = self._index - oi = other._index - if si < oi: - return -1 - if si > oi: - return 1 - return 0 + return richcmp(self._index, other._index, op) def is_complex(self): r""" diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 64406a9d159..ef85cd27ddc 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -426,6 +426,24 @@ def __iter__(self): yield self(height/other) yield self(-height/other) + def __truediv__(self, I): + """ + Form the quotient by an integral ideal. + + EXAMPLES:: + + sage: QQ / ZZ + Q/Z + """ + from sage.rings.ideal import Ideal_generic + from sage.groups.additive_abelian.qmodnz import QmodnZ + if I is ZZ: + return QmodnZ(1) + elif isinstance(I, Ideal_generic) and I.base_ring() is ZZ: + return QmodnZ(I.gen()) + else: + return super(RationalField, self).__truediv__(I) + def range_by_height(self, start, end=None): r""" Range function for rational numbers, ordered by height. diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index cf89e278c27..aa12ae0a043 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1869,7 +1869,7 @@ cdef class RealBall(RingElement): EXAMPLES:: sage: RBF(0).union(1).endpoints() - (0.000000000000000, 1.00000000000000) + (-9.31322574615479e-10, 1.00000000093133) """ cdef RealBall my_other = self._parent.coerce(other) cdef RealBall res = self._new() @@ -3421,7 +3421,7 @@ cdef class RealBall(RingElement): sage: RBF(-1).zeta(1) [-0.0833333333333333 +/- 4.26e-17] sage: RBF(-1).zeta(2) - [-1.083333333333333 +/- 4.08e-16] + [-1.083333333333333 +/- 4.96e-16] """ cdef RealBall a_ball cdef RealBall res = self._new() @@ -3458,7 +3458,7 @@ cdef class RealBall(RingElement): TESTS:: sage: RBF(1/3).polylog(2r) - [0.36621322997706 +/- 4.62e-15] + [0.366213229977063 +/- 5.85e-16] """ cdef RealBall s_as_ball cdef Integer s_as_Integer diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index f428c0a5b8f..e1b647c6045 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -119,6 +119,7 @@ cdef class Ring(ParentWithGens): running ._test_elements_neq() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass @@ -645,7 +646,7 @@ cdef class Ring(ParentWithGens): EXAMPLES:: - sage: QQ / ZZ + sage: QQ['x'] / ZZ Traceback (most recent call last): ... TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index 3d2076399bf..16b93f222e7 100644 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -369,7 +369,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, sage: E.rank() 1 sage: E._EllipticCurve_rational_field__rank - {True: 1} + (1, True) sage: E.analytic_rank = lambda : 0 sage: E.prove_BSD() Traceback (most recent call last): @@ -528,9 +528,9 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, rank_lower_bd > rank_upper_bd: raise RuntimeError("Something went wrong with 2-descent.") if BSD.rank != len(gens): - if BSD.rank != len(BSD.curve._EllipticCurve_rational_field__gens[True]): + gens = BSD.curve.gens(proof=True) + if BSD.rank != len(gens): raise RuntimeError("Could not get generators") - gens = BSD.curve._EllipticCurve_rational_field__gens[True] BSD.gens = [BSD.curve.point(x, check=True) for x in gens] if BSD.rank != BSD.curve.analytic_rank(): diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 5ff13e175f7..e550571b001 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -246,11 +246,11 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, C = Mod(y, y^2 + 7) Computing L(S,2) - L(S,2) = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(-1, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(-1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(x^2 + 2, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y + 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y - 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] + L(S,2) = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(-1, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(-1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(x^2 + 2, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y + 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x + Mod(1/2*y - 3/2, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] Computing the Selmer group #LS2gen = 2 - LS2gen = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y + 1/2, y^2 + 7)*x - 1, x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] + LS2gen = [Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)), Mod(Mod(1, y^2 + 7)*x^2 + Mod(1/2*y + 1/2, y^2 + 7)*x + Mod(-1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7))] Search for trivial points on the curve Trivial points on the curve = [[Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7)], [1, 1, 0], [Mod(1/2*y + 3/2, y^2 + 7), Mod(-y - 2, y^2 + 7), 1]] zc = Mod(Mod(-1/2*y + 1/2, y^2 + 7)*x^2 + Mod(-1/2*y - 1/2, y^2 + 7)*x + Mod(-y - 1, y^2 + 7), x^3 + Mod(1, y^2 + 7)*x + Mod(y, y^2 + 7)) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 6d2934b4448..e8e0b8f6746 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -174,13 +174,18 @@ def __init__(self, ainvs, **kwds): [True, True] """ - self.__np = {} - self.__gens = {} - self.__rank = {} - self.__regulator = {} + # Cached values for the generators, rank and regulator. + # The format is a tuple (value, proven). "proven" is a boolean + # which says whether or not the value was proven. + self.__gens = None + self.__rank = None + self.__regulator = None + + # Other cached values self.__generalized_modular_degree = {} self.__generalized_congruence_number = {} self._isoclass = {} + EllipticCurve_number_field.__init__(self, Q, ainvs) if 'conductor' in kwds: @@ -196,7 +201,7 @@ def __init__(self, ainvs, **kwds): if 'rank' in kwds: self._set_rank(kwds['rank']) if 'regulator' in kwds: - self.__regulator[True] = kwds['regulator'] + self.__regulator = (kwds['regulator'], True) if 'torsion_order' in kwds: self._set_torsion_order(kwds['torsion_order']) @@ -215,12 +220,11 @@ def _set_rank(self, r): sage: E._set_rank(99) # bogus value -- not checked sage: E.rank() # returns bogus cached value 99 - sage: E._EllipticCurve_rational_field__rank={} # undo the damage + sage: E._EllipticCurve_rational_field__rank = None # undo the damage sage: E.rank() # the correct rank 1 """ - self.__rank = {} - self.__rank[True] = Integer(r) + self.__rank = (Integer(r), True) def _set_torsion_order(self, t): """ @@ -333,9 +337,8 @@ def _set_gens(self, gens): sage: E.gens() [(-2 : 3 : 1), (-1 : 3 : 1), (0 : 2 : 1)] """ - self.__gens = {} - self.__gens[True] = [self.point(x, check=True) for x in gens] - self.__gens[True].sort() + gens = sorted(self.point(x, check=True) for x in gens) + self.__gens = (gens, True) def lmfdb_page(self): r""" @@ -860,9 +863,9 @@ def two_descent(self, verbose=True, first_limit, second_limit, n_aux, second_descent) if C.certain(): - self.__gens[True] = [self.point(x, check=True) for x in C.gens()] - self.__gens[True].sort() - self.__rank[True] = len(self.__gens[True]) + gens = sorted(self.point(x, check=True) for x in C.gens()) + self.__gens = (gens, True) + self.__rank = (Integer(len(gens)), True) return C.certain() #################################################################### @@ -1924,9 +1927,8 @@ def simon_two_descent(self, verbose=0, lim1=5, lim3=50, limtriv=3, print("Rank determined successfully, saturating...") gens = self.saturation(pts)[0] if len(gens) == rank_low_bd: - self.__gens[True] = gens - self.__gens[True].sort() - self.__rank[True] = rank_low_bd + self.__gens = (gens, True) + self.__rank = (Integer(rank_low_bd), True) return rank_low_bd, two_selmer_rank, pts @@ -1981,10 +1983,10 @@ def three_selmer_rank(self, algorithm='UseSUnits'): E = magma(self) return Integer(E.ThreeSelmerGroup(MethodForFinalStep = magma('"%s"'%algorithm)).Ngens()) - def rank(self, use_database=False, verbose=False, - only_use_mwrank=True, - algorithm='mwrank_lib', - proof=None): + def rank(self, use_database=True, verbose=False, + only_use_mwrank=True, + algorithm='mwrank_lib', + proof=None): """ Return the rank of this elliptic curve, assuming no conjectures. @@ -1993,9 +1995,8 @@ def rank(self, use_database=False, verbose=False, INPUT: - - - ``use_database (bool)`` - (default: ``False``), if - ``True``, try to look up the regulator in the Cremona database. + - ``use_database (bool)`` -- (default: ``True``), if + ``True``, try to look up the rank in the Cremona database. - ``verbose`` - (default: ``False``), if specified changes the verbosity of mwrank computations. @@ -2013,12 +2014,7 @@ def rank(self, use_database=False, verbose=False, proof.elliptic_curve or sage.structure.proof). Note that results obtained from databases are considered proof = True - - OUTPUT: - - - - ``rank (int)`` - the rank of the elliptic curve. - + OUTPUT: the rank of the elliptic curve as :class:`Integer` IMPLEMENTATION: Uses L-functions, mwrank, and databases. @@ -2057,33 +2053,60 @@ def rank(self, use_database=False, verbose=False, sage: EllipticCurve([1,0,0,0,37455]).rank(proof=True) Traceback (most recent call last): ... - RuntimeError: Rank not provably correct. + RuntimeError: rank not provably correct (lower bound: 0) + + TESTS:: + + sage: EllipticCurve([1,10000]).rank(algorithm="garbage") + Traceback (most recent call last): + ... + ValueError: unknown algorithm 'garbage' + + Since :trac:`23962`, the default is to use the Cremona + database. We also check that the result is cached correctly:: + + sage: E = EllipticCurve([-517, -4528]) # 1888b1 + sage: E.rank(use_database=False) + Traceback (most recent call last): + ... + RuntimeError: rank not provably correct (lower bound: 0) + sage: E._EllipticCurve_rational_field__rank + (0, False) + sage: E.rank() + 0 + sage: E._EllipticCurve_rational_field__rank + (0, True) """ if proof is None: from sage.structure.proof.proof import get_flag proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) - try: - return self.__rank[proof] - except KeyError: - if proof is False and True in self.__rank: - return self.__rank[True] + + if self.__rank: + rank, proven = self.__rank + if proven or not proof: + return rank + if use_database: try: - self.__rank[True] = self.database_attributes()['rank'] - return self.__rank[True] + rank = Integer(self.database_attributes()['rank']) except LookupError: # curve not in database, or rank not known pass + else: + self.__rank = (rank, True) + return rank + if not only_use_mwrank: # Try zero sum rank bound first; if this is 0 or 1 it's the # true rank rank_bound = self.analytic_rank_upper_bound() if rank_bound <= 1: misc.verbose("rank %s due to zero sum bound and parity"%rank_bound) - self.__rank[proof] = rank_bound - return self.__rank[proof] + rank = Integer(rank_bound) + self.__rank = (rank, proof) + return rank # Next try evaluate the L-function or its derivative at the # central point N = self.conductor() @@ -2092,14 +2115,16 @@ def rank(self, use_database=False, verbose=False, L, err = self.lseries().at1(prec) if abs(L) > err + R(0.0001): # definitely doesn't vanish misc.verbose("rank 0 because L(E,1)=%s"%L) - self.__rank[proof] = 0 - return self.__rank[proof] + rank = Integer(0) + self.__rank = (rank, proof) + return rank else: Lprime, err = self.lseries().deriv_at1(prec) if abs(Lprime) > err + R(0.0001): # definitely doesn't vanish misc.verbose("rank 1 because L'(E,1)=%s"%Lprime) - self.__rank[proof] = 1 - return self.__rank[proof] + rank = Integer(1) + self.__rank = (rank, proof) + return rank if algorithm == 'mwrank_lib': misc.verbose("using mwrank lib") @@ -2107,35 +2132,36 @@ def rank(self, use_database=False, verbose=False, else: E = self.integral_model() C = E.mwrank_curve() C.set_verbose(verbose) - r = C.rank() - if C.certain(): - proof = True - else: + rank = Integer(C.rank()) + proven = C.certain() + self.__rank = (rank, proven) + if not proven: if proof: - print("Unable to compute the rank with certainty (lower bound=%s)." % C.rank()) + print("Unable to compute the rank with certainty (lower bound=%s)." % rank) print("This could be because Sha(E/Q)[2] is nontrivial.") print("Try calling something like two_descent(second_limit=13) on the") print("curve then trying this command again. You could also try rank") print("with only_use_mwrank=False.") del E.__mwrank_curve - raise RuntimeError('Rank not provably correct.') + raise RuntimeError('rank not provably correct (lower bound: {})'.format(rank)) else: misc.verbose("Warning -- rank not proven correct", level=1) - self.__rank[proof] = r - elif algorithm == 'mwrank_shell': + return rank + + if algorithm == 'mwrank_shell': misc.verbose("using mwrank shell") X = self.mwrank() if 'determined unconditionally' not in X or 'only a lower bound of' in X: if proof: X= "".join(X.split("\n")[-4:-2]) print(X) - raise RuntimeError('Rank not provably correct.') + raise RuntimeError('rank not provably correct') else: misc.verbose("Warning -- rank not proven correct", level=1) s = "lower bound of" X = X[X.rfind(s)+len(s)+1:] - r = Integer(X.split()[0]) + rank = Integer(X.split()[0]) else: if proof is False: proof = True #since we actually provably found the rank @@ -2147,23 +2173,17 @@ def rank(self, use_database=False, verbose=False, if i == -1: raise RuntimeError("%s\nbug -- tried to find 'Rank =' or 'found points of rank' in mwrank output but couldn't."%X) j = i + X[i:].find('\n') - r = Integer(X[i+len(match)+1:j]) - self.__rank[proof] = r + rank = Integer(X[i+len(match)+1:j]) + self.__rank = (rank, proof) + return rank - return self.__rank[proof] + raise ValueError("unknown algorithm {!r}".format(algorithm)) def gens(self, proof=None, **kwds): """ Return generators for the Mordell-Weil group E(Q) *modulo* torsion. - .. warning:: - - If the program fails to give a provably correct result, it - prints a warning message, but does not raise an - exception. Use :meth:`~gens_certain` to find out if this - warning message was printed. - INPUT: - ``proof`` -- bool or None (default None), see @@ -2201,6 +2221,12 @@ def gens(self, proof=None, **kwds): - ``generators`` - list of generators for the Mordell-Weil group modulo torsion + .. NOTE:: + + If you call this with ``proof=False``, then you can use the + :meth:`~gens_certain` method to find out afterwards + whether the generators were proved. + IMPLEMENTATION: Uses Cremona's mwrank C library. EXAMPLES:: @@ -2230,20 +2256,16 @@ def gens(self, proof=None, **kwds): proof = bool(proof) # If the gens are already cached, return them: - try: - return list(self.__gens[proof]) # return copy so not changed - except KeyError: - if proof is False and True in self.__gens: - return list(self.__gens[True]) + if self.__gens: + gens, proven = self.__gens + if proven or not proof: + return list(gens) # Return a copy - # At this point, self.__gens[True] does not exist, and in case - # proof is False, self.__gens[False] does not exist either. - - result, proved = self._compute_gens(proof, **kwds) - self.__gens[proved] = result - self.__rank[proved] = len(result) - self._known_points = result - return list(result) + gens, proved = self._compute_gens(proof, **kwds) + self.__gens = (gens, proved) + self.__rank = (Integer(len(gens)), proved) + self._known_points = gens + return list(gens) def _compute_gens(self, proof, verbose=False, @@ -2391,8 +2413,18 @@ def gens_certain(self): [(0 : -1 : 1)] sage: E.gens_certain() True + + TESTS:: + + sage: E = EllipticCurve([2, 4, 6, 8, 10]) + sage: E.gens_certain() + Traceback (most recent call last): + ... + RuntimeError: no generators have been computed yet """ - return True in self.__gens + if not self.__gens: + raise RuntimeError("no generators have been computed yet") + return self.__gens[1] def ngens(self, proof=None): """ @@ -2423,26 +2455,20 @@ def ngens(self, proof=None): """ return len(self.gens(proof = proof)) - def regulator(self, use_database=True, proof=None, precision=None, - descent_second_limit=12, verbose=False): + def regulator(self, proof=None, precision=53, **kwds): r""" Return the regulator of this curve, which must be defined over `\QQ`. INPUT: - - ``use_database`` -- bool (default: ``False``), if ``True``, - try to look up the generators in the Cremona database. - - ``proof`` -- bool or ``None`` (default: ``None``, see proof.[tab] or sage.structure.proof). Note that results from databases are considered proof = True - - ``precision`` -- int or ``None`` (default: ``None``): the - precision in bits of the result (default real precision if None) - - - ``descent_second_limit`` -- (default: 12)- used in 2-descent + - ``precision`` -- (int, default 53): the precision in bits of + the result - - ``verbose`` -- whether to print mwrank's verbose output + - ``**kwds`` -- passed to :meth:`gens()` method EXAMPLES:: @@ -2462,11 +2488,7 @@ def regulator(self, use_database=True, proof=None, precision=None, sage: EllipticCurve([0, 0, 1, -79, 342]).regulator(proof=False) # long time (6s on sage.math, 2011) 14.790527570131... """ - if precision is None: - RR = rings.RealField() - precision = RR.precision() - else: - RR = rings.RealField(precision) + R = rings.RealField(precision) if proof is None: from sage.structure.proof.proof import get_flag @@ -2475,29 +2497,23 @@ def regulator(self, use_database=True, proof=None, precision=None, proof = bool(proof) # We return a cached value if it exists and has sufficient precision: - try: - reg = self.__regulator[proof] - if reg.parent().precision() >= precision: - return RR(reg) - else: # Found regulator value but precision is too low - pass - except KeyError: - if proof is False and True in self.__regulator: - reg = self.__regulator[True] - if reg.parent().precision() >= precision: - return RR(reg) - else: # Found regulator value but precision is too low + if self.__regulator: + reg, proven = self.__regulator + if proven or not proof: + # Coerce to the target field R. This will fail if the + # precision was too low. + try: + return R.coerce(reg) + except TypeError: pass - # Next we find the gens, taking them from the database if they - # are there and use_database is True, else computing them: - - G = self.gens(proof=proof, use_database=use_database, descent_second_limit=descent_second_limit, verbose=verbose) - - # Finally compute the regulator of the generators found: + G = self.gens(proof=proof, **kwds) - self.__regulator[proof] = self.regulator_of_points(G,precision=precision) - return self.__regulator[proof] + # Compute the regulator of the generators found: + reg = self.regulator_of_points(G, precision=precision) + self.__regulator = (reg, self.gens_certain()) + assert reg.parent() is R + return reg def saturation(self, points, verbose=False, max_prime=0, odd_primes_only=False): """ @@ -2838,7 +2854,6 @@ def point_search(self, height_limit, verbose=False, rank_bound=None): points = self.saturation(points, verbose=verbose)[0] return points - def selmer_rank(self): """ The rank of the 2-Selmer group of the curve. @@ -2886,7 +2901,6 @@ def selmer_rank(self): self.__selmer_rank = C.selmer_rank() return self.__selmer_rank - def rank_bound(self): """ Upper bound on the rank of the curve, computed using @@ -2921,7 +2935,6 @@ def rank_bound(self): self.__rank_bound = C.rank_bound() return self.__rank_bound - def an(self, n): """ The n-th Fourier coefficient of the modular form corresponding to diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 42032e76e3c..e0473b9b51c 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -115,46 +115,6 @@ from sage.libs.all import pari -# Do we need to work around the PARI ellwp() bug? -_ellwp_factor2 = None - -def _ellwp_flag1(lattice, z): - """ - Evaluate the Weierstrass P function attached to the lattice - ``lattice`` and its derivative at ``z``. - - This calls the PARI function ``ellwp(..., flag=1)``, working around - a bug in PARI versions <= 2.9.3 where the derivative is a factor 2 - too small. - - OUTPUT: ``(P(z), P'(z))`` - - TESTS:: - - sage: from sage.schemes.elliptic_curves.period_lattice import _ellwp_flag1 - sage: E = EllipticCurve([0, 1]) - sage: _ellwp_flag1(E, E((0,1)).elliptic_logarithm()) - (-7.718602... E-30, 2.00000000000000) - """ - global _ellwp_factor2 - if _ellwp_factor2 is None: - # Check whether our PARI/GP version is buggy or not. This - # computation should return 1.0, but in older PARI versions it - # returns 0.5 - d = float(pari("my(E=ellinit([0,1/4]));ellwp(E,ellpointtoz(E,[0,1/2]),1)[2]")) - if d == 1.0: - _ellwp_factor2 = False - elif d == 0.5: - _ellwp_factor2 = True - else: - raise AssertionError("unexpected result from ellwp() test: {}".format(d)) - x, y = pari.ellwp(lattice, z, 1) - if _ellwp_factor2: - return (x, 2*y) - else: - return (x, y) - - class PeriodLattice(FreeModule_generic_pid): """ The class for the period lattice of an algebraic variety. @@ -643,7 +603,6 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): periods = self.E.pari_curve().omega(prec).sage() return (R(periods[0]), C(periods[1])) - from sage.libs.pari.all import pari E_pari = pari([R(self.embedding(ai).real()) for ai in self.E.a_invariants()]).ellinit() periods = E_pari.omega(prec).sage() return (R(periods[0]), C(periods[1])) @@ -1819,7 +1778,7 @@ def elliptic_exponential(self, z, to_curve=True): # So we force the results back into the real/complex fields of # the same precision as the input. - x, y = _ellwp_flag1(self.basis(prec=prec), z) + x, y = pari(self.basis(prec=prec)).ellwp(z, flag=1) x, y = [C(t) for t in (x,y)] if self.real_flag and z_is_real: diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 11b85824fa0..5754b306eca 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -2072,12 +2072,9 @@ def _number_field_from_algebraics(self): sage: H = End(P) sage: f = H([QQbar(3^(1/3))*x^2 + QQbar(sqrt(-2))*y^2, y^2]) sage: f._number_field_from_algebraics() - Scheme endomorphism of Projective Space of dimension 1 over Number Field - in a with defining polynomial y^6 + 6*y^4 + 6*y^3 + 12*y^2 - 36*y + 17 + Scheme endomorphism of Projective Space of dimension 1 over Number Field in a with defining polynomial y^6 + 6*y^4 - 6*y^3 + 12*y^2 + 36*y + 17 Defn: Defined on coordinates by sending (z0 : z1) to - ((48/269*a^5 + 27/269*a^4 + 320/269*a^3 + 468/269*a^2 + 772/269*a - - 1092/269)*z0^2 + (48/269*a^5 + 27/269*a^4 + 320/269*a^3 + 468/269*a^2 - + 1041/269*a - 1092/269)*z1^2 : z1^2) + ((-48/269*a^5 + 27/269*a^4 - 320/269*a^3 + 468/269*a^2 - 772/269*a - 1092/269)*z0^2 + (48/269*a^5 - 27/269*a^4 + 320/269*a^3 - 468/269*a^2 + 1041/269*a + 1092/269)*z1^2 : z1^2) :: diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 46947def602..067d3d4a712 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -828,6 +828,7 @@ cdef class CategoryObject(SageObject): running ._test_enumerated_set_iter_list() . . . pass running ._test_eq() . . . pass running ._test_euclidean_degree() . . . pass + running ._test_fraction_field() . . . pass running ._test_gcd_vs_xgcd() . . . pass running ._test_metric() . . . pass running ._test_new() . . . pass @@ -891,6 +892,7 @@ cdef class CategoryObject(SageObject): _test_enumerated_set_iter_list _test_eq _test_euclidean_degree + _test_fraction_field _test_gcd_vs_xgcd _test_metric _test_new diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index 819963968a9..43fe75d9ee2 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -19,9 +19,6 @@ cpdef inline parent(x): - If ``x`` is a Sage :class:`Element`, return ``x.parent()``. - - If ``x`` has a ``parent`` method and ``x`` does not have an - ``__int__`` or ``__float__`` method, return ``x.parent()``. - - Otherwise, return ``type(x)``. .. SEEALSO:: @@ -62,15 +59,7 @@ cpdef inline parent(x): """ if isinstance(x, Element): return (x)._parent - # Fast check for "number" types, including int and float - if PyNumber_Check(x): - return type(x) - try: - p = x.parent - except AttributeError: - return type(x) - else: - return p() + return type(x) cdef inline int classify_elements(left, right): diff --git a/src/sage/symbolic/expression.pxd b/src/sage/symbolic/expression.pxd index 1c38335bbbc..0dfe83295eb 100644 --- a/src/sage/symbolic/expression.pxd +++ b/src/sage/symbolic/expression.pxd @@ -17,6 +17,8 @@ cdef class Expression(CommutativeRingElement): cpdef Expression _subs_expr(self, expr) cpdef int _cmp_add(Expression left, Expression right) except -2 cpdef int _cmp_mul(Expression left, Expression right) except -2 + cdef bint _rel_equal1(Expression self, Expression other) except -1 + cdef bint _rel_equal2(Expression self, Expression other) except -1 cpdef bint is_Expression(x) cdef Expression new_Expression_from_GEx(parent, GEx juice) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index c2ddd699130..3f5dee54bee 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -138,6 +138,7 @@ Test if :trac:`9947` is fixed:: from __future__ import print_function, absolute_import from cysignals.signals cimport sig_on, sig_off +from sage.ext.cplusplus cimport ccrepr, ccreadstr from inspect import ismethod import operator @@ -399,7 +400,7 @@ cdef class Expression(CommutativeRingElement): cdef GConstant* c if is_a_constant(self._gobj): from sage.symbolic.constants import constants_name_table - return constants_name_table[GEx_to_str(&self._gobj)] + return constants_name_table[ccrepr(self._gobj)] if is_a_infinity(self._gobj): if (ex_to_infinity(self._gobj).is_unsigned_infinity()): return unsigned_infinity @@ -467,8 +468,7 @@ cdef class Expression(CommutativeRingElement): """ cdef GArchive ar ar.archive_ex(self._gobj, "sage_ex") - ar_str = GArchive_to_str(&ar) - return (0, map(repr, self.variables()), ar_str) + return (0, [repr(x) for x in self.variables()], ccrepr(ar)) def _dbgprint(self): r""" @@ -479,7 +479,11 @@ cdef class Expression(CommutativeRingElement): sage: (1+x)._dbgprint() x + 1 """ - self._gobj.dbgprint() + sig_on() + try: + self._gobj.dbgprint() + finally: + sig_off() def _dbgprinttree(self): r""" @@ -532,7 +536,11 @@ cdef class Expression(CommutativeRingElement): x (symbol) ... ===== """ - self._gobj.dbgprinttree(); + sig_on() + try: + self._gobj.dbgprinttree() + finally: + sig_off() def __setstate__(self, state): """ @@ -570,7 +578,7 @@ cdef class Expression(CommutativeRingElement): # initialize archive cdef GArchive ar - GArchive_from_str(&ar, state[2], len(state[2])) + ccreadstr(ar, state[2]) # extract the expression from the archive self._gobj = GEx(ar.unarchive_ex(sym_lst, 0)) @@ -1180,7 +1188,7 @@ cdef class Expression(CommutativeRingElement): -3.00000000000000 sage: cos(I)._eval_self(RR) 1.54308063481524 - sage: float(cos(I)) + sage: float(cos(I)) # abs tol 1e-15 1.5430806348152437 TESTS:: @@ -1189,9 +1197,8 @@ cdef class Expression(CommutativeRingElement): sage: e._eval_self(float) 0.9036020036... """ - cdef GEx res try: - res = self._gobj.evalf(0, {'parent':R}) + res = self._convert({'parent':R}) except TypeError as err: # try the evaluation again with the complex field # corresponding to the parent R @@ -1202,9 +1209,10 @@ cdef class Expression(CommutativeRingElement): R_complex = R.complex_field() except (TypeError, AttributeError): raise err - res = self._gobj.evalf(0, {'parent':R_complex}) - if is_a_numeric(res): - ans = py_object_from_numeric(res) + res = self._convert({'parent':R_complex}) + + if res.is_numeric(): + ans = res.pyobject() # Convert ans to R. if R is float and isinstance(ans, complex) and not ans.imag: # Python does not automatically convert "real" complex @@ -1259,7 +1267,12 @@ cdef class Expression(CommutativeRingElement): sage: f._convert({'parent':int}) 0 """ - cdef GEx res = self._gobj.evalf(0, kwds) + cdef GEx res + sig_on() + try: + res = self._gobj.evalf(0, kwds) + finally: + sig_off() return new_Expression_from_GEx(self._parent, res) def _mpfr_(self, R): @@ -1583,7 +1596,33 @@ cdef class Expression(CommutativeRingElement): sage: hash(unsigned_infinity) == hash(SR(unsigned_infinity)) True """ - return self._gobj.gethash() + sig_on() + try: + return self._gobj.gethash() + finally: + sig_off() + + cdef bint _rel_equal1(Expression self, Expression other) except -1: + """ + Internal helper function. + """ + sig_on() + try: + return (self._gobj.lhs().is_equal(other._gobj.lhs()) + and self._gobj.rhs().is_equal(other._gobj.rhs())) + finally: + sig_off() + + cdef bint _rel_equal2(Expression self, Expression other) except -1: + """ + Internal helper function. + """ + sig_on() + try: + return (self._gobj.lhs().is_equal(other._gobj.rhs()) + and self._gobj.rhs().is_equal(other._gobj.lhs())) + finally: + sig_off() cpdef _richcmp_(left, right, int op): """ @@ -1656,15 +1695,12 @@ cdef class Expression(CommutativeRingElement): # both lhs and rhs are relations, so we can get to work if l.operator() == r.operator(): e2 = ( # case: (x _ y) ?= (x _ y) - ( l._gobj.lhs().is_equal(r._gobj.lhs()) and - l._gobj.rhs().is_equal(r._gobj.rhs()) ) or - + left._rel_equal1(right) or # case: (x == y) ?= (y == x) # (x != y) ?= (y != x) ( ( l.operator() == operator.eq or l.operator() == operator.ne ) and - l._gobj.lhs().is_equal(r._gobj.rhs()) and - l._gobj.rhs().is_equal(r._gobj.lhs()) )) + left._rel_equal2(right) )) else: e2 = ( # case: (x < y) ?= (y > x) (or vice versa) # (x <= y) ?= (y >= x) (or vice versa) @@ -1676,9 +1712,7 @@ cdef class Expression(CommutativeRingElement): r.operator() == operator.ge ) or ( l.operator() == operator.ge and r.operator() == operator.le ) ) and - l._gobj.lhs().is_equal(r._gobj.rhs()) and - l._gobj.rhs().is_equal(r._gobj.lhs()) ) - + left._rel_equal2(right) ) else: e2 = False # l is relational but r isn't. @@ -2354,7 +2388,11 @@ cdef class Expression(CommutativeRingElement): False """ cdef Expression symbol0 = self.coerce_in(var) - return self._gobj.is_polynomial(symbol0._gobj) + sig_on() + try: + return self._gobj.is_polynomial(symbol0._gobj) + finally: + sig_off() cpdef bint is_relational(self): """ @@ -4830,7 +4868,12 @@ cdef class Expression(CommutativeRingElement): """ cdef Expression p = self.coerce_in(pattern) cdef GExList mlst - cdef bint res = self._gobj.match(p._gobj, mlst) + cdef bint res + sig_on() + try: + res = self._gobj.match(p._gobj, mlst) + finally: + sig_off() if not res: return None @@ -4879,7 +4922,11 @@ cdef class Expression(CommutativeRingElement): from sage.symbolic.comparison import print_sorted cdef Expression p = self.coerce_in(pattern) cdef GExList found - self._gobj.find(p._gobj, found) + sig_on() + try: + self._gobj.find(p._gobj, found) + finally: + sig_off() res = [] cdef GExListIter itr = found.begin() while itr != found.end(): @@ -5172,6 +5219,7 @@ cdef class Expression(CommutativeRingElement): (x, y, t) |--> x^2 + y^2 + t + cos(x) + sin(y) """ cdef dict sdict = {} + cdef GEx res if args and args[0] is None: # this is needed because sometimes this function get called as @@ -5193,9 +5241,12 @@ cdef class Expression(CommutativeRingElement): for k, v in sdict.iteritems(): smap.insert(make_pair((self.coerce_in(k))._gobj, (self.coerce_in(v))._gobj)) - - return new_Expression_from_GEx(self._parent, - self._gobj.subs_map(smap, 0)) + sig_on() + try: + res = self._gobj.subs_map(smap, 0) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, res) subs = substitute @@ -5242,8 +5293,13 @@ cdef class Expression(CommutativeRingElement): x - 1 """ cdef Expression p = self.coerce_in(expr) - return new_Expression_from_GEx(self._parent, self._gobj.subs(p._gobj)) - + cdef GEx res + sig_on() + try: + res = self._gobj.subs(p._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, res) substitute_expression = deprecated_function_alias(12834, substitute) subs_expr = deprecated_function_alias(12834, subs) @@ -6096,6 +6152,7 @@ cdef class Expression(CommutativeRingElement): """ cdef Expression ss = self.coerce_in(s) cdef Expression nn = self.coerce_in(n) + cdef GEx r if n != 1 and not is_a_symbol(ss._gobj): raise TypeError("n != 1 only allowed for s being a variable") @@ -6105,7 +6162,12 @@ cdef class Expression(CommutativeRingElement): for i from 0 <= i < ss._gobj.nops(): res = res.coefficient(new_Expression_from_GEx(self._parent, ss._gobj.op(i))) return res - return new_Expression_from_GEx(self._parent, self._gobj.coeff(ss._gobj, nn._gobj)) + sig_on() + try: + r = self._gobj.coeff(ss._gobj, nn._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) coeff = deprecated_function_alias(17438, coefficient) @@ -6207,7 +6269,11 @@ cdef class Expression(CommutativeRingElement): if x is None: x = self.default_variable() xx = self.coerce_in(x) - self._gobj.coefficients(xx._gobj, vec) + sig_on() + try: + self._gobj.coefficients(xx._gobj, vec) + finally: + sig_off() l = [] for p in vec: l.append([new_Expression_from_GEx(self._parent, p.first), @@ -6282,7 +6348,13 @@ cdef class Expression(CommutativeRingElement): x^3 + 2/x """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.lcoeff(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.lcoeff(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) leading_coeff = leading_coefficient @@ -6305,7 +6377,13 @@ cdef class Expression(CommutativeRingElement): a*x + x*y + x/y + 100 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.tcoeff(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.tcoeff(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) trailing_coeff = trailing_coefficient @@ -6333,7 +6411,12 @@ cdef class Expression(CommutativeRingElement): 0 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, GEx(self._gobj.ldegree(ss._gobj))) + sig_on() + try: + return new_Expression_from_GEx(self._parent, + GEx(self._gobj.ldegree(ss._gobj))) + finally: + sig_off() def degree(self, s): """ @@ -6359,7 +6442,12 @@ cdef class Expression(CommutativeRingElement): 0 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, GEx(self._gobj.degree(ss._gobj))) + sig_on() + try: + return new_Expression_from_GEx(self._parent, + GEx(self._gobj.degree(ss._gobj))) + finally: + sig_off() def unit(self, s): """ @@ -6392,7 +6480,13 @@ cdef class Expression(CommutativeRingElement): -1 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.unit(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.unit(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def content(self, s): """ @@ -6431,7 +6525,13 @@ cdef class Expression(CommutativeRingElement): 2 """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.content(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.content(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def primitive_part(self, s): """ @@ -6465,7 +6565,13 @@ cdef class Expression(CommutativeRingElement): x + 2*sin(y) """ cdef Expression ss = self.coerce_in(s) - return new_Expression_from_GEx(self._parent, self._gobj.primpart(ss._gobj)) + cdef GEx r + sig_on() + try: + r = self._gobj.primpart(ss._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def unit_content_primitive(self, s): """ @@ -6496,7 +6602,11 @@ cdef class Expression(CommutativeRingElement): """ cdef Expression ss = self.coerce_in(s) cdef GEx unit, cont, prim - self._gobj.unitcontprim(ss._gobj, unit, cont, prim) + sig_on() + try: + self._gobj.unitcontprim(ss._gobj, unit, cont, prim) + finally: + sig_off() return (new_Expression_from_GEx(self._parent, unit), new_Expression_from_GEx(self._parent, cont), new_Expression_from_GEx(self._parent, prim)) @@ -7387,7 +7497,13 @@ cdef class Expression(CommutativeRingElement): sage: abs(pi+i) abs(pi + I) """ - return new_Expression_from_GEx(self._parent, g_abs(self._gobj)) + cdef GEx r + sig_on() + try: + r = g_abs(self._gobj) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def abs(self, hold=False): """ @@ -8948,8 +9064,13 @@ cdef class Expression(CommutativeRingElement): sage: (1+sin((x + 1)/x - 1/x)).combine(deep=True) sin(1) + 1 """ - return new_Expression_from_GEx(self._parent, - self._gobj.combine_fractions(deep)) + cdef GEx r + sig_on() + try: + r = self._gobj.combine_fractions(deep) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def normalize(self): """ @@ -8992,7 +9113,13 @@ cdef class Expression(CommutativeRingElement): ALGORITHM: Uses GiNaC. """ - return new_Expression_from_GEx(self._parent, self._gobj.normal(0, False, True)) + cdef GEx r + sig_on() + try: + r = self._gobj.normal(0, False, True) + finally: + sig_off() + return new_Expression_from_GEx(self._parent, r) def numerator(self, bint normalize = True): """ @@ -9061,9 +9188,14 @@ cdef class Expression(CommutativeRingElement): TypeError: self is not a rational expression """ cdef GExVector vec - cdef GEx oper, power + cdef GEx oper, power, ex if normalize: - return new_Expression_from_GEx(self._parent, self._gobj.numer()) + sig_on() + try: + ex = self._gobj.numer() + finally: + sig_off() + return new_Expression_from_GEx(self._parent, ex) elif is_a_mul(self._gobj): for i from 0 <= i < self._gobj.nops(): oper = self._gobj.op(i) @@ -9148,7 +9280,12 @@ cdef class Expression(CommutativeRingElement): cdef GExVector vec cdef GEx oper, ex, power if normalize: - return new_Expression_from_GEx(self._parent, self._gobj.denom()) + sig_on() + try: + ex = self._gobj.denom() + finally: + sig_off() + return new_Expression_from_GEx(self._parent, ex) elif is_a_mul(self._gobj): for i from 0 <= i < self._gobj.nops(): oper = self._gobj.op(i) @@ -9235,7 +9372,11 @@ cdef class Expression(CommutativeRingElement): cdef GEx oper, ex, power cdef GNumeric power_num if normalize: - ex = self._gobj.numer_denom() + sig_on() + try: + ex = self._gobj.numer_denom() + finally: + sig_off() return (new_Expression_from_GEx(self._parent, ex.op(0)), new_Expression_from_GEx(self._parent, ex.op(1))) elif is_a_mul(self._gobj): diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index f668c30558c..0d7e6036374 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -14,6 +14,8 @@ The symbolic ring #***************************************************************************** from __future__ import absolute_import +from sage.ext.cplusplus cimport ccrepr + from sage.libs.pynac.pynac cimport * from sage.rings.integer cimport Integer @@ -881,7 +883,7 @@ cdef class SymbolicRing(CommutativeRing): sage: SR._repr_element_(x+2) 'x + 2' """ - return GEx_to_str(&x._gobj) + return ccrepr(x._gobj) def _latex_element_(self, Expression x): """ diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 12d5042b7ec..2d52dd1613e 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -778,14 +778,18 @@ def __init__(self, ring, rank, name=None, latex_name=None, start_index=0, self._sindex = start_index self._output_formatter = output_formatter # Dictionary of the tensor modules built on self - # (keys = (k,l) --the tensor type) : - self._tensor_modules = {(1,0): self} # self is considered as the set of - # tensors of type (1,0) - # Dictionary of exterior powers of self and of the dual of self: - # (keys = p --the power degree) : - self._exterior_powers = {} + # (keys = (k,l) --the tensor type) + # This dictionary is to be extended on need by the method tensor_module + self._tensor_modules = {(1,0): self} # self is considered as the set + # of tensors of type (1,0) + # Dictionaries of exterior powers of self and of its dual + # (keys = p --the power degree) + # These dictionaries are to be extended on need by the methods + # exterior_power and dual_exterior_power + self._exterior_powers = {1: self} self._dual_exterior_powers = {} - self._known_bases = [] # List of known bases on the free module + # List of known bases on the free module: + self._known_bases = [] self._def_basis = None # default basis self._basis_changes = {} # Dictionary of the changes of bases # Zero element: @@ -1021,8 +1025,6 @@ def exterior_power(self, p): from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule if p == 0: return self._ring - if p == 1: - return self if p not in self._exterior_powers: self._exterior_powers[p] = ExtPowerFreeModule(self, p) return self._exterior_powers[p] diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index 5a34f03a31f..9233350897e 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -266,15 +266,17 @@ def __init__(self, fmodule, symbol, latex_symbol=None): # Initialization of the components w.r.t the current basis of the zero # elements of all tensor modules constructed up to now (including the # base module itself, since it is considered as a type-(1,0) tensor - # module) + # module): for t in fmodule._tensor_modules.values(): t._zero_element._components[self] = t._zero_element._new_comp(self) # (since new components are initialized to zero) # Initialization of the components w.r.t the current basis of the zero - # elements of all exterior powers constructed up to now + # elements of all exterior powers of the module and its dual + # constructed up to now: + for t in fmodule._exterior_powers.values(): + t._zero_element._components[self] = t._zero_element._new_comp(self) for t in fmodule._dual_exterior_powers.values(): t._zero_element._components[self] = t._zero_element._new_comp(self) - # (since new components are initialized to zero) # The dual basis: self._dual_basis = self._init_dual_basis() diff --git a/src/sage/tests/books/judson-abstract-algebra/fields-sage.py b/src/sage/tests/books/judson-abstract-algebra/fields-sage.py index e9f2ea3309d..529d6e823bb 100644 --- a/src/sage/tests/books/judson-abstract-algebra/fields-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/fields-sage.py @@ -274,10 +274,12 @@ ~~~~~~~~~~~~~~~~~~~~~~ :: sage: r1.as_number_field_element() - (Number Field in a with defining polynomial y^4 + y^2 - 1, a, Ring morphism: - From: Number Field in a with defining polynomial y^4 + y^2 - 1 - To: Algebraic Real Field - Defn: a |--> -0.7861513777574233?) + (Number Field in a with defining polynomial y^4 - y^2 - 1, + a^3 - a, + Ring morphism: + From: Number Field in a with defining polynomial y^4 - y^2 - 1 + To: Algebraic Real Field + Defn: a |--> -1.272019649514069?) ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/version.py b/src/sage/version.py index aaec001d8c5..b74807859b3 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,4 +1,4 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '8.1.beta7' -date = '2017-10-03' +version = '8.1.beta8' +date = '2017-10-16'