diff --git a/.github/workflows/tox-experimental.yml b/.github/workflows/tox-experimental.yml index 5e036abbe8f..4b3c6b1eb84 100644 --- a/.github/workflows/tox-experimental.yml +++ b/.github/workflows/tox-experimental.yml @@ -38,7 +38,7 @@ jobs: fail-fast: false max-parallel: 6 matrix: - tox_system_factor: [ubuntu-trusty, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7, centos-8, gentoo, archlinux-latest, slackware-14.2, conda-forge, ubuntu-bionic-i386, ubuntu-focal-i386, debian-buster-i386, centos-7-i386] + tox_system_factor: [ubuntu-trusty, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7, centos-8, gentoo, archlinux-latest, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386] tox_packages_factor: [maximal] targets_pattern: [0-g, h-o, p, q-z] env: diff --git a/.github/workflows/tox-optional.yml b/.github/workflows/tox-optional.yml index 7ce3c44da47..92245c2a7db 100644 --- a/.github/workflows/tox-optional.yml +++ b/.github/workflows/tox-optional.yml @@ -38,7 +38,7 @@ jobs: fail-fast: false max-parallel: 6 matrix: - tox_system_factor: [ubuntu-trusty, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7, centos-8, gentoo, archlinux-latest, slackware-14.2, conda-forge, ubuntu-bionic-i386, ubuntu-focal-i386, debian-buster-i386, centos-7-i386] + tox_system_factor: [ubuntu-trusty, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7, centos-8, gentoo, archlinux-latest, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386] tox_packages_factor: [maximal] targets_pattern: [0-g, h-o, p, q-z] env: diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 609ac4dde5b..2390bf30aaf 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -38,7 +38,7 @@ jobs: fail-fast: false max-parallel: 20 matrix: - tox_system_factor: [ubuntu-trusty, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7, centos-8, gentoo, gentoo-python3.7, archlinux-latest, slackware-14.2, conda-forge, ubuntu-bionic-i386, ubuntu-focal-i386, debian-buster-i386, centos-7-i386] + tox_system_factor: [ubuntu-trusty, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7, centos-8, gentoo, gentoo-python3.7, archlinux-latest, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386] tox_packages_factor: [minimal, standard] env: TOX_ENV: docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} diff --git a/.zenodo.json b/.zenodo.json index 9d3d03c28b9..0aeb3c81cf5 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.3.rc3", - "version": "9.3.rc3", + "title": "sagemath/sage: 9.3", + "version": "9.3", "upload_type": "software", - "publication_date": "2021-04-12", + "publication_date": "2021-05-09", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.3.rc3", + "identifier": "https://github.com/sagemath/sage/tree/9.3", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index 7cad775ab1d..c4a47dfc279 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.3.rc3, Release Date: 2021-04-12 +SageMath version 9.3, Release Date: 2021-05-09 diff --git a/build/pkgs/brial/spkg-configure.m4 b/build/pkgs/brial/spkg-configure.m4 index 3d69c88f82d..a0f00838c75 100644 --- a/build/pkgs/brial/spkg-configure.m4 +++ b/build/pkgs/brial/spkg-configure.m4 @@ -1,5 +1,6 @@ SAGE_SPKG_CONFIGURE([brial], [ - SAGE_SPKG_DEPCHECK([boost m4ri], [ + dnl Trac #31624: Avoid C++ ABI issues + SAGE_SPKG_DEPCHECK([gcc boost m4ri], [ # If we're using the system m4ri and boost, ensure that we can # compile and run an executable linked against both libbrial and # libbrial_groebner (both are used by SageMath). diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index c4c843511a8..a39456c6909 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=8e87b8d927704c25058ba2d9595e48e22062197f -md5=ebdea78d9fb120ab8e31f4ea5dd01d8e -cksum=3284139585 +sha1=2d5d2d8a2a6dbc721935f6b3d3ada9a6bd977e19 +md5=d84b8fcb2ddd6949d3461f49fae01702 +cksum=2508666370 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 808d0aab19d..b644f6ab59f 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -c0dc957ff06d230f943cad6ae12dc3b028eec49c +3f4547f2cc40338ba42329d53f7fb48c31ff9fc8 diff --git a/build/pkgs/fplll/spkg-configure.m4 b/build/pkgs/fplll/spkg-configure.m4 index 20a64a58e45..f870e4dbf72 100644 --- a/build/pkgs/fplll/spkg-configure.m4 +++ b/build/pkgs/fplll/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([fplll], [ - SAGE_SPKG_DEPCHECK([mpfr], [ + SAGE_SPKG_DEPCHECK([gcc mpfr], [ dnl If we're using the system mpfr, use pkgconfig to determine dnl if there's a usable system copy of fplll. Unless there's dnl a system that ships fplll without fplll.pc file, falling diff --git a/build/pkgs/fplll/spkg-install.in b/build/pkgs/fplll/spkg-install.in index 619a3e8d53c..dda663d433c 100644 --- a/build/pkgs/fplll/spkg-install.in +++ b/build/pkgs/fplll/spkg-install.in @@ -20,6 +20,11 @@ if [ "x$SAGE_DEBUG" = "xyes" ]; then CONFIGUREFLAGS="$CONFIGUREFLAGS --enable-debug" fi +if [ -x "$SAGE_LOCAL"/bin/gcc ]; then + # Trac #31624: Avoid C++ ABI issues + CONFIGUREFLAGS="$CONFIGUREFLAGS --without-qd" +fi + export CXXFLAGS="$CXXFLAGS" export CPPFLAGS="$CPPFLAGS" export CXX="$CXX" diff --git a/build/pkgs/freetype/checksums.ini b/build/pkgs/freetype/checksums.ini index 15ea9b472ff..704e1b370d5 100644 --- a/build/pkgs/freetype/checksums.ini +++ b/build/pkgs/freetype/checksums.ini @@ -1,5 +1,5 @@ tarball=freetype-VERSION.tar.bz2 -sha1=3296b64ad1e7540289f22e4b6383e26e928b0a20 -md5=c50a3c9e5e62bdc938a6e1598a782947 -cksum=2822306030 +sha1=040d6a4be23708132c85ef9df837eb3f8a04c4ab +md5=4934a8b61b636920bcce58e7c7f3e1a2 +cksum=2814275332 upstream_url=https://download.savannah.gnu.org/releases/freetype/freetype-VERSION.tar.gz diff --git a/build/pkgs/freetype/package-version.txt b/build/pkgs/freetype/package-version.txt index 8bbb6e406a7..b52282a1b4e 100644 --- a/build/pkgs/freetype/package-version.txt +++ b/build/pkgs/freetype/package-version.txt @@ -1 +1 @@ -2.10.1 +2.10.4 diff --git a/build/pkgs/freetype/spkg-configure.m4 b/build/pkgs/freetype/spkg-configure.m4 index 846bcb368ce..06bef2b302c 100644 --- a/build/pkgs/freetype/spkg-configure.m4 +++ b/build/pkgs/freetype/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([freetype], [ - SAGE_SPKG_DEPCHECK([libpng], [ + SAGE_SPKG_DEPCHECK([gcc libpng], [ dnl freetype versions are libtool's ones, cf trac #30014 PKG_CHECK_MODULES([FREETYPE], [freetype2 >= 16.1], [], [sage_spkg_install_freetype=yes]) ]) diff --git a/build/pkgs/libgd/spkg-configure.m4 b/build/pkgs/libgd/spkg-configure.m4 index 8591449fce4..0e7baedd82c 100644 --- a/build/pkgs/libgd/spkg-configure.m4 +++ b/build/pkgs/libgd/spkg-configure.m4 @@ -1,21 +1,6 @@ SAGE_SPKG_CONFIGURE([libgd], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_LIBPNG]) - AC_REQUIRE([SAGE_SPKG_CONFIGURE_FREETYPE]) - AC_MSG_CHECKING([Installing freetype? ]) - if test x$sage_spkg_install_freetype = xyes; then - AC_MSG_RESULT([Yes. Install libgd as well.]) - sage_spkg_install_libgd=yes - else - dnl do not just rely on libpng being a dependency of freetype - AC_MSG_CHECKING([Installing libpng? ]) - if test x$sage_spkg_install_libpng = xyes; then - AC_MSG_RESULT([Yes. Install libgd as well.]) - sage_spkg_install_libgd=yes - else - AC_MSG_RESULT([No.]) + dnl Trac #31624: Avoid C++ ABI issues + SAGE_SPKG_DEPCHECK([gcc libpng freetype], [ PKG_CHECK_MODULES([LIBGD], [gdlib >= 2.1], [], [sage_spkg_install_libgd=yes]) - fi - fi + ]) ]) - - diff --git a/build/pkgs/ntl/spkg-configure.m4 b/build/pkgs/ntl/spkg-configure.m4 index 5f153f19600..48e41de6ea7 100644 --- a/build/pkgs/ntl/spkg-configure.m4 +++ b/build/pkgs/ntl/spkg-configure.m4 @@ -1,17 +1,7 @@ SAGE_SPKG_CONFIGURE([ntl], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AC_MSG_CHECKING([installing gmp/mpir? ]) - if test x$sage_spkg_install_mpir = xyes -o x$sage_spkg_install_gmp = xyes; then - AC_MSG_RESULT([yes; install ntl as well]) - sage_spkg_install_ntl=yes - else - AC_MSG_RESULT([no]) - fi - m4_pushdef(SAGE_NTL_VERSION_MAJOR, [10]) m4_pushdef(SAGE_NTL_VERSION_MINOR, [3]) - - if test x$sage_spkg_install_ntl != xyes; then + SAGE_SPKG_DEPCHECK([gmp mpir gcc], [ AC_CHECK_HEADER([NTL/ZZ.h], [], [sage_spkg_install_ntl=yes]) AC_MSG_CHECKING([whether we can link a program using NTL]) NTL_SAVED_LIBS=$LIBS @@ -40,7 +30,7 @@ SAGE_SPKG_CONFIGURE([ntl], [ AC_MSG_RESULT([no]) sage_spkg_install_ntl=yes ]) - fi + ]) m4_popdef([SAGE_NTL_VERSION_MAJOR]) m4_popdef([SAGE_NTL_VERSION_MINOR]) diff --git a/build/pkgs/ppl/spkg-configure.m4 b/build/pkgs/ppl/spkg-configure.m4 index 257fb777acc..484dbd2d670 100644 --- a/build/pkgs/ppl/spkg-configure.m4 +++ b/build/pkgs/ppl/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([ppl], [ - SAGE_SPKG_DEPCHECK([glpk gmp mpir], [ + SAGE_SPKG_DEPCHECK([gcc glpk gmp mpir], [ # If our dependencies come from the system, then we can use the # system ppl, too. This macro works sort-of like the # PKG_CHECK_MODULES macro, defining e.g. PPL_CFLAGS when a diff --git a/build/pkgs/pynac/package-version.txt b/build/pkgs/pynac/package-version.txt index 0d98118e038..4373c7f55cb 100644 --- a/build/pkgs/pynac/package-version.txt +++ b/build/pkgs/pynac/package-version.txt @@ -1 +1 @@ -0.7.27.p4 +0.7.27.p7 diff --git a/build/pkgs/pynac/patches/disable_poly_mul_expand.patch b/build/pkgs/pynac/patches/disable_poly_mul_expand.patch new file mode 100644 index 00000000000..507dcae68af --- /dev/null +++ b/build/pkgs/pynac/patches/disable_poly_mul_expand.patch @@ -0,0 +1,39 @@ +diff --git a/ginac/mul.cpp b/ginac/mul.cpp +index 1a29c01..c800cbf 100644 +--- a/ginac/mul.cpp ++++ b/ginac/mul.cpp +@@ -1325,18 +1325,22 @@ ex mul::expand(unsigned options) const + const auto& add2end = add2.seq.end(); + epvector distrseq; + auto s = add1.seq.size()+add2.seq.size(); +- if (s > 400) { +-// // the condition is probably too simple +- try { +- // can it be converted/expanded via Singular? +- last_expanded = poly_mul_expand(last_expanded, +- elem.rest); +- continue; +- } +- catch (std::runtime_error) { +- std::cerr << "can't happen while calling poly_mul_expand\n"; +- } +- } ++// // the poly_mul_expand function is buggy and ++// // therefore cannot be used (see sage :trac:`31478`), ++// // so we comment out this section of code until the ++// // function has been fixed ++// if (s > 400) { ++//// // the condition is probably too simple ++// try { ++// // can it be converted/expanded via Singular? ++// last_expanded = poly_mul_expand(last_expanded, ++// elem.rest); ++// continue; ++// } ++// catch (std::runtime_error) { ++// std::cerr << "can't happen while calling poly_mul_expand\n"; ++// } ++// } + + distrseq.reserve(s); + // Multiply add2 with the overall coefficient of add1 and append it to distrseq: diff --git a/build/pkgs/pynac/patches/seriesbug.patch b/build/pkgs/pynac/patches/seriesbug.patch new file mode 100644 index 00000000000..31cce9c8fd1 --- /dev/null +++ b/build/pkgs/pynac/patches/seriesbug.patch @@ -0,0 +1,41 @@ +diff --git a/ginac/useries.cpp b/ginac/useries.cpp +index fd68d49..3af04d8 100644 +--- a/ginac/useries.cpp ++++ b/ginac/useries.cpp +@@ -462,7 +462,16 @@ void symbol::useries(flint_series_t& fp, int order) const + + void add::useries(flint_series_t& fp, int order) const + { +- fmpq_poly_set_ui(fp.ft, 0); ++ const numeric& oc = overall_coeff; ++ if (oc.is_zero()) ++ fmpq_poly_set_ui(fp.ft, 0); ++ else if (oc.is_long()) ++ fmpq_poly_set_si(fp.ft, oc.to_long()); ++ else if (oc.is_mpz()) ++ fmpq_poly_set_mpz(fp.ft, oc.as_mpz()); ++ else ++ fmpq_poly_set_mpq(fp.ft, oc.as_mpq()); ++ + for (const auto & elem : seq) { + const ex& t = recombine_pair_to_ex(elem); + flint_series_t fp1; +@@ -477,18 +486,6 @@ void add::useries(flint_series_t& fp, int order) const + } + fmpq_poly_add(fp.ft, fp.ft, fp1.ft); + } +- const numeric& oc = overall_coeff; +- if (oc.is_zero()) +- return; +- +- flint_series_t fp1; +- if (oc.is_long()) +- fmpq_poly_set_si(fp1.ft, oc.to_long()); +- else if (oc.is_mpz()) +- fmpq_poly_set_mpz(fp1.ft, oc.as_mpz()); +- else +- fmpq_poly_set_mpq(fp1.ft, oc.as_mpq()); +- fmpq_poly_add(fp.ft, fp.ft, fp1.ft); + } + + void mul::useries(flint_series_t& fp, int order) const diff --git a/build/pkgs/sagelib/package-version.txt b/build/pkgs/sagelib/package-version.txt index 68a49ac44ce..c3cae12bcc1 100644 --- a/build/pkgs/sagelib/package-version.txt +++ b/build/pkgs/sagelib/package-version.txt @@ -1 +1 @@ -9.3.rc3 +9.3 diff --git a/build/pkgs/sagelib/src/setup.py b/build/pkgs/sagelib/src/setup.py index 0d7c29d7463..d20e408a8cf 100755 --- a/build/pkgs/sagelib/src/setup.py +++ b/build/pkgs/sagelib/src/setup.py @@ -5,6 +5,9 @@ import os import sys import time +# Import setuptools before importing distutils, so that setuptools +# can replace distutils by its own vendored copy. +import setuptools from distutils import log from setuptools import setup diff --git a/build/pkgs/setuptools_scm/checksums.ini b/build/pkgs/setuptools_scm/checksums.ini index 901eb000a2a..e2afcaf1458 100644 --- a/build/pkgs/setuptools_scm/checksums.ini +++ b/build/pkgs/setuptools_scm/checksums.ini @@ -1,5 +1,5 @@ tarball=setuptools_scm-VERSION.tar.gz -sha1=af08a257a725dbdde9795859249ddf79caf4fc22 -md5=c11bf23d80224691a46ee5deb84c42db -cksum=929248754 +sha1=183e0947ee14f8107a3ad6a7f635f04f54a30011 +md5=aa7f0efbbf46c5576db5994dd1ce3f8d +cksum=4017375148 upstream_url=https://pypi.io/packages/source/s/setuptools_scm/setuptools_scm-VERSION.tar.gz diff --git a/build/pkgs/setuptools_scm/package-version.txt b/build/pkgs/setuptools_scm/package-version.txt index 6b244dcd696..5fe60723048 100644 --- a/build/pkgs/setuptools_scm/package-version.txt +++ b/build/pkgs/setuptools_scm/package-version.txt @@ -1 +1 @@ -5.0.1 +6.0.1 diff --git a/build/pkgs/zeromq/spkg-configure.m4 b/build/pkgs/zeromq/spkg-configure.m4 index a584a74cc21..8c0fd29e891 100644 --- a/build/pkgs/zeromq/spkg-configure.m4 +++ b/build/pkgs/zeromq/spkg-configure.m4 @@ -1,3 +1,6 @@ SAGE_SPKG_CONFIGURE([zeromq], [ - AX_ZMQ([4.2.5], [], [sage_spkg_install_zeromq=yes]) + dnl Trac #31624: Avoid C++ ABI issues + SAGE_SPKG_DEPCHECK([gcc], [ + AX_ZMQ([4.2.5], [], [sage_spkg_install_zeromq=yes]) + ]) ]) diff --git a/m4/sage_check_osx_supported.m4 b/m4/sage_check_osx_supported.m4 index 6e7b56ada9f..36984469c24 100644 --- a/m4/sage_check_osx_supported.m4 +++ b/m4/sage_check_osx_supported.m4 @@ -40,29 +40,5 @@ AC_DEFUN([SAGE_CHECK_OSX_SUPPORTED], [ fi fi >& AS_MESSAGE_FD - ####################################################################### - # (OS X only) - # Sage will probably not build at all if either Fink or MacPorts can be - # found, and the error messages can be extremely confusing. Even if it - # does build, the product will probably be wrong. This runs a basic - # check to find them. Once the Sage build process is perfected, this - # won't be necessary. - # dphilp 15/9/2008 - ####################################################################### - PORTS_PATH=`which port` - if test -f "$PORTS_PATH"; then - AC_MSG_ERROR(["found MacPorts in $PORTS_PATH. Either: - (1) rename /opt/local and /sw, or - (2) change PATH and DYLD_LIBRARY_PATH - (Once Sage is built, you can restore them.)]) - fi - - FINK_PATH=`which fink` - if test -f "$FINK_PATH"; then - AC_MSG_ERROR(["found Fink in $FINK_PATH. Either: - (1) rename /opt/local and /sw, or - (2) change PATH and DYLD_LIBRARY_PATH - (Once Sage is built, you can restore them.)]) - fi ]) ]) diff --git a/m4/sage_spkg_collect.m4 b/m4/sage_spkg_collect.m4 index 956bc7b8acd..62f4b07f063 100644 --- a/m4/sage_spkg_collect.m4 +++ b/m4/sage_spkg_collect.m4 @@ -123,6 +123,7 @@ SAGE_PIP_PACKAGES='' SAGE_SCRIPT_PACKAGES='' SAGE_NEED_SYSTEM_PACKAGES="" +SAGE_NEED_SYSTEM_PACKAGES_OPTIONAL="" # for each package in pkgs/, add them to the SAGE_PACKAGE_VERSIONS and # SAGE_PACKAGE_DEPENDENCIES lists, and to one or more of the above variables @@ -159,6 +160,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do SAGE_PACKAGE_TREES="${SAGE_PACKAGE_TREES}$(printf '\ntrees_')${SPKG_NAME} = ${SPKG_TREE_VAR}" uninstall_message="" + SAGE_NEED_SYSTEM_PACKAGES_VAR=SAGE_NEED_SYSTEM_PACKAGES # Check consistency of 'DIR/type' file case "$SPKG_TYPE" in base) @@ -176,6 +178,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do message="$SPKG_TYPE, will be installed as an SPKG" ], [ message="$SPKG_TYPE, use \"$srcdir/configure --enable-$SPKG_NAME\" to install" + SAGE_NEED_SYSTEM_PACKAGES_VAR=SAGE_NEED_SYSTEM_PACKAGES_OPTIONAL ]) ;; *) @@ -235,7 +238,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do AS_VAR_COPY([reason], [sage_use_system]) AS_CASE([$reason], [yes], [ message="no suitable system package; $message" - AS_VAR_APPEND([SAGE_NEED_SYSTEM_PACKAGES], [" $SPKG_NAME"]) + AS_VAR_APPEND([$SAGE_NEED_SYSTEM_PACKAGES_VAR], [" $SPKG_NAME"]) ], [installed], [ message="already installed as an SPKG$uninstall_message" ], [ message="$reason; $message" ]) @@ -359,12 +362,12 @@ AC_SUBST([SAGE_SDIST_PACKAGES]) ]) AC_DEFUN([SAGE_SYSTEM_PACKAGE_NOTICE], [ - AS_IF([test -n "$SAGE_NEED_SYSTEM_PACKAGES"], [ + AS_IF([test -n "$SAGE_NEED_SYSTEM_PACKAGES" -o -n "$SAGE_NEED_SYSTEM_PACKAGES_OPTIONAL"], [ AC_MSG_NOTICE([ notice: the following SPKGs did not find equivalent system packages: - $SAGE_NEED_SYSTEM_PACKAGES + $SAGE_NEED_SYSTEM_PACKAGES $SAGE_NEED_SYSTEM_PACKAGES_OPTIONAL ]) AC_MSG_CHECKING([for the package system in use]) SYSTEM=$(build/bin/sage-guess-package-system 2>& AS_MESSAGE_FD) @@ -381,8 +384,25 @@ AC_DEFUN([SAGE_SYSTEM_PACKAGE_NOTICE], [ build them (though some may have to be built anyway): $COMMAND +]) + AS_VAR_SET([need_reconfig_msg], [yes]) + ]) + SYSTEM_PACKAGES=$(build/bin/sage-get-system-packages $SYSTEM $SAGE_NEED_SYSTEM_PACKAGES_OPTIONAL) + AS_IF([test -n "$SYSTEM_PACKAGES"], [ + PRINT_SYS="build/bin/sage-print-system-package-command $SYSTEM --verbose=\" \" --prompt=\" \$ \" --sudo" + COMMAND=$(eval "$PRINT_SYS" update && eval "$PRINT_SYS" install $SYSTEM_PACKAGES && SAGE_ROOT="$SAGE_ROOT" eval "$PRINT_SYS" setup-build-env ) + AC_MSG_NOTICE([ + + hint: installing the following system packages, if not + already present, may provide additional optional features: + +$COMMAND +]) + ]) + AS_VAR_IF([need_reconfig_msg], [yes], [ + AC_MSG_NOTICE([ - After installation, re-run configure using: + hint: After installation, re-run configure using: \$ ./config.status --recheck && ./config.status ]) diff --git a/src/VERSION.txt b/src/VERSION.txt index 68a49ac44ce..c3cae12bcc1 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.3.rc3 +9.3 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index eb3d9a19f12..461cb470923 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='9.3.rc3' -SAGE_RELEASE_DATE='2021-04-12' -SAGE_VERSION_BANNER='SageMath version 9.3.rc3, Release Date: 2021-04-12' +SAGE_VERSION='9.3' +SAGE_RELEASE_DATE='2021-05-09' +SAGE_VERSION_BANNER='SageMath version 9.3, Release Date: 2021-05-09' diff --git a/src/doc/en/installation/launching.rst b/src/doc/en/installation/launching.rst index 681c97c0d53..6ca60404deb 100644 --- a/src/doc/en/installation/launching.rst +++ b/src/doc/en/installation/launching.rst @@ -143,6 +143,31 @@ different installations of SageMath, you can use the additional option jupyter kernelspec install --user $SAGE_LOCAL/share/jupyter/kernels/sagemath --name sagemath-dev-worktree +The ``jupyter kernelspec`` approach by default does lead to about 2Gb of +sagemath documentation being copied into your personal jupyter configuration +directory. You can avoid that by instead putting a symlink in the relevant spot. +Assuming that sagemath is properly installed, you can use + +.. CODE-BLOCK:: bash + + sage -sh -c 'ls -d $SAGE_LOCAL/share/jupyter/kernels/sagemath' + +to find location of the sagemath kernel description and + +.. CODE-BLOCK:: bash + + jupyter --paths + +to find valid data directories for your jupyter installation. +A command along the lines of + +.. CODE-BLOCK:: bash + + ln -s `sage -sh -c 'ls -d $SAGE_LOCAL/share/jupyter/kernels/sagemath'` $HOME/.local/share/jupyter + +can then be used to create a symlink to the sagemath kernel description +in a location where your own ``jupyter`` can find it. + To get the full functionality of the SageMath kernel in your global Jupyter installation, the following Notebook Extension packages also need to be installed (or linked) in the environment from which the diff --git a/src/doc/en/reference/plot3d/threejs.rst b/src/doc/en/reference/plot3d/threejs.rst index 388ed735989..bf2318b4630 100644 --- a/src/doc/en/reference/plot3d/threejs.rst +++ b/src/doc/en/reference/plot3d/threejs.rst @@ -43,6 +43,10 @@ Options currently supported by the viewer: - ``decimals`` -- (default: 2) integer determining decimals displayed in labels +- ``depth_write`` -- (default: True for opaque surfaces, False for transparent surfaces) + whether to write the surface's depth into the depth buffer for the purpose of occluding + objects behind it + - ``frame`` -- (default: True) Boolean determining whether frame is drawn - ``online`` -- (default: False) Boolean determining whether the local standard package diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index ecd1bf6c72f..3378296f1d5 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1942,6 +1942,10 @@ REFERENCES: Integrals*, in NIST Digital Library of Mathematical Functions. https://dlmf.nist.gov/7 +.. [DLMF-Legendre] \T. M. Dunster: *Legendre and Related Functions*, in NIST + Digital Library of Mathematical Functions. + https://dlmf.nist.gov/14 + .. [DLMF-Struve] \R. B. Paris: *11. Struve and Related Functions*, in NIST Digital Library of Mathematical Functions. https://dlmf.nist.gov/11 diff --git a/src/sage/ext_data/threejs/threejs_template.html b/src/sage/ext_data/threejs/threejs_template.html index 1db1e15d7bd..1f94e841cb0 100644 --- a/src/sage/ext_data/threejs/threejs_template.html +++ b/src/sage/ext_data/threejs/threejs_template.html @@ -176,7 +176,7 @@ var texture = new THREE.Texture( canvas ); texture.needsUpdate = true; - var materialOptions = { map: texture, sizeAttenuation: false }; + var materialOptions = { map: texture, sizeAttenuation: false, depthWrite: false }; if ( opacity < 1 ) { // Setting opacity=1 would cause the texture's alpha component to be // discarded, giving the text a black background instead of the @@ -395,13 +395,15 @@ var side = json.singleSide ? THREE.FrontSide : THREE.DoubleSide; var transparent = json.opacity < 1 ? true : false; + var depthWrite = 'depthWrite' in json ? json.depthWrite : !transparent; var flatShading = json.useFlatShading ? json.useFlatShading : false; var material = new THREE.MeshPhongMaterial( { side: side, color: useFaceColors ? 'white' : json.color, vertexColors: useFaceColors ? THREE.FaceColors : THREE.NoColors, transparent: transparent, opacity: json.opacity, - shininess: 20, flatShading: flatShading } ); + shininess: 20, flatShading: flatShading, + depthWrite: depthWrite } ); var c = new THREE.Vector3(); geometry.computeBoundingBox(); diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 6c49e760567..9b5636f3fdc 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -1424,6 +1424,115 @@ def _derivative_(self, n, x, *args,**kwds): legendre_Q = Func_legendre_Q() class Func_assoc_legendre_P(BuiltinFunction): + r""" + Return the Ferrers function `\mathtt{P}_n^m(x)` of first kind for + `x \in (-1,1)` with general order `m` and general degree `n`. + + Ferrers functions of first kind are one of two linearly independent + solutions of the associated Legendre differential equation + + .. MATH:: + + (1-x^2) \frac{\mathrm{d}^2 w}{\mathrm{d}x^2} - + 2x \frac{\mathrm{d} w}{\mathrm{d}x} + + \left(n(n+1) - \frac{m^2}{1-x^2}\right) w = 0 + + on the interval `x \in (-1, 1)` and are usually denoted by + `\mathtt{P}_n^m(x)`. + + .. SEEALSO :: + + The other linearly independent solution is called *Ferrers function of + second kind* and denoted by `\mathtt{Q}_n^m(x)`, + see :class:`Func_assoc_legendre_Q`. + + .. WARNING:: + + Ferrers functions must be carefully distinguished from associated + Legendre functions which are defined on `\CC \setminus (- \infty, 1]` + and have not yet been implemented. + + EXAMPLES: + + We give the first Ferrers functions for non-negative integers + `n` and `m` in the interval `-1= 0 and m >= 0 - and (x in ZZ or not SR(x).is_numeric())): - return self.eval_poly(n, m, x) + if n in ZZ and m in ZZ and (x in ZZ or not SR(x).is_numeric()): + return self._eval_int_ord_deg_(n, m, x) def _eval_special_values_(self, n, m, x): """ Special values known. - EXAMPLES:: + EXAMPLES: + + Case `|m| > |n|` for integers:: sage: gen_legendre_P(2,3,4) 0 - sage: gen_legendre_P(2,0,4)==legendre_P(2,4) - True - sage: gen_legendre_P(2,2,4) - 45 - sage: gen_legendre_P(2,2,x) - 3*x^2 - 3 + + Case `x = 0`:: + sage: gen_legendre_P(13/2,2,0) - 2*sqrt(2)*gamma(19/4)/(sqrt(pi)*gamma(13/4)) + 4*sqrt(pi)/(gamma(13/4)*gamma(-15/4)) sage: (m,n) = var('m,n') sage: gen_legendre_P(n,m,0) - 2^m*cos(1/2*pi*m + 1/2*pi*n)*gamma(1/2*m + 1/2*n + 1/2)/(sqrt(pi)*gamma(-1/2*m + 1/2*n + 1)) + sqrt(pi)*2^m/(gamma(-1/2*m + 1/2*n + 1)*gamma(-1/2*m - 1/2*n + 1/2)) sage: gen_legendre_P(n,3,0) - 8*cos(3/2*pi + 1/2*pi*n)*gamma(1/2*n + 2)/(sqrt(pi)*gamma(1/2*n - 1/2)) + 8*sqrt(pi)/(gamma(1/2*n - 1/2)*gamma(-1/2*n - 1)) sage: gen_legendre_P(3,m,0) - 2^m*cos(3/2*pi + 1/2*pi*m)*gamma(1/2*m + 2)/(sqrt(pi)*gamma(-1/2*m + 5/2)) + sqrt(pi)*2^m/(gamma(-1/2*m + 5/2)*gamma(-1/2*m - 1)) + + Case `m = n` for integers:: + + sage: m = var('m') + sage: assume(m, 'integer') + sage: gen_legendre_P(m, m, x) + (-1)^m*(-x^2 + 1)^(1/2*m)*factorial(2*m)/(2^m*factorial(m)) + sage: gen_legendre_P(m, m, .2) + 0.960000000000000^(1/2*m)*(-1)^m*factorial(2*m)/(2^m*factorial(m)) + sage: gen_legendre_P(2, 2, x) + -3*x^2 + 3 + + Case `n = 0`:: + + sage: gen_legendre_P(m, 0, x) + legendre_P(m, x) + sage: gen_legendre_P(2,0,4) == legendre_P(2,4) + True + """ - if m > n: - return ZZ(0) if m == 0: + # https://dlmf.nist.gov/14.7#E1 return legendre_P(n, x) - if n == m: - return factorial(2*m)/2**m/factorial(m) * (x**2-1)**(m/2) if x == 0: from .gamma import gamma from .other import sqrt - from .trig import cos - if m in QQ and n in QQ: - return 2**m/sqrt(SR.pi())*cos((n+m)/2*SR.pi())*(gamma(QQ(n+m+1)/2)/gamma(QQ(n-m)/2+1)) - elif isinstance(n, Expression) or isinstance(m, Expression): - return 2**m/sqrt(SR.pi())*cos((n+m)/2*SR.pi())*(gamma((n+m+1)/2)/gamma((n-m)/2+1)) + # https://dlmf.nist.gov/14.5#E1 + return 2**m*sqrt(SR.pi())/gamma(n/2-m/2+1)/gamma(QQ(1/2)-n/2-m/2) + if m.is_integer() and n.is_integer(): + if abs(m) > abs(n): + # https://dlmf.nist.gov/14.7#E10 and https://dlmf.nist.gov/14.9#E3 + # and https://dlmf.nist.gov/14.9#E5 + return ZZ.zero() + if m == n: + # http://dlmf.nist.gov/14.5.iv and https://dlmf.nist.gov/14.9#E3 + return (-1)**m*factorial(2*m)/(2**m*factorial(m)) * (1-x**2)**(m/2) + + def _eval_int_ord_deg_(self, n, m, x): + r""" + Evaluate the Ferrers function `P(n, m, x)` for `m` and `n` being + concrete integers. + + TESTS:: + + sage: gen_legendre_P._eval_int_ord_deg_(-2, 1, x) + -sqrt(-x^2 + 1) + sage: gen_legendre_P._eval_int_ord_deg_(2, -1, x) + 1/2*sqrt(-x^2 + 1)*x + sage: gen_legendre_P._eval_int_ord_deg_(-2, -1, x) + 1/2*sqrt(-x^2 + 1) + + """ + # use connection formulas to fall back on non-negative n and m: + if n < 0: + # https://dlmf.nist.gov/14.9#E5 + return self._eval_int_ord_deg_(-n-1, m, x) + if m < 0: + # https://dlmf.nist.gov/14.9#E3 + return (-1)**(-m)*factorial(n+m)/factorial(n-m) * self._eval_int_ord_deg_(n, -m, x) + # apply Rodrigues formula: + return self.eval_gen_poly(n, m, x) def _evalf_(self, n, m, x, parent=None, **kwds): """ - Float evaluation of Legendre P(n, m, x) function. + Float evaluation of Ferrers function P(n, m, x). EXAMPLES:: @@ -1511,18 +1661,30 @@ def _evalf_(self, n, m, x, parent=None, **kwds): 14.3165258449040 - 12.7850496155152*I sage: gen_legendre_P(5/2,2,ComplexField(70)(1+I)) 14.316525844904028532 - 12.785049615515157033*I - """ - ret = self._eval_special_values_(n, m, x) - if ret is not None: - return ret + sage: gen_legendre_P(2/3,1,0.) + -0.773063511309286 + """ import mpmath from sage.libs.mpmath.all import call as mpcall return mpcall(mpmath.legenp, n, m, x, parent=parent) - def eval_poly(self, n, m, arg, **kwds): - """ - Return the associated Legendre P(n, m, arg) polynomial for integers `n > -1, m > -1`. + def eval_gen_poly(self, n, m, arg, **kwds): + r""" + Return the Ferrers function of first kind `\mathtt{P}_n^m(x)` for + integers `n > -1, m > -1` given by the following Rodrigues-type + formula: + + .. MATH:: + + \mathtt{P}_n^m(x) = (-1)^{m+n} \frac{(1-x^2)^{m/2}}{2^n n!} + \frac{\mathrm{d}^{m+n}}{\mathrm{d}x^{m+n}} (1-x^2)^n. + + INPUT: + + - ``n`` -- an integer degree + - ``m`` -- an integer order + - ``x`` -- either an integer or a non-numerical symbolic expression EXAMPLES:: @@ -1533,21 +1695,23 @@ def eval_poly(self, n, m, arg, **kwds): REFERENCE: - - T. M. Dunster, Legendre and Related Functions, https://dlmf.nist.gov/14.7#E10 + - [DLMF-Legendre]_, Section 14.7 eq. 10 (https://dlmf.nist.gov/14.7#E10) """ - from sage.functions.other import factorial if n < 0 or m < 0: return R = PolynomialRing(QQ, 'x') x = R.gen() p = (1-x**2)**ZZ(n) - for i in range(m + n): + for _ in range(m + n): p = p.diff(x) ex1 = (1-arg**2)**(QQ(m)/2)/2**n/factorial(ZZ(n)) ex2 = sum(b * arg**a for a, b in enumerate(p)) return (-1)**(m+n)*ex1*ex2 - def _derivative_(self, n, m, x, *args,**kwds): + from sage.misc.superseded import deprecated_function_alias + eval_poly = deprecated_function_alias(25034, eval_gen_poly) + + def _derivative_(self, n, m, x, *args, **kwds): """ Return the derivative of ``gen_legendre_P(n,m,x)``. @@ -1562,12 +1726,14 @@ def _derivative_(self, n, m, x, *args,**kwds): Traceback (most recent call last): ... NotImplementedError: Derivative w.r.t. to the index is not supported. + """ diff_param = kwds['diff_param'] if diff_param == 0: raise NotImplementedError("Derivative w.r.t. to the index is not supported.") else: - return ((n-m+1)*gen_legendre_P(n+1, m, x) - (n+1)*x*gen_legendre_P(n, m, x))/(x**2 - 1) + # https://dlmf.nist.gov/14.10#E4 + return ((m-n-1)*gen_legendre_P(n+1, m, x) + (n+1)*x*gen_legendre_P(n, m, x))/(1 - x**2) gen_legendre_P = Func_assoc_legendre_P() diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 31b59c8695f..c92e783bbe7 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -228,6 +228,18 @@ def _eval_(self, n, m, theta, phi, **kwargs): sage: ex = spherical_harmonic(3,2,1,2*pi/3) sage: QQbar(ex * sqrt(pi)/cos(1)/sin(1)^2).minpoly() x^4 + 105/32*x^2 + 11025/1024 + + Check whether :trac:`25034` yields correct results compared to Maxima:: + + sage: spherical_harmonic(1,1,pi/3,pi/6).n() # abs tol 1e-14 + 0.259120612103502 + 0.149603355150537*I + sage: maxima.spherical_harmonic(1,1,pi/3,pi/6).n() # abs tol 1e-14 + 0.259120612103502 + 0.149603355150537*I + sage: spherical_harmonic(1,-1,pi/3,pi/6).n() # abs tol 1e-14 + -0.259120612103502 + 0.149603355150537*I + sage: maxima.spherical_harmonic(1,-1,pi/3,pi/6).n() # abs tol 1e-14 + -0.259120612103502 + 0.149603355150537*I + """ if n in ZZ and m in ZZ and n > -1: if abs(m) > n: diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 5ff84e23a19..d32b53b6ac7 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -320,9 +320,12 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): ....: G = BipartiteGraph(A) sage: for _ in range(10): ....: make_bip_graph(A) + sage: import gc + sage: _ = gc.collect() sage: start_mem = get_memory_usage() sage: for _ in range(10): ....: make_bip_graph(A) + sage: _ = gc.collect() sage: print(round(get_memory_usage() - start_mem)) 0.0 """ diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 885fe8572e3..1925fd80a0e 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -6590,6 +6590,12 @@ cdef class Matrix(Matrix1): doctest:...: DeprecationWarning: "extend" should be used as keyword argument See https://trac.sagemath.org/29243 for details. [] + + Check :trac:`30518`:: + + sage: K. = QuadraticField(-1) + sage: m = matrix(K, 4, [2,4*i,-i,0, -4*i,2,-1,0, 2*i,-2,0,0, 4*i+4, 4*i-4,1-i,-2]) + sage: assert all(m*v == e*v for e, vs, _ in m.eigenvectors_right() for v in vs) """ if other is not None: if isinstance(other, bool): diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 655fe2aac39..d101f6ab4b5 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -1590,10 +1590,10 @@ def kloosterman_sum(self, a=1, b=0): sage: G = DirichletGroup(12, QQbar) sage: e = G.gens()[0] + sage: e.kloosterman_sum(5, 4) + 0.?e-17 - 4.000000000000000?*I sage: e.kloosterman_sum(5,11) - Traceback (most recent call last): - ... - NotImplementedError: Kloosterman sums not implemented over this ring + 0 """ G = self.parent() zo = G.zeta_order() diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 24766d3fdda..7de14e8d774 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -764,7 +764,6 @@ def dual_lattice(self): """ return self.span(self.gram_matrix().inverse()*self.basis_matrix()) - @cached_method def discriminant_group(self, s=0): r""" Return the discriminant group `L^\vee / L` of this lattice. @@ -803,6 +802,18 @@ def discriminant_group(self, s=0): Finite quadratic module over Integer Ring with invariants () Gram matrix of the quadratic form with values in Q/2Z: [] + + Test that the memory leak in :trac:`31625` is fixed:: + + sage: import gc + sage: L = IntegralLattice("A2") + sage: for k in range(1,500): + ....: G = L.twist(k) + ....: D = G.discriminant_group() + sage: tmp = gc.collect() + sage: tmp = gc.collect() + sage: len([a for a in gc.get_objects() if type(a)==type(L)])<=300 + True """ from sage.modules.torsion_quadratic_module import TorsionQuadraticModule D = TorsionQuadraticModule(self.dual_lattice(), self) diff --git a/src/sage/modules/torsion_quadratic_module.py b/src/sage/modules/torsion_quadratic_module.py index 39e7065ac48..27a019554e4 100644 --- a/src/sage/modules/torsion_quadratic_module.py +++ b/src/sage/modules/torsion_quadratic_module.py @@ -867,26 +867,24 @@ def orthogonal_group(self, gens=None, check=False): from sage.groups.fqf_orthogonal import FqfOrthogonalGroup,_isom_fqf from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap + ambient = AbelianGroupGap(self.invariants()).aut() # slow brute force implementation - flag = False if gens is None: try: - return self._orthogonal_group + gens = self._orthogonal_group_gens except AttributeError: - flag = True gens = _isom_fqf(self) + gens = tuple(ambient(g) for g in gens) + self._orthogonal_group_gens = gens else: # see if there is an action try: gens = [matrix(x*g for x in self.smith_form_gens()) for g in gens] except TypeError: - pass - ambient = AbelianGroupGap(self.invariants()).aut() - # the ambient knows what to do with the generators - gens = tuple(ambient(g) for g in gens) + pass + # the ambient knows what to do with the generators + gens = tuple(ambient(g) for g in gens) Oq = FqfOrthogonalGroup(ambient, gens, self, check=check) - if flag: - self._orthogonal_group = Oq return Oq def orthogonal_submodule_to(self, S): diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index 79a9390c354..d25d93faf56 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -18,7 +18,6 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** -from copy import deepcopy from sage.plot.primitive import GraphicPrimitive_xydata from sage.misc.decorators import options, rename_keyword from sage.plot.colors import to_mpl_color @@ -35,7 +34,7 @@ class BezierPath(GraphicPrimitive_xydata): sage: from sage.plot.bezier_path import BezierPath sage: BezierPath([[(0,0), (.5,.5),(1,0)],[(.5,1),(0,0)]], {'linestyle':'dashed'}) - Bezier path from (0, 0) to (0, 0) + Bezier path from (0.0, 0.0) to (0.0, 0.0) We use :func:`bezier_path` to actually plot Bezier curves:: @@ -56,17 +55,44 @@ def __init__(self, path, options): sage: from sage.plot.bezier_path import BezierPath sage: BezierPath([[(0,0),(.5,.5),(1,0)],[(.5,1),(0,0)]], {'linestyle':'dashed'}) - Bezier path from (0, 0) to (0, 0) + Bezier path from (0.0, 0.0) to (0.0, 0.0) + + sage: BezierPath([[(0,0), (1,2), (3,6), (2,-1), (3,3)]], {}) + Traceback (most recent call last): + ... + ValueError: invalid input for BezierPath + + TESTS: + + Check :trac:`31646`:: + + sage: from sage.plot.bezier_path import BezierPath + sage: p2d = [[(3,0),(4,1),(2,1),(3,0)], [(2,2),(3,1),(2,1)]] + sage: P = BezierPath(p2d, {}) + sage: P.path + [array([[3., 0.], [4., 1.], [2., 1.], [3., 0.]]), + array([[2., 2.], [3., 1.], [2., 1.]])] """ import numpy as np - self.path = deepcopy(path) - codes = [1] + (len(self.path[0])-1)*[len(self.path[0])] - vertices = self.path[0] - for curve in self.path[1:]: - vertices += curve - codes += (len(curve)) * [len(curve)+1] + + self.path = [np.array(l, float) for l in path] + + # In oder to feed later to matplotlib.path.Path we convert in the following form + # - vertices: an Nx2 float array of vertices + # - codes: an N-length uint8 array of vertex types, or None + # where each code could be MOVETO (=1), LINETO (=2), CURVE3 (=3), CURVE4 (=4) + self.vertices = np.concatenate(self.path) + N, _ = self.vertices.shape + codes = np.zeros((N,), np.uint8) + k = 0 + for i, curve in enumerate(self.path): + code = len(curve) + (i > 0) + if code < 2 or code > 4: + raise ValueError('invalid input for BezierPath') + codes[k:k+len(curve)] = code + k += len(curve) + codes[0] = 1 # MOVETO self.codes = codes - self.vertices = np.array(vertices, float) GraphicPrimitive_xydata.__init__(self, options) def _allowed_options(self): @@ -178,9 +204,11 @@ def _repr_(self): sage: from sage.plot.bezier_path import BezierPath sage: B = BezierPath([[(0,0),(.5,.5),(1,0)],[(.5,1),(0,0)]], {'linestyle':'dashed'}) sage: B._repr_() - 'Bezier path from (0, 0) to (0, 0)' + 'Bezier path from (0.0, 0.0) to (0.0, 0.0)' """ - return "Bezier path from %s to %s" % (self.path[0][0], self.path[-1][-1]) + x0, y0 = self.vertices[0] + x1, y1 = self.vertices[-1] + return "Bezier path from (%s, %s) to (%s, %s)" % (x0, y0, x1, y1) def _render_on_subplot(self, subplot): """ diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index 7c29e3eea0d..9a7571fd113 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -1357,10 +1357,11 @@ cdef class IndexFaceSet(PrimitiveObject): sage: G = polygon([(0,0,1), (1,1,1), (2,0,1)], color='red', opacity=0.5, ....: render_order=2, threejs_flat_shading=True, - ....: single_side=True, mesh=True, thickness=10) + ....: single_side=True, mesh=True, thickness=10, depth_write=True) sage: G.threejs_repr(G.default_render_params()) [('surface', {'color': '#ff0000', + 'depthWrite': True, 'faces': [[0, 1, 2]], 'linewidth': 10.0, 'opacity': 0.5, @@ -1455,6 +1456,9 @@ cdef class IndexFaceSet(PrimitiveObject): if self._extra_kwds.get('thickness'): surface['linewidth'] = float(self._extra_kwds['thickness']) + if 'depth_write' in self._extra_kwds: + surface['depthWrite'] = bool(self._extra_kwds['depth_write']) + return [('surface', surface)] def obj_repr(self, render_params): diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index c78b92618c3..eb91f880a8e 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -225,6 +225,19 @@ def bezier3d(path, **options): sage: curve = bezier3d(path, thickness=5, color='blue') sage: curve Graphics3d Object + + TESTS: + + Check for :trac:`31640`:: + + sage: p2d = [[(3,0.0),(3,0.13),(2,0.2),(2,0.3)], [(2.7,0.4),(2.6,0.5),(2.5,0.5)], [(2.3,0.5),(2.2,0.4),(2.1,0.3)]] + sage: bp = bezier_path(p2d) + sage: bp.plot3d() + Graphics3d Object + + sage: p3d = p3d = [[(3,0,0),(3,0.1,0),(2.9,0.2,0),(2.8,0.3,0)], [(2.7,0.4,0),(2,0.5,0),(2.5,0.5,0)], [(2.3,0.5,0),(2.2,0.4,0),(2.1,0.3,0)]] + sage: bezier3d(p3d) + Graphics3d Object """ from . import parametric_plot3d as P3D from sage.modules.free_module_element import vector @@ -247,7 +260,7 @@ def bezier3d(path, **options): G += P3D.parametric_plot3d(list(B), (0, 1), color=options['color'], aspect_ratio=options['aspect_ratio'], thickness=options['thickness'], opacity=options['opacity']) else: G += line3d([p0,curve[0]], color=options['color'], thickness=options['thickness'], opacity=options['opacity']) - p0 = curve[-1] + p0 = vector(curve[-1]) return G @rename_keyword(alpha='opacity') diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index 52db870239f..94f882ee933 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -150,6 +150,10 @@ def default(self): InteractiveShell=InteractiveShell, TerminalInteractiveShell=InteractiveShell, InteractiveShellApp=Config(extensions=[SAGE_EXTENSION]), + # TODO: jedi is disabled by default because it causes too many troubles + # disabling ticket: https://trac.sagemath.org/ticket/31648 + # reenabling ticket: https://trac.sagemath.org/ticket/31649 + IPCompleter=Config(use_jedi=False), ) if self._doctest_mode(): # Using the file-backed history causes problems in parallel tests diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 8167c524522..29932830f3c 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -2789,6 +2789,10 @@ cdef class NumberFieldElement(FieldElement): sage: E = C.algebraic_closure() sage: E(a) -4.949886207424724? - 0.2195628712241434?*I + + sage: NF. = QuadraticField(2) + sage: AA(sqrt2) + 1.414213562373095? """ if self.is_rational(): return parent(self._rational_()) diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 238879061ae..d212e106165 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -1706,29 +1706,6 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpq_canonicalize(res.value) return res - def _algebraic_(self, parent): - r""" - Convert this element to an algebraic number, if possible. - - EXAMPLES:: - - sage: NF. = QuadraticField(-1) - sage: QQbar(1+i) - I + 1 - sage: NF. = QuadraticField(2) - sage: AA(sqrt3) - 1.414213562373095? - """ - import sage.rings.qqbar as qqbar - if (parent is qqbar.QQbar - and list(self._parent.polynomial()) == [1, 0, 1]): - # AlgebraicNumber.__init__ does a better job than - # NumberFieldElement._algebraic_ in this case, but - # QQbar._element_constructor_ calls the latter first. - return qqbar.AlgebraicNumber(self) - else: - return NumberFieldElement._algebraic_(self, parent) - cpdef bint is_one(self): r""" Check whether this number field element is `1`. @@ -2417,6 +2394,34 @@ cdef class NumberFieldElement_gaussian(NumberFieldElement_quadratic): from sage.symbolic.constants import I return self[1]*(I if self.standard_embedding else -I) + self[0] + def _algebraic_(self, parent): + r""" + Convert this element to an algebraic number, if possible. + + EXAMPLES:: + + sage: NF. = QuadraticField(-1) + sage: QQbar(i+2) + I + 2 + sage: K. = QuadraticField(-1, embedding=CC(0,-1)) + sage: QQbar(ii+2) + -I + 2 + sage: AA(i) + Traceback (most recent call last): + ... + ValueError: unable to convert i to an element of Algebraic Real Field + """ + import sage.rings.qqbar as qqbar + if parent is qqbar.QQbar: + # AlgebraicNumber.__init__ does a better job than + # NumberFieldElement._algebraic_ in this case, but + # QQbar._element_constructor_ calls the latter first. + return qqbar.AlgebraicNumber(self) + elif parent is qqbar.AA and self[1].is_zero(): + return qqbar.AlgebraicReal(self) + else: + raise ValueError(f"unable to convert {self!r} to an element of {parent!r}") + cpdef real_part(self): r""" Real part. diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 671644effc8..81e333be4f5 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -115,10 +115,6 @@ 3.146264369941973? sage: QQbar(I) I - sage: AA(I) - Traceback (most recent call last): - ... - ValueError: Cannot coerce algebraic number with non-zero imaginary part to algebraic real sage: QQbar(I * golden_ratio) 1.618033988749895?*I sage: AA(golden_ratio)^2 - AA(golden_ratio) @@ -150,24 +146,30 @@ sage: QQbar(-1)^(1/3) 0.500000000000000? + 0.866025403784439?*I -We can explicitly coerce from `\QQ[I]`. (Technically, this is not quite -kosher, since `\QQ[I]` does not come with an embedding; we do not know -whether the field generator is supposed to map to `+I` or `-I`. We assume -that for any quadratic field with polynomial `x^2+1`, the generator maps -to `+I`.):: - - sage: K. = QQ[I] - sage: pythag = QQbar(3/5 + 4*im/5); pythag - 4/5*I + 3/5 - sage: pythag.abs() == 1 - True +However, implicit coercion from `\QQ[I]` is only allowed when it is equipped +with a complex embedding:: -However, implicit coercion from `\QQ[I]` is not allowed:: + sage: i.parent() + Number Field in I with defining polynomial x^2 + 1 with I = 1*I + sage: QQbar(1) + i + I + 1 + sage: K. = QuadraticField(-1, embedding=None) sage: QQbar(1) + im Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Algebraic Field' and 'Number Field in I with defining polynomial x^2 + 1 with I = 1*I' + TypeError: unsupported operand parent(s) for +: 'Algebraic Field' and + 'Number Field in im with defining polynomial x^2 + 1' + +However, we can explicitly coerce from the abstract number field `\QQ[I]`. +(Technically, this is not quite kosher, since we do not know whether the field +generator is supposed to map to `+I` or `-I`. We assume that for any quadratic +field with polynomial `x^2+1`, the generator maps to `+I`.):: + + sage: pythag = QQbar(3/5 + 4*im/5); pythag + 4/5*I + 3/5 + sage: pythag.abs() == 1 + True We can implicitly coerce from algebraic reals to algebraic numbers:: @@ -553,8 +555,10 @@ import operator import sage.rings.ring +import sage.rings.number_field.number_field_base from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method +from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical from sage.structure.sage_object import SageObject from sage.structure.richcmp import (richcmp, richcmp_method, rich_to_bool, richcmp_not_equal, @@ -569,7 +573,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.number_field.number_field import NumberField, GaussianField, CyclotomicField -from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic +from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic, NumberFieldElement_gaussian from sage.arith.all import factor from . import infinity from sage.categories.action import Action @@ -1063,9 +1067,17 @@ def __init__(self): sage: QQbar.category() # indirect doctest Category of infinite fields + + Coercions:: + + sage: AA.has_coerce_map_from(ZZ) + True + sage: AA.has_coerce_map_from(int) + True """ from sage.categories.fields import Fields AlgebraicField_common.__init__(self, self, ('x',), normalize=False, category=Fields().Infinite()) + self._populate_coercion_lists_([ZZ, QQ]) def _element_constructor_(self, x): r""" @@ -1157,8 +1169,6 @@ def _coerce_map_from_(self, from_par): TESTS:: - sage: AA.has_coerce_map_from(ZZ) # indirect doctest - True sage: K. = QuadraticField(7, embedding=AA(7).sqrt()); AA.has_coerce_map_from(K) True sage: a in AA @@ -1167,9 +1177,23 @@ def _coerce_map_from_(self, from_par): 5.645751311064590? sage: AA.has_coerce_map_from(SR) False + + sage: K = NumberField(x^3 - 2, 'a', embedding=2.**(1/3)) + sage: AA.has_coerce_map_from(K) + True + sage: K. = QuadraticField(3, embedding=-2.) + sage: s + AA(1) + -0.732050807568878? + sage: K. = QuadraticField(3, embedding=2.) + sage: s + AA(1) + 2.732050807568878? + sage: K. = QuadraticField(-5) + sage: AA.has_coerce_map_from(K) + False """ - return (from_par is ZZ or from_par is QQ - or from_par is AA) + if isinstance(from_par, sage.rings.number_field.number_field_base.NumberField): + emb = from_par.coerce_embedding() + return emb is not None and parent_is_real_numerical(emb.codomain()) def completion(self, p, prec, extras={}): r""" @@ -1497,9 +1521,15 @@ def __init__(self): sage: QQbar._repr_option('element_is_atomic') False + + sage: QQbar.has_coerce_map_from(ZZ) + True + sage: QQbar.has_coerce_map_from(int) + True """ from sage.categories.fields import Fields AlgebraicField_common.__init__(self, AA, ('I',), normalize=False, category=Fields().Infinite()) + self._populate_coercion_lists_([ZZ, QQ]) def _element_constructor_(self, x): """ @@ -1565,17 +1595,28 @@ def _coerce_map_from_(self, from_par): TESTS:: - sage: QQbar.has_coerce_map_from(ZZ) # indirect doctest - True sage: QQbar.has_coerce_map_from(AA) True sage: QQbar.has_coerce_map_from(CC) False sage: QQbar.has_coerce_map_from(SR) False + + sage: i + QQbar(2) + I + 2 + sage: K. = QuadraticField(-1, embedding=ComplexField(13)(0,-1)) + sage: ii + QQbar(2) + -I + 2 + + sage: L. = QuadraticField(-1, embedding=Zp(5).teichmuller(2)) + sage: QQbar.has_coerce_map_from(L) + False """ - return (from_par is ZZ or from_par is QQ - or from_par is AA or from_par is QQbar) + if from_par is AA: + return True + if isinstance(from_par, sage.rings.number_field.number_field_base.NumberField): + emb = from_par.coerce_embedding() + return emb is not None and parent_is_numerical(emb.codomain()) def completion(self, p, prec, extras={}): r""" @@ -3453,10 +3494,11 @@ def __init__(self, parent, x): self._descr = ANRational(x) elif isinstance(x, ANDescr): self._descr = x - elif parent is QQbar and \ - isinstance(x, NumberFieldElement_quadratic) and \ - list(x.parent().polynomial()) == [1, 0, 1]: - self._descr = ANExtensionElement(QQbar_I_generator, QQbar_I_nf(x.list())) + elif parent is QQbar and isinstance(x, NumberFieldElement_gaussian): + if x.parent()._standard_embedding: + self._descr = ANExtensionElement(QQbar_I_generator, QQbar_I_nf(x.list())) + else: + self._descr = ANExtensionElement(QQbar_I_generator, QQbar_I_nf([x[0], -x[1]])) else: raise TypeError("Illegal initializer for algebraic number") diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 6246c865b66..f81c4ff9717 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -3150,13 +3150,6 @@ cdef class Expression(CommutativeRingElement): sage: bool(f(x) - f(x) == 0) True - Check that we catch exceptions from Pynac (:trac:`19904`):: - - sage: bool(SR(QQbar(I)) == I) - Traceback (most recent call last): - ... - TypeError: unsupported operand parent(s)... - Check that :trac:`24658` is fixed:: sage: val = pi - 2286635172367940241408/1029347477390786609545*sqrt(2) @@ -4564,6 +4557,11 @@ cdef class Expression(CommutativeRingElement): sage: (1/(1-2*x)).series(x) 1 + 2*x + 4*x^2 + Order(x^3) sage: set_series_precision(20) + + Check that :trac:`31645` is fixed:: + + sage: (x^(-1) + 1).series(x,1) + 1*x^(-1) + 1 + Order(x) """ cdef Expression symbol0 = self.coerce_in(symbol) cdef GEx x @@ -4875,6 +4873,22 @@ cdef class Expression(CommutativeRingElement): sage: ((-x)^(3/4)).expand() (-x)^(3/4) sage: forget() + + Check that :trac:`31077` is fixed (also see :trac:`31679`):: + + sage: a,b,c,d = var("a b c d") + sage: f = ((a + b + c)^30 * (3*b + d - 5/d)^3).expand().subs(a=0,b=2,c=-1) + sage: sum(sign(s) * (abs(ZZ(s)) % ZZ(2^30)) * d^i for s,i in f.coefficients()) + d^3 + 18*d^2 + 93*d - 465/d + 450/d^2 - 125/d^3 + 36 + + Check that :trac:`31411` is fixed:: + + sage: q, j = var("q, j") + sage: A = q^(2/3) + q^(2/5) + sage: B = product(1 - q^j, j, 1, 31) * q^(1/24) + sage: bool((A * B).expand() == (A * B.expand()).expand()) + True # 64-bit + True # 32-bit # known bug (#31585) """ if side is not None: if not is_a_relational(self._gobj): diff --git a/src/sage/version.py b/src/sage/version.py index 3e211b80c0e..fd6e15e31ff 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 = '9.3.rc3' -date = '2021-04-12' -banner = 'SageMath version 9.3.rc3, Release Date: 2021-04-12' +version = '9.3' +date = '2021-05-09' +banner = 'SageMath version 9.3, Release Date: 2021-05-09' diff --git a/tox.ini b/tox.ini index 1d7534148ef..702c8be311e 100644 --- a/tox.ini +++ b/tox.ini @@ -103,7 +103,7 @@ passenv = TARGETS_PRE TARGETS_OPTIONAL docker: EXTRA_DOCKER_BUILD_ARGS - # Use DOCKER_BUILDKIT=1 for new version + # Use DOCKER_BUILDKIT=1 for new version - for which unfortunately we cannot save failed builds as an image docker: DOCKER_BUILDKIT # Set for example to "with-system-packages configured with-targets-pre with-targets" # to tag intermediate images. @@ -322,29 +322,31 @@ setenv = # manylinux. # https://github.com/pypa/manylinux # - # There are manylinux-1, manylinux-2010, and manylinux-2014. + # There are manylinux-1, manylinux-2010, manylinux-2014, and manylinux_2_24. # manylinux-1 is too old - it only has python2.4, which is not supported by - # sage_bootstrap. + # sage_bootstrap; it will reach its EOL on Jan 1, 2022. # Our default is manylinux-2014. # - # Default arch is x86_64. Use -i686 for 32-bit build. manylinux-2014 supports more archs. + # Default arch is x86_64. Use -i686 (or our alias -i386) for 32-bit build. + # manylinux-2014 and newer support more archs. # manylinux: SYSTEM=fedora manylinux: IGNORE_MISSING_SYSTEM_PACKAGES=yes - # temporarily because we do not have autotools, we have to patch the downloaded - # configure tarball. The sed command can be removed once the relaxed version check - # in build/pkgs/xz/spkg-configure.m4 has been included in a release. - manylinux: BOOTSTRAP=./bootstrap -D && sed -i.bak s/5[.]0[.]0/4.999.0/ configure manylinux: BASE_IMAGE=quay.io/pypa/manylinux2014 manylinux-1: BASE_IMAGE=quay.io/pypa/manylinux1 + manylinux-1: BOOTSTRAP=./bootstrap -D manylinux-2010: BASE_IMAGE=quay.io/pypa/manylinux2010 manylinux-2014: BASE_IMAGE=quay.io/pypa/manylinux2014 + manylinux-2_24: SYSTEM=debian + manylinux-2_24: BASE_IMAGE=quay.io/pypa/manylinux_2_24 + manylinux-2_24: BOOTSTRAP=ACLOCAL_PATH=/usr/share/aclocal ./bootstrap manylinux: ARCH_IMAGE_PREFIX= manylinux: ARCH_IMAGE_SUFFIX=_x86_64 manylinux-i686: ARCH_IMAGE_SUFFIX=_i686 - manylinux-2014-aarch64: ARCH_IMAGE_SUFFIX=_aarch64 - manylinux-2014-ppc64le: ARCH_IMAGE_SUFFIX=_ppc64le - manylinux-2014-s390x: ARCH_IMAGE_SUFFIX=_s390x + manylinux-i386: ARCH_IMAGE_SUFFIX=_i686 + manylinux-aarch64: ARCH_IMAGE_SUFFIX=_aarch64 + manylinux-ppc64le: ARCH_IMAGE_SUFFIX=_ppc64le + manylinux-s390x: ARCH_IMAGE_SUFFIX=_s390x # # Resulting full image:tag name # @@ -474,6 +476,7 @@ commands = docker-{arm64,armhf}: docker run --rm --privileged multiarch/qemu-user-static:register --reset docker: bash -c 'for docker_target in {env:DOCKER_TARGETS:with-targets}; do \ docker: BUILD_TAG={env:DOCKER_PUSH_REPOSITORY:}sage-{envname}-$docker_target:$(git describe --dirty --always); \ + docker: DOCKER_BUILDKIT={env:DOCKER_BUILDKIT:0} \ docker: docker build . -f {envdir}/Dockerfile \ docker: --target $docker_target \ docker: --tag $BUILD_TAG \