diff --git a/VERSION.txt b/VERSION.txt index 7f6d87da9b8..2c62fdb1942 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 8.8.beta5, Release Date: 2019-05-11 +SageMath version 8.8.beta6, Release Date: 2019-05-22 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index dd3949c7058..23e36b6227c 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=75b58f92f04eac5ac6d680de929111518e9769f4 -md5=c349a0f3533c5e8ec809b9a20eac89f2 -cksum=2447773146 +sha1=c91befc71803600bcfcfa5637b8330f65dcf594c +md5=eee7fd54b6aa2131981ab46442fe09a0 +cksum=2162906054 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 9b5c4542c79..18eed1357e5 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -319 +320 diff --git a/build/pkgs/jupymake/SPKG.txt b/build/pkgs/jupymake/SPKG.txt new file mode 100644 index 00000000000..f5a98bf06fc --- /dev/null +++ b/build/pkgs/jupymake/SPKG.txt @@ -0,0 +1,20 @@ += jupymake = + +== Description == + +The Python module JuPyMake provides an interface to polymake. + +== License == + + * GPL v2 + +== Upstream Contact == + + https://github.com/polymake/JuPyMake + +== Dependencies == + + * pip + * polymake + +== Special Update/Build Instructions == diff --git a/build/pkgs/jupymake/checksums.ini b/build/pkgs/jupymake/checksums.ini new file mode 100644 index 00000000000..9e697f2a1dc --- /dev/null +++ b/build/pkgs/jupymake/checksums.ini @@ -0,0 +1,4 @@ +tarball=JuPyMake-VERSION.tar.gz +sha1=0dc4e4a29afbdc733908249cd28b7ed4c4ab8b73 +md5=646f0c6c91166ea84e233587fc2dec1e +cksum=4049738923 diff --git a/build/pkgs/jupymake/package-version.txt b/build/pkgs/jupymake/package-version.txt new file mode 100644 index 00000000000..b63ba696b7a --- /dev/null +++ b/build/pkgs/jupymake/package-version.txt @@ -0,0 +1 @@ +0.9 diff --git a/build/pkgs/jupymake/spkg-install b/build/pkgs/jupymake/spkg-install new file mode 100644 index 00000000000..4892b22fc93 --- /dev/null +++ b/build/pkgs/jupymake/spkg-install @@ -0,0 +1,15 @@ +if [ "$SAGE_LOCAL" = "" ]; then + echo "SAGE_LOCAL undefined ... exiting"; + echo "Maybe run 'sage -sh'?" + exit 1 +fi + +#Install new version +cd src + +sdh_pip_install . + +if [ $? -ne 0 ]; then + echo "Error installing JuPyMake." + exit 1 +fi diff --git a/build/pkgs/jupymake/type b/build/pkgs/jupymake/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/jupymake/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/libpng/SPKG.txt b/build/pkgs/libpng/SPKG.txt index fd1619c178c..177fd285291 100644 --- a/build/pkgs/libpng/SPKG.txt +++ b/build/pkgs/libpng/SPKG.txt @@ -27,9 +27,11 @@ This spkg depends on: == Special Update/Build Instructions == - * On Darwin, the symbolic links libpng.* created by libpng16 may + * On old versions of Darwin, the symbolic links libpng.* created by libpng16 may interfere with a system-wide libPng.dylib. + --- the following is very likely to be obsolete in 2014 --- + This system-wide library is likely to be a different version and on top of that, the symbols exported there are prefixed with "_cg" (for "Core Graphics"). So even if by chance the functionalities of @@ -46,6 +48,8 @@ This spkg depends on: - when Mercurial is built because it uses $EDITOR, cf. #4678; - when R is built and it finds -lpng, cf. #4409 and #11696. + --- this is no longer done, as of #27186 --- + As not all of these problems are easily dealt with and new ones may arise, we chose to delete the $SAGE_LOCAL/lib/libpng.* symlinks. Therefore, some packages like Tachyon, which by default look for diff --git a/build/pkgs/libpng/package-version.txt b/build/pkgs/libpng/package-version.txt index 274ef150522..23b5c1f9732 100644 --- a/build/pkgs/libpng/package-version.txt +++ b/build/pkgs/libpng/package-version.txt @@ -1 +1 @@ -1.6.29.p0 +1.6.29.p1 diff --git a/build/pkgs/libpng/spkg-configure.m4 b/build/pkgs/libpng/spkg-configure.m4 new file mode 100644 index 00000000000..bd7402ff3b2 --- /dev/null +++ b/build/pkgs/libpng/spkg-configure.m4 @@ -0,0 +1,16 @@ +SAGE_SPKG_CONFIGURE([libpng], [ + AC_REQUIRE([SAGE_SPKG_CONFIGURE_ZLIB]) + AC_MSG_CHECKING([Installing zlib? ]) + if test x$sage_spkg_install_zlib = xyes; then + AC_MSG_RESULT([Yes. Install libpng as well.]) + sage_spkg_install_libpng=yes + else + AC_MSG_RESULT([No.]) + dnl First try checking for libpng with pkg-config + PKG_CHECK_MODULES([LIBPNG], [libpng >= 1.2], [], [ + dnl Fallback to manually grubbing around for headers and libs + AC_CHECK_HEADERS([png.h], [break], [sage_spkg_install_libpng=yes]) + AC_SEARCH_LIBS([png_get_io_ptr], [png], [], [sage_spkg_install_libpng=yes]) + ]) + fi +]) diff --git a/build/pkgs/libpng/spkg-install b/build/pkgs/libpng/spkg-install index f708e1f6da9..75a47f7fca5 100644 --- a/build/pkgs/libpng/spkg-install +++ b/build/pkgs/libpng/spkg-install @@ -16,6 +16,3 @@ cd src sdh_configure --enable-shared=yes sdh_make sdh_make_install - -# Delete libpng.* symlinks, see SPKG.txt for details -rm -f "$SAGE_DESTDIR_LOCAL"/lib/libpng.* diff --git a/build/pkgs/lrslib/package-version.txt b/build/pkgs/lrslib/package-version.txt index bf0d57af6fa..54baf794ad3 100644 --- a/build/pkgs/lrslib/package-version.txt +++ b/build/pkgs/lrslib/package-version.txt @@ -1 +1 @@ -062+autotools-2017-03-03.p0 +062+autotools-2017-03-03.p1 diff --git a/build/pkgs/lrslib/spkg-install b/build/pkgs/lrslib/spkg-install index 30dacb8b8e4..14a634cc5e5 100644 --- a/build/pkgs/lrslib/spkg-install +++ b/build/pkgs/lrslib/spkg-install @@ -1,4 +1,4 @@ cd src/ -sdh_configure +sdh_configure CPPFLAGS="-DLRS_QUIET $CPPFLAGS" sdh_make sdh_make_install diff --git a/build/pkgs/ninja_build/spkg-configure.m4 b/build/pkgs/ninja_build/spkg-configure.m4 new file mode 100644 index 00000000000..1176e8b95e7 --- /dev/null +++ b/build/pkgs/ninja_build/spkg-configure.m4 @@ -0,0 +1,15 @@ +SAGE_SPKG_CONFIGURE( + [ninja_build], [ + AC_CACHE_CHECK([for ninja >= 1.7.2], [ac_cv_path_NINJA], [ + AC_PATH_PROGS_FEATURE_CHECK([NINJA], [ninja], [ + ninja_version=`$ac_path_NINJA --version 2>&1 \ + | $SED -n -e 's/\([[0-9]]*\.[[0-9]]*\.[[0-9]]*\).*/\1/p'` + AS_IF([test -n "$ninja_version"], [ + AX_COMPARE_VERSION([$ninja_version], [ge], [1.7.2], [ + ac_cv_path_NINJA="$ac_path_NINJA" + ]) + ]) + ]) + ]) + AS_IF([test -z "$ac_cv_path_NINJA"], [sage_spkg_install_ninja_build=yes]) +]) diff --git a/build/pkgs/normaliz/checksums.ini b/build/pkgs/normaliz/checksums.ini index 8bb0e8c82c8..4c2a623043c 100644 --- a/build/pkgs/normaliz/checksums.ini +++ b/build/pkgs/normaliz/checksums.ini @@ -1,4 +1,4 @@ tarball=normaliz-VERSION.tar.gz -sha1=5c8ba35446d2306ed6e2a7944776711c7569a80a -md5=5f450845141a1d9baddb143b48a0cc3a -cksum=289674826 +sha1=ab5c5c5653061e8223da511114871850e799f30d +md5=504b249df9552a5d4a336c630fb9f4b4 +cksum=566272739 diff --git a/build/pkgs/normaliz/package-version.txt b/build/pkgs/normaliz/package-version.txt index a76ccff2a6e..0b2eb36f508 100644 --- a/build/pkgs/normaliz/package-version.txt +++ b/build/pkgs/normaliz/package-version.txt @@ -1 +1 @@ -3.7.1 +3.7.2 diff --git a/build/pkgs/normaliz/spkg-install b/build/pkgs/normaliz/spkg-install index c9bd7c4a723..496fe6ea1c9 100644 --- a/build/pkgs/normaliz/spkg-install +++ b/build/pkgs/normaliz/spkg-install @@ -3,7 +3,7 @@ cd src # Disable features that require packages SCIP and CoCoA, both of which # are experimental packages. -# FLINT is a standard package and E-ANTIC is a standard pakcage. We +# FLINT is a standard package and E-ANTIC is an optional package. We # pass --enable-flint and --enable-enfnormaliz to configure so # that an error will be signalled if FLINT or E-ANTIC cannot be found, rather # than building normaliz without it. diff --git a/build/pkgs/polymake/SPKG.txt b/build/pkgs/polymake/SPKG.txt index 38761197b9f..2a20c29f8a6 100644 --- a/build/pkgs/polymake/SPKG.txt +++ b/build/pkgs/polymake/SPKG.txt @@ -35,7 +35,7 @@ On Ubuntu/Debian, use: sudo apt-get install libxml-libxslt-perl libxml-writer-perl libxml2-dev libperl-dev libfile-slurp-perl libjson-perl libsvg-perl libterm-readkey-perl libterm-readline-gnu-perl libmongodb-perl On Fedora 23, use: - sudo yum install perl-ExtUtils-Embed perl-File-Slurp perl-JSON perl-MongoDB + sudo yum install perl-ExtUtils-Embed perl-File-Slurp perl-JSON perl-MongoDB perl-Term-ReadLine-Gnu On Gentoo, use emerge --ask XML-Writer XML-LibXML XML-LibXSLT File-Slurp dev-perl/Term-ReadLine-Gnu JSON SVG dev-perl/MongoDB diff --git a/build/pkgs/polymake/patches/0001-bundled-libnormaliz-support-configure.pl-Conditional.patch b/build/pkgs/polymake/patches/0001-bundled-libnormaliz-support-configure.pl-Conditional.patch index 283864811c6..1c85673467f 100644 --- a/build/pkgs/polymake/patches/0001-bundled-libnormaliz-support-configure.pl-Conditional.patch +++ b/build/pkgs/polymake/patches/0001-bundled-libnormaliz-support-configure.pl-Conditional.patch @@ -1,7 +1,7 @@ From ddef1df5781ad60d65de71e7689b56dfad7288b5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Apr 2019 14:59:19 +0200 -Subject: [PATCH] bundled/libnormaliz/support/configure.pl: Conditionalize +Subject: [PATCH 1/3] bundled/libnormaliz/support/configure.pl: Conditionalize include of omp.h on _OPENMP --- diff --git a/build/pkgs/polymake/patches/0002-Add-PERL_SET_CONTEXT-for-thread-correctness.patch b/build/pkgs/polymake/patches/0002-Add-PERL_SET_CONTEXT-for-thread-correctness.patch new file mode 100644 index 00000000000..a6b1c38614d --- /dev/null +++ b/build/pkgs/polymake/patches/0002-Add-PERL_SET_CONTEXT-for-thread-correctness.patch @@ -0,0 +1,128 @@ +From 51f36ef29e7d2482c23ea4da697e626cc61da611 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Thu, 2 May 2019 13:31:00 +0200 +Subject: [PATCH 2/3] Add PERL_SET_CONTEXT for thread correctness + +--- + lib/callable/src/perl/methods.cc | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/lib/callable/src/perl/methods.cc b/lib/callable/src/perl/methods.cc +index 11beefb2..fccf63b7 100644 +--- a/lib/callable/src/perl/methods.cc ++++ b/lib/callable/src/perl/methods.cc +@@ -40,6 +40,7 @@ const char Extension[]="Polymake::Core::Extension"; + void Main::set_application(const AnyString& appname) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(1); + mPUSHp(appname.ptr, appname.len); + PUTBACK; +@@ -49,6 +50,7 @@ void Main::set_application(const AnyString& appname) + void Main::set_application_of(const Object& x) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(1); + PUSHs(x.obj_ref); + PUTBACK; +@@ -58,6 +60,7 @@ void Main::set_application_of(const Object& x) + void Main::add_extension(const AnyString& path) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(2); + mPUSHp(Extension, sizeof(Extension)-1); + mPUSHp(path.ptr, path.len); +@@ -83,6 +86,7 @@ void Main::reset_preference(const AnyString& label_exp) + SV* Main::lookup_extension(const AnyString& path) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(2); + mPUSHp(Extension, sizeof(Extension)-1); + mPUSHp(path.ptr, path.len); +@@ -93,6 +97,7 @@ SV* Main::lookup_extension(const AnyString& path) + void Main::call_app_method(const char* method, const AnyString& arg) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(2); + SV* const app=glue::get_current_application(aTHX); + PUSHs(app); +@@ -104,6 +109,7 @@ void Main::call_app_method(const char* method, const AnyString& arg) + void Main::set_custom_var(const AnyString& name, const AnyString& key, Value& x) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(3); + mPUSHp(name.ptr, name.len); + if (key.ptr) mPUSHp(key.ptr, key.len); +@@ -115,6 +121,7 @@ void Main::set_custom_var(const AnyString& name, const AnyString& key, Value& x) + void Main::reset_custom(const AnyString& name, const AnyString& key) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(2); + mPUSHp(name.ptr, name.len); + if (key.ptr) mPUSHp(key.ptr, key.len); +@@ -125,6 +132,7 @@ void Main::reset_custom(const AnyString& name, const AnyString& key) + Scope Main::newScope() + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(0); + return Scope(this, call_func_scalar(aTHX_ new_scope_cv)); + } +@@ -137,6 +145,7 @@ void Scope::prefer_now(const AnyString& labels) const + void Scope::set_custom_var(const AnyString& name, const AnyString& key, Value& x) const + { + dTHXa(pm_main->pi); ++ PERL_SET_CONTEXT(pm_main->pi); + PmStartFuncall(3); + mPUSHp(name.ptr, name.len); + if (key.ptr) mPUSHp(key.ptr, key.len); +@@ -148,6 +157,7 @@ void Scope::set_custom_var(const AnyString& name, const AnyString& key, Value& x + std::string Main::greeting(int verbose) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(1); + mPUSHi(verbose); + PUTBACK; +@@ -157,6 +167,7 @@ std::string Main::greeting(int verbose) + void Main::shell_enable() + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(0); + glue::call_func_void(aTHX_ shell_enable_cv); + } +@@ -167,6 +178,7 @@ Main::shell_execute_t Main::shell_execute(const std::string& input) + return shell_execute_t(true, input, input, input); + + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(1); + mPUSHp(input.c_str(), input.size()); + PUTBACK; +@@ -187,6 +199,7 @@ Main::shell_execute_t Main::shell_execute(const std::string& input) + Main::shell_complete_t Main::shell_complete(const std::string& input) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(1); + mPUSHp(input.c_str(), input.size()); + PUTBACK; +@@ -209,6 +222,7 @@ Main::shell_complete_t Main::shell_complete(const std::string& input) + std::vector Main::shell_context_help(const std::string& input, size_t pos, bool full, bool html) + { + dTHXa(pi); ++ PERL_SET_CONTEXT(pi); + PmStartFuncall(4); + mPUSHp(input.c_str(), input.size()); + if (pos == std::string::npos) +-- +2.19.0 + diff --git a/build/pkgs/polymake/patches/0003-Shell-Mock-Add-compile_scope.patch b/build/pkgs/polymake/patches/0003-Shell-Mock-Add-compile_scope.patch new file mode 100644 index 00000000000..0e51c353852 --- /dev/null +++ b/build/pkgs/polymake/patches/0003-Shell-Mock-Add-compile_scope.patch @@ -0,0 +1,24 @@ +From 50ce55eea115b74eae9421de43a4405e254ef579 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Fri, 10 May 2019 14:59:44 +0200 +Subject: [PATCH 3/3] Shell::Mock: Add compile_scope + +--- + perllib/Polymake/Core/ShellMock.pm | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/perllib/Polymake/Core/ShellMock.pm b/perllib/Polymake/Core/ShellMock.pm +index 46d59654..137f0b24 100644 +--- a/perllib/Polymake/Core/ShellMock.pm ++++ b/perllib/Polymake/Core/ShellMock.pm +@@ -34,6 +34,7 @@ use Polymake::Struct ( + + sub term { shift } + sub interactive { 0 } ++sub compile_scope { undef } + + sub complete { + my ($self, $string)=@_; +-- +2.19.0 + diff --git a/build/pkgs/polymake/spkg-install b/build/pkgs/polymake/spkg-install index 677ce9ae615..9067a681bef 100644 --- a/build/pkgs/polymake/spkg-install +++ b/build/pkgs/polymake/spkg-install @@ -12,9 +12,11 @@ if [ `uname` = Darwin ]; then fi # We disable SoPlex to avoid linking errors (#24905). +# Since polymake v3.4, it does not find our lrs installation if we do not provide --with-lrs explicitly. ./configure --without-java \ --without-javaview \ --without-soplex \ + --with-lrs="$SAGE_LOCAL" \ --prefix="$SAGE_LOCAL" \ --exec-prefix="$SAGE_LOCAL" \ --includedir="$SAGE_LOCAL"/include \ diff --git a/build/pkgs/pynormaliz/checksums.ini b/build/pkgs/pynormaliz/checksums.ini index a9abb02266c..3a198b364ba 100644 --- a/build/pkgs/pynormaliz/checksums.ini +++ b/build/pkgs/pynormaliz/checksums.ini @@ -1,4 +1,4 @@ tarball=PyNormaliz-VERSION.tar.gz -sha1=880da253bf0785ae49efa12d2649e955034064f6 -md5=c157e80f4995690a2065cefc5e773ef0 -cksum=902471877 +sha1=cca8ea11f3ce3cf68455611e883da34b11c16949 +md5=97941329304064aef5fd1ead9776d33b +cksum=1286083212 diff --git a/build/pkgs/pynormaliz/package-version.txt b/build/pkgs/pynormaliz/package-version.txt index 879b416e609..95e3ba81920 100644 --- a/build/pkgs/pynormaliz/package-version.txt +++ b/build/pkgs/pynormaliz/package-version.txt @@ -1 +1 @@ -2.1 +2.5 diff --git a/build/pkgs/pynormaliz/spkg-check b/build/pkgs/pynormaliz/spkg-check new file mode 100644 index 00000000000..ce7324c2c91 --- /dev/null +++ b/build/pkgs/pynormaliz/spkg-check @@ -0,0 +1,2 @@ +cd src +sage-python23 setup.py test diff --git a/build/pkgs/r/checksums.ini b/build/pkgs/r/checksums.ini index 8141fea8382..9364b3d6f21 100644 --- a/build/pkgs/r/checksums.ini +++ b/build/pkgs/r/checksums.ini @@ -1,4 +1,4 @@ tarball=R-VERSION.tar.gz -sha1=057ea91daed3e68a12b2a473ee1283cf26f360e2 -md5=3e4b40b2bbd4a2f8133ac45dbef6a485 -cksum=3313280655 +sha1=c8a1949e763d22ec3b1dbdd251afcb0f1d2d5c76 +md5=65601eac6d353f7efb5b48c29097c2fb +cksum=3870442260 diff --git a/build/pkgs/r/package-version.txt b/build/pkgs/r/package-version.txt index 18547dc1733..40c341bdcdb 100644 --- a/build/pkgs/r/package-version.txt +++ b/build/pkgs/r/package-version.txt @@ -1 +1 @@ -3.5.2.p0 +3.6.0 diff --git a/build/pkgs/rw/spkg-configure.m4 b/build/pkgs/rw/spkg-configure.m4 new file mode 100644 index 00000000000..4a7a95c5511 --- /dev/null +++ b/build/pkgs/rw/spkg-configure.m4 @@ -0,0 +1,16 @@ +SAGE_SPKG_CONFIGURE([rw], [ + # Check for "rw.h" in the system's include directory... + AC_CHECK_HEADER([rw.h], + [sage_spkg_install_rw=no], + [sage_spkg_install_rw=yes]) + + #...and ensure that we have at least one function "calculate_level" + # that we need from librw. If either check fails, we want to set + # sage_spkg_install_rw=yes. However if both checks succeed, the + # first will set sage_spkg_install_rw=no and the second will do + # nothing. + AC_SEARCH_LIBS([calculate_level], + [rw], + [], + [sage_spkg_install_rw=yes]) +]) diff --git a/build/pkgs/tachyon/patches/Make-config.patch b/build/pkgs/tachyon/patches/Make-config.patch index c5ef209c73a..f52089d60f4 100644 --- a/build/pkgs/tachyon/patches/Make-config.patch +++ b/build/pkgs/tachyon/patches/Make-config.patch @@ -71,7 +71,7 @@ -PNGLIB= +USEPNG= -DUSEPNG +PNGINC= -I$(SAGE_LOCAL)/include -+PNGLIB= -L$(SAGE_LOCAL)/lib -lpng16 -lz ++PNGLIB= -L$(SAGE_LOCAL)/lib -lpng -lz -# Uncomment the following lines to enable PNG support -#USEPNG= -DUSEPNG diff --git a/build/pkgs/zlib/spkg-configure.m4 b/build/pkgs/zlib/spkg-configure.m4 index 4ccaae9dce6..44b5620c6f1 100644 --- a/build/pkgs/zlib/spkg-configure.m4 +++ b/build/pkgs/zlib/spkg-configure.m4 @@ -1,8 +1,8 @@ SAGE_SPKG_CONFIGURE([zlib], [ - dnl inflateValidate is needed for libpng at least; checking this ensures - dnl we have the minimum required zlib version - AC_CHECK_LIB([z], [inflateValidate], [ - AX_CHECK_ZLIB([], [zlib_cv_libz=no]) - ]) - AS_IF([test "x$zlib_cv_libz" != "xyes"], [sage_spkg_install_zlib=yes]) + AX_CHECK_ZLIB([ + PKG_CHECK_MODULES([LIBPNG], [libpng >= 1.2], [], [ + dnl inflateValidate is needed for Sage's libpng, newer than 1.2; this ensures + dnl we have the minimum required for building zlib version + AC_CHECK_LIB([z], [inflateValidate], [], [sage_spkg_install_zlib=yes]) + ])], [sage_spkg_install_zlib=yes]) ]) diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 76ca16740ad..54525d7618a 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='8.8.beta5' -SAGE_RELEASE_DATE='2019-05-11' -SAGE_VERSION_BANNER='SageMath version 8.8.beta5, Release Date: 2019-05-11' +SAGE_VERSION='8.8.beta6' +SAGE_RELEASE_DATE='2019-05-22' +SAGE_VERSION_BANNER='SageMath version 8.8.beta6, Release Date: 2019-05-22' diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 8c2aa9d457f..8d9bedfaad4 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -63,6 +63,9 @@ REFERENCES: Vertex Cover Problem: Theory and Experiments. *SIAM ALENEX/ANALCO* 2004: 62-69. +.. [Ack2016] Lennart Ackermans, Oplosbaarheid van Kegelsneden. + http://www.math.leidenuniv.nl/nl/theses/Bachelor/. + .. [ADKF1970] \V. Arlazarov, E. Dinic, M. Kronrod, and I. Faradzev. 'On Economical Construction of the Transitive Closure of a Directed Graph.' @@ -85,7 +88,7 @@ REFERENCES: Benjamin Lorenz, Andreas Paffenholz, and Thomas Rehn, Computing convex hulls and counting integer points with polymake, Math. Program. Comput. 9 (2017), no. 1, 1–38, - https://doi.org/10.1007/s12532-016-0104-z + :doi:`10.1007/s12532-016-0104-z` .. [AguSot05] Marcelo Aguiar and Frank Sottile, *Structure of the Malvenuto-Reutenauer Hopf algebra of @@ -122,6 +125,13 @@ REFERENCES: Adv. Math. **106** (1994), 216–243. mathscinet:`MR1279219` +.. [AKMMMP2002] Sang Yook An, Seog Young Kim, David C. Marshall, + Susan H. Marshall, William G. McCallum, + Alexander R. Perlis, + *Jacobians of Genus One Curves*, + Journal of Number Theory 90 (2002), pp.304--315, + http://www.math.arizona.edu/~wmc/Research/JacobianFinal.pdf + .. [AJL2011] \S. Ariki, N. Jacon, and C. Lecouvey. *The modular branching rule for affine Hecke algebras of type A*. Adv. Math. 228:481-526, 2011. @@ -183,6 +193,12 @@ REFERENCES: N. Pytheas Fogg (Ed.), Arithmetics, and Combinatorics (Lecture Notes in Mathematics, Vol. 1794), 2002. +.. [ARVT2005] Michael Artin, Fernando Rodriguez-Villegas, John Tate, + On the Jacobians of plane cubics, + Advances in Mathematics 198 (2005) 1, pp. 366--382 + :doi:`10.1016/j.aim.2005.06.004` + http://www.math.utexas.edu/users/villegas/publications/jacobian-cubics.pdf + .. [AS-Bessel] \F. W. J. Olver: 9. Bessel Functions of Integer Order, in Abramowitz and Stegun: Handbook of Mathematical Functions. http://people.math.sfu.ca/~cbm/aands/page_355.htm @@ -277,6 +293,19 @@ REFERENCES: .. [Bat1991] \V. V. Batyrev, *On the classification of smooth projective toric varieties*, Tohoku Math. J. **43** (1991), 569-585 +.. [Bat1994] Victor V. Batyrev, + "Dual polyhedra and mirror symmetry for Calabi-Yau + hypersurfaces in toric varieties", + J. Algebraic Geom. 3 (1994), no. 3, 493-535. + :arxiv:`alg-geom/9310003v1` + +.. [Baz2011] Ivan Bazhov, + On orbits of the automorphism group on a complete toric + variety. + Beitr Algebra Geom (2013) 54: 471, + :arxiv:`1110.4275`, + :doi:`10.1007/s13366-011-0084-0`. + .. [BB1997] Mladen Bestvina and Noel Brady. *Morse theory and finiteness properties of groups*. Invent. Math. **129** (1997). No. 3, @@ -289,6 +318,10 @@ REFERENCES: the Method of Four Russians Over Larger Finite Fields*. :arxiv:`0901.1413`, 2009. +.. [BB2013] Gavin Brown, Jaroslaw Buczynski: + *Maps of toric varieties in Cox coordinates*, + :arxiv:`1004.4924` + .. [BeBo2009] Olivier Bernardi and Nicolas Bonichon, *Intervals in Catalan lattices and realizers of triangulations*, JCTA 116 (2009) @@ -362,6 +395,11 @@ REFERENCES: 203–218. Springer, 2010. pre-print available at http://eprint.iacr.org/2010/313.pdf +.. [BCdlOG2000] Volker Braun, Philip Candelas, Xendia de la Ossa, + Antonella Grassi, *Toric Calabi-Yau Fourfolds, Duality + Between N=1 Theories and Divisors that Contribute to the + Superpotential*, :arxiv:`hep-th/0001208` + .. [BCGKKKLNPRRTY2012] \J. Borghoff, A. Canteaut, T. Güneysu, E. B. Kavun, M. Knezevic, \L. R. Knudsen, G. Leander, V. Nikov, C. Paar, C. Rechberger, \P. Rombouts, S. S. Thomsen, and T. Yalcin, @@ -545,6 +583,12 @@ REFERENCES: Conference, AMS/IP Studies in Advanced Mathematics 35 (2003). :arxiv:`math/0204057v1` +.. [BIP] Rene Birkner, Nathan Owen Ilten, and Lars Petersen: + Computations with equivariant toric vector bundles, + The Journal of Software for Algebra and Geometry: Macaulay2. + http://msp.org/jsag/2010/2-1/p03.xhtml + http://www.math.uiuc.edu/Macaulay2/doc/Macaulay2-1.8.2/share/doc/Macaulay2/ToricVectorBundles/html/ + .. [Bir1975] \J. Birman. *Braids, Links, and Mapping Class Groups*, Princeton University Press, 1975 @@ -673,6 +717,10 @@ REFERENCES: equations: I. Fibonacci and Lucas perfect powers." Annals of Math, 2006. +.. [BMSS2006] Alin Bostan, Bruno Salvy, Francois Morain, Eric Schost. Fast + algorithms for computing isogenies between elliptic + curves. [Research Report] 2006, pp.28. + .. [BN2010] \D. Bump and M. Nakasuji. Integration on `p`-adic groups and crystal bases. Proc. Amer. Math. Soc. 138(5), pp. 1595--1605. @@ -690,6 +738,11 @@ REFERENCES: .. [Bo2009] Bosch, S., Algebra, Springer 2009 +.. [Bor1993] Lev A. Borisov, + "Towards the mirror symmetry for Calabi-Yau complete + intersections in Gorenstein Fano toric varieties", 1993. + :arxiv:`alg-geom/9310001v1` + .. [BOR2009] Emmanuel Briand, Rosa Orellana, Mercedes Rosas. *The stability of the Kronecker products of Schur functions*. @@ -701,6 +754,12 @@ REFERENCES: .. [BP1982] \H. Beker and F. Piper. *Cipher Systems: The Protection of Communications*. John Wiley and Sons, 1982. +.. [BP1993] Dominique Bernardi and Bernadette Perrin-Riou, + Variante `p`-adique de la conjecture de Birch et + Swinnerton-Dyer (le cas supersingulier), + C. R. Acad. Sci. Paris, Sér I. Math., 317 (1993), no. 3, + 227-232. + .. [BP1994] \A. Berman and R. J. Plemmons. Nonnegative Matrices in the Mathematical Sciences. SIAM, Philadelphia, 1994. @@ -730,6 +789,10 @@ REFERENCES: Journal of Mathematical Sociology 25.2 (2001): 163-177, http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf +.. [Bra2011] Volker Braun, + Toric Elliptic Fibrations and F-Theory Compactifications, + :arxiv:`1110.4883` + .. [Bre1993] Richard P. Brent. *On computing factors of cyclotomic polynomials*. Mathematics of Computation. **61** (1993). No. 203. pp 131--149. @@ -894,6 +957,11 @@ REFERENCES: vol 368, pages 67-134, 1996 +.. [CD2007] Adrian Clingher and Charles F. Doran, + "Modular invariants for lattice polarized K3 surfaces", + Michigan Math. J. 55 (2007), no. 2, 355-393. + :arxiv:`math/0602146v1` [math.AG] + .. [CDL2015] \A. Canteaut, Sebastien Duval, Gaetan Leurent *Construction of Lightweight S-Boxes using Feistel and MISTY Structures*; in Proceedings of SAC 2015; LNCS 9566; @@ -959,6 +1027,10 @@ REFERENCES: .. [Cha18] Frédéric Chapoton, *Some properties of a new partial order on Dyck paths*, 2018, :arxiv:`1809.10981` +.. [Cha22005] \B. Cha. Vanishing of some cohomology goups and bounds + for the Shafarevich-Tate groups of elliptic + curves. J. Number Theory, 111:154-178, 2005. + .. [Cha2008] Frédéric Chapoton. *Sur le nombre d'intervalles dans les treillis de Tamari*. Sém. Lothar. Combin. (2008). @@ -1017,11 +1089,6 @@ REFERENCES: Introduction to Algorithms (2nd ed.), MIT Press and McGraw-Hill, 2001, 549-552, ISBN 0-262-03293-7. -.. [CLS2014] \C. Ceballos, J.-P. Labbé, C. Stump, *Subword complexes, - cluster complexes, and generalized multi-associahedra*, - \J. Algebr. Comb. **39** (2014) pp. 17-51. - :doi:`10.1007/s10801-013-0437-x`, :arxiv:`1108.1776`. - .. [CLO2005] \D. Cox, J. Little, D. O'Shea. Using Algebraic Geometry. Springer, 2005. @@ -1030,6 +1097,11 @@ REFERENCES: Mathematics*. American Mathematical Society, Providence, RI, 2011. +.. [CLS2014] \C. Ceballos, J.-P. Labbé, C. Stump, *Subword complexes, + cluster complexes, and generalized multi-associahedra*, + \J. Algebr. Comb. **39** (2014) pp. 17-51. + :doi:`10.1007/s10801-013-0437-x`, :arxiv:`1108.1776`. + .. [CMO2011] \C. Chun, D. Mayhew, J. Oxley, A chain theorem for internally 4-connected binary matroids. J. Combin. Theory Ser. B 101 (2011), 141-189. @@ -1078,6 +1150,15 @@ REFERENCES: .. [Coh2007] Henri Cohen, Number Theory, Volume II. Graduate Texts in Mathematics 240. Springer, 2007. +.. [Coj2005] Alina Carmen Cojocaru, + On the surjectivity of the Galois representations + associated to non-CM elliptic curves. + With an appendix by Ernst Kani. + Canad. Math. Bull. 48 (2005), no. 1, 16--31. + +.. [Col2004] Pierre Colmez, Invariant `\mathcal{L}` et derivees de + valeurs propres de Frobenius, preprint, 2004. + .. [Col2013] Julia Collins. *An algorithm for computing the Seifert matrix of a link from a braid representation*. (2013). http://www.maths.ed.ac.uk/~jcollins/SeifertMatrix/SeifertMatrix.pdf @@ -1096,6 +1177,9 @@ REFERENCES: Signature Function*, July 2018 http://www.unige.ch/math/folks/conway/Notes/LevineTristramSurvey.pdf +.. [Cox] David Cox, "What is a Toric Variety", + https://dacox.people.amherst.edu/lectures/tutorial.ps + .. [CP2001] John Crisp and Luis Paris. *The solution to a conjecture of Tits on the subgroup generated by the squares of the generators of an Artin group*. Invent. Math. **145** @@ -1113,6 +1197,10 @@ REFERENCES: d'Andecy. *Representation theory of the Yokonuma-Hecke algebra*. (2014) :arxiv:`1302.6225v2`. +.. [CPS2006] \J.E. Cremona, M. Prickett and S. Siksek, Height Difference + Bounds For Elliptic Curves over Number Fields, Journal of Number + Theory 116(1) (2006), pages 42-68. + .. [CR1962] Curtis, Charles W.; Reiner, Irving "Representation theory of finite groups and associative algebras." Pure and Applied Mathematics, Vol. XI Interscience Publishers, a @@ -1151,6 +1239,16 @@ REFERENCES: .. [CS2003] \John E. Cremona and Michael Stoll. On The Reduction Theory of Binary Forms. Journal für die reine und angewandte Mathematik, 565 (2003), 79-99. +.. [CS2006] \J. E. Cremona, and S. Siksek, Computing a Lower Bound for the + Canonical Height on Elliptic Curves over `\QQ`, ANTS VII + Proceedings: F.Hess, S.Pauli and M.Pohst (eds.), ANTS VII, Lecture + Notes in Computer Science 4076 (2006), pages 275-286. + +.. [CT2013] \J. E. Cremona and T. Thongjunthug, The Complex AGM, periods of + elliptic curves over $\CC$ and complex elliptic logarithms. + Journal of Number Theory Volume 133, Issue 8, August 2013, pages + 2813-2841. + .. [CTTL2014] \C. Carlet, Deng Tang, Xiaohu Tang, and Qunying Liao: *New Construction of Differentially 4-Uniform Bijections*, Inscrypt, pp. 22-38, 2013. @@ -1212,6 +1310,10 @@ REFERENCES: schemes of coding theory, Philips Res. Rep., Suppl., vol. 10, 1973. +.. [De1970] \M. Demazure + Sous-groupes algébriques de rang maximum du groupe de Cremona. + Ann. Sci. Ecole Norm. Sup. 1970, 3, 507--588. + .. [De1974] \M. Demazure, *Désingularisation des variétés de Schubert*, Ann. E. N. S., Vol. 6, (1974), p. 163-172 @@ -1366,6 +1468,9 @@ REFERENCES: Amer. Math. Soc. **100** (1987). No 3. http://educ.jmu.edu/~dromscg/vita/preprints/Isomorphisms.pdf +.. [DS1994] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, + chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. + .. [Du2001] \I. Duursma, "From weight enumerators to zeta functions", in Discrete Applied Mathematics, vol. 111, no. 1-2, pp. 55-73, 2001. @@ -1381,6 +1486,10 @@ REFERENCES: .. [Du2009] Du Ye. *On the Complexity of Deciding Degeneracy in Games*. :arxiv:`0905.3012v1` (2009) +.. [Du2010] \J. J. Duistermaat, + Discrete integrable systems. QRT maps and elliptic surfaces. + Springer Monographs in Mathematics. Berlin: Springer. xxii, 627 p., 2010 + .. [Du2018] \O. Dunkelman, *Efficient Construction of the Boomerang Connection Table* (preprint); in Cryptology ePrint Archive, (2018), 631. @@ -1422,6 +1531,10 @@ REFERENCES: In Proceedings of the second ACM conference on Online social networks (COSN '14) :doi:`10.1145/2660460.2660465` +.. [Edix] Edixhoven, B., *Point counting after Kedlaya*, EIDMA-Stieltjes + graduate course, Leiden + (notes: https://www.math.leidenuniv.nl/~edix/oww/mathofcrypt/carls_edixhoven/kedlaya.pdf) + .. [Ega1981] Yoshimi Egawa, Characterization of H(n, q) by the parameters, Journal of Combinatorial Theory, Series A, Volume 31, Issue 2, 1981, Pages 108-125, ISSN 0097-3165,:doi:`10.1016/0097-3165(81)90007-8`. @@ -1543,6 +1656,11 @@ REFERENCES: curves". LMS Journal of Computation and Mathematics (2014), volume 17, issue 01, pp. 1-23. +.. [FMSS1995] Fulton, MacPherson, Sottile, Sturmfels: + *Intersection theory on spherical varieties*, + J. of Alg. Geometry 4 (1995), 181-193. + http://www.math.tamu.edu/~frank.sottile/research/ps/spherical.ps.gz + .. [FMV2014] Xander Faber, Michelle Manes, and Bianca Viray. Computing Conjugating Sets and Automorphism Groups of Rational Functions. Journal of Algebra, 423 (2014), 1161-1190. @@ -1602,6 +1720,9 @@ REFERENCES: Mathematische Nachrichten, volume 83, Issue 1, pages 143-159, 1978. http://igm.univ-mlv.fr/~berstel/Mps/Travaux/A/1978-3MajorIndexMathNachr.pdf +.. [FS1994] William Fulton, Bernd Sturmfels, *Intersection Theory on + Toric Varieties*, :arxiv:`alg-geom/9403002` + .. [FS2009] Philippe Flajolet and Robert Sedgewick, `Analytic combinatorics `_. Cambridge University Press, Cambridge, 2009. @@ -1615,7 +1736,10 @@ REFERENCES: Fortsch. Phys. **42** (1994), no. 1, pp. 1-48. :doi:`10.1002/prop.2190420102`, :arXiv:`hep-th/9306162`. -.. [Fu1993] Wiliam Fulton, *Introduction to Toric Varieties*, +.. [Ful1989] \W. Fulton. Algebraic curves: an introduction to algebraic geometry. Addison-Wesley, + Redwood City CA (1989). + +.. [Ful1993] Wiliam Fulton, *Introduction to Toric Varieties*, Princeton University Press, 1993. .. [Ful1997] William Fulton, @@ -1724,6 +1848,11 @@ REFERENCES: semistandard decomposition tableaux.*; Trans. Amer. Math. Soc., 366(1): 457-489, 2014. :arxiv:`1103.1456v2`. +.. [GJPST2009] \G. Grigorov, A. Jorza, S. Patrikis, W. Stein, C. Tarniţǎ. Computational + verification of the Birch and Swinnerton-Dyer + conjecture for individual elliptic curves. + Math. Comp. 78 (2009), no. 268, 2397--2425. + .. [GJRW2010] Ewgenij Gawrilow, Michael Joswig, Thilo Rörig, and Nikolaus Witte, Drawing polytopal graphs with polymake, Comput. Vis. Sci. 13 (2010), no. 2, 99–110, https://doi.org/10.1007/s00791-009-0127-3 @@ -1828,6 +1957,9 @@ REFERENCES: birational rowmotion*. http://www.cip.ifi.lmu.de/~grinberg/algebra/skeletal.pdf +.. [Gri2005] \G. Grigorov, Kato's Euler System and the Main Conjecture, + Harvard Ph.D. Thesis (2005). + .. [GroLar1] \R. Grossman and R. G. Larson, *Hopf-algebraic structure of families of trees*, J. Algebra 126 (1) (1989), 184-210. Preprint: :arxiv:`0711.3877v1` @@ -1880,6 +2012,9 @@ REFERENCES: Graphs". Transactions of the American Mathematical Society, Vol. 280, No. 1. (Nov., 1983), pp. 97-126. +.. [GZ1986] \B. Gross and D. Zagier, *Heegner points and + derivatives of L-series.* Invent. Math. 84 (1986), no. 2, 225-320. + .. _ref-H: **H** @@ -1904,6 +2039,8 @@ REFERENCES: 1960 http://cms.math.ca/cjm/v12/cjm1960v12.0145-0157.pdf +.. [Har1977] \R. Hartshorne. Algebraic Geometry. Springer-Verlag, New York, 1977. + .. [Har1994] Frank Harary. *Graph Theory*. Reading, MA: Addison-Wesley, 1994. .. [HarPri] F. Harary and G. Prins. The block-cutpoint-tree of @@ -1912,6 +2049,9 @@ REFERENCES: .. [Hat2002] Allen Hatcher, "Algebraic Topology", Cambridge University Press (2002). +.. [HC2006] Mark van Hoeij and John Cremona, Solving Conics over + function fields. J. Théor. Nombres Bordeaux, 2006. + .. [He2002] \H. Heys *A Tutorial on Linear and Differential Cryptanalysis* ; 2002' available at http://www.engr.mun.ca/~howard/PAPERS/ldc_tutorial.pdf @@ -2058,6 +2198,9 @@ REFERENCES: Mapping Class Groups and Moduli, volume 243 of LMS Lect. Notes, 67-77, Cambridge Univ. Press (1997) +.. [HSV2006] Hess, Smart, Vercauteren, "The Eta Pairing Revisited", + IEEE Trans. Information Theory, 52(10): 4595-4602, 2006. + .. [HT1972] Samuel Huang and Dov Tamari. *Problems of associativity: A simple proof for the lattice property of systems ordered by a semi-associative law*. @@ -2132,6 +2275,9 @@ REFERENCES: .. [Ja1971] \N. Jacobson. *Exceptional Lie Algebras*. Marcel Dekker, Inc. New York. 1971. IBSN No. 0-8247-1326-5. +.. [Jet2008] \D. Jetchev. Global divisibility of Heegner points and + Tamagawa numbers. Compos. Math. 144 (2008), no. 4, 811--826. + .. [JK1981] Gordon James, Adalbert Kerber, *The Representation Theory of the Symmetric Group*, Encyclopedia of Mathematics and its Applications, vol. 16, @@ -2253,6 +2399,11 @@ REFERENCES: .. [Kat1991] Nicholas M. Katz, *Exponential sums and differential equations*, Princeton University Press, Princeton NJ, 1991. +.. [Kat2004] Kayuza Kato, `p`-adic Hodge theory and values of zeta + functions of modular forms, Cohomologies `p`-adiques et + applications arithmétiques III, Astérisque vol 295, SMF, + Paris, 2004. + .. [Kau1968] \W. H. Kautz. "Bounds on directed (d, k) graphs". Theory of cellular logic networks and machines, AFCRL-68-0668, SRI Project 7258, Final Rep., pp. 20-28, 1968. @@ -2276,6 +2427,10 @@ REFERENCES: .. [Ke2008] \B. Keller, *Cluster algebras, quiver representations and triangulated categories*, :arxiv:`0807.1960`. +.. [Ked2001] Kedlaya, K., *Counting points on hyperelliptic curves using + Monsky-Washnitzer cohomology*, J. Ramanujan Math. Soc. 16 (2001) no + 4, 323-338 + .. [KG2016] \P. Karpmann and Benjamin Gregoire, *The LITTLUN S-box and the FLY block cipher*, Lightweight Cryptography Workshop, 2016. https://www.nist.gov/sites/default/files/documents/2016/10/18/karpman-paper-lwc2016.pdf @@ -2340,6 +2495,11 @@ REFERENCES: Compositio Mathematica, **149** (2013), no. 10. :arxiv:`1111.3660`. +.. [Kly1990] Klyachko, Aleksandr Anatolevich. + Equivariant Bundles on Toral Varieties, + Math USSR Izv. 35 (1990), 337-375. + http://iopscience.iop.org/0025-5726/35/2/A04/pdf/0025-5726_35_2_A04.pdf + .. [KM1994] \S.-J. Kang and K. C. Misra. Crystal bases and tensor product decompositions of `U_q(G_2)`-modules. J. Algebra 163, pp. 675--691, 1994. @@ -2388,6 +2548,9 @@ REFERENCES: Polynomials in Computer Algebra Systems: A Practical Guide. John Wiley, Chichester (1999): 79-99. +.. [Koh1996] Kohel, "Endomorphism Rings of Elliptic Curves over Finite + Fields", UC Berkeley PhD thesis 1996. + .. [Koh2000] David Kohel, *Hecke Module Structure of Quaternions*, in Class Field Theory — Its Centenary and Prospect (Tokyo, 1998), Advanced Studies in Pure Mathematics, 30, @@ -2402,6 +2565,10 @@ REFERENCES: no. 11 (2007): 1451-1457. http://linearcodes.uni-bayreuth.de/twoweight/ +.. [Kol1991] \V. A. Kolyvagin. On the structure of Shafarevich-Tate + groups. Algebraic geometry, 94--121, Lecture Notes in Math., 1479, + Springer, Berlin, 1991. + .. [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 @@ -2447,9 +2614,16 @@ REFERENCES: .. [KR2005] \P.L. Krapivsky and S. Redner. "Network Growth by Copying", Phys. Rev. E vol. 71 (2005), p. 036118. +.. [Kra1989] Kraus, Alain, Quelques remarques à propos des invariants + \(c_4\), \(c_6\) et \(\Delta\) d'une courbe elliptique, Acta + Arith. 54 (1989), 75-80. + .. [Kre2002] \V. Kreps. *Social Network Analysis* (2002). [Online] Available: http://www.orgnet.com/sna.html +.. [KS] Sheldon Katz and Stein Arild Stromme, "Schubert", + A Maple package for intersection theory and enumerative geometry. + .. [KS1998] Maximilian Kreuzer and Harald Skarke, *Classification of Reflexive Polyhedra in Three Dimensions*, :arxiv:`hep-th/9805190` @@ -2550,6 +2724,11 @@ REFERENCES: Systems*, in Journal of Symbolic Computation (1992) vol\. 13, pp\. 117-131 +.. [Laz2004] Robert Lazarsfeld: + Positivity in algebraic geometry II; + Positivity for Vector Bundles, and Multiplier Ideals, + Modern Surveys in Mathematics volume 49 (2004). + .. [LB1988] Lee, P.J., Brickell, E.F. An observation on the security of McEliece's public-key cryptosystem. EuroCrypt 1988. LNCS, vol. 330, pp. 275–280. @@ -2723,6 +2902,10 @@ REFERENCES: and of planar binary trees. :arXiv:`math/0102066v1`. +.. [LS] \A. Lum, W. Stein. Verification of the Birch and + Swinnerton-Dyer Conjecture for Elliptic Curves with Complex + Multiplication (unpublished) + .. [LS2007] Thomas Lam and Mark Shimozono. *Dual graded graphs for Kac-Moody algebras*. Algebra & Number Theory 1.4 (2007) pp. 451-488. @@ -2779,6 +2962,13 @@ REFERENCES: local components of a newform*, Mathematics of Computation **81** (2012) 1179-1200. :doi:`10.1090/S0025-5718-2011-02530-5` +.. [LW2015] \T. Lawson and C. Wuthrich, Vanishing of some Galois + cohomology groups for elliptic curves, :arxiv:`1505.02940` + +.. [LY2001] \K. Lauter and T. Yang, "Computing genus 2 curves from + invariants on the Hilbert moduli space", Journal of Number Theory 131 + (2011), pages 936 - 958 + .. [Lyo2003] \R. Lyons, *Determinantal probability measures*. Publications Mathématiques de l'Institut des Hautes Études Scientifiques 98(1) (2003), pp. 167-212. @@ -2880,14 +3070,11 @@ REFERENCES: .. [May1967] \J. P. May, Simplicial Objects in Algebraic Topology, University of Chicago Press (1967) -.. [MW1990] Brendan D. McKay and Nicholas C. Worland. "Uniform Generation of - Random Regular Graphs of Moderate Degree". Journal of Algorithms, - 11(1):52-67, 1990. - :doi:`10.1016/0196-6774(90)90029-E`. +.. [Maz1978] \B. Mazur. Modular curves and the Eisenstein ideal. Inst. + Hautes Études Sci. Publ. Math. No. 47 (1977), 33--186 (1978). -.. [MW1994] Yiu-Kwong Man and Francis J. Wright. *Fast Polynomial - Dispersion Computation and its Application to Indefinite - Summation*. ISSAC 1994. +.. [Maz1978b] \B. Mazur. Rational Isogenies of Prime Degree. + *Inventiones mathematicae* 44, 129-162 (1978). .. [McC1978] \K. McCrimmon. *Jordan algebras and their applications*. Bull. Amer. Math. Soc. **84** 1978. @@ -2915,6 +3102,10 @@ REFERENCES: .. [MF1999] \J.H. Mathews and K.D. Fink. *Numerical Methods Using MATLAB*. 3rd edition, Prentice-Hall, 1999. +.. [Mes1991] Mestre, Jean-François. *Construction de courbes de genre 2 à partir de + leurs modules*. Effective methods in algebraic geometry (Castiglioncello, + 1990), 313--334, Progr. Math., 94, Birkhauser Boston, Boston, MA, 1991. + .. [Mil1958] \J. W. Milnor, *The Steenrod algebra and its dual*, Ann. of Math. (2) 67 (1958), 150-171. @@ -2923,13 +3114,12 @@ REFERENCES: polynomials*. Trans. Amer. Math. Soc., 245 (1978), 89-118. +.. [Mil2004] Victor S. Miller, "The Weil pairing, and its + efficient calculation", J. Cryptol., 17(4):235-261, 2004 + .. [MirMor2009] \R. Miranda, D.R. Morrison, "Embeddings of Integral Quadratic Forms" http://www.math.ucsb.edu/~drm/manuscripts/eiqf.pdf . -.. [MJ1991] Mestre, Jean-François. *Construction de courbes de genre 2 à partir de - leurs modules*. Effective methods in algebraic geometry (Castiglioncello, - 1990), 313--334, Progr. Math., 94, Birkhauser Boston, Boston, MA, 1991. - .. [MKO1998] Hans Munthe--Kaas and Brynjulf Owren. *Computations in a free Lie algebra*. (1998). `Downloadable from Munthe-Kaas's website @@ -2968,6 +3158,9 @@ REFERENCES: .. [Mon2010] \T. Monteil, The asymptotic language of smooth curves, talk at LaCIM2010. +.. [Mo2009] \D. Moody, Des. Codes Cryptogr. (2009) + 52: 381. :doi:`10.1007/s10623-009-9287-x` + .. [MoPa1994] \P. Morton and P. Patel. The Galois theory of periodic points of polynomial maps. Proc. London Math. Soc., 68 (1994), 225-263. @@ -3023,6 +3216,14 @@ REFERENCES: Theory*. Cambridge: Cambridge University Press, (2013). ISBN 9781107005488. +.. [MT1991] Mazur, B., & Tate, J. (1991). The `p`-adic sigma + function. Duke Mathematical Journal, 62(3), 663-688. + +.. [MTT1986] \B. Mazur, J. Tate, and J. Teitelbaum, On `p`-adic + analogues of the conjectures of Birch and + Swinnerton-Dyer, Inventiones mathematicae 84, (1986), + 1-48. + .. [Mu1997] Murty, M. Ram. *Congruences between modular forms*. In "Analytic Number Theory" (ed. Y. Motohashi), London Math. Soc. Lecture Notes 247 (1997), 313-320, Cambridge Univ. Press. @@ -3043,6 +3244,15 @@ REFERENCES: and S. A. Vanstone. *Handbook of Applied Cryptography*. CRC Press, 1996. +.. [MW1990] Brendan D. McKay and Nicholas C. Worland. "Uniform Generation of + Random Regular Graphs of Moderate Degree". Journal of Algorithms, + 11(1):52-67, 1990. + :doi:`10.1016/0196-6774(90)90029-E`. + +.. [MW1994] Yiu-Kwong Man and Francis J. Wright. *Fast Polynomial + Dispersion Computation and its Application to Indefinite + Summation*. ISSAC 1994. + .. [MW2009] Meshulam and Wallach, "Homological connectivity of random `k`-dimensional complexes", preprint, math.CO/0609773. @@ -3067,6 +3277,11 @@ REFERENCES: .. [Nik1977] V. V. Nikulin, "Integral symmetric bilinear forms and some of their applications" Izv. Akad. Nauk SSSR Ser. Mat., 1979, Volume 43, Issue 1, Pages 111–177. +.. [Nil2005] Benjamin Nill, + "Gorenstein toric Fano varieties", + Manuscripta Math. 116 (2005), no. 2, 183-210. + :arxiv:`math/0405448v1` [math.AG] + .. [NN2007] Nisan, Noam, et al., eds. *Algorithmic game theory.* Cambridge University Press, 2007. @@ -3180,12 +3395,16 @@ REFERENCES: .. [Pec2014] Oliver Pechenik, *Cyclic sieving of increasing tableaux and small Schroeder paths*, JCTA 125 (2014), 357-378, - https://doi.org/10.1016/j.jcta.2014.04.002 + :doi:`10.1016/j.jcta.2014.04.002` .. [Pen2012] \R. Pendavingh, On the evaluation at `(-i, i)` of the Tutte polynomial of a binary matroid. Preprint: :arxiv:`1203.0910` +.. [Per2007] Markus Perling, + Divisorial Cohomology Vanishing on Toric Varieties, + :arxiv:`0711.4836v2` + .. [Pet2010] Christiane Peters, Information-set decoding for linear codes over `GF(q)`, Proc. of PQCrypto 2010, pp. 81-94. @@ -3206,6 +3425,9 @@ REFERENCES: Ann. Sci. Math. Québec, 19 (1): 79--90. http://www.lacim.uqam.ca/~christo/Publi%C3%A9s/1995/Alg%C3%A8bres%20de%20Hopf%20de%20tableaux.pdf +.. [Pol2003] Robert Pollack, *On the `p`-adic `L`-function of a modular form + at a supersingular prime*, Duke Math. J. 118 (2003), no. 3, 523-558. + .. [Pon2010] \S. Pon. *Types B and D affine Stanley symmetric functions*, unpublished PhD Thesis, UC Davis, 2010. @@ -3219,7 +3441,7 @@ REFERENCES: .. [Pop1972] \V. M. Popov. "Invariant description of linear, time-invariant controllable systems". SIAM Journal on Control, 10(2):252-264, - 1972. https://doi.org/10.1137/0310020 . + 1972. :doi:`10.1137/0310020` .. [Pos1988] \H. Postl. 'Fast evaluation of Dickson Polynomials' Contrib. to General Algebra, Vol. 6 (1988) pp. 223-225 @@ -3234,6 +3456,10 @@ REFERENCES: Providence, RI, 2013. :arxiv:`1112.6163` +.. [PR2003] Perrin-Riou, *Arithmétique des courbes elliptiques à + réduction supersingulière en `p`*, + Experiment. Math. 12 (2003), no. 2, 155-186. + .. [PR2015] \P. Pilarczyk and P. Réal, *Computation of cubical homology, cohomology, and (co)homological operations via chain contraction*, Adv. Comput. Math. 41 (2015), pp @@ -3281,6 +3507,10 @@ REFERENCES: .. [PWZ1997] Marko Petkovsek, Herbert S. Wilf, Doron Zeilberger, A = B, AK Peters, Ltd., Wellesley, MA, USA, 1997, pp. 73--100 +.. [PZGH1999] Petho A., Zimmer H.G., Gebel J. and Herrmann E., + Computing all S-integral points on elliptic curves + Math. Proc. Camb. Phil. Soc. (1999), 127, 383-402 + .. _ref-Q: .. _ref-R: @@ -3413,6 +3643,7 @@ REFERENCES: .. [Rot2006] Ron Roth, Introduction to Coding Theory, Cambridge University Press, 2006 + .. [RR1997] Arun Ram and Jeffrey Remmel. *Applications of the Frobenius formulas and the characters of the symmetric group and the Hecke algebras of type A*. J. Algebraic Combin. @@ -3425,6 +3656,10 @@ REFERENCES: *Spectra of Symmetrized Shuffling Operators*. :arXiv:`1102.2460v2`. +.. [Rub1991] \K. Rubin. The "main conjectures" of Iwasawa theory for + imaginary quadratic fields. Invent. Math. 103 (1991), + no. 1, 25--68. + .. [Rud1958] \M. E. Rudin. *An unshellable triangulation of a tetrahedron*. Bull. Amer. Math. Soc. 64 (1958), 90-91. @@ -3506,6 +3741,16 @@ REFERENCES: operations, Ann. of Math. Stud. 50 (Princeton University Press, 1962). +.. [Ser1972] Jean-Pierre Serre, + Propriétés galoisiennes des points d'ordre fini + des courbes elliptiques. + Invent. Math. 15 (1972), no. 4, 259--331. + +.. [Ser1987] Jean-Pierre Serre, + Sur les représentations modulaires de degré + 2 de `\text{Gal}(\bar\QQ/\QQ)`. + Duke Math. J. 54 (1987), no. 1, 179--230. + .. [Ser1985] \C. Series. The geometry of Markoff numbers. The Mathematical Intelligencer, 7(3):20--29, 1985. @@ -3525,6 +3770,13 @@ REFERENCES: Reduction*. Advances in Cryptology - EUROCRYPT '95. LNCS Volume 921, 1995, pp 1-12. +.. [SH1995b] Bernd Sturmfels, Serkan Hosten: + GRIN: An implementation of Grobner bases for integer programming, + in "Integer Programming and Combinatorial Optimization", + [E. Balas and J. Clausen, eds.], + Proceedings of the IV. IPCO Conference (Copenhagen, May 1995), + Springer Lecture Notes in Computer Science 920 (1995) 267-276. + .. [SHET2018] \O. Seker, P. Heggernes, T. Ekim, and Z. Caner Taskin. *Generation of random chordal graphs using subtrees of a tree*, :arxiv:`1810.13326v1`. @@ -3549,12 +3801,20 @@ REFERENCES: and T. Shirai, *Piccolo: An ultra-lightweight block-cipher*; in CHES, (2011), pp. 342-457. +.. [Sil1988] Joseph H. Silverman, Computing heights on + elliptic curves. Mathematics of Computation, Vol. 51, + No. 183 (Jul., 1988), pp. 339-358. + .. [Sil1994] Joseph H. Silverman, Advanced topics in the arithmetic of elliptic curves. GTM 151, Springer-Verlag, New York, 1994. .. [Sil2007] Joseph H. Silverman. The Arithmetic of Dynamics Systems. GTM 241, Springer-Verlag, New York, 2007. +.. [Sil2009] Joseph H. Silverman, The Arithmetic of Elliptic + Curves. Second edition. Graduate Texts in Mathematics, 106. + Springer, 2009. + .. [SK2011] \J. Spreer and W. Kühnel, "Combinatorial properties of the K3 surface: Simplicial blowups and slicings", Experimental Mathematics, Volume 20, Issue 2, 2011. @@ -3650,6 +3910,15 @@ REFERENCES: .. [St1986] Richard Stanley. *Two poset polytopes*, Discrete Comput. Geom. (1986), :doi:`10.1007/BF02187680` +.. [St2011b] \W. Stein, "Toward a Generalization of the Gross-Zagier + Conjecture", Int Math Res Notices (2011), + :doi:`10.1093/imrn/rnq075` + +.. [Sta1973] \H. M. Stark, Class-Numbers of Complex Quadratic + Fields. In: Kuijk W. (eds) Modular Functions of One + Variable I. Lecture Notes in Mathematics, + vol 320. (1973), Springer, Berlin, Heidelberg + .. [Sta2007] Stanley, Richard: *Hyperplane Arrangements*, Geometric Combinatorics (E. Miller, V. Reiner, and B. Sturmfels, eds.), IAS/Park City Mathematics Series, vol. 13, @@ -3717,6 +3986,17 @@ REFERENCES: .. [Stu1993] \B. Sturmfels, Algorithms in invariant theory, Springer-Verlag, 1993. +.. [Stu1995] Bernd Sturmfels, + Grobner Bases and Convex Polytopes + AMS University Lecture Series Vol. 8 (01 December 1995) + +.. [Stu1997] Bernd Sturmfels, + Equations defining toric varieties, + Algebraic Geometry - Santa Cruz 1995, + Proc. Sympos. Pure Math., 62, Part 2, + Amer. Math. Soc., Providence, RI, 1997, + pp. 437-449. + .. [Stu2008] \C. Stump -- More bijective Catalan combinatorics on permutations and on colored permutations, Preprint. :arXiv:`0808.2822`. @@ -3731,6 +4011,10 @@ REFERENCES: .. [STW2018] Christian Stump, Hugh Thomas and Nathan Williams, *Cataland: why the fuss?*, 2018. :arxiv:`1503.00710` +.. [SU2014] Christopher Skinner and Eric Urban, + The Iwasawa main conjectures for GL2. + Invent. Math. 195 (2014), no. 1, 1-277. + .. [sudoku:escargot] "Al Escargot", due to Arto Inkala, http://timemaker.blogspot.com/2006/12/ai-escargot-vwv.html @@ -3754,6 +4038,10 @@ REFERENCES: http://www.math.miami.edu/~armstrong/686sp13/McKay_Yi_Sun.pdf 2010 +.. [Sut2012] Sutherland. A local-global principle for rational + isogenies of prime degree. Journal de Théorie des Nombres de Bordeaux, + 2012. + .. [SV1970] \H. Schneider and M. Vidyasagar. Cross-positive matrices. SIAM Journal on Numerical Analysis, 7:508-519, 1970. @@ -3771,6 +4059,10 @@ REFERENCES: 2369, Springer, 2002, p267--275. http://modular.math.washington.edu/papers/stein-watkins/ +.. [SW2013] \W. Stein and C. Wuthrich, Algorithms + for the Arithmetic of Elliptic Curves using Iwasawa Theory + Mathematics of Computation 82 (2013), 1757-1792. + .. [St1922] Ernst Steinitz, *Polyeder und Raumeinteilungen*. In *Encyclopädie der Mathematischen Wissenschaften*, Franz Meyer and Hand Mohrmann, eds., volume 3, *Geometrie, erster Teil, zweite Hälfte*, @@ -3843,6 +4135,10 @@ REFERENCES: .. [Terwilliger2011] Paul Terwilliger. *The universal Askey-Wilson algebra*. SIGMA **7** (2011), 069, 24 pages. :arxiv:`1104.2813`. +.. [Tho2010] \T. Thongjunthug, Computing a lower bound for the canonical + height on elliptic curves over number fields, Math. Comp. 79 + (2010), pages 2431-2449. + .. [TIDES] \A. Abad, R. Barrio, F. Blesa, M. Rodriguez. TIDES tutorial: Integrating ODEs by using the Taylor Series Method (http://www.unizar.es/acz/05Publicaciones/Monografias/MonografiasPublicadas/Monografia36/IndMonogr36.htm) @@ -3916,7 +4212,7 @@ REFERENCES: .. [VBB1992] Marc Van Barel and Adhemar Bultheel. "A general module theoretic framework for vector M-Padé and matrix rational interpolation." Numer. Algorithms, 3:451-462, 1992. - https://doi.org/10.1007/BF02141952 + :doi:`10.1007/BF02141952` .. [Vee1978] William Veech, "Interval exchange transformations", J. Analyse Math. 33 (1978), 222-272 @@ -3973,6 +4269,9 @@ REFERENCES: .. [Wam1999] van Wamelen, Paul. *Examples of genus two CM curves defined over the rationals*. Math. Comp. 68 (1999), no. 225, 307--320. +.. [Wam1999b] \P. van Wamelen, Pari-GP code, section "thecubic" + https://www.math.lsu.edu/~wamelen/Genus2/FindCurve/igusa2curve.gp + .. [Wan1998] Daqing Wan, "Dimension variation of classical and p-adic modular forms", Invent. Math. 133, (1998) 449-463. @@ -4009,6 +4308,9 @@ REFERENCES: .. [Wel1988] Codes and Cryptography, Dominic Welsh, Oxford Sciences Publications, 1988 +.. [Wer1998] Annette Werner, Local heights on abelian varieties and + rigid analytic uniformization, Doc. Math. 3 (1998), 301-319. + .. [WFYTP2008] \D. Watanable, S. Furuya, H. Yoshida, K. Takaragi, and B. Preneel, *A new keystream generator MUGI*; in FSE, (2002), pp. 179-194. @@ -4019,7 +4321,7 @@ REFERENCES: .. [Wol1974] W. A. Wolovich. "Linear Multivariable Systems", Applied Mathematical Sciences (volume 11). Springer-Verlag New-York, 1974. - doi.org/10.1007/978-1-4612-6392-0 . + :doi:`10.1007/978-1-4612-6392-0` .. [Woo1998] \R. M. W. Wood, "Problems in the Steenrod algebra," Bull. London Math. Soc. 30 (1998), no. 5, 449-517. @@ -4042,6 +4344,10 @@ REFERENCES: submitted to NIST, (2008), available at http://www3.ntu.edu.sg/home/wuhj/research/jh/jh_round3.pdf +.. [Wu2004] Wuthrich, C. (2004). On p-adic heights in families of + elliptic curves. Journal of the London Mathematical + Society, 70(1), 23-40. + .. [WW1991] Michelle Wachs and Dennis White, *p, q-Stirling numbers and set partition statistics*, Journal of Combinatorial Theory, Series A 56.1 (1991): 27-46. diff --git a/src/ext/doctest/python3-known-passing.txt b/src/ext/doctest/python3-known-passing.txt index d3346aa6465..e9e03a3dea6 100644 --- a/src/ext/doctest/python3-known-passing.txt +++ b/src/ext/doctest/python3-known-passing.txt @@ -1,6 +1,8 @@ +src/doc/ src/sage/algebras/ src/sage/arith/ src/sage/calculus/ +src/sage/categories/ src/sage/coding/ src/sage/combinat/designs/ src/sage/combinat/posets/ @@ -42,6 +44,7 @@ src/sage/sandpiles/ src/sage/sat/ src/sage/schemes/ src/sage/server/ +src/sage/sets/ src/sage/stats/ src/sage/structure/ src/sage/tensor/ diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 6516f550c35..2b4d052465d 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -100,12 +100,13 @@ from sage.rings.polynomial.term_order import TermOrder from sage.rings.quotient_ring import QuotientRing_nc from sage.rings.quotient_ring_element import QuotientRingElement +from sage.misc.cachefunc import cached_function class Differential(with_metaclass( InheritComparisonClasscallMetaclass, UniqueRepresentation, Morphism - )): + )): r""" Differential of a commutative graded algebra. @@ -141,7 +142,7 @@ def __classcall__(cls, A, im_gens): True """ if isinstance(im_gens, (list, tuple)): - im_gens = {A.gen(i): x for i,x in enumerate(im_gens)} + im_gens = {A.gen(i): x for i, x in enumerate(im_gens)} R = A.cover_ring() I = A.defining_ideal() @@ -367,13 +368,19 @@ def coboundaries(self, n): Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [0 1] + sage: d.coboundaries(1) + Vector space of degree 2 and dimension 0 over Rational Field + Basis matrix: + [] + """ A = self.domain() F = A.base_ring() if n == 0: return VectorSpace(F, 0) if n == 1: - return VectorSpace(F, 0) + V0 = VectorSpace(F, len(A.basis(1))) + return V0.subspace([]) M = self.differential_matrix(n-1) V0 = VectorSpace(F, M.nrows()) V1 = VectorSpace(F, M.ncols()) @@ -494,7 +501,8 @@ def cohomology(self, n): H_basis_raw = [H.lift(H.basis()[i]) for i in range(H.dimension())] A = self.domain() B = A.basis(n) - H_basis = [sum([c*b for (c,b) in zip(coeffs, B)]) for coeffs in H_basis_raw] + H_basis = [sum(c*b for (c, b) in zip(coeffs, B)) for coeffs in + H_basis_raw] # Put brackets around classes. H_basis_brackets = [CohomologyClass(b) for b in H_basis] return CombinatorialFreeModule(A.base_ring(), H_basis_brackets) @@ -523,6 +531,7 @@ def _is_nonzero(self): """ return any(x for x in self._dic_.values()) + class Differential_multigraded(Differential): """ Differential of a commutative multi-graded algebra. @@ -605,7 +614,7 @@ def differential_matrix_multigraded(self, n, total=False): dic = im.lift().dict() for j in dic.keys(): k = cokeys.index(j) - m[i,k] = dic[j] + m[i, k] = dic[j] m.set_immutable() return m @@ -781,7 +790,7 @@ def cohomology(self, n, total=False): H_basis_raw = [H.lift(H.basis()[i]) for i in range(H.dimension())] A = self.domain() B = A.basis(n, total) - H_basis = [sum([c*b for (c,b) in zip(coeffs, B)]) for coeffs in H_basis_raw] + H_basis = [sum(c*b for (c, b) in zip(coeffs, B)) for coeffs in H_basis_raw] # Put brackets around classes. H_basis_brackets = [CohomologyClass(b) for b in H_basis] return CombinatorialFreeModule(A.base_ring(), H_basis_brackets) @@ -915,7 +924,7 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None): if not R or not I: if n > 1: F = FreeAlgebra(base, n, names) - else: # n = 1 + else: # n = 1 F = PolynomialRing(base, n, names) gens = F.gens() rels = {} @@ -925,7 +934,7 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None): rels[gens[j]*gens[i]] = ((-1) ** (tot_degs[i] * tot_degs[j]) * gens[i] * gens[j]) if n > 1: - R = F.g_algebra(rels, order = TermOrder('wdegrevlex', tot_degs)) + R = F.g_algebra(rels, order=TermOrder('wdegrevlex', tot_degs)) else: # n = 1 R = F.quotient(rels) if base.characteristic() == 2: @@ -1046,9 +1055,9 @@ def _basis_for_free_alg(self, n): else: odd_degrees.append(a) - if not even_degrees: # No even generators. + if not even_degrees: # No even generators. return [tuple(_) for _ in exterior_algebra_basis(n, tuple(odd_degrees))] - if not odd_degrees: # No odd generators. + if not odd_degrees: # No odd generators. return [tuple(_) for _ in WeightedIntegerVectors(n, tuple(even_degrees))] # General case: both even and odd generators. @@ -1648,7 +1657,7 @@ def _coerce_map_from_(self, other): if isinstance(other, GCAlgebra_multigraded): if self._degrees_multi != other._degrees_multi: return False - elif isinstance(other, GCAlgebra): # Not multigraded + elif isinstance(other, GCAlgebra): # Not multigraded return False return super(GCAlgebra_multigraded, self)._coerce_map_from_(other) @@ -1797,7 +1806,7 @@ def degree(self, total=False): raise ValueError('This element is not homogeneous') ########################################################### -## Differential algebras +# Differential algebras class DifferentialGCAlgebra(GCAlgebra): """ @@ -1904,6 +1913,7 @@ def __init__(self, A, differential): R=A.cover_ring(), I=A.defining_ideal()) self._differential = Differential(self, differential._dic_) + self._minimalmodels = {} def graded_commutative_algebra(self): """ @@ -2162,12 +2172,8 @@ def cohomology_generators(self, max_degree): ALGORITHM: - Use induction on degree, so assume we know what happens in - degrees less than `n`. Compute the cocycles `Z` in degree `n`. - Form a subspace `W` of this, spanned by the cocycles generated - by the lower degree generators, along with the coboundaries in - degree `n`. Find a basis for the complement of `W` in `Z`: - these represent cohomology generators. + Reduce a basis of the `n`'th cohomology modulo all the degree n + products of the lower degrees cohomologys. EXAMPLES:: @@ -2210,51 +2216,384 @@ def cohomology_generators(self, max_degree): sage: acyclic = X.cdg_algebra({x: y}) sage: acyclic.cohomology_generators(3) {} + + Test that redundant generators are eliminated:: + + sage: A. = GradedCommutativeAlgebra(QQ) + sage: d = A.differential({e1:e4*e3,e2:e4*e3}) + sage: B = A.cdg_algebra(d) + sage: B.cohomology_generators(3) + {1: [e4, e3, -e1 + e2], 2: [e2*e4, e2*e3]} + """ + if not (max_degree in ZZ and max_degree > 0): + raise ValueError('the given maximal degree must be a ' + 'positive integer') + def vector_to_element(v, deg): """ If an element of this algebra in degree ``deg`` is represented by a raw vector ``v``, convert it back to an element of the algebra again. """ - return sum(c*b for (c,b) in zip(v, self.basis(deg))) - - field = self.base_ring() - # gens: dictionary indexed by degree. Value is a list of - # cohomology generators in that degree. - gens = {} - # cocycles: dictionary indexed by degree. Value is a spanning - # set for the cocycles in that degree. - cocycles = {0: self.one()} - for n in range(1, max_degree+1): - old_cocycles = [] - for i in gens: - for g in gens[i]: - lowdim_cocycles = cocycles[n-i] - for x in lowdim_cocycles: - a = g*x - if a: - old_cocycles.append(a) - # Eliminate duplicates. - old_cocycles = set(old_cocycles) - # Convert elements of old_cocycles to raw vectors: - old_cocycles_raw = [cocyc.basis_coefficients(total=True) - for cocyc in old_cocycles] - old_cocycles_raw += self.coboundaries(n).basis() - cochains = VectorSpace(field, len(self.basis(n))) - W = cochains.submodule(old_cocycles_raw) - basis_of_complement = [] - all_cocycles = self.cocycles(n).basis() - for z in all_cocycles: - if z not in W: - basis_of_complement.append(z) - cocycle_basis = [vector_to_element(coeffs, n) - for coeffs in basis_of_complement] - # Only keep nonempty lists of generators. - if cocycle_basis: - gens[n] = cocycle_basis - cocycles[n] = list(old_cocycles) + cocycle_basis - return gens + return sum(c*b for (c, b) in zip(v, self.basis(deg))) + if max_degree == 1: + cohom1 = self.cohomology(1).basis().keys() + if not cohom1: + return {} + return {1: [g.representative() for g in cohom1]} + smaller_degree = {i: [g.representative() for g in + self.cohomology(i).basis().keys()] for i in + range(1, max_degree)} + already_generated = [] + for i in range(1, max_degree): + already_generated += [a*b for a in smaller_degree[i] for b in + smaller_degree[max_degree-i]] + CR = self.cohomology_raw(max_degree) + V = CR.V() + S = CR.submodule([CR(V(g.basis_coefficients(total=True))) for g in + already_generated if not g.is_zero()]) + Q = CR.quotient(S) + res = self.cohomology_generators(max_degree-1) + if Q.basis(): + res[max_degree] = [vector_to_element(CR.lift(Q.lift(g)), max_degree) + for g in Q.basis()] + return res + + def minimal_model(self, i=3, max_iterations=3): + """ + Try to compute a map from a ``i``-minimal gcda that is a + ``i``-quasi-isomorphism up to degree ``max_degree``. + + INPUT: + + - ``i`` -- integer (default: `3`); degree to which the result is + required to induce an isomorphism in cohomology, and the domain is + required to be minimal. + + - ``max_iterations`` -- integer (default: `3`); the number of + iterations of the method at each degree. If the algorithm does not + finish in this many iterations at each degree, an error is raised. + + OUTPUT: + + A morphism from a minimal Sullivan (up to degree ``i``) CDGA's to self, + that induces an isomorphism in cohomology up to degree ``i``, and a + monomorphism in degree ``i+1``. + + EXAMPLES:: + + sage: S. = GradedCommutativeAlgebra(QQ, degrees = (1,1,2)) + sage: d = S.differential({x:x*y,y:x*y}) + sage: R = S.cdg_algebra(d) + sage: p = R.minimal_model() + sage: T = p.domain() + sage: p + Commutative Differential Graded Algebra morphism: + From: Commutative Differential Graded Algebra with generators ('x1_0', 'x2_0') in degrees (1, 2) over Rational Field with differential: + x1_0 --> 0 + x2_0 --> 0 + To: Commutative Differential Graded Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) over Rational Field with differential: + x --> x*y + y --> x*y + z --> 0 + Defn: (x1_0, x2_0) --> (-x + y, z) + sage: R.cohomology(1) + Free module generated by {[-x + y]} over Rational Field + sage: T.cohomology(1) + Free module generated by {[x1_0]} over Rational Field + sage: [p(g.representative()) for g in T.cohomology(1).basis().keys()] + [-x + y] + sage: R.cohomology(2) + Free module generated by {[z]} over Rational Field + sage: T.cohomology(2) + Free module generated by {[x2_0]} over Rational Field + sage: [p(g.representative()) for g in T.cohomology(2).basis().keys()] + [z] + + + + sage: A. = GradedCommutativeAlgebra(QQ) + sage: d = A.differential({e1:e1*e7,e2:e2*e7,e3:-e3*e7, e4:-e4*e7}) + sage: B = A.cdg_algebra(d) + sage: phi = B.minimal_model(i=3) + sage: M = phi.domain() + sage: M + Commutative Differential Graded Algebra with generators ('x1_0', 'x1_1', 'x1_2', 'x2_0', 'x2_1', 'x2_2', 'x2_3', 'y3_0', 'y3_1', 'y3_2', 'y3_3', 'y3_4', 'y3_5', 'y3_6', 'y3_7', 'y3_8') in degrees (1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) over Rational Field with differential: + x1_0 --> 0 + x1_1 --> 0 + x1_2 --> 0 + x2_0 --> 0 + x2_1 --> 0 + x2_2 --> 0 + x2_3 --> 0 + y3_0 --> x2_3^2 + y3_1 --> x2_2*x2_3 + y3_2 --> x2_1*x2_3 + y3_3 --> x2_1*x2_2 + x2_0*x2_3 + y3_4 --> x2_2^2 + y3_5 --> x2_0*x2_2 + y3_6 --> x2_1^2 + y3_7 --> x2_0*x2_1 + y3_8 --> x2_0^2 + sage: phi + Commutative Differential Graded Algebra morphism: + From: Commutative Differential Graded Algebra with generators ('x1_0', 'x1_1', 'x1_2', 'x2_0', 'x2_1', 'x2_2', 'x2_3', 'y3_0', 'y3_1', 'y3_2', 'y3_3', 'y3_4', 'y3_5', 'y3_6', 'y3_7', 'y3_8') in degrees (1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) over Rational Field with differential: + x1_0 --> 0 + x1_1 --> 0 + x1_2 --> 0 + x2_0 --> 0 + x2_1 --> 0 + x2_2 --> 0 + x2_3 --> 0 + y3_0 --> x2_3^2 + y3_1 --> x2_2*x2_3 + y3_2 --> x2_1*x2_3 + y3_3 --> x2_1*x2_2 + x2_0*x2_3 + y3_4 --> x2_2^2 + y3_5 --> x2_0*x2_2 + y3_6 --> x2_1^2 + y3_7 --> x2_0*x2_1 + y3_8 --> x2_0^2 + To: Commutative Differential Graded Algebra with generators ('e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7') in degrees (1, 1, 1, 1, 1, 1, 1) over Rational Field with differential: + e1 --> e1*e7 + e2 --> e2*e7 + e3 --> -e3*e7 + e4 --> -e4*e7 + e5 --> 0 + e6 --> 0 + e7 --> 0 + Defn: (x1_0, x1_1, x1_2, x2_0, x2_1, x2_2, x2_3, y3_0, y3_1, y3_2, y3_3, y3_4, y3_5, y3_6, y3_7, y3_8) --> (e7, e6, e5, e2*e4, e2*e3, e1*e4, e1*e3, 0, 0, 0, 0, 0, 0, 0, 0, 0) + sage: [B.cohomology(i).dimension() for i in [1..3]] + [3, 7, 13] + sage: [M.cohomology(i).dimension() for i in [1..3]] + [3, 7, 13] + + ALGORITHM: + + Construct the minimal Sullivan algebra ``S`` by iteratively adding + generators to it. Start with one closed generator of degree 1 for each + element in the basis of the first cohomology of the algebra. Then + proceed degree by degree. At each degree `d`, we keep adding generators + of degree `d-1` whose differential kills the elements in the kernel of + the map `H^d(S)\to H^d(self)`. Once this map is made injective, we add + the needed closed generators in degree `d` to make it surjective. + + .. WARNING:: + + The method is not granted to finish (it can't, since the minimal + model could be infinitely generated in some degrees). + The parameter ``max_iterations`` controls how many iterations of + the method are attempted at each degree. In case they are not + enough, an exception is raised. If you think that the result will + be finitely generated, you can try to run it again with a higher + value for ``max_iterations``. + + .. SEEALSO:: + + :wikipedia:`Rational_homotopy_theory#Sullivan_algebras` + + TESTS:: + + sage: A. = GradedCommutativeAlgebra(QQ,degrees = (1,2,3,3)) + sage: d = A.differential({x:y}) + sage: B = A.cdg_algebra(d) + sage: B.minimal_model(i=3) + Commutative Differential Graded Algebra morphism: + From: Commutative Differential Graded Algebra with generators ('x3_0', 'x3_1') in degrees (3, 3) over Rational Field with differential: + x3_0 --> 0 + x3_1 --> 0 + To: Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') in degrees (1, 2, 3, 3) over Rational Field with differential: + x --> y + y --> 0 + z --> 0 + t --> 0 + Defn: (x3_0, x3_1) --> (t, z) + + """ + max_degree = int(i) + if max_degree < 1: + raise ValueError("the degree must be a positive integer") + if max_iterations not in ZZ or max_iterations < 1: + raise ValueError("max_iterations must be a positive integer") + if max_degree in self._minimalmodels: + return self._minimalmodels[max_degree] + from copy import copy + + def extend(phi, ndegrees, ndifs, nimags, nnames): + """ + Extend phi to a new algebra with new genererators, labeled by nnames + """ + B = phi.domain() + names = [str(g) for g in B.gens()] + degrees = [g.degree() for g in B.gens()] + A = GradedCommutativeAlgebra(B.base_ring(), names=names + nnames, + degrees=degrees + ndegrees) + h = B.hom(A.gens()[:B.ngens()], check=False) + d = B.differential() + diff = {h(g): h(d(g)) for g in B.gens()} + cndifs = copy(ndifs) + for g in A.gens()[B.ngens():]: + diff[g] = h(cndifs.pop(0)) + NB = A.cdg_algebra(diff) + Nphi = NB.hom([phi(g) for g in B.gens()] + nimags, check=False) + return Nphi + + def extendx(phi, degree): + B = phi.domain() + imagesbcohom = [phi(g.representative()) for g in B.cohomology(degree).basis().keys()] + CS = self.cohomology_raw(degree) + VS = CS.V() + CB = B.cohomology_raw(degree) + imagesphico = [] + for g in imagesbcohom: + if g.is_zero(): + imagesphico.append(CS.zero()) + else: + imagesphico.append(CS(VS(g.basis_coefficients()))) + phico = CB.hom(imagesphico, codomain=CS) + QI = CS.quotient(phico.image()) + if QI.dimension() > 0: + nnames = ['x{}_{}'.format(degree, j) for j in + range(QI.dimension())] + nbasis = [] + bbasis = self.basis(degree) + for v in QI.basis(): + vl = CS.lift(QI.lift(v)) + g = sum(bbasis[j]*vl[j] for j in range(len(bbasis))) + nbasis.append(g) + nimags = nbasis + ndegrees = [degree for j in nbasis] + return extend(phi, ndegrees, [B.zero() for g in nimags], + nimags, nnames) + return phi + + def extendy(phi, degree): + nnamesy = 0 + for iteration in range(max_iterations): + B = phi.domain() + imagesbcohom = [phi(g.representative()) for g in + B.cohomology(degree).basis().keys()] + CS = self.cohomology_raw(degree) + VS = CS.V() + CB = B.cohomology_raw(degree) + imagesphico = [] + for g in imagesbcohom: + if g.is_zero(): + imagesphico.append(CS.zero()) + else: + imagesphico.append(CS(VS(g.basis_coefficients()))) + phico = CB.hom(imagesphico, codomain=CS) + K = phico.kernel() + if K.dimension() == 0: + return phi + if iteration == max_iterations-1: + raise ValueError("could not cover all relations in max iterations in degree {}".format(degree)) + ndifs = [CB.lift(g) for g in K.basis()] + basisdegree = B.basis(degree) + ndifs = [sum(basisdegree[j]*g[j] for j in + range(len(basisdegree))) for g in ndifs] + MS = self.differential().differential_matrix(degree-1) + nimags = [] + for g in ndifs: + if phi(g).is_zero(): + nimags.append(vector(MS.nrows()*[0])) + else: + nimags.append(MS.solve_left(vector(phi(g).basis_coefficients()))) + nimags = [sum(self.basis(degree-1)[j]*g[j] for j in range(len(self.basis(degree-1)))) for g in nimags] + ndegrees = [degree-1 for g in nimags] + nnames = ['y{}_{}'.format(degree-1, j+nnamesy) for j in range(len(nimags))] + nnamesy += len(nimags) + phi = extend(phi, ndegrees, ndifs, nimags, nnames) + B = phi.domain() + + if not self._minimalmodels: + degnzero = 1 + while self.cohomology(degnzero).dimension() == 0: + degnzero += 1 + if degnzero > max_degree: + raise ValueError("cohomology is trivial up to max_degree") + gens = [g.representative() for g in self.cohomology(degnzero).basis().keys()] + names = ['x{}_{}'.format(degnzero, j) for j in range(len(gens))] + A = GradedCommutativeAlgebra(self.base_ring(), names, degrees=[degnzero for j in names]) + B = A.cdg_algebra(A.differential({})) + # Solve case that fails with one generator return B,gens + phi = B.hom(gens) + phi = extendy(phi, degnzero+1) + self._minimalmodels[degnzero] = phi + else: + degnzero = max(self._minimalmodels) + phi = self._minimalmodels[degnzero] + + for degree in range(degnzero+1, max_degree+1): + phi = extendx(phi, degree) + phi = extendy(phi, degree+1) + self._minimalmodels[degree] = phi + + return phi + + def cohomology_algebra(self, max_degree=3): + """ + Compute a CDGA with trivial differential, that is isomorphic to the cohomology of + self up to``max_degree`` + + INPUT: + + - ``max_degree`` -- integer (default: `3`); degree to which the result is required to + be isomorphic to self's cohomology. + + EXAMPLES:: + + sage: A. = GradedCommutativeAlgebra(QQ) + sage: d = A.differential({e1:-e1*e6,e2:-e2*e6,e3:-e3*e6,e4:-e5*e6,e5:e4*e6}) + sage: B = A.cdg_algebra(d) + sage: M = B.cohomology_algebra() + sage: M + Commutative Differential Graded Algebra with generators ('x0', 'x1', 'x2') in degrees (1, 1, 2) over Rational Field with differential: + x0 --> 0 + x1 --> 0 + x2 --> 0 + sage: M.cohomology(1) + Free module generated by {[x1], [x0]} over Rational Field + sage: B.cohomology(1) + Free module generated by {[e7], [e6]} over Rational Field + sage: M.cohomology(2) + Free module generated by {[x0*x1], [x2]} over Rational Field + sage: B.cohomology(2) + Free module generated by {[e6*e7], [e4*e5]} over Rational Field + sage: M.cohomology(3) + Free module generated by {[x1*x2], [x0*x2]} over Rational Field + sage: B.cohomology(3) + Free module generated by {[e4*e5*e7], [e4*e5*e6]} over Rational Field + """ + cohomgens = self.cohomology_generators(max_degree) + if not cohomgens: + raise ValueError("Cohomology ring has no generators") + chgens = [] + degrees = [] + for d in cohomgens: + for g in cohomgens[d]: + degrees.append(d) + chgens.append(g) + A = GradedCommutativeAlgebra(self.base_ring(), ['x{}'.format(i) for i in range(len(chgens))], degrees) + rels = [] + for d in range(1, max_degree+1): + B1 = A.basis(d) + V2 = self.cohomology_raw(d) + images = [] + for g in B1: + ig = g._im_gens_(self, chgens) + if ig.is_zero(): + images.append(V2.zero()) + else: + images.append(V2(V2.V()(ig.basis_coefficients()))) + V1 = self.base_ring()**len(B1) + h = V1.hom(images, codomain=V2) + K = h.kernel() + for g in K.basis(): + newrel = sum(g[i]*B1[i] for i in range(len(B1))) + rels.append(newrel) + return A.quotient(A.ideal(rels)).cdg_algebra({}) class Element(GCAlgebra.Element): def differential(self): @@ -2340,13 +2679,14 @@ def is_cohomologous_to(self, other): if other.is_zero(): return self.is_coboundary() if (not isinstance(other, DifferentialGCAlgebra.Element) - or self.parent() is not other.parent()): + or self.parent() is not other.parent()): raise ValueError('The element {} does not lie in this DGA'.format(other)) if (self - other).is_homogeneous(): return (self - other).is_coboundary() else: return (self.is_coboundary() and other.is_coboundary()) + class DifferentialGCAlgebra_multigraded(DifferentialGCAlgebra, GCAlgebra_multigraded): """ A commutative differential multi-graded algebras. @@ -2561,6 +2901,7 @@ class Element(GCAlgebra_multigraded.Element, DifferentialGCAlgebra.Element): ################################################ # Main entry point + def GradedCommutativeAlgebra(ring, names=None, degrees=None, relations=None): r""" A graded commutative algebra. @@ -2851,6 +3192,17 @@ def __init__(self, parent, im_gens, check=True): Traceback (most recent call last): ... ValueError: the proposed morphism does not respect the differentials + + In the case of only one generator, the cover ring is a polynomial ring, + hence the noncommutativity relations should not be checked:: + + sage: A. = GradedCommutativeAlgebra(QQ) + sage: A.cover_ring() + Multivariate Polynomial Ring in e1 over Rational Field + sage: A.hom([2*e1]) + Graded Commutative Algebra endomorphism of Graded Commutative Algebra with generators ('e1',) in degrees (1,) over Rational Field + Defn: (e1,) --> (2*e1,) + """ domain = parent.domain() codomain = parent.codomain() @@ -2868,16 +3220,17 @@ def __init__(self, parent, im_gens, check=True): raise ValueError('not all elements of im_gens are in ' 'the codomain') R = domain.cover_ring() - from_free = dict(zip(R.free_algebra().gens(), im_gens)) from_R = dict(zip(R.gens(), im_gens)) - # First check the nc-relations: x*y=-y*x for x, y in odd - # degrees. These are in the form of a dictionary, with - # typical entry left:right. - for left in R.relations(): - zero = left.subs(from_free) - R.relations()[left].subs(from_R) - if zero: - raise ValueError('the proposed morphism does not respect ' - 'the nc-relations') + if hasattr(R, 'free_algebra'): + from_free = dict(zip(R.free_algebra().gens(), im_gens)) + # First check the nc-relations: x*y=-y*x for x, y in odd + # degrees. These are in the form of a dictionary, with + # typical entry left:right. + for left in R.relations(): + zero = left.subs(from_free) - R.relations()[left].subs(from_R) + if zero: + raise ValueError('the proposed morphism does not respect ' + 'the nc-relations') # Now check any extra relations, including x**2=0 for x in # odd degree. These are defined by a list of generators of # the defining ideal. @@ -2889,7 +3242,7 @@ def __init__(self, parent, im_gens, check=True): # If the domain and codomain have differentials, check # those, too. if (isinstance(domain, DifferentialGCAlgebra) and - isinstance(codomain, DifferentialGCAlgebra)): + isinstance(codomain, DifferentialGCAlgebra)): dom_diff = domain.differential() cod_diff = codomain.differential() if any(cod_diff(self(g)) != self(dom_diff(g)) @@ -2968,10 +3321,10 @@ def is_graded(self, total=False): sage: H([z,z]).is_graded(total=True) True """ - return all(not y or # zero is always allowed as an image + return all(not y or # zero is always allowed as an image (y.is_homogeneous() and x.degree(total=total) == y.degree(total=total)) - for (x,y) in zip(self.domain().gens(), self.im_gens())) + for (x, y) in zip(self.domain().gens(), self.im_gens())) def _repr_type(self): """ @@ -2987,7 +3340,7 @@ def _repr_type(self): 'Commutative Differential Graded Algebra' """ if (isinstance(self.domain(), DifferentialGCAlgebra) and - isinstance(self.codomain(), DifferentialGCAlgebra)): + isinstance(self.codomain(), DifferentialGCAlgebra)): return "Commutative Differential Graded Algebra" return "Graded Commutative Algebra" @@ -3054,7 +3407,7 @@ def zero(self): True """ return GCAlgebraMorphism(self, [self.codomain().zero()] - * self.domain().ngens()) + * self.domain().ngens()) @cached_method def identity(self): @@ -3181,6 +3534,8 @@ def representative(self): """ return self._x + +@cached_function def exterior_algebra_basis(n, degrees): """ Basis of an exterior algebra in degree ``n``, where the @@ -3204,26 +3559,30 @@ def exterior_algebra_basis(n, degrees): sage: exterior_algebra_basis(10, (1,5,1,1)) [] """ - zeroes = [0]*len(degrees) - if not degrees: - if n == 0: - return [zeroes] - else: - return [] + if n == 0: + return [[0 for j in degrees]] if len(degrees) == 1: - if n == degrees[0]: + if degrees[0] == n: return [[1]] - elif n == 0: - return [zeroes] else: return [] - result = [[0] + v for - v in exterior_algebra_basis(n, degrees[1:])] - if n == 0 and zeroes not in result: - result += [zeroes] - d = degrees[0] - return result + [[1] + v for - v in exterior_algebra_basis(n-d, degrees[1:])] + if not degrees: + return [] + if min(degrees) > n: + return [] + if sum(degrees) < n: + return [] + if sum(degrees) == n: + return [[1 for j in degrees]] + i = len(degrees) // 2 + res = [] + for j in range(n+1): + v1 = exterior_algebra_basis(j, degrees[:i]) + v2 = exterior_algebra_basis(n-j, degrees[i:]) + res += [l1+l2 for l1 in v1 for l2 in v2] + res.sort() + return res + def total_degree(deg): """ @@ -3256,4 +3615,3 @@ def total_degree(deg): if deg in ZZ: return deg return sum(deg) - diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index b3bd69d7ffd..23526a5bb2d 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -20,7 +20,7 @@ True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 William Stein # Copyright (C) 2009 Jonathan Bober # Copyright (C) 2014 Julian Rueth @@ -29,8 +29,8 @@ # 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/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function, absolute_import from six.moves import zip from six import integer_types @@ -297,7 +297,9 @@ def _repr_(self): def ngens(self): """ Return the number of generators of the quaternion algebra as a K-vector - space, not including 1. This value is always 3: the algebra is spanned + space, not including 1. + + This value is always 3: the algebra is spanned by the standard basis `1`, `i`, `j`, `k`. EXAMPLES:: @@ -336,9 +338,12 @@ def basis(self): self.__basis = tuple([self(1)] + list(self.gens())) return self.__basis + @cached_method def inner_product_matrix(self): """ - Return the inner product matrix associated to ``self``, i.e. the + Return the inner product matrix associated to ``self``. + + This is the Gram matrix of the reduced norm as a quadratic form on ``self``. The standard basis `1`, `i`, `j`, `k` is orthogonal, so this matrix is just the diagonal matrix with diagonal entries `2`, `2a`, `2b`, @@ -353,13 +358,9 @@ def inner_product_matrix(self): [ 0 0 38 0] [ 0 0 0 190] """ - try: return self.__inner_product_matrix - except AttributeError: pass - a, b = self._a, self._b - M = diagonal_matrix(self.base_ring(), [2, -2*a, -2*b, 2*a*b]) + M = diagonal_matrix(self.base_ring(), [2, -2 * a, -2 * b, 2 * a * b]) M.set_immutable() - self.__inner_product_matrix = M return M def is_commutative(self): @@ -471,7 +472,7 @@ def is_finite(self): """ return self.base_ring().is_finite() - def is_integral_domain(self, proof = True): + def is_integral_domain(self, proof=True): """ Return ``False`` always, since all quaternion algebras are noncommutative and integral domains are commutative (in Sage). @@ -535,8 +536,9 @@ def random_element(self, *args, **kwds): -979933/553629 + 255525/657688*i - 3511/6929*j - 700105/258683*k """ K = self.base_ring() - return self([ K.random_element(*args, **kwds) for _ in range(4) ]) + return self([K.random_element(*args, **kwds) for _ in range(4)]) + @cached_method def vector_space(self): """ Return the vector space associated to ``self`` with inner product given @@ -552,12 +554,7 @@ def vector_space(self): [ 0 0 -38 0] [ 0 0 0 -114] """ - try: - return self.__vector_space - except AttributeError: - V = VectorSpace(self.base_ring(), 4, inner_product_matrix = self.inner_product_matrix()) - self.__vector_space = V - return V + return VectorSpace(self.base_ring(), 4, inner_product_matrix=self.inner_product_matrix()) class QuaternionAlgebra_ab(QuaternionAlgebra_abstract): @@ -633,7 +630,8 @@ def __init__(self, base_ring, a, b, names='i,j,k'): self._populate_coercion_lists_(coerce_list=[base_ring]) self._gens = [self([0,1,0,0]), self([0,0,1,0]), self([0,0,0,1])] - def maximal_order(self, take_shortcuts = True): + @cached_method + def maximal_order(self, take_shortcuts=True): r""" Return a maximal order in this quaternion algebra. @@ -700,7 +698,7 @@ def maximal_order(self, take_shortcuts = True): ....: R = A.maximal_order(take_shortcuts=False) ....: assert A.discriminant() == R.discriminant() - We don't support number fields other than the rationals yet:: + We do not support number fields other than the rationals yet:: sage: K = QuadraticField(5) sage: QuaternionAlgebra(K,-1,-1).maximal_order() @@ -708,9 +706,6 @@ def maximal_order(self, take_shortcuts = True): ... NotImplementedError: maximal order only implemented for rational quaternion algebras """ - try: return self.__maximal_order - except AttributeError: pass - if self.base_ring() != QQ: raise NotImplementedError("maximal order only implemented for rational quaternion algebras") @@ -751,8 +746,7 @@ def maximal_order(self, take_shortcuts = True): basis = [(1+j)/2, (i+k)/2, -(j+a*k)/q, k] if basis: - self.__maximal_order = self.quaternion_order(basis) - return self.__maximal_order + return self.quaternion_order(basis) # The following code should always work (over QQ) # Start with <1,i,j,k> @@ -842,9 +836,7 @@ def maximal_order(self, take_shortcuts = True): e_new_gens.extend(e[1:]) e_new = basis_for_quaternion_lattice(list(R.basis()) + e_new_gens, reverse=True) - self.__maximal_order = self.quaternion_order(e_new) - return self.__maximal_order - + return self.quaternion_order(e_new) def invariants(self): """ @@ -948,7 +940,7 @@ def _repr_(self): sage: str(Q) 'Quaternion Algebra (-5, -2) with base ring Rational Field' """ - return "Quaternion Algebra (%r, %r) with base ring %s"%(self._a, self._b, self.base_ring()) + return "Quaternion Algebra (%r, %r) with base ring %s" % (self._a, self._b, self.base_ring()) def inner_product_matrix(self): """ @@ -976,6 +968,7 @@ def inner_product_matrix(self): a, b = self._a, self._b return diagonal_matrix(self.base_ring(), [2, -2*a, -2*b, 2*a*b]) + @cached_method def discriminant(self): """ Given a quaternion algebra `A` defined over a number field, @@ -997,24 +990,20 @@ def discriminant(self): sage: QuaternionAlgebra(QQ[sqrt(2)],3,19).discriminant() Fractional ideal (1) """ - try: - return self.__discriminant - except AttributeError: - pass if not is_RationalField(self.base_ring()): try: F = self.base_ring() - self.__discriminant = F.hilbert_conductor(self._a, self._b) + return F.hilbert_conductor(self._a, self._b) except NotImplementedError: raise ValueError("base field must be rational numbers or number field") else: - self.__discriminant = hilbert_conductor(self._a, self._b) - return self.__discriminant + return hilbert_conductor(self._a, self._b) def ramified_primes(self): """ - Return the primes that ramify in this quaternion algebra. Currently - only implemented over the rational numbers. + Return the primes that ramify in this quaternion algebra. + + Currently only implemented over the rational numbers. EXAMPLES:: @@ -1083,6 +1072,7 @@ def quaternion_order(self, basis, check=True): def ideal(self, gens, left_order=None, right_order=None, check=True, **kwds): r""" Return the quaternion ideal with given gens over `\ZZ`. + Neither a left or right order structure need be specified. INPUT: @@ -1111,7 +1101,9 @@ def ideal(self, gens, left_order=None, right_order=None, check=True, **kwds): def modp_splitting_data(self, p): r""" Return mod `p` splitting data for this quaternion algebra at - the unramified prime `p`. This is `2\times 2` + the unramified prime `p`. + + This is `2\times 2` matrices `I`, `J`, `K` over the finite field `\GF{p}` such that if the quaternion algebra has generators `i, j, k`, then `I^2 = i^2`, `J^2 = j^2`, `IJ=K` and `IJ=-JI`. @@ -1164,7 +1156,6 @@ def modp_splitting_data(self, p): sage: v = [Q.modp_splitting_data(p) for p in primes(20,1000)] - Proper error handling:: sage: Q.modp_splitting_data(5) @@ -1181,11 +1172,11 @@ def modp_splitting_data(self, p): raise NotImplementedError("must be rational quaternion algebra") p = ZZ(p) if not p.is_prime(): - raise ValueError("p (=%s) must be prime"%p) + raise ValueError("p (=%s) must be prime" % p) if p == 2: raise NotImplementedError("p must be odd") if self.discriminant() % p == 0: - raise ValueError("p (=%s) must be an unramified prime"%p) + raise ValueError("p (=%s) must be an unramified prime" % p) i, j, k = self.gens() F = GF(p) @@ -1434,7 +1425,9 @@ def gen(self, n): def __eq__(self, R): """ - Compare orders self and other. Two orders are equal if they + Compare orders self and other. + + Two orders are equal if they have the same basis and are in the same quaternion algebra. EXAMPLES:: @@ -1454,7 +1447,9 @@ def __eq__(self, R): def __ne__(self, other): """ - Compare orders self and other. Two orders are equal if they + Compare orders self and other. + + Two orders are equal if they have the same basis and are in the same quaternion algebra. EXAMPLES:: @@ -1514,7 +1509,7 @@ def _repr_(self): sage: QuaternionAlgebra(-11,-1).maximal_order() Order of Quaternion Algebra (-11, -1) with base ring Rational Field with basis (1/2 + 1/2*i, 1/2*j - 1/2*k, i, -k) """ - return 'Order of %s with basis %s'%(self.quaternion_algebra(), self.basis()) + return 'Order of %s with basis %s' % (self.quaternion_algebra(), self.basis()) def random_element(self, *args, **kwds): """ @@ -1537,7 +1532,7 @@ def random_element(self, *args, **kwds): sage: QuaternionAlgebra(-11,-1).maximal_order().random_element(-10,10) -9/2 - 7/2*i - 7/2*j - 3/2*k """ - return sum( (ZZ.random_element(*args, **kwds) * b for b in self.basis()) ) + return sum(ZZ.random_element(*args, **kwds) * b for b in self.basis()) def intersection(self, other): """ @@ -1583,6 +1578,7 @@ def intersection(self, other): # todo -- A(list(e)) could be A(e) return QuaternionOrder(A, [A(list(e)) for e in B.intersection(C).basis()]) + @cached_method def free_module(self): r""" Return the free `\ZZ`-module that corresponds to this order @@ -1606,16 +1602,14 @@ def free_module(self): [ 0 0 1/2 1/2] [ 0 0 0 1] """ - try: return self.__free_module - except AttributeError: pass V = self.quaternion_algebra().base_ring()**4 - M = V.span([V(list(g)) for g in self.basis()], ZZ) - self.__free_module = M - return M + return V.span([V(list(g)) for g in self.basis()], ZZ) def discriminant(self): r""" - Return the discriminant of this order, which we define as + Return the discriminant of this order. + + This is defined as `\sqrt{ det ( Tr(e_i \bar{e}_j ) ) }`, where `\{e_i\}` is the basis of the order. @@ -1635,7 +1629,7 @@ def discriminant(self): for d in self.basis(): MM = [] for e in self.basis(): - MM.append( (d * e.conjugate()).reduced_trace() ) + MM.append((d * e.conjugate()).reduced_trace()) L.append(MM) return (MatrixSpace(QQ, 4, 4)(L)).determinant().sqrt() @@ -1869,15 +1863,14 @@ def scale(self, alpha, left=False): sage: I.gens()[0] * i 2*i + 212*j - 2*k """ - Q = self.quaternion_algebra() alpha = Q(alpha) if left: - gens = [alpha*b for b in self.basis()] + gens = [alpha * b for b in self.basis()] else: - gens = [b*alpha for b in self.basis()] - return Q.ideal(gens, left_order = self.__left_order, - right_order = self.__right_order, check=False) + gens = [b * alpha for b in self.basis()] + return Q.ideal(gens, left_order=self.__left_order, + right_order=self.__right_order, check=False) def quaternion_algebra(self): """ @@ -1959,7 +1952,7 @@ def _compute_order(self, side='left'): raise NotImplementedError("computation of left and right orders only implemented over QQ") M = [(~b).matrix(action=action) for b in self.basis()] B = self.basis_matrix() - invs = [B*m for m in M] + invs = [B * m for m in M] # Now intersect the row spans of each matrix in invs ISB = [Q(v) for v in intersection_of_row_modules_over_ZZ(invs).row_module(ZZ).basis()] return Q.quaternion_order(ISB) @@ -2034,12 +2027,14 @@ def __repr__(self): sage: I.__repr__() 'Fractional ideal (2 + 6*j + 4*k, 2*i + 4*j + 2*k, 8*j, 8*k)' """ - return 'Fractional ideal %s'%(self.gens(),) + return 'Fractional ideal %s' % (self.gens(),) def quaternion_order(self): """ Return the order for which this ideal is a left or right - fractional ideal. If this ideal has both a left and right + fractional ideal. + + If this ideal has both a left and right ideal structure, then the left order is returned. If it has neither structure, then an error is raised. @@ -2076,7 +2071,9 @@ def ring(self): def basis(self): """ - Return basis for this fractional ideal. The basis is in Hermite form. + Return basis for this fractional ideal. + + The basis is in Hermite form. OUTPUT: tuple @@ -2088,9 +2085,9 @@ def basis(self): return self.__basis def gens(self): - """ + r""" Return the generators for this ideal, which are the same as - the `\\ZZ`-basis for this ideal. + the `\ZZ`-basis for this ideal. EXAMPLES:: @@ -2184,44 +2181,6 @@ def basis_matrix(self): self.__hermite_basis_matrix = B return B - def free_module(self): - r""" - Return the free module associated to this quaternionic - fractional ideal, viewed as a submodule of - ``Q.free_module()``, where ``Q`` is the ambient quaternion - algebra. - - OUTPUT: - - Free `\ZZ`-module of rank 4 embedded in an ambient `\QQ^4`. - - EXAMPLES:: - - sage: QuaternionAlgebra(-11,-1).maximal_order().unit_ideal().basis_matrix() - [ 1/2 1/2 0 0] - [ 0 0 1/2 -1/2] - [ 0 1 0 0] - [ 0 0 0 -1] - - This shows that the issue at :trac:`6760` is fixed:: - - sage: R. = QuaternionAlgebra(-1, -13) - sage: I = R.ideal([2+i, 3*i, 5*j, j+k]); I - Fractional ideal (2 + i, 3*i, j + k, 5*k) - sage: I.free_module() - Free module of degree 4 and rank 4 over Integer Ring - Echelon basis matrix: - [2 1 0 0] - [0 3 0 0] - [0 0 1 1] - [0 0 0 5] - """ - try: return self.__free_module - except AttributeError: - M = self.basis_matrix().row_module(ZZ) - self.__free_module = M - return M - def theta_series_vector(self, B): r""" Return theta series coefficients of ``self``, as a vector @@ -2248,14 +2207,17 @@ def theta_series_vector(self, B): """ B = Integer(B) try: - if len(self.__theta_series_vector)>= B: return self.__theta_series_vector[:B] - except AttributeError: pass + if len(self.__theta_series_vector)>= B: + return self.__theta_series_vector[:B] + except AttributeError: + pass V = FreeModule(ZZ, B) Q = self.quadratic_form() v = V(Q.representation_number_list(B)) self.__theta_series_vector = v return v + @cached_method def quadratic_form(self): """ Return the normalized quadratic form associated to this quaternion ideal. @@ -2276,8 +2238,6 @@ def quadratic_form(self): sage: I.theta_series(10) 1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + 24*q^6 + 24*q^7 + 36*q^8 + 36*q^9 + O(q^10) """ - try: return self.__quadratic_form - except AttributeError: pass from sage.quadratic_forms.quadratic_form import QuadraticForm # first get the gram matrix gram_matrix = self.gram_matrix() @@ -2288,9 +2248,7 @@ def quadratic_form(self): if g != 1: gram_matrix = gram_matrix / g # now get the quadratic form - Q = QuadraticForm(gram_matrix) - self.__quadratic_form = Q - return Q + return QuadraticForm(gram_matrix) def theta_series(self, B, var='q'): r""" @@ -2329,7 +2287,8 @@ def theta_series(self, B, var='q'): return self.__theta_series.add_bigoh(B) else: ZZ[[var]](self.__theta_series.list()[:B+1]) - except AttributeError: pass + except AttributeError: + pass v = self.theta_series_vector(B) theta = ZZ[[var]](v.list()).add_bigoh(B) self.__theta_series = theta @@ -2355,7 +2314,7 @@ def gram_matrix(self): A = self.__basis B = [z.conjugate() for z in self.__basis] two = QQ(2) - m = [two*(a*b).reduced_trace() for b in B for a in A] + m = [two * (a * b).reduced_trace() for b in B for a in A] M44 = MatrixSpace(QQ, 4, 4) return M44(m, coerce=False) @@ -2452,6 +2411,10 @@ def free_module(self): r""" Return the underlying free `\ZZ`-module corresponding to this ideal. + OUTPUT: + + Free `\ZZ`-module of rank 4 embedded in an ambient `\QQ^4`. + EXAMPLES:: sage: X = BrandtModule(3,5).right_ideals() @@ -2472,6 +2435,12 @@ def free_module(self): [ 0 0 4/7 16/7] [ 0 0 0 20/7] + sage: QuaternionAlgebra(-11,-1).maximal_order().unit_ideal().basis_matrix() + [ 1/2 1/2 0 0] + [ 0 0 1/2 -1/2] + [ 0 1 0 0] + [ 0 0 0 -1] + The free module method is also useful since it allows for checking if one ideal is contained in another, computing quotients `I/J`, etc.:: @@ -2484,6 +2453,19 @@ def free_module(self): True sage: X[0].free_module() / I.free_module() Finitely generated module V/W over Integer Ring with invariants (4, 4) + + This shows that the issue at :trac:`6760` is fixed:: + + sage: R. = QuaternionAlgebra(-1, -13) + sage: I = R.ideal([2+i, 3*i, 5*j, j+k]); I + Fractional ideal (2 + i, 3*i, j + k, 5*k) + sage: I.free_module() + Free module of degree 4 and rank 4 over Integer Ring + Echelon basis matrix: + [2 1 0 0] + [0 3 0 0] + [0 0 1 1] + [0 0 0 5] """ return self.basis_matrix().row_module(ZZ) @@ -2499,7 +2481,7 @@ def intersection(self, J): """ V = self.free_module().intersection(J.free_module()) - H,d = V.basis_matrix()._clear_denom() + H, d = V.basis_matrix()._clear_denom() A = self.quaternion_algebra() gens = quaternion_algebra_cython.rational_quaternions_from_integral_matrix_and_denom(A, H, d) return A.ideal(gens) @@ -2523,7 +2505,7 @@ def multiply_by_conjugate(self, J): Fractional ideal (8 + 8*j + 112*k, 8*i + 16*j + 136*k, 32*j + 128*k, 160*k) """ Jbar = [b.conjugate() for b in J.basis()] - gens = [a*b for a in self.basis() for b in Jbar] + gens = [a * b for a in self.basis() for b in Jbar] basis = tuple(basis_for_quaternion_lattice(gens)) R = self.quaternion_algebra() return R.ideal(basis, check=False) @@ -2581,7 +2563,7 @@ def is_equivalent(I, J, B=10): def __contains__(self, x): """ - Returns whether x is in self. + Return whether x is in self. EXAMPLES:: @@ -2675,8 +2657,8 @@ def cyclic_right_subideals(self, p, alpha=None): # try rescaling the ideal. B, d = self.basis_matrix()._clear_denom() g = gcd(B.list()) - IB = B/g - scale = g/d + IB = B / g + scale = g / d try: A = W.span_of_basis([W(f(Q(a.list())).list()) for a in IB.rows()]) except (ValueError, ZeroDivisionError) as msg: @@ -2754,7 +2736,8 @@ def basis_for_quaternion_lattice(gens, reverse = False): [1, i, j, k] """ - if len(gens) == 0: return [] + if not gens: + return [] Z, d = quaternion_algebra_cython.integral_matrix_and_denom_from_rational_quaternions(gens, reverse) H = Z._hnf_pari(0, include_zero_rows=False) A = gens[0].parent() @@ -2763,8 +2746,10 @@ def basis_for_quaternion_lattice(gens, reverse = False): def intersection_of_row_modules_over_ZZ(v): r""" - Intersects the `\ZZ`-modules with basis matrices the full rank `4 \times 4` - `\QQ`-matrices in the list v. The returned intersection is + Intersect the `\ZZ`-modules with basis matrices the full rank `4 \times 4` + `\QQ`-matrices in the list v. + + The returned intersection is represented by a `4 \times 4` matrix over `\QQ`. This can also be done using modules and intersection, but that would take over twice as long because of overhead, hence this function. @@ -2805,7 +2790,7 @@ def intersection_of_row_modules_over_ZZ(v): def normalize_basis_at_p(e, p, B = lambda x,y: (x*y.conjugate()).reduced_trace()): r""" - Computes a (at ``p``) normalized basis from the given basis ``e`` + Compute a (at ``p``) normalized basis from the given basis ``e`` of a `\ZZ`-module. The returned basis is (at ``p``) a `\ZZ_p` basis for the same @@ -2821,14 +2806,15 @@ def normalize_basis_at_p(e, p, B = lambda x,y: (x*y.conjugate()).reduced_trace() `0 = v_2(b) = v_2(a) \leq v_2(c)`. INPUT: - - ``e`` -- list; basis of a `\ZZ` module. - WARNING: will be modified! - - ``p`` -- prime for at which the basis should be normalized + - ``e`` -- list; basis of a `\ZZ` module. + WARNING: will be modified! + + - ``p`` -- prime for at which the basis should be normalized - - ``B`` -- (default: - ``lambda x,y: ((x*y).conjugate()).reduced_trace()``) - a bilinear form with respect to which to normalize + - ``B`` -- (default: + ``lambda x,y: ((x*y).conjugate()).reduced_trace()``) + a bilinear form with respect to which to normalize OUTPUT: @@ -2927,6 +2913,7 @@ def normalize_basis_at_p(e, p, B = lambda x,y: (x*y.conjugate()).reduced_trace() f = normalize_basis_at_p(e[2:N], p) return [(f0, min_v), (f1, min_v)] + f + def maxord_solve_aux_eq(a, b, p): r""" Given ``a`` and ``b`` and an even prime ideal ``p`` find @@ -2981,4 +2968,4 @@ def maxord_solve_aux_eq(a, b, p): (R(3), R(2)) : (1,0,1), (R(3), R(3)) : (1,1,1), } - return lut[ (R(a), R(b)) ] + return lut[(R(a), R(b))] diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 9a8f02dd0a5..7db80183b8c 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3437,7 +3437,12 @@ def merge(self, other): from sage.sets.all import FiniteEnumeratedSet new_domain = set(self._domain).union(set(other._domain)) - new_domain = FiniteEnumeratedSet(sorted(new_domain)) + try: + new_domain = FiniteEnumeratedSet(sorted(new_domain)) + except TypeError: + # Sorting the domain will sometimes fail with Python 3. + # Fallback (not ideal: find a better solution?) + new_domain = FiniteEnumeratedSet(sorted(new_domain, key=str)) return PermutationGroupFunctor(self.gens() + other.gens(), new_domain) diff --git a/src/sage/combinat/designs/covering_design.py b/src/sage/combinat/designs/covering_design.py index f46e3d8ca67..f204dddd09e 100644 --- a/src/sage/combinat/designs/covering_design.py +++ b/src/sage/combinat/designs/covering_design.py @@ -524,8 +524,13 @@ def best_known_covering_design_www(v, k, t, verbose=False): url = "https://ljcr.dmgordon.org/cover/get_cover.php" + param if verbose: print("Looking up the bounds at %s" % url) - with urlopen(url) as f: + + f = urlopen(url) + try: s = bytes_to_str(f.read()) + finally: + f.close() + if 'covering not in database' in s: # not found str = "no (%d, %d, %d) covering design in database\n" % (v, k, t) raise ValueError(str) diff --git a/src/sage/combinat/designs/design_catalog.py b/src/sage/combinat/designs/design_catalog.py index 51396461121..4fdf1e5a423 100644 --- a/src/sage/combinat/designs/design_catalog.py +++ b/src/sage/combinat/designs/design_catalog.py @@ -21,7 +21,7 @@ sage: C = designs.best_known_covering_design_from_LJCR(7, 3, 2) # optional - internet sage: C # optional - internet - (7,3,2)-covering design of size 7 + (7, 3, 2)-covering design of size 7 Lower bound: 7 Method: lex covering Submitted on: 1996-12-01 00:00:00 diff --git a/src/sage/combinat/rigged_configurations/kleber_tree.py b/src/sage/combinat/rigged_configurations/kleber_tree.py index 7bf1e624b12..521fb218f91 100644 --- a/src/sage/combinat/rigged_configurations/kleber_tree.py +++ b/src/sage/combinat/rigged_configurations/kleber_tree.py @@ -73,6 +73,7 @@ from sage.misc.latex import latex from sage.misc.misc_c import prod from sage.arith.all import binomial +from sage.features import FeatureNotPresentError from sage.rings.integer import Integer from sage.structure.parent import Parent @@ -834,7 +835,7 @@ def _children_iter(self, node): try: poly = Polyhedron(ieqs=ieqs, backend='normaliz') self._has_normaliz = True - except ImportError: + except FeatureNotPresentError: poly = Polyhedron(ieqs=ieqs) self._has_normaliz = False diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 51610c813f1..961b2966eb5 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -86,12 +86,18 @@ class IntegrableRepresentation(UniqueRepresentation, CategoryObject): EXAMPLES:: sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]).print_strings() + sage: IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]).print_strings() # py2 2*Lambda[0] + Lambda[2]: 4 31 161 665 2380 7658 22721 63120 166085 417295 1007601 2349655 Lambda[0] + 2*Lambda[1]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 Lambda[0] + 2*Lambda[3]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 Lambda[1] + Lambda[2] + Lambda[3]: 1 10 60 274 1056 3601 11199 32354 88009 227555 563390 1343178 3*Lambda[2] - delta: 3 21 107 450 1638 5367 16194 45687 121876 310056 757056 1783324 + sage: IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]).print_strings() # py3 + 2*Lambda[0] + Lambda[2]: 4 31 161 665 2380 7658 22721 63120 166085 417295 1007601 2349655 + Lambda[0] + 2*Lambda[3]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 + Lambda[0] + 2*Lambda[1]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 + Lambda[1] + Lambda[2] + Lambda[3]: 1 10 60 274 1056 3601 11199 32354 88009 227555 563390 1343178 + 3*Lambda[2] - delta: 3 21 107 450 1638 5367 16194 45687 121876 310056 757056 1783324 sage: Lambda = RootSystem(['D',4,1]).weight_lattice(extended=true).fundamental_weights() sage: IntegrableRepresentation(Lambda[0]+Lambda[1]).print_strings() # long time Lambda[0] + Lambda[1]: 1 10 62 293 1165 4097 13120 38997 109036 289575 735870 1799620 @@ -159,7 +165,7 @@ class IntegrableRepresentation(UniqueRepresentation, CategoryObject): {Lambda[0]: [1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56]} sage: Lambda = RootSystem(['G',2,1]).dual.weight_lattice(extended=true).fundamental_weights() sage: V = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[2]) - sage: V.print_strings() # long time + sage: V.print_strings() # long time py2 6*Lambdacheck[0]: 4 28 100 320 944 2460 6064 14300 31968 69020 144676 293916 4*Lambdacheck[0] + Lambdacheck[2]: 4 22 84 276 800 2124 5288 12470 28116 61056 128304 261972 3*Lambdacheck[0] + Lambdacheck[1]: 2 16 58 192 588 1568 3952 9520 21644 47456 100906 207536 @@ -167,15 +173,30 @@ class IntegrableRepresentation(UniqueRepresentation, CategoryObject): 2*Lambdacheck[1] - deltacheck: 2 8 32 120 354 980 2576 6244 14498 32480 69776 145528 2*Lambdacheck[0] + 2*Lambdacheck[2]: 2 12 48 164 492 1344 3428 8256 18960 41844 89208 184512 3*Lambdacheck[2] - deltacheck: 4 16 60 208 592 1584 4032 9552 21728 47776 101068 207888 + sage: V.print_strings() # long time py3 + 6*Lambdacheck[0]: 4 28 100 320 944 2460 6064 14300 31968 69020 144676 293916 + 3*Lambdacheck[0] + Lambdacheck[1]: 2 16 58 192 588 1568 3952 9520 21644 47456 100906 207536 + 4*Lambdacheck[0] + Lambdacheck[2]: 4 22 84 276 800 2124 5288 12470 28116 61056 128304 261972 + Lambdacheck[0] + Lambdacheck[1] + Lambdacheck[2]: 1 6 26 94 294 832 2184 5388 12634 28390 61488 128976 + 2*Lambdacheck[1] - deltacheck: 2 8 32 120 354 980 2576 6244 14498 32480 69776 145528 + 2*Lambdacheck[0] + 2*Lambdacheck[2]: 2 12 48 164 492 1344 3428 8256 18960 41844 89208 184512 + 3*Lambdacheck[2] - deltacheck: 4 16 60 208 592 1584 4032 9552 21728 47776 101068 207888 sage: Lambda = RootSystem(['A',6,2]).weight_lattice(extended=true).fundamental_weights() sage: V = IntegrableRepresentation(Lambda[0]+2*Lambda[1]) - sage: V.print_strings() # long time + sage: V.print_strings() # long time py2 5*Lambda[0]: 3 42 378 2508 13707 64650 272211 1045470 3721815 12425064 39254163 118191378 3*Lambda[0] + Lambda[2]: 1 23 234 1690 9689 47313 204247 800029 2893198 9786257 31262198 95035357 Lambda[0] + 2*Lambda[1]: 1 14 154 1160 6920 34756 153523 612354 2248318 7702198 24875351 76341630 Lambda[0] + Lambda[1] + Lambda[3] - 2*delta: 6 87 751 4779 25060 113971 464842 1736620 6034717 19723537 61152367 181068152 Lambda[0] + 2*Lambda[2] - 2*delta: 3 54 499 3349 18166 84836 353092 1341250 4725259 15625727 48938396 146190544 Lambda[0] + 2*Lambda[3] - 4*delta: 15 195 1539 9186 45804 200073 789201 2866560 9723582 31120281 94724550 275919741 + sage: V.print_strings() # long time py3 + 5*Lambda[0]: 3 42 378 2508 13707 64650 272211 1045470 3721815 12425064 39254163 118191378 + 3*Lambda[0] + Lambda[2]: 1 23 234 1690 9689 47313 204247 800029 2893198 9786257 31262198 95035357 + Lambda[0] + Lambda[1] + Lambda[3] - 2*delta: 6 87 751 4779 25060 113971 464842 1736620 6034717 19723537 61152367 181068152 + Lambda[0] + 2*Lambda[3] - 4*delta: 15 195 1539 9186 45804 200073 789201 2866560 9723582 31120281 94724550 275919741 + Lambda[0] + 2*Lambda[1]: 1 14 154 1160 6920 34756 153523 612354 2248318 7702198 24875351 76341630 + Lambda[0] + 2*Lambda[2] - 2*delta: 3 54 499 3349 18166 84836 353092 1341250 4725259 15625727 48938396 146190544 """ def __init__(self, Lam): """ @@ -910,13 +931,20 @@ def dominant_maximal_weights(self): EXAMPLES:: sage: Lambda = RootSystem(['C',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: IntegrableRepresentation(2*Lambda[0]).dominant_maximal_weights() + sage: IntegrableRepresentation(2*Lambda[0]).dominant_maximal_weights() # py2 (2*Lambda[0], Lambda[0] + Lambda[2] - delta, 2*Lambda[1] - delta, Lambda[1] + Lambda[3] - 2*delta, 2*Lambda[2] - 2*delta, 2*Lambda[3] - 3*delta) + sage: IntegrableRepresentation(2*Lambda[0]).dominant_maximal_weights() # py3 + (2*Lambda[0], + Lambda[0] + Lambda[2] - delta, + Lambda[1] + Lambda[3] - 2*delta, + 2*Lambda[3] - 3*delta, + 2*Lambda[1] - delta, + 2*Lambda[2] - 2*delta) """ k = self.level() Lambda = self._P.fundamental_weights() diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 512f51566ff..530b423bb53 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1062,7 +1062,7 @@ def _iter_topological_visit_(self, marked, sage: P.add(42) sage: P.add(5) sage: marked = set() - sage: list(P.null._iter_topological_visit_(marked, reverse=True)) + sage: list(P.null._iter_topological_visit_(marked, reverse=True, key=repr)) [oo, 42, 5, null] """ if (condition is not None and @@ -1129,7 +1129,7 @@ def iter_topological(self, reverse=False, key=None, condition=None): :: sage: for e in P.shells_topological(include_special=True, - ....: reverse=True): + ....: reverse=True, key=repr): ....: print(e) ....: print(list(e.iter_topological(reverse=True, key=repr))) oo @@ -1152,7 +1152,7 @@ def iter_topological(self, reverse=False, key=None, condition=None): :: sage: for e in P.shells_topological(include_special=True, - ....: reverse=True): + ....: reverse=True, key=repr): ....: print(e) ....: print(list(e.iter_topological(reverse=False, key=repr))) oo @@ -1175,7 +1175,8 @@ def iter_topological(self, reverse=False, key=None, condition=None): :: sage: list(P.null.iter_topological( - ....: reverse=True, condition=lambda s: s.element[0] == 1)) + ....: reverse=True, condition=lambda s: s.element[0] == 1, + ....: key=repr)) [(1, 3), (1, 2), (1, 1), null] .. SEEALSO:: @@ -1791,9 +1792,8 @@ def shells_topological(self, include_special=False, ``True`` gives largest first. - ``key`` -- (default: ``None``) a function used for sorting - the direct successors of a shell (used in case of a tie). If - this is ``None``, then the successors are sorted according - to their representation strings. + the direct successors of a shell (used in case of a tie). + If this is ``None``, no sorting occurs. OUTPUT: @@ -1812,14 +1812,14 @@ def shells_topological(self, include_special=False, ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), ....: T((4, 4)), T((1, 2)), T((2, 2))]) - sage: list(P.shells_topological()) + sage: list(P.shells_topological(key=repr)) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4)] - sage: list(P.shells_topological(reverse=True)) + sage: list(P.shells_topological(reverse=True, key=repr)) [(4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1)] - sage: list(P.shells_topological(include_special=True)) + sage: list(P.shells_topological(include_special=True, key=repr)) [null, (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (4, 4), oo] sage: list(P.shells_topological( - ....: include_special=True, reverse=True)) + ....: include_special=True, reverse=True, key=repr)) [oo, (4, 4), (1, 3), (2, 2), (1, 2), (2, 1), (1, 1), null] .. SEEALSO:: @@ -1832,8 +1832,6 @@ def shells_topological(self, include_special=False, :meth:`MutablePosetShell.iter_depth_first`, :meth:`MutablePosetShell.iter_topological`. """ - if key is None: - key = repr shell = self.oo if not reverse else self.null return iter(e for e in shell.iter_topological(reverse, key) if include_special or not e.is_special()) @@ -1904,7 +1902,7 @@ def elements_topological(self, **kwargs): ....: return all(l <= r for l, r in zip(left, right)) sage: P = MP([T((1, 1)), T((1, 3)), T((2, 1)), ....: T((4, 4)), T((1, 2)), T((2, 2))]) - sage: [(v, type(v)) for v in P.elements_topological()] + sage: [(v, type(v)) for v in P.elements_topological(key=repr)] [((1, 1), ), ((1, 2), ), ((1, 3), ), @@ -1988,15 +1986,15 @@ def keys_topological(self, **kwargs): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP([(1, 1), (2, 1), (4, 4)], ....: key=lambda c: c[0]) - sage: [(v, type(v)) for v in P.keys_topological()] + sage: [(v, type(v)) for v in P.keys_topological(key=repr)] [(1, ), (2, ), (4, )] - sage: [(v, type(v)) for v in P.elements_topological()] + sage: [(v, type(v)) for v in P.elements_topological(key=repr)] [((1, 1), <... 'tuple'>), ((2, 1), <... 'tuple'>), ((4, 4), <... 'tuple'>)] - sage: [(v, type(v)) for v in P.shells_topological()] + sage: [(v, type(v)) for v in P.shells_topological(key=repr)] [((1, 1), ), ((2, 1), ), ((4, 4), )] @@ -2043,7 +2041,8 @@ def repr(self, include_special=False, reverse=False): """ s = 'poset(' s += ', '.join(repr(shell) for shell in - self.shells_topological(include_special, reverse)) + self.shells_topological(include_special, reverse, + key=repr)) s += ')' return s @@ -2077,7 +2076,9 @@ def repr_full(self, reverse=False): | +-- no predecessors """ sortedshells = tuple( - self.shells_topological(include_special=True, reverse=reverse)) + self.shells_topological(include_special=True, + reverse=reverse, + key=repr)) strings = [self.repr(include_special=False, reverse=reverse)] for shell in sortedshells: strings.append('+-- ' + repr(shell)) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index aca06281f68..56bfea1111f 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -287,10 +287,11 @@ class OEIS: The database can be searched by subsequence:: - sage: search = oeis([1,2,3,5,8,13]) ; search # optional -- internet - 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. - 1: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2. - 2: ... + sage: search = oeis([1,2,3,5,8,13]) # optional -- internet + sage: search = sorted(search, key=lambda x: x.id()); search # optional -- internet + [A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1., + A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2., + A290689: Number of transitive rooted trees with n nodes.] sage: fibo = search[0] # optional -- internet @@ -331,11 +332,11 @@ class OEIS: The database can be searched by description:: - sage: oeis('prime gap factorization', max_results=4) # optional -- internet - 0: A073491: Numbers having no prime gaps in their factorization. - 1: A073490: Number of prime gaps in factorization of n. - 2: A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization. - 3: A073492: Numbers having at least one prime gap in their factorization. + sage: sorted(oeis('prime gap factorization', max_results=4), key=lambda x: x.id()) # optional --internet + [A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization., + A073490: Number of prime gaps in factorization of n., + A073491: Numbers having no prime gaps in their factorization., + A073492: Numbers having at least one prime gap in their factorization.] .. WARNING:: @@ -343,9 +344,7 @@ class OEIS: database, and once again for creating the sequence ``fibo``):: sage: oeis([1,2,3,5,8,13]) # optional -- internet - 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. - 1: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2. - 2: ... + ... sage: fibo = oeis('A000045') # optional -- internet @@ -353,10 +352,10 @@ class OEIS: Instead, do the following, to reuse the result of the search to create the sequence:: - sage: oeis([1,2,3,5,8,13]) # optional -- internet - 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. - 1: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2. - 2: ... + sage: sorted(oeis([1,2,3,5,8,13]), key=lambda x: x.id()) # optional -- internet + [A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1., + A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2., + A290689: Number of transitive rooted trees with n nodes.] sage: fibo = _[0] # optional -- internet """ @@ -447,10 +446,10 @@ def find_by_description(self, description, max_results=3, first_result=0): EXAMPLES:: - sage: oeis.find_by_description('prime gap factorization') # optional -- internet - 0: A073491: Numbers having no prime gaps in their factorization. - 1: A073490: Number of prime gaps in factorization of n. - 2: A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization. + sage: sorted(oeis.find_by_description('prime gap factorization'), key=lambda x: x.id()) # optional -- internet + [A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization., + A073490: Number of prime gaps in factorization of n., + A073491: Numbers having no prime gaps in their factorization.] sage: prime_gaps = _[1] ; prime_gaps # optional -- internet A073490: Number of prime gaps in factorization of n. diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 4b222dd1db9..549468cf1d4 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -545,16 +545,26 @@ def _run(self, test, compileflags, out): Check that :trac:`26038` is fixed:: - sage: a = 1 + sage: a = 1 # py2 ....: b = 2 Traceback (most recent call last): ... SyntaxError: doctest is not a single statement - sage: a = 1 + sage: a = 1 # py3 + ....: b = 2 + Traceback (most recent call last): + ... + SyntaxError: multiple statements found while compiling a single statement + sage: a = 1 # py2 ....: @syntax error Traceback (most recent call last): ... SyntaxError: invalid syntax + sage: a = 1 # py3 + ....: @syntax error + Traceback (most recent call last): + ... + SyntaxError: multiple statements found while compiling a single statement """ # Ensure that injecting globals works as expected in doctests set_globals(test.globs) diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index 368d93d66f8..5acf9711283 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -710,7 +710,7 @@ def create_doctests(self, namespace): sage: import sys sage: bitness = '64' if sys.maxsize > (1 << 32) else '32' - sage: n = -920390823904823094890238490238484; hash(n) > 0 + sage: gp.get_precision() == 38 False # 32-bit True # 64-bit sage: ex = doctests[18].examples[13] diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py index 4038c3e097b..4832647e3dc 100644 --- a/src/sage/doctest/test.py +++ b/src/sage/doctest/test.py @@ -229,7 +229,7 @@ sage: subprocess.call(["sage", "-tp", "1000000", "--timeout=120", # long time ....: "--warn-long", "0", "99seconds.rst", "interrupt_diehard.rst"], **kwds2) Running doctests... - Doctesting 2 files using 1000000 threads. + Doctesting 2 files using 1000000 threads... Killing test 99seconds.rst Killing test interrupt_diehard.rst ---------------------------------------------------------------------- diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index f4a6b9565b9..8d7e6f82601 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -5,7 +5,8 @@ supports symbolic functionality through Maxima and numeric evaluation through mpmath and scipy. -Airy functions are solutions to the differential equation `f''(x) - x f(x) = 0`. +Airy functions are solutions to the differential equation +`f''(x) - x f(x) = 0`. Four global function symbols are immediately available, please see @@ -35,22 +36,20 @@ 0 """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Oscar Gerardo Lazo Arjona # Copyright (C) 2012 Douglas McNeil # # 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/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.symbolic.function import BuiltinFunction from sage.symbolic.expression import Expression from sage.symbolic.ring import SR from sage.rings.integer_ring import ZZ -from sage.rings.real_double import RDF -from sage.rings.rational import Rational as R from sage.calculus.functional import derivative @@ -102,7 +101,8 @@ def _derivative_(self, alpha, x, diff_param=None): sage: derivative(airy_ai_general(n, x), n) Traceback (most recent call last): ... - NotImplementedError: cannot differentiate airy_ai in the first parameter + NotImplementedError: cannot differentiate airy_ai + in the first parameter """ if diff_param == 0: raise NotImplementedError("cannot differentiate airy_ai in the" @@ -217,10 +217,10 @@ def _evalf_(self, x, **kwargs): 0.006591139357460719 sage: airy_ai_simple(I).n(algorithm='scipy') # rel tol 1e-10 0.33149330543214117 - 0.3174498589684438*I - + TESTS:: - sage: parent(airy_ai_simple(3).n(algorithm='scipy')) + sage: parent(airy_ai_simple(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_ai_simple(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): @@ -231,16 +231,16 @@ def _evalf_(self, x, **kwargs): parent = kwargs.get('parent') if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: - raise NotImplementedError("%s not implemented for precision > 53"%self.name()) + raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.all import RR, CC - from sage.functions.other import real,imag + from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[0] if parent is None: return RR(y) else: - y = airy(complex(real(x),imag(x)))[0] + y = airy(complex(real(x), imag(x)))[0] if parent is None: return CC(y) return parent(y) @@ -315,30 +315,31 @@ def _evalf_(self, x, **kwargs): -0.00195864095020418 sage: airy_ai_prime(I).n(algorithm='scipy') # rel tol 1e-10 -0.43249265984180707 + 0.09804785622924324*I - + TESTS:: - sage: parent(airy_ai_prime(3).n(algorithm='scipy')) + sage: parent(airy_ai_prime(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_ai_prime(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): ... - NotImplementedError: airy_ai_prime not implemented for precision > 53 + NotImplementedError: airy_ai_prime not implemented + for precision > 53 """ algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath' parent = kwargs.get('parent', None) if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: - raise NotImplementedError("%s not implemented for precision > 53"%self.name()) + raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.all import RR, CC - from sage.functions.other import real,imag + from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[1] if parent is None: return RR(y) else: - y = airy(complex(real(x),imag(x)))[1] + y = airy(complex(real(x), imag(x)))[1] if parent is None: return CC(y) return parent(y) @@ -350,6 +351,7 @@ def _evalf_(self, x, **kwargs): else: raise ValueError("unknown algorithm '%s'" % algorithm) + airy_ai_general = FunctionAiryAiGeneral() airy_ai_simple = FunctionAiryAiSimple() airy_ai_prime = FunctionAiryAiPrime() @@ -453,7 +455,7 @@ def airy_ai(alpha, x=None, hold_derivative=True, **kwds): ....: (x, -10, 5), color='red') Graphics object consisting of 2 graphics primitives - **References** + REFERENCES: - Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 10" @@ -465,7 +467,7 @@ def airy_ai(alpha, x=None, hold_derivative=True, **kwds): return airy_ai_simple(x, **kwds) # We take care of all other cases. - if not alpha in ZZ and not isinstance(alpha, Expression): + if alpha not in ZZ and not isinstance(alpha, Expression): return airy_ai_general(alpha, x, **kwds) if hold_derivative: return airy_ai_general(alpha, x, **kwds) @@ -536,7 +538,8 @@ def _derivative_(self, alpha, x, diff_param=None): sage: derivative(airy_bi_general(n, x), n) Traceback (most recent call last): ... - NotImplementedError: cannot differentiate airy_bi in the first parameter + NotImplementedError: cannot differentiate airy_bi + in the first parameter """ if diff_param == 0: raise NotImplementedError("cannot differentiate airy_bi in the" @@ -651,10 +654,10 @@ def _evalf_(self, x, **kwargs): 14.037328963730136 sage: airy_bi_simple(I).n(algorithm='scipy') # rel tol 1e-10 0.648858208330395 + 0.34495863476804844*I - + TESTS:: - sage: parent(airy_bi_simple(3).n(algorithm='scipy')) + sage: parent(airy_bi_simple(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_bi_simple(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): @@ -665,16 +668,16 @@ def _evalf_(self, x, **kwargs): parent = kwargs.get('parent', None) if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: - raise NotImplementedError("%s not implemented for precision > 53"%self.name()) + raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.all import RR, CC - from sage.functions.other import real,imag + from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[2] if parent is None: return RR(y) else: - y = airy(complex(real(x),imag(x)))[2] + y = airy(complex(real(x), imag(x)))[2] if parent is None: return CC(y) return parent(y) @@ -749,30 +752,31 @@ def _evalf_(self, x, **kwargs): 161.92668350461398 sage: airy_bi_prime(I).n(algorithm='scipy') # rel tol 1e-10 0.135026646710819 - 0.1288373867812549*I - + TESTS:: - sage: parent(airy_bi_prime(3).n(algorithm='scipy')) + sage: parent(airy_bi_prime(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_bi_prime(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): ... - NotImplementedError: airy_bi_prime not implemented for precision > 53 + NotImplementedError: airy_bi_prime not implemented + for precision > 53 """ algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath' parent = kwargs.get('parent', None) if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: - raise NotImplementedError("%s not implemented for precision > 53"%self.name()) + raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.all import RR, CC - from sage.functions.other import real,imag + from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[3] if parent is None: return RR(y) else: - y = airy(complex(real(x),imag(x)))[3] + y = airy(complex(real(x), imag(x)))[3] if parent is None: return CC(y) return parent(y) @@ -784,6 +788,7 @@ def _evalf_(self, x, **kwargs): else: raise ValueError("unknown algorithm '%s'" % algorithm) + airy_bi_general = FunctionAiryBiGeneral() airy_bi_simple = FunctionAiryBiSimple() airy_bi_prime = FunctionAiryBiPrime() @@ -888,7 +893,7 @@ def airy_bi(alpha, x=None, hold_derivative=True, **kwds): ....: (x, -10, 5), color='red') Graphics object consisting of 2 graphics primitives - **References** + REFERENCES: - Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 10" @@ -900,7 +905,7 @@ def airy_bi(alpha, x=None, hold_derivative=True, **kwds): return airy_bi_simple(x, **kwds) # We take care of all other cases. - if not alpha in ZZ and not isinstance(alpha, Expression): + if alpha not in ZZ and not isinstance(alpha, Expression): return airy_bi_general(alpha, x, **kwds) if hold_derivative: return airy_bi_general(alpha, x, **kwds) diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index a82fa942c6d..d3261e00b83 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -195,8 +195,7 @@ - [WP-Struve]_ """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Benjamin Jones # # Distributed under the terms of the GNU General Public License (GPL) @@ -208,31 +207,23 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function from sage.functions.other import sqrt from sage.functions.log import exp from sage.functions.hyperbolic import sinh, cosh +from sage.functions.trig import sin, cos from sage.libs.mpmath import utils as mpmath_utils from sage.misc.latex import latex -from sage.rings.all import RR, Integer -from sage.structure.element import parent, get_coercion_model +from sage.rings.all import Integer, ZZ, QQ +from sage.structure.element import get_coercion_model from sage.symbolic.constants import pi from sage.symbolic.ring import SR from sage.symbolic.function import BuiltinFunction from sage.symbolic.expression import Expression -# remove after deprecation period -from sage.calculus.calculus import maxima -from sage.functions.trig import sin, cos -from sage.functions.other import real, imag, sqrt -from sage.misc.sage_eval import sage_eval -from sage.rings.real_mpfr import RealField -from sage.plot.plot import plot -from sage.rings.all import ZZ, QQ - class Function_Bessel_J(BuiltinFunction): r""" @@ -1202,11 +1193,6 @@ def Bessel(*args, **kwds): _type = 'J' if not (_type in ['I', 'J', 'K', 'Y']): raise ValueError("type must be one of I, J, K, Y") - # record the numerical evaluation system - if 'algorithm' in kwds: - _system = kwds['algorithm'] - else: - _system = 'mpmath' # return the function _f = bessel_type_dict[_type] diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index 8f0ae04e929..1844c39e4da 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -2,19 +2,14 @@ Gamma and related functions """ from __future__ import print_function, absolute_import -from six.moves import range -from six import integer_types from sage.symbolic.function import GinacFunction, BuiltinFunction -from sage.libs.pynac.pynac import (register_symbol, symbol_table, - py_factorial_py, I) -from sage.structure.element import coercion_model +from sage.libs.pynac.pynac import (register_symbol, symbol_table) from sage.structure.all import parent as s_parent -from sage.symbolic.expression import Expression -from sage.rings.all import Integer, Rational, RealField, ZZ, ComplexField +from sage.rings.all import Rational, ComplexField +from sage.rings.complex_number import is_ComplexNumber from sage.functions.exp_integral import Ei from sage.libs.mpmath import utils as mpmath_utils -from sage.arith.all import binomial as arith_binomial from .log import exp from .other import sqrt from sage.symbolic.constants import pi diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 263f51191d1..767283ef145 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -282,8 +282,7 @@ Willis of the University of Nebraska at Kearney. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # 2006 David Joyner # 2010 Stefan Reiterer @@ -297,28 +296,25 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from six.moves import range import warnings from sage.misc.latex import latex -from sage.misc.sage_eval import sage_eval from sage.rings.all import ZZ, QQ, RR, CC -from sage.rings.polynomial.polynomial_element import Polynomial -from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.real_mpfr import is_RealField from sage.rings.complex_field import is_ComplexField - -from sage.symbolic.ring import SR, is_SymbolicVariable from sage.symbolic.function import BuiltinFunction, GinacFunction from sage.symbolic.expression import Expression +from sage.symbolic.all import SR from sage.functions.other import factorial, binomial from sage.structure.all import parent + class OrthogonalFunction(BuiltinFunction): """ Base class for orthogonal polynomials. diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 9d140d7b14a..2c22a61c46e 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -26,7 +26,6 @@ from sage.libs.pynac.pynac import (register_symbol, symbol_table, I) from sage.symbolic.all import SR from sage.rings.all import Integer, Rational, RealField, ZZ, ComplexField -from sage.rings.complex_number import is_ComplexNumber from sage.misc.latex import latex import math @@ -35,11 +34,7 @@ # avoid name conflicts with `parent` as a function parameter from sage.structure.all import parent as s_parent -from sage.symbolic.constants import pi -from sage.functions.log import exp from sage.functions.trig import arctan2 -from sage.functions.exp_integral import Ei -from sage.libs.mpmath import utils as mpmath_utils from sage.arith.all import binomial as arith_binomial one_half = SR.one() / SR(2) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 6d1011e3684..9e573519901 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -159,17 +159,11 @@ # **************************************************************************** from sage.rings.integer import Integer -from sage.rings.real_mpfr import RealField from sage.rings.complex_field import ComplexField from sage.misc.latex import latex -from sage.rings.all import ZZ, RR, RDF, CDF -from .gamma import log_gamma -from .other import real, imag +from sage.rings.all import ZZ from sage.symbolic.constants import pi from sage.symbolic.function import BuiltinFunction -from sage.symbolic.expression import Expression -from sage.calculus.calculus import maxima -from sage.structure.element import parent from sage.libs.mpmath import utils as mpmath_utils from sage.functions.all import sqrt, sin, cot, exp from sage.symbolic.all import I @@ -551,7 +545,7 @@ def _evalf_(self, x, parent=None, algorithm=None): sage: elliptic_ec(I).n() 1.63241178144043 - 0.369219492375499*I """ - R = parent or parent(z) + R = parent or parent(x) from mpmath import ellipe return mpmath_utils.call(ellipe, x, parent=R) @@ -623,7 +617,7 @@ def _evalf_(self, u, m, parent=None, algorithm=None): sage: elliptic_eu(1,1).n(200) 0.7615941559557648881194582... """ - R = parent or parent(z) + R = parent or parent(u) return mpmath_utils.call(elliptic_eu_f, u, m, parent=R) def _derivative_(self, u, m, diff_param): diff --git a/src/sage/functions/trig.py b/src/sage/functions/trig.py index 5f760912f09..fbee1cd0cc8 100644 --- a/src/sage/functions/trig.py +++ b/src/sage/functions/trig.py @@ -1,8 +1,7 @@ r""" Trigonometric Functions """ -from sage.symbolic.function import BuiltinFunction, GinacFunction -from sage.symbolic.expression import is_Expression +from sage.symbolic.function import GinacFunction import math diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 7072367c3f6..4e144f7a142 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -176,7 +176,7 @@ REFERENCES: -- [Fu1993]_ +- [Ful1993]_ """ # **************************************************************************** @@ -1244,9 +1244,9 @@ def classify_cone_2d(ray0, ray1, check=True): OUTPUT: A pair `(d,k)` of integers classifying the cone up to `GL(2, \ZZ)` - equivalence. See Proposition 10.1.1 of [CLS]_ for the + equivalence. See Proposition 10.1.1 of [CLS2011]_ for the definition. We return the unique `(d,k)` with minimal `k`, see - Proposition 10.1.3 of [CLS]_. + Proposition 10.1.3 of [CLS2011]_. EXAMPLES:: @@ -1272,7 +1272,7 @@ def classify_cone_2d(ray0, ray1, check=True): Check using the connection between the Hilbert basis of the cone spanned by the two rays (in arbitrary dimension) and the Hirzebruch-Jung continued fraction expansion, see Chapter 10 of - [CLS]_ :: + [CLS2011]_ :: sage: from sage.geometry.cone import normalize_rays sage: for i in range(10): @@ -1316,7 +1316,7 @@ def classify_cone_2d(ray0, ray1, check=True): assert 0 <= k < d assert gcd(d,k) == 1 - # compute unique k, see Proposition 10.1.3 of [CLS] + # compute unique k, see Proposition 10.1.3 of [CLS2011] if d > 0: for ktilde in range(k): if (k*ktilde) % d == 1: @@ -3522,7 +3522,7 @@ def sublattice(self, *args, **kwds): The sublattice spanned by the cone. Let `\sigma` be the given cone and `N=` ``self.lattice()`` the - ambient lattice. Then, in the notation of [Fu1993]_, this + ambient lattice. Then, in the notation of [Ful1993]_, this method returns the sublattice .. MATH:: @@ -3641,7 +3641,7 @@ def sublattice_complement(self, *args, **kwds): `\ZZ`-basis for the ambient :meth:`lattice() `. - In the notation of [Fu1993]_, let `\sigma` be the given cone + In the notation of [Ful1993]_, let `\sigma` be the given cone and `N=` ``self.lattice()`` the ambient lattice. Then this method returns @@ -3700,7 +3700,7 @@ def orthogonal_sublattice(self, *args, **kwds): Let `M=` ``self.dual_lattice()`` be the lattice dual to the ambient lattice of the given cone `\sigma`. Then, in the - notation of [Fu1993]_, this method returns the sublattice + notation of [Ful1993]_, this method returns the sublattice .. MATH:: @@ -3763,7 +3763,7 @@ def relative_quotient(self, subcone): The quotient of the spanned lattice by the lattice spanned by a subcone. - In the notation of [Fu1993]_, let `N` be the ambient lattice + In the notation of [Ful1993]_, let `N` be the ambient lattice and `N_\sigma` the sublattice spanned by the given cone `\sigma`. If `\rho < \sigma` is a subcone, then `N_\rho` = ``rho.sublattice()`` is a saturated sublattice of `N_\sigma` = @@ -3863,7 +3863,7 @@ def relative_orthogonal_quotient(self, supercone): The quotient of the dual spanned lattice by the dual of the supercone's spanned lattice. - In the notation of [Fu1993]_, if ``supercone`` = `\rho > + In the notation of [Ful1993]_, if ``supercone`` = `\rho > \sigma` = ``self`` is a cone that contains `\sigma` as a face, then `M(\rho)` = ``supercone.orthogonal_sublattice()`` is a saturated sublattice of `M(\sigma)` = diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index e0746668198..300356e3141 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -3348,7 +3348,7 @@ def complex(self, base_ring=ZZ, extended=False): 0 where the leftmost non-zero entry is in degree `0` and the - rightmost entry in degree `d`. See [Klyachko]_, eq. (3.2). This + rightmost entry in degree `d`. See [Kly1990]_, eq. (3.2). This complex computes the homology of `|\Sigma|\subset N_\RR` with arbitrary support, diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 112272b6db4..e942cd51f63 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- """ The Normaliz backend for polyhedral computations @@ -10,6 +10,7 @@ AUTHORS: - Matthias Köppe (2016-12): initial version +- Jean-Philippe Labbé (2019-04): Expose normaliz features and added functionalities """ #***************************************************************************** @@ -26,6 +27,7 @@ from sage.structure.element import Element from sage.misc.all import prod +from sage.features import PythonModule from sage.rings.all import ZZ, QQ from sage.arith.functions import LCM_list @@ -49,7 +51,7 @@ def _format_function_call(fn_name, *v, **k): sage: _format_function_call('foo', 17, hellooooo='goodbyeeee') "foo(17, hellooooo='goodbyeeee')" """ - args = [ repr(a) for a in v ] + [ "%s=%r" % (arg,val) for arg, val in sorted(k.items()) ] + args = [ repr(a) for a in v ] + [ "%s=%r" % (arg, val) for arg, val in sorted(k.items()) ] return "{}({})".format(fn_name, ", ".join(args)) ######################################################################### @@ -188,6 +190,7 @@ def _nmz_result(self, normaliz_cone, property): ... NormalizError: Some error in the normaliz input data detected: Unknown ConeProperty... """ + PythonModule("PyNormaliz", spkg="pynormaliz").require() import PyNormaliz return PyNormaliz.NmzResult(normaliz_cone, property) @@ -237,6 +240,7 @@ def _init_from_normaliz_data(self, data, verbose=False): if verbose: print("# Calling {}".format(_format_function_call('PyNormaliz.NmzCone', **data))) + PythonModule("PyNormaliz", spkg="pynormaliz").require() import PyNormaliz cone = PyNormaliz.NmzCone(**data) assert cone, "{} did not return a cone".format(_format_function_call('PyNormaliz.NmzCone', **data)) @@ -373,6 +377,7 @@ def vert_ray_line_QQ(): data = {"vertices": nmz_vertices, "cone": nmz_rays, "subspace": nmz_lines} + self._init_from_normaliz_data(data, verbose=verbose) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): @@ -548,6 +553,7 @@ def _make_normaliz_cone(data, verbose=False): sage: NmzResult(nmz_cone, "ExtremeRays") # optional - pynormaliz [[1L, 2L, 0L], [2L, 1L, 0L]] """ + PythonModule("PyNormaliz", spkg="pynormaliz").require() import PyNormaliz if verbose: print("# Calling PyNormaliz.NmzCone(**{})".format(data)) @@ -555,6 +561,34 @@ def _make_normaliz_cone(data, verbose=False): assert cone, "NmzCone(**{}) did not return a cone".format(data) return cone + @staticmethod + def _cone_generators(pynormaliz_cone): + r""" + Returns the generators of a pynormaliz cone. + + This is particularly useful to get the reordering of the vertices (or + rays) that is internally used by normaliz. + + INPUT: + + - ``pynormaliz_cone`` -- a pynormaliz cone object. + + OUTPUT: + + - a tuple of generators for the cone. + + TESTS:: + + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz + sage: data = {'inhom_inequalities': [[-1L, 2L, 0L], [0L, 0L, 1L], [2L, -1L, 0L]]} # optional - pynormaliz + sage: nmz_cone = Polyhedron_normaliz._make_normaliz_cone(data,verbose=False) # optional - pynormaliz + sage: Polyhedron_normaliz._cone_generators(nmz_cone) # optional - pynormaliz + [[1L, 2L, 0L], [0L, 0L, 1L], [2L, 1L, 0L]] + """ + PythonModule("PyNormaliz", spkg="pynormaliz").require() + import PyNormaliz + return PyNormaliz.NmzResult(pynormaliz_cone, "Generators") + def _get_nmzcone_data(self): r""" Get the data necessary to reproduce the normaliz cone. @@ -581,16 +615,15 @@ def _get_nmzcone_data(self): 'subspace': [], 'vertices': [[0L, 0L, 1L]]} """ - import PyNormaliz if self.is_empty(): return {} - vertices = PyNormaliz.NmzResult(self._normaliz_cone, "VerticesOfPolyhedron") + vertices = self._nmz_result(self._normaliz_cone, "VerticesOfPolyhedron") # get rid of the last 0 in rays: - rays = [r[:-1] for r in PyNormaliz.NmzResult(self._normaliz_cone, "ExtremeRays")] - lines = PyNormaliz.NmzResult(self._normaliz_cone, "MaximalSubspace") - ineqs = PyNormaliz.NmzResult(self._normaliz_cone, "SupportHyperplanes") - eqs = PyNormaliz.NmzResult(self._normaliz_cone, "Equations") + rays = [r[:-1] for r in self._nmz_result(self._normaliz_cone, "ExtremeRays")] + lines = self._nmz_result(self._normaliz_cone, "MaximalSubspace") + ineqs = self._nmz_result(self._normaliz_cone, "SupportHyperplanes") + eqs = self._nmz_result(self._normaliz_cone, "Equations") data = {'vertices': vertices, 'cone': rays, @@ -653,25 +686,6 @@ def format_field(key, value): else: return s - -######################################################################### -class Polyhedron_QQ_normaliz(Polyhedron_normaliz, Polyhedron_QQ): - r""" - Polyhedra over `\QQ` with normaliz. - - INPUT: - - - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None`` - - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None`` - - EXAMPLES:: - - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - pynormaliz - ....: rays=[(1,1)], lines=[], - ....: backend='normaliz', base_ring=QQ) - sage: TestSuite(p).run(skip='_test_pickling') # optional - pynormaliz - """ - def integral_hull(self): r""" Return the integral hull in the polyhedron. @@ -714,6 +728,254 @@ def integral_hull(self): return self.parent().element_class._from_normaliz_cone(parent=self.parent(), normaliz_cone=cone) + def ehrhart_series(self, variable='t'): + r""" + Return the Ehrhart series of a compact rational polyhedron. + + The Ehrhart series is the generating function where the coefficient of + `t^k` is number of integer lattice points inside the `k`-th dilation of + the polytope. + + INPUT: + + - ``variable`` -- string (default: ``'t'``) + + OUTPUT: + + A rational function. + + EXAMPLES:: + + sage: S = Polyhedron(vertices=[[0,1],[1,0]], backend='normaliz') # optional - pynormaliz + sage: ES = S.ehrhart_series() # optional - pynormaliz + sage: ES.numerator() # optional - pynormaliz + 1 + sage: ES.denominator().factor() # optional - pynormaliz + (t - 1)^2 + + sage: C = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]],backend='normaliz') # optional - pynormaliz + sage: ES = C.ehrhart_series() # optional - pynormaliz + sage: ES.numerator() # optional - pynormaliz + t^2 + 4*t + 1 + sage: ES.denominator().factor() # optional - pynormaliz + (t - 1)^4 + + The following example is from the Normaliz manual contained in the file + ``rational.in``:: + + sage: rat_poly = Polyhedron(vertices=[[1/2,1/2],[-1/3,-1/3],[1/4,-1/2]],backend='normaliz') # optional - pynormaliz + sage: ES = rat_poly.ehrhart_series() # optional - pynormaliz + sage: ES.numerator() # optional - pynormaliz + 2*t^6 + 3*t^5 + 4*t^4 + 3*t^3 + t^2 + t + 1 + sage: ES.denominator().factor() # optional - pynormaliz + (-1) * (t + 1)^2 * (t - 1)^3 * (t^2 + 1) * (t^2 + t + 1) + + The polyhedron should be compact:: + + sage: C = Polyhedron(backend='normaliz',rays=[[1,2],[2,1]]) # optional - pynormaliz + sage: C.ehrhart_series() # optional - pynormaliz + Traceback (most recent call last): + ... + NotImplementedError: Ehrhart series can only be computed for compact polyhedron + + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.backend_normaliz.hilbert_series` + """ + if self.is_empty(): + return 0 + + if not self.is_compact(): + raise NotImplementedError("Ehrhart series can only be computed for compact polyhedron") + + cone = self._normaliz_cone + e = self._nmz_result(cone, "EhrhartSeries") + # The output format of PyNormaliz is a list with 3 things: + # 1) the coefficients of the h^*-polynomial + # 2) a list of the exponents e such that (1-t^e) appears as a factor in + # the denominator + # 3) a shifting of the generating function. + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.rings.fraction_field import FractionField + poly_ring = FractionField(PolynomialRing(ZZ, variable)) + t = poly_ring.gens()[0] + es = sum([e[0][i]*t**i for i in range(len(e[0]))]) + for expo in range(len(e[1])): + es = es / (1 - t**e[1][expo]) + + # The shift: + es = es * t**e[2] + + return es + + def ehrhart_quasipolynomial(self, variable='t'): + r""" + Return the Ehrhart quasi-polynomial of a compact rational polyhedron + using Normaliz. + + INPUT: + + - ``variable`` -- string (default: ``'t'``) + + OUTPUT: + + If it is a polynomial, returns the polynomial. Otherwise, returns a + tuple of rational polynomials whose length is the quasi-period of the + quasi-polynomial and each rational polynomial describes a residue class. + + EXAMPLES:: + + sage: C = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]],backend='normaliz') # optional - pynormaliz + sage: C.ehrhart_quasipolynomial() # optional - pynormaliz + t^3 + 3*t^2 + 3*t + 1 + + sage: P = Polyhedron(vertices=[[0,0],[3/2,0],[0,3/2],[1,1]],backend='normaliz') # optional - pynormaliz + sage: P.ehrhart_quasipolynomial() # optional - pynormaliz + (3/2*t^2 + 2*t + 1, 3/2*t^2 + 2*t + 1/2) + sage: P.ehrhart_quasipolynomial('x') # optional - pynormaliz + (3/2*x^2 + 2*x + 1, 3/2*x^2 + 2*x + 1/2) + + The quasi-polynomial evaluated at ``i`` counts the integral points + in the ``i``-th dilate:: + + sage: Q = Polyhedron(vertices = [[-1/3],[2/3]],backend='normaliz') # optional - pynormaliz + sage: p0,p1,p2 = Q.ehrhart_quasipolynomial() # optional - pynormaliz + sage: r0 = [p0(i) for i in range(15)] # optional - pynormaliz + sage: r1 = [p1(i) for i in range(15)] # optional - pynormaliz + sage: r2 = [p2(i) for i in range(15)] # optional - pynormaliz + sage: result = [None]*15 # optional - pynormaliz + sage: result[::3] = r0[::3] # optional - pynormaliz + sage: result[1::3] = r1[1::3] # optional - pynormaliz + sage: result[2::3] = r2[2::3] # optional - pynormaliz + sage: result == [(i*Q).integral_points_count() for i in range(15)] # optional - pynormaliz + True + + The polyhedron should be compact:: + + sage: C = Polyhedron(backend='normaliz',rays=[[1,2],[2,1]]) # optional - pynormaliz + sage: C.ehrhart_quasipolynomial() # optional - pynormaliz + Traceback (most recent call last): + ... + NotImplementedError: Ehrhart quasi-polynomial can only be computed for compact polyhedron + + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.backend_normaliz.hilbert_series`, + :meth:`~sage.geometry.polyhedron.backend_normaliz.ehrhart_series` + """ + if self.is_empty(): + return 0 + + if not self.is_compact(): + raise NotImplementedError("Ehrhart quasi-polynomial can only be computed for compact polyhedron") + + cone = self._normaliz_cone + # Normaliz needs to compute the EhrhartSeries first + PythonModule("PyNormaliz", spkg="pynormaliz").require() + import PyNormaliz + assert PyNormaliz.NmzCompute(cone, ["EhrhartSeries"]) + e = self._nmz_result(cone, "EhrhartQuasiPolynomial") + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + poly_ring = PolynomialRing(QQ, variable) + t = poly_ring.gens()[0] + if len(e) == 2: + # It is a polynomial + es = sum([e[0][i]*t**i for i in range(len(e[0]))]) + return es / ZZ(e[1]) + else: + # It is a quasi-polynomial + polynomials = [] + for p in e[:-1]: + es = sum([p[i]*t**i for i in range(len(p))]) / ZZ(e[-1]) + polynomials += [es] + + return tuple(polynomials) + + def hilbert_series(self, grading, variable='t'): + r""" + Return the Hilbert series of the polyhedron with respect to ``grading``. + + INPUT: + + - ``grading`` -- vector. The grading to use to form the Hilbert series + + - ``variable`` -- string (default: ``'t'``) + + OUTPUT: + + A rational function. + + EXAMPLES:: + + sage: C = Polyhedron(backend='normaliz',rays=[[0,0,1],[0,1,1],[1,0,1],[1,1,1]]) # optional - pynormaliz + sage: HS = C.hilbert_series([1,1,1]) # optional - pynormaliz + sage: HS.numerator() # optional - pynormaliz + t^2 + 1 + sage: HS.denominator().factor() # optional - pynormaliz + (-1) * (t + 1) * (t - 1)^3 * (t^2 + t + 1) + + By changing the grading, you can get the Ehrhart series of the square + lifted at height 1:: + + sage: C.hilbert_series([0,0,1]) # optional - pynormaliz + (t + 1)/(-t^3 + 3*t^2 - 3*t + 1) + + Here is an example ``2cone.in`` from the Normaliz manual:: + + sage: C = Polyhedron(backend='normaliz',rays=[[1,3],[2,1]]) # optional - pynormaliz + sage: HS = C.hilbert_series([1,1]) # optional - pynormaliz + sage: HS.numerator() # optional - pynormaliz + t^5 + t^4 + t^3 + t^2 + 1 + sage: HS.denominator().factor() # optional - pynormaliz + (t + 1) * (t - 1)^2 * (t^2 + 1) * (t^2 + t + 1) + + sage: HS = C.hilbert_series([1,2]) # optional - pynormaliz + sage: HS.numerator() # optional - pynormaliz + t^8 + t^6 + t^5 + t^3 + 1 + sage: HS.denominator().factor() # optional - pynormaliz + (t + 1) * (t - 1)^2 * (t^2 + 1) * (t^6 + t^5 + t^4 + t^3 + t^2 + t + 1) + + Here is the magic square example form the Normaliz manual:: + + sage: eq = [[0,1,1,1,-1,-1,-1, 0, 0, 0], + ....: [0,1,1,1, 0, 0, 0,-1,-1,-1], + ....: [0,0,1,1,-1, 0, 0,-1, 0, 0], + ....: [0,1,0,1, 0,-1, 0, 0,-1, 0], + ....: [0,1,1,0, 0, 0,-1, 0, 0,-1], + ....: [0,0,1,1, 0,-1, 0, 0, 0,-1], + ....: [0,1,1,0, 0,-1, 0,-1, 0, 0]] + sage: magic_square = Polyhedron(eqns=eq,backend='normaliz') & Polyhedron(rays=identity_matrix(9).rows()) # optional - pynormaliz + sage: grading = [1,1,1,0,0,0,0,0,0] + sage: magic_square.hilbert_series(grading) # optional - pynormaliz + (t^6 + 2*t^3 + 1)/(-t^9 + 3*t^6 - 3*t^3 + 1) + + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.backend_normaliz.ehrhart_series` + """ + if self.is_empty(): + return 0 + + data = self._get_nmzcone_data() + data['grading'] = [grading] + new_cone = self._make_normaliz_cone(data) + h = self._nmz_result(new_cone, "HilbertSeries") + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.rings.fraction_field import FractionField + poly_ring = FractionField(PolynomialRing(ZZ, variable)) + t = poly_ring.gens()[0] + hs = sum([h[0][i]*t**i for i in range(len(h[0]))]) + for expo in range(len(h[1])): + hs = hs / (1 - t**h[1][expo]) + + # The shift: + hs = hs * t**h[2] + + return hs + def integral_points(self, threshold=10000): r""" Return the integral points in the polyhedron. @@ -927,7 +1189,7 @@ def integral_points(self, threshold=10000): if box_min is None: return () box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) - if box_points= 2 and self.rays_list(): # A mix of polytope and cone + raise NotImplementedError("triangulation of non-compact polyhedra that are not cones is not supported") + + data = self._get_nmzcone_data() + # Recreates a pointed cone. This is a hack and should be fixed once + # Normaliz accepts compact polyhedron + # For now, we lose the information about the volume? + # if self.is_compact(): + # data['cone'] = data['vertices'] + if not self.is_compact(): + data.pop('vertices', None) + data.pop('inhom_equations', None) + data.pop('inhom_inequalities', None) + cone = self._make_normaliz_cone(data) + + nmz_triangulation = self._nmz_result(cone, "Triangulation") + triang_indices = tuple(vector(ZZ, s[0]) for s in nmz_triangulation) + + # Get the Normaliz ordering of generators + if self.is_compact(): + generators = [list(vector(ZZ, g)[:-1]) for g in self._cone_generators(cone)] + else: + generators = [list(vector(ZZ, g)) for g in self._cone_generators(cone)] + + # Get the Sage ordering of generators + if self.is_compact(): + poly_gen = self.vertices_list() + else: + poly_gen = self.rays_list() + + # When triangulating, Normaliz uses the indexing of 'Generators' and + # not necessarily the indexing of the V-representation. So we apply the + # appropriate relabeling into the V-representation inside sage. + triangulation = [tuple(sorted([poly_gen.index(generators[i]) for i in s])) for s in triang_indices] + + return triangulation + +######################################################################### +class Polyhedron_QQ_normaliz(Polyhedron_normaliz, Polyhedron_QQ): + r""" + Polyhedra over `\QQ` with normaliz. + + INPUT: + + - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None`` + - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None`` + + EXAMPLES:: + + sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - pynormaliz + ....: rays=[(1,1)], lines=[], + ....: backend='normaliz', base_ring=QQ) + sage: TestSuite(p).run(skip='_test_pickling') # optional - pynormaliz + """ + pass + ######################################################################### class Polyhedron_ZZ_normaliz(Polyhedron_QQ_normaliz, Polyhedron_ZZ): r""" @@ -957,4 +1412,3 @@ class Polyhedron_ZZ_normaliz(Polyhedron_QQ_normaliz, Polyhedron_ZZ): sage: TestSuite(p).run(skip='_test_pickling') # optional - pynormaliz """ pass - diff --git a/src/sage/geometry/polyhedron/backend_polymake.py b/src/sage/geometry/polyhedron/backend_polymake.py index e244e45b5e1..976750cc3ac 100644 --- a/src/sage/geometry/polyhedron/backend_polymake.py +++ b/src/sage/geometry/polyhedron/backend_polymake.py @@ -26,8 +26,6 @@ from sage.structure.element import Element -from sage.rings.all import ZZ, QQ - from .base import Polyhedron_base from .base_QQ import Polyhedron_QQ from .base_ZZ import Polyhedron_ZZ diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 753ea409a3a..8240cb1e564 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -212,9 +212,9 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, **kwds): sage: Polyhedron_base._init_from_Vrepresentation(p, [], [], []) Traceback (most recent call last): ... - NotImplementedError: A derived class must implement this method. + NotImplementedError: a derived class must implement this method """ - raise NotImplementedError('A derived class must implement this method.') + raise NotImplementedError('a derived class must implement this method') def _init_from_Hrepresentation(self, ieqs, eqns, **kwds): """ @@ -237,9 +237,9 @@ def _init_from_Hrepresentation(self, ieqs, eqns, **kwds): sage: Polyhedron_base._init_from_Hrepresentation(p, [], []) Traceback (most recent call last): ... - NotImplementedError: A derived class must implement this method. + NotImplementedError: a derived class must implement this method """ - raise NotImplementedError('A derived class must implement this method.') + raise NotImplementedError('a derived class must implement this method') def _init_empty_polyhedron(self): """ @@ -391,7 +391,7 @@ def base_extend(self, base_ring, backend=None): INPUT: - - ``base_ring`` -- the new base ring. + - ``base_ring`` -- the new base ring - ``backend`` -- the new backend, see :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. @@ -433,7 +433,7 @@ def change_ring(self, base_ring, backend=None): INPUT: - - ``base_ring`` -- the new base ring. + - ``base_ring`` -- the new base ring - ``backend`` -- the new backend or ``None`` (default), see :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. @@ -570,11 +570,11 @@ def _is_subpolyhedron(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron`. + - ``other`` -- a :class:`Polyhedron` OUTPUT: - Boolean. + Boolean EXAMPLES:: @@ -1058,7 +1058,7 @@ def cdd_Hrepresentation(self): sage: triangle.cdd_Hrepresentation() Traceback (most recent call last): ... - TypeError: The base ring must be ZZ, QQ, or RDF + TypeError: the base ring must be ZZ, QQ, or RDF """ from .cdd_file_format import cdd_Hrepresentation try: @@ -1069,7 +1069,7 @@ def cdd_Hrepresentation(self): elif self.base_ring() is RDF: cdd_type = 'real' else: - raise TypeError('The base ring must be ZZ, QQ, or RDF') + raise TypeError('the base ring must be ZZ, QQ, or RDF') return cdd_Hrepresentation(cdd_type, list(self.inequality_generator()), list(self.equation_generator())) @@ -1130,7 +1130,7 @@ def cdd_Vrepresentation(self): elif self.base_ring() is RDF: cdd_type = 'real' else: - raise TypeError('The base ring must be ZZ, QQ, or RDF') + raise TypeError('the base ring must be ZZ, QQ, or RDF') return cdd_Vrepresentation(cdd_type, list(self.vertex_generator()), list(self.ray_generator()), @@ -1362,7 +1362,7 @@ def Hrepresentation(self, index=None): INPUT: - - ``index`` -- either an integer or ``None``. + - ``index`` -- either an integer or ``None`` OUTPUT: @@ -1568,7 +1568,7 @@ def Vrepresentation(self, index=None): INPUT: - - ``index`` -- either an integer or ``None``. + - ``index`` -- either an integer or ``None`` OUTPUT: @@ -2511,7 +2511,7 @@ def is_inscribed(self, certificate=False): INPUT: - ``certificate`` -- (default: ``False``) boolean; specifies whether to - return the circumcenter, if found + return the circumcenter, if found. OUTPUT: @@ -2553,20 +2553,20 @@ def is_inscribed(self, certificate=False): sage: square.is_inscribed() Traceback (most recent call last): ... - NotImplementedError: This function is implemented for full-dimensional polyhedron only. + NotImplementedError: this function is implemented for full-dimensional polyhedron only sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)]) sage: p.is_inscribed() Traceback (most recent call last): ... - NotImplementedError: This function is not implemented for unbounded polyhedron. + NotImplementedError: this function is not implemented for unbounded polyhedron """ if not self.is_compact(): - raise NotImplementedError("This function is not implemented for unbounded polyhedron.") + raise NotImplementedError("this function is not implemented for unbounded polyhedron") if not self.is_full_dimensional(): - raise NotImplementedError("This function is implemented for full-dimensional polyhedron only.") + raise NotImplementedError("this function is implemented for full-dimensional polyhedron only") dimension = self.dimension() vertices = self.vertices() @@ -2679,10 +2679,10 @@ def is_simplicial(self): sage: p.is_simplicial() Traceback (most recent call last): ... - NotImplementedError: This function is implemented for polytopes only. + NotImplementedError: this function is implemented for polytopes only """ if not(self.is_compact()): - raise NotImplementedError("This function is implemented for polytopes only.") + raise NotImplementedError("this function is implemented for polytopes only") d = self.dim() return all(len([vertex for vertex in face.incident()]) == d for face in self.Hrepresentation()) @@ -2737,8 +2737,16 @@ def gale_transform(self): REFERENCES: Lectures in Geometric Combinatorics, R.R.Thomas, 2006, AMS Press. + + TESTS:: + + sage: P = Polyhedron(rays=[[1,0,0]]) + sage: P.gale_transform() + Traceback (most recent call last): + ... + ValueError: not a polytope """ - if not self.is_compact(): raise ValueError('Not a polytope.') + if not self.is_compact(): raise ValueError('not a polytope') A = matrix(self.n_vertices(), [ [1]+x for x in self.vertex_generator()]) @@ -2854,17 +2862,41 @@ def face_fan(self): return FaceFan(self) + def _triangulate_normaliz(self): + r""" + Gives a triangulation of the polyhedron using normaliz + + OUTPUT: + + A tuple of pairs ``(simplex,simplex_volume)`` used in the + triangulation. + + .. NOTE:: + + This function depends on Normaliz (i.e. the ``pynormaliz`` optional + package). See the Normaliz documentation for further details. + + TESTS:: + + sage: K = Polyhedron(vertices=[[1,1]], rays=[[1,0],[1,2]]) + sage: K._triangulate_normaliz() + Traceback (most recent call last): + ... + TypeError: the polyhedron's backend should be 'normaliz' + """ + raise TypeError("the polyhedron's backend should be 'normaliz'") + def triangulate(self, engine='auto', connected=True, fine=False, regular=None, star=None): r""" Returns a triangulation of the polytope. INPUT: - - ``engine`` -- either 'auto' (default), 'internal', or - 'TOPCOM'. The latter two instruct this package to always - use its own triangulation algorithms or TOPCOM's algorithms, - respectively. By default ('auto'), TOPCOM is used if it is - available and internal routines otherwise. + - ``engine`` -- either 'auto' (default), 'internal', + 'TOPCOM', or 'normaliz'. The 'internal' and 'TOPCOM' instruct + this package to always use its own triangulation algorithms + or TOPCOM's algorithms, respectively. By default ('auto'), + TOPCOM is used if it is available and internal routines otherwise. The remaining keyword parameters are passed through to the :class:`~sage.geometry.triangulation.point_configuration.PointConfiguration` @@ -2920,14 +2952,65 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s A vertex at (-1, 1, -1), A vertex at (1, 1, 1)] sage: Polyhedron(simplex_vertices) A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices + + It is possible to use ``'normaliz'`` as an engine. For this, the + polyhedron should have the backend set to normaliz:: + + sage: P = Polyhedron(vertices=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]],backend='normaliz') # optional - pynormaliz + sage: P.triangulate(engine='normaliz') # optional - pynormaliz + (<0,1,2>, <1,2,3>) + + sage: P = Polyhedron(vertices=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]]) + sage: P.triangulate(engine='normaliz') + Traceback (most recent call last): + ... + TypeError: the polyhedron's backend should be 'normaliz' + + The normaliz engine can triangulate pointed cones:: + + sage: C1 = Polyhedron(rays=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]],backend='normaliz') # optional - pynormaliz + sage: C1.triangulate(engine='normaliz') # optional - pynormaliz + (<0,1,2>, <1,2,3>) + sage: C2 = Polyhedron(rays=[[1,0,1],[0,0,1],[0,1,1],[1,1,10/9]],backend='normaliz') # optional - pynormaliz + sage: C2.triangulate(engine='normaliz') # optional - pynormaliz + (<0,1,2>, <1,2,3>) + + They can also be affine cones:: + + sage: K = Polyhedron(vertices=[[1,1,1]],rays=[[1,0,0],[0,1,0],[1,1,-1],[1,1,1]], backend='normaliz') # optional - pynormaliz + sage: K.triangulate(engine='normaliz') # optional - pynormaliz + (<0,1,2>, <0,1,3>) """ - if not self.is_compact(): - raise NotImplementedError('I can only triangulate compact polytopes.') + if self.lines(): + raise NotImplementedError('triangulation of polyhedra with lines is not supported') + if len(self.vertices_list()) >= 2 and self.rays_list(): + raise NotImplementedError('triangulation of non-compact polyhedra that are not cones is not supported') + if not self.is_compact() and engine != 'normaliz': + raise NotImplementedError("triangulation of pointed polyhedra requires 'normaliz'") from sage.geometry.triangulation.point_configuration import PointConfiguration - pc = PointConfiguration((v.vector() for v in self.vertex_generator()), - connected=connected, fine=fine, regular=regular, star=star) - pc.set_engine(engine) - return pc.triangulate() + if self.is_compact(): + pc = PointConfiguration((v.vector() for v in self.vertex_generator()), + connected=connected, fine=fine, regular=regular, star=star) + # If the engine is not normaliz, we pass directly to the + # PointConfiguration module. + if engine != 'normaliz': + pc.set_engine(engine) + return pc.triangulate() + else: + return pc(self._triangulate_normaliz()) + else: # From above, we have a pointed cone and the engine is normaliz + try: + pc = PointConfiguration((v.vector() for v in self.ray_generator()), + connected=connected, fine=fine, regular=regular, star=star) + return pc(self._triangulate_normaliz()) + except AssertionError: + # PointConfiguration is not adapted to inhomogeneous cones + # This is a hack. TODO: Implement the necessary things in + # PointConfiguration to accep such cases. + c = self.representative_point() + normed_v = ((1/(r.vector()*c))*r.vector() for r in self.ray_generator()) + pc = PointConfiguration(normed_v, connected=connected, fine=fine, regular=regular, star=star) + return pc(self._triangulate_normaliz()) @coerce_binop def minkowski_sum(self, other): @@ -2947,11 +3030,11 @@ def minkowski_sum(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base`. + - ``other`` -- a :class:`Polyhedron_base` OUTPUT: - The Minkowski sum of ``self`` and ``other``. + The Minkowski sum of ``self`` and ``other`` EXAMPLES:: @@ -3015,7 +3098,7 @@ def minkowski_difference(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base`. + - ``other`` -- a :class:`Polyhedron_base` OUTPUT: @@ -3103,7 +3186,7 @@ def __sub__(self, other): INPUT: - - ``other`` -- a translation vector or a polyhedron. + - ``other`` -- a translation vector or a polyhedron OUTPUT: @@ -3169,7 +3252,7 @@ def translation(self, displacement): INPUT: - ``displacement`` -- a displacement vector or a list/tuple of - coordinates that determines a displacement vector. + coordinates that determines a displacement vector OUTPUT: @@ -3196,7 +3279,7 @@ def product(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base`. + - ``other`` -- a :class:`Polyhedron_base` OUTPUT: @@ -3327,7 +3410,7 @@ def subdirect_sum(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base`. + - ``other`` -- a :class:`Polyhedron_base` EXAMPLES:: @@ -3383,7 +3466,7 @@ def direct_sum(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base`. + - ``other`` -- a :class:`Polyhedron_base` EXAMPLES:: @@ -3433,7 +3516,7 @@ def dilation(self, scalar): INPUT: - - ``scalar`` -- A scalar, not necessarily in :meth:`base_ring`. + - ``scalar`` -- A scalar, not necessarily in :meth:`base_ring` OUTPUT: @@ -3495,7 +3578,7 @@ def _acted_upon_(self, actor, self_on_left): INPUT: - ``actor`` -- A scalar, not necessarily in :meth:`base_ring`, - or a :class:`Polyhedron`. + or a :class:`Polyhedron` OUTPUT: @@ -3573,7 +3656,7 @@ def convex_hull(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron`. + - ``other`` -- a :class:`Polyhedron` OUTPUT: @@ -3601,7 +3684,7 @@ def intersection(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron`. + - ``other`` -- a :class:`Polyhedron` OUTPUT: @@ -3717,7 +3800,7 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): INPUT: - - ``face`` -- a PolyhedronFace. + - ``face`` -- a PolyhedronFace - ``linear_coefficients`` -- tuple of integer. Specifies the coefficient of the normal vector of the cutting hyperplane used to truncate the face. @@ -3861,7 +3944,7 @@ def stack(self, face, position=None): INPUT: - - ``face`` -- a PolyhedronFace. + - ``face`` -- a PolyhedronFace - ``position`` -- a positive integer. Determines a relative distance from the barycenter of ``face``. A value close to 0 will place the @@ -3888,7 +3971,7 @@ def stack(self, face, position=None): sage: cube.stack(cube.faces(0)[0]) Traceback (most recent call last): ... - ValueError: Can not stack onto a vertex. + ValueError: can not stack onto a vertex sage: stacked_square_half = cube.stack(square_face,position=1/2) sage: stacked_square_half.f_vector() @@ -3906,7 +3989,7 @@ def stack(self, face, position=None): sage: hexaprism.stack(square_face,position=4) Traceback (most recent call last): ... - ValueError: The chosen position is too large. + ValueError: the chosen position is too large It is possible to stack on unbounded faces:: @@ -3932,7 +4015,7 @@ def stack(self, face, position=None): if not isinstance(face, PolyhedronFace): raise TypeError("{} should be a PolyhedronFace of {}".format(face, self)) elif face.dim() == 0: - raise ValueError("Can not stack onto a vertex.") + raise ValueError("can not stack onto a vertex") if position is None: position = 1 @@ -3966,7 +4049,7 @@ def stack(self, face, position=None): new_vertex = (1-position)*barycenter + position*repr_point if not locus_polyhedron.contains(new_vertex): - raise ValueError("The chosen position is too large.") + raise ValueError("the chosen position is too large") return Polyhedron(vertices=self.vertices() + (new_vertex,), rays=self.rays(), @@ -4008,7 +4091,6 @@ def lawrence_extension(self, v): lambda_V = [u + [0] for u in V if u != v] + [v+[1]] + [v+[2]] return Polyhedron(lambda_V) - def lawrence_polytope(self): r""" Return the Lawrence polytope of ``self``. @@ -4150,12 +4232,12 @@ def barycentric_subdivision(self, subdivision_frac=None): sage: P.barycentric_subdivision(1/2) Traceback (most recent call last): ... - ValueError: The subdivision fraction should be between 0 and 1/2. + ValueError: the subdivision fraction should be between 0 and 1/2 sage: P = Polyhedron(ieqs=[[1,0,1],[0,1,0],[1,0,0],[0,0,1]]) sage: P.barycentric_subdivision() Traceback (most recent call last): ... - ValueError: The polytope has to be compact. + ValueError: the polytope has to be compact sage: P = Polyhedron(vertices=[[0,0,0],[0,1,0],[1,0,0],[0,0,1]], backend='field') sage: P.barycentric_subdivision() A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 14 vertices @@ -4164,10 +4246,10 @@ def barycentric_subdivision(self, subdivision_frac=None): subdivision_frac = ZZ.one() / 3 if not self.is_compact(): - raise ValueError("The polytope has to be compact.") + raise ValueError("the polytope has to be compact") if not (0 < subdivision_frac < ZZ.one() / 2): - raise ValueError("The subdivision fraction should be " - "between 0 and 1/2.") + raise ValueError("the subdivision fraction should be " + "between 0 and 1/2") b_ring = self.parent()._coerce_base_ring(subdivision_frac) barycenter = self.center() @@ -4558,7 +4640,7 @@ def vertex_graph(self): pairs = [] for i, j in combinations(range(n), 2): common_ineq = vertex_ineq_incidence[i] & vertex_ineq_incidence[j] - if not common_ineq: # or len(common_ineq) < d-2: + if not common_ineq: # or len(common_ineq) < d-2: continue if len(set.intersection(*[ineq_vertex_incidence[k] for k in common_ineq])) == 2: @@ -4621,7 +4703,7 @@ def vertex_digraph(self, f, increasing=True): if f.codomain().dimension() == 1: orientation_check = lambda v: f(v) >= 0 else: - raise TypeError('The linear map f must have ' + raise TypeError('the linear map f must have ' 'one-dimensional codomain') else: try: @@ -4769,7 +4851,7 @@ def one_point_suspension(self, vertex): INPUT: - - ``vertex`` -- a Vertex of ``self``. + - ``vertex`` -- a Vertex of ``self`` EXAMPLES:: @@ -4802,7 +4884,7 @@ def one_point_suspension(self, vertex): sage: cube.one_point_suspension(e) Traceback (most recent call last): ... - TypeError: The vertex A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices should be a Vertex or PolyhedronFace of dimension 0 + TypeError: the vertex A 1-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 2 vertices should be a Vertex or PolyhedronFace of dimension 0 """ from sage.geometry.polyhedron.representation import Vertex from sage.geometry.polyhedron.face import PolyhedronFace @@ -4811,7 +4893,7 @@ def one_point_suspension(self, vertex): elif isinstance(vertex, PolyhedronFace) and vertex.dim() == 0: return self.face_split(vertex) else: - raise TypeError("The vertex {} should be a Vertex or PolyhedronFace of dimension 0".format(vertex)) + raise TypeError("the vertex {} should be a Vertex or PolyhedronFace of dimension 0".format(vertex)) def face_split(self, face): """ @@ -4825,7 +4907,7 @@ def face_split(self, face): INPUT: - - ``face`` -- a PolyhedronFace or a Vertex. + - ``face`` -- a PolyhedronFace or a Vertex EXAMPLES:: @@ -4848,7 +4930,7 @@ def face_split(self, face): new_vertices = [list(x) + [0] for x in self.vertex_generator()] + \ [list(face.as_polyhedron().center()) + [x] for x in [-1, 1]] # Splitting the face else: - raise TypeError("The face {} should be a Vertex or PolyhedronFace".format(face)) + raise TypeError("the face {} should be a Vertex or PolyhedronFace".format(face)) new_rays = [] new_rays.extend( [ r + [0] for r in self.ray_generator() ] ) @@ -4899,7 +4981,7 @@ def render_solid(self, **kwds): return proj.render_solid_3d(**kwds) if self.ambient_dim() == 2: return proj.render_fill_2d(**kwds) - raise ValueError("render_solid is only defined for 2 and 3 dimensional polyhedra.") + raise ValueError("render_solid is only defined for 2 and 3 dimensional polyhedra") def render_wireframe(self, **kwds): """ @@ -4918,7 +5000,7 @@ def render_wireframe(self, **kwds): return proj.render_wireframe_3d(**kwds) if self.ambient_dim() == 2: return proj.render_outline_2d(**kwds) - raise ValueError("render_wireframe is only defined for 2 and 3 dimensional polyhedra.") + raise ValueError("render_wireframe is only defined for 2 and 3 dimensional polyhedra") def schlegel_projection(self, projection_dir=None, height=1.1): """ @@ -5022,7 +5104,7 @@ def _volume_latte(self, verbose=False, algorithm='triangulate', **kwargs): INPUT: - - ``arg`` -- a cdd or LattE description string. + - ``arg`` -- a cdd or LattE description string - ``algorithm`` -- (default: 'triangulate') the integration method. Use 'triangulate' for polytope triangulation or 'cone-decompose' for tangent cone decomposition method. @@ -5040,7 +5122,7 @@ def _volume_latte(self, verbose=False, algorithm='triangulate', **kwargs): .. NOTE:: This function depends on LattE (i.e., the ``latte_int`` optional - package). See the LattE documentation for furthe details. + package). See the LattE documentation for further details. EXAMPLES:: @@ -5069,13 +5151,51 @@ def _volume_latte(self, verbose=False, algorithm='triangulate', **kwargs): sage: polytopes.cuboctahedron()._volume_latte(raw_output=True) #optional - latte_int '20/3' + + Testing inexact rings:: + + sage: P = Polyhedron(vertices=[[0,0],[1,0],[0,1]],base_ring=RDF) + sage: P.volume(engine='latte') + Traceback (most recent call last): + ... + ValueError: LattE integrale cannot be applied over inexact rings """ from sage.interfaces.latte import integrate if self.base_ring() == RDF: - raise ValueError("LattE integrale cannot be applied over inexact rings.") + raise ValueError("LattE integrale cannot be applied over inexact rings") else: return integrate(self.cdd_Hrepresentation(), algorithm=algorithm, cdd=True, verbose=verbose, **kwargs) + def _volume_normaliz(self, measure='induced'): + r""" + Computes the volume of a polytope using normaliz. + + INPUT: + + - ``measure`` -- (default: 'induced') the measure to take. 'induced' + correspond to ``EuclideanVolume`` in normaliz and 'induced_lattice' + correspond to ``Volume`` in normaliz + + OUTPUT: + + A float value (when ``measure`` is 'induced') or a rational number + (when ``measure`` is 'induced_lattice') + + .. NOTE:: + + This function depends on Normaliz (i.e., the ``pynormaliz`` optional + package). See the Normaliz documentation for further details. + + TESTS:: + + sage: P = Polyhedron(vertices=[[0,0],[1,0],[0,1],[1,1]]) + sage: P._volume_normaliz() + Traceback (most recent call last): + ... + TypeError: the backend should be normaliz + """ + raise TypeError("the backend should be normaliz") + @cached_method def volume(self, measure='ambient', engine='auto', **kwds): """ @@ -5087,22 +5207,26 @@ def volume(self, measure='ambient', engine='auto', **kwds): * ``ambient`` (default): Lebesgue measure of ambient space (volume) * ``induced``: Lebesgue measure of the affine hull (relative volume) - * ``induced_rational``: Scaling of the Lebesgue measure for rational polytopes + * ``induced_rational``: Scaling of the Lebesgue measure for rational + polytopes, such that the unit hypercube has volume 1 + * ``induced_lattice``: Scaling of the Lebesgue measure, such that the + volume of the hypercube is factorial(n) - ``engine`` -- string. The backend to use. Allowed values are: * ``'auto'`` (default): choose engine according to measure - * ``'internal'``: see :meth:`triangulate`. - * ``'TOPCOM'``: see :meth:`triangulate`. - * ``'lrs'``: use David Avis's lrs program (optional). - * ``'latte'``: use LattE integrale program (optional). + * ``'internal'``: see :meth:`triangulate` + * ``'TOPCOM'``: see :meth:`triangulate` + * ``'lrs'``: use David Avis's lrs program (optional) + * ``'latte'``: use LattE integrale program (optional) + * ``'normaliz'``: use Normaliz program (optional) - ``**kwds`` -- keyword arguments that are passed to the - triangulation engine. + triangulation engine OUTPUT: - The volume of the polytope. + The volume of the polytope EXAMPLES:: @@ -5160,6 +5284,26 @@ def volume(self, measure='ambient', engine='auto', **kwds): sage: edge.volume(measure='induced') 1 + sage: P = Polyhedron(backend='normaliz',vertices=[[1,0,0],[0,0,1],[-1,1,1],[-1,2,0]]) # optional - pynormaliz + sage: P.volume() # optional - pynormaliz + 0 + sage: P.volume(measure='induced') # optional - pynormaliz + 3/2*sqrt(3) + sage: P.volume(measure='induced',engine='normaliz') # optional - pynormaliz + 2.598076211353316 + sage: P.volume(measure='induced_rational') # optional - pynormaliz, latte_int + 3/2 + sage: P.volume(measure='induced_rational',engine='normaliz') # optional - pynormaliz + 3/2 + sage: P.volume(measure='induced_lattice') # optional - pynormaliz + 3 + + The same polytope without normaliz backend:: + + sage: P = Polyhedron(vertices=[[1,0,0],[0,0,1],[-1,1,1],[-1,2,0]]) + sage: P.volume(measure='induced_lattice',engine='latte') # optional - latte_int + 3 + sage: Dexact = polytopes.dodecahedron() sage: v = Dexact.faces(2)[0].as_polyhedron().volume(measure='induced', engine='internal'); v -80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240) @@ -5209,25 +5353,56 @@ def volume(self, measure='ambient', engine='auto', **kwds): +Infinity sage: P.volume(measure='ambient') 0 - sage: P.volume(measure='induced_rational') + sage: P.volume(measure='induced_rational') # optional - pynormaliz + +Infinity + sage: P.volume(measure='induced_rational',engine='latte') # optional - latte_int +Infinity """ - if measure == 'induced_rational' and engine not in ['auto', 'latte']: - raise TypeError("The induced rational measure can only be computed with the engine set to `auto` or `latte`") + from sage.features import FeatureNotPresentError, PythonModule + if measure == 'induced_rational' and engine not in ['auto', 'latte', 'normaliz']: + raise RuntimeError("the induced rational measure can only be computed with the engine set to `auto`, `latte`, or `normaliz`") + if measure == 'induced_lattice' and engine not in ['auto', 'latte', 'normaliz']: + raise RuntimeError("the induced lattice measure can only be computed with the engine set to `auto`, `latte`, or `normaliz`") if engine == 'auto' and measure == 'induced_rational': - engine = 'latte' + # Enforce a default choice, change if a better engine is found. + from sage.features.latte import Latte + try: + Latte().require() + engine = 'latte' + except FeatureNotPresentError: + try: + PythonModule("PyNormaliz", spkg="pynormaliz").require() + engine = 'normaliz' + except FeatureNotPresentError: + raise RuntimeError("the induced rational measure can only be computed with the optional packages `latte_int`, or `pynormaliz`") + + if engine == 'auto' and measure == 'induced_lattice': + # Enforce a default choice, change if a better engine is found. + try: + PythonModule("PyNormaliz", spkg="pynormaliz").require() + engine = 'normaliz' + except FeatureNotPresentError: + try: + from sage.features.latte import Latte + Latte().require() + engine = 'latte' + except FeatureNotPresentError: + raise RuntimeError("the induced rational measure can only be computed with the optional packages `latte_int`, or `pynormaliz`") if measure == 'ambient': if self.dim() < self.ambient_dim(): return self.base_ring().zero() - if engine == 'lrs': - return self._volume_lrs(**kwds) - elif engine == 'latte': - return self._volume_latte(**kwds) # if the polyhedron is unbounded, return infinity if not self.is_compact(): from sage.rings.infinity import infinity return infinity + if engine == 'lrs': + return self._volume_lrs(**kwds) + elif engine == 'latte': + return self._volume_latte(**kwds) + elif engine == 'normaliz': + return self._volume_normaliz(measure='euclidean') + triangulation = self.triangulate(engine=engine, **kwds) pc = triangulation.point_configuration() return sum([pc.volume(simplex) for simplex in triangulation]) / ZZ(self.dim()).factorial() @@ -5239,18 +5414,32 @@ def volume(self, measure='ambient', engine='auto', **kwds): if not self.is_compact(): from sage.rings.infinity import infinity return infinity + if engine == 'normaliz': + return self._volume_normaliz(measure='euclidean') # use an orthogonal transformation, which preserves volume up to a factor provided by the transformation matrix A, b = self.affine_hull(orthogonal=True, as_affine_map=True) Adet = (A.matrix().transpose() * A.matrix()).det() return self.affine_hull(orthogonal=True).volume(measure='ambient', engine=engine, **kwds) / sqrt(Adet) elif measure == 'induced_rational': - if self.dim() < self.ambient_dim() and engine != 'latte': - raise TypeError("The induced rational measure can only be computed with the engine set to `auto` or `latte`") # if the polyhedron is unbounded, return infinity if not self.is_compact(): from sage.rings.infinity import infinity return infinity - return self._volume_latte(**kwds) + if engine == 'latte': + return self._volume_latte(**kwds) + else: # engine is 'normaliz' + return self._volume_normaliz(measure='induced_lattice') / ZZ(self.dim()).factorial() + elif measure == 'induced_lattice': + # if the polyhedron is unbounded, return infinity + if not self.is_compact(): + from sage.rings.infinity import infinity + return infinity + if engine == 'latte': + return self._volume_latte(**kwds) * ZZ(self.dim()).factorial() + else: # engine is 'normaliz' + return self._volume_normaliz(measure='induced_lattice') + else: + raise TypeError("the measure should be `ambient`, `induced`, `induced_rational`, or `induced_lattice`") def integrate(self, polynomial, **kwds): r""" @@ -5258,16 +5447,16 @@ def integrate(self, polynomial, **kwds): INPUT: - - ``P`` -- Polyhedron. + - ``P`` -- Polyhedron - ``polynomial`` -- A multivariate polynomial or a valid LattE description string for - polynomials. + polynomials - - ``**kwds`` -- additional keyword arguments that are passed to the engine. + - ``**kwds`` -- additional keyword arguments that are passed to the engine OUTPUT: - The integral of the polynomial over the polytope. + The integral of the polynomial over the polytope .. NOTE:: @@ -5296,7 +5485,7 @@ def integrate(self, polynomial, **kwds): sage: P.integrate(x*y) # optional - latte_int Traceback (most recent call last): ... - NotImplementedError: The polytope must be full-dimensional. + NotImplementedError: the polytope must be full-dimensional TESTS:: @@ -5313,7 +5502,7 @@ def integrate(self, polynomial, **kwds): sage: P.integrate(x^2*y^2*z^2) # optional - latte_int Traceback (most recent call last): ... - TypeError: The base ring must be ZZ, QQ, or RDF + TypeError: the base ring must be ZZ, QQ, or RDF Testing a univariate polynomial:: @@ -5328,12 +5517,12 @@ def integrate(self, polynomial, **kwds): sage: P.integrate('[[1,[2,2]]]') # optional - latte_int Traceback (most recent call last): ... - TypeError: LattE integrale cannot be applied over inexact rings. + TypeError: LattE integrale cannot be applied over inexact rings """ if self.base_ring() == RDF: - raise TypeError("LattE integrale cannot be applied over inexact rings.") + raise TypeError("LattE integrale cannot be applied over inexact rings") elif not self.is_full_dimensional(): - raise NotImplementedError("The polytope must be full-dimensional.") + raise NotImplementedError("the polytope must be full-dimensional") else: from sage.interfaces.latte import integrate return integrate(self.cdd_Hrepresentation(), polynomial, @@ -5349,7 +5538,7 @@ def contains(self, point): INPUT: - - ``point`` -- coordinates of a point (an iterable). + - ``point`` -- coordinates of a point (an iterable) OUTPUT: @@ -5429,7 +5618,7 @@ def interior_contains(self, point): INPUT: - - ``point`` -- coordinates of a point. + - ``point`` -- coordinates of a point OUTPUT: @@ -5486,11 +5675,11 @@ def relative_interior_contains(self, point): INPUT: - - ``point`` -- coordinates of a point. + - ``point`` -- coordinates of a point OUTPUT: - ``True`` or ``False``. + ``True`` or ``False`` EXAMPLES:: @@ -5740,7 +5929,7 @@ def lattice_polytope(self, envelope=False): in 2-d lattice M """ if not self.is_compact(): - raise NotImplementedError('Only compact lattice polytopes are allowed.') + raise NotImplementedError('only compact lattice polytopes are allowed') try: vertices = self.vertices_matrix(ZZ).columns() @@ -5786,7 +5975,7 @@ def _integral_points_PALP(self): [M(1, 1), M(0, 1), M(1, 0), M(0, 0)] """ if not self.is_compact(): - raise ValueError('Can only enumerate points in a compact polyhedron.') + raise ValueError('can only enumerate points in a compact polyhedron') lp = self.lattice_polytope(True) # remove cached values to get accurate timings try: @@ -5835,9 +6024,9 @@ def bounding_box(self, integral=False, integral_hull=False): box_min = [] box_max = [] if self.n_vertices == 0: - raise ValueError('Empty polytope is not allowed') + raise ValueError('empty polytope is not allowed') if not self.is_compact(): - raise ValueError('Only polytopes (compact polyhedra) are allowed.') + raise ValueError('only polytopes (compact polyhedra) are allowed') for i in range(self.ambient_dim()): coords = [ v[i] for v in self.vertex_generator() ] max_coord = max(coords) @@ -5992,9 +6181,17 @@ def integral_points(self, threshold=100000): sage: P = Polyhedron([[]]) # single point in 0 dimensions sage: P.integral_points() ((),) + + Test unbounded polyhedron:: + + sage: P = Polyhedron(rays=[[1,0,0]]) + sage: P.integral_points() + Traceback (most recent call last): + ... + ValueError: can only enumerate points in a compact polyhedron """ if not self.is_compact(): - raise ValueError('Can only enumerate points in a compact polyhedron.') + raise ValueError('can only enumerate points in a compact polyhedron') # Trivial cases: polyhedron with 0 or 1 vertices if self.n_vertices() == 0: return () @@ -6010,7 +6207,7 @@ def integral_points(self, threshold=100000): if box_min is None: return () box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) - if not self.is_lattice_polytope() or \ + if not self.is_lattice_polytope() or \ (self.is_simplex() and box_points < 1000) or \ box_points < threshold: from sage.geometry.integral_points import rectangular_box_points @@ -6094,7 +6291,7 @@ def get_integral_point(self, index, **kwds): """ if not self.is_compact(): - raise ValueError('Can only enumerate points in a compact polyhedron.') + raise ValueError('can only enumerate points in a compact polyhedron') if not 0 <= index < self.integral_points_count(**kwds): raise IndexError('polytope index out of range') @@ -6174,11 +6371,11 @@ def random_integral_point(self, **kwds): """ if not self.is_compact(): - raise ValueError('Can only sample integral points in a compact polyhedron.') + raise ValueError('can only sample integral points in a compact polyhedron') count = self.integral_points_count() if count == 0: - raise EmptySetError('Polyhedron does not contain any integral points.') + raise EmptySetError('polyhedron does not contain any integral points') return self.get_integral_point(current_randstate().python_random().randint(0, count-1), **kwds) @@ -6196,7 +6393,7 @@ def combinatorial_automorphism_group(self, vertex_graph_only=False): - ``vertex_graph_only`` -- boolean (default: ``False``); whether to return the automorphism group of the vertex edges graph or - of the lattice. + of the lattice OUTPUT: @@ -6646,7 +6843,7 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): INPUT: - - ``other`` -- a polyhedron object. + - ``other`` -- a polyhedron object - ``algorithm`` (default = ``bipartite_graph``) -- the algorithm to use. The other possible value is ``face_lattice``. @@ -6838,7 +7035,7 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, sage: A = L.affine_hull(orthonormal=True) Traceback (most recent call last): ... - ValueError: The base ring needs to be extended; try with "extend=True" + ValueError: the base ring needs to be extended; try with "extend=True" sage: A = L.affine_hull(orthonormal=True, extend=True); A A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices sage: A.vertices() @@ -6908,7 +7105,7 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, sage: A = P.affine_hull(orthonormal=True) Traceback (most recent call last): ... - ValueError: The base ring needs to be extended; try with "extend=True" + ValueError: the base ring needs to be extended; try with "extend=True" sage: A = P.affine_hull(orthonormal=True, extend=True); A A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices sage: A.vertices() @@ -7063,7 +7260,7 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, A = M.gram_schmidt(orthonormal=orthonormal)[0] except TypeError: if not extend: - raise ValueError('The base ring needs to be extended; try with "extend=True"') + raise ValueError('the base ring needs to be extended; try with "extend=True"') M = matrix(AA, M) A = M.gram_schmidt(orthonormal=orthonormal)[0] if as_affine_map: diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 4d0433d6ec9..71914d635ad 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -1106,7 +1106,7 @@ def icosidodecahedron(self, exact=True, backend=None): verts.extend(p(x) for x in gens) if exact: - return Polyhedron(vertices=verts,base_ring=K) + return Polyhedron(vertices=verts,base_ring=K,backend=backend) else: verts = [(RR(x), RR(y), RR(z)) for x, y, z in verts] return Polyhedron(vertices=verts, backend=backend) diff --git a/src/sage/graphs/base/boost_graph.pxd b/src/sage/graphs/base/boost_graph.pxd index 381c1663637..f29031e423e 100644 --- a/src/sage/graphs/base/boost_graph.pxd +++ b/src/sage/graphs/base/boost_graph.pxd @@ -9,6 +9,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from libcpp.vector cimport vector +from libcpp.pair cimport pair cdef extern from "boost/graph/adjacency_list.hpp" namespace "boost": cdef cppclass vecS: @@ -59,6 +60,7 @@ cdef extern from "boost_interface.cpp": v_index num_verts() void add_edge(v_index u, v_index v) void add_edge(v_index u, v_index v, double w) + vector[pair[int, pair[int, double]]] edge_list() e_index num_edges() result_ec edge_connectivity() double clustering_coeff(v_index v) @@ -71,6 +73,7 @@ cdef extern from "boost_interface.cpp": result_distances dijkstra_shortest_paths(v_index s) result_distances bellman_ford_shortest_paths(v_index s) vector[vector[double]] johnson_shortest_paths() + vector[vector[double]] floyd_warshall_shortest_paths() ctypedef property[edge_weight_t, double] EdgeWeight diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index fa6e4b93ef0..862d55c3721 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -30,6 +30,7 @@ with ``delete()``. :func:`min_spanning_tree` | Compute a minimum spanning tree of a (weighted) graph. :func:`shortest_paths` | Use Dijkstra or Bellman-Ford algorithm to compute the single-source shortest paths. :func:`johnson_shortest_paths` | Use Johnson algorithm to compute the all-pairs shortest paths. + :func:`floyd_warshall_shortest_paths` | Use Floyd-Warshall algorithm to compute the all-pairs shortest paths. :func:`johnson_closeness_centrality` | Use Johnson algorithm to compute the closeness centrality of all vertices. :func:`blocks_and_cut_vertices` | Use Tarjan's algorithm to compute the blocks and cut vertices of the graph. :func:`min_cycle_basis` | Return a minimum weight cycle basis of the input graph. @@ -1018,14 +1019,60 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): return (dist, pred) -cpdef johnson_shortest_paths(g, weight_function=None): +cdef get_predecessors(BoostWeightedGraph g, result, int_to_v, directed, weight_type): + r""" + Return the predecessor matrix from the distance matrix of the graph. + + INPUT: + + - ``g`` -- the input boost graph + + - ``result`` -- the matrix of shortest distances + + - ``int_to_v`` -- a list; it is a mapping from `(0, \ldots, n-1)` + to the vertex set of the original sage graph. + + - ``directed`` -- boolean; whether the input graph is directed + + - ``weight_type`` -- correct data type for edge weights + + OUTPUT: + + A dictionary of dictionaries ``pred`` such that ``pred[u][v]`` indicates + the predecessor of `v` in the shortest path from `u` to `v`. + """ + cdef vector[pair[int, pair[int, double]]] edges + sig_on() + edges = g.edge_list() + sig_off() + cdef int N = g.num_verts() + cdef dict pred = {v: {v: None} for v in int_to_v} + import sys + for p in edges: + dst = weight_type(p.second.second) + # dst is the weight of the edge (u, v) + u = p.first + v = p.second.first + for k in range(N): + if result[k][u] == sys.float_info.max or result[k][v] == sys.float_info.max: + continue + if weight_type(result[k][u]) + dst == weight_type(result[k][v]): + pred[int_to_v[k]][int_to_v[v]] = int_to_v[u] + if directed: + continue + if weight_type(result[k][u]) == weight_type(result[k][v]) + dst: + pred[int_to_v[k]][int_to_v[u]] = int_to_v[v] + return pred + +cpdef johnson_shortest_paths(g, weight_function=None, distances=True, predecessors=False): r""" Use Johnson algorithm to solve the all-pairs-shortest-paths. - This routine outputs the distance between each pair of vertices, using a - dictionary of dictionaries. It works on all kinds of graphs, but it is - designed specifically for graphs with negative weights (otherwise there are - more efficient algorithms, like Dijkstra). + This routine outputs the distance between each pair of vertices and the + predecessors matrix (depending on the values of boolean ``distances`` and + ``predecessors``) using a dictionary of dictionaries. It works on all kinds + of graphs, but it is designed specifically for graphs with negative weights + (otherwise there are more efficient algorithms, like Dijkstra). The time-complexity is `O(mn\log n)`, where `n` is the number of nodes and `m` is the number of edges. @@ -1037,11 +1084,20 @@ cpdef johnson_shortest_paths(g, weight_function=None): - ``weight_function`` -- function (default: ``None``); a function that associates a weight to each edge. If ``None`` (default), the weights of ``g`` are used, if available, otherwise all edges have weight 1. + + - ``distances`` -- boolean (default: ``True``); whether to return the + dictionary of shortest distances + + - ``predecessors`` -- boolean (default: ``False``); whether to return the + predecessors matrix OUTPUT: - A dictionary of dictionary ``distances`` such that ``distances[v][w]`` is - the distance between vertex ``v`` and vertex ``w``. + Depending on the input, this function return the dictionary of + predecessors, the dictionary of distances, or a pair of dictionaries + ``(distances, predecessors)`` where ``distance[u][v]`` denotes the distance + of a shortest path from `u` to `v` and ``predecessors[u][v]`` indicates the + predecessor of `w` on a shortest path from `u` to `v`. EXAMPLES: @@ -1054,6 +1110,12 @@ cpdef johnson_shortest_paths(g, weight_function=None): 1: {0: 1, 1: 0, 2: 2, 3: 3}, 2: {0: 3, 1: 2, 2: 0, 3: 1}, 3: {0: 4, 1: 3, 2: 1, 3: 0}} + sage: g = graphs.Grid2dGraph(2,2) + sage: johnson_shortest_paths(g, distances=False, predecessors=True) + {(0, 0): {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (1, 0)}, + (0, 1): {(0, 0): (0, 1), (0, 1): None, (1, 0): (0, 0), (1, 1): (0, 1)}, + (1, 0): {(0, 0): (1, 0), (0, 1): (0, 0), (1, 0): None, (1, 1): (1, 0)}, + (1, 1): {(0, 0): (1, 0), (0, 1): (1, 1), (1, 0): (1, 1), (1, 1): None}} Directed graphs:: @@ -1063,6 +1125,12 @@ cpdef johnson_shortest_paths(g, weight_function=None): 1: {1: 0, 2: -2, 3: -1}, 2: {2: 0, 3: 1}, 3: {3: 0}} + sage: g = DiGraph([(1,2,3),(2,3,2),(1,4,1),(4,2,1)], weighted=True) + sage: johnson_shortest_paths(g, distances=False, predecessors=True) + {1: {1: None, 2: 4, 3: 2, 4: 1}, + 2: {2: None, 3: 2}, + 3: {3: None}, + 4: {2: 4, 3: 2, 4: None}} TESTS: @@ -1082,11 +1150,20 @@ cpdef johnson_shortest_paths(g, weight_function=None): ValueError: the graph contains a negative cycle """ from sage.graphs.generic_graph import GenericGraph + cdef dict dist = {} + cdef dict pred = {} if not isinstance(g, GenericGraph): raise TypeError("the input must be a Sage graph") elif not g.num_edges(): - return {v: {v: 0} for v in g} + dist = {v: {v: 0} for v in g} + pred = {v: {v: None} for v in g} + if distances and predecessors: + return (dist, pred) + if distances: + return dist + if predecessors: + return pred # These variables are automatically deleted when the function terminates. cdef v_index i cdef list int_to_v = list(g) @@ -1095,6 +1172,7 @@ cpdef johnson_shortest_paths(g, weight_function=None): cdef BoostVecWeightedGraph g_boost_und cdef int N = g.num_verts() cdef vector[vector[double]] result + cdef int u_int, v_int if g.is_directed(): boost_weighted_graph_from_sage_graph(&g_boost_dir, g, v_to_int, weight_function) @@ -1122,9 +1200,178 @@ cpdef johnson_shortest_paths(g, weight_function=None): correct_type = RR import sys - return {int_to_v[v]: {int_to_v[w]: correct_type(result[v][w]) - for w in range(N) if result[v][w] != sys.float_info.max} - for v in range(N)} + if distances: + dist = {int_to_v[v]: {int_to_v[w]: correct_type(result[v][w]) + for w in range(N) if result[v][w] != sys.float_info.max} + for v in range(N)} + + if predecessors: + if g.is_directed(): + pred = get_predecessors(g_boost_dir, result, int_to_v, True, correct_type) + else: + pred = get_predecessors(g_boost_und, result, int_to_v, False, correct_type) + + if distances and predecessors: + return (dist, pred) + if distances: + return dist + if predecessors: + return pred + +cpdef floyd_warshall_shortest_paths(g, weight_function=None, distances=True, predecessors=False): + r""" + Use Floyd-Warshall algorithm to solve the all-pairs-shortest-paths. + + This routine outputs the distance between each pair of vertices and the + predecessors matrix (depending on the values of boolean ``distances`` and + ``predecessors``) using a dictionary of dictionaries. This method should be + preferred only if the graph is dense. If the graph is sparse the much + faster johnson_shortest_paths should be used. + + The time-complexity is `O(n^3 + nm)`, where `n` is the number of nodes and + `m` the number of edges. The factor `nm` in the complexity is added only + when ``predecessors`` is set to ``True``. + + INPUT: + + - ``g`` -- the input Sage graph + + - ``weight_function`` -- function (default: ``None``); a function that + associates a weight to each edge. If ``None`` (default), the weights of + ``g`` are used, if available, otherwise all edges have weight 1. + + - ``distances`` -- boolean (default: ``True``); whether to return + the dictionary of shortest distances + + - ``predecessors`` -- boolean (default: ``False``); whether to return the + predecessors matrix + + OUTPUT: + + Depending on the input, this function return the dictionary of + predecessors, the dictionary of distances, or a pair of dictionaries + ``(distances, predecessors)`` where ``distance[u][v]`` denotes the distance + of a shortest path from `u` to `v` and ``predecessors[u][v]`` indicates the + predecessor of `w` on a shortest path from `u` to `v`. + + EXAMPLES: + + Undirected graphs:: + + sage: from sage.graphs.base.boost_graph import floyd_warshall_shortest_paths + sage: g = Graph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True) + sage: floyd_warshall_shortest_paths(g) + {0: {0: 0, 1: 1, 2: 3, 3: 4}, + 1: {0: 1, 1: 0, 2: 2, 3: 3}, + 2: {0: 3, 1: 2, 2: 0, 3: 1}, + 3: {0: 4, 1: 3, 2: 1, 3: 0}} + sage: g = graphs.Grid2dGraph(2,2) + sage: floyd_warshall_shortest_paths(g, distances=False, predecessors=True) + {(0, 0): {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (1, 0)}, + (0, 1): {(0, 0): (0, 1), (0, 1): None, (1, 0): (0, 0), (1, 1): (0, 1)}, + (1, 0): {(0, 0): (1, 0), (0, 1): (0, 0), (1, 0): None, (1, 1): (1, 0)}, + (1, 1): {(0, 0): (1, 0), (0, 1): (1, 1), (1, 0): (1, 1), (1, 1): None}} + + Directed graphs:: + + sage: g = DiGraph([(0,1,1),(1,2,-2),(1,3,4),(2,3,1)], weighted=True) + sage: floyd_warshall_shortest_paths(g) + {0: {0: 0, 1: 1, 2: -1, 3: 0}, + 1: {1: 0, 2: -2, 3: -1}, + 2: {2: 0, 3: 1}, + 3: {3: 0}} + sage: g = DiGraph([(1,2,3),(2,3,2),(1,4,1),(4,2,1)], weighted=True) + sage: floyd_warshall_shortest_paths(g, distances=False, predecessors=True) + {1: {1: None, 2: 4, 3: 2, 4: 1}, + 2: {2: None, 3: 2}, + 3: {3: None}, + 4: {2: 4, 3: 2, 4: None}} + + TESTS: + + Given an input which is not a graph:: + + sage: floyd_warshall_shortest_paths("I am not a graph!") + Traceback (most recent call last): + ... + TypeError: the input must be a Sage graph + + If there is a negative cycle: + + sage: g = DiGraph([(0,1,1),(1,2,-2),(2,0,0.5),(2,3,1)], weighted=True) + sage: floyd_warshall_shortest_paths(g) + Traceback (most recent call last): + ... + ValueError: the graph contains a negative cycle + """ + from sage.graphs.generic_graph import GenericGraph + cdef dict dist = {} + cdef dict pred = {} + + if not isinstance(g, GenericGraph): + raise TypeError("the input must be a Sage graph") + elif not g.num_edges(): + dist = {v: {v: 0} for v in g} + pred = {v: {v: None} for v in g} + if distances and predecessors: + return (dist, pred) + if distances: + return dist + if predecessors: + return pred + # These variables are automatically deleted when the function terminates. + cdef v_index i + cdef list int_to_v = list(g) + cdef dict v_to_int = {v: i for i, v in enumerate(int_to_v)} + cdef BoostVecWeightedDiGraphU g_boost_dir + cdef BoostVecWeightedGraph g_boost_und + cdef int N = g.num_verts() + cdef vector[vector[double]] result + cdef int u_int, v_int + + if g.is_directed(): + boost_weighted_graph_from_sage_graph(&g_boost_dir, g, v_to_int, weight_function) + sig_on() + result = g_boost_dir.floyd_warshall_shortest_paths() + sig_off() + else: + boost_weighted_graph_from_sage_graph(&g_boost_und, g, v_to_int, weight_function) + sig_on() + result = g_boost_und.floyd_warshall_shortest_paths() + sig_off() + + if not result.size(): + raise ValueError("the graph contains a negative cycle") + + if weight_function is not None: + correct_type = type(weight_function(next(g.edge_iterator()))) + elif g.weighted(): + correct_type = type(next(g.edge_iterator())[2]) + else: + correct_type = int + # Needed for rational curves. + from sage.rings.real_mpfr import RealNumber, RR + if correct_type == RealNumber: + correct_type = RR + + import sys + if distances: + dist = {int_to_v[v]: {int_to_v[w]: correct_type(result[v][w]) + for w in range(N) if result[v][w] != sys.float_info.max} + for v in range(N)} + + if predecessors: + if g.is_directed(): + pred = get_predecessors(g_boost_dir, result, int_to_v, True, correct_type) + else: + pred = get_predecessors(g_boost_und, result, int_to_v, False, correct_type) + + if distances and predecessors: + return (dist, pred) + if distances: + return dist + if predecessors: + return pred cpdef johnson_closeness_centrality(g, weight_function=None): @@ -1267,7 +1514,6 @@ cpdef min_cycle_basis(g_sage, weight_function=None, by_weight=False): * :wikipedia:`Cycle_basis` """ - cdef Py_ssize_t u_int, v_int, i, j cdef object u, v cdef Py_ssize_t n = g_sage.num_verts() diff --git a/src/sage/graphs/base/boost_interface.cpp b/src/sage/graphs/base/boost_interface.cpp index 0f8544f8ed2..f593d45dda6 100644 --- a/src/sage/graphs/base/boost_interface.cpp +++ b/src/sage/graphs/base/boost_interface.cpp @@ -12,11 +12,15 @@ #include #include #include +#include #include #include +#include +#include #include #include +#include typedef int v_index; typedef long e_index; @@ -108,6 +112,17 @@ class BoostGraph boost::add_edge(vertices[u], vertices[v], weight, graph); } + std::vector>> edge_list() { + std::vector>> to_return; + typename boost::graph_traits::edge_iterator ei, ei_end; + for (boost::tie(ei, ei_end) = boost::edges(graph); ei != ei_end; ++ei) { + to_return.push_back({index[boost::source(*ei, graph)], + {index[boost::target(*ei, graph)], + get(boost::edge_weight, graph, *ei)}}); + } + return to_return; + } + result_ec edge_connectivity() { result_ec to_return; edge_container disconnecting_set; @@ -263,7 +278,16 @@ class BoostGraph } return to_return; } + std::vector > floyd_warshall_shortest_paths() { + v_index N = num_verts(); + std::vector > D(N, std::vector(N)); + if (floyd_warshall_all_pairs_shortest_paths(graph, D)) { + return D; + } else { + return std::vector >(); + } + } std::vector > johnson_shortest_paths() { v_index N = num_verts(); diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index de63b582a7c..41b5e097236 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -9660,8 +9660,8 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, sage: G = graphs.CycleGraph(4) sage: G.pagerank(algorithm="Networkx") {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - sage: G.pagerank(alpha=0.50, algorithm="igraph") # optional - python_igraph - {0: 0.25, 1: 0.25, 2: 0.24999999999999997, 3: 0.24999999999999997} + sage: G.pagerank(alpha=0.50, algorithm="igraph") # optional - python_igraph # abs tol 1e-9 + {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} sage: G = Graph([(1, 2, 40), (2, 3, 50), (3, 4, 60), (1, 4, 70), (4, 5, 80), (5, 6, 20)]) sage: G.pagerank(algorithm="NetworkX") # abs tol 1e-9 {1: 0.16112205885619568, @@ -16897,6 +16897,10 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, Floyd-Warshall algorithm. Works also with weighted graphs, even with negative weights (but no negative cycle is allowed). + - ``'Floyd-Warshall_Boost'``: the Boost implementation of the + Floyd-Warshall algorithm. Works also with weighted graphs, even with + negative weights (but no negative cycle is allowed). + - ``'Dijkstra_NetworkX'``: the Dijkstra algorithm, implemented in NetworkX. It works with weighted graphs, but no negative weight is allowed. @@ -16909,7 +16913,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, - ``None`` (default): Sage chooses the best algorithm: ``'BFS'`` if ``by_weight`` is ``False``, ``'Dijkstra_Boost'`` if all weights are - positive, ``'Floyd-Warshall-Cython'`` otherwise. + positive, ``'Floyd-Warshall_Boost'`` otherwise. - ``weight_function`` -- function (default: ``None``); a function that takes as input an edge ``(u, v, l)`` and outputs its weight. If not @@ -16926,8 +16930,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, indicates the length ``dist[u][v]`` of the shortest weighted path from `u` to `v`. The second is a compact representation of all the paths - it indicates the predecessor ``pred[u][v]`` of `v` in the shortest path - from `u` to `v`. If the algorithm used is ``Johnson_Boost``, - predecessors are not computed. + from `u` to `v`. .. NOTE:: @@ -17001,7 +17004,8 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") - sage: d1 == d2 == d3 == d4 == d5 == d6 + sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 True Checking that distances are equal regardless of the algorithm used:: @@ -17013,7 +17017,8 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") - sage: d1 == d2 == d3 == d4 == d5 == d6 + sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 True Checking that weighted distances are equal regardless of the algorithm @@ -17027,7 +17032,8 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") sage: d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") - sage: d1 == d2 == d3 == d4 + sage: d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") + sage: d1 == d2 == d3 == d4 == d5 True Checking a random path is valid:: @@ -17123,7 +17129,7 @@ def weight_function(e): for e in self.edge_iterator(): try: if weight_function(e) < 0: - algorithm = "Floyd-Warshall-Python" + algorithm = "Floyd-Warshall_Boost" break except (ValueError, TypeError): raise ValueError("the weight function cannot find the" @@ -17145,12 +17151,19 @@ def weight_function(e): from sage.graphs.distances_all_pairs import floyd_warshall return floyd_warshall(self, distances=True) + elif algorithm == "Floyd-Warshall_Boost": + if not by_weight: + def weight_function(e): + return 1 + from sage.graphs.base.boost_graph import floyd_warshall_shortest_paths + return floyd_warshall_shortest_paths(self, weight_function, distances=True, predecessors=True) + elif algorithm == "Johnson_Boost": if not by_weight: def weight_function(e): return 1 from sage.graphs.base.boost_graph import johnson_shortest_paths - return [johnson_shortest_paths(self, weight_function), None] + return johnson_shortest_paths(self, weight_function, distances=True, predecessors=True) elif algorithm == "Dijkstra_Boost": from sage.graphs.base.boost_graph import shortest_paths diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 91b186d6f77..4e728a69d72 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -440,7 +440,12 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, for x in gens: for cycle in x: domain = domain.union(cycle) - domain = sorted(domain) + try: + domain = sorted(domain) + except TypeError: + # Sorting the domain will sometimes fail with Python 3. + # Fallback (not ideal: find a better solution?) + domain = sorted(domain, key=str) #Here we need to check if all of the points are integers #to make the domain contain all integers up to the max. @@ -498,6 +503,9 @@ def construction(self): ('a','b') sage: p = g1*g2; p (1,2)(3,4,5)('a','b') + sage: P = parent(p) + sage: P + Permutation Group with generators [('a','b'), (1,2), (1,2,3,4,5)] """ gens = self.gens() if len(gens) == 1 and gens[0].is_one(): @@ -1481,13 +1489,18 @@ def orbit(self, point, action="OnPoints"): Action of `S_4` on sets of disjoint sets:: sage: S4 = groups.permutation.Symmetric(4) - sage: S4.orbit(((1,2),(3,4)), action = "OnSetsDisjointSets") - ({{1, 2}, {3, 4}}, {{2, 3}, {1, 4}}, {{1, 3}, {2, 4}}) + sage: O = S4.orbit(((1,2),(3,4)), action = "OnSetsDisjointSets") + sage: {1, 2} in O[0] and {3, 4} in O[0] + True + sage: {1, 4} in O[1] and {2, 3} in O[1] + True + sage: all([set(union(*x)) == {1,2,3,4} for x in O]) + True Action of `S_4` (on a nonstandard domain) on tuples of sets:: sage: S4 = PermutationGroup([ [('c','d')], [('a','c')], [('a','b')] ]) - sage: S4.orbit((('a','c'),('b','d')),"OnTuplesSets") + sage: S4.orbit((('a','c'),('b','d')),"OnTuplesSets") # py2 (({'a', 'c'}, {'b', 'd'}), ({'a', 'd'}, {'c', 'b'}), ({'c', 'b'}, {'a', 'd'}), @@ -1499,7 +1512,7 @@ def orbit(self, point, action="OnPoints"): sage: S4 = PermutationGroup([ [((11,(12,13)),'d')], ....: [((12,(12,11)),(11,(12,13)))], [((12,(12,11)),'b')] ]) - sage: S4.orbit((( (11,(12,13)), (12,(12,11))),('b','d')),"OnTuplesSets") + sage: S4.orbit((( (11,(12,13)), (12,(12,11))),('b','d')),"OnTuplesSets") # py2 (({(11, (12, 13)), (12, (12, 11))}, {'b', 'd'}), ({'d', (12, (12, 11))}, {(11, (12, 13)), 'b'}), ({(11, (12, 13)), 'b'}, {'d', (12, (12, 11))}), @@ -1936,6 +1949,7 @@ def _order(self): sage: [SymmetricGroup(n).stabilizer(1)._gap_().Size() for n in [4..10]] [6, 24, 120, 720, 5040, 40320, 362880] + sage: n = 10 sage: special_gens = [ ....: [(3,4), (2,4)], ....: [(4,5), (3,5), (2,5)], diff --git a/src/sage/groups/perm_gps/symgp_conjugacy_class.py b/src/sage/groups/perm_gps/symgp_conjugacy_class.py index 349c9800dd5..692380841c7 100644 --- a/src/sage/groups/perm_gps/symgp_conjugacy_class.py +++ b/src/sage/groups/perm_gps/symgp_conjugacy_class.py @@ -342,10 +342,14 @@ def conjugacy_class_iterator(part, S=None): It is also possible to specify any underlying set:: sage: it = conjugacy_class_iterator([2,2,2], 'abcdef') - sage: next(it) + sage: next(it) # py2 [('a', 'c'), ('b', 'e'), ('d', 'f')] - sage: next(it) + sage: next(it) # py2 [('a', 'f'), ('c', 'b'), ('e', 'd')] + sage: sorted(flatten(next(it))) + ['a', 'b', 'c', 'd', 'e', 'f'] + sage: all(len(x) == 2 for x in next(it)) + True """ n = sum(part) if part not in _Partitions: diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index bb863e96e84..a7a9fabe0a6 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -1578,7 +1578,7 @@ def gap_reset_workspace(max_workspace_size=None, verbose=False): g = Gap(use_workspace_cache=False, max_workspace_size=None) g.eval('SetUserPreference("HistoryMaxLines", 30)') from sage.tests.gap_packages import all_installed_packages - for pkg in all_installed_packages(): + for pkg in all_installed_packages(gap=g): try: g.load_package(pkg, verbose=verbose) except RuntimeError as msg: diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 0806dbdcb90..4dc7f01a83f 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -34,7 +34,8 @@ import sys import time -from .expect import Expect, ExpectElement, FunctionElement +from .expect import Expect +from .interface import (Interface, InterfaceElement, InterfaceFunctionElement) from sage.misc.misc import get_verbose from sage.misc.cachefunc import cached_method @@ -45,7 +46,6 @@ from time import sleep import warnings -from warnings import warn _name_pattern = re.compile('SAGE[0-9]+') @@ -107,24 +107,28 @@ def polymake_console(command=''): os.system(command or os.getenv('SAGE_POLYMAKE_COMMAND') or 'polymake') -class Polymake(ExtraTabCompletion, Expect): +class PolymakeAbstract(ExtraTabCompletion, Interface): r""" - Interface to the polymake interpreter. + Abstract interface to the polymake interpreter. - In order to use this interface, you need to either install the - optional polymake package for Sage, or install polymake system-wide - on your computer; it is available from https://polymake.org. + This class should not be instantiated directly, + but through its subclasses Polymake (Pexpect interface) + or PolymakeJuPyMake (JuPyMake interface). - Type ``polymake.[tab]`` for a list of most functions - available from your polymake install. Type - ``polymake.Function?`` for polymake's help about a given ``Function``. - Type ``polymake(...)`` to create a new polymake - object, and ``polymake.eval(...)`` to run a string using - polymake and get the result back as a string. + EXAMPLES: - EXAMPLES:: + sage: from sage.interfaces.polymake import PolymakeAbstract, polymake_expect, polymake_jupymake - sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake + We test the verbosity management with very early doctests + because messages will not be repeated. + + Testing the Pexpect interface:: + + sage: type(polymake_expect) + <...sage.interfaces.polymake.PolymakeExpect... + sage: isinstance(polymake_expect, PolymakeAbstract) + True + sage: p = polymake_expect.rand_sphere(4, 20, seed=5) # optional - polymake sage: p # optional - polymake Random spherical polytope of dimension 4; seed=5... sage: set_verbose(3) @@ -135,45 +139,33 @@ class Polymake(ExtraTabCompletion, Expect): sage: set_verbose(0) sage: p.F_VECTOR # optional - polymake 20 94 148 74 - sage: print(p.F_VECTOR._sage_doc_()) # optional - polymake # random - property_types/Algebraic Types/Vector: - A type for vectors with entries of type Element. - - You can perform algebraic operations such as addition or scalar multiplication. - You can create a new Vector by entering its elements, e.g.: - $v = new Vector(1,2,3); - or - $v = new Vector([1,2,3]); + Testing the JuPyMake interface:: - .. automethod:: _eval_line + sage: isinstance(polymake_jupymake, PolymakeAbstract) + True + sage: p = polymake_jupymake.rand_sphere(4, 20, seed=5) # optional - jupymake + sage: p # optional - jupymake + Random spherical polytope of dimension 4; seed=5... + sage: set_verbose(3) + sage: p.H_VECTOR # optional - jupymake + polymake: used package ppl + The Parma Polyhedra Library ... + 1 16 40 16 1 + sage: set_verbose(0) + sage: p.F_VECTOR # optional - jupymake + 20 94 148 74 """ - def __init__(self, script_subdirectory=None, - logfile=None, server=None, server_tmpdir=None, - seed=None, command=None): + def __init__(self, seed=None): """ TESTS:: - sage: from sage.interfaces.polymake import Polymake - sage: Polymake() + sage: from sage.interfaces.polymake import PolymakeAbstract + sage: PolymakeAbstract() Polymake - sage: Polymake().is_running() - False """ - if command is None: - command = "env TERM=dumb {}".format(os.getenv('SAGE_POLYMAKE_COMMAND') or 'polymake') - Expect.__init__(self, - name="polymake", - command=command, - prompt="polytope > ", - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - logfile=logfile, - eval_using_file_cutoff=1024) # > 1024 causes hangs - + Interface.__init__(self, "polymake") self._seed = seed self.__tab_completion = {} @@ -306,6 +298,42 @@ def _function_call_string(self, function, args, kwds): return "{}({});".format(function, ",".join(list(kwds))) return "{}({});".format(function, ",".join(list(args))) + def _coerce_impl(self, x, use_special=True): + """ + Implementation of coercion. + + TESTS: + + Test that dictionaries are converted to hashes:: + + sage: h = polymake({'"a"': 1, '"b"': 2}) # optional - polymake + sage: h # optional - polymake + HASH(0x...) + sage: h['"a"'] # optional - polymake + 1 + """ + if isinstance(x, dict): + # Convert dictionaries to hashes. + # This is an adaptation of the list/tuple code from Interface._coerce_impl + A = [] + z = dict() + cls = self._object_class() + def convert(y): + if isinstance(y, cls): + return y + else: + return self(y) + for k, v in x.items(): + k = convert(k) + v = convert(v) + z[k] = v + A.append("{}=>{}".format(k.name(), v.name())) + r = self.new("{" + ",".join(A) + "}") + r.__sage_dict = z # do this to avoid having the entries of the list be garbage collected + return r + else: + return super(PolymakeAbstract, self)._coerce_impl(x, use_special=use_special) + def console(self): """ Raise an error, pointing to :meth:`~sage.interfaces.interface.Interface.interact` and :func:`polymake_console`. @@ -333,7 +361,7 @@ def _install_hints(self): """ return "Please install the optional polymake package for sage (but read its SPKG.txt first!)"+os.linesep+"or install polymake system-wide" - def _start(self, alt_message=None): + def _start(self): """ Start the polymake interface in the application "polytope". @@ -343,10 +371,6 @@ def _start(self, alt_message=None): TESTS:: - sage: polymake.application('fan') # optional - polymake - sage: 'normal_fan' in dir(polymake) # optional - polymake - True - sage: polymake.quit() # optional - polymake sage: polymake._start() # optional - polymake Since 'normal_fan' is not defined in the polymake application 'polytope', @@ -357,22 +381,9 @@ def _start(self, alt_message=None): False """ - if not self.is_running(): - self._change_prompt("polytope > ") - Expect._start(self, alt_message=None) self.application("polytope") self.eval('use Scalar::Util qw(reftype);') self.eval('use Scalar::Util qw(blessed);') - self.eval('use File::Slurp;') - - def _quit_string(self): - """ - TESTS:: - - sage: polymake._quit_string() - 'exit;' - """ - return "exit;" def _assign_symbol(self): """ @@ -414,137 +425,6 @@ def _read_in_file_command(self, filename): """ return 'eval read_file "{}";\n'.format(filename) - def _keyboard_interrupt(self): - """ - Interrupt a computation with - - TESTS: - - For reasons that are not clear to the author, the following test - is very flaky. Therefore, this test is marked as "not tested". - - sage: c = polymake.cube(15) # optional - polymake - sage: alarm(1) # not tested - sage: try: # not tested # indirect doctest - ....: c.F_VECTOR - ....: except KeyboardInterrupt: - ....: pass - Interrupting Polymake... - doctest:warning - ... - RuntimeWarning: We ignore that Polymake issues warning during keyboard interrupt - doctest:warning - ... - RuntimeWarning: We ignore that Polymake raises error during keyboard interrupt - - Afterwards, the interface should still be running. :: - - sage: c.N_FACETS # optional - polymake - 30 - - """ - if not self.is_running(): - raise KeyboardInterrupt - print("Interrupting %s..." % self) - while True: - try: - self._expect.send(chr(3)) - except pexpect.ExceptionPexpect as msg: - raise pexpect.ExceptionPexpect("THIS IS A BUG -- PLEASE REPORT. This should never happen.\n" + msg) - sleep(0.1) - i = self._expect.expect_list(self._prompt, timeout=1) - if i == 0: - break - elif i == 7: # EOF - warnings.warn("Polymake {} during keyboard interrupt".format(_available_polymake_answers[i]), RuntimeWarning) - self._crash_msg() - self.quit() - elif i == 8: # Timeout - self.quit() - raise RuntimeError("{} interface is not responding. We closed it".format(self)) - elif i != 3: # Anything but a "computation killed" - warnings.warn("We ignore that {} {} during keyboard interrupt".format(self, _available_polymake_answers[i]), RuntimeWarning) - raise KeyboardInterrupt("Ctrl-c pressed while running {}".format(self)) - - def _synchronize(self): - """ - TESTS:: - - sage: Q = polymake.cube(4) # optional - polymake - sage: polymake('"ok"') # optional - polymake - ok - sage: polymake._expect.sendline() # optional - polymake - 1 - - Now the interface is badly out of sync:: - - sage: polymake('"foobar"') # optional - polymake - ) failed: - PolymakeError: Can't locate object method "description" via package "1" - (perhaps you forgot to load "1"?)...> - sage: Q.typeof() # optional - polymake # random - ('foobar...', 'Polymake::polytope::Polytope__Rational') - sage: Q.typeof.clear_cache() # optional - polymake - - After synchronisation, things work again as expected:: - - sage: polymake._synchronize() # optional - polymake - doctest:warning - ... - UserWarning: Polymake seems out of sync: - The expected output did not appear before reaching the next prompt. - sage: polymake('"back to normal"') # optional - polymake - back to normal - sage: Q.typeof() # optional - polymake - ('Polymake::polytope::Polytope__Rational', 'ARRAY') - - """ - if not self.is_running(): - return - rnd = randrange(2147483647) - res = str(rnd+1) - cmd = 'print 1+{};' + self._expect.linesep - self._sendstr(cmd.format(rnd)) - pat = self._expect.expect(self._prompt, timeout=0.5) - # 0: normal prompt - # 1: continuation prompt - # 2: user input expected when requestion "help" - # 3: what we are looking for when interrupting a computation - # 4: error - # 5: warning - # 6: anything but an error or warning, thus, an information - # 7: unexpected end of the stream - # 8: (expected) timeout - if pat == 8: # timeout - warnings.warn("{} unexpectedly {} during synchronisation.".format(self, _available_polymake_answers[pat]), RuntimeWarning) - self.interrupt() - # ... but we continue, as that probably means we currently are at the end of the buffer - elif pat == 7: # EOF - self._crash_msg() - self.quit() - elif pat == 0: - # We got the right prompt, but perhaps in a wrong position in the stream - # The result of the addition should appear *before* our prompt - if res not in self._expect.before: - try: - warnings.warn("{} seems out of sync: The expected output did not appear before reaching the next prompt.".format(self)) - while True: - i = self._expect.expect_list(self._prompt, timeout=0.1) - if i == 8: # This time, we do expect a timeout - return - elif i > 0: - raise RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[i])) - except pexpect.TIMEOUT: - warnings.warn("A timeout has occured when synchronising {}.".format(self), RuntimeWarning) - self._interrupt() - except pexpect.EOF: - self._crash_msg() - self.quit() - else: - return - else: - raise RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) - def _next_var_name(self): r""" Returns the next unused variable name. @@ -779,598 +659,288 @@ def help(self, topic, pager=True): PolymakeError: unknown help topic 'Triangulation' """ H = self.eval('help("{}");\n'.format(topic)) + if not H: + raise PolymakeError("unknown help topic '{}'".format(topic)) if pager: from IPython.core.page import page page(H, start=0) else: return H - def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=True, **kwds): - r""" - Evaluate a command. + def _tab_completion(self): + """ + Returns a list of polymake function names. - INPUT: + NOTE: - - ``line``, a command (string) to be evaluated - - ``allow_use_file`` (optional bool, default ``True``), whether or not - to use a file if the line is very long. - - ``wait_for_prompt`` (optional, default ``True``), whether or not - to wait before polymake returns a prompt. If it is a string, it is considered - as alternative prompt to be waited for. - - ``restart_if_needed`` (optional bool, default ``True``), whether or - not to restart polymake in case something goes wrong - - further optional arguments (e.g., timeout) that will be passed to - :meth:`pexpect.pty_spawn.spawn.expect`. Note that they are ignored - if the line is too long and thus is evaluated via a file. So, - if a timeout is defined, it should be accompanied by ``allow_use_file=False``. + - The list of functions depends on the current application. The + result is cached, of course separately for each application. + - It is generally not the case that all the returned function names + can actually successfully be called. - Different reaction types of polymake, including warnings, comments, - errors, request for user interaction, and yielding a continuation prompt, - are taken into account. + TESTS:: - Usually, this method is indirectly called via :meth:`~sage.interfaces.expect.Expect.eval`. + sage: polymake.application('fan') # optional - polymake + sage: 'normal_fan' in dir(polymake) # optional - polymake # indirect doctest + True + sage: polymake.application('polytope') # optional - polymake - EXAMPLES:: + Since 'normal_fan' is not defined in the polymake application 'polytope', + we now get + :: - sage: p = polymake.cube(3) # optional - polymake # indirect doctest + sage: 'normal_fan' in dir(polymake) # optional - polymake + False - Here we see that remarks printed by polymake are displayed if - the verbosity is positive:: + Global functions from 'core' are available:: - sage: set_verbose(1) - sage: p.N_LATTICE_POINTS # optional - polymake # random - used package latte - LattE (Lattice point Enumeration) is a computer software dedicated to the - problems of counting lattice points and integration inside convex polytopes. - Copyright by Matthias Koeppe, Jesus A. De Loera and others. - http://www.math.ucdavis.edu/~latte/ - 27 - sage: set_verbose(0) + sage: 'show_credits' in dir(polymake) # optional - polymake + True - If polymake raises an error, the polymake *interface* raises - a :class:`PolymakeError`:: + Global functions from 'common' are available:: - sage: polymake.eval('FOOBAR(3);') # optional - polymake - Traceback (most recent call last): - ... - PolymakeError: Undefined subroutine &Polymake::User::FOOBAR called... + sage: 'lex_ordered' in dir(polymake) # optional - polymake + True + """ + if not self.is_running(): + self._start() + try: + return self.__tab_completion[self._application] + except KeyError: + pass + s = self.eval("apropos '';").split('\n') + out = [] + for name in s: + if name.startswith("/common/functions/") or name.startswith("/core/functions") or name.startswith("/" + self._application + "/functions/"): + out.append(name.split("/")[-1]) + self.__tab_completion[self._application] = sorted(out) + return self.__tab_completion[self._application] - If a command is incomplete, then polymake returns a continuation - prompt. In that case, we raise an error:: + # Polymake specific methods - sage: polymake.eval('print 3') # optional - polymake - Traceback (most recent call last): - ... - SyntaxError: Incomplete polymake command 'print 3' - sage: polymake.eval('print 3;') # optional - polymake - '3' + def application(self, app): + """ + Change to a given polymake application. - However, if the command contains line breaks but eventually is complete, - no error is raised:: + INPUT: - sage: print(polymake.eval('$tmp="abc";\nprint $tmp;')) # optional - polymake - abc + - ``app``, a string, one of "common", "fulton", "group", "matroid", "topaz", + "fan", "graph", "ideal", "polytope", "tropical" - When requesting help, polymake sometimes expect the user to choose - from a list. In that situation, we abort with a warning, and show - the list from which the user can choose; we could demonstrate this using - the :meth:`help` method, but here we use an explicit code evaluation:: + EXAMPLES: - sage: print(polymake.eval('help "TRIANGULATION";')) # optional - polymake # random - doctest:warning + We expose a computation that uses both the 'polytope' and the 'fan' + application of polymake. Let us start by defining a polytope `q` in + terms of inequalities. Polymake knows to compute the f- and h-vector + and finds that the polytope is very ample:: + + sage: q = polymake.new_object("Polytope", INEQUALITIES=[[5,-4,0,1],[-3,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1],[1,0,-1,0],[3,-1,0,0]]) # optional - polymake + sage: q.H_VECTOR # optional - polymake + 1 5 5 1 + sage: q.F_VECTOR # optional - polymake + 8 14 8 + sage: q.VERY_AMPLE # optional - polymake + true + + In the application 'fan', polymake can now compute the normal fan + of `q` and its (primitive) rays:: + + sage: polymake.application('fan') # optional - polymake + sage: g = q.normal_fan() # optional - polymake + sage: g.RAYS # optional - polymake + -1 0 1/4 + 0 -1 1/4 + 1 0 0 + 1 1 -1/4 + 0 1 0 + 0 0 -1 + 0 -1 0 + -1 0 0 + sage: g.RAYS.primitive() # optional - polymake + -4 0 1 + 0 -4 1 + 1 0 0 + 4 4 -1 + 0 1 0 + 0 0 -1 + 0 -1 0 + -1 0 0 + + Note that the list of functions available by tab completion depends + on the application. + + TESTS: + + Since 'trop_witness' is not defined in the polymake application 'polytope' + but only in 'tropical', the following shows the effect of changing + the application. :: + + sage: polymake.application('polytope') # optional - polymake + sage: 'trop_witness' in dir(polymake) # optional - polymake + False + sage: polymake.application('tropical') # optional - polymake + sage: 'trop_witness' in dir(polymake) # optional - polymake + True + sage: polymake.application('polytope') # optional - polymake + sage: 'trop_witness' in dir(polymake) # optional - polymake + False + + For completeness, we show what happens when asking for an application + that doesn't exist:: + + sage: polymake.application('killerapp') # optional - polymake + Traceback (most recent call last): ... - UserWarning: Polymake expects user interaction. We abort and return - the options that Polymake provides. - There are 5 help topics matching 'TRIANGULATION': - 1: objects/Cone/properties/Triangulation and volume/TRIANGULATION - 2: objects/Polytope/properties/Triangulation and volume/TRIANGULATION - 3: objects/Visualization/Visual::PointConfiguration/methods/TRIANGULATION - 4: objects/Visualization/Visual::Polytope/methods/TRIANGULATION - 5: objects/PointConfiguration/properties/Triangulation and volume/TRIANGULATION + ValueError: Unknown polymake application 'killerapp' - By default, we just wait until polymake returns a result. However, - it is possible to explicitly set a timeout. The following usually does - work in an interactive session and often in doc tests, too. However, - sometimes it hangs, and therefore we remove it from the tests, for now:: + Of course, a different error results when we send an explicit + command in polymake to change to an unknown application:: - sage: c = polymake.cube(15) # optional - polymake - sage: polymake.eval('print {}->F_VECTOR;'.format(c.name()), timeout=1) # not tested # optional - polymake + sage: polymake.eval('application "killerapp";') # optional - polymake Traceback (most recent call last): ... - RuntimeError: Polymake fails to respond timely + PolymakeError: Unknown application killerapp - We verify that after the timeout, polymake is still able to give answers:: + """ + if app not in ["common", "fulton", "group", "matroid", "topaz", "fan", "graph", "ideal", "polytope", "tropical"]: + raise ValueError("Unknown polymake application '{}'".format(app)) + self._application = app + self.eval('application "{}";'.format(app)) - sage: c # optional - polymake - cube of dimension 15 - sage: c.N_VERTICES # optional - polymake - 32768 + def new_object(self, name, *args, **kwds): + """ + Return a new instance of a given polymake type, with given positional or named arguments. - Note, however, that the recovery after a timeout is not perfect. - It may happen that in some situation the interface collapses and - thus polymake would automatically be restarted, thereby losing all - data that have been computed before. + INPUT: + + - ``name`` of a polymake class (potentially templated), as string. + - further positional or named arguments, to be passed to the constructor. + + EXAMPLES:: + + sage: q = polymake.new_object("Polytope", INEQUALITIES=[[4,-4,0,1],[-4,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1]]) # optional - polymake + sage: q.N_VERTICES # optional - polymake + 4 + sage: q.BOUNDED # optional - polymake + true + sage: q.VERTICES # optional - polymake + 1 2 0 4 + 1 3 0 8 + 1 2 1 8 + 1 3 1 8 + sage: q.full_typename() # optional - polymake + 'Polytope' """ - line = line.strip() - if allow_use_file and wait_for_prompt and self._eval_using_file_cutoff and len(line) > self._eval_using_file_cutoff: - return self._eval_line_using_file(line) try: - if not self.is_running(): - self._start() - E = self._expect - try: - if len(line) >= 4096: - raise RuntimeError("Sending more than 4096 characters with {} on a line may cause a hang and you're sending {} characters".format(self, len(line))) - E.sendline(line) - if not wait_for_prompt: - return '' + f = self.__new[name] + except AttributeError: + self.__new = {} + f = self.__new[name] = self._function_class()(self, "new {}".format(name)) + except KeyError: + f = self.__new[name] = self._function_class()(self, "new {}".format(name)) + return f(*args, **kwds) - except OSError as msg: - if restart_if_needed: - # The subprocess most likely crashed. - # If it's really still alive, we fall through - # and raise RuntimeError. - if sys.platform.startswith('sunos'): - # On (Open)Solaris, we might need to wait a - # while because the process might not die - # immediately. See Trac #14371. - for t in [0.5, 1.0, 2.0]: - if E.isalive(): - time.sleep(t) - else: - break - if not E.isalive(): - try: - self._synchronize() - except (TypeError, RuntimeError): - pass - return self._eval_line(line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False, **kwds) - raise_(RuntimeError, "{}\nError evaluating {} in {}".format(msg, line, self), sys.exc_info()[2]) - p_warnings = [] - p_errors = [] - have_warning = False - have_error = False - have_log = False - if len(line) > 0: - first = True - while True: - try: - if isinstance(wait_for_prompt, six.string_types): - pat = E.expect(wait_for_prompt, **kwds) - else: - pat = E.expect_list(self._prompt, **kwds) - except pexpect.EOF as msg: - try: - if self.is_local(): - tmp_to_use = self._local_tmpfile() - else: - tmp_to_use = self._remote_tmpfile() - if self._read_in_file_command(tmp_to_use) in line: - raise pexpect.EOF(msg) - except NotImplementedError: - pass - if self._quit_string() in line: - # we expect to get an EOF if we're quitting. - return '' - elif restart_if_needed: # the subprocess might have crashed - try: - self._synchronize() - return self._eval_line(line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False, **kwds) - except (TypeError, RuntimeError): - pass - raise RuntimeError("{}\n{} crashed executing {}".format(msg, self, line)) - if self._terminal_echo: - out = E.before - else: - out = E.before.rstrip('\n\r') - if self._terminal_echo and first: - i = out.find("\n") - j = out.rfind("\r") - out = out[i+1:j].replace('\r\n', '\n') - else: - out = out.strip().replace('\r\n', '\n') - first = False - if have_error: - p_errors.append(out) - have_error = False - out = "" - elif have_warning: - p_warnings.append(out) - have_warning = False - out = "" - elif have_log: - if get_verbose() > 0: - print(out) - have_log = False - out = "" - # 0: normal prompt - # 1: continuation prompt - # 2: user input expected when requestion "help" - # 3: what we are looking for when interrupting a computation - # 4: error - # 5: warning - # 6: anything but an error or warning, thus, an information - # 7: unexpected end of the stream - # 8: (expected) timeout - if pat == 0: - have_log = False - have_error = False - have_warning = False - if E.buffer: - if not E.buffer.strip(): - E.send(chr(3)) - sleep(0.1) - pat = E.expect_list(self._prompt) - if E.buffer or pat: - raise RuntimeError("Couldn't return to prompt after command '{}'".format(line)) - break - elif pat == 1: # unexpected continuation prompt - # Return to normal prompt - i = pat - E.send(chr(3)) - sleep(0.1) - i = E.expect_list(self._prompt) - assert i == 0, "Command '{}': Couldn't return to normal prompt after polymake {}. Instead, polymake {}".format(line, _available_polymake_answers[pat], _available_polymake_answers[i]) - raise SyntaxError("Incomplete polymake command '{}'".format(line)) - elif pat == 2: # request for user interaction - # Return to normal prompt - warnings.warn("{} expects user interaction. We abort and return the options that {} provides.".format(self, self)) - i = pat - while i: - self._expect.send(chr(3)) - sleep(0.1) - i = self._expect.expect(self._prompt, timeout=0.1) - # User interaction is expected to happen when requesting help - if line.startswith('help'): - out = os.linesep.join(out.split(os.linesep)[:-1]) - break - else: - RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) - elif pat == 3: # killed by signal - i = pat - while pat != 0: - E.send(chr(3)) - sleep(0.1) - i = E.expect_list(self._prompt) - RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) - elif pat == 4: # polymake error - have_error = True - elif pat == 5: # polymake warning - have_warning = True - elif pat == 6: # apparently polymake prints a comment - have_log = True - elif pat == 7: # we have reached the end of the buffer - warnings.warn("Polymake unexpectedly {}".format(_available_polymake_answers[pat]), RuntimeWarning) - E.buffer = E.before + E.after + E.buffer - break - else: # timeout or some other problem - # Polymake would still continue with the computation. Thus, we send an interrupt - E.send(chr(3)) - sleep(0.1) - while E.expect_list(self._prompt, timeout=0.1): - # ... and since a single Ctrl-c just interrupts *one* of polymake's - # rule chains, we repeat until polymake is running out of rules. - E.send(chr(3)) - sleep(0.1) - raise RuntimeError("Polymake {}".format(_available_polymake_answers[pat])) - else: - out = '' - except KeyboardInterrupt: - self._keyboard_interrupt() - raise KeyboardInterrupt("Ctrl-c pressed while running {}".format(self)) - for w in p_warnings: - warnings.warn(w, RuntimeWarning) - for e in p_errors: - raise PolymakeError(e) - return out - - def _tab_completion(self): - """ - Returns a list of polymake function names. - - NOTE: - - - The list of functions depends on the current application. The - result is cached, of course separately for each application. - - It is generally not the case that all the returned function names - can actually successfully be called. - - TESTS:: +######################################## +## Elements - sage: polymake.application('fan') # optional - polymake - sage: 'normal_fan' in dir(polymake) # optional - polymake # indirect doctest - True - sage: polymake.quit() # optional - polymake - sage: polymake._start() # optional - polymake +class PolymakeElement(ExtraTabCompletion, InterfaceElement): + """ + Elements in the polymake interface. - Since 'normal_fan' is not defined in the polymake application 'polytope', - we now get - :: + EXAMPLES: - sage: 'normal_fan' in dir(polymake) # optional - polymake - False + We support all "big" polymake types, Perl arrays of length + different from one, and Perl scalars:: - Global functions from 'core' are available:: + sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake + sage: p.typename() # optional - polymake + 'Polytope' + sage: p # optional - polymake + Random spherical polytope of dimension 4; seed=5... - sage: 'show_credits' in dir(polymake) # optional - polymake - True + Now, one can work with that element in Python syntax, for example:: - Global functions from 'common' are available:: + sage: p.VERTICES[2][2] # optional - polymake + 1450479926727001/2251799813685248 - sage: 'lex_ordered' in dir(polymake) # optional - polymake - True + """ + def _repr_(self): """ - if not self.is_running(): - self._start() - try: - return self.__tab_completion[self._application] - except KeyError: - pass - s = self.eval("apropos '';").split(self._expect.linesep) - out = [] - for name in s: - if name.startswith("/common/functions/") or name.startswith("/core/functions") or name.startswith("/" + self._application + "/functions/"): - out.append(name.split("/")[-1]) - self.__tab_completion[self._application] = sorted(out) - return self.__tab_completion[self._application] + String representation of polymake elements. - # Polymake specific methods + EXAMPLES: - def application(self, app): - """ - Change to a given polymake application. + In the case of a "big" object, if polymake provides a description + of the object that is not longer than single line, it is used for + printing:: - INPUT: + sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - polymake + sage: p # optional - polymake + Random spherical polytope of dimension 3; seed=15... + sage: c = polymake.cube(4) # optional - polymake + sage: c # optional - polymake + cube of dimension 4 - - ``app``, a string, one of "common", "fulton", "group", "matroid", "topaz", - "fan", "graph", "ideal", "polytope", "tropical" + We use the print representation of scalars to display scalars:: - EXAMPLES: + sage: p.N_VERTICES # optional - polymake + 12 - We expose a computation that uses both the 'polytope' and the 'fan' - application of polymake. Let us start by defining a polytope `q` in - terms of inequalities. Polymake knows to compute the f- and h-vector - and finds that the polytope is very ample:: + The items of a Perl arrays are shown separated by commas:: - sage: q = polymake.new_object("Polytope", INEQUALITIES=[[5,-4,0,1],[-3,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1],[1,0,-1,0],[3,-1,0,0]]) # optional - polymake - sage: q.H_VECTOR # optional - polymake - 1 5 5 1 - sage: q.F_VECTOR # optional - polymake - 8 14 8 - sage: q.VERY_AMPLE # optional - polymake - true + sage: p.get_member('list_properties') # optional - polymake # random + POINTS, CONE_AMBIENT_DIM, BOUNDED, FEASIBLE, N_POINTS, POINTED, + CONE_DIM, FULL_DIM, LINEALITY_DIM, LINEALITY_SPACE, + COMBINATORIAL_DIM, AFFINE_HULL, VERTICES, N_VERTICES - In the application 'fan', polymake can now compute the normal fan - of `q` and its (primitive) rays:: + We chose to print rule chains explicitly, so that the user doesn't + need to know how to list the rules using polymake commands:: - sage: polymake.application('fan') # optional - polymake - sage: g = q.normal_fan() # optional - polymake - sage: g.RAYS # optional - polymake - -1 0 1/4 - 0 -1 1/4 - 1 0 0 - 1 1 -1/4 - 0 1 0 - 0 0 -1 - 0 -1 0 - -1 0 0 - sage: g.RAYS.primitive() # optional - polymake - -4 0 1 - 0 -4 1 - 1 0 0 - 4 4 -1 - 0 1 0 - 0 0 -1 - 0 -1 0 - -1 0 0 + sage: r = p.get_schedule('"H_VECTOR"') # optional - polymake + sage: r # optional - polymake # random + precondition : N_RAYS | N_INPUT_RAYS ( ppl.convex_hull.primal: FACETS, LINEAR_SPAN : RAYS | INPUT_RAYS ) + sensitivity check for FacetPerm + ppl.convex_hull.primal: FACETS, LINEAR_SPAN : RAYS | INPUT_RAYS + RAYS_IN_FACETS : RAYS, FACETS + SIMPLICIAL : COMBINATORIAL_DIM, RAYS_IN_FACETS + N_FACETS : FACETS + precondition : COMBINATORIAL_DIM ( F_VECTOR : N_FACETS, N_RAYS, COMBINATORIAL_DIM ) + F_VECTOR : N_FACETS, N_RAYS, COMBINATORIAL_DIM + precondition : SIMPLICIAL ( H_VECTOR : F_VECTOR ) + H_VECTOR : F_VECTOR + sage: r.typeof() # optional - polymake + ('Polymake::Core::Scheduler::RuleChain', 'ARRAY') - Note that the list of functions available by tab completion depends - on the application. + Similarly, polymake matrices and vectors are explicitly listed:: - TESTS: + sage: c.VERTICES.typename() # optional - polymake + 'Matrix' + sage: c.VERTICES[0].typename() # optional - polymake + 'Vector' + sage: c.VERTICES # optional - polymake # random + 1 -1 -1 -1 -1 + 1 1 -1 -1 -1 + 1 -1 1 -1 -1 + 1 1 1 -1 -1 + 1 -1 -1 1 -1 + 1 1 -1 1 -1 + 1 -1 1 1 -1 + 1 1 1 1 -1 + 1 -1 -1 -1 1 + 1 1 -1 -1 1 + 1 -1 1 -1 1 + 1 1 1 -1 1 + 1 -1 -1 1 1 + 1 1 -1 1 1 + 1 -1 1 1 1 + 1 1 1 1 1 + sage: c.VERTICES[0] # optional - polymake + 1 -1 -1 -1 -1 - Since 'trop_witness' is not defined in the polymake application 'polytope' - but only in 'tropical', the following shows the effect of changing - the application. :: - - sage: polymake.application('polytope') # optional - polymake - sage: 'trop_witness' in dir(polymake) # optional - polymake - False - sage: polymake.application('tropical') # optional - polymake - sage: 'trop_witness' in dir(polymake) # optional - polymake - True - sage: polymake.application('polytope') # optional - polymake - sage: 'trop_witness' in dir(polymake) # optional - polymake - False - - For completeness, we show what happens when asking for an application - that doesn't exist:: - - sage: polymake.application('killerapp') # optional - polymake - Traceback (most recent call last): - ... - ValueError: Unknown polymake application 'killerapp' - - Of course, a different error results when we send an explicit - command in polymake to change to an unknown application:: - - sage: polymake.eval('application "killerapp";') # optional - polymake - Traceback (most recent call last): - ... - PolymakeError: Unknown application killerapp - - """ - if not self.is_running(): - self._start() - if app not in ["common", "fulton", "group", "matroid", "topaz", "fan", "graph", "ideal", "polytope", "tropical"]: - raise ValueError("Unknown polymake application '{}'".format(app)) - self._application = app - patterns = ["{} > ".format(app), # 0: normal prompt - r"{} \([0-9]+\)> ".format(app), # 1: continuation prompt - "Please choose ".format(app), # 2: user input expected when requesting "help" - "killed by signal", # 3: what we are looking for when interrupting a computation - "polymake: +ERROR: +", # 4: error - "polymake: +WARNING: +", # 5: warning - "polymake: +", # 6: anything but an error or warning, thus, an information - pexpect.EOF, # 7: unexpected end of the stream - pexpect.TIMEOUT] # 8: timeout - self._change_prompt(self._expect.compile_pattern_list(patterns)) - self._sendstr('application "{}";{}'.format(app, self._expect.linesep)) - pat = self._expect.expect_list(self._prompt) - if pat: - raise RuntimeError("When changing the application, polymake unexpectedly {}".format(_available_polymake_answers[pat])) - - def new_object(self, name, *args, **kwds): - """ - Return a new instance of a given polymake type, with given positional or named arguments. - - INPUT: - - - ``name`` of a polymake class (potentially templated), as string. - - further positional or named arguments, to be passed to the constructor. - - EXAMPLES:: - - sage: q = polymake.new_object("Polytope", INEQUALITIES=[[4,-4,0,1],[-4,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1]]) # optional - polymake - sage: q.N_VERTICES # optional - polymake - 4 - sage: q.BOUNDED # optional - polymake - true - sage: q.VERTICES # optional - polymake - 1 2 0 4 - 1 3 0 8 - 1 2 1 8 - 1 3 1 8 - sage: q.full_typename() # optional - polymake - 'Polytope' - - """ - try: - f = self.__new[name] - except AttributeError: - self.__new = {} - f = self.__new[name] = self._function_class()(self, "new {}".format(name)) - except KeyError: - f = self.__new[name] = self._function_class()(self, "new {}".format(name)) - return f(*args, **kwds) - - -polymake = Polymake() - - -def reduce_load_Polymake(): - """ - Returns the polymake interface object defined in :mod:`sage.interfaces.polymake`. - - EXAMPLES:: - - sage: from sage.interfaces.polymake import reduce_load_Polymake - sage: reduce_load_Polymake() - Polymake - """ - return polymake - -######################################## -## Elements - -class PolymakeElement(ExtraTabCompletion, ExpectElement): - """ - Elements in the polymake interface. - - EXAMPLES: - - We support all "big" polymake types, Perl arrays of length - different from one, and Perl scalars:: - - sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake - sage: p.typename() # optional - polymake - 'Polytope' - sage: p # optional - polymake - Random spherical polytope of dimension 4; seed=5... - - Now, one can work with that element in Python syntax, for example:: - - sage: p.VERTICES[2][2] # optional - polymake - 1450479926727001/2251799813685248 - - """ - def _repr_(self): - """ - String representation of polymake elements. - - EXAMPLES: - - In the case of a "big" object, if polymake provides a description - of the object that is not longer than single line, it is used for - printing:: - - sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - polymake - sage: p # optional - polymake - Random spherical polytope of dimension 3; seed=15... - sage: c = polymake.cube(4) # optional - polymake - sage: c # optional - polymake - cube of dimension 4 - - We use the print representation of scalars to display scalars:: - - sage: p.N_VERTICES # optional - polymake - 12 - - The items of a Perl arrays are shown separated by commas:: - - sage: p.get_member('list_properties') # optional - polymake # random - POINTS, CONE_AMBIENT_DIM, BOUNDED, FEASIBLE, N_POINTS, POINTED, - CONE_DIM, FULL_DIM, LINEALITY_DIM, LINEALITY_SPACE, - COMBINATORIAL_DIM, AFFINE_HULL, VERTICES, N_VERTICES - - We chose to print rule chains explicitly, so that the user doesn't - need to know how to list the rules using polymake commands:: - - sage: r = p.get_schedule('"H_VECTOR"') # optional - polymake - sage: r # optional - polymake # random - precondition : N_RAYS | N_INPUT_RAYS ( ppl.convex_hull.primal: FACETS, LINEAR_SPAN : RAYS | INPUT_RAYS ) - sensitivity check for FacetPerm - ppl.convex_hull.primal: FACETS, LINEAR_SPAN : RAYS | INPUT_RAYS - RAYS_IN_FACETS : RAYS, FACETS - SIMPLICIAL : COMBINATORIAL_DIM, RAYS_IN_FACETS - N_FACETS : FACETS - precondition : COMBINATORIAL_DIM ( F_VECTOR : N_FACETS, N_RAYS, COMBINATORIAL_DIM ) - F_VECTOR : N_FACETS, N_RAYS, COMBINATORIAL_DIM - precondition : SIMPLICIAL ( H_VECTOR : F_VECTOR ) - H_VECTOR : F_VECTOR - sage: r.typeof() # optional - polymake - ('Polymake::Core::Scheduler::RuleChain', 'ARRAY') - - Similarly, polymake matrices and vectors are explicitly listed:: - - sage: c.VERTICES.typename() # optional - polymake - 'Matrix' - sage: c.VERTICES[0].typename() # optional - polymake - 'Vector' - sage: c.VERTICES # optional - polymake # random - 1 -1 -1 -1 -1 - 1 1 -1 -1 -1 - 1 -1 1 -1 -1 - 1 1 1 -1 -1 - 1 -1 -1 1 -1 - 1 1 -1 1 -1 - 1 -1 1 1 -1 - 1 1 1 1 -1 - 1 -1 -1 -1 1 - 1 1 -1 -1 1 - 1 -1 1 -1 1 - 1 1 1 -1 1 - 1 -1 -1 1 1 - 1 1 -1 1 1 - 1 -1 1 1 1 - 1 1 1 1 1 - sage: c.VERTICES[0] # optional - polymake - 1 -1 -1 -1 -1 - - For other types, we simply use the print representation offered - by polymake:: + For other types, we simply use the print representation offered + by polymake:: sage: p.TWO_FACE_SIZES.typename() # optional - polymake 'Map' @@ -2047,131 +1617,1030 @@ def _sage_doc_(self): return "Undocumented polymake type '{}'".format(self.full_typename()) -class PolymakeFunctionElement(FunctionElement): - """ - A callable (function or member function) bound to a polymake element. +class PolymakeFunctionElement(InterfaceFunctionElement): + """ + A callable (function or member function) bound to a polymake element. + + EXAMPLES:: + + sage: c = polymake.cube(2) # optional - polymake + sage: V = polymake.new_object('Vector', [1,0,0]) # optional - polymake + sage: V # optional - polymake + 1 0 0 + sage: c.contains # optional - polymake + Member function 'contains' of Polymake::polytope::Polytope__Rational object + sage: c.contains(V) # optional - polymake + true + + """ + def __init__(self, obj, name, memberfunction=False): + """ + INPUT: + + - Polymake object that this function is bound to + - name (string): It actually says how to call this function in polymake. + So, if it is a member function, it will look like `"$SAGE123[0]->func_name"`. + - ``memberfunction`` (bool, default False): Whether this is a member function + or a plain function applied with this element as first argument. + + EXAMPLES:: + + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake + sage: p.minkowski_sum_fukuda # optional - polymake + minkowski_sum_fukuda (bound to Polymake::polytope::Polytope__Rational object) + sage: p.get_schedule # optional - polymake + Member function 'get_schedule' of Polymake::polytope::Polytope__Rational object + + """ + self._obj = obj + self._name = name + self._is_memberfunc = memberfunction + + def _repr_(self): + """ + EXAMPLES:: + + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake + sage: p.minkowski_sum_fukuda # optional - polymake + minkowski_sum_fukuda (bound to Polymake::polytope::Polytope__Rational object) + sage: p.contains # optional - polymake + Member function 'contains' of Polymake::polytope::Polytope__Rational object + + """ + if self._is_memberfunc: + return "Member function '{}' of {} object".format(self._name.split("->")[-1], self._obj.typeof()[0]) + return "{} (bound to {} object)".format(self._name, self._obj.typeof()[0]) + + def __call__(self, *args, **kwds): + """ + EXAMPLES: + + We consider both member functions of an element and global functions + bound to an element:: + + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake + sage: p.get_schedule('"VERTICES"') # optional - polymake # random + sensitivity check for VertexPerm + cdd.convex_hull.canon: POINTED, RAYS, LINEALITY_SPACE : INPUT_RAYS + sage: p.minkowski_sum_fukuda(p).F_VECTOR # optional - polymake + 13 33 22 + + """ + if self._is_memberfunc: + return self._obj._check_valid().function_call(self._name, list(args), kwds) + return self._obj._check_valid().function_call(self._name, [self._obj] + list(args), kwds) + + def _sage_doc_(self): + """ + Return documentation of this function. + + NOTE: + + For unclear reasons, accessing documentation with `?` sometimes + does not include the return value of this method. + + EXAMPLES:: + + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake + sage: print(p.get_schedule._sage_doc_()) # optional - polymake # random + objects/Core::Object/methods/get_schedule: + get_schedule(request; ... ) -> Core::RuleChain + + Compose an optimal chain of production rules providing all requested properties. + The returned RuleChain object can be applied to the original object as well as to any other object + with the same initial set of properties. If no feasible rule chain exists, `undef' is returned. + + To watch the rule scheduler at work, e.g. to see announcements about tried preconditions, + you may temporarily increase the verbosity levels $Verbose::rules and $Verbose::scheduler. + + Arguments: + String request : name of a property with optional alternatives or a property path in dotted notation. + Several requests may be listed. + + Returns Core::RuleChain + sage: print(p.minkowski_sum_fukuda._sage_doc_()) # optional - polymake # random + functions/Producing a polytope from polytopes/minkowski_sum_fukuda: + minkowski_sum_fukuda(summands) -> Polytope + + Computes the (VERTICES of the) Minkowski sum of a list of polytopes using the algorithm by Fukuda described in + Komei Fukuda, From the zonotope construction to the Minkowski addition of convex polytopes, J. Symbolic Comput., 38(4):1261-1272, 2004. + + Arguments: + Array> summands + + Returns Polytope + + Example: + > $p = minkowski_sum_fukuda([cube(2),simplex(2),cross(2)]); + > print $p->VERTICES; + 1 -2 -1 + 1 -1 -2 + 1 3 -1 + 1 3 1 + 1 2 -2 + 1 -2 2 + 1 -1 3 + 1 1 3 + + """ + P = self._obj._check_valid() + return P.help(self._name.split("->")[-1], pager=False) + + +class PolymakeExpect(PolymakeAbstract, Expect): + r""" + Interface to the polymake interpreter using pexpect. + + In order to use this interface, you need to either install the + optional polymake package for Sage, or install polymake system-wide + on your computer; it is available from https://polymake.org. + + Type ``polymake.[tab]`` for a list of most functions + available from your polymake install. Type + ``polymake.Function?`` for polymake's help about a given ``Function``. + Type ``polymake(...)`` to create a new polymake + object, and ``polymake.eval(...)`` to run a string using + polymake and get the result back as a string. + + EXAMPLES:: + + sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: type(polymake) + <...sage.interfaces.polymake.PolymakeExpect... + sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake + sage: p # optional - polymake + Random spherical polytope of dimension 4; seed=5... + sage: set_verbose(3) + sage: p.H_VECTOR; # optional - polymake # random + used package ppl + The Parma Polyhedra Library ... + sage: p.H_VECTOR # optional - polymake + 1 16 40 16 1 + sage: set_verbose(0) + sage: p.F_VECTOR # optional - polymake + 20 94 148 74 + sage: print(p.F_VECTOR._sage_doc_()) # optional - polymake # random + property_types/Algebraic Types/Vector: + A type for vectors with entries of type Element. + + You can perform algebraic operations such as addition or scalar multiplication. + + You can create a new Vector by entering its elements, e.g.: + $v = new Vector(1,2,3); + or + $v = new Vector([1,2,3]); + + .. automethod:: _eval_line + """ + + def __init__(self, script_subdirectory=None, + logfile=None, server=None, server_tmpdir=None, + seed=None, command=None): + """ + TESTS:: + + sage: from sage.interfaces.polymake import PolymakeExpect + sage: PolymakeExpect() + Polymake + sage: PolymakeExpect().is_running() + False + + """ + if command is None: + command = "env TERM=dumb {}".format(os.getenv('SAGE_POLYMAKE_COMMAND') or 'polymake') + PolymakeAbstract.__init__(self, seed=seed) + Expect.__init__(self, + name="polymake", + command=command, + prompt="polytope > ", + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=False, + logfile=logfile, + eval_using_file_cutoff=1024) # > 1024 causes hangs + + def _start(self, alt_message=None): + """ + Start the polymake interface in the application "polytope". + + NOTE: + + There should be no need to call this explicitly. + + TESTS:: + + sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: polymake.application('fan') # optional - polymake + sage: 'normal_fan' in dir(polymake) # optional - polymake + True + sage: polymake.quit() # optional - polymake + sage: polymake._start() # optional - polymake + + Since 'normal_fan' is not defined in the polymake application 'polytope', + we now get + :: + + sage: 'normal_fan' in dir(polymake) # optional - polymake + False + + """ + if not self.is_running(): + self._change_prompt("polytope > ") + Expect._start(self, alt_message=None) + PolymakeAbstract._start(self) + self.eval('use File::Slurp;') + + def _quit_string(self): + """ + TESTS:: + + sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: polymake._quit_string() + 'exit;' + """ + return "exit;" + + def _keyboard_interrupt(self): + """ + Interrupt a computation with + + TESTS: + + For reasons that are not clear to the author, the following test + is very flaky. Therefore, this test is marked as "not tested". + + sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: c = polymake.cube(15) # optional - polymake + sage: alarm(1) # not tested + sage: try: # not tested # indirect doctest + ....: c.F_VECTOR + ....: except KeyboardInterrupt: + ....: pass + Interrupting Polymake... + doctest:warning + ... + RuntimeWarning: We ignore that Polymake issues warning during keyboard interrupt + doctest:warning + ... + RuntimeWarning: We ignore that Polymake raises error during keyboard interrupt + + Afterwards, the interface should still be running. :: + + sage: c.N_FACETS # optional - polymake + 30 + + """ + if not self.is_running(): + raise KeyboardInterrupt + print("Interrupting %s..." % self) + while True: + try: + self._expect.send(chr(3)) + except pexpect.ExceptionPexpect as msg: + raise pexpect.ExceptionPexpect("THIS IS A BUG -- PLEASE REPORT. This should never happen.\n" + msg) + sleep(0.1) + i = self._expect.expect_list(self._prompt, timeout=1) + if i == 0: + break + elif i == 7: # EOF + warnings.warn("Polymake {} during keyboard interrupt".format(_available_polymake_answers[i]), RuntimeWarning) + self._crash_msg() + self.quit() + elif i == 8: # Timeout + self.quit() + raise RuntimeError("{} interface is not responding. We closed it".format(self)) + elif i != 3: # Anything but a "computation killed" + warnings.warn("We ignore that {} {} during keyboard interrupt".format(self, _available_polymake_answers[i]), RuntimeWarning) + raise KeyboardInterrupt("Ctrl-c pressed while running {}".format(self)) + + def _synchronize(self): + """ + TESTS:: + + sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: Q = polymake.cube(4) # optional - polymake + sage: polymake('"ok"') # optional - polymake + ok + sage: polymake._expect.sendline() # optional - polymake + 1 + + Now the interface is badly out of sync:: + + sage: polymake('"foobar"') # optional - polymake + ) failed: + PolymakeError: Can't locate object method "description" via package "1" + (perhaps you forgot to load "1"?)...> + sage: Q.typeof() # optional - polymake # random + ('foobar...', 'Polymake::polytope::Polytope__Rational') + sage: Q.typeof.clear_cache() # optional - polymake + + After synchronisation, things work again as expected:: + + sage: polymake._synchronize() # optional - polymake + doctest:warning + ... + UserWarning: Polymake seems out of sync: + The expected output did not appear before reaching the next prompt. + sage: polymake('"back to normal"') # optional - polymake + back to normal + sage: Q.typeof() # optional - polymake + ('Polymake::polytope::Polytope__Rational', 'ARRAY') + + """ + if not self.is_running(): + return + rnd = randrange(2147483647) + res = str(rnd+1) + cmd = 'print 1+{};' + self._expect.linesep + self._sendstr(cmd.format(rnd)) + pat = self._expect.expect(self._prompt, timeout=0.5) + # 0: normal prompt + # 1: continuation prompt + # 2: user input expected when requestion "help" + # 3: what we are looking for when interrupting a computation + # 4: error + # 5: warning + # 6: anything but an error or warning, thus, an information + # 7: unexpected end of the stream + # 8: (expected) timeout + if pat == 8: # timeout + warnings.warn("{} unexpectedly {} during synchronisation.".format(self, _available_polymake_answers[pat]), RuntimeWarning) + self.interrupt() + # ... but we continue, as that probably means we currently are at the end of the buffer + elif pat == 7: # EOF + self._crash_msg() + self.quit() + elif pat == 0: + # We got the right prompt, but perhaps in a wrong position in the stream + # The result of the addition should appear *before* our prompt + if res not in self._expect.before: + try: + warnings.warn("{} seems out of sync: The expected output did not appear before reaching the next prompt.".format(self)) + while True: + i = self._expect.expect_list(self._prompt, timeout=0.1) + if i == 8: # This time, we do expect a timeout + return + elif i > 0: + raise RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[i])) + except pexpect.TIMEOUT: + warnings.warn("A timeout has occured when synchronising {}.".format(self), RuntimeWarning) + self._interrupt() + except pexpect.EOF: + self._crash_msg() + self.quit() + else: + return + else: + raise RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) + + def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=True, **kwds): + r""" + Evaluate a command. + + INPUT: + + - ``line``, a command (string) to be evaluated + - ``allow_use_file`` (optional bool, default ``True``), whether or not + to use a file if the line is very long. + - ``wait_for_prompt`` (optional, default ``True``), whether or not + to wait before polymake returns a prompt. If it is a string, it is considered + as alternative prompt to be waited for. + - ``restart_if_needed`` (optional bool, default ``True``), whether or + not to restart polymake in case something goes wrong + - further optional arguments (e.g., timeout) that will be passed to + :meth:`pexpect.pty_spawn.spawn.expect`. Note that they are ignored + if the line is too long and thus is evaluated via a file. So, + if a timeout is defined, it should be accompanied by ``allow_use_file=False``. + + Different reaction types of polymake, including warnings, comments, + errors, request for user interaction, and yielding a continuation prompt, + are taken into account. + + Usually, this method is indirectly called via :meth:`~sage.interfaces.expect.Expect.eval`. + + EXAMPLES:: + + sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: p = polymake.cube(3) # optional - polymake # indirect doctest + + Here we see that remarks printed by polymake are displayed if + the verbosity is positive:: + + sage: set_verbose(1) + sage: p.N_LATTICE_POINTS # optional - polymake # random + used package latte + LattE (Lattice point Enumeration) is a computer software dedicated to the + problems of counting lattice points and integration inside convex polytopes. + Copyright by Matthias Koeppe, Jesus A. De Loera and others. + http://www.math.ucdavis.edu/~latte/ + 27 + sage: set_verbose(0) + + If polymake raises an error, the polymake *interface* raises + a :class:`PolymakeError`:: + + sage: polymake.eval('FOOBAR(3);') # optional - polymake + Traceback (most recent call last): + ... + PolymakeError: Undefined subroutine &Polymake::User::FOOBAR called... + + If a command is incomplete, then polymake returns a continuation + prompt. In that case, we raise an error:: + + sage: polymake.eval('print 3') # optional - polymake + Traceback (most recent call last): + ... + SyntaxError: Incomplete polymake command 'print 3' + sage: polymake.eval('print 3;') # optional - polymake + '3' + + However, if the command contains line breaks but eventually is complete, + no error is raised:: + + sage: print(polymake.eval('$tmp="abc";\nprint $tmp;')) # optional - polymake + abc + + When requesting help, polymake sometimes expect the user to choose + from a list. In that situation, we abort with a warning, and show + the list from which the user can choose; we could demonstrate this using + the :meth:`help` method, but here we use an explicit code evaluation:: + + sage: print(polymake.eval('help "TRIANGULATION";')) # optional - polymake # random + doctest:warning + ... + UserWarning: Polymake expects user interaction. We abort and return + the options that Polymake provides. + There are 5 help topics matching 'TRIANGULATION': + 1: objects/Cone/properties/Triangulation and volume/TRIANGULATION + 2: objects/Polytope/properties/Triangulation and volume/TRIANGULATION + 3: objects/Visualization/Visual::PointConfiguration/methods/TRIANGULATION + 4: objects/Visualization/Visual::Polytope/methods/TRIANGULATION + 5: objects/PointConfiguration/properties/Triangulation and volume/TRIANGULATION + + By default, we just wait until polymake returns a result. However, + it is possible to explicitly set a timeout. The following usually does + work in an interactive session and often in doc tests, too. However, + sometimes it hangs, and therefore we remove it from the tests, for now:: + + sage: c = polymake.cube(15) # optional - polymake + sage: polymake.eval('print {}->F_VECTOR;'.format(c.name()), timeout=1) # not tested # optional - polymake + Traceback (most recent call last): + ... + RuntimeError: Polymake fails to respond timely + + We verify that after the timeout, polymake is still able to give answers:: + + sage: c # optional - polymake + cube of dimension 15 + sage: c.N_VERTICES # optional - polymake + 32768 + + Note, however, that the recovery after a timeout is not perfect. + It may happen that in some situation the interface collapses and + thus polymake would automatically be restarted, thereby losing all + data that have been computed before. + + """ + line = line.strip() + if allow_use_file and wait_for_prompt and self._eval_using_file_cutoff and len(line) > self._eval_using_file_cutoff: + return self._eval_line_using_file(line) + try: + if not self.is_running(): + self._start() + E = self._expect + try: + if len(line) >= 4096: + raise RuntimeError("Sending more than 4096 characters with {} on a line may cause a hang and you're sending {} characters".format(self, len(line))) + E.sendline(line) + if not wait_for_prompt: + return '' + + except OSError as msg: + if restart_if_needed: + # The subprocess most likely crashed. + # If it's really still alive, we fall through + # and raise RuntimeError. + if sys.platform.startswith('sunos'): + # On (Open)Solaris, we might need to wait a + # while because the process might not die + # immediately. See Trac #14371. + for t in [0.5, 1.0, 2.0]: + if E.isalive(): + time.sleep(t) + else: + break + if not E.isalive(): + try: + self._synchronize() + except (TypeError, RuntimeError): + pass + return self._eval_line(line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False, **kwds) + raise_(RuntimeError, "{}\nError evaluating {} in {}".format(msg, line, self), sys.exc_info()[2]) + + p_warnings = [] + p_errors = [] + have_warning = False + have_error = False + have_log = False + if len(line) > 0: + first = True + while True: + try: + if isinstance(wait_for_prompt, six.string_types): + pat = E.expect(wait_for_prompt, **kwds) + else: + pat = E.expect_list(self._prompt, **kwds) + except pexpect.EOF as msg: + try: + if self.is_local(): + tmp_to_use = self._local_tmpfile() + else: + tmp_to_use = self._remote_tmpfile() + if self._read_in_file_command(tmp_to_use) in line: + raise pexpect.EOF(msg) + except NotImplementedError: + pass + if self._quit_string() in line: + # we expect to get an EOF if we're quitting. + return '' + elif restart_if_needed: # the subprocess might have crashed + try: + self._synchronize() + return self._eval_line(line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False, **kwds) + except (TypeError, RuntimeError): + pass + raise RuntimeError("{}\n{} crashed executing {}".format(msg, self, line)) + if self._terminal_echo: + out = E.before + else: + out = E.before.rstrip('\n\r') + if self._terminal_echo and first: + i = out.find("\n") + j = out.rfind("\r") + out = out[i+1:j].replace('\r\n', '\n') + else: + out = out.strip().replace('\r\n', '\n') + first = False + if have_error: + p_errors.append(out) + have_error = False + out = "" + elif have_warning: + p_warnings.append(out) + have_warning = False + out = "" + elif have_log: + if get_verbose() > 0: + print(out) + have_log = False + out = "" + # 0: normal prompt + # 1: continuation prompt + # 2: user input expected when requestion "help" + # 3: what we are looking for when interrupting a computation + # 4: error + # 5: warning + # 6: anything but an error or warning, thus, an information + # 7: unexpected end of the stream + # 8: (expected) timeout + if pat == 0: + have_log = False + have_error = False + have_warning = False + if E.buffer: + if not E.buffer.strip(): + E.send(chr(3)) + sleep(0.1) + pat = E.expect_list(self._prompt) + if E.buffer or pat: + raise RuntimeError("Couldn't return to prompt after command '{}'".format(line)) + break + elif pat == 1: # unexpected continuation prompt + # Return to normal prompt + i = pat + E.send(chr(3)) + sleep(0.1) + i = E.expect_list(self._prompt) + assert i == 0, "Command '{}': Couldn't return to normal prompt after polymake {}. Instead, polymake {}".format(line, _available_polymake_answers[pat], _available_polymake_answers[i]) + raise SyntaxError("Incomplete polymake command '{}'".format(line)) + elif pat == 2: # request for user interaction + # Return to normal prompt + warnings.warn("{} expects user interaction. We abort and return the options that {} provides.".format(self, self)) + i = pat + while i: + self._expect.send(chr(3)) + sleep(0.1) + i = self._expect.expect(self._prompt, timeout=0.1) + # User interaction is expected to happen when requesting help + if line.startswith('help'): + out = os.linesep.join(out.split(os.linesep)[:-1]) + break + else: + RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) + elif pat == 3: # killed by signal + i = pat + while pat != 0: + E.send(chr(3)) + sleep(0.1) + i = E.expect_list(self._prompt) + RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) + elif pat == 4: # polymake error + have_error = True + elif pat == 5: # polymake warning + have_warning = True + elif pat == 6: # apparently polymake prints a comment + have_log = True + elif pat == 7: # we have reached the end of the buffer + warnings.warn("Polymake unexpectedly {}".format(_available_polymake_answers[pat]), RuntimeWarning) + E.buffer = E.before + E.after + E.buffer + break + else: # timeout or some other problem + # Polymake would still continue with the computation. Thus, we send an interrupt + E.send(chr(3)) + sleep(0.1) + while E.expect_list(self._prompt, timeout=0.1): + # ... and since a single Ctrl-c just interrupts *one* of polymake's + # rule chains, we repeat until polymake is running out of rules. + E.send(chr(3)) + sleep(0.1) + raise RuntimeError("Polymake {}".format(_available_polymake_answers[pat])) + else: + out = '' + except KeyboardInterrupt: + self._keyboard_interrupt() + raise KeyboardInterrupt("Ctrl-c pressed while running {}".format(self)) + for w in p_warnings: + warnings.warn(w, RuntimeWarning) + for e in p_errors: + raise PolymakeError(e) + return out + + def application(self, app): + """ + Change to a given polymake application. + + INPUT: + + - ``app``, a string, one of "common", "fulton", "group", "matroid", "topaz", + "fan", "graph", "ideal", "polytope", "tropical" + + EXAMPLES: + + We expose a computation that uses both the 'polytope' and the 'fan' + application of polymake. Let us start by defining a polytope `q` in + terms of inequalities. Polymake knows to compute the f- and h-vector + and finds that the polytope is very ample:: + + sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: q = polymake.new_object("Polytope", INEQUALITIES=[[5,-4,0,1],[-3,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1],[1,0,-1,0],[3,-1,0,0]]) # optional - polymake + sage: q.H_VECTOR # optional - polymake + 1 5 5 1 + sage: q.F_VECTOR # optional - polymake + 8 14 8 + sage: q.VERY_AMPLE # optional - polymake + true + + In the application 'fan', polymake can now compute the normal fan + of `q` and its (primitive) rays:: + + sage: polymake.application('fan') # optional - polymake + sage: g = q.normal_fan() # optional - polymake + sage: g.RAYS # optional - polymake + -1 0 1/4 + 0 -1 1/4 + 1 0 0 + 1 1 -1/4 + 0 1 0 + 0 0 -1 + 0 -1 0 + -1 0 0 + sage: g.RAYS.primitive() # optional - polymake + -4 0 1 + 0 -4 1 + 1 0 0 + 4 4 -1 + 0 1 0 + 0 0 -1 + 0 -1 0 + -1 0 0 + + Note that the list of functions available by tab completion depends + on the application. + + TESTS: + + Since 'trop_witness' is not defined in the polymake application 'polytope' + but only in 'tropical', the following shows the effect of changing + the application. :: + + sage: polymake.application('polytope') # optional - polymake + sage: 'trop_witness' in dir(polymake) # optional - polymake + False + sage: polymake.application('tropical') # optional - polymake + sage: 'trop_witness' in dir(polymake) # optional - polymake + True + sage: polymake.application('polytope') # optional - polymake + sage: 'trop_witness' in dir(polymake) # optional - polymake + False + + For completeness, we show what happens when asking for an application + that doesn't exist:: + + sage: polymake.application('killerapp') # optional - polymake + Traceback (most recent call last): + ... + ValueError: Unknown polymake application 'killerapp' + + Of course, a different error results when we send an explicit + command in polymake to change to an unknown application:: + + sage: polymake.eval('application "killerapp";') # optional - polymake + Traceback (most recent call last): + ... + PolymakeError: Unknown application killerapp + + """ + if not self.is_running(): + self._start() + if app not in ["common", "fulton", "group", "matroid", "topaz", "fan", "graph", "ideal", "polytope", "tropical"]: + raise ValueError("Unknown polymake application '{}'".format(app)) + self._application = app + patterns = ["{} > ".format(app), # 0: normal prompt + r"{} \([0-9]+\)> ".format(app), # 1: continuation prompt + "Please choose ".format(app), # 2: user input expected when requesting "help" + "killed by signal", # 3: what we are looking for when interrupting a computation + "polymake: +ERROR: +", # 4: error + "polymake: +WARNING: +", # 5: warning + "polymake: +", # 6: anything but an error or warning, thus, an information + pexpect.EOF, # 7: unexpected end of the stream + pexpect.TIMEOUT] # 8: timeout + self._change_prompt(self._expect.compile_pattern_list(patterns)) + self._sendstr('application "{}";{}'.format(app, self._expect.linesep)) + pat = self._expect.expect_list(self._prompt) + if pat: + raise RuntimeError("When changing the application, polymake unexpectedly {}".format(_available_polymake_answers[pat])) + +Polymake = PolymakeExpect + +class PolymakeJuPyMake(PolymakeAbstract): + + r""" + Interface to the polymake interpreter using JuPyMake. + + In order to use this interface, you need to either install the + optional polymake package for Sage, or install polymake system-wide + on your computer; it is available from https://polymake.org. + Also install the jupymake Python package. + + Type ``polymake.[tab]`` for a list of most functions + available from your polymake install. Type + ``polymake.Function?`` for polymake's help about a given ``Function``. + Type ``polymake(...)`` to create a new polymake + object, and ``polymake.eval(...)`` to run a string using + polymake and get the result back as a string. EXAMPLES:: - sage: c = polymake.cube(2) # optional - polymake - sage: V = polymake.new_object('Vector', [1,0,0]) # optional - polymake - sage: V # optional - polymake - 1 0 0 - sage: c.contains # optional - polymake - Member function 'contains' of Polymake::polytope::Polytope__Rational object - sage: c.contains(V) # optional - polymake - true + sage: from sage.interfaces.polymake import polymake_jupymake as polymake + sage: type(polymake) + <...sage.interfaces.polymake.PolymakeJuPyMake... + sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - jupymake + sage: p # optional - jupymake + Random spherical polytope of dimension 4; seed=5... + sage: set_verbose(3) + sage: p.H_VECTOR; # optional - jupymake # random + used package ppl + The Parma Polyhedra Library ... + sage: p.H_VECTOR # optional - jupymake + 1 16 40 16 1 + sage: set_verbose(0) + sage: p.F_VECTOR # optional - jupymake + 20 94 148 74 + sage: print(p.F_VECTOR._sage_doc_()) # optional - jupymake # random + property_types/Algebraic Types/Vector: + A type for vectors with entries of type Element. + + You can perform algebraic operations such as addition or scalar multiplication. + You can create a new Vector by entering its elements, e.g.: + $v = new Vector(1,2,3); + or + $v = new Vector([1,2,3]); + + Python strings are translated to polymake (Perl) identifiers. + To obtain Perl strings, use strings containing double-quote characters. + Python dicts are translated to Perl hashes. + + sage: L = polymake.db_query({'"_id"': '"F.4D.0047"'}, # long time, optional - jupymake internet perl_mongodb + ....: db='"LatticePolytopes"', + ....: collection='"SmoothReflexive"'); L + BigObjectArray + sage: len(L) # long time, optional - jupymake internet perl_mongodb + 1 + sage: P = L[0] # long time, optional - jupymake internet perl_mongodb + sage: sorted(P.list_properties(), key=str) # long time, optional - jupymake internet perl_mongodb + [..., LATTICE_POINTS_GENERATORS, ..., POINTED, ...] + sage: P.F_VECTOR # long time, optional - jupymake internet perl_mongodb + 20 40 29 9 """ - def __init__(self, obj, name, memberfunction=False): + + def __init__(self, seed=None, verbose=False): """ - INPUT: + Initialize ``self``. - - Polymake object that this function is bound to - - name (string): It actually says how to call this function in polymake. - So, if it is a member function, it will look like `"$SAGE123[0]->func_name"`. - - ``memberfunction`` (bool, default False): Whether this is a member function - or a plain function applied with this element as first argument. + INPUT: - EXAMPLES:: + - ``verbose`` -- boolean (default: ``False``); whether to print the + commands passed to polymake. - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: p.minkowski_sum_fukuda # optional - polymake - minkowski_sum_fukuda (bound to Polymake::polytope::Polytope__Rational object) - sage: p.get_schedule # optional - polymake - Member function 'get_schedule' of Polymake::polytope::Polytope__Rational object + TESTS:: + sage: from sage.interfaces.polymake import PolymakeJuPyMake + sage: PolymakeJuPyMake() + Polymake """ - self._obj = obj - self._name = name - self._is_memberfunc = memberfunction + self._verbose = verbose + PolymakeAbstract.__init__(self, seed=seed) - def _repr_(self): + _is_running = False # class variable + + def is_running(self): """ - EXAMPLES:: + Return True if self is currently running. - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: p.minkowski_sum_fukuda # optional - polymake - minkowski_sum_fukuda (bound to Polymake::polytope::Polytope__Rational object) - sage: p.contains # optional - polymake - Member function 'contains' of Polymake::polytope::Polytope__Rational object + TESTS:: - """ - if self._is_memberfunc: - return "Member function '{}' of {} object".format(self._name.split("->")[-1], self._obj.typeof()[0]) - return "{} (bound to {} object)".format(self._name, self._obj.typeof()[0]) + sage: from sage.interfaces.polymake import PolymakeJuPyMake + sage: pm = PolymakeJuPyMake() + sage: pm(1) # optional - jupymake + 1 + sage: pm.is_running() # optional - jupymake + True - def __call__(self, *args, **kwds): + Several PolymakeJuPyMake interfaces can be created, but they all + talk to the same polymake interpreter:: + + sage: pm2 = PolymakeJuPyMake() + sage: pm2.is_running() # optional - jupymake + True """ - EXAMPLES: + return self._is_running - We consider both member functions of an element and global functions - bound to an element:: + def _start(self): + """ + Initialize the interpreter. - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: p.get_schedule('"VERTICES"') # optional - polymake # random - sensitivity check for VertexPerm - cdd.convex_hull.canon: POINTED, RAYS, LINEALITY_SPACE : INPUT_RAYS - sage: p.minkowski_sum_fukuda(p).F_VECTOR # optional - polymake - 13 33 22 + TESTS:: + sage: from sage.interfaces.polymake import PolymakeJuPyMake + sage: pm = PolymakeJuPyMake() + sage: pm._start() # optional - jupymake + sage: pm.is_running() # optional - jupymake + True """ - if self._is_memberfunc: - return self._obj._check_valid().function_call(self._name, list(args), kwds) - return self._obj._check_valid().function_call(self._name, [self._obj] + list(args), kwds) + from JuPyMake import InitializePolymake + if not self.is_running(): + InitializePolymake() # Can only be called once + PolymakeJuPyMake._is_running = True + PolymakeAbstract._start(self) + self.eval("sub Polymake::Core::Shell::Mock::fill_history {}") + self._tab_completion() # Run it here already because it causes a segfault when invoked in actual tab completion situation?! - def _sage_doc_(self): - """ - Return documentation of this function. + def eval(self, code, **kwds): + r""" + Evaluate a command. - NOTE: + INPUT: - For unclear reasons, accessing documentation with `?` sometimes - does not include the return value of this method. + - ``code``, a command (string) to be evaluated + + Different reaction types of polymake, including warnings, comments, + errors, request for user interaction, and yielding a continuation prompt, + are taken into account. EXAMPLES:: - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: print(p.get_schedule._sage_doc_()) # optional - polymake # random - objects/Core::Object/methods/get_schedule: - get_schedule(request; ... ) -> Core::RuleChain - - Compose an optimal chain of production rules providing all requested properties. - The returned RuleChain object can be applied to the original object as well as to any other object - with the same initial set of properties. If no feasible rule chain exists, `undef' is returned. - - To watch the rule scheduler at work, e.g. to see announcements about tried preconditions, - you may temporarily increase the verbosity levels $Verbose::rules and $Verbose::scheduler. - - Arguments: - String request : name of a property with optional alternatives or a property path in dotted notation. - Several requests may be listed. - - Returns Core::RuleChain - sage: print(p.minkowski_sum_fukuda._sage_doc_()) # optional - polymake # random - functions/Producing a polytope from polytopes/minkowski_sum_fukuda: - minkowski_sum_fukuda(summands) -> Polytope - - Computes the (VERTICES of the) Minkowski sum of a list of polytopes using the algorithm by Fukuda described in - Komei Fukuda, From the zonotope construction to the Minkowski addition of convex polytopes, J. Symbolic Comput., 38(4):1261-1272, 2004. - - Arguments: - Array> summands - - Returns Polytope - - Example: - > $p = minkowski_sum_fukuda([cube(2),simplex(2),cross(2)]); - > print $p->VERTICES; - 1 -2 -1 - 1 -1 -2 - 1 3 -1 - 1 3 1 - 1 2 -2 - 1 -2 2 - 1 -1 3 - 1 1 3 + sage: from sage.interfaces.polymake import polymake_jupymake as polymake + sage: p = polymake.cube(3) # optional - jupymake # indirect doctest + + Here we see that remarks printed by polymake are displayed if + the verbosity is positive:: + + sage: set_verbose(1) + sage: p.N_LATTICE_POINTS # optional - jupymake # random + used package latte + LattE (Lattice point Enumeration) is a computer software dedicated to the + problems of counting lattice points and integration inside convex polytopes. + Copyright by Matthias Koeppe, Jesus A. De Loera and others. + http://www.math.ucdavis.edu/~latte/ + 27 + sage: set_verbose(0) + + If polymake raises an error, the polymake *interface* raises + a :class:`PolymakeError`:: + + sage: polymake.eval('FOOBAR(3);') # optional - jupymake + Traceback (most recent call last): + ... + PolymakeError: Undefined subroutine &Polymake::User::FOOBAR called... + + If a command is incomplete, then polymake returns a continuation + prompt. In that case, we raise an error:: + + sage: polymake.eval('print 3') # optional - jupymake + Traceback (most recent call last): + ... + SyntaxError: Incomplete polymake command 'print 3' + sage: polymake.eval('print 3;') # optional - jupymake + '3' + + However, if the command contains line breaks but eventually is complete, + no error is raised:: + + sage: print(polymake.eval('$tmp="abc";\nprint $tmp;')) # optional - jupymake + abc + + When requesting help, polymake sometimes expect the user to choose + from a list. In that situation, we abort with a warning, and show + the list from which the user can choose; we could demonstrate this using + the :meth:`help` method, but here we use an explicit code evaluation:: + + sage: print(polymake.eval('help "TRIANGULATION";')) # optional - jupymake # random + doctest:warning + ... + UserWarning: Polymake expects user interaction. We abort and return + the options that Polymake provides. + There are 5 help topics matching 'TRIANGULATION': + 1: objects/Cone/properties/Triangulation and volume/TRIANGULATION + 2: objects/Polytope/properties/Triangulation and volume/TRIANGULATION + 3: objects/Visualization/Visual::PointConfiguration/methods/TRIANGULATION + 4: objects/Visualization/Visual::Polytope/methods/TRIANGULATION + 5: objects/PointConfiguration/properties/Triangulation and volume/TRIANGULATION + + By default, we just wait until polymake returns a result. However, + it is possible to explicitly set a timeout. The following usually does + work in an interactive session and often in doc tests, too. However, + sometimes it hangs, and therefore we remove it from the tests, for now:: + + sage: c = polymake.cube(15) # optional - jupymake + sage: polymake.eval('print {}->F_VECTOR;'.format(c.name()), timeout=1) # not tested # optional - jupymake + Traceback (most recent call last): + ... + RuntimeError: Polymake fails to respond timely + + We verify that after the timeout, polymake is still able to give answers:: + + sage: c # optional - jupymake + cube of dimension 15 + sage: c.N_VERTICES # optional - jupymake + 32768 + + Note, however, that the recovery after a timeout is not perfect. + It may happen that in some situation the interface collapses and + thus polymake would automatically be restarted, thereby losing all + data that have been computed before. """ - P = self._obj._check_valid() - return P.help(self._name.split("->")[-1], pager=False) + if not self.is_running(): + self._start() + from JuPyMake import ExecuteCommand + if self._verbose: + print("## eval: {}".format(code)) + parsed, stdout, stderr, error = ExecuteCommand(code) + if get_verbose() > 0 or self._verbose: + stderr = stderr.rstrip('\n\r') + if stderr: + print(stderr) + if error: + # "Error evaluating {} in {}: {}".format(code, self, error) + raise PolymakeError(error) + if not parsed: + raise SyntaxError("Incomplete polymake command '{}'".format(code)) + return stdout + + _eval_line = eval + + +def reduce_load_Polymake(): + """ + Returns the polymake interface object defined in :mod:`sage.interfaces.polymake`. + + EXAMPLES:: + + sage: from sage.interfaces.polymake import reduce_load_Polymake + sage: reduce_load_Polymake() + Polymake + """ + return polymake + + +polymake_expect = PolymakeExpect() + +polymake_jupymake = PolymakeJuPyMake() + +from sage.features import PythonModule +if PythonModule("JuPyMake").is_present(): + polymake = polymake_jupymake +else: + polymake = polymake_expect diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index d5494049a9f..fa5f67465fe 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -550,7 +550,7 @@ def set_seed(self, seed=None): sage: r = R() sage: r.set_seed(1) 1 - sage: r.sample("1:10", 5) + sage: r.sample("1:10", 5) # random [1] 3 4 5 7 2 """ if seed is None: diff --git a/src/sage/libs/ntl/ntl_lzz_pX.pyx b/src/sage/libs/ntl/ntl_lzz_pX.pyx index 8a36824282c..f8d45641693 100644 --- a/src/sage/libs/ntl/ntl_lzz_pX.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pX.pyx @@ -183,7 +183,7 @@ cdef class ntl_zz_pX(object): """ return str(self.list()) - def __getitem__(self, i): + def __getitem__(self, long i): """ Return the ith coefficient of f. @@ -203,12 +203,10 @@ cdef class ntl_zz_pX(object): y = ntl_zz_p.__new__(ntl_zz_p) y.c = self.c self.c.restore_c() - if not isinstance(i, long): - i = long(i) y.x = zz_pX_GetCoeff(self.x, i) return y - def __setitem__(self, i, val): + def __setitem__(self, long i, val): """ Set the ith coefficient of self to val. If i is out of range, raise an exception. @@ -223,13 +221,8 @@ cdef class ntl_zz_pX(object): ... ValueError: index (=-1) is out of range """ - cdef long zero = 0L - if not isinstance(i, long): - i = long(i) - if (i < zero): + if (i < 0): raise ValueError("index (=%s) is out of range" % i) - if not isinstance(val, long): - val = long(val) self.c.restore_c() zz_pX_SetCoeff_long(self.x, i, val) return diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 7732bf8d7e6..cd36b276f29 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -5023,8 +5023,17 @@ cdef class Matrix_integer_dense(Matrix_dense): - ``matrix`` - the Hermite normal form of self. + + A ValueError is raised if the matrix is not square, fixing :trac:`5548`:: + + sage: random_matrix(ZZ,16,4)._hnf_mod(100) + Traceback (most recent call last): + ... + ValueError: matrix is not square """ t = verbose('hermite mod %s'%D, caller_name='matrix_integer_dense') + if self._nrows != self._ncols: + raise ValueError("matrix is not square") cdef Matrix_integer_dense res = self._new(self._nrows,self._ncols) self._hnf_modn(res, D) verbose('finished hnf mod', t, caller_name='matrix_integer_dense') diff --git a/src/sage/matrix/misc.pyx b/src/sage/matrix/misc.pyx index 180beae4f53..1cbbd94c365 100644 --- a/src/sage/matrix/misc.pyx +++ b/src/sage/matrix/misc.pyx @@ -420,7 +420,7 @@ def matrix_rational_echelon_form_multimodular(Matrix self, height_guess=None, pr verbose("Not checking validity of result (since proof=False).", level=2, caller_name="multimod echelon") break d = E.denominator() - hdE = long((d*E).height()) + hdE = int((d*E).height()) if hdE * self.ncols() * height < prod: verbose("Validity of result checked.", level=2, caller_name="multimod echelon") break diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 4f9d6b82260..d4284bdfabf 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -862,6 +862,13 @@ def intersection(self, other): Return the intersection of self and other inside a common ambient Jacobian product. + When ``other`` is a modular abelian variety, the output will be a tuple + ``(G, A)``, where ``G`` is a finite subgroup that surjects onto the + component group and ``A`` is the identity component. So in particular, + the intersection is the variety ``G+A``. Note that ``G`` is not chosen + in any canonical way. When ``other`` is a finite group, the + intersection will be returned as a finite group. + INPUT: @@ -875,7 +882,9 @@ def intersection(self, other): - ``G`` - finite subgroup of self - ``A`` - abelian variety (identity component of - intersection) If other is a finite group: + intersection) + + If other is a finite group: - ``G`` - a finite group @@ -915,6 +924,24 @@ def intersection(self, other): ] sage: (D[0] + D[1]).intersection(D[1] + D[2]) (Finite subgroup with invariants [5, 10] over QQbar of Abelian subvariety of dimension 3 of J0(67), Abelian subvariety of dimension 2 of J0(67)) + + When the intersection is infinite, the output is ``(G, A)``, where + ``G`` surjects onto the component group. This choice of ``G`` is not + canonical (see :trac:`26189`). In this following example, ``B`` is a + subvariety of ``J``:: + + sage: d1 = J0(11).degeneracy_map(22, 1) + sage: d2 = J0(11).degeneracy_map(22, 2) + sage: B = (d1-d2).image() + sage: J = J0(22) + sage: J.intersection(B) + (Finite subgroup with invariants [] over QQbar of Abelian variety J0(22) of dimension 2, + Abelian subvariety of dimension 1 of J0(22)) + sage: G, B = B.intersection(J); G, B + (Finite subgroup with invariants [2] over QQbar of Abelian subvariety of dimension 1 of J0(22), + Abelian subvariety of dimension 1 of J0(22)) + sage: G.is_subgroup(B) + True """ # First check whether we are intersecting an abelian variety # with a finite subgroup. If so, call the intersection method diff --git a/src/sage/modular/modform/l_series_gross_zagier.py b/src/sage/modular/modform/l_series_gross_zagier.py index c0dc715c2b1..77b40a773d8 100644 --- a/src/sage/modular/modform/l_series_gross_zagier.py +++ b/src/sage/modular/modform/l_series_gross_zagier.py @@ -16,7 +16,7 @@ def __init__(self, E, A, prec=53): `\QQ` and `A` is an ideal class in an imaginary quadratic number field. For the exact definition, in the more general setting of modular forms - instead of elliptic curves, see section IV of [GrossZagier]_. + instead of elliptic curves, see section IV of [GZ1986]_. INPUT: diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index aac16c5b35b..12087687dda 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -195,7 +195,7 @@ AUTHOR: - - William Stein, 2009 +- William Stein, 2009 """ # **************************************************************************** @@ -213,7 +213,7 @@ from sage.modules.free_module import is_FreeModule from sage.structure.all import parent from sage.structure.sequence import Sequence -from .fgp_element import DEBUG, FGP_Element +from .fgp_element import DEBUG, FGP_Element from .fgp_morphism import FGP_Morphism, FGP_Homset from sage.rings.all import Integer, ZZ from sage.arith.all import lcm @@ -225,8 +225,6 @@ _fgp_module = sage.misc.weak_dict.WeakValueDictionary() - - def FGP_Module(V, W, check=True): """ INPUT: @@ -244,7 +242,6 @@ def FGP_Module(V, W, check=True): - the quotient ``V/W`` as a finitely generated R-module - EXAMPLES:: sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) @@ -255,10 +252,11 @@ def FGP_Module(V, W, check=True): sage: Q is sage.modules.fg_pid.fgp_module.FGP_Module(V, W, check=False) True """ - key = (V,V.basis_matrix(),W,W.basis_matrix()) + key = (V, V.basis_matrix(), W, W.basis_matrix()) try: return _fgp_module[key] - except KeyError: pass + except KeyError: + pass M = FGP_Module_class(V, W, check=check) _fgp_module[key] = M return M @@ -291,7 +289,7 @@ class FGP_Module_class(Module): - ``W`` -- an R-submodule of V - - ``check`` -- bool (default: True) + - ``check`` -- bool (default: ``True``) EXAMPLES:: @@ -334,7 +332,7 @@ def __init__(self, V, W, check=True): - ``W`` -- an R-submodule of V - - ``check`` -- bool (default: True); if True, more checks on + - ``check`` -- bool (default: ``True``); if ``True``, more checks on correctness are performed; in particular, we check the data types of V and W, and that W is a submodule of V with the same base ring. @@ -378,7 +376,7 @@ def _module_constructor(self, V, W, check=True): - ``W`` -- an R-submodule of ``V``. - - ``check`` -- bool (default: True). + - ``check`` -- bool (default: ``True``). OUTPUT: @@ -392,11 +390,11 @@ def _module_constructor(self, V, W, check=True): sage: Q._module_constructor(V,W) Finitely generated module V/W over Integer Ring with invariants (4, 12) """ - return FGP_Module(V,W,check) + return FGP_Module(V, W, check) def _coerce_map_from_(self, S): """ - Return whether ``S`` canonically coerces to ``self``a. + Return whether ``S`` canonically coerces to ``self``. INPUT: @@ -471,8 +469,8 @@ def _repr_(self): sage: (V/W)._repr_() 'Finitely generated module V/W over Integer Ring with invariants (4, 12)' """ - I = str(self.invariants()).replace(',)',')') - return "Finitely generated module V/W over %s with invariants %s"%(self.base_ring(), I) + I = str(self.invariants()).replace(',)', ')') + return "Finitely generated module V/W over %s with invariants %s" % (self.base_ring(), I) def __truediv__(self, other): """ @@ -611,7 +609,6 @@ def __ge__(self, other): """ return other.is_submodule(self) - def _element_constructor_(self, x, check=True): """ INPUT: @@ -755,7 +752,9 @@ def submodule(self, x): def has_canonical_map_to(self, A): """ Return True if self has a canonical map to A, relative to the - given presentation of A. This means that A is a finitely + given presentation of A. + + This means that A is a finitely generated quotient module, self.V() is a submodule of A.V() and self.W() is a submodule of A.W(), i.e., that there is a natural map induced by inclusion of the V's. Note that we do @@ -783,8 +782,10 @@ def has_canonical_map_to(self, A): def is_submodule(self, A): """ - Return True if self is a submodule of A. More precisely, this returns True if - if ``self.V()`` is a submodule of ``A.V()``, with ``self.W()`` equal to ``A.W()``. + Return True if self is a submodule of A. + + More precisely, this returns True if if ``self.V()`` is a + submodule of ``A.V()``, with ``self.W()`` equal to ``A.W()``. Compare :meth:`.has_canonical_map_to`. @@ -838,7 +839,9 @@ def V(self): def cover(self): """ - If this module was constructed as V/W, returns the cover module V. This is the same as self.V(). + If this module was constructed as V/W, returns the cover module V. + + This is the same as self.V(). EXAMPLES:: @@ -872,7 +875,9 @@ def W(self): def relations(self): """ - If this module was constructed as V/W, returns the relations module V. This is the same as self.W(). + If this module was constructed as V/W, returns the relations module V. + + This is the same as self.W(). EXAMPLES:: @@ -916,7 +921,9 @@ def _smith_form(self): """ Return matrices S, U, and V such that S = U*R*V, and S is in Smith normal form, and R is the relative matrix that defines - self (see :meth:`._relative_matrix`). + self. + + See :meth:`._relative_matrix`. EXAMPLES:: @@ -933,6 +940,8 @@ def _smith_form(self): def base_ring(self): """ + Return the base ring of self. + EXAMPLES:: sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) @@ -953,8 +962,8 @@ def invariants(self, include_ones=False): INPUT: - - ``include_ones`` -- bool (default: False); if True, also - include 1's in the output list. + - ``include_ones`` -- bool (default: ``False``); if ``True``, also + include 1's in the output list. EXAMPLES:: @@ -973,9 +982,9 @@ def invariants(self, include_ones=False): (1, 1, 0) """ - D,_,_ = self._smith_form() + D, _, _ = self._smith_form() - v = [D[i,i] for i in range(D.nrows())] + [Integer(0)]*(D.ncols()-D.nrows()) + v = [D[i, i] for i in range(D.nrows())] + [Integer(0)] * (D.ncols()-D.nrows()) w = tuple([x for x in v if x != 1]) v = tuple(v) self.invariants.set_cache(v, True) @@ -1037,7 +1046,7 @@ def smith_form_gens(self): def gens_to_smith(self): r""" - Return the transformation matrix from the user to smith form generators. + Return the transformation matrix from the user to Smith form generators. To go in the other direction use :meth:`smith_to_gens`. @@ -1045,7 +1054,7 @@ def gens_to_smith(self): - a matrix over the base ring - EXAMLES:: + EXAMPLES:: sage: L2 = IntegralLattice(3 * matrix([[-2,0,0],[0,1,0],[0,0,-4]])) sage: D = L2.discriminant_group().normal_form() @@ -1082,14 +1091,15 @@ def gens_to_smith(self): [0 0 0 1 0] [0 0 0 0 1] """ - gens_to_smith = matrix(self.base_ring(), [t.vector() for t in self.gens()]) + gens_to_smith = matrix(self.base_ring(), + [t.vector() for t in self.gens()]) gens_to_smith.set_immutable() return gens_to_smith @cached_method def smith_to_gens(self): r""" - Return the transformation matrix from smith form to user generators. + Return the transformation matrix from Smith form to user generators. To go in the other direction use :meth:`gens_to_smith`. @@ -1140,7 +1150,7 @@ def smith_to_gens(self): sage: x.vector() * D.smith_to_gens() (2, 33, 10, 1, 3) """ - if self.base_ring()!= ZZ: + if self.base_ring() != ZZ: # it is not raise NotImplementedError("the base ring must be ZZ") base = self.base_ring() @@ -1167,7 +1177,7 @@ def gens_vector(self, x, reduce=False): - ``reduce`` -- (default: ``False``); if ``True``, reduce coefficients modulo invariants; this is - ignored if the base ring isn't `\ZZ` + ignored if the base ring is not `\ZZ` EXAMPLES: @@ -1216,8 +1226,9 @@ def gens_vector(self, x, reduce=False): from sage.rings.all import infinity if reduce and self.base_ring() == ZZ: orders = [g.order() for g in self.gens()] - v = v.parent()([v[i] if orders[i] == infinity - else v[i] % orders[i] for i in range(len(self.gens()))]) + v = v.parent()([v[i] if orders[i] == infinity + else v[i] % orders[i] + for i in range(len(self.gens()))]) return v def coordinate_vector(self, x, reduce=False): @@ -1231,7 +1242,7 @@ def coordinate_vector(self, x, reduce=False): - ``reduce`` -- (default: False); if True, reduce coefficients modulo invariants; this is - ignored if the base ring isn't ZZ. + ignored if the base ring is not ZZ. OUTPUT: @@ -1248,14 +1259,13 @@ def coordinate_vector(self, x, reduce=False): sage: Q.coordinate_vector(-Q.0, reduce=True) (3, 0, 0) - If x isn't in self, it is coerced in:: + If x is not in self, it is coerced in:: sage: Q.coordinate_vector(V.0) (1, 0, -3) sage: Q.coordinate_vector(Q(V.0)) (1, 0, -3) - TESTS:: sage: V = span([[1/2,0,0],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) @@ -1292,19 +1302,22 @@ def coordinate_vector(self, x, reduce=False): sage: x == Q.0 True """ - try: T = self.__T + try: + T = self.__T except AttributeError: - self.optimized() # computes T as side effect -- see the "optimized" method. + self.optimized() # computes T as side effect + # see the "optimized" method. T = self.__T x = self(x) c = self._V.coordinate_vector(x.lift()) - b = (c*T).change_ring(self.base_ring()) + b = (c * T).change_ring(self.base_ring()) if reduce and self.base_ring() == ZZ: I = self.invariants() - return b.parent()([b[i] if I[i] == 0 else b[i] % I[i] for i in range(len(I))]) + return b.parent()([b[i] if I[i] == 0 else b[i] % I[i] + for i in range(len(I))]) else: # Don't know (or not requested) canonical way to reduce @@ -1339,7 +1352,7 @@ def gen(self, i): """ v = self.gens() if i < 0 or i >= len(v): - raise ValueError("Generator %s not defined"%i) + raise ValueError("Generator %s not defined" % i) return v[i] def smith_form_gen(self, i): @@ -1363,7 +1376,7 @@ def smith_form_gen(self, i): """ v = self.smith_form_gens() if i < 0 or i >= len(v): - raise ValueError("Smith form generator %s not defined"%i) + raise ValueError("Smith form generator %s not defined" % i) return v[i] def optimized(self): @@ -1417,7 +1430,8 @@ def optimized(self): if self.__optimized is True: return self, None return self.__optimized - except AttributeError: pass + except AttributeError: + pass V = self._V.span_of_basis([x.lift() for x in self.smith_form_gens()]) M = self._module_constructor(V, self._W.intersection(V)) # Compute matrix T of linear transformation from self._V to V. @@ -1438,7 +1452,6 @@ def optimized(self): self.__optimized = M, X return M, X - def hom(self, im_gens, codomain=None, check=True): """ Homomorphism defined by giving the images of ``self.gens()`` in some @@ -1545,7 +1558,7 @@ def hom(self, im_gens, codomain=None, check=True): im_gens = Sequence(im_gens, universe=N) if is_FreeModule(N): - # If im_smith_gens aren't in an R-module, but are in a Free-module, + # If im_smith_gens are not in an R-module, but are in a Free-module, # then we quotient out by the 0 submodule and get an R-module. N = FGP_Module(N, N.zero_submodule(), check=DEBUG) im_gens = Sequence(im_gens, universe=N) @@ -1560,7 +1573,6 @@ def hom(self, im_gens, codomain=None, check=True): else: return self._hom_general(im_gens, check) - def _hom_general(self, im_gens, check=True): """ Homomorphism defined by giving the images of ``self.gens()`` in some @@ -1868,7 +1880,7 @@ def ngens(self): sage: A.ngens() 1 - This works (but please don't do it in production code!) :: + This works (but please do not do it in production code!) :: sage: A.gens = lambda: [1,2,"Barcelona!"] sage: A.ngens() @@ -1887,12 +1899,13 @@ def __hash__(self): 1328975982 # 32-bit -7071641102956720018 # 64-bit """ - return hash( (self.V(), self.W()) ) + return hash((self.V(), self.W())) ############################################################## # Useful for testing ############################################################## + def random_fgp_module(n, R=ZZ, finite=False): """ Return a random FGP module inside a rank n free module over R. @@ -1913,23 +1926,25 @@ def random_fgp_module(n, R=ZZ, finite=False): """ K = R.fraction_field() V = K**n - i = ZZ.random_element(max(n,1)) + i = ZZ.random_element(max(n, 1)) A = V.span([V.random_element() for _ in range(i)], R) if not finite: i = ZZ.random_element(i+1) while True: B = A.span([A.random_element() for _ in range(i)], R) - #Q = A/B - Q = FGP_Module_class(A,B,check=DEBUG) + # Q = A/B + Q = FGP_Module_class(A, B, check=DEBUG) if not finite or Q.is_finite(): return Q + def random_fgp_morphism_0(*args, **kwds): """ Construct a random fgp module using random_fgp_module, then construct a random morphism that sends each generator - to a random multiple of itself. Inputs are the same - as to random_fgp_module. + to a random multiple of itself. + + Inputs are the same as to :func:`random_fgp_module`. EXAMPLES:: @@ -1939,7 +1954,8 @@ def random_fgp_morphism_0(*args, **kwds): """ A = random_fgp_module(*args, **kwds) - return A.hom([ZZ.random_element()*g for g in A.smith_form_gens()]) + return A.hom([ZZ.random_element() * g for g in A.smith_form_gens()]) + def test_morphism_0(*args, **kwds): """ diff --git a/src/sage/numerical/backends/cplex_backend.pyx b/src/sage/numerical/backends/cplex_backend.pyx index 331296e9f89..d91097e2e1e 100644 --- a/src/sage/numerical/backends/cplex_backend.pyx +++ b/src/sage/numerical/backends/cplex_backend.pyx @@ -7,7 +7,7 @@ AUTHORS: """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2010 Nathann Cohen # # This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ AUTHORS: # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from cysignals.memory cimport sig_malloc, sig_free @@ -140,6 +140,7 @@ cdef class CPLEXBackend(GenericBackend): self.set_variable_type(n,1) if name is not None: + name = str_to_bytes(name) c_name = name status = CPXchgcolname(self.env, self.lp, 1, &n, &c_name) check(status) @@ -237,7 +238,8 @@ cdef class CPLEXBackend(GenericBackend): self.set_variable_type(j, 1) if names: - c_name = names[i] + name = str_to_bytes(names[i]) + c_name = name status = CPXchgcolname(self.env, self.lp, 1, &j, &c_name) check(status) @@ -483,7 +485,7 @@ cdef class CPLEXBackend(GenericBackend): sage: p.solve() # optional - CPLEX 10.0 sage: p.get_values([x,y]) # optional - CPLEX - [0.0, 3.0] + [0, 3] """ cdef int status status = CPXdelrows(self.env, self.lp, i, i) @@ -549,7 +551,8 @@ cdef class CPLEXBackend(GenericBackend): bound[0] = lower_bound if names: - c_names[0] = names[0] + name = str_to_bytes(names[0]) + c_names[0] = name for 1<= i = +int(CPX_INFBOUND) else ub) + return (None if lb <= -CPX_INFBOUND else lb, + None if ub >= +CPX_INFBOUND else ub) cpdef add_col(self, indices, coeffs): r""" @@ -1098,7 +1104,7 @@ cdef class CPLEXBackend(GenericBackend): status = CPXgetctype(self.env, self.lp, &ctype, variable, variable) - return value if (status == 3003 or ctype=='C') else round(value) + return value if (status == 3003 or ctype == 'C') else int(round(value)) cpdef int ncols(self): r""" @@ -1163,7 +1169,7 @@ cdef class CPLEXBackend(GenericBackend): return "" check(status) - s = str(n) + s = char_to_str(n) sig_free(n) return s @@ -1197,7 +1203,7 @@ cdef class CPLEXBackend(GenericBackend): return "" check(status) - s = str(n) + s = char_to_str(n) sig_free(n) return s @@ -1371,7 +1377,7 @@ cdef class CPLEXBackend(GenericBackend): status = CPXgetub(self.env, self.lp, &ub, index, index) check(status) - return ub if ub < int(CPX_INFBOUND) else None + return ub if ub < CPX_INFBOUND else None else: x = 'U' @@ -1423,7 +1429,7 @@ cdef class CPLEXBackend(GenericBackend): if value is False: status = CPXgetlb(self.env, self.lp, &lb, index, index) check(status) - return None if lb <= int(-CPX_INFBOUND) else lb + return None if lb <= -CPX_INFBOUND else lb else: x = 'L' @@ -1592,7 +1598,7 @@ cdef class CPLEXBackend(GenericBackend): check( CPXsetlogfile(self.env, NULL) ) self._logfilename = '' else: # Set log file to logfilename - ff = fopen(value, "a") + ff = fopen(str_to_bytes(value), "a") if not ff: raise ValueError("Unable to append file {}.".format(value)) check( CPXsetlogfile(self.env, ff) ) diff --git a/src/sage/numerical/backends/cvxopt_backend.pyx b/src/sage/numerical/backends/cvxopt_backend.pyx index c3999ad5943..419c5f69cbd 100644 --- a/src/sage/numerical/backends/cvxopt_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_backend.pyx @@ -386,15 +386,16 @@ cdef class CVXOPTBackend(GenericBackend): sage: p = get_solver(solver = "CVXOPT") sage: p.add_variables(5) 4 - sage: p.add_linear_constraint(list(zip(range(5), range(5))), 2.0, 2.0) + sage: p.add_linear_constraint(zip(range(5), range(5)), 2.0, 2.0) sage: p.row(0) ([1, 2, 3, 4], [1, 2, 3, 4]) sage: p.row_bounds(0) (2.00000000000000, 2.00000000000000) - sage: p.add_linear_constraint(list(zip(range(5), range(5))), 1.0, 1.0, name='foo') + sage: p.add_linear_constraint(zip(range(5), range(5)), 1.0, 1.0, name='foo') sage: p.row_name(-1) 'foo' """ + coefficients = list(coefficients) for c in coefficients: while c[0] > len(self.G_matrix)-1: self.add_variable() diff --git a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx index 96f325f05ca..8f6c97e979e 100644 --- a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx @@ -283,6 +283,7 @@ cdef class CVXOPTSDPBackend(GenericSDPBackend): sage: p.row_name(-1) 'fun' """ + coefficients = list(coefficients) from sage.structure.element import is_Matrix for t in coefficients: m = t[1] diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index ee95b475bb0..55ac3485bf1 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -563,12 +563,12 @@ cdef class GLPKBackend(GenericBackend): sage: p = get_solver(solver = "GLPK") sage: p.add_variables(5) 4 - sage: p.add_linear_constraint(list(zip(range(5), range(5))), 2.0, 2.0) + sage: p.add_linear_constraint(zip(range(5), range(5)), 2.0, 2.0) sage: p.row(0) ([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) sage: p.row_bounds(0) (2.0, 2.0) - sage: p.add_linear_constraint(list(zip(range(5), range(5))), 1.0, 1.0, name='foo') + sage: p.add_linear_constraint(zip(range(5), range(5)), 1.0, 1.0, name='foo') sage: p.row_name(1) 'foo' @@ -594,8 +594,10 @@ cdef class GLPKBackend(GenericBackend): cdef int * row_i cdef double * row_values - row_i = mem.allocarray(len(coefficients)+1, sizeof(int)) - row_values = mem.allocarray(len(coefficients)+1, sizeof(double)) + coefficients = list(coefficients) + cdef int n_coeff = len(coefficients) + row_i = mem.allocarray(n_coeff + 1, sizeof(int)) + row_values = mem.allocarray(n_coeff + 1, sizeof(double)) cdef Py_ssize_t i = 1 for c,v in coefficients: @@ -604,7 +606,7 @@ cdef class GLPKBackend(GenericBackend): i += 1 sig_on() - glp_set_mat_row(self.lp, n, len(coefficients), row_i, row_values) + glp_set_mat_row(self.lp, n, n_coeff, row_i, row_values) sig_off() if upper_bound is not None and lower_bound is None: diff --git a/src/sage/numerical/backends/gurobi_backend.pyx b/src/sage/numerical/backends/gurobi_backend.pyx index 647edee259c..f5405c39672 100644 --- a/src/sage/numerical/backends/gurobi_backend.pyx +++ b/src/sage/numerical/backends/gurobi_backend.pyx @@ -516,11 +516,13 @@ cdef class GurobiBackend(GenericBackend): if lower_bound is None and upper_bound is None: raise ValueError("At least one of 'upper_bound' or 'lower_bound' must be set.") + coefficients = list(coefficients) + cdef int n = len(coefficients) cdef int * row_i cdef double * row_values - row_i = sig_malloc((len(coefficients)) * sizeof(int)) - row_values = sig_malloc((len(coefficients)) * sizeof(double)) + row_i = sig_malloc(n * sizeof(int)) + row_values = sig_malloc(n * sizeof(double)) for i,(c,v) in enumerate(coefficients): @@ -531,17 +533,17 @@ cdef class GurobiBackend(GenericBackend): name = "" if upper_bound is not None and lower_bound is None: - error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_LESS_EQUAL, upper_bound, name) + error = GRBaddconstr(self.model, n, row_i, row_values, GRB_LESS_EQUAL, upper_bound, name) elif lower_bound is not None and upper_bound is None: - error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_GREATER_EQUAL, lower_bound, name) + error = GRBaddconstr(self.model, n, row_i, row_values, GRB_GREATER_EQUAL, lower_bound, name) elif upper_bound is not None and lower_bound is not None: if lower_bound == upper_bound: - error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_EQUAL, lower_bound, name) + error = GRBaddconstr(self.model, n, row_i, row_values, GRB_EQUAL, lower_bound, name) else: - error = GRBaddrangeconstr(self.model, len(coefficients), row_i, row_values, lower_bound, upper_bound, name) + error = GRBaddrangeconstr(self.model, n, row_i, row_values, lower_bound, upper_bound, name) check(self.env,error) diff --git a/src/sage/repl/ipython_kernel/install.py b/src/sage/repl/ipython_kernel/install.py index dc3dd6ed4ad..073fae573c8 100644 --- a/src/sage/repl/ipython_kernel/install.py +++ b/src/sage/repl/ipython_kernel/install.py @@ -207,11 +207,12 @@ def kernel_spec(self): sage: from sage.repl.ipython_kernel.install import SageKernelSpec sage: spec = SageKernelSpec(prefix=tmp_dir()) sage: spec.kernel_spec() - {'argv': ..., 'display_name': 'SageMath ...'} + {'argv': ..., 'display_name': 'SageMath ...', 'language': 'sage'} """ return dict( argv=self._kernel_cmd(), display_name=self._display_name, + language='sage', ) def _install_spec(self): diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 15c8a3d43f2..d2c7a514741 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -759,14 +759,14 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, ....: 'n', alpha=0) Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large n. + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=-1) Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large n. + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large n. :: @@ -798,8 +798,8 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, ....: 'n', alpha=-1, zeta=2, precision=3) Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large n. + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1/2, zeta=2, precision=3) 1/sqrt(pi)*(1/2)^n*n^(-1/2) - 1/8/sqrt(pi)*(1/2)^n*n^(-3/2) @@ -1007,7 +1007,7 @@ def inverse_gamma_derivative(shift, r): result = A(0) elif alpha <= 0 and precision > 0: from .misc import NotImplementedOZero - raise NotImplementedOZero(A) + raise NotImplementedOZero(A, exact_part=A.zero()) for (k, r) in it: result += binomial(beta, r) * \ diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 90e08ce7090..6df3bfd277f 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -991,7 +991,8 @@ def _repr_(self, latex=False): else: f = repr s = ' + '.join(f(elem) for elem in - self.summands.elements_topological(reverse=True)) + self.summands.elements_topological(reverse=True, + key=repr)) s = s.replace('+ -', '- ') if not s: return '0' @@ -1939,12 +1940,12 @@ def O(self): sage: AR(0).O() Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large x. + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large x. """ if not self.summands: from .misc import NotImplementedOZero - raise NotImplementedOZero(self.parent()) + raise NotImplementedOZero(self.parent(), exact_part=self.parent().zero()) return sum(self.parent().create_summand('O', growth=element) for element in self.summands.maximal_elements()) @@ -2619,6 +2620,13 @@ def substitute(self, rules=None, domain=None, **kwds): Traceback (most recent call last): ... ValueError: Cannot substitute in u: duplicate key u. + + :: + + sage: B(0).subs({'_zero_': None}) is None + True + sage: B(1).subs({'_one_': AA(1)}).parent() is AA + True """ # check if nothing to do if not rules and not kwds: @@ -2653,7 +2661,8 @@ def substitute(self, rules=None, domain=None, **kwds): # check if all keys are generators gens_str = tuple(str(g) for g in gens) for k in locals: - if str(k) not in gens_str: + sk = str(k) + if sk not in gens_str and not sk.startswith('_'): raise ValueError('Cannot substitute %s in %s ' 'since it is not a generator of %s.' % (k, self, self.parent())) @@ -3279,7 +3288,8 @@ def _singularity_analysis_(self, var, zeta, precision=None): sage: (1/T)._singularity_analysis_('n', 1) Traceback (most recent call last): ... - NotImplementedOZero: T^(-1) + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large n. """ from .misc import NotImplementedOZero OZeroEncountered = False @@ -3293,14 +3303,15 @@ def _singularity_analysis_(self, var, zeta, precision=None): contribution = s._singularity_analysis_( var=var, zeta=zeta, precision=precision) - except NotImplementedOZero: + except NotImplementedOZero as ozero: OZeroEncountered = True + result += ozero.exact_part else: result += contribution if OZeroEncountered and (isinstance(result, int) and result == 0 or result.is_exact()): - raise NotImplementedOZero(self) + raise NotImplementedOZero(var=var, exact_part=result) return result def limit(self): @@ -4344,7 +4355,8 @@ def ngens(self): def coefficients_of_generating_function(self, function, singularities, precision=None, - return_singular_expansions=False): + return_singular_expansions=False, + error_term=None): r""" Return the asymptotic growth of the coefficients of some generating function by means of Singularity Analysis. @@ -4361,6 +4373,11 @@ def coefficients_of_generating_function(self, function, singularities, precision - ``return_singular_expansions`` -- (default: ``False``) a boolean. If set, the singular expansions are also returned. + - ``error_term`` -- (default: ``None``) an asymptotic expansion. + If ``None``, then this is interpreted as zero. + The contributions of the coefficients are added to ``error_term`` + during Singularity Analysis. + OUTPUT: - If ``return_singular_expansions=False``: An asymptotic expansion from @@ -4420,15 +4437,24 @@ def coefficients_of_generating_function(self, function, singularities, precision ``return_singular_expansions`` will change to return singular expansions around the singularities. - TESTS:: + In the following example, the result is an exact asymptotic expression + for sufficiently large `n` (i.e., there might be finitely many + exceptional values). This is encoded by an `O(0)` error term:: sage: def f(z): ....: return z/(1-z) sage: B.coefficients_of_generating_function(f, (1,), precision=3) Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large n. + NotImplementedOZero: got 1 + O(0) + The error term O(0) means 0 for sufficiently large n. + + In this case, we can manually intervene by adding an an error term + that suits us:: + + sage: B.coefficients_of_generating_function(f, (1,), precision=3, + ....: error_term=O(n^-100)) + 1 + O(n^(-100)) """ from sage.symbolic.ring import SR from .misc import NotImplementedOZero @@ -4441,7 +4467,10 @@ def coefficients_of_generating_function(self, function, singularities, precision default_prec=precision) T = A.gen() - result = self.zero() + if error_term is None: + result = self.zero() + else: + result = error_term for singularity in singularities: singular_expansion = A(function((1-1/T)*singularity)) singular_expansions[singularity] = singular_expansion @@ -4450,13 +4479,14 @@ def coefficients_of_generating_function(self, function, singularities, precision contribution = singular_expansion._singularity_analysis_( var='Z', zeta=singularity, precision=precision).subs(Z=self.gen()) - except NotImplementedOZero: + except NotImplementedOZero as ozero: OZeroEncountered = True + result += ozero.exact_part.subs(Z=self.gen()) else: result += contribution if OZeroEncountered and result.is_exact(): - raise NotImplementedOZero(self) + raise NotImplementedOZero(self, exact_part=result) if return_singular_expansions: from collections import namedtuple diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 873dcb91df9..0a9c4c05e9b 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -1317,8 +1317,8 @@ def _singularity_analysis_(self, var, zeta, precision): sage: G(1)._singularity_analysis_('n', 2, precision=3) Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large n. + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large n. sage: G('exp(x)')._singularity_analysis_('n', 2, precision=3) Traceback (most recent call last): ... @@ -1329,7 +1329,7 @@ def _singularity_analysis_(self, var, zeta, precision): if len(factors) == 0: from .asymptotic_expansion_generators import asymptotic_expansions from .misc import NotImplementedOZero - raise NotImplementedOZero(var=var) + raise NotImplementedOZero(var=var, exact_part=0) elif len(factors) == 1: return factors[0]._singularity_analysis_( var=var, zeta=zeta, precision=precision) diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index f2c58a12714..fcfe933b21d 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -782,42 +782,60 @@ class NotImplementedOZero(NotImplementedError): which is raised when the result is O(0) which means 0 for sufficiently large values of the variable. """ - def __init__(self, data=None, var=None): + def __init__(self, asymptotic_ring=None, var=None, exact_part=0): r""" INPUT: - - ``data`` -- (default: ``None``) an :class:`AsymptoticRing` or a string. + - ``asymptotic_ring`` -- (default: ``None``) an :class:`AsymptoticRing` or ``None``. - ``var`` -- (default: ``None``) a string. - TESTS:: + Either ``asymptotic_ring`` or ``var`` has to be specified. + + - ``exact_part`` -- (default: ``0``) asymptotic expansion + + EXAMPLES:: sage: A = AsymptoticRing('n^ZZ', ZZ) sage: from sage.rings.asymptotic.misc import NotImplementedOZero + sage: raise NotImplementedOZero(A) Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large n. - sage: raise NotImplementedOZero('something') + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large n. + + sage: raise NotImplementedOZero(var='m') Traceback (most recent call last): ... - NotImplementedOZero: something - sage: raise NotImplementedOZero(var='m') + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large m. + + TESTS:: + + sage: raise NotImplementedOZero(A, var='m') + Traceback (most recent call last): + ... + ValueError: specify either 'asymptotic_ring' or 'var' + sage: raise NotImplementedOZero() Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large m. + ValueError: specify either 'asymptotic_ring' or 'var' """ - from .asymptotic_ring import AsymptoticRing - if isinstance(data, AsymptoticRing) or var is not None: - if var is None: - var = ', '.join(str(g) for g in data.gens()) - message = ('The error term in the result is O(0) ' - 'which means 0 for sufficiently ' - 'large {}.'.format(var)) - else: - message = data + if (asymptotic_ring is None) == (var is None): + raise ValueError("specify either 'asymptotic_ring' or 'var'") + + if var is None: + var = ', '.join(str(g) for g in asymptotic_ring.gens()) + message = ('got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') + + 'O(0)') + + 'The error term O(0) ' + 'means 0 for sufficiently large {}.'.format(var)) + + if asymptotic_ring is not None and isinstance(exact_part, int) and exact_part == 0: + exact_part = asymptotic_ring.zero() + self.exact_part = exact_part + super(NotImplementedOZero, self).__init__(message) diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 959e09dad5b..4439859572f 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -3889,8 +3889,8 @@ def _singularity_analysis_(self, var, zeta, precision): sage: T('2*x^(-1)')._singularity_analysis_('n', 2, precision=3) Traceback (most recent call last): ... - NotImplementedOZero: The error term in the result is O(0) - which means 0 for sufficiently large n. + NotImplementedOZero: got O(0) + The error term O(0) means 0 for sufficiently large n. """ return self.coefficient * self.growth._singularity_analysis_( var=var, zeta=zeta, precision=precision) diff --git a/src/sage/rings/function_field/differential.py b/src/sage/rings/function_field/differential.py index a6544d26845..592d55a4cc4 100644 --- a/src/sage/rings/function_field/differential.py +++ b/src/sage/rings/function_field/differential.py @@ -1,8 +1,8 @@ """ Differentials of function fields -Sage provides basic arithmetic and advanced computations with differentials on -global function fields. +Sage provides basic arithmetic with differentials of function fields. Advanced +computations with differentials are available for global function fields. EXAMPLES: @@ -68,31 +68,29 @@ class FunctionFieldDifferential(ModuleElement): """ Base class for differentials on function fields. - """ - pass - -class FunctionFieldDifferential_global(FunctionFieldDifferential): - """ - Differentials on global function fields. INPUT: - ``f`` -- element of the function field - - ``t`` -- element of the function field; if `t` is not specified, `t` - is the generator of the base rational function field + - ``t`` -- element of the function field; if `t` is not specified, the generator + of the base differential is assumed EXAMPLES:: - sage: F.=FunctionField(GF(7)) + sage: F.=FunctionField(QQ) sage: f = x/(x^2 + x + 1) sage: f.differential() - ((6*x^2 + 1)/(x^4 + 2*x^3 + 3*x^2 + 2*x + 1)) d(x) + ((-x^2 + 1)/(x^4 + 2*x^3 + 3*x^2 + 2*x + 1)) d(x) - sage: K. = FunctionField(GF(4)); _. = K[] + :: + + sage: K. = FunctionField(QQ); _. = K[] sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: L(x).differential() + d(x) sage: y.differential() - (x*y^2 + 1/x*y) d(x) + ((21/4*x/(x^7 + 27/4))*y^2 + ((3/2*x^7 + 9/4)/(x^8 + 27/4*x))*y + 7/2*x^4/(x^7 + 27/4)) d(x) """ def __init__(self, parent, f, t=None): """ @@ -100,7 +98,7 @@ def __init__(self, parent, f, t=None): TESTS:: - sage: F.=FunctionField(GF(7)) + sage: F. = FunctionField(GF(7)) sage: f = x/(x^2 + x + 1) sage: w = f.differential() sage: TestSuite(w).run() @@ -108,8 +106,7 @@ def __init__(self, parent, f, t=None): ModuleElement.__init__(self, parent) if t is not None: - der = parent.function_field().derivation() - f *= der(t) + f *= parent._derivation(t) * parent._gen_derivative_inv self._f = f @@ -129,12 +126,10 @@ def _repr_(self): sage: f.differential() (-1/x^2) d(x) """ - F = self.parent().function_field() - if self._f.is_zero(): # zero differential return '0' - r = 'd({})'.format(F.base_field().gen()) + r = 'd({})'.format(self.parent()._gen_base_differential) if self._f.is_one(): return r @@ -153,12 +148,10 @@ def _latex_(self): sage: latex(w) \left( x y^{2} + \frac{1}{x} y \right)\, dx """ - F = self.parent().function_field() - if self._f.is_zero(): # zero differential return '0' - r = 'd{}'.format(F.base_field().gen()) + r = 'd{}'.format(self.parent()._gen_base_differential) if self._f.is_one(): return r @@ -354,6 +347,22 @@ def valuation(self, place): return (self._f.valuation(place) + 2*min(F(x).valuation(place), 0) + F.different().valuation(place)) +class FunctionFieldDifferential_global(FunctionFieldDifferential): + """ + Differentials on global function fields. + + EXAMPLES:: + + sage: F.=FunctionField(GF(7)) + sage: f = x/(x^2 + x + 1) + sage: f.differential() + ((6*x^2 + 1)/(x^4 + 2*x^3 + 3*x^2 + 2*x + 1)) d(x) + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: y.differential() + (x*y^2 + 1/x*y) d(x) + """ def residue(self, place): """ Return the residue of the differential at the place. @@ -478,8 +487,25 @@ class DifferentialsSpace(UniqueRepresentation, Parent): sage: L.=K.extension(Y^3+x+x^3*Y) sage: L.space_of_differentials() Space of differentials of Function field in y defined by y^3 + x^3*y + x + + The space of differentials is a one-dimensional module over the function + field. So a base differential is chosen to represent differentials. + Usually the generator of the base rational function field is a seprating + element and used to generate the base differential. Otherwise a separating + element is automatically found and used to generate the base differential + relative which other differentials are denoted:: + + sage: K. = FunctionField(GF(5)) + sage: R. = K[] + sage: L. = K.extension(y^5 - 1/x) + sage: L(x).differential() + 0 + sage: y.differential() + d(y) + sage: (y^2).differential() + (2*y) d(y) """ - Element = FunctionFieldDifferential_global + Element = FunctionFieldDifferential def __init__(self, field, category=None): """ @@ -494,6 +520,19 @@ def __init__(self, field, category=None): """ Parent.__init__(self, base=field, category=Modules(field).FiniteDimensional().WithBasis().or_subcategory(category)) + # Starting from the base rational function field, find the first + # generator x of an intermediate function field that doesn't map to zero + # by the derivation map and use dx as our base differential. + + der = field.derivation() + for F in reversed(field._intermediate_fields(field.rational_function_field())): + if der(F.gen()) != 0: + break + + self._derivation = der + self._gen_base_differential = F.gen() + self._gen_derivative_inv = ~der(F.gen()) # used for fast computation + def _repr_(self): """ Return the string representation of the space of differentials. @@ -577,3 +616,20 @@ def basis(self): """ return Family([self.element_class(self, self.base().one())]) +class DifferentialsSpace_global(DifferentialsSpace): + """ + Space of differentials of a global function field. + + INPUT: + + - ``field`` -- function field + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: L.space_of_differentials() + Space of differentials of Function field in y defined by y^3 + x^3*y + x + """ + Element = FunctionFieldDifferential_global + diff --git a/src/sage/rings/function_field/element.pyx b/src/sage/rings/function_field/element.pyx index 780edde0ef2..19007e5d4a7 100644 --- a/src/sage/rings/function_field/element.pyx +++ b/src/sage/rings/function_field/element.pyx @@ -356,6 +356,23 @@ cdef class FunctionFieldElement(FieldElement): sage: L. = K.extension(Y^2 + Y + x +1/x) sage: (y^3 + x).differential() (((x^2 + 1)/x^2)*y + (x^4 + x^3 + 1)/x^3) d(x) + + TESTS: + + Verify that :trac:`27712` is resolved:: + + sage: K. = FunctionField(GF(31)) + sage: R. = K[] + sage: L. = K.extension(y^2 - x) + sage: R. = L[] + sage: M. = L.extension(z^2 - y) + + sage: x.differential() + d(x) + sage: y.differential() + (16/x*y) d(x) + sage: z.differential() + (8/x*z) d(x) """ F = self.parent() W = F.space_of_differentials() diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 503a973a2a4..c8f36b4463d 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -95,7 +95,7 @@ sage: O.basis() (1, y, 1/x*y^2 + 1/x*y, 1/x^3*y^3 + 2/x^3*y^2 + 1/x^3*y) sage: I = O.ideal(x,y); I - Ideal (x, y + x) of Maximal order of Function field in y defined by y^4 + y + 2*x^5 + Ideal (x, y) of Maximal order of Function field in y defined by y^4 + y + 2*x^5 sage: J = I^-1 sage: J.basis_matrix() [ 1 0 0 0] @@ -183,6 +183,8 @@ from sage.categories.homset import Hom from sage.categories.function_fields import FunctionFields +from .differential import DifferentialsSpace, DifferentialsSpace_global + from .element import ( FunctionFieldElement, FunctionFieldElement_rational, @@ -234,6 +236,8 @@ class FunctionField(Field): sage: K Rational function field in x over Rational Field """ + _differentials_space = DifferentialsSpace + def __init__(self, base_field, names, category=FunctionFields()): """ Initialize. @@ -730,7 +734,7 @@ def _intermediate_fields(self, base): OUTPUT: - - a list of fields; the first entry is ``base``, the last entry is this field. + - a list of fields; the first entry is this field, the last entry is ``base`` EXAMPLES:: @@ -926,8 +930,7 @@ def space_of_differentials(self): sage: L.space_of_differentials() Space of differentials of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) """ - from .differential import DifferentialsSpace - return DifferentialsSpace(self) + return self._differentials_space(self) def divisor_group(self): """ @@ -2598,6 +2601,7 @@ class FunctionField_global(FunctionField_polymod): 0 """ Element = FunctionFieldElement_global + _differentials_space = DifferentialsSpace_global def __init__(self, polynomial, names): """ @@ -4173,6 +4177,8 @@ class RationalFunctionField_global(RationalFunctionField): """ Rational function field over finite fields. """ + _differentials_space = DifferentialsSpace_global + def places(self, degree=1): """ Return all places of the degree. diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 07b44d98864..43652538523 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -42,13 +42,13 @@ sage: I^2 Ideal (x) of Maximal order of Function field in y defined by y^2 + x^3*y + x sage: ~I - Ideal (1, 1/x*y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + Ideal (1/x*y) of Maximal order of Function field in y defined by y^2 + x^3*y + x sage: ~I * I Ideal (1) of Maximal order of Function field in y defined by y^2 + x^3*y + x sage: J = O.ideal(x+y) * I sage: J.factor() - (Ideal (x, y) of Maximal order of Function field in y defined by y^2 + x^3*y + x)^2 * + (Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x)^2 * (Ideal (x^3 + x + 1, y + x) of Maximal order of Function field in y defined by y^2 + x^3*y + x) Ideals in the maximal infinite order of a global function field:: @@ -60,13 +60,13 @@ sage: I + I == I True sage: I^2 - Ideal (1/x^3,1/x^4*y) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 + Ideal (1/x^4*y) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 sage: ~I - Ideal (x,y) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 + Ideal (y) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 sage: ~I * I Ideal (1) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 sage: I.factor() - (Ideal (1/x,1/x^3*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4)^4 + (Ideal (1/x^3*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4)^4 AUTHORS: @@ -91,6 +91,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.misc import powerset from sage.structure.parent import Parent from sage.structure.element import Element @@ -139,6 +140,107 @@ def __init__(self, ring): Element.__init__(self, ring.ideal_monoid()) self._ring = ring + def _repr_short(self): + """ + Return a string representation of this ideal that doesn't + include the name of the ambient ring. + + EXAMPLES:: + + sage: K. = FunctionField(GF(3^2)); R. = K[] + sage: F. = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/y) + sage: I._repr_short() + '(1/x^4*y^2)' + """ + if self.is_zero(): + return "(0)" + + return "(%s)" % (', '.join([repr(g) for g in self.gens_reduced()]), ) + + def _repr_(self): + """ + Return a string representation of this ideal. + + EXAMPLES:: + + sage: K. = FunctionField(QQ) + sage: O = K.maximal_order() + sage: I = O.ideal(x,1/(x+1)); I + Ideal (1/(x + 1)) of Maximal order of Rational function field in x over Rational Field + + sage: K. = FunctionField(QQ); R. = K[] + sage: L. = K.extension(y^2 - x^3 - 1) + sage: O = L.equation_order() + sage: O.ideal(x^2 + 1) + Ideal (x^2 + 1) of Order in Function field in y defined by y^2 - x^3 - 1 + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y); I + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y); I + Ideal (y) of Maximal order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + + sage: K. = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal(x/(x^2+1)) + sage: I + Ideal (1/x) of Maximal infinite order of Rational function field + in x over Finite Field of size 2 + + sage: K. = FunctionField(GF(3^2)); _. = PolynomialRing(K) + sage: F. = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: Oinf.ideal(1/y) + Ideal (1/x^4*y^2) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4 + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: Oinf.ideal(1/y) + Ideal (1/x*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x + """ + if self.is_zero(): + return "Zero ideal of %s" % (self._ring,) + + return "Ideal %s of %s" % (self._repr_short(), self.ring()) + + def _latex_(self): + """ + Return the LaTeX representation of the ideal. + + We use Stichtenoth's notation for the ideal: the generators + followed by a symbol for the ring, either O or Oinf. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: latex(I) + (y)\mathcal{O} + """ + gens_str = ', '.join(g._latex_() for g in self.gens_reduced()) + + # maybe we should have a better way to test this... like an + # order method called 'is_infinite'? + + from .order import FunctionFieldOrderInfinite + if isinstance(self.ring(), FunctionFieldOrderInfinite): + return "({})\\mathcal{{O}}_\infty".format(gens_str) + else: + return "({})\\mathcal{{O}}".format(gens_str) + def _div_(self, other): """ Return the ideal divided by the ``other`` ideal. @@ -162,7 +264,10 @@ def gens_reduced(self): r""" Return reduced generators. - This just returns the generators for now. + For now, this method just looks at the generators and sees if any + can be removed without changing the ideal. It prefers principal + representations (a single generator) over all others, and otherwise + picks the generator set with the shortest print representation. This method is provided so that ideals in function fields have the method :meth:`gens_reduced()`, just like ideals of number @@ -176,7 +281,15 @@ def gens_reduced(self): sage: I.gens_reduced() (x,) """ - return self.gens() + gens = self.gens() + if len(gens) == 1: + return gens + candidate_gensets = [] + for genset in powerset(gens): + if self.parent()(genset) == self: + candidate_gensets.append(genset) + candidate_gensets.sort(key=lambda item: (len(item), len(repr(item)), item)) + return candidate_gensets[0] def ring(self): """ @@ -251,7 +364,7 @@ def place(self): sage: Oinf = F.maximal_order_infinite() sage: I = Oinf.ideal(1/x) sage: I.factor() - (Ideal (1/x,1/x^3*y^2) of Maximal infinite order of Function field + (Ideal (1/x^3*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4)^3 sage: J = I.factor()[0][0] sage: J.is_prime() @@ -264,7 +377,7 @@ def place(self): sage: Oinf = L.maximal_order_infinite() sage: I = Oinf.ideal(1/x) sage: I.factor() - (Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y + (Ideal (1/x*y) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x)^2 sage: J = I.factor()[0][0] sage: J.is_prime() @@ -313,9 +426,9 @@ def factor(self): sage: f= 1/x sage: I = Oinf.ideal(f) sage: I.factor() - (Ideal (1/x,1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order + (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1/x^2*y + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2) * - (Ideal (1/x,1/x^2*y + 1) of Maximal infinite order + (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2) """ return Factorization(self._factor(), cr=True) @@ -480,19 +593,6 @@ def __hash__(self): """ return hash( (self._ring, self._gen) ) - def _repr_(self): - """ - Return the string representation of this ideal. - - EXAMPLES:: - - sage: K. = FunctionField(QQ) - sage: O = K.maximal_order() - sage: I = O.ideal(x,1/(x+1)); I - Ideal (1/(x + 1)) of Maximal order of Rational function field in x over Rational Field - """ - return "Ideal (%s) of %s" % (self._gen, self._ring) - def __contains__(self, element): """ Test if ``element`` is in this ideal. @@ -912,20 +1012,6 @@ def module(self): """ return self._module - def __repr__(self): - """ - Return a string representation of this ideal. - - EXAMPLES:: - - sage: K. = FunctionField(QQ); R. = K[] - sage: L. = K.extension(y^2 - x^3 - 1) - sage: O = L.equation_order() - sage: O.ideal(x^2 + 1) - Ideal (x^2 + 1, (x^2 + 1)*y) of Order in Function field in y defined by y^2 - x^3 - 1 - """ - return "Ideal (%s) of %s" % (', '.join([repr(g) for g in self.gens()]), self.ring()) - def gens(self): """ Return a set of generators of this ideal. @@ -1063,7 +1149,7 @@ def __invert__(self): sage: I^-1 Ideal (-1, (1/(x^3 + 1))*y) of Order in Function field in y defined by y^2 - x^3 - 1 sage: ~I * I - Ideal (1, y) of Order in Function field in y defined by y^2 - x^3 - 1 + Ideal (1) of Order in Function field in y defined by y^2 - x^3 - 1 """ if len(self.gens()) == 0: raise ZeroDivisionError @@ -1101,7 +1187,7 @@ class FunctionFieldIdeal_global(FunctionFieldIdeal): sage: L. = K.extension(y^2 - x^3*y - x) sage: O = L.maximal_order() sage: O.ideal(y) - Ideal (x, y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x """ def __init__(self, ring, hnf, denominator=1): """ @@ -1147,7 +1233,7 @@ def __bool__(self): sage: L. = K.extension(y^2 - x^3*y - x) sage: O = L.maximal_order() sage: I = O.ideal(y); I - Ideal (x, y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x sage: I.is_zero() False sage: J = 0*I; J @@ -1159,7 +1245,7 @@ def __bool__(self): sage: L.=K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() sage: I = O.ideal(y); I - Ideal (x^2 + 1, y) of Maximal order of Function field in y + Ideal (y) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x sage: I.is_zero() False @@ -1203,7 +1289,7 @@ def __contains__(self, x): sage: L. = K.extension(Y^2 - x^3 - 1) sage: O = L.maximal_order() sage: I = O.ideal([y]); I - Ideal (x^3 + 1, y) of Maximal order of Function field in y + Ideal (y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 sage: x * y in I True @@ -1216,7 +1302,7 @@ def __contains__(self, x): sage: L. = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() sage: I = O.ideal([y]); I - Ideal (x^2 + 1, y) of Maximal order of Function field in y + Ideal (y) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x sage: x * y in I True @@ -1244,9 +1330,9 @@ def __invert__(self): sage: O = L.maximal_order() sage: I = O.ideal(y) sage: ~I - Ideal (1, (1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 sage: I^(-1) - Ideal (1, (1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 sage: ~I * I Ideal (1) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 @@ -1255,10 +1341,10 @@ def __invert__(self): sage: O = L.maximal_order() sage: I = O.ideal(y) sage: ~I - Ideal (x, (x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x sage: I^(-1) - Ideal (x, (x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x sage: ~I * I Ideal (1) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x @@ -1305,30 +1391,6 @@ def _richcmp_(self, other, op): """ return richcmp((self._denominator, self._hnf), (other._denominator, other._hnf), op) - def _repr_(self): - """ - Return string representation. - - EXAMPLES:: - - sage: K. = FunctionField(GF(2)); _. = K[] - sage: L. = K.extension(Y^2 - x^3*Y - x) - sage: O = L.maximal_order() - sage: I = O.ideal(y); I - Ideal (x, y) of Maximal order of Function field in y defined by y^2 + x^3*y + x - - sage: L. = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y); I - Ideal (x^2 + 1, y) of Maximal order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - """ - if self.is_zero(): - return "Zero ideal of %s" % (self._ring,) - - s = ', '.join([repr(g) for g in self.gens_two()]) - return "Ideal (%s) of %s" % (s, self._ring) - def _add_(self, other): """ Add with other ideal. @@ -1341,7 +1403,7 @@ def _add_(self, other): sage: I = O.ideal(y) sage: J = O.ideal(x+y) sage: I + J - Ideal (x, y) of Maximal order of Function field in y defined by y^2 + x^3*y + x + Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x sage: L. = K.extension(Y^2 + Y + x + 1/x) sage: O = L.maximal_order() @@ -1368,7 +1430,7 @@ def _mul_(self, other): sage: I = O.ideal(y) sage: J = O.ideal(x+y) sage: I * J - Ideal (x^4 + x^2 + x, x*y + x^4 + x) of Maximal order + Ideal (x^4 + x^2 + x, x*y + x^2) of Maximal order of Function field in y defined by y^2 + x^3*y + x sage: L. = K.extension(Y^2 + Y + x + 1/x) @@ -1376,7 +1438,7 @@ def _mul_(self, other): sage: I = O.ideal(y) sage: J = O.ideal(x+y) sage: I * J - Ideal ((x^4 + x^3 + x + 1)/x, (x + 1)*y + (x^2 + 1)/x) of Maximal order + Ideal ((x + 1)*y + (x^2 + 1)/x) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x """ O = self._ring @@ -1609,7 +1671,27 @@ def gens_two(self): """ Return two generators of this fractional ideal. - If the ideal is principal, one generator may be returned. + If the ideal is principal, one generator *may* be returned. + + ALGORITHM: + + At most two generators are required to generate ideals in + Dedekind domains. + + Lemma 4.7.9, algorithm 4.7.10, and exercise 4.29 of [Coh1993]_ + tell us that for an integral ideal `I` in a number field, if + we pick `a` such that `\gcd(N(I), N(a)/N(I)) = 1`, then `a` + and `N(I)` generate the ideal. `N()` is the norm, and this + result (presumably) generalizes to function fields. + + After computing `N(I)`, we search exhaustively to find `a`. + + .. TODO:: + + Always return a single generator for a principal ideal. + + Testing for principality is not trivial. Algorithm 6.5.10 + of [Coh1993]_ could probably be adapted for function fields. EXAMPLES:: @@ -1618,10 +1700,10 @@ def gens_two(self): sage: O = F.maximal_order() sage: I = O.ideal(y) sage: I # indirect doctest - Ideal (x^3 + x^2 + x, y) of Maximal order of Function field + Ideal (y) of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2 sage: ~I # indirect doctest - Ideal (1, (1/(x^6 + x^4 + x^2))*y^2) of Maximal order of Function field + Ideal ((1/(x^6 + x^4 + x^2))*y^2) of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2 sage: K. = FunctionField(GF(2)); _. = K[] @@ -1629,10 +1711,10 @@ def gens_two(self): sage: O = L.maximal_order() sage: I = O.ideal(y) sage: I # indirect doctest - Ideal (x^2 + 1, y) of Maximal order of Function field in y + Ideal (y) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x sage: ~I # indirect doctest - Ideal (x, (x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order + Ideal ((x/(x^2 + 1))*y + x/(x^2 + 1)) of Maximal order of Function field in y defined by y^2 + y + (x^2 + 1)/x """ d = self.denominator() @@ -2111,21 +2193,6 @@ def _richcmp_(self, other, op): """ return richcmp(self._gen, other._gen, op) - def _repr_(self): - """ - Return the string representation of this ideal. - - EXAMPLES:: - - sage: K. = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal(x/(x^2+1)) - sage: I - Ideal (1/x) of Maximal infinite order of Rational function field - in x over Finite Field of size 2 - """ - return "Ideal (%s) of %s" % (self._gen, self._ring) - def _add_(self, other): """ Add this ideal with the other ideal. @@ -2363,7 +2430,7 @@ def __contains__(self, x): sage: L. = K.extension(y^2 - x^3 - 1) sage: O = L.equation_order() sage: I = O.ideal_with_gens_over_base([1, y]); I - Ideal (1, y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 sage: y in I True sage: y/x in I @@ -2415,60 +2482,6 @@ def __eq__(self, other): else: return False - def _repr_short(self): - """ - Represent the list of generators. - - EXAMPLES:: - - sage: P. = QQ[] - sage: P*[a^2,a*b+c,c^3] - Ideal (a^2, a*b + c, c^3) of Multivariate Polynomial Ring in a, b, c over Rational Field - sage: (P*[a^2,a*b+c,c^3])._repr_short() - '(a^2, a*b + c, c^3)' - - If the string representation of a generator contains a line break, - the generators are not represented from left to right but from - top to bottom. This is the case, e.g., for matrices:: - - sage: MS = MatrixSpace(QQ,2,2) - sage: MS*[MS.1,2] - Left Ideal - ( - [0 1] - [0 0], - - [2 0] - [0 2] - ) - of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - - - """ - L = [] - has_return = False - for x in self.gens(): - s = repr(x) - if '\n' in s: - has_return = True - s = s.replace('\n','\n ') - L.append(s) - if has_return: - return '\n(\n %s\n)\n'%(',\n\n '.join(L)) - return '(%s)'%(', '.join(L)) - - def _repr_(self): - """ - Return a string representation of this ideal. - - EXAMPLES:: - - sage: P. = QQ[] - sage: P*[a^2,a*b+c,c^3] # indirect doctest - Ideal (a^2, a*b + c, c^3) of Multivariate Polynomial Ring in a, b, c over Rational Field - """ - return "Ideal %s of %s" % (self._repr_short(), self.ring()) - def module(self): """ Return the module over the maximal order of the base field that @@ -2515,7 +2528,7 @@ class FunctionFieldIdealInfinite_global(FunctionFieldIdealInfinite): sage: F. = K.extension(t^3+t^2-x^4) sage: Oinf = F.maximal_order_infinite() sage: Oinf.ideal(1/y) - Ideal (1/x^2,1/x^4*y^2) of Maximal infinite order of Function field + Ideal (1/x^4*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 """ def __init__(self, ring, ideal): @@ -2553,44 +2566,6 @@ def __hash__(self): """ return hash((self.ring(), self._ideal)) - def _repr_(self): - """ - Return the string representation of this ideal. - - EXAMPLES:: - - sage: K. = FunctionField(GF(3^2)); _. = PolynomialRing(K) - sage: F. = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: Oinf.ideal(1/y) - Ideal (1/x^2,1/x^4*y^2) of Maximal infinite order of Function field - in y defined by y^3 + y^2 + 2*x^4 - - sage: K. = FunctionField(GF(2)); _. = K[] - sage: L. = K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: Oinf.ideal(1/y) - Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x - """ - return self._repr_short() + " of {}".format(self.ring()) - - def _repr_short(self): - """ - Return the short string representation of this ideal. - - EXAMPLES:: - - sage: K. = FunctionField(GF(3^2)); R. = K[] - sage: F. = K.extension(t^3 + t^2 - x^4) - sage: Oinf = F.maximal_order_infinite() - sage: I = Oinf.ideal(1/y) - sage: I._repr_short() - 'Ideal (1/x^2,1/x^4*y^2)' - """ - gens_str = ','.join([repr(g) for g in self.gens_two()]) - return "Ideal ({})".format(gens_str) - def _add_(self, other): """ Add this ideal with the ``other`` ideal. @@ -2637,7 +2612,7 @@ def _mul_(self, other): sage: I = Oinf.ideal(1/x^2*1/y) sage: J = Oinf.ideal(1/x) sage: I * J - Ideal (1/x^5,1/x^7*y^2) of Maximal infinite order of Function field + Ideal (1/x^7*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 sage: K. = FunctionField(GF(2)); _. = K[] @@ -2646,7 +2621,7 @@ def _mul_(self, other): sage: I = Oinf.ideal(1/x^2*1/y) sage: J = Oinf.ideal(1/x) sage: I * J - Ideal (1/x^4,1/x^4*y) of Maximal infinite order of Function field in y + Ideal (1/x^4*y) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x """ return FunctionFieldIdealInfinite_global(self._ring, self._ideal * other._ideal) @@ -2678,7 +2653,7 @@ def __invert__(self): sage: Oinf = F.maximal_order_infinite() sage: J = Oinf.ideal(y) sage: ~J - Ideal (1/x^2,1/x^4*y^2) of Maximal infinite order + Ideal (1/x^4*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 sage: J * ~J Ideal (1) of Maximal infinite order of Function field @@ -2689,7 +2664,7 @@ def __invert__(self): sage: Oinf = L.maximal_order_infinite() sage: J = Oinf.ideal(y) sage: ~J - Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y + Ideal (1/x*y) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x sage: J * ~J Ideal (1) of Maximal infinite order of Function field in y @@ -2844,7 +2819,7 @@ def is_prime(self): sage: Oinf = F.maximal_order_infinite() sage: I = Oinf.ideal(1/x) sage: I.factor() - (Ideal (1/x,1/x^3*y^2) of Maximal infinite order of Function field + (Ideal (1/x^3*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4)^3 sage: I.is_prime() False @@ -2857,7 +2832,7 @@ def is_prime(self): sage: Oinf = L.maximal_order_infinite() sage: I = Oinf.ideal(1/x) sage: I.factor() - (Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y + (Ideal (1/x*y) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x)^2 sage: I.is_prime() False @@ -2879,7 +2854,7 @@ def prime_below(self): sage: Oinf = F.maximal_order_infinite() sage: I = Oinf.ideal(1/x) sage: I.factor() - (Ideal (1/x,1/x^3*y^2) of Maximal infinite order of Function field + (Ideal (1/x^3*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4)^3 sage: J = I.factor()[0][0] sage: J.is_prime() @@ -2893,7 +2868,7 @@ def prime_below(self): sage: Oinf = L.maximal_order_infinite() sage: I = Oinf.ideal(1/x) sage: I.factor() - (Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y + (Ideal (1/x*y) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x)^2 sage: J = I.factor()[0][0] sage: J.is_prime() @@ -2943,9 +2918,9 @@ def _factor(self): sage: f= 1/x sage: I = Oinf.ideal(f) sage: I._factor() - [(Ideal (1/x,1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order of Function field in y + [(Ideal (1/x, 1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1), - (Ideal (1/x,1/x^2*y + 1) of Maximal infinite order of Function field in y + (Ideal (1/x, 1/x^2*y + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1)] """ if self._ideal.is_prime.is_in_cache() and self._ideal.is_prime(): diff --git a/src/sage/rings/function_field/order.py b/src/sage/rings/function_field/order.py index a6fb4ca2e87..2d582091461 100644 --- a/src/sage/rings/function_field/order.py +++ b/src/sage/rings/function_field/order.py @@ -53,7 +53,7 @@ sage: O.decomposition(p) [(Ideal (x + 1, y + 1) of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), - (Ideal (x + 1, y^2 + y + 1) of Maximal order + (Ideal (x + 1, (1/(x^3 + x^2 + x))*y^2 + y + 1) of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] sage: p1,relative_degree,ramification_index = O.decomposition(p)[1] @@ -364,7 +364,7 @@ def ideal_with_gens_over_base(self, gens): sage: O = L.equation_order(); O Order in Function field in y defined by y^2 + 6*x^3 + 6 sage: I = O.ideal_with_gens_over_base([1, y]); I - Ideal (1, y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 sage: I.module() Free module of degree 2 and rank 2 over Maximal order of Rational function field in x over Finite Field of size 7 Echelon basis matrix: @@ -421,7 +421,7 @@ def ideal(self, *gens): sage: S.ideal(1/y) Ideal (1, (6/(x^3 + 1))*y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 sage: I2 = S.ideal(x^2-4); I2 - Ideal (x^2 + 3, (x^2 + 3)*y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + Ideal (x^2 + 3) of Order in Function field in y defined by y^2 + 6*x^3 + 6 sage: I2 == S.ideal(I) True """ @@ -666,7 +666,7 @@ def ideal_with_gens_over_base(self, gens): sage: O = L.equation_order(); O Order in Function field in y defined by y^2 + 6*x^3 + 6 sage: I = O.ideal_with_gens_over_base([1, y]); I - Ideal (1, y) of Order in Function field in y defined by y^2 + 6*x^3 + 6 + Ideal (1) of Order in Function field in y defined by y^2 + 6*x^3 + 6 sage: I.module() Free module of degree 2 and rank 2 over Maximal order of Rational function field in x over Finite Field of size 7 Echelon basis matrix: @@ -1313,7 +1313,7 @@ def _ideal_from_vectors(self, vecs): sage: v2 (0, 1) sage: O._ideal_from_vectors([v1,v2]) - Ideal (x^3 + 1, y) of Maximal order of Function field in y + Ideal (y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 """ d = lcm([v.denominator() for v in vecs]) @@ -1405,7 +1405,7 @@ def ideal(self, *gens, **kwargs): sage: L. = K.extension(y^2 - x^3 - 1) sage: S = L.maximal_order() sage: S.ideal(1/y) - Ideal (1, (1/(x^3 + 1))*y) of Maximal order of Function field + Ideal ((1/(x^3 + 1))*y) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 sage: I2 = S.ideal(x^2-4); I2 Ideal (x^2 + 3) of Maximal order of Function field in y defined by y^2 + 6*x^3 + 6 @@ -1561,7 +1561,7 @@ def different(self): sage: L. = K.extension(y^4 + x*y + 4*x + 1) sage: O = L.maximal_order() sage: O.different() - Ideal (x^4 + 4*x^3 + 3*x^2 + 6*x + 4, y + 2*x^3 + x^2 + 6*x + 1) + Ideal (y^3 + 2*x) of Maximal order of Function field in y defined by y^4 + x*y + 4*x + 1 """ return ~self.codifferent() @@ -1692,7 +1692,7 @@ def decomposition(self, ideal): sage: O.decomposition(p) [(Ideal (x + 1, y + 1) of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), - (Ideal (x + 1, y^2 + y + 1) of Maximal order + (Ideal (x + 1, (1/(x^3 + x^2 + x))*y^2 + y + 1) of Maximal order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] """ F = self.function_field() @@ -2249,7 +2249,7 @@ def ideal(self, *gens): sage: F. = K.extension(t^3 - x^2*(x^2 + x + 1)^2) sage: Oinf = F.maximal_order_infinite() sage: I = Oinf.ideal(x,y); I - Ideal (x^2) of Maximal infinite order of Function field + Ideal (y) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2 sage: K. = FunctionField(GF(2)); _. = K[] @@ -2279,7 +2279,7 @@ def ideal_with_gens_over_base(self, gens): sage: F. = K.extension(t^3 - x^2*(x^2 + x + 1)^2) sage: Oinf = F.maximal_order_infinite() sage: Oinf.ideal_with_gens_over_base((x^2, y, (1/(x^2 + x + 1))*y^2)) - Ideal (x^2) of Maximal infinite order of Function field in y + Ideal (y) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2 """ F = self.function_field() @@ -2367,16 +2367,16 @@ def decomposition(self): sage: F. = K.extension(t^3 - x^2*(x^2 + x + 1)^2) sage: Oinf = F.maximal_order_infinite() sage: Oinf.decomposition() - [(Ideal (1/x,1/x^2*y + 1) of Maximal infinite order + [(Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 1, 1), - (Ideal (1/x,1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order + (Ideal ((1/(x^4 + x^3 + x^2))*y^2 + 1/x^2*y + 1) of Maximal infinite order of Function field in y defined by y^3 + x^6 + x^4 + x^2, 2, 1)] sage: K. = FunctionField(GF(2)); _. = K[] sage: L. = K.extension(Y^2 + Y + x + 1/x) sage: Oinf = L.maximal_order_infinite() sage: Oinf.decomposition() - [(Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y + [(Ideal (1/x*y) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x, 1, 2)] """ F = self.function_field() diff --git a/src/sage/rings/function_field/place.py b/src/sage/rings/function_field/place.py index 962184e8bb8..45c6ca86780 100644 --- a/src/sage/rings/function_field/place.py +++ b/src/sage/rings/function_field/place.py @@ -269,7 +269,7 @@ def prime_ideal(self): sage: L.=K.extension(Y^3+x+x^3*Y) sage: p = L.places()[0] sage: p.prime_ideal() - Ideal (1/x,1/x^3*y^2 + 1/x) of Maximal infinite order of Function field + Ideal (1/x^3*y^2 + 1/x) of Maximal infinite order of Function field in y defined by y^3 + x^3*y + x """ return self._prime diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 20fd8d6026b..af358d5b860 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -132,7 +132,7 @@ from sage.structure.element import is_Element from sage.structure.sequence import Sequence - +from sage.structure.factorization import Factorization from sage.structure.category_object import normalize_names import sage.structure.parent_gens import sage.structure.coerce_exceptions @@ -9457,6 +9457,41 @@ def elements_of_bounded_height(self, **kwds): prec = kwds.pop('precision', 53) return bdd_height(self, B, tolerance=tol, precision=prec) + def _factor_univariate_polynomial(self, poly, **kwargs): + """ + Factorisation of univariate polynomials over absolute number fields. + + This is called by the ``factor`` method of univariate polynomials. + + EXAMPLES:: + + sage: K. = NumberField(x**2+1) + sage: x = polygen(K,'x') + sage: factor(x*x+4) # indirect doctest + (x - 2*i) * (x + 2*i) + """ + if self.degree() == 1: + factors = poly.change_ring(QQ).factor() + return Factorization([(p.change_ring(self), e) + for p, e in factors], self(factors.unit())) + + # Convert the polynomial we want to factor to PARI + f = poly._pari_with_name() + try: + # Try to compute the PARI nf structure with important=False. + # This will raise RuntimeError if the computation is too + # difficult. + Rpari = self.pari_nf(important=False) + except RuntimeError: + # Cannot easily compute the nf structure, use the defining + # polynomial instead. + Rpari = self.pari_polynomial("y") + G = list(Rpari.nffactor(f)) + # PARI's nffactor() ignores the unit, _factor_pari_helper() + # adds back the unit of the factorization. + return poly._factor_pari_helper(G) + + class NumberField_cyclotomic(NumberField_absolute): """ Create a cyclotomic extension of the rational field. diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index dd20acf2e8a..2ffd4b62300 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -87,7 +87,7 @@ from sage.misc.latex import latex from sage.misc.cachefunc import cached_method - +from sage.structure.factorization import Factorization import sage.rings.polynomial.polynomial_element as polynomial_element from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -2371,6 +2371,28 @@ def is_free(self, proof=None): return True return False + def _factor_univariate_polynomial(self, poly, **kwargs): + """ + Factorisation of univariate polynomials over relative number fields. + + This is called by the ``factor`` method of univariate polynomials. + + EXAMPLES:: + + sage: K. = NumberField(x**2+1) + sage: L. = K.extension(x*x-2) + sage: x = polygen(L,'x') + sage: factor(x**2+8) # indirect doctest + (x + 2*i*sqrt2) * (x - 2*i*sqrt2) + """ + M = self.absolute_field('a') + from_M, to_M = M.structure() + g = M['x']([to_M(x) for x in poly.list()]) + F = g.factor() + S = poly.parent() + v = [(S([from_M(x) for x in f.list()]), e) for f, e in F] + return Factorization(v, from_M(F.unit())) + def lift_to_base(self, element): """ Lift an element of this extension into the base field if possible, diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 325c27c12c7..00b7acb4fde 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -992,7 +992,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): x^-40 - 4*x^-29 + 6*x^-18 - 4*x^-7 + x^4 """ cdef LaurentPolynomial_univariate self = _self - cdef long right = long(r) + cdef long right = r if right != r: raise ValueError("exponent must be an integer") return self._parent.element_class(self._parent, self.__u**right, self.__n*right) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index d976eb8db69..2ea6444536b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2987,6 +2987,37 @@ def std(self): return self.ring().ideal( self.__call_singular('std'), side=self.side()) # return self.__call_singular('std') + def elimination_ideal(self, variables): + r""" + Return the elimination ideal of this ideal with respect to the + variables given in "variables". + + EXAMPLES:: + + sage: A. = FreeAlgebra(QQ, 3) + sage: H = A.g_algebra({y*x:x*y-z, z*x:x*z+2*x, z*y:y*z-2*y}) + sage: H.inject_variables() + Defining x, y, z + sage: I = H.ideal([y^2, x^2, z^2-H.one()],coerce=False) + sage: I.elimination_ideal([x, z]) + Left Ideal (y^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {...} + sage: J = I.twostd() + sage: J + Twosided Ideal (z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {...} + sage: J.elimination_ideal([x, z]) + Twosided Ideal (y^2) of Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, nc-relations: {...} + + + ALGORITHM: Uses Singular's eliminate command + """ + from sage.misc.misc_c import prod + if self.side() == 'twosided': + J = self.twostd() + else: + J = self + return J.ring().ideal(J.__call_singular('eliminate', prod(variables)), side=self.side()) +# return self.__call_singular('std') + @cached_method def twostd(self): r""" diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index e6cad378c6c..989bb54991c 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -2221,6 +2221,39 @@ cdef class NCPolynomial_plural(RingElement): p = pNext(p) return pd + def _im_gens_(self, codomain, im_gens): + """ + Return the image of ``self`` in codomain under the map that sends + the images of the generators of the parent of ``self`` to the + tuple of elements of im_gens. + + INPUT: + + - ``codomain`` -- The parent where the images live + + - ``im_gens`` -- A list or tuple with the images of the generators of this ring. + + EXAMPLES:: + + sage: A. = FreeAlgebra(GF(389), 3) + sage: R = A.g_algebra(relations={y*x:-x*y + z}, order='lex') + sage: R.inject_variables() + Defining x, z, y + sage: B. = FreeAlgebra(GF(389), 3) + sage: S = B.g_algebra({b*a:2*a*b, c*a:-2*a*c}) + sage: S.inject_variables() + Defining a, b, c + sage: (x*y - x^2*z)._im_gens_(S, [a*b, b, a*b*c]) + -2*a^2*b^3 + 2*a^2*b^2*c + sage: -(a*b)*(a*b)*b+(a*b)*(a*b*c) + -2*a^2*b^3 + 2*a^2*b^2*c + """ + if self.is_zero(): + return codomain.zero() + from sage.misc.misc_c import prod + d = self.dict() + return sum(prod(im_gens[i]**val for i, val in enumerate(t))*codomain(d[t]) for t in d) + cdef long _hash_c(self): """ @@ -3063,9 +3096,9 @@ def ExteriorAlgebra(base_ring, names,order='degrevlex'): cdef poly *addwithcarry(poly *tempvector, poly *maxvector, int pos, ring *_ring): if p_GetExp(tempvector, pos, _ring) < p_GetExp(maxvector, pos, _ring): - p_SetExp(tempvector, pos, p_GetExp(tempvector, pos, _ring)+1, _ring) + p_SetExp(tempvector, pos, p_GetExp(tempvector, pos, _ring)+1, _ring) else: - p_SetExp(tempvector, pos, 0, _ring) - tempvector = addwithcarry(tempvector, maxvector, pos + 1, _ring) + p_SetExp(tempvector, pos, 0, _ring) + tempvector = addwithcarry(tempvector, maxvector, pos + 1, _ring) p_Setm(tempvector, _ring) return tempvector diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index bd458a41a28..e2db857d266 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -4262,8 +4262,6 @@ cdef class Polynomial(CommutativeAlgebraElement): if not (ch == 0 or is_prime(ch)): raise NotImplementedError("factorization of polynomials over rings with composite characteristic is not implemented") - from sage.rings.number_field.number_field_base import is_NumberField - from sage.rings.number_field.number_field_rel import is_RelativeNumberField from sage.rings.number_field.all import NumberField from sage.rings.finite_rings.finite_field_constructor import is_FiniteField @@ -4275,42 +4273,11 @@ cdef class Polynomial(CommutativeAlgebraElement): except PariError: raise NotImplementedError - elif is_RelativeNumberField(R): - - M = R.absolute_field('a') - from_M, to_M = M.structure() - g = M['x']([to_M(x) for x in self.list()]) - F = g.factor() - S = self._parent - v = [(S([from_M(x) for x in f.list()]), e) for f, e in F] - return Factorization(v, from_M(F.unit())) - elif is_FiniteField(R): v = [x.__pari__("a") for x in self.list()] f = pari(v).Polrev() G = list(f.factor()) - elif is_NumberField(R): - if R.degree() == 1: - factors = self.change_ring(QQ).factor() - return Factorization([(self._parent(p), e) for p, e in factors], R(factors.unit())) - - # Convert the polynomial we want to factor to PARI - f = self._pari_with_name() - try: - # Try to compute the PARI nf structure with important=False. - # This will raise RuntimeError if the computation is too - # difficult. - Rpari = R.pari_nf(important=False) - except RuntimeError: - # Cannot easily compute the nf structure, use the defining - # polynomial instead. - Rpari = R.pari_polynomial("y") - G = list(Rpari.nffactor(f)) - # PARI's nffactor() ignores the unit, _factor_pari_helper() - # adds back the unit of the factorization. - return self._factor_pari_helper(G) - if G is None: # See if we can do this as a singular polynomial as a fallback # This was copied from the general multivariate implementation diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 94c907e4913..95d2c3afcff 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -449,7 +449,7 @@ def arithmetic_genus(self): r""" Return the arithmetic genus of this projective curve. - This is the arithmetic genus `g_a(C)` as defined in [Hartshorne]_. If `P` is the + This is the arithmetic genus `g_a(C)` as defined in [Har1977]_. If `P` is the Hilbert polynomial of the defining ideal of this curve, then the arithmetic genus of this curve is `1 - P(0)`. This curve must be irreducible. @@ -545,7 +545,7 @@ def arithmetic_genus(self): r""" Return the arithmetic genus of this projective curve. - This is the arithmetic genus `g_a(C)` as defined in [Hartshorne]_. For a projective + This is the arithmetic genus `g_a(C)` as defined in [Har1977]_. For a projective plane curve of degree `d`, this is simply `(d-1)(d-2)/2`. It need *not* equal the geometric genus (the genus of the normalization of the curve). This curve must be irreducible. @@ -568,10 +568,6 @@ def arithmetic_genus(self): sage: C = Curve([y^3*x - x^2*y*z - 7*z^4]) sage: C.arithmetic_genus() 3 - - REFERENCES: - - .. [Hartshorne] \R. Hartshorne. Algebraic Geometry. Springer-Verlag, New York, 1977. """ if not self.is_irreducible(): raise TypeError("this curve must be irreducible") @@ -1053,7 +1049,7 @@ def excellent_position(self, Q): r""" Return a transformation of this curve into one in excellent position with respect to the point ``Q``. - Here excellent position is defined as in [Fulton89]_. A curve `C` of degree `d` containing the point + Here excellent position is defined as in [Ful1989]_. A curve `C` of degree `d` containing the point `(0 : 0 : 1)` with multiplicity `r` is said to be in excellent position if none of the coordinate lines are tangent to `C` at any of the fundamental points `(1 : 0 : 0)`, `(0 : 1 : 0)`, and `(0 : 0 : 1)`, and if the two coordinate lines containing `(0 : 0 : 1)` intersect `C` transversally in `d - r` distinct @@ -1128,11 +1124,6 @@ def excellent_position(self, Q): (-2.828427124746190?)*x^3 + (-2)*x^2*y + 2*y^3 + (-2)*x^2*z + 2*y^2*z Defn: Defined on coordinates by sending (x : y : z) to (1/2*x + 1/2*y : (-1/2)*x + 1/2*y : 1/2*x + (-1/2)*y + z) - - REFERENCES: - - .. [Fulton89] \W. Fulton. Algebraic curves: an introduction to algebraic geometry. Addison-Wesley, - Redwood City CA (1989). """ PP = self.ambient_space() # check that Q is on this curve diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index abc1278e4a5..a1d867367f0 100644 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -273,33 +273,16 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, REFERENCES: - .. [Cha] \B. Cha. Vanishing of some cohomology goups and bounds for the - Shafarevich-Tate groups of elliptic curves. J. Number Theory, 111:154- - 178, 2005. - .. [Jetchev] \D. Jetchev. Global divisibility of Heegner points and - Tamagawa numbers. Compos. Math. 144 (2008), no. 4, 811--826. - .. [Kato] \K. Kato. p-adic Hodge theory and values of zeta functions of - modular forms. Astérisque, (295):ix, 117-290, 2004. - .. [Kolyvagin] \V. A. Kolyvagin. On the structure of Shafarevich-Tate - groups. Algebraic geometry, 94--121, Lecture Notes in Math., 1479, - Springer, Berlin, 1991. - .. [LawsonWuthrich] \T. Lawson and C. Wuthrich, Vanishing of some Galois - cohomology groups for elliptic curves, :arxiv:`1505.02940` - .. [LumStein] \A. Lum, W. Stein. Verification of the Birch and - Swinnerton-Dyer Conjecture for Elliptic Curves with Complex - Multiplication (unpublished) - .. [Mazur] \B. Mazur. Modular curves and the Eisenstein ideal. Inst. - Hautes Études Sci. Publ. Math. No. 47 (1977), 33--186 (1978). - .. [Rubin] \K. Rubin. The "main conjectures" of Iwasawa theory for - imaginary quadratic fields. Invent. Math. 103 (1991), no. 1, 25--68. - .. [SteinWuthrich] \W. Stein and C. Wuthrich, Algorithms - for the Arithmetic of Elliptic Curves using Iwasawa Theory - Mathematics of Computation 82 (2013), 1757-1792. - .. [SteinEtAl] \G. Grigorov, A. Jorza, S. Patrikis, W. Stein, - C. Tarniţǎ. Computational verification of the Birch and - Swinnerton-Dyer conjecture for individual elliptic curves. - Math. Comp. 78 (2009), no. 268, 2397--2425. - + - [Cha2005]_ + - [Jet2008]_ + - [Kat2004]_ + - [Kol1991]_ + - [LW2015]_ + - [LS] + - [Maz1978]_ + - [Rub1991]_ + - [SW2013]_ + - [GJPST2009]_ EXAMPLES:: @@ -676,7 +659,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, for p in BSD.primes: # the lemma about the vanishing of H^1 is false in Stein et al for p=5 and 11 # here is the correction from Lawson-Wuthrich. Especially Theorem 14 in - # [LawsonWuthrich] above. + # [LW2015] above. if p in kolyvagin_primes or p == 2 or D_K % p == 0: continue crit_lw = False diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index a122572ac0c..4102504064f 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -399,13 +399,7 @@ def compute_codomain_kohel(E, kernel, degree): .. NOTE:: - This function uses the formulas of Section 2.4 of [K96]_. - - REFERENCES: - - .. [K96] Kohel, "Endomorphism Rings of Elliptic Curves over Finite - Fields", UC Berkeley PhD thesis 1996. - + This function uses the formulas of Section 2.4 of [Koh1996]_. """ # First set up the polynomial ring @@ -3669,19 +3663,13 @@ def compute_isogeny_starks(E1, E2, ell): ALGORITHM: This function uses Starks Algorithm as presented in section 6.2 of - [BMSS]_. + [BMSS2006]_. .. NOTE:: - As published in [BMSS]_, the algorithm is incorrect, and a + As published in [BMSS2006]_, the algorithm is incorrect, and a correct version (with slightly different notation) can be found - in [M09]_. The algorithm originates in [S72]_. - - REFERENCES: - - .. [BMSS] Boston, Morain, Salvy, Schost, "Fast Algorithms for Isogenies." - .. [M09] Moody, "The Diffie-Hellman Problem and Generalization of Verheul's Theorem" - .. [S72] Stark, "Class-numbers of complex quadratic fields." + in [Mo2009]_. The algorithm originates in [Sta1973]_. EXAMPLES:: @@ -3717,7 +3705,7 @@ def compute_isogeny_starks(E1, E2, ell): R = PolynomialRing(K, 'x') x = R.gen() - wp1 = E1.weierstrass_p(prec=4*ell+4) #BMSS claim 2*ell is enough, but it is not M09 + wp1 = E1.weierstrass_p(prec=4*ell+4) #BMSS2006 claim 2*ell is enough, but it is not M09 wp2 = E2.weierstrass_p(prec=4*ell+4) # viewed them as power series in Z = z^2 diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index ef76e083ebb..ccbe66889e4 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -1512,7 +1512,7 @@ def division_polynomial_0(self, n, x=None): Returns the `n^{th}` torsion (division) polynomial, without the 2-torsion factor if `n` is even, as a polynomial in `x`. - These are the polynomials `g_n` defined in [MazurTate1991]_, but with + These are the polynomials `g_n` defined in [MT1991]_, but with the sign flipped for even `n`, so that the leading coefficient is always positive. @@ -1532,7 +1532,7 @@ def division_polynomial_0(self, n, x=None): - ``n`` - positive integer, or the special values ``-1`` and ``-2`` which mean `B_6 = (2y + a_1 x + a_3)^2` and `B_6^2` respectively (in - the notation of [MazurTate1991]_); or a list of integers. + the notation of [MT1991]_); or a list of integers. - ``x`` - a ring element to use as the "x" variable or ``None`` (default: ``None``). If ``None``, then a new polynomial ring will @@ -1544,7 +1544,7 @@ def division_polynomial_0(self, n, x=None): ALGORITHM: - Recursion described in [MazurTate1991]_. The recursive + Recursion described in [MT1991]_. The recursive formulae are evaluated `O(\log^2 n)` times. AUTHORS: @@ -1553,11 +1553,6 @@ def division_polynomial_0(self, n, x=None): - John Cremona (2008-08-26): unified division polynomial code - REFERENCES: - - .. [MazurTate1991] Mazur, B., & Tate, J. (1991). The `p`-adic sigma - function. Duke Mathematical Journal, 62(3), 663-688. - EXAMPLES:: sage: E = EllipticCurve("37a") @@ -1869,13 +1864,7 @@ def _multiple_x_numerator(self, n, x=None): denominator (:meth:`_multiple_x_denominator`). Be careful. E.g. if a point on an elliptic curve with coefficients in `\ZZ` reduces to a singular point modulo a prime, then there will be cancellation, - otherwise not, see [Wuthrich2004]_. - - REFERENCES: - - .. [Wuthrich2004] Wuthrich, C. (2004). On p-adic heights in families of - elliptic curves. Journal of the London Mathematical Society, 70(1), - 23-40. + otherwise not, see [Wu2004]_. .. SEEALSO:: diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py index 37364ef6bf8..29f959c1211 100644 --- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py +++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py @@ -56,16 +56,11 @@ REFERENCES: -.. [MaTaTe] B. Mazur, J. Tate, and J. Teitelbaum, - On `p`-adic analogues of the conjectures of Birch and - Swinnerton-Dyer, Inventiones mathematicae 84, (1986), 1-48. +- [MTT1986]_ -.. [Crem97] John Cremona, Algorithms for modular elliptic curves, - Cambridge University Press, 1997. +- [Cre1997]_ -.. [StWu] William Stein and Christian Wuthrich, Algorithms for the - Arithmetic of Elliptic Curves using Iwasawa Theory, Mathematics - of Computation 82 (2013), 1757-1792. +- [SW2013]_ AUTHORS: @@ -159,8 +154,8 @@ class ModularSymbol(SageObject): `\QQ\to \QQ` obtained by sending `r` to the normalized symmetrized (or anti-symmetrized) integral `\infty` to `r`. - This is as defined in [MaTaTe]_, but normalized to depend on the curve - and not only its isogeny class as in [StWu]_. + This is as defined in [MTT1986]_, but normalized to depend on the curve + and not only its isogeny class as in [SW2013]_. See the documentation of ``E.modular_symbol()`` in elliptic curves over the rational numbers for help. diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index ed4ae464ad4..1931e4ae1e4 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -3353,7 +3353,7 @@ def reducible_primes(self, algorithm='Billerey', max_l=None, [2, 3] sage: E.reducible_primes() [2, 3] - sage: E = EllipticCurve_from_j(K(2268945/128)).global_minimal_model() # c.f. [Sutherland12] + sage: E = EllipticCurve_from_j(K(2268945/128)).global_minimal_model() # c.f. [Sut2012] sage: rho = E.galois_representation() sage: rho.isogeny_bound() # ... but there is no 7-isogeny ... [7] diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 47dba1f8c53..bc5ca5df699 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -1477,7 +1477,7 @@ def _miller_(self, Q, n): ALGORITHM: - Double-and-add. See also [Mil04]_. + Double-and-add. See also [Mil2004]_. AUTHORS: @@ -1579,17 +1579,12 @@ def weil_pairing(self, Q, n): ALGORITHM: - Implemented using Proposition 8 in [Mil04]_. The value 1 is + Implemented using Proposition 8 in [Mil2004]_. The value 1 is returned for linearly dependent input points. This condition is caught via a DivisionByZeroError, since the use of a discrete logarithm test for linear dependence, is much too slow for large `n`. - REFERENCES: - - .. [Mil04] Victor S. Miller, "The Weil pairing, and its - efficient calculation", J. Cryptol., 17(4):235-261, 2004 - AUTHOR: - David Hansen (2009-01-25) @@ -1880,7 +1875,7 @@ def ate_pairing(self, Q, n, k, t, q=None): True Using the same data, we show that the ate pairing is a power of the - Tate pairing (see [HSV]_ end of section 3.1):: + Tate pairing (see [HSV2006]_ end of section 3.1):: sage: c = (k*p^(k-1)).mod(n); T = t - 1 sage: N = gcd(T^k - 1, p^k - 1) @@ -1951,17 +1946,12 @@ def ate_pairing(self, Q, n, k, t, q=None): NOTES: - First defined in the paper of [HSV]_, the ate pairing can be + First defined in the paper of [HSV2006]_, the ate pairing can be computationally effective in those cases when the trace of the curve over the base field is significantly smaller than the expected value. This implementation is simply Miller's algorithm followed by a naive exponentiation, and makes no claims towards efficiency. - REFERENCES: - - .. [HSV] Hess, Smart, Vercauteren, "The Eta Pairing Revisited", - IEEE Trans. Information Theory, 52(10): 4595-4602, 2006. - AUTHORS: - Mariah Lenox (2011-03-08) @@ -2451,23 +2441,10 @@ def height(self, precision=None, normalised=True, algorithm='pari'): There are two normalisations used in the literature, one of which is double the other. We use the larger of the two, which is the one appropriate for the BSD conjecture. This is - consistent with [Cre]_ and double that of [SilBook]_. + consistent with [Cre1997]_ and double that of [Sil2009]_. See :wikipedia:`Néron-Tate height` - REFERENCES: - - .. [Cre] John Cremona, Algorithms for Modular Elliptic Curves. - Cambridge University Press, 1997. - - .. [Sil1988] Joseph H. Silverman, Computing heights on - elliptic curves. Mathematics of Computation, Vol. 51, - No. 183 (Jul., 1988), pp. 339-358. - - .. [SilBook] Joseph H. Silverman, The Arithmetic of Elliptic - Curves. Second edition. Graduate Texts in Mathematics, 106. - Springer, 2009. - EXAMPLES:: sage: E = EllipticCurve('11a'); E diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 053eb9b774e..15577068fd9 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -1553,7 +1553,7 @@ def analytic_rank_upper_bound(self, by ``max_Delta``. This computation can be run on curves with very large conductor (so long as the conductor is known or quickly computable) when `\Delta` is not too large (see below). - Uses Bober's rank bounding method as described in [Bob13]_. + Uses Bober's rank bounding method as described in [Bob2013]_. INPUT: @@ -1733,12 +1733,6 @@ def analytic_rank_upper_bound(self, sage: E.analytic_rank_upper_bound(max_Delta=2.37,adaptive=False, # long time ....: N=N,root_number=1,bad_primes=bad_primes,ncpus=2) # long time 32 - - REFERENCES: - - .. [Bob13] \J.W. Bober. Conditionally bounding analytic ranks of elliptic curves. - ANTS 10. http://msp.org/obs/2013/1-1/obs-v1-n1-p07-s.pdf - """ Z = LFunctionZeroSum_EllipticCurve(self, N) bound = Z.analytic_rank_upper_bound(max_Delta=max_Delta, @@ -2664,7 +2658,7 @@ def CPS_height_bound(self): IMPLEMENTATION: Call the corresponding mwrank C++ library function. Note that - the formula in the [CPS]_ paper is given for number fields. It is + the formula in the [CPS2006]_ paper is given for number fields. It is only the implementation in Sage that restricts to the rational field. """ @@ -3360,7 +3354,7 @@ def lseries_gross_zagier(self, A): on the class group of `K`, one gets `L_K(E,\chi,s) = \sum_{A} \chi(A) L(E,A,s)` where `A` runs through the class group of `K`. - For the exact definition see section IV of [GrossZagier]_. + For the exact definition see section IV of [GZ1986]_. EXAMPLES:: @@ -3381,11 +3375,6 @@ def lseries_gross_zagier(self, A): 0.502803417587467 sage: E.lseries()(2) * E.quadratic_twist(-40).lseries()(2) 0.502803417587467 - - REFERENCES: - - .. [GrossZagier] \B. Gross and D. Zagier, *Heegner points and - derivatives of L-series.* Invent. Math. 84 (1986), no. 2, 225-320. """ try: return self.__lseries_gross_zagier[A] @@ -6188,7 +6177,7 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, sage: [len(e.S_integral_points([2], both_signs=False)) for e in cremona_curves([11..100])] # long time (17s on sage.math, 2011) [2, 0, 2, 3, 3, 1, 3, 1, 3, 5, 3, 5, 4, 1, 1, 2, 2, 2, 3, 1, 2, 1, 0, 1, 3, 3, 1, 1, 5, 3, 4, 2, 1, 1, 5, 3, 2, 2, 1, 1, 1, 0, 1, 3, 0, 1, 0, 1, 1, 3, 7, 1, 3, 3, 3, 1, 1, 2, 3, 1, 2, 3, 1, 2, 1, 3, 3, 1, 1, 1, 0, 1, 3, 3, 1, 1, 7, 1, 0, 1, 1, 0, 1, 2, 0, 3, 1, 2, 1, 3, 1, 2, 2, 4, 5, 3, 2, 1, 1, 6, 1, 0, 1, 3, 1, 3, 3, 1, 1, 1, 1, 1, 3, 1, 5, 1, 2, 4, 1, 1, 1, 1, 1, 0, 1, 0, 2, 2, 0, 0, 1, 0, 1, 1, 6, 1, 0, 1, 1, 0, 4, 3, 1, 2, 1, 2, 3, 1, 1, 1, 1, 8, 3, 1, 2, 1, 2, 0, 8, 2, 0, 6, 2, 3, 1, 1, 1, 3, 1, 3, 2, 1, 3, 1, 2, 1, 6, 9, 3, 3, 1, 1, 2, 3, 1, 1, 5, 5, 1, 1, 0, 1, 1, 2, 3, 1, 1, 2, 3, 1, 3, 1, 1, 1, 1, 0, 0, 1, 3, 3, 1, 3, 1, 1, 2, 2, 0, 0, 6, 1, 0, 1, 1, 1, 1, 3, 1, 2, 6, 3, 1, 2, 2, 1, 1, 1, 1, 7, 5, 4, 3, 3, 1, 1, 1, 1, 1, 1, 8, 5, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 2, 3, 6, 1, 1, 7, 3, 3, 4, 5, 9, 6, 1, 0, 7, 1, 1, 3, 1, 1, 2, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 7, 8, 2, 3, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1] - An example from [PZGH]_:: + An example from [PZGH1999]_:: sage: E = EllipticCurve([0,0,0,-172,505]) sage: E.rank(), len(E.S_integral_points([3,5,7])) # long time (5s on sage.math, 2011) @@ -6209,12 +6198,6 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, (7323 : 623052 : 1), (17687 : 2343476 : 1)] - REFERENCES: - - .. [PZGH] Petho A., Zimmer H.G., Gebel J. and Herrmann E., - Computing all S-integral points on elliptic curves - Math. Proc. Camb. Phil. Soc. (1999), 127, 383-402 - - Some parts of this implementation are partially based on the function integral_points() diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 21060ba369c..74b4b3b9b4f 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -366,19 +366,12 @@ def L_invariant(self, prec=20): One instance where this constant appears is in the exceptional case of the `p`-adic Birch and Swinnerton-Dyer conjecture as - formulated in [MTT]_. See [Col]_ for a detailed discussion. + formulated in [MTT1986]_. See [Col2004]_ for a detailed discussion. INPUT: - ``prec`` - the `p`-adic precision, default is 20. - REFERENCES: - - [MTT]_ - - .. [Col] Pierre Colmez, Invariant `\mathcal{L}` et dérivées de - valeurs propres de Frobenius, Astérisque 331 (2010), 13-28. - EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) @@ -619,8 +612,8 @@ def _height(P, check=True): def padic_regulator(self, prec=20): r""" - Compute the canonical `p`-adic regulator on the extended Mordell-Weil group as in [MTT]_ - (with the correction of [Wer]_ and sign convention in [SW]_.) + Compute the canonical `p`-adic regulator on the extended Mordell-Weil group as in [MTT1986]_ + (with the correction of [Wer1998]_ and sign convention in [SW2013]_.) The `p`-adic Birch and Swinnerton-Dyer conjecture predicts that this value appears in the formula for the leading term of @@ -630,15 +623,6 @@ def padic_regulator(self, prec=20): - ``prec`` -- the `p`-adic precision, default is 20. - REFERENCES: - - [MTT]_ - - .. [Wer] Annette Werner, Local heights on abelian varieties and - rigid analytic uniformization, Doc. Math. 3 (1998), 301-319. - - [SW]_ - EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) diff --git a/src/sage/schemes/elliptic_curves/ell_wp.py b/src/sage/schemes/elliptic_curves/ell_wp.py index aa3961ec00a..c9473758a02 100644 --- a/src/sage/schemes/elliptic_curves/ell_wp.py +++ b/src/sage/schemes/elliptic_curves/ell_wp.py @@ -27,7 +27,7 @@ REFERENCES: -- [BMSS] Boston, Morain, Salvy, Schost, "Fast Algorithms for Isogenies." +- [BMSS2006]_ AUTHORS: @@ -209,10 +209,7 @@ def compute_wp_quadratic(k, A, B, prec): A Laurent series aproximating the Weierstrass `\wp`-function to precision ``prec``. ALGORITHM: - This function uses the algorithm described in section 3.2 of [BMSS]. - - REFERENCES: - [BMSS] Boston, Morain, Salvy, Schost, "Fast Algorithms for Isogenies." + This function uses the algorithm described in section 3.2 of [BMSS2006]_. EXAMPLES:: @@ -251,7 +248,7 @@ def compute_wp_quadratic(k, A, B, prec): def compute_wp_fast(k, A, B, m): r""" - Computes the Weierstrass function of an elliptic curve defined by short Weierstrass model: `y^2 = x^3 + Ax + B`. It does this with as fast as polynomial of degree `m` can be multiplied together in the base ring, i.e. `O(M(n))` in the notation of [BMSS]. + Computes the Weierstrass function of an elliptic curve defined by short Weierstrass model: `y^2 = x^3 + Ax + B`. It does this with as fast as polynomial of degree `m` can be multiplied together in the base ring, i.e. `O(M(n))` in the notation of [BMSS2006]_. Let `p` be the characteristic of the underlying field: Then we must have either `p=0`, or `p > m + 3`. @@ -269,7 +266,7 @@ def compute_wp_fast(k, A, B, m): ALGORITHM: This function uses the algorithm described in section 3.3 of - [BMSS]. + [BMSS2006]_. EXAMPLES:: diff --git a/src/sage/schemes/elliptic_curves/formal_group.py b/src/sage/schemes/elliptic_curves/formal_group.py index 5029a1b2419..dfaa1eafc4b 100644 --- a/src/sage/schemes/elliptic_curves/formal_group.py +++ b/src/sage/schemes/elliptic_curves/formal_group.py @@ -112,7 +112,7 @@ def w(self, prec=20): to precision `O(t^{prec})` of Proposition IV.1.1 of - [SilBook]_. This is the formal expansion of + [Sil2009]_. This is the formal expansion of `w = -1/y` about the formal parameter `t = -x/y` at `\infty`. The result is cached, and a cached version is returned if @@ -252,7 +252,7 @@ def x(self, prec=20): x(t) = t^{-2} - a_1 t^{-1} - a_2 - a_3 t - \cdots - to precision `O(t^{prec})` of page 113 of [SilBook]_. + to precision `O(t^{prec})` of page 113 of [Sil2009]_. .. warning:: @@ -290,7 +290,7 @@ def y(self, prec=20): y(t) = - t^{-3} + a_1 t^{-2} + a_2 t + a_3 + \cdots - to precision `O(t^{prec})` of page 113 of [SilBook]_. + to precision `O(t^{prec})` of page 113 of [Sil2009]_. The result is cached, and a cached version is returned if possible. @@ -342,7 +342,7 @@ def differential(self, prec=20): f(t) = 1 + a_1 t + ({a_1}^2 + a_2) t^2 + \cdots - to precision `O(t^{prec})` of page 113 of [SilBook]_. + to precision `O(t^{prec})` of page 113 of [Sil2009]_. The result is cached, and a cached version is returned if possible. @@ -427,7 +427,7 @@ def inverse(self, prec=20): i(t) = - t + a_1 t^2 + \cdots - to precision `O(t^{prec})` of page 114 of [SilBook]_. + to precision `O(t^{prec})` of page 114 of [Sil2009]_. The result is cached, and a cached version is returned if possible. @@ -484,7 +484,7 @@ def group_law(self, prec=10): F(t_1, t_2) = t_1 + t_2 - a_1 t_1 t_2 - \cdots - to precision `O(t1,t2)^{prec}` of page 115 of [SilBook]_. + to precision `O(t1,t2)^{prec}` of page 115 of [Sil2009]_. The result is cached, and a cached version is returned if possible. @@ -600,7 +600,7 @@ def mult_by_n(self, n, prec=10): [n](t) = n t + \cdots - to precision `O(t^{prec})` of Proposition 2.3 of [SilBook]_. + to precision `O(t^{prec})` of Proposition 2.3 of [Sil2009]_. .. warning:: diff --git a/src/sage/schemes/elliptic_curves/gal_reps.py b/src/sage/schemes/elliptic_curves/gal_reps.py index af9c9540ac1..ea34e537cc1 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps.py +++ b/src/sage/schemes/elliptic_curves/gal_reps.py @@ -90,19 +90,9 @@ REFERENCES: -.. [Se1] Jean-Pierre Serre, - Propriétés galoisiennes des points d'ordre fini - des courbes elliptiques. - Invent. Math. 15 (1972), no. 4, 259--331. -.. [Se2] Jean-Pierre Serre, - Sur les représentations modulaires de degré - 2 de `\text{Gal}(\bar\QQ/\QQ)`. - Duke Math. J. 54 (1987), no. 1, 179--230. -.. [Co] Alina Carmen Cojocaru, - On the surjectivity of the Galois representations - associated to non-CM elliptic curves. - With an appendix by Ernst Kani. - Canad. Math. Bull. 48 (2005), no. 1, 16--31. +- [Ser1972]_ +- [Ser1987]_ +- [Coj2005]_ AUTHORS: diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index 7450d9d05b9..5d001f135d3 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -14,7 +14,7 @@ sage: rho = E.galois_representation() sage: rho.is_surjective(29) # Cyclotomic character not surjective. False - sage: rho.is_surjective(31) # See Section 5.10 of [Serre72]. + sage: rho.is_surjective(31) # See Section 5.10 of [Ser1972]. True sage: rho.non_surjective() # long time (4s on sage.math, 2014) [3, 5, 29] @@ -32,12 +32,8 @@ REFERENCES: -.. [Serre72] Jean-Pierre Serre. *Propriétés galoisiennes des points d'ordre - fini des courbes elliptiques*. Inventiones mathematicae, 1972. - -.. [Sutherland12] Sutherland. A local-global principle for rational - isogenies of prime degree. Journal de Théorie des Nombres de Bordeaux, - 2012. +- [Ser1972]_ +- [Sut2012]_ """ # **************************************************************************** @@ -183,7 +179,7 @@ def non_surjective(self, A=100): sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() - sage: rho.non_surjective() # See Section 5.10 of [Serre72]. + sage: rho.non_surjective() # See Section 5.10 of [Ser1972]. [3, 5, 29] sage: K = NumberField(x**2 + 3, 'a'); a = K.gen() sage: E = EllipticCurve([0, -1, 1, -10, -20]).change_ring(K) # X_0(11) @@ -236,7 +232,7 @@ def is_surjective(self, p, A=100): sage: rho = E.galois_representation() sage: rho.is_surjective(29) # Cyclotomic character not surjective. False - sage: rho.is_surjective(7) # See Section 5.10 of [Serre72]. + sage: rho.is_surjective(7) # See Section 5.10 of [Ser1972]. True If `E` is defined over `\QQ`, then the exceptional primes for `E_{/K}` @@ -299,14 +295,14 @@ def isogeny_bound(self, A=100): sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() - sage: rho.isogeny_bound() # See Section 5.10 of [Serre72]. + sage: rho.isogeny_bound() # See Section 5.10 of [Ser1972]. [3, 5] sage: K = NumberField(x**2 + 1, 'a') sage: EllipticCurve_from_j(K(1728)).galois_representation().isogeny_bound() # CM over K [0] sage: EllipticCurve_from_j(K(0)).galois_representation().isogeny_bound() # CM NOT over K [2, 3] - sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sutherland12] + sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sut2012] sage: E.galois_representation().isogeny_bound() # No 7-isogeny, but... [7] @@ -376,7 +372,7 @@ def reducible_primes(self): sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) sage: rho = E.galois_representation() - sage: rho.isogeny_bound() # See Section 5.10 of [Serre72]. + sage: rho.isogeny_bound() # See Section 5.10 of [Ser1972]. [3, 5] sage: rho.reducible_primes() [3, 5] @@ -386,7 +382,7 @@ def reducible_primes(self): [0] sage: EllipticCurve_from_j(K(0)).galois_representation().reducible_primes() # CM but NOT over K [2, 3] - sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sutherland12] + sage: E = EllipticCurve_from_j(K(2268945/128)) # c.f. [Sut2012] sage: rho = E.galois_representation() sage: rho.isogeny_bound() # ... but there is no 7-isogeny ... [7] @@ -432,7 +428,7 @@ def _non_surjective(E, patience=100): sage: K = NumberField(x**2 - 29, 'a'); a = K.gen() sage: E = EllipticCurve([1, 0, ((5 + a)/2)**2, 0, 0]) - sage: sage.schemes.elliptic_curves.gal_reps_number_field._non_surjective(E) # See Section 5.10 of [Serre72]. + sage: sage.schemes.elliptic_curves.gal_reps_number_field._non_surjective(E) # See Section 5.10 of [Ser1972]. [3, 5, 29] sage: E = EllipticCurve_from_j(1728).change_ring(K) # CM sage: sage.schemes.elliptic_curves.gal_reps_number_field._non_surjective(E) @@ -510,7 +506,7 @@ def Frobenius_filter(E, L, patience=100): Example to show that the output may contain primes where the representation is in fact reducible. Over `\QQ` the following is - essentially the unique such example by [Sutherland12]_:: + essentially the unique such example by [Sut2012]_:: sage: E = EllipticCurve_from_j(2268945/128) sage: sage.schemes.elliptic_curves.gal_reps_number_field.Frobenius_filter(E, [7, 11]) @@ -542,7 +538,7 @@ def Frobenius_filter(E, L, patience=100): L.sort() include_2 = False - if 2 in L: # c.f. Section 5.3(a) of [Serre72]. + if 2 in L: # c.f. Section 5.3(a) of [Ser1972]. L.remove(2) include_2 = not E.division_polynomial(2).is_irreducible() @@ -582,7 +578,7 @@ def _exceptionals(E, L, patience=1000): r""" Determine which primes in L are exceptional for E, using Proposition 19 of Section 2.8 of Serre's ``Propriétés Galoisiennes des Points d'Ordre - Fini des Courbes Elliptiques'' [Serre72]_. + Fini des Courbes Elliptiques'' [Ser1972]_. INPUT: @@ -624,13 +620,13 @@ def _exceptionals(E, L, patience=1000): L = list(set(L)) # Remove duplicates from L. for l in L: - if l == 2: # c.f. Section 5.3(a) of [Serre72]. + if l == 2: # c.f. Section 5.3(a) of [Ser1972]. if (E.j_invariant() - 1728).is_square(): output.append(2) elif not E.division_polynomial(2).is_irreducible(): output.append(2) - elif l == 3: # c.f. Section 5.3(b) of [Serre72]. + elif l == 3: # c.f. Section 5.3(b) of [Ser1972]. if K(-3).is_square(): output.append(3) elif not (K['x'].gen()**3 - E.j_invariant()).is_irreducible(): @@ -704,7 +700,7 @@ def _exceptionals(E, L, patience=1000): # be contained Borel subgroup. D[l][0] = False - if det != 0: # c.f. [Serre72], Section 2.8, Prop. 19 + if det != 0: # c.f. [Ser1972], Section 2.8, Prop. 19 u = trace**2 / det if u not in (1, 2, 4) and u**2 - 3 * u + 1 != 0: D[l][2] = False @@ -1503,7 +1499,7 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): An example where a prime is not reducible but passes the test:: - sage: E = EllipticCurve_from_j(K(2268945/128)).global_minimal_model() # c.f. [Sutherland12] + sage: E = EllipticCurve_from_j(K(2268945/128)).global_minimal_model() # c.f. [Sut2012] sage: reducible_primes_Billerey(E) [7] diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 0adb93d758d..db655894589 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -4321,7 +4321,7 @@ def mod(self, p, prec=53): `(p+1) E(\GF{p})`, i.e., it gives a well defined element of the abelian group `E(\GF{p}) / (p+1) E(\GF{p})`. - See [SteinToward]_, Proposition 5.4 for a proof of the above + See [St2011b]_, Proposition 5.4 for a proof of the above well-definedness assertion. EXAMPLES: @@ -4362,10 +4362,6 @@ def mod(self, p, prec=53): ValueError: p must be coprime to conductors and discriminant sage: P.mod(13,70) (3 : 4 : 1) - - REFERENCES: - - .. [SteinToward] Stein, "Toward a Generalization of the Gross-Zagier Conjecture", Int Math Res Notices (2011), :doi:`10.1093/imrn/rnq075` """ # check preconditions p = ZZ(p) @@ -7073,7 +7069,7 @@ def heegner_sha_an(self, D, prec=53): 1.00000000000000 If we remove the hypothesis that `E(K)` has rank 1 in Conjecture - 2.3 in [Gross-Zagier, 1986, page 311], then that conjecture is + 2.3 in [GZ1986]_ page 311, then that conjecture is false, as the following example shows:: sage: E = EllipticCurve('65a') # long time @@ -7097,7 +7093,7 @@ def heegner_sha_an(self, D, prec=53): pass # Use the BSD conjecture over the quadratic imaginary K -- - # see page 311 of [Gross-Zagier, 1986] for the formula. + # see page 311 of [GZ1986]_ for the formula. E = self # notational convenience F = E.quadratic_twist(D).minimal_model() K = rings.QuadraticField(D, 'a') @@ -7139,7 +7135,7 @@ def heegner_sha_an(self, D, prec=53): # accounts for the fact that the height over K is twice the # height over QQ, i.e., for P in E(QQ) we have h_K(P,P) = # 2*h_Q(P,P). See, e.g., equation (6.4) on page 230 of - # [Gross-Zagier, 1986]. + # [GZ1986]_. Reg_prod = 2**(rE + rF) * E.regulator(precision=prec) * F.regulator(precision=prec) # Next we call off to the _heegner_index_in_EK function, which # saturates the group E(QQ) + E^D(QQ) in E(K), given us the index, diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 9bbb1005aee..968b2941025 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -2,30 +2,14 @@ Canonical heights for elliptic curves over number fields Also, rigorous lower bounds for the canonical height of non-torsion -points, implementing the algorithms in [CS]_ (over `\QQ`) and [TT]_, -which also refer to [CPS]_. +points, implementing the algorithms in [CS2006]_ (over `\QQ`) and [Tho2010]_, +which also refer to [CPS2006]_. AUTHORS: - Robert Bradshaw (2010): initial version - John Cremona (2014): added many docstrings and doctests - -REFERENCES: - -.. [CS] \J.E.Cremona, and S. Siksek, Computing a Lower Bound for the - Canonical Height on Elliptic Curves over `\QQ`, ANTS VII - Proceedings: F.Hess, S.Pauli and M.Pohst (eds.), ANTS VII, Lecture - Notes in Computer Science 4076 (2006), pages 275-286. - -.. [TT] \T. Thongjunthug, Computing a lower bound for the canonical - height on elliptic curves over number fields, Math. Comp. 79 - (2010), pages 2431-2449. - -.. [CPS] \J.E. Cremona, M. Prickett and S. Siksek, Height Difference - Bounds For Elliptic Curves over Number Fields, Journal of Number - Theory 116(1) (2006), pages 42-68. - """ ############################################################################## # Copyright (C) 2010 Robert Bradshaw @@ -908,13 +892,13 @@ def alpha(self, v, tol=0.01): OUTPUT: - The constant `\alpha_v`. In the notation of [CPS]_ (2006) and - [TT]_ (section 3.2), `\alpha_v^3=\epsilon_v`. The result is + The constant `\alpha_v`. In the notation of [CPS2006]_ and + [Tho2010]_ (section 3.2), `\alpha_v^3=\epsilon_v`. The result is cached since it only depends on the curve. EXAMPLES: - Example 1 from [CPS]_ (2006):: + Example 1 from [CPS2006]_:: sage: K.=QuadraticField(-1) sage: E = EllipticCurve([0,0,0,1+5*i,3+i]) @@ -923,7 +907,7 @@ def alpha(self, v, tol=0.01): sage: alpha 1.12272013439355 - Compare with `\log(\epsilon_v)=0.344562...` in [CPS]_:: + Compare with `\log(\epsilon_v)=0.344562...` in [CPS2006]_:: sage: 3*alpha.log() 0.347263296676126 @@ -1033,7 +1017,7 @@ def DE(self, n): OUTPUT: - The value `D_E(n)` as defined in [TT]_, section 4. + The value `D_E(n)` as defined in [Tho2010]_, section 4. EXAMPLES:: @@ -1059,7 +1043,7 @@ def ME(self): OUTPUT: - The norm of the ideal `M_E` as defined in [TT]_, section 3.1. + The norm of the ideal `M_E` as defined in [Tho2010]_, section 3.1. This is `1` if `E` is a global minimal model, and in general measures the non-minimality of `E`. @@ -1098,17 +1082,17 @@ def B(self, n, mu): OUTPUT: - The real value `B_n(\mu)` as defined in [TT]_, section 5. + The real value `B_n(\mu)` as defined in [Tho2010]_, section 5. EXAMPLES: - Example 10.2 from [TT]_:: + Example 10.2 from [Tho2010]_:: sage: K.=QuadraticField(-1) sage: E = EllipticCurve([0,1-i,i,-i,0]) sage: H = E.height_function() - In [TT]_ the value is given as 0.772:: + In [Tho2010]_ the value is given as 0.772:: sage: RealField(12)( H.B(5, 0.01) ) 0.777 @@ -1203,7 +1187,7 @@ def S(self, xi1, xi2, v): OUTPUT: - The union of intervals `S^{(v)}(\xi_1,\xi_2)` defined in [TT]_ + The union of intervals `S^{(v)}(\xi_1,\xi_2)` defined in [Tho2010]_ section 6.1. EXAMPLES: @@ -1251,7 +1235,7 @@ def Sn(self, xi1, xi2, n, v): OUTPUT: - The union of intervals `S_n^{(v)}(\xi_1,\xi_2)` defined in [TT]_ + The union of intervals `S_n^{(v)}(\xi_1,\xi_2)` defined in [Tho2010]_ (Lemma 6.1). EXAMPLES: @@ -1299,7 +1283,7 @@ def real_intersection_is_empty(self, Bk, v): empty or not. When ``Bk`` is the list of `b=B_n(\mu)` for `n=1,2,3,\dots` for some `\mu>0` this means that all non-torsion points on `E` with everywhere good reduction have - canonical height strictly greater than `\mu`, by [TT]_, + canonical height strictly greater than `\mu`, by [Tho2010]_, Proposition 6.2. EXAMPLES: @@ -1399,7 +1383,7 @@ def wp_c(self, v): sage: H.wp_c(K.places()[0]) 2.66213425640096 """ - # Note that we normalise w1, w2 differently from [TT]_! + # Note that we normalise w1, w2 differently from [Tho2010]_! w2, w1 = self.E.period_lattice(v).normalised_basis() return max(abs(v(self.E.c4()/240)) ** 0.5, abs(v(self.E.c6()/6048)) ** (1.0/3)) * abs(w1)**2 @@ -1668,11 +1652,11 @@ def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): True or False, according as the intersection of the unions of intervals `T_n^{(v)}(-b,b)` for `b` in the list ``Bk`` (see - [TT]_, section 7) is empty or not. When ``Bk`` is the list of + [Tho2010]_, section 7) is empty or not. When ``Bk`` is the list of `b=\sqrt{B_n(\mu)}` for `n=1,2,3,\dots` for some `\mu>0` this means that all non-torsion points on `E` with everywhere good reduction have canonical height strictly greater than `\mu`, - by [TT]_, Proposition 7.8. + by [Tho2010]_, Proposition 7.8. EXAMPLES:: @@ -1704,7 +1688,7 @@ def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion b2 = v(self.E.b2()) - # Note that we normalise w1, w2 differently from [TT]_! + # Note that we normalise w1, w2 differently from [Tho2010]_! w2, w1 = self.E.period_lattice(v).normalised_basis() tau = w2/w1 bounds = [RDF((B.sqrt() + abs(b2)/12) * abs(w1) ** 2) for B in Bk] @@ -1833,7 +1817,7 @@ def test_mu(self, mu, N, verbose=True): [] """ # Compute the list of values `B_n(\mu)` for n in 1..N. If any - # of these is 1 we can return True right away (see [TT]_, + # of these is 1 we can return True right away (see [Tho2010]_, # Proposition 5.1). Bk = [] for n in ZZ.range(1, N + 1): @@ -1881,14 +1865,14 @@ def min_gr(self, tol, n_max, verbose=False): EXAMPLES: - Example 1 from [CS]_ (where a lower bound of 1.9865 was + Example 1 from [CS2006]_ (where a lower bound of 1.9865 was given):: sage: E = EllipticCurve([1, 0, 1, 421152067, 105484554028056]) # 60490d1 sage: E.height_function().min_gr(.0001, 5) 1.98684388146518 - Example 10.1 from [TT]_ (where a lower bound of 0.18 was + Example 10.1 from [Tho2010]_ (where a lower bound of 0.18 was given):: sage: K. = QuadraticField(-1) @@ -1897,7 +1881,7 @@ def min_gr(self, tol, n_max, verbose=False): sage: H.min_gr(0.1,4) # long time (8.1s) 0.1621049443313762 - Example 10.2 from [TT]_:: + Example 10.2 from [Tho2010]_:: sage: K. = QuadraticField(-1) sage: E = EllipticCurve([0,1-i,i,-i,0]) @@ -1914,7 +1898,7 @@ def min_gr(self, tol, n_max, verbose=False): sage: P.height() 0.0230242154471211 - Example 10.3 from [TT]_ (where the same bound of 0.25 is + Example 10.3 from [Tho2010]_ (where the same bound of 0.25 is given):: sage: K. = NumberField(x^3-2) @@ -2002,14 +1986,14 @@ def min(self, tol, n_max, verbose=False): EXAMPLES: - Example 1 from [CS]_ (where the same lower bound of 0.1126 was + Example 1 from [CS2006]_ (where the same lower bound of 0.1126 was given):: sage: E = EllipticCurve([1, 0, 1, 421152067, 105484554028056]) # 60490d1 sage: E.height_function().min(.0001, 5) 0.0011263287309893311 - Example 10.1 from [TT]_ (where a lower bound of 0.18 was + Example 10.1 from [Tho2010]_ (where a lower bound of 0.18 was given):: sage: K. = QuadraticField(-1) @@ -2018,7 +2002,7 @@ def min(self, tol, n_max, verbose=False): sage: H.min(0.1,4) # long time (8.1s) 0.1621049443313762 - Example 10.2 from [TT]_:: + Example 10.2 from [Tho2010]_:: sage: K. = QuadraticField(-1) sage: E = EllipticCurve([0,1-i,i,-i,0]) @@ -2033,7 +2017,7 @@ def min(self, tol, n_max, verbose=False): sage: P.height() 0.0230242154471211 - Example 10.3 from [TT]_ (where the same bound of 0.0625 is + Example 10.3 from [Tho2010]_ (where the same bound of 0.0625 is given):: sage: K. = NumberField(x^3-2) diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index 7afb821b162..d09a011f394 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -386,7 +386,7 @@ def graph(self): .. note:: There are only finitely many possible isogeny graphs for - curves over `\QQ` [M78]. This function tries to lay out + curves over `\QQ` [Maz1978b]. This function tries to lay out the graph nicely by special casing each isogeny graph. This could also be done over other number fields, such as quadratic fields. @@ -402,11 +402,6 @@ def graph(self): sage: G = isocls.graph() sage: sorted(G._pos.items()) [(1, [-0.8660254, 0.5]), (2, [-0.8660254, 1.5]), (3, [-1.7320508, 0]), (4, [0, 0]), (5, [0, -1]), (6, [0.8660254, 0.5]), (7, [0.8660254, 1.5]), (8, [1.7320508, 0])] - - REFERENCES: - - .. [M78] \B. Mazur. Rational Isogenies of Prime Degree. - *Inventiones mathematicae* 44,129-162 (1978). """ from sage.graphs.graph import Graph diff --git a/src/sage/schemes/elliptic_curves/jacobian.py b/src/sage/schemes/elliptic_curves/jacobian.py index 7ee4cdd2933..75887700bc5 100644 --- a/src/sage/schemes/elliptic_curves/jacobian.py +++ b/src/sage/schemes/elliptic_curves/jacobian.py @@ -40,7 +40,7 @@ REFERENCES: -.. [WpJacobianVariety] :wikipedia:`Jacobian_variety` +- :wikipedia:`Jacobian_variety` """ ############################################################################## diff --git a/src/sage/schemes/elliptic_curves/kraus.py b/src/sage/schemes/elliptic_curves/kraus.py index 80dfd07e7a4..7379c607ca8 100644 --- a/src/sage/schemes/elliptic_curves/kraus.py +++ b/src/sage/schemes/elliptic_curves/kraus.py @@ -21,12 +21,12 @@ return such a model. The implementation of this functionality is based on work of Kraus -[Kraus]_ which gives a local condition for when a pair of number field +[Kra1989]_ which gives a local condition for when a pair of number field elements \(c_4\), \(c_6\) belong to a Weierstrass model which is integral at a prime \(P\), together with a global version. Only primes dividing 2 or 3 are hard to deal with. In order to compute the corresponding integral model one then needs to combine together the -local transformations implicit in [Kraus]_ into a single global one. +local transformations implicit in [Kra1989]_ into a single global one. Various utility functions relating to the testing and use of Kraus's conditions are included here. @@ -34,12 +34,6 @@ AUTHORS: - John Cremona (2015) - -REFERENCES: - -.. [Kraus] Kraus, Alain, Quelques remarques à propos des invariants - \(c_4\), \(c_6\) et \(\Delta\) d'une courbe elliptique, Acta - Arith. 54 (1989), 75-80. """ ############################################################################## diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 7b3a9c9cb7e..a3494c4f3fb 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -23,27 +23,16 @@ If `E` is supersingular, the series will have coefficients in a quadratic extension of `\QQ_p`, and the coefficients will be unbounded. In this case we have only implemented the series for `\eta = 0`. We have also implemented the -`p`-adic L-series as formulated by Perrin-Riou [BP]_, which has coefficients in +`p`-adic L-series as formulated by Perrin-Riou [BP1993]_, which has coefficients in the Dieudonné module `D_pE = H^1_{dR}(E/\QQ_p)` of `E`. There is a different -description by Pollack [Po]_ which is not available here. +description by Pollack [Pol2003]_ which is not available here. According to the `p`-adic version of the Birch and Swinnerton-Dyer conjecture -[MTT]_, the order of vanishing of the `L`-function at the trivial character +[MTT1986]_, the order of vanishing of the `L`-function at the trivial character (i.e. of the series for `\eta = 0` at `T = 0`) is just the rank of `E(\QQ)`, or this rank plus one if the reduction at `p` is split multiplicative. -See [SW]_ for more details. - -REFERENCES: - -- [MTT]_ - -- [BP]_ - -.. [Po] Robert Pollack, *On the `p`-adic `L`-function of a modular form - at a supersingular prime*, Duke Math. J. 118 (2003), no. 3, 523-558. - -- [SW]_ +See [SW2013]_ for more details. AUTHORS: @@ -526,15 +515,15 @@ def order_of_vanishing(self): Return the order of vanishing of this `p`-adic L-series. The output of this function is provably correct, due to a - theorem of Kato [Ka]_. + theorem of Kato [Kat2004]_. .. NOTE:: currently `p` must be a prime of good ordinary reduction. REFERENCES: - - [MTT]_ + - [MTT1986]_ - - [Ka]_ + - [Kat2004]_ EXAMPLES:: @@ -690,7 +679,7 @@ def _quotient_of_periods_to_twist(self, D): For a fundamental discriminant `D` of a quadratic number field this computes the constant `\eta` such that `\sqrt{\vert D\vert }\cdot\Omega_{E_D}^{+} =\eta\cdot \Omega_E^{sign(D)}`. - As in [MTT]_ page 40. This is either 1 or 2 unless the condition + As in [MTT1986]_ page 40. This is either 1 or 2 unless the condition on the twist is not satisfied, e.g. if we are 'twisting back' to a semi-stable curve. @@ -1330,7 +1319,7 @@ def Dp_valued_series(self, n=3, quadratic_twist=+1, prec=5): `\omega` is the invariant differential and `\varphi` is the Frobenius on `D_p(E)`. According to the `p`-adic Birch and Swinnerton-Dyer - conjecture [BP]_ this function has a zero of order + conjecture [BP1993]_ this function has a zero of order rank of `E(\QQ)` and it's leading term is contains the order of the Tate-Shafarevich group, the Tamagawa numbers, the order of the torsion subgroup and the `D_p`-valued `p`-adic regulator. @@ -1627,13 +1616,7 @@ def Dp_valued_regulator(self, prec=20, v1=0, v2=0): .. NOTE:: The definition here is corrected with respect to - Perrin-Riou's article [PR]_. See [SW]_. - - REFERENCES: - - .. [PR] Perrin-Riou, *Arithmétique des courbes elliptiques à - réduction supersingulière en `p`*, - Experiment. Math. 12 (2003), no. 2, 155-186. + Perrin-Riou's article [PR2003]_. See [SW2013]_. EXAMPLES:: diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index afe7a08d08e..a6809286eaf 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -79,10 +79,7 @@ REFERENCES: -.. [CT] \J. E. Cremona and T. Thongjunthug, The Complex AGM, periods of - elliptic curves over `\CC` and complex elliptic logarithms. - Journal of Number Theory Volume 133, Issue 8, August 2013, pages - 2813-2841. +- [CT2013]_ AUTHORS: @@ -1245,7 +1242,7 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): ALGORITHM: - Uses the complex AGM. See [CT]_ for details. + Uses the complex AGM. See [CT2013]_ for details. EXAMPLES:: @@ -1438,7 +1435,7 @@ def elliptic_logarithm(self, P, prec=None, reduce=True): ALGORITHM: - Uses the complex AGM. See [CT]_ for details. + Uses the complex AGM. See [CT2013]_ for details. EXAMPLES:: diff --git a/src/sage/schemes/elliptic_curves/period_lattice_region.pyx b/src/sage/schemes/elliptic_curves/period_lattice_region.pyx index 93555f21bda..72c13bf319c 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice_region.pyx +++ b/src/sage/schemes/elliptic_curves/period_lattice_region.pyx @@ -6,20 +6,13 @@ of the period lattice of an elliptic curve, used in computing minimum height bounds. In particular, these are the approximating sets ``S^{(v)}`` in section 3.2 of -Thotsaphon Thongjunthug's Ph.D. Thesis and paper [TT]_. +Thotsaphon Thongjunthug's Ph.D. Thesis and paper [Tho2010]_. AUTHORS: - Robert Bradshaw (2010): initial version - John Cremona (2014): added some docstrings and doctests - -REFERENCES: - -.. [T] \T. Thongjunthug, Computing a lower bound for the canonical - height on elliptic curves over number fields, Math. Comp. 79 - (2010), pages 2431-2449. - """ #***************************************************************************** diff --git a/src/sage/schemes/elliptic_curves/sha_tate.py b/src/sage/schemes/elliptic_curves/sha_tate.py index 7ccb0c053ff..8898ea234d0 100644 --- a/src/sage/schemes/elliptic_curves/sha_tate.py +++ b/src/sage/schemes/elliptic_curves/sha_tate.py @@ -459,19 +459,7 @@ def an_padic(self, p, prec=0, use_twists=True): Returns the conjectural order of `Sha(E/\QQ)`, according to the `p`-adic analogue of the Birch and Swinnerton-Dyer conjecture as formulated - in [MTT]_ and [BP]_. - - REFERENCES: - - .. [MTT] \B. Mazur, J. Tate, and J. Teitelbaum, On `p`-adic - analogues of the conjectures of Birch and Swinnerton-Dyer, - Inventiones mathematicae 84, (1986), 1-48. - - .. [BP] Dominique Bernardi and Bernadette Perrin-Riou, - Variante `p`-adique de la conjecture de Birch et - Swinnerton-Dyer (le cas supersingulier), - C. R. Acad. Sci. Paris, Sér I. Math., 317 (1993), no. 3, - 227-232. + in [MTT1986]_ and [BP1993]_. INPUT: @@ -725,7 +713,7 @@ def p_primary_order(self, p): Return the order of the `p`-primary part of the Tate-Shafarevich group. - This uses the result of Skinner and Urban [SU]_ on the + This uses the result of Skinner and Urban [SU2014]_ on the main conjecture in Iwasawa theory. In particular the elliptic curve must have good ordinary reduction at `p`, the residual Galois representation must be surjective. Furthermore there must @@ -756,12 +744,6 @@ def p_primary_order(self, p): ... ValueError: The order is not provably known using Skinner-Urban. Try running p_primary_bound to get a bound. - - REFERENCES: - - .. [SU] Christopher Skinner and Eric Urban, - The Iwasawa main conjectures for GL2. - Invent. Math. 195 (2014), no. 1, 1-277. """ E = self.E # does not work if p = 2 @@ -823,8 +805,8 @@ def p_primary_bound(self, p): ALGORITHM: - The algorithm is described in [SW]_. The results for the - reducible case can be found in [Wu]_. The main ingredient is + The algorithm is described in [SW2013]_. The results for the + reducible case can be found in [Wu2004]_. The main ingredient is Kato's result on the main conjecture in Iwasawa theory. EXAMPLES:: @@ -872,17 +854,6 @@ def p_primary_bound(self, p): sage: E = EllipticCurve("5040bi1") sage: E.sha().p_primary_bound(5) # long time 0 - - REFERENCES: - - .. [SW] William Stein and Christian Wuthrich, Algorithms - for the Arithmetic of Elliptic Curves using Iwasawa Theory - Mathematics of Computation 82 (2013), 1757-1792. - - .. [Wu] Christian Wuthrich, On the integrality of modular - symbols and Kato's Euler system for elliptic curves. - Doc. Math. 19 (2014), 381-402. - """ p = Integer(p) if p == 2: @@ -1098,8 +1069,8 @@ def bound_kolyvagin(self, D=0, regulator=None, def bound_kato(self): r""" - Returns a list of primes `p` such that the theorems of Kato's [Ka]_ - and others (e.g., as explained in a thesis of Grigor Grigorov [Gri]_) + Returns a list of primes `p` such that the theorems of Kato's [Kat2004]_ + and others (e.g., as explained in a thesis of Grigor Grigorov [Gri2005]_) imply that if `p` divides the order of `Sha(E/\QQ)` then `p` is in the list. @@ -1130,7 +1101,7 @@ def bound_kato(self): [2] For the following curve one really has that 25 divides the - order of `Sha` (by [GJPST]_):: + order of `Sha` (by [GJPST2009]_):: sage: E = EllipticCurve([1, -1, 0, -332311, -73733731]) # 1058D1 sage: E.sha().bound_kato() # long time (about 1 second) @@ -1149,22 +1120,6 @@ def bound_kato(self): sage: E = EllipticCurve([0, 0, 1, -1, 0]) # 37A (rank 1) sage: E.sha().bound_kato() False - - REFERENCES: - - .. [Ka] Kayuza Kato, `p`-adic Hodge theory and values of zeta - functions of modular forms, Cohomologies `p`-adiques et - applications arithmétiques III, Astérisque vol 295, SMF, - Paris, 2004. - - .. [Gri] \G. Grigorov, Kato's Euler System and the Main Conjecture, - Harvard Ph.D. Thesis (2005). - - .. [GJPST] \G. Grigorov, A. Jorza, S. Patrikis, W. A. Stein, - and C. Tarniţǎ, Computational verification of the Birch and - Swinnerton-Dyer conjecture for individual elliptic curves, - Math. Comp. 78 (2009), 2397-2425. - """ E = self.Emin if E.has_cm(): diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 55c22722d5b..7585b910503 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -1339,20 +1339,12 @@ def Jacobian(self): * the defining polynomials of the algebraic scheme. Note that some authors do not include these in the definition of the Jacobian ideal. An example of a reference that does include - the defining equations is [LazarsfeldJacobian]_. + the defining equations is [Laz2004]_, p. 181. OUTPUT: An ideal in the coordinate ring of the ambient space. - REFERENCES: - - .. [LazarsfeldJacobian] - Robert Lazarsfeld: - Positivity in algebraic geometry II; - Positivity for Vector Bundles, and Multiplier Ideals, - page 181. - EXAMPLES:: sage: P3. = ProjectiveSpace(3, QQ) diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py index f5090be4635..2d1f0afa4da 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py @@ -74,7 +74,7 @@ def kummer_morphism(self): def clebsch_invariants(self): r""" - Return the Clebsch invariants `(A, B, C, D)` of Mestre, p 317, [MJ1991]_. + Return the Clebsch invariants `(A, B, C, D)` of Mestre, p 317, [Mes1991]_. .. SEEALSO:: @@ -182,7 +182,7 @@ def absolute_igusa_invariants_kohel(self): def clebsch_invariants(self): r""" - Return the Clebsch invariants `(A, B, C, D)` of Mestre, p 317, [MJ1991]_. + Return the Clebsch invariants `(A, B, C, D)` of Mestre, p 317, [Mes1991]_. .. SEEALSO:: diff --git a/src/sage/schemes/hyperelliptic_curves/invariants.py b/src/sage/schemes/hyperelliptic_curves/invariants.py index d6812641ad2..5340826ba7a 100644 --- a/src/sage/schemes/hyperelliptic_curves/invariants.py +++ b/src/sage/schemes/hyperelliptic_curves/invariants.py @@ -46,7 +46,7 @@ def differential_operator(f, g, k): r""" Return the differential operator `(f g)_k` symbolically in the polynomial ring in ``dfdx, dfdy, dgdx, dgdy``. - This is defined by Mestre on p 315 [MJ1991]_: + This is defined by Mestre on p 315 [Mes1991]_: .. MATH:: @@ -114,7 +114,7 @@ def Ueberschiebung(f, g, k): r""" Return the differential operator `(f g)_k`. - This is defined by Mestre on page 315 [MJ1991]_: + This is defined by Mestre on page 315 [Mes1991]_: .. MATH:: @@ -140,7 +140,7 @@ def Ueberschiebung(f, g, k): def ubs(f): r""" - Given a sextic form `f`, return a dictionary of the invariants of Mestre, p 317 [MJ1991]_. + Given a sextic form `f`, return a dictionary of the invariants of Mestre, p 317 [Mes1991]_. `f` may be homogeneous in two variables or inhomogeneous in one. @@ -260,7 +260,7 @@ def igusa_to_clebsch(I2, I4, I6, I10): def clebsch_invariants(f): r""" Given a sextic form `f`, return the Clebsch invariants `(A, B, C, D)` of - Mestre, p 317, [MJ1991]_. + Mestre, p 317, [Mes1991]_. `f` may be homogeneous in two variables or inhomogeneous in one. diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py index d90dd56c17a..8ee60d478d1 100644 --- a/src/sage/schemes/hyperelliptic_curves/mestre.py +++ b/src/sage/schemes/hyperelliptic_curves/mestre.py @@ -124,8 +124,8 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, ALGORITHM: - This is Mestre's algorithm [M1991]_. Our implementation is based on the - formulae on page 957 of [LY2001]_, cross-referenced with [W1999]_ to + This is Mestre's algorithm [Mes1991]_. Our implementation is based on the + formulae on page 957 of [LY2001]_, cross-referenced with [Wam1999b]_ to correct typos. First construct Mestre's conic using the :func:`Mestre_conic` function. @@ -139,17 +139,6 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, where `c_{ijk}` are defined as rational functions in the invariants (see the source code for detailed formulae for `c_{ijk}`). The output is the hyperelliptic curve `y^2 = f`. - - REFERENCES: - - .. [LY2001] \K. Lauter and T. Yang, "Computing genus 2 curves from - invariants on the Hilbert moduli space", Journal of Number Theory 131 - (2011), pages 936 - 958 - .. [M1991] \J.-F. Mestre, "Construction de courbes de genre 2 a partir de - leurs modules", in Effective methods in algebraic geometry - (Castiglioncello, 1990), volume 94 of Progr. Math., pages 313 - 334 - .. [W1999] \P. van Wamelen, Pari-GP code, section "thecubic" - https://www.math.lsu.edu/~wamelen/Genus2/FindCurve/igusa2curve.gp """ from sage.structure.sequence import Sequence i = Sequence(i) @@ -263,7 +252,7 @@ def Mestre_conic(i, xyz=False, names='u,v,w'): ALGORITHM: The formulas are taken from pages 956 - 957 of [LY2001]_ and based on pages - 321 and 332 of [M1991]_. + 321 and 332 of [Mes1991]_. See the code or [LY2001]_ for the detailed formulae defining x, y, z and L. diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index ee97899b903..13363c1170a 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -10,13 +10,9 @@ REFERENCES: -.. [Ked2001] Kedlaya, K., *Counting points on hyperelliptic curves using - Monsky-Washnitzer cohomology*, J. Ramanujan Math. Soc. 16 (2001) no - 4, 323-338 +- [Ked2001]_ -.. [Edix] Edixhoven, B., *Point counting after Kedlaya*, EIDMA-Stieltjes - graduate course, Leiden - (notes: https://www.math.leidenuniv.nl/~edix/oww/mathofcrypt/carls_edixhoven/kedlaya.pdf) +- [Edix]_ AUTHORS: diff --git a/src/sage/schemes/plane_conics/con_rational_function_field.py b/src/sage/schemes/plane_conics/con_rational_function_field.py index 57eff4d39ec..a474b5226f6 100644 --- a/src/sage/schemes/plane_conics/con_rational_function_field.py +++ b/src/sage/schemes/plane_conics/con_rational_function_field.py @@ -71,10 +71,8 @@ class ProjectiveConic_rational_function_field(ProjectiveConic_field): REFERENCES: - .. [HC2006] Mark van Hoeij and John Cremona, Solving Conics over - function fields. J. Théor. Nombres Bordeaux, 2006. - .. [ACKERMANS2016] Lennart Ackermans, Oplosbaarheid van Kegelsneden. - http://www.math.leidenuniv.nl/nl/theses/Bachelor/. + - [HC2006]_ + - [Ack2016]_ """ def __init__(self, A, f): r""" @@ -446,7 +444,7 @@ def find_point(self, supports, roots, case, solution = 0): ALGORITHM: The algorithm used is the algorithm FindPoint in [HC2006]_, with - a simplification from [ACKERMANS2016]_. + a simplification from [Ack2016]_. EXAMPLES:: @@ -477,13 +475,13 @@ def find_point(self, supports, roots, case, solution = 0): Ft(self.coefficients()[5])] deg = [coefficients[0].degree(), coefficients[1].degree(), coefficients[2].degree()] - # definitions as in [HC2006] and [ACKERMANS2016] + # definitions as in [HC2006] and [Ack2016] A = ((deg[1] + deg[2]) / 2).ceil() - case B = ((deg[2] + deg[0]) / 2).ceil() - case C = ((deg[0] + deg[1]) / 2).ceil() - case # For all roots as calculated by has_rational_point(), we create - # a system of linear equations. As in [ACKERMANS2016], we do this + # a system of linear equations. As in [Ack2016], we do this # by calculating the matrices for all phi_p, with basis consisting # of monomials of x, y and z in the space V of potential solutions: # t^0, ..., t^A, t^0, ..., t^B and t^0, ..., t^C. diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index b6374ec408b..70ab50bd831 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -1036,15 +1036,10 @@ def Chow_form(self): the ambient projective space of `X`. The elimination ideal `I = J' \cap K[u_{ij}]` is a principal ideal, let `R` be its generator. The Chow form is obtained by writing `R` as a polynomial in Plucker coordinates (i.e. bracket polynomials). - [DalbecSturmfels]_. + [DS1994]_. OUTPUT: a homogeneous polynomial. - REFERENCES: - - .. [DalbecSturmfels] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, - chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. - EXAMPLES:: sage: P. = ProjectiveSpace(GF(17), 3) diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index 1aed9c9e0b6..89e82467b05 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -32,7 +32,7 @@ action. These are in one-to-one correspondence with the cones of the fan and, therefore, the toric Chow group is a quotient of the free Abelian group generated by the cones. In particular, the toric Chow -group has finite rank. One can show [FMSS1]_ that the toric Chow +group has finite rank. One can show [FMSS1995]_ that the toric Chow groups equal the "full" Chow group of a toric variety, so there is no need to distinguish these in the following. @@ -42,20 +42,11 @@ REFERENCES: -.. [wp:ChowRing] - :wikipedia:`Chow_ring` +- :wikipedia:`Chow_ring` -.. [FMSS1] - Fulton, MacPherson, Sottile, Sturmfels: - *Intersection theory on spherical varieties*, - J. of Alg. Geometry 4 (1995), 181-193. - http://www.math.tamu.edu/~frank.sottile/research/ps/spherical.ps.gz - -.. [FultonChow] - Chapter 5.1 "Chow Groups" of Fulton, William: - *Introduction to Toric Varieties*, - Princeton University Press +- [FMSS1995]_ +- [Ful1993]_, Chapter 5.1, "Chow Groups" EXAMPLES:: @@ -357,7 +348,7 @@ def intersection_with_divisor(self, divisor): """ Intersect the Chow cycle with ``divisor``. - See [FultonChow]_ for a description of the toric algorithm. + See Chapter 5.1 of [Ful1993]_ for a description of the toric algorithm. INPUT: @@ -878,7 +869,7 @@ def degree(self, k=None): EXAMPLES: - Four exercises from page 65 of [FultonP65]_. First, an example + Four exercises from page 65 of [Ful1993]_. First, an example with `A_1(X)=\ZZ\oplus\ZZ/3\ZZ`:: sage: X = ToricVariety(Fan(cones=[[0,1],[1,2],[2,0]], @@ -921,7 +912,7 @@ def degree(self, k=None): sage: X.Chow_group().degree(2) # long time (2s on sage.math, 2011) C2 x Z^5 - Finally, Example 1.3 of [FS]_:: + Finally, Example 1.3 of [FS1994]_:: sage: points_mod = lambda k: matrix([[ 1, 1, 2*k+1],[ 1,-1, 1], ....: [-1, 1, 1],[-1,-1, 1],[-1,-1,-1], @@ -1041,7 +1032,7 @@ def relation_gens(self): where `n_{\rho,\sigma}` is a (randomly chosen) lift of the generator of `N_\sigma/N_\rho \simeq \ZZ`. See also Exercise - 12.5.7 of [CLS]_. + 12.5.7 of [CLS2011]_. See also :meth:`relations` to obtain the relations as submodule of the free module generated by the cones. Or use diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 13d7b4b88b9..5ef1081f94b 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -1169,7 +1169,7 @@ def is_ample(self): sage: (-K).is_ample() True - Example 6.1.3, 6.1.11, 6.1.17 of [CLS]_:: + Example 6.1.3, 6.1.11, 6.1.17 of [CLS2011]_:: sage: from itertools import product sage: fan = Fan(cones=[(0,1), (1,2), (2,3), (3,0)], @@ -1247,7 +1247,7 @@ def is_nef(self): sage: (-K).is_nef() True - Example 6.1.3, 6.1.11, 6.1.17 of [CLS]_:: + Example 6.1.3, 6.1.11, 6.1.17 of [CLS2011]_:: sage: from itertools import product sage: fan = Fan(cones=[(0,1), (1,2), (2,3), (3,0)], @@ -1300,7 +1300,7 @@ def polyhedron(self): sage: P_antiK.integral_points() ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0)) - Example 6.1.3, 6.1.11, 6.1.17 of [CLS]_:: + Example 6.1.3, 6.1.11, 6.1.17 of [CLS2011]_:: sage: fan = Fan(cones=[(0,1), (1,2), (2,3), (3,0)], ....: rays=[(-1,2), (0,1), (1,0), (0,-1)]) @@ -1426,7 +1426,7 @@ def sections_monomials(self): sage: P2.divisor(2).sections_monomials() (z, y, x) - From [CoxTutorial]_ page 38:: + From [Cox]_ page 38:: sage: lp = LatticePolytope([(1,0),(1,1),(0,1),(-1,0),(0,-1)]) sage: lp @@ -1439,12 +1439,6 @@ def sections_monomials(self): sage: AK.sections_monomials() (x3*x4^2*x5, x2*x3^2*x4^2, x1*x4*x5^2, x1*x2*x3*x4*x5, x1*x2^2*x3^2*x4, x1^2*x2*x5^2, x1^2*x2^2*x3*x5, x1^2*x2^3*x3^2) - - REFERENCES: - - .. [CoxTutorial] - David Cox, "What is a Toric Variety", - http://www.cs.amherst.edu/~dac/lectures/tutorial.ps """ return tuple(self.monomial(m) for m in self.sections()) @@ -1724,13 +1718,13 @@ def cohomology(self, weight=None, deg=None, dim=False): cohomology. For toric divisors, the local sections can be chosen to be monomials (instead of general homogeneous polynomials), this is the reason for the extra grading by - `m\in M`. General references would be [Fu1993]_, [CLS]_. Here + `m\in M`. General references would be [Ful1993]_, [CLS2011]_. Here are some salient features of our implementation: * First, a finite set of `M`-lattice points is identified that supports the cohomology. The toric divisor determines a (polyhedral) chamber decomposition of `M_\RR`, see Section - 9.1 and Figure 4 of [CLS]_. The cohomology vanishes on the + 9.1 and Figure 4 of [CLS2011]_. The cohomology vanishes on the non-compact chambers. Hence, the convex hull of the vertices of the chamber decomposition contains all non-vanishing cohomology groups. This is returned by the private method @@ -1742,8 +1736,8 @@ def cohomology(self, weight=None, deg=None, dim=False): * For each point `m\in M`, the weight-`m` part of the cohomology can be rewritten as the cohomology of a - simplicial complex, see Exercise 9.1.10 of [CLS]_, - [Perling]_. This is returned by the private method + simplicial complex, see Exercise 9.1.10 of [CLS2011]_, + [Per2007]_. This is returned by the private method :meth:`_sheaf_complex`. The simplicial complex is the same for all points in a @@ -1755,15 +1749,9 @@ def cohomology(self, weight=None, deg=None, dim=False): :meth:`_sheaf_cohomology`. Summing over the supporting points `m\in M` yields the cohomology of the sheaf`. - REFERENCES: - - .. [Perling] - Markus Perling: Divisorial Cohomology Vanishing on Toric Varieties, - :arxiv:`0711.4836v2` - EXAMPLES: - Example 9.1.7 of Cox, Little, Schenck: "Toric Varieties" [CLS]_:: + Example 9.1.7 of Cox, Little, Schenck: "Toric Varieties" [CLS2011]_:: sage: F = Fan(cones=[(0,1), (1,2), (2,3), (3,4), (4,5), (5,0)], ....: rays=[(1,0), (1,1), (0,1), (-1,0), (-1,-1), (0,-1)]) diff --git a/src/sage/schemes/toric/fano_variety.py b/src/sage/schemes/toric/fano_variety.py index 6765f5e7389..6ad4129c2ea 100644 --- a/src/sage/schemes/toric/fano_variety.py +++ b/src/sage/schemes/toric/fano_variety.py @@ -8,7 +8,7 @@ The interface is provided via :func:`CPRFanoToricVariety`. A careful exposition of different flavours of Fano varieties can be found in -the paper by Benjamin Nill [Nill2005]_. The main goal of this module is to +the paper by Benjamin Nill [Nil2005]_. The main goal of this module is to support work with **Gorenstein weak Fano toric varieties**. Such a variety corresponds to a **coherent crepant refinement of the normal fan of a reflexive polytope** `\Delta`, where crepant means that primitive generators @@ -18,7 +18,7 @@ precisely the maximal cones of the subdivision. These varieties are important for string theory in physics, as they serve as ambient spaces for mirror pairs of Calabi-Yau manifolds via constructions due to Victor V. Batyrev -[Batyrev1994]_ and Lev A. Borisov [Borisov1993]_. +[Bat1994]_ and Lev A. Borisov [Bor1993]_. From the combinatorial point of view "crepant" requirement is much more simple and natural to work with than "coherent." For this reason, the code in this @@ -28,30 +28,10 @@ REFERENCES: -.. [Batyrev1994] - Victor V. Batyrev, - "Dual polyhedra and mirror symmetry for Calabi-Yau hypersurfaces in toric - varieties", - J. Algebraic Geom. 3 (1994), no. 3, 493-535. - :arxiv:`alg-geom/9310003v1` - -.. [Borisov1993] - Lev A. Borisov, - "Towards the mirror symmetry for Calabi-Yau complete intersections in - Gorenstein Fano toric varieties", 1993. - :arxiv:`alg-geom/9310001v1` - -.. [CD2007] - Adrian Clingher and Charles F. Doran, - "Modular invariants for lattice polarized K3 surfaces", - Michigan Math. J. 55 (2007), no. 2, 355-393. - :arxiv:`math/0602146v1` [math.AG] - -.. [Nill2005] - Benjamin Nill, - "Gorenstein toric Fano varieties", - Manuscripta Math. 116 (2005), no. 2, 183-210. - :arxiv:`math/0405448v1` [math.AG] +- [Bat1994]_ +- [Bor1993]_ +- [CD2007]_ +- [Nil2005]_ AUTHORS: diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index 7a74c8273eb..4bff92bcb01 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -546,13 +546,7 @@ def cardinality(self): ALGORITHM: - Uses the formula in Fulton [F]_, section 4.5. - - REFERENCES: - - .. [F] - Fulton, W., "Introduction to Toric Varieties", - Princeton University Press, 1993. + Uses the formula in Fulton [Ful1993]_, section 4.5. AUTHORS: diff --git a/src/sage/schemes/toric/ideal.py b/src/sage/schemes/toric/ideal.py index ed7c486cec0..8fc31e72342 100644 --- a/src/sage/schemes/toric/ideal.py +++ b/src/sage/schemes/toric/ideal.py @@ -31,7 +31,7 @@ Here, the "naive" ideal generated by `z_0 z_2 - z_1^2` does already equal the toric ideal. But that is not true in general! For example, -this toric ideal ([ProcSympPureMath62]_, Example 1.2) is the twisted +this toric ideal ([Stu1997]_, Example 1.2) is the twisted cubic and cannot be generated by `2=\dim \ker(A)` polynomials:: sage: A = matrix([[3,2,1,0],[0,1,2,3]]) @@ -46,7 +46,7 @@ Multivariate Polynomial Ring in z0, z1, z2, z3 over Rational Field The following family of toric ideals is from Example 4.4 of -[ProcSympPureMath62]_. One can show that `I_d` is generated by one +[Stu1997]_. One can show that `I_d` is generated by one quadric and `d` binomials of degree `d`:: sage: I = lambda d: ToricIdeal(matrix([[1,1,1,1,1],[0,1,1,0,0],[0,0,1,1,d]])) @@ -69,7 +69,7 @@ z2^3*z3 - z1^3*z4) of Multivariate Polynomial Ring in z0, z1, z2, z3, z4 over Rational Field -Finally, the example in [GRIN]_ :: +Finally, the example in [SH1995b]_ :: sage: A = matrix(ZZ, [ [15, 4, 14, 19, 2, 1, 10, 17], ....: [18, 11, 13, 5, 16, 16, 8, 19], @@ -94,7 +94,7 @@ ....: z0*z2-z1*z3]) # Computed with Maple 12 True -The next example first appeared in Example 12.7 in [GBCP]_. It is also +The next example first appeared in Example 12.7 in [Stu1995]_. It is also used by the Maple 12 help system as example:: sage: A = matrix(ZZ, [[1, 2, 3, 4, 0, 1, 4, 5], @@ -110,30 +110,6 @@ ....: z1*z3-z5*z7, -z3^2*z5+z1^2*z7, z1^3-z3*z5^2]) True - -REFERENCES: - -.. [GRIN] - Bernd Sturmfels, Serkan Hosten: - GRIN: An implementation of Grobner bases for integer programming, - in "Integer Programming and Combinatorial Optimization", - [E. Balas and J. Clausen, eds.], - Proceedings of the IV. IPCO Conference (Copenhagen, May 1995), - Springer Lecture Notes in Computer Science 920 (1995) 267-276. - -.. [ProcSympPureMath62] - Bernd Sturmfels: - Equations defining toric varieties, - Algebraic Geometry - Santa Cruz 1995, - Proc. Sympos. Pure Math., 62, Part 2, - Amer. Math. Soc., Providence, RI, 1997, - pp. 437-449. - -.. [GBCP] - Bernd Sturmfels: - Grobner Bases and Convex Polytopes - AMS University Lecture Series Vol. 8 (01 December 1995) - AUTHORS: - Volker Braun (2011-01-03): Initial version @@ -191,7 +167,7 @@ class ToricIdeal(MPolynomialIdeal): - ``algorithm`` -- string (optional). The algorithm to use. For now, must be ``'HostenSturmfels'`` which is the algorithm - proposed by Hosten and Sturmfels in [GRIN]_. + proposed by Hosten and Sturmfels in [SH1995b]_. EXAMPLES:: @@ -414,7 +390,7 @@ def _ideal_quotient_by_variable(self, ring, ideal, n): ALGORITHM: - Proposition 4 of [GRIN]_. + Proposition 4 of [SH1995b]_. EXAMPLES:: @@ -437,7 +413,7 @@ def _ideal_quotient_by_variable(self, ring, ideal, n): # TODO: Can we use the weighted homogeneity with respect to # the rows of self.A() when computing the Groebner basis, see - # [GRIN]? + # [SH1995b]? basis = J.groebner_basis() # x_n = y[0] # the cheapest variable in the revlex order diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py index 7a95ad340d4..b45da763faa 100644 --- a/src/sage/schemes/toric/library.py +++ b/src/sage/schemes/toric/library.py @@ -892,7 +892,7 @@ def Cube_sublattice(self, names='z+', base_ring=QQ): r""" Construct the toric variety defined by a face fan over a 3-dimensional cube, but not the unit cube in the - N-lattice. See [FultonP65]_. + N-lattice. See p. 65 of [Ful1993]_. Its Chow group is `A_2(X)=\ZZ^5`, which distinguishes it from the face fan of the unit cube. @@ -929,13 +929,6 @@ def Cube_sublattice(self, names='z+', base_ring=QQ): in 3-d lattice N sage: Cube_sublattice.gens() (z0, z1, z2, z3, z4, z5, z6, z7) - - REFERENCES: - - .. [FultonP65] - Page 65, 3rd exercise (Section 3.4) of Wiliam Fulton, - "Introduction to Toric Varieties", Princeton University - Press """ return self._make_CPRFanoToricVariety('Cube_sublattice', names, base_ring) @@ -997,7 +990,7 @@ def Cube_deformation(self,k, names=None, base_ring=QQ): The fans of this sequence of toric varieties all equal the face fan of a unit cube topologically, but the ``(1,1,1)``-vertex is moved to ``(1,1,2k+1)``. This example - was studied in [FS]_. + was studied in [FS1994]_. INPUT: @@ -1035,12 +1028,6 @@ def Cube_deformation(self,k, names=None, base_ring=QQ): in 3-d lattice N sage: X_2.gens() (z0, z1, z2, z3, z4, z5, z6, z7) - - REFERENCES: - - .. [FS] - William Fulton, Bernd Sturmfels, *Intersection Theory on - Toric Varieties*, :arxiv:`alg-geom/9403002` """ # We are going to eventually switch off consistency checks, so we need # to be sure that the input is acceptable. @@ -1061,7 +1048,7 @@ def Cube_deformation(self,k, names=None, base_ring=QQ): def BCdlOG(self, names='v1 v2 c1 c2 v4 v5 b e1 e2 e3 f g v6', base_ring=QQ): r""" Construct the 5-dimensional toric variety studied in - [BCdlOG]_, [HLY2002]_ + [BCdlOG2000]_, [HLY2002]_ INPUT: @@ -1100,16 +1087,6 @@ def BCdlOG(self, names='v1 v2 c1 c2 v4 v5 b e1 e2 e3 f g v6', base_ring=QQ): in 5-d lattice N sage: X.gens() (v1, v2, c1, c2, v4, v5, b, e1, e2, e3, f, g, v6) - - REFERENCES: - - .. [BCdlOG] - Volker Braun, Philip Candelas, Xendia de la Ossa, - Antonella Grassi, *Toric Calabi-Yau Fourfolds, Duality - Between N=1 Theories and Divisors that Contribute to the - Superpotential*, :arxiv:`hep-th/0001208` - - - [HLY2002]_ """ return self._make_CPRFanoToricVariety('BCdlOG', names, base_ring) diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index 5ee5ce4b055..9818f2ada99 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -22,7 +22,7 @@ The toric morphisms are perhaps the most mysterious at the beginning. Let us quickly review their definition (See Definition -3.3.3 of [CLS]_). Let `\Sigma_1` be a fan in `N_{1,\RR}` and `\Sigma_2` be a +3.3.3 of [CLS2011]_). Let `\Sigma_1` be a fan in `N_{1,\RR}` and `\Sigma_2` be a fan in `N_{2,\RR}`. A morphism `\phi: X_{\Sigma_1} \to X_{\Sigma_2}` of the associated toric varieties is toric if `\phi` maps the maximal torus `T_{N_1} \subseteq X_{\Sigma_1}` into `T_{N_2} \subseteq @@ -135,7 +135,7 @@ If we denote the homogeneous coordinates of `O_{\mathbb{P}^1}(2)` by `x`, `t`, `y` corresponding to the rays `(1,2)`, `(1,1)`, and `(1,0)` -then the blow-up map is [BB]_: +then the blow-up map is [BB2013]_: .. MATH:: @@ -346,13 +346,6 @@ None connected components over (1, 2), each with 0 irreducible components. None connected components over (0, 2), each with 0 irreducible components. 1 connected components over (0, 1), each with 2 irreducible components. - -REFERENCES: - -.. [BB] - Gavin Brown, Jaroslaw Buczynski: - *Maps of toric varieties in Cox coordinates*, - :arxiv:`1004.4924` """ #***************************************************************************** diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index bebc01be1a7..8253173ac4b 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -4,7 +4,7 @@ Klyachko bundles are torus-equivariant bundles on toric varieties. That is, the action of the maximal torus on the toric variety lifts to an action on the bundle. There is an equivalence of -categories between [Klyachko]_ bundles and multiple filtrations (one for +categories between Klyachko bundles [Kly1990]_ and multiple filtrations (one for each ray of the fan) of a vector space. The multi-filtrations are implemented in :mod:`sage.modules.multi_filtered_vector_space`. @@ -31,18 +31,9 @@ REFERENCES: -.. [Klyachko] - Klyachko, Aleksandr Anatolevich: - Equivariant Bundles on Toral Varieties, - Math USSR Izv. 35 (1990), 337-375. - http://iopscience.iop.org/0025-5726/35/2/A04/pdf/0025-5726_35_2_A04.pdf - -.. [BirknerIltenPetersen] - Rene Birkner, Nathan Owen Ilten, and Lars Petersen: - Computations with equivariant toric vector bundles, - The Journal of Software for Algebra and Geometry: Macaulay2. - http://msp.org/jsag/2010/2-1/p03.xhtml - http://www.math.uiuc.edu/Macaulay2/doc/Macaulay2-1.8.2/share/doc/Macaulay2/ToricVectorBundles/html/ +- [Kly1990]_ + +- [BIP]_ """ #***************************************************************************** @@ -441,7 +432,7 @@ def E_intersection(self, sigma, m): r""" Return the vector subspace ``E^\sigma(m)``. - See [Klyachko]_, equation 4.1. + See [Kly1990]_, equation 4.1. INPUT: @@ -484,7 +475,7 @@ def E_quotient(self, sigma, m): r""" Return the vector space quotient `E_\sigma(m)`. - See [Klyachko]_, equation 4.1. + See [Kly1990]_, equation 4.1. INPUT: @@ -601,7 +592,7 @@ def cohomology_complex(self, m): r""" Return the "cohomology complex" `C^*(m)` - See [Klyachko]_, equation 4.2. + See [Kly1990]_, equation 4.2. INPUT: diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py index 05a13bbdf83..60c95f9a332 100644 --- a/src/sage/schemes/toric/variety.py +++ b/src/sage/schemes/toric/variety.py @@ -9,7 +9,7 @@ An **excellent reference on toric varieties** is the book "Toric Varieties" by David A. Cox, John B. Little, and Hal Schenck -[CLS]_. +[CLS2011]_. The interface to this module is provided through functions :func:`AffineToricVariety` and :func:`ToricVariety`, although you may @@ -23,13 +23,6 @@ ring). This description works best for simplicial fans of the full dimension. -REFERENCES: - -.. [CLS] - David A. Cox, John B. Little, Hal Schenck, - "Toric Varieties", Graduate Studies in Mathematics, - Amer. Math. Soc., Providence, RI, 2011 - AUTHORS: - Andrey Novoseltsev (2010-05-17): initial version. @@ -2095,7 +2088,7 @@ def volume_class(self): means that the cohomology class `[t] \cap [y]` should be `\frac{1}{2}` times the volume class. Note that this is different from the volume normalization chosen in - [Schubert]_:: + [KS]_:: sage: P1xP1_Z2 = toric_varieties.P1xP1_Z2() sage: Dt = P1xP1_Z2.divisor(1); Dt @@ -2116,12 +2109,6 @@ def volume_class(self): sage: A = P1xP1_Z2.Chow_group(QQ) sage: A(Dt).intersection_with_divisor(Dy).count_points() 1/2 - - REFERENCES: - - .. [Schubert] - Sheldon Katz and Stein Arild Stromme, - A Maple package for intersection theory and enumerative geometry. """ if not self.is_orbifold(): raise NotImplementedError('Cohomology computations are only ' @@ -2751,7 +2738,7 @@ def orbit_closure(self, cone): `V(\sigma)` of the torus orbit `O(\sigma)` in the ambient toric variety `X_\Sigma`, which is again a toric variety. - See Proposition 3.2.7 of [CLS]_ for more details. + See Proposition 3.2.7 of [CLS2011]_ for more details. INPUT: @@ -2837,16 +2824,8 @@ def Demazure_roots(self): REFERENCES: - .. [Demazure] - \M. Demazure - Sous-groupes algébriques de rang maximum du groupe de Cremona. - Ann. Sci. Ecole Norm. Sup. 1970, 3, 507--588. - - .. [Bazhov] - Ivan Bazhov: - On orbits of the automorphism group on a complete toric variety. - :arxiv:`1110.4275`, - :doi:`10.1007/s13366-011-0084-0`. + - [De1970]_ + - [Baz2011]_ EXAMPLES:: @@ -2854,7 +2833,7 @@ def Demazure_roots(self): sage: P2.Demazure_roots() (M(-1, 0), M(-1, 1), M(0, -1), M(0, 1), M(1, -1), M(1, 0)) - Here are the remaining three examples listed in [Bazhov]_, Example 2.1 and 2.3:: + Here are the remaining three examples listed in [Baz2011]_, Example 2.1 and 2.3:: sage: s = 3 sage: cones = [(0,1),(1,2),(2,3),(3,0)] @@ -3246,7 +3225,7 @@ def _element_constructor_(self,x): intersection of the divisors corresponding to the rays is still proportional to the product of the variables, but the coefficient is a multiple depending on the orbifold - singularity. See also [CLS]_, Lemma 12.5.2:: + singularity. See also [CLS2011]_, Lemma 12.5.2:: sage: P2_123 = toric_varieties.P2_123() sage: HH = P2_123.cohomology_ring() diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index eaebb84c9fd..9e913cc1e72 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -4,7 +4,7 @@ There are 16 reflexive polygons in the plane, see :func:`~sage.geometry.lattice_polytope.ReflexivePolytopes`. Each of them defines a toric Fano variety. And each of them has a unique -crepant resolution to a smooth toric surface [CLSsurfaces]_ by +crepant resolution to a smooth toric surface (Section 10.4 in [CLS2011]_) by subdividing the face fan. An anticanonical hypersurface defines an elliptic curve in this ambient space, which we call a toric elliptic curve. The purpose of this module is to write an anticanonical @@ -20,7 +20,7 @@ of the elliptic curve. This is why you will never have to specify the origin (or zero section) in the following. -It turns out [VolkerBraun]_ that the anticanonical hypersurface +It turns out [Bra2011]_ that the anticanonical hypersurface equation of any one of the above 16 toric surfaces is a specialization (that is, set one or more of the coefficients to zero) of the following three cases. In inhomogeneous coordinates, they are @@ -123,28 +123,10 @@ REFERENCES: -.. [VolkerBraun] - Volker Braun: - Toric Elliptic Fibrations and F-Theory Compactifications - :arxiv:`1110.4883` - -.. [Duistermaat] - J. J. Duistermaat, - Discrete integrable systems. QRT maps and elliptic surfaces. - Springer Monographs in Mathematics. Berlin: Springer. xxii, 627 p., 2010 - -.. [ArtinVillegasTate] - Michael Artin, Fernando Rodriguez-Villegas, John Tate, - On the Jacobians of plane cubics, - Advances in Mathematics 198 (2005) 1, pp. 366--382 - :doi:`10.1016/j.aim.2005.06.004` - http://www.math.utexas.edu/users/villegas/publications/jacobian-cubics.pdf - -.. [CLSsurfaces] - Section 10.4 in - David A. Cox, John B. Little, Hal Schenck, - "Toric Varieties", Graduate Studies in Mathematics, - Amer. Math. Soc., Providence, RI, 2011 +- [Bra2011]_ +- [Du2010]_ +- [ARVT2005]_ +- [CLS2011]_ """ ######################################################################## diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index 6397343ec92..d2c6e8f0baa 100644 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -93,11 +93,7 @@ REFERENCES: -.. [AnEtAl] - An, Sang Yook et al: - *Jacobians of Genus One Curves*, - Journal of Number Theory 90 (2002), pp.304--315, - http://www.math.arizona.edu/~wmc/Research/JacobianFinal.pdf +- [AKMMMP2002]_ """ ######################################################################## diff --git a/src/sage/symbolic/comparison.pyx b/src/sage/symbolic/comparison.pyx index 0802768cd1a..a701b76ca53 100644 --- a/src/sage/symbolic/comparison.pyx +++ b/src/sage/symbolic/comparison.pyx @@ -259,6 +259,8 @@ cpdef int mixed_order(lhs, rhs) except -2: sage: mixed_order(SR(oo), sqrt(2)) 1 """ + if lhs is rhs: + return 0 if not is_Expression(lhs): lhs = SR(lhs) if not is_Expression(rhs): diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index c651cb217af..044ea8efc86 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -214,13 +214,13 @@ # version 2 or any later version. The full text of the GPL is available at: # http://www.gnu.org/licenses/ ############################################################################### -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import import math from functools import partial from sage.rings.infinity import (infinity, minus_infinity, unsigned_infinity) +from sage.structure.richcmp import richcmp_method, op_EQ, op_GE, op_LE constants_table = {} constants_name_table = {} @@ -263,6 +263,7 @@ def unpickle_Constant(class_name, name, conversions, latex, mathml, domain): cls = globals()[class_name] return cls(name=name) +@richcmp_method class Constant(object): def __init__(self, name, conversions=None, latex=None, mathml="", domain='complex'): @@ -292,7 +293,7 @@ def __init__(self, name, conversions=None, latex=None, mathml="", register_symbol(self.expression(), self._conversions) - def __eq__(self, other): + def __richcmp__(self, other, op): """ EXAMPLES:: @@ -306,8 +307,10 @@ def __eq__(self, other): sage: p != s True """ - return (self.__class__ == other.__class__ and - self._name == other._name) + if self.__class__ == other.__class__ and self._name == other._name: + return op in [op_EQ, op_GE, op_LE] + else: + return NotImplemented def __reduce__(self): """ diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 4badeaffd0c..28f58ed6da5 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -2006,6 +2006,33 @@ cdef class Expression(CommutativeRingElement): return False return True + def is_rational_expression(self): + """ + Return True if this expression if a rational expression, i.e., + a quotient of polynomials. + + EXAMPLES:: + + sage: var('x y z') + (x, y, z) + sage: ((x + y + z)/(1 + x^2)).is_rational_expression() + True + sage: ((1 + x + y)^10).is_rational_expression() + True + sage: ((1/x + z)^5 - 1).is_rational_expression() + True + sage: (1/(x + y)).is_rational_expression() + True + sage: (exp(x) + 1).is_rational_expression() + False + sage: (sin(x*y) + z^3).is_rational_expression() + False + sage: (exp(x) + exp(-x)).is_rational_expression() + False + """ + return all([all([part.is_polynomial(v) for v in part.variables()]) + for part in (self.numerator(), self.denominator())]) + def is_real(self): """ Return True if this expression is known to be a real number. @@ -4104,7 +4131,7 @@ cdef class Expression(CommutativeRingElement): sage: g = derivative(f, x); g # this is a complex expression -1/2*((x^2 + 1)*x/(x^2 - 1)^2 - x/(x^2 - 1))/((x^2 + 1)/(x^2 - 1))^(3/4) sage: g.factor() - -x/((x + 1)^2*(x - 1)^2*((x^2 + 1)/((x + 1)*(x - 1)))^(3/4)) + -x/((x + 1)^2*(x - 1)^2*((x^2 + 1)/(x^2 - 1))^(3/4)) :: @@ -11117,11 +11144,22 @@ cdef class Expression(CommutativeRingElement): sage: f(x) = function('f')(x) sage: (f(x).diff(x)^2-1).factor() (diff(f(x), x) + 1)*(diff(f(x), x) - 1) + + Check that :trac:`27304` is fixed:: + + sage: factor(2*exp(x) + exp(-x)) + (2*e^(2*x) + 1)*e^(-x) + sage: factor(x*exp(-x) + exp(-x)) + (x + 1)*e^(-x) + sage: factor(x + sqrt(x)) + x + sqrt(x) + sage: factor((x + sqrt(x))/(x - sqrt(x))) + (x + sqrt(x))/(x - sqrt(x)) """ from sage.calculus.calculus import symbolic_expression_from_maxima_string cdef GEx x cdef bint b - if dontfactor: + if dontfactor or not self.is_rational_expression(): m = self._maxima_() name = m.name() varstr = ','.join(['_SAGE_VAR_' + str(v) for v in dontfactor]) diff --git a/src/sage/tests/gap_packages.py b/src/sage/tests/gap_packages.py index c86b6e8d3fd..9ec48148f90 100644 --- a/src/sage/tests/gap_packages.py +++ b/src/sage/tests/gap_packages.py @@ -17,7 +17,6 @@ """ import os -import os.path from sage.libs.gap.libgap import libgap @@ -113,7 +112,7 @@ def test_packages(packages, only_failures=False): return table(rows, header_row=True) -def all_installed_packages(ignore_dot_gap=False): +def all_installed_packages(ignore_dot_gap=False, gap=None): """ Return list of all installed packages. @@ -123,6 +122,9 @@ def all_installed_packages(ignore_dot_gap=False): ignore the `.gap/` directory (usually in the user home directory) when searching for packages. + - ``gap`` -- The GAP interface to use (default: ``libgap``); can + be either ``libgap`` or a pexpect ``Gap`` instance. + OUTPUT: Tuple of strings in alphabetic order. @@ -132,9 +134,19 @@ def all_installed_packages(ignore_dot_gap=False): sage: from sage.tests.gap_packages import all_installed_packages sage: all_installed_packages() (...'GAPDoc'...) + sage: all_installed_packages() == all_installed_packages(gap=gap) + True """ + if gap is None: + gap = libgap + + if gap == libgap: + paths = [str(p) for p in gap.eval('GAPInfo.RootPaths')] + else: + paths = [str(p) for p in gap('GAPInfo.RootPaths')] + packages = [] - for path in libgap.eval('GAPInfo.RootPaths').sage(): + for path in paths: if ignore_dot_gap and path.endswith('/.gap/'): continue pkg_dir = os.path.join(path, 'pkg') diff --git a/src/sage/version.py b/src/sage/version.py index dd75f6f2808..0bb02f0d9d0 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '8.8.beta5' -date = '2019-05-11' -banner = 'SageMath version 8.8.beta5, Release Date: 2019-05-11' +version = '8.8.beta6' +date = '2019-05-22' +banner = 'SageMath version 8.8.beta6, Release Date: 2019-05-22'