diff --git a/.homebrew-build-env b/.homebrew-build-env index 29f0ba3b304..e0e892f4471 100644 --- a/.homebrew-build-env +++ b/.homebrew-build-env @@ -2,7 +2,7 @@ # that activate keg-only homebrew package installations HOMEBREW=`brew --prefix` || return 1 -for l in gettext bzip2 texinfo; do +for l in gettext bzip2 texinfo polymake; do if [ -d "$HOMEBREW/opt/$l/bin" ]; then PATH="$HOMEBREW/opt/$l/bin:$PATH" fi @@ -23,7 +23,7 @@ export PKG_CONFIG_PATH LIBRARY_PATH="$HOMEBREW/lib$LIBRARY_PATH" [ -z "$CPATH" ] || CPATH=":${CPATH}" CPATH="$HOMEBREW/include$CPATH" -for l in readline bzip2 ntl; do +for l in readline bzip2 ntl polymake; do if [ -d "$HOMEBREW/opt/$l/lib" ]; then LIBRARY_PATH="$HOMEBREW/opt/$l/lib:$LIBRARY_PATH" fi diff --git a/.zenodo.json b/.zenodo.json index 4a9c0e96236..489c739efdd 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.5.beta5", - "version": "9.5.beta5", + "title": "sagemath/sage: 9.5.beta6", + "version": "9.5.beta6", "upload_type": "software", - "publication_date": "2021-10-28", + "publication_date": "2021-11-12", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.5.beta5", + "identifier": "https://github.com/sagemath/sage/tree/9.5.beta6", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index c79c2d06798..b437f328147 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.5.beta5, Release Date: 2021-10-28 +SageMath version 9.5.beta6, Release Date: 2021-11-12 diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 9980b4e22d2..704985a5e37 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -56,11 +56,12 @@ # be given as arguments. If $SAGE_DESTDIR is not set then the command is # run with $SAGE_SUDO, if set. # -# - sdh_pip_install [...] +# - sdh_pip_install [--no-deps] [--build-isolation] [...] # -# Runs `pip install` with the given arguments, as well as additional -# default arguments used for installing packages into Sage with pip. -# Currently this is just a wrapper around the `sage-pip-install` command. +# Builds a wheel using `pip wheel` with the given options [...], then installs +# the wheel. Unless the special option --build-isolation is given, +# the wheel is built using the option --no-build-isolation. +# If the special option --no-deps is given, it is passed to pip install. # If $SAGE_DESTDIR is not set then the command is run with $SAGE_SUDO, if # set. # @@ -240,10 +241,31 @@ sdh_pip_install() { echo "Installing $PKG_NAME" mkdir -p dist rm -f dist/*.whl - python3 -m pip wheel --use-feature=in-tree-build --wheel-dir=dist --no-binary :all: --verbose --no-deps --no-index --isolated --no-build-isolation --ignore-requires-python "$@" || \ + install_options="" + # pip has --no-build-isolation but no flag that turns the default back on... + build_isolation_option="--no-build-isolation --no-binary :all:" + while [ $# -gt 0 ]; do + case "$1" in + --build-isolation) + # If a package requests build isolation, we allow it to provision + # its build environment using the stored wheels. + # We pass --find-links and remove the --no-binary option. + # The SPKG needs to declare "setuptools_wheel" as a dependency. + build_isolation_option="--find-links=$SAGE_SPKG_WHEELS" + ;; + --no-deps) + install_options="$install_options $1" + ;; + *) + break + ;; + esac + shift + done + python3 -m pip wheel --use-feature=in-tree-build --wheel-dir=dist --verbose --no-deps --no-index --isolated --ignore-requires-python $build_isolation_option "$@" || \ sdh_die "Error building a wheel for $PKG_NAME" - sdh_store_and_pip_install_wheel . + sdh_store_and_pip_install_wheel $install_options . } sdh_store_wheel() { diff --git a/build/bin/sage-spkg b/build/bin/sage-spkg index 7f390e3a0f2..5d9a763a13e 100755 --- a/build/bin/sage-spkg +++ b/build/bin/sage-spkg @@ -498,7 +498,7 @@ export PKG_NAME="$PKG_NAME" export PKG_BASE="$PKG_BASE" export PKG_VER="$PKG_VER" -for lib in "\$SAGE_ROOT/build/bin/sage-dist-helpers" "\$SAGE_SRC/bin/sage-env-config" "\$SAGE_SRC/bin/sage-env" "\$SAGE_ROOT/build/bin/sage-build-env-config" "\$SAGE_ROOT/build/bin/sage-build-env"; do +for lib in "\$SAGE_ROOT/build/bin/sage-dist-helpers" "\$SAGE_SRC/bin/sage-src-env-config" "\$SAGE_SRC/bin/sage-env-config" "\$SAGE_SRC/bin/sage-env" "\$SAGE_ROOT/build/bin/sage-build-env-config" "\$SAGE_ROOT/build/bin/sage-build-env"; do source "\$lib" if [ \$? -ne 0 ]; then echo >&2 "Error: failed to source \$lib" @@ -506,7 +506,6 @@ for lib in "\$SAGE_ROOT/build/bin/sage-dist-helpers" "\$SAGE_SRC/bin/sage-env-co exit 1 fi done -export PATH="$SAGE_INST_LOCAL/bin:$PATH" export SAGE_INST_LOCAL="$SAGE_INST_LOCAL" @@ -773,6 +772,7 @@ if [ "$SAGE_CHECK" = "yes" -o "$SAGE_CHECK" = "warn" ]; then if [ $? -ne 0 ]; then TEST_SUITE_RESULT="failed" if [ "$SAGE_CHECK" = "warn" ]; then + # The following warning message must be consistent with SAGE_ROOT/build/make/install (see trac:32781) error_msg "Warning: Failures testing package $PKG_NAME (ignored)" "make check" else error_msg "Error testing package $PKG_NAME" "make check" diff --git a/build/make/install b/build/make/install index 1d17884c1ba..eaf6ed7b47a 100755 --- a/build/make/install +++ b/build/make/install @@ -122,7 +122,8 @@ EOF elif [ "$SAGE_CHECK" = "warn" ]; then echo "SAGE_CHECK=warn, so scanning the log files. This may take a few seconds." - warnings=`look_for_errors "$SAGE_LOGS/*.log" 20 "^Warning: Error testing" package` + # The following warning message must be consistent with SAGE_ROOT/build/bin/sage-spkg (see trac:32781) + warnings=`look_for_errors "$SAGE_LOGS/*.log" 20 "^Warning: Failures testing package" package` if [ -n "$warnings" ]; then cat >&2 < +Date: Sun, 24 Oct 2021 23:57:06 +0200 +Subject: [PATCH] Revert #3252 + +--- + interface/trsv.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/interface/trsv.c b/interface/trsv.c +index 6a6e8f8bab..a054d8eeb6 100644 +--- a/interface/trsv.c ++++ b/interface/trsv.c +@@ -188,12 +188,6 @@ void CNAME(enum CBLAS_ORDER order, enum CBLAS_UPLO Uplo, + + if (n == 0) return; + +- if (incx == 1 && trans == 0 && n < 50) { +- buffer = NULL; +- (trsv[(trans<<2) | (uplo<<1) | unit])(n, a, lda, x, incx, buffer); +- return; +- } +- + IDEBUG_START; + + FUNCTION_PROFILE_START(); \ No newline at end of file diff --git a/build/pkgs/openblas/spkg-install.in b/build/pkgs/openblas/spkg-install.in index b06a55d3130..f6ac7753838 100644 --- a/build/pkgs/openblas/spkg-install.in +++ b/build/pkgs/openblas/spkg-install.in @@ -14,6 +14,22 @@ fi if [ "x$SAGE_FAT_BINARY" = "xyes" ]; then OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE DYNAMIC_ARCH=1" + machine=$($CC -dumpmachine) + if [[ $machine =~ x86_64-apple-darwin* ]]; then + OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE TARGET=CORE2" + elif [[ $os-$machine =~ arm64-apple-darwin* ]]; then + OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE TARGET=VORTEX" + elif [[ $machine =~ (x86_64|amd64)-* ]]; then + OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE TARGET=PRESCOTT" + elif [[ $machine =~ (i386|i486|i586|i686)-* ]]; then + OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE TARGET=KATMAI" + elif [[ $machine =~ (ppc64le|powerpc64le)-* ]]; then + OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE TARGET=POWER8" + elif [[ $machine =~ ppc64-* ]]; then + OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE TARGET=POWER6" + elif [[ $machine =~ aarch64-* ]]; then + OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE TARGET=ARMV8" + fi fi echo "Building OpenBLAS: $MAKE $OPENBLAS_CONFIGURE" @@ -21,9 +37,6 @@ echo "Building OpenBLAS: $MAKE $OPENBLAS_CONFIGURE" # Ensure USE_TLS=1 ; see https://trac.sagemath.org/ticket/27256 OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE USE_TLS=1" -# Disable AVX512 for now, see https://trac.sagemath.org/ticket/27961 -OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE NO_AVX512=1" - if ! (sdh_make libs netlib shared $OPENBLAS_CONFIGURE); then if [[ $OPENBLAS_CONFIGURE == *"TARGET"* ]]; then sdh_die "Error building OpenBLAS" diff --git a/build/pkgs/packaging/dependencies b/build/pkgs/packaging/dependencies index 4818dfe9b48..2c5e2481b17 100644 --- a/build/pkgs/packaging/dependencies +++ b/build/pkgs/packaging/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | setuptools pip wheel pyparsing +$(PYTHON) | setuptools pip wheel pyparsing setuptools_wheel ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/packaging/spkg-install.in b/build/pkgs/packaging/spkg-install.in index deba1bb42bb..dd9cb64a082 100644 --- a/build/pkgs/packaging/spkg-install.in +++ b/build/pkgs/packaging/spkg-install.in @@ -1 +1 @@ -cd src && sdh_pip_install . +cd src && sdh_pip_install --build-isolation . diff --git a/build/pkgs/pdf2svg/SPKG.rst b/build/pkgs/pdf2svg/SPKG.rst new file mode 100644 index 00000000000..2a87b276be0 --- /dev/null +++ b/build/pkgs/pdf2svg/SPKG.rst @@ -0,0 +1,19 @@ +pdf2svg - PDF to SVG convertor +============================== + +Description +----------- + +pdf2svg is a tiny command-line utility using Cairo and Poppler to convert PDF +documents into SVG files. Multi-page PDF can be split up to one SVG per page by +passing a file naming specification. + +License +------- + +GPL + +Upstream Contact +---------------- + +http://cityinthesky.co.uk/opensource/pdf2svg/ diff --git a/build/pkgs/pdf2svg/distros/alpine.txt b/build/pkgs/pdf2svg/distros/alpine.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/alpine.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/arch.txt b/build/pkgs/pdf2svg/distros/arch.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/arch.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/conda.txt b/build/pkgs/pdf2svg/distros/conda.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/conda.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/cygwin.txt b/build/pkgs/pdf2svg/distros/cygwin.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/cygwin.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/debian.txt b/build/pkgs/pdf2svg/distros/debian.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/debian.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/fedora.txt b/build/pkgs/pdf2svg/distros/fedora.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/fedora.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/freebsd.txt b/build/pkgs/pdf2svg/distros/freebsd.txt new file mode 100644 index 00000000000..225444481b8 --- /dev/null +++ b/build/pkgs/pdf2svg/distros/freebsd.txt @@ -0,0 +1 @@ +graphics/pdf2svg diff --git a/build/pkgs/pdf2svg/distros/homebrew.txt b/build/pkgs/pdf2svg/distros/homebrew.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/homebrew.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/macports.txt b/build/pkgs/pdf2svg/distros/macports.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/macports.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/nix.txt b/build/pkgs/pdf2svg/distros/nix.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/nix.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/opensuse.txt b/build/pkgs/pdf2svg/distros/opensuse.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/opensuse.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/repology.txt b/build/pkgs/pdf2svg/distros/repology.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/repology.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/distros/void.txt b/build/pkgs/pdf2svg/distros/void.txt new file mode 100644 index 00000000000..52c66a99cbf --- /dev/null +++ b/build/pkgs/pdf2svg/distros/void.txt @@ -0,0 +1 @@ +pdf2svg diff --git a/build/pkgs/pdf2svg/spkg-configure.m4 b/build/pkgs/pdf2svg/spkg-configure.m4 new file mode 100644 index 00000000000..88eedf2ec02 --- /dev/null +++ b/build/pkgs/pdf2svg/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([pdf2svg], [ + AC_PATH_PROG([PDF2SVG], [pdf2svg]) + AS_IF([test -z "$ac_cv_path_PDF2SVG"], [sage_spkg_install_pdf2svg=yes]) +]) + diff --git a/build/pkgs/pdf2svg/type b/build/pkgs/pdf2svg/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/pdf2svg/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt b/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt index c7390e63993..da97cd97866 100644 --- a/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt +++ b/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt @@ -2,7 +2,7 @@ perl-ExtUtils-Embed perl-File-Slurp perl-JSON perl-Term-ReadLine-Gnu -perl-Term-ReadKey +perl-TermReadKey perl-XML-Writer perl-XML-LibXML perl-XML-LibXSLT diff --git a/build/pkgs/polymake/dependencies b/build/pkgs/polymake/dependencies index 3572f765d54..7d77b977a21 100644 --- a/build/pkgs/polymake/dependencies +++ b/build/pkgs/polymake/dependencies @@ -1,4 +1,4 @@ -$(MP_LIBRARY) bliss cddlib lrslib normaliz perl_term_readline_gnu ppl perl_cpan_polymake_prereq libxml2 | ninja_build +$(MP_LIBRARY) bliss cddlib $(findstring lrslib,$(OPTIONAL_INSTALLED_PACKAGES)) normaliz perl_term_readline_gnu ppl perl_cpan_polymake_prereq libxml2 | ninja_build ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/polymake/distros/arch.txt b/build/pkgs/polymake/distros/arch.txt new file mode 100644 index 00000000000..2a9cc70b2f5 --- /dev/null +++ b/build/pkgs/polymake/distros/arch.txt @@ -0,0 +1 @@ +polymake diff --git a/build/pkgs/polymake/distros/debian.txt b/build/pkgs/polymake/distros/debian.txt new file mode 100644 index 00000000000..6b4b4327e45 --- /dev/null +++ b/build/pkgs/polymake/distros/debian.txt @@ -0,0 +1,2 @@ +polymake +libpolymake-dev diff --git a/build/pkgs/polymake/distros/fedora.txt b/build/pkgs/polymake/distros/fedora.txt new file mode 100644 index 00000000000..2a9cc70b2f5 --- /dev/null +++ b/build/pkgs/polymake/distros/fedora.txt @@ -0,0 +1 @@ +polymake diff --git a/build/pkgs/polymake/distros/homebrew.txt b/build/pkgs/polymake/distros/homebrew.txt new file mode 100644 index 00000000000..69a7629040a --- /dev/null +++ b/build/pkgs/polymake/distros/homebrew.txt @@ -0,0 +1 @@ +apaffenholz/polymake/polymake diff --git a/build/pkgs/polymake/distros/nix.txt b/build/pkgs/polymake/distros/nix.txt new file mode 100644 index 00000000000..2a9cc70b2f5 --- /dev/null +++ b/build/pkgs/polymake/distros/nix.txt @@ -0,0 +1 @@ +polymake diff --git a/build/pkgs/polymake/spkg-configure.m4 b/build/pkgs/polymake/spkg-configure.m4 new file mode 100644 index 00000000000..fb7be48bebb --- /dev/null +++ b/build/pkgs/polymake/spkg-configure.m4 @@ -0,0 +1,45 @@ +SAGE_SPKG_CONFIGURE([polymake], [ + dnl Need polymake >= 3.5 for "improve callable library compatibility with threads" + m4_pushdef([POLYMAKE_VERSION_MIN], [3.5]) + AC_CACHE_CHECK([for polymake-config >= ]POLYMAKE_VERSION_MIN, [ac_cv_path_POLYMAKE_CONFIG], [ + AC_PATH_PROGS_FEATURE_CHECK([POLYMAKE_CONFIG], [polymake-config], [ + polymake_config_version=$($ac_path_POLYMAKE_CONFIG --version 2>&1) + AS_IF([test -n "$polymake_config_version"], [ + AX_COMPARE_VERSION([$polymake_config_version], [ge], POLYMAKE_VERSION_MIN, [ + ac_cv_path_POLYMAKE_CONFIG="$ac_path_POLYMAKE_CONFIG" + ]) + ]) + ]) + ]) + AS_IF([test -z "$ac_cv_path_POLYMAKE_CONFIG"], + [sage_spkg_install_polymake=yes], + [AC_MSG_CHECKING([whether libpolymake works]) + AC_LANG_PUSH([C++]) + saved_CXX="$CXX" + saved_CPPFLAGS="$CPPFLAGS" + saved_LDFLAGS="$LDFLAGS" + CXX="$($ac_cv_path_POLYMAKE_CONFIG --cc)" + CPPFLAGS="$($ac_cv_path_POLYMAKE_CONFIG --includes) $($ac_cv_path_POLYMAKE_CONFIG --cflags) $CPPFLAGS" + LDFLAGS="-lpolymake $($ac_cv_path_POLYMAKE_CONFIG --ldflags) $LDFLAGS" + AC_RUN_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[ + polymake::Main* main_polymake_session = new polymake::Main; + main_polymake_session->shell_enable(); + main_polymake_session->set_application("polytope"); + ]] + )], [ + AC_MSG_RESULT([yes]) + sage_require_perl_cpan_polymake_prereq=no + sage_require_perl_term_readline_gnu=no + ], [ + AC_MSG_RESULT([no]) + sage_spkg_install_polymake=yes + ]) + CXX="$saved_CXX" + CPPFLAGS="$saved_CPPFLAGS" + LDFLAGS="$saved_LDFLAGS" + AC_LANG_POP([C++]) + ]) + m4_popdef([POLYMAKE_VERSION_MIN]) +]) diff --git a/build/pkgs/polymake/spkg-install.in b/build/pkgs/polymake/spkg-install.in index ff2e6718363..827409cccd2 100644 --- a/build/pkgs/polymake/spkg-install.in +++ b/build/pkgs/polymake/spkg-install.in @@ -15,11 +15,15 @@ case $(uname) in esac # 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. +if [ -x $SAGE_LOCAL/bin/lrs1 ]; then + more_configure_options="$more_configure_options --with-lrs=$SAGE_LOCAL" +fi + ./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/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 9d4666c07f4..01a931f5eb5 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1 +1 @@ -sage-setup +sage-setup ~= 9.5.b6 diff --git a/build/pkgs/sagelib/package-version.txt b/build/pkgs/sagelib/package-version.txt index 2b08eebb761..a72129631b5 100644 --- a/build/pkgs/sagelib/package-version.txt +++ b/build/pkgs/sagelib/package-version.txt @@ -1 +1 @@ -9.5.beta5 +9.5.beta6 diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index 1e11d51d901..fb7c047d6c6 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -52,6 +52,7 @@ include sage/misc/fast_methods.* include sage/misc/constant_function.* include sage/misc/call.* include sage/misc/bindable_class.* +include sage/misc/namespace_package.p* include sage/misc/verbose.* include sage/misc/repr.* diff --git a/src/VERSION.txt b/src/VERSION.txt index 2b08eebb761..a72129631b5 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.5.beta5 +9.5.beta6 diff --git a/src/bin/sage-env b/src/bin/sage-env index b4c0c6ea207..a0426df5233 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -131,7 +131,9 @@ fi # Don't execute the commands more than once for the same version of -# sage-env. Check this after checking the validity of SAGE_ROOT, but +# sage-env... for the same combination of SAGE_LOCAL and SAGE_VENV. +# +# Check this after checking the validity of SAGE_ROOT, but # before modifying its value. # # The idea of versioning is that SAGE_ENV_SOURCED will be set to a @@ -147,13 +149,14 @@ fi # - sage-5.4: version 2 (#13395) # - sage-5.10: version 3 (#14699) # - sage-6.0: version 4 (#14715) +# - sage-9.5: version 5 (#32745) # -SAGE_ENV_VERSION=4 +SAGE_ENV_VERSION="5:$SAGE_LOCAL:$SAGE_VENV" if [ "$SAGE_ENV_SOURCED" = "$SAGE_ENV_VERSION" ]; then # Already sourced, nothing to do. return 0 fi -export SAGE_ENV_SOURCED=$SAGE_ENV_VERSION +export SAGE_ENV_SOURCED="$SAGE_ENV_VERSION" if [ -n "$NEW_SAGE_ROOT" ]; then export SAGE_ROOT="$NEW_SAGE_ROOT" diff --git a/src/bin/sage-list-packages b/src/bin/sage-list-packages index f2e9331ca2e..813b1c0d648 100755 --- a/src/bin/sage-list-packages +++ b/src/bin/sage-list-packages @@ -91,16 +91,16 @@ else: if WARN: print(WARN) if args['installed_only']: - L = [pkg for pkg in L if pkg['installed']] + L = [pkg for pkg in L if pkg.is_installed()] elif args['not_installed_only']: - L = [pkg for pkg in L if not pkg['installed']] + L = [pkg for pkg in L if not pkg.is_installed()] -L.sort(key=lambda pkg: pkg['name']) +L.sort(key=lambda pkg: pkg.name) # print (while getting rid of None in versions) for pkg in L: - pkg['installed_version'] = pkg['installed_version'] or 'not_installed' - pkg['remote_version'] = pkg['remote_version'] or '?' - print(format_string.format(**pkg)) + pkg.installed_version = pkg.installed_version or 'not_installed' + pkg.remote_version = pkg.remote_version or '?' + print(format_string.format(**pkg._asdict())) if WARN: print(WARN) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index d7a416185f8..882456dd15d 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -156,7 +156,7 @@ if __name__ == "__main__": pytest_options = ["--import-mode", "importlib"] if args.verbose: pytest_options.append("-v") - exit_code_pytest = pytest.main(pytest_options + args) + exit_code_pytest = pytest.main(pytest_options + args.filenames) except ModuleNotFoundError: print("Pytest is not installed, skip checking tests that rely on it.") diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index ed215d6aeb0..547dbe14054 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.5.beta5' -SAGE_RELEASE_DATE='2021-10-28' -SAGE_VERSION_BANNER='SageMath version 9.5.beta5, Release Date: 2021-10-28' +SAGE_VERSION='9.5.beta6' +SAGE_RELEASE_DATE='2021-11-12' +SAGE_VERSION_BANNER='SageMath version 9.5.beta6, Release Date: 2021-11-12' diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index ab6cb1dbbab..534a0fdee43 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -1,6 +1,14 @@ Category Framework ================== +Introduction +------------ + +.. toctree:: + :maxdepth: 2 + + sage/categories + The Sage Category Framework --------------------------- diff --git a/src/doc/en/reference/combinat/index.rst b/src/doc/en/reference/combinat/index.rst index 1066b9a34f3..4470e97836d 100644 --- a/src/doc/en/reference/combinat/index.rst +++ b/src/doc/en/reference/combinat/index.rst @@ -3,7 +3,6 @@ Combinatorics .. automodule:: sage.combinat - Comprehensive Module List ------------------------- diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 529ff3f41a7..d1da854a364 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -1,4 +1,4 @@ -Comprehensive Module list +Comprehensive Module List ========================= .. NOTE:: @@ -15,7 +15,6 @@ Comprehensive Module list .. toctree:: :maxdepth: 1 - sage/combinat/__init__ sage/combinat/abstract_tree sage/combinat/affine_permutation sage/combinat/algebraic_combinatorics @@ -28,10 +27,9 @@ Comprehensive Module list sage/combinat/blob_algebra sage/combinat/cartesian_product sage/combinat/catalog_partitions - sage/combinat/chas/__init__ + sage/combinat/chas/all sage/combinat/chas/fsym sage/combinat/chas/wqsym - sage/combinat/cluster_algebra_quiver/__init__ sage/combinat/cluster_algebra_quiver/all sage/combinat/cluster_algebra_quiver/cluster_seed sage/combinat/cluster_algebra_quiver/mutation_class @@ -50,7 +48,6 @@ Comprehensive Module list sage/combinat/constellation sage/combinat/core sage/combinat/counting - sage/combinat/crystals/__init__ sage/combinat/crystals/affine sage/combinat/crystals/affine_factorization sage/combinat/crystals/affinization @@ -90,7 +87,6 @@ Comprehensive Module list sage/combinat/degree_sequences sage/combinat/derangements sage/combinat/descent_algebra - sage/combinat/designs/__init__ sage/combinat/designs/all sage/combinat/designs/bibd sage/combinat/designs/resolvable_bibd @@ -149,7 +145,6 @@ Comprehensive Module list sage/combinat/k_tableau sage/combinat/kazhdan_lusztig sage/combinat/knutson_tao_puzzles - sage/combinat/matrices/__init__ sage/combinat/matrices/all sage/combinat/matrices/dancing_links sage/combinat/matrices/dlxcpp @@ -157,14 +152,12 @@ Comprehensive Module list sage/combinat/matrices/latin sage/combinat/misc sage/combinat/multiset_partition_into_sets_ordered - sage/combinat/ncsf_qsym/__init__ sage/combinat/ncsf_qsym/all sage/combinat/ncsf_qsym/combinatorics sage/combinat/ncsf_qsym/generic_basis_code sage/combinat/ncsf_qsym/ncsf sage/combinat/ncsf_qsym/qsym sage/combinat/ncsf_qsym/tutorial - sage/combinat/ncsym/__init__ sage/combinat/ncsym/all sage/combinat/ncsym/bases sage/combinat/ncsym/dual @@ -190,7 +183,6 @@ Comprehensive Module list sage/combinat/perfect_matching sage/combinat/permutation sage/combinat/permutation_cython - sage/combinat/posets/__init__ sage/combinat/posets/all sage/combinat/posets/cartesian_product sage/combinat/posets/d_complete @@ -213,7 +205,6 @@ Comprehensive Module list sage/combinat/ribbon sage/combinat/ribbon_shaped_tableau sage/combinat/ribbon_tableau - sage/combinat/rigged_configurations/__init__ sage/combinat/rigged_configurations/all sage/combinat/rigged_configurations/bij_abstract_class sage/combinat/rigged_configurations/bij_infinity @@ -236,7 +227,6 @@ Comprehensive Module list sage/combinat/rigged_configurations/rigged_partition sage/combinat/rigged_configurations/tensor_product_kr_tableaux sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element - sage/combinat/root_system/__init__ sage/combinat/root_system/all sage/combinat/root_system/ambient_space sage/combinat/root_system/associahedron @@ -298,7 +288,6 @@ Comprehensive Module list sage/combinat/schubert_polynomial sage/combinat/set_partition sage/combinat/set_partition_ordered - sage/combinat/sf/__init__ sage/combinat/sf/all sage/combinat/sf/character sage/combinat/sf/classical @@ -334,7 +323,6 @@ Comprehensive Module list sage/combinat/skew_partition sage/combinat/skew_tableau sage/combinat/sloane_functions - sage/combinat/species/__init__ sage/combinat/species/all sage/combinat/species/characteristic_species sage/combinat/species/composition_species @@ -375,9 +363,8 @@ Comprehensive Module list sage/combinat/tuple sage/combinat/tutorial sage/combinat/vector_partition - sage/combinat/words/__init__ sage/combinat/words/abstract_word - sage/combinat/words/all + sage/combinat/words sage/combinat/words/alphabet sage/combinat/words/finite_word sage/combinat/words/infinite_word diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 1f7728cdf6f..ea885e6f4d7 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -290,16 +290,16 @@ def create_key(self, base_ring, arg1=None, arg2=None, newname += '_' varnames.append(newname) R = PolynomialRing( - PolRing.base(), varnames, - sparse=sparse, order=T) + PolRing.base(), varnames, + sparse=sparse, order=T) return tuple(degrees), R # normalise the generator names from sage.rings.integer import Integer if isinstance(arg1, (Integer, int)): arg1, arg2 = arg2, arg1 - if not names is None: + if names is not None: arg1 = names - elif not name is None: + elif name is not None: arg1 = name if arg2 is None: arg2 = len(arg1) @@ -866,13 +866,13 @@ def g_algebra(self, relations, names=None, order='degrevlex', check=True): assert v1 > v2 c_coef = None d_poly = None - for (m,c) in commuted: + for m, c in commuted: if list(m) == [(v2,1),(v1,1)]: c_coef = c - #buggy coercion workaround + # buggy coercion workaround d_poly = commuted - self(c) * self(m) break - assert not c_coef is None,list(m) + assert c_coef is not None, list(m) v2_ind = self.gens().index(v2) v1_ind = self.gens().index(v1) cmat[v2_ind,v1_ind] = c_coef diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index e40871376d4..e664e0f9559 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -108,11 +108,12 @@ def GroupAlgebra(G, R=IntegerRing()): over Rational Field """ if not (G in Magmas() or G in AdditiveMagmas()): - raise ValueError("%s is not a magma or additive magma"%G) - if not R in Rings(): - raise ValueError("%s is not a ring"%R) + raise ValueError("%s is not a magma or additive magma" % G) + if R not in Rings(): + raise ValueError("%s is not a ring" % R) return G.algebra(R) + class GroupAlgebra_class(CombinatorialFreeModule): def _coerce_map_from_(self, S): r""" diff --git a/src/sage/algebras/hall_algebra.py b/src/sage/algebras/hall_algebra.py index a8ea8d18aff..089050d1627 100644 --- a/src/sage/algebras/hall_algebra.py +++ b/src/sage/algebras/hall_algebra.py @@ -5,12 +5,12 @@ - Travis Scrimshaw (2013-10-17): Initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method @@ -230,7 +230,7 @@ def __init__(self, base_ring, q, prefix='H'): self._q = q try: q_inverse = q**-1 - if not q_inverse in base_ring: + if q_inverse not in base_ring: hopf_structure = False else: hopf_structure = True @@ -580,7 +580,7 @@ def __init__(self, base_ring, q, prefix='I'): self._q = q try: q_inverse = q**-1 - if not q_inverse in base_ring: + if q_inverse not in base_ring: hopf_structure = False else: hopf_structure = True diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py index 0ec6ca765c3..5c14016eab2 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py @@ -320,10 +320,10 @@ def __classcall_private__(cls, R=None, arg0=None, index_set=None, sage: type(V) """ - if not R in CommutativeRings(): - raise ValueError("arg0 must be a commutative ring got {}".format(R)) + if R not in CommutativeRings(): + raise ValueError(f"arg0 must be a commutative ring got {R}") - #This is the only exposed class so we clean keywords here + # This is the only exposed class so we clean keywords here known_keywords = ['category', 'prefix', 'bracket', 'latex_bracket', 'string_quotes', 'sorting_key', 'graded', 'super'] for key in kwds: diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 08b921ea160..a700b6b8854 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -18,7 +18,7 @@ of irreducible modules """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Eric Webster # Copyright (C) 2011 Hugh Thomas # @@ -26,8 +26,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/ +# **************************************************************************** import itertools @@ -240,7 +240,7 @@ def __init__(self, R, n, r): raise ValueError("n (={}) must be a positive integer".format(n)) if r not in ZZ or r < 0: raise ValueError("r (={}) must be a non-negative integer".format(r)) - if not R in Rings.Commutative(): + if R not in Rings.Commutative(): raise ValueError("R (={}) must be a commutative ring".format(R)) self._n = n diff --git a/src/sage/categories/__init__.py b/src/sage/categories/__init__.py index 11af5bbf980..e69de29bb2d 100644 --- a/src/sage/categories/__init__.py +++ b/src/sage/categories/__init__.py @@ -1,29 +0,0 @@ -r""" -Sage categories quickref ------------------------- - -- sage.categories.primer? A primer on Elements, Parents, and Categories -- sage.categories.tutorial? A tutorial on Elements, Parents, and Categories -- Category? Technical background on categories -- Sets() Semigroups() Algebras(QQ) Some categories -- SemiGroups().example()?? Sample implementation of a semigroup -- Hom(A, B), End(A, Algebras()) Homomorphisms sets -- tensor, cartesian_product Functorial constructions - -Module layout: - -- sage.categories.basic: the basic categories -- sage.categories.all: all categories -- sage.categories.semigroups: the Semigroups() category -- sage.categories.examples.semigroups the example of Semigroups() -- sage.categories.homset, map, - morphism, functors: morphisms, ... -- sage.categories.cartesian_product, tensor, - dual: functorial constructions - - -Todo: put the quickref in quickref.py, and only some pointers here? - -""" - -from . import primer diff --git a/src/sage/categories/algebra_modules.py b/src/sage/categories/algebra_modules.py index b74bb51649d..d2e16148fd8 100644 --- a/src/sage/categories/algebra_modules.py +++ b/src/sage/categories/algebra_modules.py @@ -51,8 +51,8 @@ def __init__(self, A): sage: TestSuite(AlgebraModules(QQ['a'])).run() """ from sage.categories.commutative_algebras import CommutativeAlgebras - if not hasattr(A, "base_ring") or not A in CommutativeAlgebras(A.base_ring()): - raise TypeError("A (=%s) must be a commutative algebra"%A) + if not hasattr(A, "base_ring") or A not in CommutativeAlgebras(A.base_ring()): + raise TypeError("A (=%s) must be a commutative algebra" % A) Category_module.__init__(self, A) @classmethod diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index a92fc4e09cd..110a9954da3 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -1,3 +1,34 @@ +r""" +Sage categories quickref + +- ``sage.categories.primer?`` a primer on Elements, Parents, and Categories +- ``sage.categories.tutorial?`` a tutorial on Elements, Parents, and Categories +- ``Category?`` technical background on categories +- ``Sets()``, ``Semigroups()``, ``Algebras(QQ)`` some categories +- ``SemiGroups().example()??`` sample implementation of a semigroup +- ``Hom(A, B)``, ``End(A, Algebras())`` homomorphisms sets +- ``tensor``, ``cartesian_product`` functorial constructions + +Module layout: + +- :mod:`sage.categories.basic` the basic categories +- :mod:`sage.categories.all` all categories +- :mod:`sage.categories.semigroups` the ``Semigroups()`` category +- :mod:`sage.categories.examples.semigroups` the example of ``Semigroups()`` +- :mod:`sage.categories.homset` morphisms, ... +- :mod:`sage.categories.map` +- :mod:`sage.categories.morphism` +- :mod:`sage.categories.functors` +- :mod:`sage.categories.cartesian_product` functorial constructions +- :mod:`sage.categories.tensor` +- :mod:`sage.categories.dual` +""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + +from . import primer + from sage.misc.lazy_import import lazy_import from .all__sagemath_objects import * diff --git a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py index 96bcbab9f05..bb58d78cbde 100644 --- a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py +++ b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py @@ -2,15 +2,15 @@ r""" Common category for Generalized Coxeter Groups or Complex Reflection Groups """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Nicolas M. Thiéry # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import itertools from sage.misc.abstract_method import abstract_method @@ -201,7 +201,7 @@ def simple_reflection(self, i): 3 (1,4)(2,8)(3,5)(7,10)(9,11) asdf (2,5)(3,9)(4,6)(8,11)(10,12) """ - if not i in self.index_set(): + if i not in self.index_set(): raise ValueError("%s is not in the Dynkin node set %s" % (i, self.index_set())) return self.one().apply_simple_reflection(i) # don't care about left/right diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index d8802949324..e0adb301ce2 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -133,7 +133,7 @@ def cayley_graph_disabled(self, connecting_set=None): connecting_set = self.group_generators() else: for g in connecting_set: - if not g in self: + if g not in self: raise RuntimeError("Each element of the connecting set must be in the group!") connecting_set = [self(g) for g in connecting_set] from sage.graphs.all import DiGraph diff --git a/src/sage/categories/finite_permutation_groups.py b/src/sage/categories/finite_permutation_groups.py index 8c9827dc8b8..8595aef7795 100644 --- a/src/sage/categories/finite_permutation_groups.py +++ b/src/sage/categories/finite_permutation_groups.py @@ -223,10 +223,10 @@ def cycle_index(self, parent = None): """ from sage.categories.modules import Modules if parent is None: - from sage.rings.rational_field import QQ - from sage.combinat.sf.sf import SymmetricFunctions - parent = SymmetricFunctions(QQ).powersum() - elif not parent in Modules.WithBasis: + from sage.rings.rational_field import QQ + from sage.combinat.sf.sf import SymmetricFunctions + parent = SymmetricFunctions(QQ).powersum() + elif parent not in Modules.WithBasis: raise ValueError("`parent` should be a module with basis indexed by partitions") base_ring = parent.base_ring() return parent.sum_of_terms([C.an_element().cycle_type(), base_ring(C.cardinality())] diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index ada869b0403..6ab5657e929 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -407,7 +407,7 @@ def order_ideal_toggle(self, I, v): ....: for P in P4) True """ - if not v in I: + if v not in I: if all(u in I for u in self.lower_covers(v)): from sage.sets.set import Set return I.union(Set({v})) diff --git a/src/sage/categories/ring_ideals.py b/src/sage/categories/ring_ideals.py index 569958d364a..51573635ef0 100644 --- a/src/sage/categories/ring_ideals.py +++ b/src/sage/categories/ring_ideals.py @@ -1,20 +1,21 @@ r""" Ring ideals """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from .category_types import Category_ideal from .modules import Modules from sage.categories.rings import Rings _Rings = Rings() + class RingIdeals(Category_ideal): """ The category of two-sided ideals in a fixed ring. @@ -54,8 +55,8 @@ def __init__(self, R): sage: TestSuite(RingIdeals(ZZ)).run() """ - if not R in _Rings: - raise TypeError("R (=%s) must be a ring"%R) + if R not in _Rings: + raise TypeError("R (=%s) must be a ring" % R) Category_ideal.__init__(self, R) def super_categories(self): diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 31da05bd00c..438c33b6e9b 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -304,7 +304,7 @@ def cayley_graph(self, side="right", simple=False, elements = None, generators = from sage.graphs.digraph import DiGraph from .monoids import Monoids from .groups import Groups - if not side in ["left", "right", "twosided"]: + if side not in ["left", "right", "twosided"]: raise ValueError("option 'side' must be 'left', 'right' or 'twosided'") if elements is None: assert self.is_finite(), "elements should be specified for infinite semigroups" @@ -314,7 +314,7 @@ def cayley_graph(self, side="right", simple=False, elements = None, generators = if simple or self in Groups(): result = DiGraph() else: - result = DiGraph(multiedges = True, loops = True) + result = DiGraph(multiedges=True, loops=True) result.add_vertices(elements) if connecting_set is not None: diff --git a/src/sage/combinat/__init__.py b/src/sage/combinat/__init__.py index d7d8e22b536..e69de29bb2d 100644 --- a/src/sage/combinat/__init__.py +++ b/src/sage/combinat/__init__.py @@ -1,49 +0,0 @@ -r""" -Combinatorics -============= - -Introductory material ---------------------- - -- :ref:`sage.combinat.quickref` -- :ref:`sage.combinat.tutorial` - -Thematic indexes ----------------- - -- :ref:`sage.combinat.algebraic_combinatorics` - - - :ref:`sage.combinat.chas` - - :ref:`sage.combinat.cluster_algebra_quiver` - - :ref:`sage.combinat.crystals` - - :ref:`sage.combinat.root_system` - - :ref:`sage.combinat.sf` - - :class:`~sage.combinat.fully_commutative_elements.FullyCommutativeElements` - -- :ref:`sage.combinat.counting` -- :ref:`sage.combinat.enumerated_sets` -- :ref:`sage.combinat.catalog_partitions` -- :ref:`sage.combinat.finite_state_machine` -- :ref:`sage.combinat.species` -- :ref:`sage.combinat.designs` -- :ref:`sage.combinat.posets` -- :ref:`sage.combinat.words` - -Utilities ---------- - -- :ref:`sage.combinat.output` -- :ref:`sage.combinat.ranker` -- :func:`Combinatorial maps ` -- :ref:`sage.combinat.misc` - -Related topics --------------- - -- :ref:`sage.coding` -- :ref:`sage.dynamics` -- :ref:`sage.graphs` - -""" -from . import quickref -from . import tutorial diff --git a/src/sage/combinat/algebraic_combinatorics.py b/src/sage/combinat/algebraic_combinatorics.py index 599913ffdb8..b8f01700156 100644 --- a/src/sage/combinat/algebraic_combinatorics.py +++ b/src/sage/combinat/algebraic_combinatorics.py @@ -1,17 +1,9 @@ r""" Algebraic combinatorics -======================= - -Quickref --------- - -.. TODO:: write it! Thematic tutorials ------------------ -.. TODO:: get Sphinx to create those cross links properly - - `Algebraic Combinatorics in Sage <../../../../thematic_tutorials/algebraic_combinatorics.html>`_ - `Lie Methods and Related Combinatorics in Sage <../../../../thematic_tutorials/lie.html>`_ - `Linear Programming (Mixed Integer) <../../../../thematic_tutorials/linear_programming.html>`_ @@ -41,10 +33,10 @@ Combinatorial Representation Theory ----------------------------------- -- :ref:`sage.combinat.root_system` -- :ref:`sage.combinat.crystals` -- :ref:`sage.combinat.rigged_configurations` -- :ref:`sage.combinat.cluster_algebra_quiver` +- :ref:`sage.combinat.root_system.all` +- :ref:`sage.combinat.crystals.all` +- :ref:`sage.combinat.rigged_configurations.all` +- :ref:`sage.combinat.cluster_algebra_quiver.all` - :class:`~sage.combinat.kazhdan_lusztig.KazhdanLusztigPolynomial` - :class:`~sage.combinat.symmetric_group_representations.SymmetricGroupRepresentation` - :ref:`sage.combinat.yang_baxter_graph` diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index cc23f903efd..729aa6cab95 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -1,6 +1,54 @@ +r""" +Combinatorics + +Introductory material +--------------------- + +- :ref:`sage.combinat.quickref` +- :ref:`sage.combinat.tutorial` + +Thematic indexes +---------------- + +- :ref:`sage.combinat.algebraic_combinatorics` + + - :ref:`sage.combinat.chas.all` + - :ref:`sage.combinat.cluster_algebra_quiver.all` + - :ref:`sage.combinat.crystals.all` + - :ref:`sage.combinat.root_system.all` + - :ref:`sage.combinat.sf.all` + - :class:`~sage.combinat.fully_commutative_elements.FullyCommutativeElements` + +- :ref:`sage.combinat.counting` +- :ref:`sage.combinat.enumerated_sets` +- :ref:`sage.combinat.catalog_partitions` +- :ref:`sage.combinat.finite_state_machine` +- :ref:`sage.combinat.species.all` +- :ref:`sage.combinat.designs.all` +- :ref:`sage.combinat.posets.all` +- :ref:`sage.combinat.words` + +Utilities +--------- + +- :ref:`sage.combinat.output` +- :ref:`sage.combinat.ranker` +- :func:`Combinatorial maps ` +- :ref:`sage.combinat.misc` + +Related topics +-------------- + +- :ref:`sage.coding` +- :ref:`sage.dynamics` +- :ref:`sage.graphs` + """ -Combinatorics features that are imported by default in the interpreter namespace -""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + +from . import quickref, tutorial from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/catalog_partitions.py b/src/sage/combinat/catalog_partitions.py index 2ff59c6017c..ca143fa540c 100644 --- a/src/sage/combinat/catalog_partitions.py +++ b/src/sage/combinat/catalog_partitions.py @@ -1,6 +1,5 @@ r""" Enumerated sets of partitions, tableaux, ... -============================================ Partitions ---------- diff --git a/src/sage/combinat/chas/__init__.py b/src/sage/combinat/chas/__init__.py index 41b823ca81e..8b137891791 100644 --- a/src/sage/combinat/chas/__init__.py +++ b/src/sage/combinat/chas/__init__.py @@ -1,13 +1 @@ -""" -Combinatorial Hopf algebras -=========================== -- :ref:`sage.combinat.sf` -- :ref:`sage.combinat.ncsf_qsym` -- :ref:`sage.combinat.ncsym` -- :ref:`sage.combinat.schubert_polynomial` -- :ref:`sage.combinat.chas.fsym` -- :ref:`sage.combinat.fqsym` -- :ref:`sage.combinat.grossman_larson_algebras` -- :ref:`sage.combinat.chas.wqsym` -""" diff --git a/src/sage/combinat/chas/all.py b/src/sage/combinat/chas/all.py index ecb6f2f0c77..899155c0385 100644 --- a/src/sage/combinat/chas/all.py +++ b/src/sage/combinat/chas/all.py @@ -1,7 +1,21 @@ """ -Combinatorial Hopf Algebras +Combinatorial Hopf algebras + +- :ref:`sage.combinat.sf.all` +- :ref:`sage.combinat.ncsf_qsym.all` +- :ref:`sage.combinat.ncsym.all` +- :ref:`sage.combinat.schubert_polynomial` +- :ref:`sage.combinat.chas.fsym` +- :ref:`sage.combinat.fqsym` +- :ref:`sage.combinat.grossman_larson_algebras` +- :ref:`sage.combinat.chas.wqsym` """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.chas.fsym', ['FreeSymmetricFunctions']) lazy_import('sage.combinat.chas.wqsym', ['WordQuasiSymmetricFunctions']) + diff --git a/src/sage/combinat/cluster_algebra_quiver/__init__.py b/src/sage/combinat/cluster_algebra_quiver/__init__.py index 314a35ef7ef..e69de29bb2d 100644 --- a/src/sage/combinat/cluster_algebra_quiver/__init__.py +++ b/src/sage/combinat/cluster_algebra_quiver/__init__.py @@ -1,10 +0,0 @@ -r""" -Cluster Algebras and Quivers -============================ - -- A compendium on the cluster algebra and quiver package in Sage [MS2011]_ - -- :ref:`sage.combinat.cluster_algebra_quiver.quiver_mutation_type` -- :ref:`sage.combinat.cluster_algebra_quiver.quiver` -- :ref:`sage.combinat.cluster_algebra_quiver.cluster_seed` -""" diff --git a/src/sage/combinat/cluster_algebra_quiver/all.py b/src/sage/combinat/cluster_algebra_quiver/all.py index 44060e2b3cb..61fec4fde04 100644 --- a/src/sage/combinat/cluster_algebra_quiver/all.py +++ b/src/sage/combinat/cluster_algebra_quiver/all.py @@ -1,7 +1,18 @@ +r""" +Cluster algebras and quivers + +- A compendium on the cluster algebra and quiver package in Sage [MS2011]_ + +- :ref:`sage.combinat.cluster_algebra_quiver.quiver_mutation_type` +- :ref:`sage.combinat.cluster_algebra_quiver.quiver` +- :ref:`sage.combinat.cluster_algebra_quiver.cluster_seed` """ -Cluster algebra and quivers features that are imported by default in the interpreter namespace -""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + from sage.misc.lazy_import import lazy_import lazy_import("sage.combinat.cluster_algebra_quiver.quiver_mutation_type", "QuiverMutationType") lazy_import("sage.combinat.cluster_algebra_quiver.quiver", "ClusterQuiver") lazy_import("sage.combinat.cluster_algebra_quiver.cluster_seed", "ClusterSeed") + diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 59abf94470f..dc7b23b4d78 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -37,9 +37,11 @@ from itertools import islice from sage.structure.sage_object import SageObject from copy import copy -from sage.rings.all import QQ, infinity +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ -from sage.rings.all import FractionField, PolynomialRing +from sage.rings.fraction_field import FractionField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.fraction_field_element import FractionFieldElement from sage.sets.all import Set from sage.graphs.digraph import DiGraph diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py index 32fe50b567d..f8954fcc00d 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py @@ -20,7 +20,8 @@ import time from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree, get_orbits -from sage.rings.all import ZZ, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity from sage.graphs.all import DiGraph from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _edge_list_to_matrix diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index dedef28db11..48a9bd9164d 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -39,7 +39,9 @@ from sage.structure.sage_object import SageObject from copy import copy -from sage.rings.all import ZZ, CC, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.all import CC +from sage.rings.infinity import infinity from sage.graphs.all import Graph, DiGraph from sage.graphs.views import EdgesView from sage.arith.misc import gcd diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index 745b16010a6..8925dc6d17b 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -23,10 +23,11 @@ from copy import copy from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method -from sage.rings.all import ZZ, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity from sage.graphs.all import Graph, DiGraph from sage.arith.all import binomial, euler_phi -from sage.all import prod +from sage.misc.misc_c import prod from sage.matrix.constructor import matrix diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 67a2a82bd88..8b24bf73aea 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -151,7 +151,10 @@ from __future__ import annotations from typing import Iterator -from sage.rings.all import ZZ, QQ, Integer, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer +from sage.rings.infinity import infinity from sage.arith.all import bernoulli, factorial from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/combinat/crystals/__init__.py b/src/sage/combinat/crystals/__init__.py index 63719c0d2f9..e69de29bb2d 100644 --- a/src/sage/combinat/crystals/__init__.py +++ b/src/sage/combinat/crystals/__init__.py @@ -1,29 +0,0 @@ -r""" -Crystals -======== - -Quickref --------- - -.. TODO:: Write it! - -Introductory material ---------------------- - -- :ref:`sage.combinat.crystals.crystals` -- The `Lie Methods and Related Combinatorics <../../../../../thematic_tutorials/lie.html>`_ thematic tutorial - -Catalogs of crystals --------------------- - -- :ref:`sage.combinat.crystals.catalog` - -See also --------- - -- The categories for crystals: :class:`Crystals`, :class:`HighestWeightCrystals`, - :class:`FiniteCrystals`, :class:`ClassicalCrystals`, :class:`RegularCrystals`, - :class:`~sage.categories.regular_supercrystals.RegularSuperCrystals` - -- The categories for crystals -- :ref:`sage.combinat.root_system` -""" diff --git a/src/sage/combinat/crystals/all.py b/src/sage/combinat/crystals/all.py index 3c4d599224f..23955e34465 100644 --- a/src/sage/combinat/crystals/all.py +++ b/src/sage/combinat/crystals/all.py @@ -1,7 +1,31 @@ +r""" +Crystals + +Introductory material +--------------------- + +- :ref:`sage.combinat.crystals.crystals` +- The `Lie Methods and Related Combinatorics <../../../../../thematic_tutorials/lie.html>`_ thematic tutorial + +Catalogs of crystals +-------------------- + +- :ref:`sage.combinat.crystals.catalog` + +See also +-------- + +- The categories for crystals: :class:`Crystals`, :class:`HighestWeightCrystals`, + :class:`FiniteCrystals`, :class:`ClassicalCrystals`, :class:`RegularCrystals`, + :class:`~sage.categories.regular_supercrystals.RegularSuperCrystals` + -- The categories for crystals +- :ref:`sage.combinat.root_system.all` """ -Crystal features that are imported by default in the interpreter namespace -""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.crystals', 'catalog', 'crystals') + diff --git a/src/sage/combinat/crystals/crystals.py b/src/sage/combinat/crystals/crystals.py index f31a3ac0811..b7288753fba 100644 --- a/src/sage/combinat/crystals/crystals.py +++ b/src/sage/combinat/crystals/crystals.py @@ -121,7 +121,7 @@ For rank two crystals, there is an alternative method of getting metapost pictures. For more information see ``C.metapost?``. -.. SEEALSO:: :ref:`The overview of crystal features in Sage` +.. SEEALSO:: :ref:`The overview of crystal features in Sage` .. TODO:: diff --git a/src/sage/combinat/designs/__init__.py b/src/sage/combinat/designs/__init__.py index 4808cf1a552..8b137891791 100644 --- a/src/sage/combinat/designs/__init__.py +++ b/src/sage/combinat/designs/__init__.py @@ -1,38 +1 @@ -r""" -Combinatorial Designs and Incidence Structures -============================================== -All designs can be accessed by ``designs.`` and are listed in the -design catalog: - -- :ref:`sage.combinat.designs.design_catalog` - -**Design-related classes** - -- :ref:`sage.combinat.designs.incidence_structures` -- :ref:`sage.combinat.designs.covering_design` - -**Constructions** - -- :ref:`sage.combinat.designs.block_design` -- :ref:`sage.combinat.designs.bibd` -- :ref:`sage.combinat.designs.resolvable_bibd` -- :ref:`sage.combinat.designs.group_divisible_designs` -- :ref:`sage.combinat.designs.latin_squares` -- :ref:`sage.combinat.designs.orthogonal_arrays` -- :ref:`sage.combinat.designs.orthogonal_arrays_build_recursive` -- :ref:`sage.combinat.designs.orthogonal_arrays_find_recursive` -- :ref:`sage.combinat.designs.difference_family` -- :ref:`sage.combinat.designs.difference_matrices` -- :ref:`sage.combinat.designs.steiner_quadruple_systems` -- :ref:`sage.combinat.designs.twographs` -- :ref:`sage.combinat.designs.database` -- :ref:`sage.combinat.designs.gen_quadrangles_with_spread` - -**Technical things** - -- :ref:`sage.combinat.designs.ext_rep` -- :ref:`sage.combinat.designs.designs_pyx` -- :ref:`sage.combinat.designs.subhypergraph_search` -- :ref:`sage.combinat.designs.evenly_distributed_sets` -""" diff --git a/src/sage/combinat/designs/all.py b/src/sage/combinat/designs/all.py index 81210cf3b7f..0948c6fa281 100644 --- a/src/sage/combinat/designs/all.py +++ b/src/sage/combinat/designs/all.py @@ -1,6 +1,44 @@ +r""" +Combinatorial designs and incidence structures + +All designs can be accessed by ``designs.`` and are listed in the +design catalog: + +- :ref:`sage.combinat.designs.design_catalog` + +**Design-related classes** + +- :ref:`sage.combinat.designs.incidence_structures` +- :ref:`sage.combinat.designs.covering_design` + +**Constructions** + +- :ref:`sage.combinat.designs.block_design` +- :ref:`sage.combinat.designs.bibd` +- :ref:`sage.combinat.designs.resolvable_bibd` +- :ref:`sage.combinat.designs.group_divisible_designs` +- :ref:`sage.combinat.designs.latin_squares` +- :ref:`sage.combinat.designs.orthogonal_arrays` +- :ref:`sage.combinat.designs.orthogonal_arrays_build_recursive` +- :ref:`sage.combinat.designs.orthogonal_arrays_find_recursive` +- :ref:`sage.combinat.designs.difference_family` +- :ref:`sage.combinat.designs.difference_matrices` +- :ref:`sage.combinat.designs.steiner_quadruple_systems` +- :ref:`sage.combinat.designs.twographs` +- :ref:`sage.combinat.designs.database` +- :ref:`sage.combinat.designs.gen_quadrangles_with_spread` + +**Technical things** + +- :ref:`sage.combinat.designs.ext_rep` +- :ref:`sage.combinat.designs.designs_pyx` +- :ref:`sage.combinat.designs.subhypergraph_search` +- :ref:`sage.combinat.designs.evenly_distributed_sets` """ -Combinatorial design features that are imported by default in the interpreter namespace -""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index 1c8350bfea4..f529886da82 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -1,6 +1,5 @@ """ Enumerated sets and combinatorial objects -========================================= .. TODO:: Proofread / point to the main classes rather than the modules @@ -132,7 +131,7 @@ - :ref:`sage.combinat.tiling` - :ref:`sage.combinat.dlx` - :ref:`sage.combinat.matrices.dlxcpp` -- :ref:`sage.combinat.species` +- :ref:`sage.combinat.species.all` - :class:`~sage.combinat.integer_lists.IntegerListsLex` - :class:`~sage.combinat.integer_vectors_mod_permgroup.IntegerVectorsModPermutationGroup` diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 5e4de70411c..fd94221cee5 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Finite State Machines, Automata, Transducers +Finite state machines, automata, transducers This module adds support for finite state machines, automata and transducers. diff --git a/src/sage/combinat/integer_lists/__init__.py b/src/sage/combinat/integer_lists/__init__.py index 6664a99ead2..4e0c59ff8a6 100644 --- a/src/sage/combinat/integer_lists/__init__.py +++ b/src/sage/combinat/integer_lists/__init__.py @@ -1,4 +1,3 @@ - from .base import IntegerListsBackend, Envelope from .lists import IntegerLists from .invlex import IntegerListsLex diff --git a/src/sage/combinat/matrices/__init__.py b/src/sage/combinat/matrices/__init__.py index aa4264e01af..e69de29bb2d 100644 --- a/src/sage/combinat/matrices/__init__.py +++ b/src/sage/combinat/matrices/__init__.py @@ -1,9 +0,0 @@ -r""" -Combinatorics on matrices -========================= - -- :ref:`sage.combinat.matrices.dancing_links` -- :ref:`sage.combinat.matrices.dlxcpp` -- :ref:`sage.combinat.matrices.hadamard_matrix` -- :ref:`sage.combinat.matrices.latin` -""" diff --git a/src/sage/combinat/matrices/all.py b/src/sage/combinat/matrices/all.py index 67793f125e7..baa34da139a 100644 --- a/src/sage/combinat/matrices/all.py +++ b/src/sage/combinat/matrices/all.py @@ -1,6 +1,15 @@ r""" -Combinatorics on matrix features that are imported by default in the interpreter namespace +Combinatorics on matrices + +- :ref:`sage.combinat.matrices.dancing_links` +- :ref:`sage.combinat.matrices.dlxcpp` +- :ref:`sage.combinat.matrices.hadamard_matrix` +- :ref:`sage.combinat.matrices.latin` """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.matrices.latin', @@ -8,3 +17,4 @@ lazy_import('sage.combinat.matrices.dlxcpp', 'DLXCPP') lazy_import('sage.combinat.matrices.hadamard_matrix', ['hadamard_matrix', 'hadamard_matrix_www']) + diff --git a/src/sage/combinat/ncsf_qsym/__init__.py b/src/sage/combinat/ncsf_qsym/__init__.py index 97f41285b1a..8b137891791 100644 --- a/src/sage/combinat/ncsf_qsym/__init__.py +++ b/src/sage/combinat/ncsf_qsym/__init__.py @@ -1,11 +1 @@ -r""" -Non-Commutative Symmetric Functions and Quasi-Symmetric Functions -================================================================= -- :ref:`sage.combinat.ncsf_qsym.tutorial` - -- :ref:`Non-Commutative Symmetric Functions (NCSF) ` -- :ref:`Quasi-Symmetric Functions (QSym) ` -- :ref:`sage.combinat.ncsf_qsym.generic_basis_code` - -""" diff --git a/src/sage/combinat/ncsf_qsym/all.py b/src/sage/combinat/ncsf_qsym/all.py index 9156bd0f05c..212da647869 100644 --- a/src/sage/combinat/ncsf_qsym/all.py +++ b/src/sage/combinat/ncsf_qsym/all.py @@ -1,6 +1,17 @@ r""" -Features that are imported by default in the interpreter namespace +Non-commutative symmetric functions and quasi-symmetric functions + +- :ref:`sage.combinat.ncsf_qsym.tutorial` + +- :ref:`Non-Commutative Symmetric Functions (NCSF) ` +- :ref:`Quasi-Symmetric Functions (QSym) ` +- :ref:`sage.combinat.ncsf_qsym.generic_basis_code` + """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from .qsym import QuasiSymmetricFunctions from .ncsf import NonCommutativeSymmetricFunctions + diff --git a/src/sage/combinat/ncsym/__init__.py b/src/sage/combinat/ncsym/__init__.py index 5717495170c..e69de29bb2d 100644 --- a/src/sage/combinat/ncsym/__init__.py +++ b/src/sage/combinat/ncsym/__init__.py @@ -1,10 +0,0 @@ -r""" -Symmetric Functions in Non-Commuting Variables -============================================== - -- :class:`Introduction to Symmetric Functions in Non-Commuting Variables ` - -- :ref:`sage.combinat.ncsym.bases` -- :ref:`sage.combinat.ncsym.dual` -- :ref:`sage.combinat.ncsym.ncsym` -""" diff --git a/src/sage/combinat/ncsym/all.py b/src/sage/combinat/ncsym/all.py index 72da0443b27..7a174e45ccf 100644 --- a/src/sage/combinat/ncsym/all.py +++ b/src/sage/combinat/ncsym/all.py @@ -1,7 +1,15 @@ +r""" +Symmetric functions in non-commuting variables + +- :class:`Introduction to Symmetric Functions in Non-Commuting Variables ` + +- :ref:`sage.combinat.ncsym.bases` +- :ref:`sage.combinat.ncsym.dual` +- :ref:`sage.combinat.ncsym.ncsym` """ -Features that are imported by default in the interpreter namespace -""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from .ncsym import SymmetricFunctionsNonCommutingVariables from .dual import SymmetricFunctionsNonCommutingVariablesDual - diff --git a/src/sage/combinat/path_tableaux/__init__.py b/src/sage/combinat/path_tableaux/__init__.py index 564cfb994c4..8b137891791 100644 --- a/src/sage/combinat/path_tableaux/__init__.py +++ b/src/sage/combinat/path_tableaux/__init__.py @@ -1,11 +1 @@ -r""" -Path Tableaux -============= - -- :ref:`sage.combinat.path_tableaux.path_tableau` -- :ref:`sage.combinat.path_tableaux.dyck_path` -- :ref:`sage.combinat.path_tableaux.frieze` -- :ref:`sage.combinat.path_tableaux.semistandard` - -""" diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index 9ae4469b28d..42a2e8ca4a5 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -1,3 +1,12 @@ r""" -PathTableaux +Path tableaux + +- :ref:`sage.combinat.path_tableaux.path_tableau` +- :ref:`sage.combinat.path_tableaux.dyck_path` +- :ref:`sage.combinat.path_tableaux.frieze` +- :ref:`sage.combinat.path_tableaux.semistandard` + """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) diff --git a/src/sage/combinat/posets/__init__.py b/src/sage/combinat/posets/__init__.py index 0ef76a3374b..e69de29bb2d 100644 --- a/src/sage/combinat/posets/__init__.py +++ b/src/sage/combinat/posets/__init__.py @@ -1,35 +0,0 @@ -r""" -Posets - -Common posets can be accessed through ``posets.`` and are listed in the -posets catalog: - -- :ref:`Catalog of posets and lattices ` - -Poset-related classes: - -- :ref:`sage.combinat.posets.posets` -- :ref:`sage.combinat.posets.lattices` - -- :ref:`sage.combinat.posets.linear_extensions` -- :ref:`sage.combinat.posets.d_complete` -- :ref:`sage.combinat.posets.forest` -- :ref:`sage.combinat.posets.mobile` -- :ref:`sage.combinat.posets.incidence_algebras` - -- :ref:`sage.combinat.posets.cartesian_product` - -- :ref:`sage.combinat.posets.moebius_algebra` - -- :ref:`sage.combinat.tamari_lattices` -- :ref:`sage.combinat.interval_posets` -- :ref:`sage.combinat.shard_order` - -If you are looking for Poset-related :mod:`categories -`, see -:class:`~sage.categories.posets.Posets`, -:class:`~sage.categories.finite_posets.FinitePosets`, -:class:`~sage.categories.lattice_posets.LatticePosets` and -:class:`~sage.categories.finite_lattice_posets.FiniteLatticePosets`. -""" - diff --git a/src/sage/combinat/posets/all.py b/src/sage/combinat/posets/all.py index e47f6e93060..f7f8bdcc7fc 100644 --- a/src/sage/combinat/posets/all.py +++ b/src/sage/combinat/posets/all.py @@ -1,6 +1,40 @@ r""" -Poset features that are imported by default in the interpreter namespace +Posets + +Common posets can be accessed through ``posets.`` and are listed in the +posets catalog: + +- :ref:`Catalog of posets and lattices ` + +Poset-related classes: + +- :ref:`sage.combinat.posets.posets` +- :ref:`sage.combinat.posets.lattices` + +- :ref:`sage.combinat.posets.linear_extensions` +- :ref:`sage.combinat.posets.d_complete` +- :ref:`sage.combinat.posets.forest` +- :ref:`sage.combinat.posets.mobile` +- :ref:`sage.combinat.posets.incidence_algebras` + +- :ref:`sage.combinat.posets.cartesian_product` + +- :ref:`sage.combinat.posets.moebius_algebra` + +- :ref:`sage.combinat.tamari_lattices` +- :ref:`sage.combinat.interval_posets` +- :ref:`sage.combinat.shard_order` + +If you are looking for Poset-related :mod:`categories +`, see +:class:`~sage.categories.posets.Posets`, +:class:`~sage.categories.finite_posets.FinitePosets`, +:class:`~sage.categories.lattice_posets.LatticePosets` and +:class:`~sage.categories.finite_lattice_posets.FiniteLatticePosets`. """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from .posets import Poset diff --git a/src/sage/combinat/quickref.py b/src/sage/combinat/quickref.py index a62944138ad..ea2aba8915a 100644 --- a/src/sage/combinat/quickref.py +++ b/src/sage/combinat/quickref.py @@ -1,6 +1,5 @@ r""" Combinatorics quickref ----------------------- Integer Sequences:: @@ -49,13 +48,13 @@ sage: L = LatticePolytope(points) sage: L.npoints(); L.plot3d() # random -:ref:`Root systems, Coxeter and Weyl groups `:: +:ref:`Root systems, Coxeter and Weyl groups `:: sage: WeylGroup(["B",3]).bruhat_poset() Finite poset containing 48 elements sage: RootSystem(["A",2,1]).weight_lattice().plot() # not tested -:ref:`Crystals `:: +:ref:`Crystals `:: sage: CrystalOfTableaux(["A",3], shape = [3,2]).some_flashy_feature() # not tested @@ -72,7 +71,7 @@ sage: M.an_element() * S.an_element() x0 -Graph theory, posets, lattices (:ref:`sage.graphs`, :ref:`sage.combinat.posets`):: +Graph theory, posets, lattices (:ref:`sage.graphs`, :ref:`sage.combinat.posets.all`):: sage: Poset({1: [2,3], 2: [4], 3: [4]}).linear_extensions().cardinality() 2 diff --git a/src/sage/combinat/rigged_configurations/__init__.py b/src/sage/combinat/rigged_configurations/__init__.py index ccecaeed2f2..e69de29bb2d 100644 --- a/src/sage/combinat/rigged_configurations/__init__.py +++ b/src/sage/combinat/rigged_configurations/__init__.py @@ -1,36 +0,0 @@ -r""" -Rigged Configurations -===================== - -.. TODO:: Proofread / point to the main classes rather than the modules? - -- :ref:`sage.combinat.rigged_configurations.rc_crystal` -- :ref:`sage.combinat.rigged_configurations.rc_infinity` - -- :ref:`sage.combinat.rigged_configurations.rigged_configurations` -- :ref:`sage.combinat.rigged_configurations.rigged_configuration_element` - -- :ref:`sage.combinat.rigged_configurations.tensor_product_kr_tableaux` -- :ref:`sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element` -- :ref:`sage.combinat.rigged_configurations.kr_tableaux` - -- :ref:`sage.combinat.rigged_configurations.kleber_tree` - -- :ref:`sage.combinat.rigged_configurations.rigged_partition` - -Bijections ----------- - -- :ref:`sage.combinat.rigged_configurations.bijection` -- :ref:`sage.combinat.rigged_configurations.bij_abstract_class` -- :ref:`sage.combinat.rigged_configurations.bij_type_A` -- :ref:`sage.combinat.rigged_configurations.bij_type_B` -- :ref:`sage.combinat.rigged_configurations.bij_type_C` -- :ref:`sage.combinat.rigged_configurations.bij_type_D` -- :ref:`sage.combinat.rigged_configurations.bij_type_A2_odd` -- :ref:`sage.combinat.rigged_configurations.bij_type_A2_even` -- :ref:`sage.combinat.rigged_configurations.bij_type_A2_dual` -- :ref:`sage.combinat.rigged_configurations.bij_type_D_twisted` -- :ref:`sage.combinat.rigged_configurations.bij_type_D_tri` -- :ref:`sage.combinat.rigged_configurations.bij_infinity` -""" diff --git a/src/sage/combinat/rigged_configurations/all.py b/src/sage/combinat/rigged_configurations/all.py index 440eed6fdbc..36a10774a89 100644 --- a/src/sage/combinat/rigged_configurations/all.py +++ b/src/sage/combinat/rigged_configurations/all.py @@ -1,6 +1,41 @@ r""" -Features that are imported by default in the interpreter namespace +Rigged configurations + +.. TODO:: Proofread / point to the main classes rather than the modules? + +- :ref:`sage.combinat.rigged_configurations.rc_crystal` +- :ref:`sage.combinat.rigged_configurations.rc_infinity` + +- :ref:`sage.combinat.rigged_configurations.rigged_configurations` +- :ref:`sage.combinat.rigged_configurations.rigged_configuration_element` + +- :ref:`sage.combinat.rigged_configurations.tensor_product_kr_tableaux` +- :ref:`sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element` +- :ref:`sage.combinat.rigged_configurations.kr_tableaux` + +- :ref:`sage.combinat.rigged_configurations.kleber_tree` + +- :ref:`sage.combinat.rigged_configurations.rigged_partition` + +Bijections +---------- + +- :ref:`sage.combinat.rigged_configurations.bijection` +- :ref:`sage.combinat.rigged_configurations.bij_abstract_class` +- :ref:`sage.combinat.rigged_configurations.bij_type_A` +- :ref:`sage.combinat.rigged_configurations.bij_type_B` +- :ref:`sage.combinat.rigged_configurations.bij_type_C` +- :ref:`sage.combinat.rigged_configurations.bij_type_D` +- :ref:`sage.combinat.rigged_configurations.bij_type_A2_odd` +- :ref:`sage.combinat.rigged_configurations.bij_type_A2_even` +- :ref:`sage.combinat.rigged_configurations.bij_type_A2_dual` +- :ref:`sage.combinat.rigged_configurations.bij_type_D_twisted` +- :ref:`sage.combinat.rigged_configurations.bij_type_D_tri` +- :ref:`sage.combinat.rigged_configurations.bij_infinity` """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/root_system/__init__.py b/src/sage/combinat/root_system/__init__.py index b04c503fad1..bc24bff5c96 100644 --- a/src/sage/combinat/root_system/__init__.py +++ b/src/sage/combinat/root_system/__init__.py @@ -1,121 +1,3 @@ -""" -Root Systems -============ - -Quickref --------- - -- ``T = CartanType(["A", 3]), T.is_finite()`` -- Cartan types -- ``T.dynkin_diagram(), DynkinDiagram(["G",2])`` -- Dynkin diagrams -- ``T.cartan_matrix(), CartanMatrix(["F",4])`` -- Cartan matrices -- ``RootSystem(T).weight_lattice()`` -- Root systems -- ``WeylGroup(["B", 6, 1]).simple_reflections()`` -- Affine Weyl groups -- ``WeylCharacterRing(["D", 4])`` -- Weyl character rings - -Introductory material ---------------------- - -- :ref:`sage.combinat.root_system` -- This overview -- :class:`CartanType` -- An introduction to Cartan types -- :class:`RootSystem` -- An introduction to root systems -- :ref:`sage.combinat.root_system.plot` -- A root system visualization tutorial - -- The `Lie Methods and Related Combinatorics <../../../../../thematic_tutorials/lie.html>`_ thematic tutorial - - -Related material ----------------- - -- :ref:`sage.combinat.crystals` -- Crystals - -Cartan datum ------------- - -- :ref:`sage.combinat.root_system.cartan_type` -- :ref:`sage.combinat.root_system.dynkin_diagram` -- :ref:`sage.combinat.root_system.cartan_matrix` -- :ref:`sage.combinat.root_system.coxeter_matrix` -- :ref:`sage.combinat.root_system.coxeter_type` - -Root systems ------------- - -- :ref:`sage.combinat.root_system.root_system` -- :ref:`sage.combinat.root_system.plot` -- :ref:`sage.combinat.root_system.root_lattice_realizations` -- :ref:`sage.combinat.root_system.root_lattice_realization_algebras` -- :ref:`sage.combinat.root_system.weight_lattice_realizations` -- :ref:`sage.combinat.root_system.root_space` -- :ref:`sage.combinat.root_system.weight_space` -- :ref:`sage.combinat.root_system.ambient_space` - -Coxeter groups --------------- - -- :ref:`sage.combinat.root_system.coxeter_group` -- :ref:`sage.combinat.root_system.weyl_group` -- :ref:`sage.combinat.root_system.extended_affine_weyl_group` -- :ref:`sage.combinat.root_system.fundamental_group` -- :ref:`sage.combinat.root_system.braid_move_calculator` -- :ref:`sage.combinat.root_system.braid_orbit` - -.. SEEALSO:: - - The categories :class:`CoxeterGroups` and :class:`WeylGroups` - -Finite reflection groups ------------------------- - -- :ref:`sage.combinat.root_system.reflection_group_complex` -- :ref:`sage.combinat.root_system.reflection_group_real` - -.. SEEALSO:: - - The category :class:`~sage.categories.complex_reflection_groups.ComplexReflectionGroups` - -Representation theory ---------------------- - -- :ref:`sage.combinat.root_system.weyl_characters` -- :ref:`sage.combinat.root_system.fusion_ring` -- :ref:`sage.combinat.root_system.integrable_representations` -- :ref:`sage.combinat.root_system.branching_rules` -- :ref:`sage.combinat.root_system.hecke_algebra_representation` -- :ref:`sage.combinat.root_system.non_symmetric_macdonald_polynomials` - -Root system data and code for specific families of Cartan types ---------------------------------------------------------------- - -- :ref:`sage.combinat.root_system.type_affine` -- :ref:`sage.combinat.root_system.type_dual` -- :ref:`sage.combinat.root_system.type_folded` -- :ref:`sage.combinat.root_system.type_reducible` -- :ref:`sage.combinat.root_system.type_relabel` -- :ref:`sage.combinat.root_system.type_marked` - -Root system data and code for specific Cartan types ---------------------------------------------------- - -- :ref:`sage.combinat.root_system.type_A` -- :ref:`sage.combinat.root_system.type_B` -- :ref:`sage.combinat.root_system.type_C` -- :ref:`sage.combinat.root_system.type_D` -- :ref:`sage.combinat.root_system.type_E` -- :ref:`sage.combinat.root_system.type_F` -- :ref:`sage.combinat.root_system.type_G` -- :ref:`sage.combinat.root_system.type_H` -- :ref:`sage.combinat.root_system.type_I` -- :ref:`sage.combinat.root_system.type_A_affine` -- :ref:`sage.combinat.root_system.type_B_affine` -- :ref:`sage.combinat.root_system.type_C_affine` -- :ref:`sage.combinat.root_system.type_D_affine` -- :ref:`sage.combinat.root_system.type_E_affine` -- :ref:`sage.combinat.root_system.type_F_affine` -- :ref:`sage.combinat.root_system.type_G_affine` -- :ref:`sage.combinat.root_system.type_BC_affine` -- :ref:`sage.combinat.root_system.type_super_A` -- :ref:`sage.combinat.root_system.type_A_infinity` -""" # currently needed to activate the backward compatibility # register_unpickle_override from . import type_A diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py index dfd959e9697..622eb87b309 100644 --- a/src/sage/combinat/root_system/all.py +++ b/src/sage/combinat/root_system/all.py @@ -1,6 +1,123 @@ -r""" -Root system features that are imported by default in the interpreter namespace """ +Root Systems + +Quickref +-------- + +- ``T = CartanType(["A", 3]), T.is_finite()`` -- Cartan types +- ``T.dynkin_diagram(), DynkinDiagram(["G",2])`` -- Dynkin diagrams +- ``T.cartan_matrix(), CartanMatrix(["F",4])`` -- Cartan matrices +- ``RootSystem(T).weight_lattice()`` -- Root systems +- ``WeylGroup(["B", 6, 1]).simple_reflections()`` -- Affine Weyl groups +- ``WeylCharacterRing(["D", 4])`` -- Weyl character rings + +Introductory material +--------------------- + +- :ref:`sage.combinat.root_system.all` -- This overview +- :class:`CartanType` -- An introduction to Cartan types +- :class:`RootSystem` -- An introduction to root systems +- :ref:`sage.combinat.root_system.plot` -- A root system visualization tutorial + +- The `Lie Methods and Related Combinatorics <../../../../../thematic_tutorials/lie.html>`_ thematic tutorial + + +Related material +---------------- + +- :ref:`sage.combinat.crystals.all` -- Crystals + +Cartan datum +------------ + +- :ref:`sage.combinat.root_system.cartan_type` +- :ref:`sage.combinat.root_system.dynkin_diagram` +- :ref:`sage.combinat.root_system.cartan_matrix` +- :ref:`sage.combinat.root_system.coxeter_matrix` +- :ref:`sage.combinat.root_system.coxeter_type` + +Root systems +------------ + +- :ref:`sage.combinat.root_system.all` +- :ref:`sage.combinat.root_system.plot` +- :ref:`sage.combinat.root_system.root_lattice_realizations` +- :ref:`sage.combinat.root_system.root_lattice_realization_algebras` +- :ref:`sage.combinat.root_system.weight_lattice_realizations` +- :ref:`sage.combinat.root_system.root_space` +- :ref:`sage.combinat.root_system.weight_space` +- :ref:`sage.combinat.root_system.ambient_space` + +Coxeter groups +-------------- + +- :ref:`sage.combinat.root_system.coxeter_group` +- :ref:`sage.combinat.root_system.weyl_group` +- :ref:`sage.combinat.root_system.extended_affine_weyl_group` +- :ref:`sage.combinat.root_system.fundamental_group` +- :ref:`sage.combinat.root_system.braid_move_calculator` +- :ref:`sage.combinat.root_system.braid_orbit` + +.. SEEALSO:: + + The categories :class:`CoxeterGroups` and :class:`WeylGroups` + +Finite reflection groups +------------------------ + +- :ref:`sage.combinat.root_system.reflection_group_complex` +- :ref:`sage.combinat.root_system.reflection_group_real` + +.. SEEALSO:: + + The category :class:`~sage.categories.complex_reflection_groups.ComplexReflectionGroups` + +Representation theory +--------------------- + +- :ref:`sage.combinat.root_system.weyl_characters` +- :ref:`sage.combinat.root_system.fusion_ring` +- :ref:`sage.combinat.root_system.integrable_representations` +- :ref:`sage.combinat.root_system.branching_rules` +- :ref:`sage.combinat.root_system.hecke_algebra_representation` +- :ref:`sage.combinat.root_system.non_symmetric_macdonald_polynomials` + +Root system data and code for specific families of Cartan types +--------------------------------------------------------------- + +- :ref:`sage.combinat.root_system.type_affine` +- :ref:`sage.combinat.root_system.type_dual` +- :ref:`sage.combinat.root_system.type_folded` +- :ref:`sage.combinat.root_system.type_reducible` +- :ref:`sage.combinat.root_system.type_relabel` +- :ref:`sage.combinat.root_system.type_marked` + +Root system data and code for specific Cartan types +--------------------------------------------------- + +- :ref:`sage.combinat.root_system.type_A` +- :ref:`sage.combinat.root_system.type_B` +- :ref:`sage.combinat.root_system.type_C` +- :ref:`sage.combinat.root_system.type_D` +- :ref:`sage.combinat.root_system.type_E` +- :ref:`sage.combinat.root_system.type_F` +- :ref:`sage.combinat.root_system.type_G` +- :ref:`sage.combinat.root_system.type_H` +- :ref:`sage.combinat.root_system.type_I` +- :ref:`sage.combinat.root_system.type_A_affine` +- :ref:`sage.combinat.root_system.type_B_affine` +- :ref:`sage.combinat.root_system.type_C_affine` +- :ref:`sage.combinat.root_system.type_D_affine` +- :ref:`sage.combinat.root_system.type_E_affine` +- :ref:`sage.combinat.root_system.type_F_affine` +- :ref:`sage.combinat.root_system.type_G_affine` +- :ref:`sage.combinat.root_system.type_BC_affine` +- :ref:`sage.combinat.root_system.type_super_A` +- :ref:`sage.combinat.root_system.type_A_infinity` +""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import @@ -24,3 +141,4 @@ lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', 'NonSymmetricMacdonaldPolynomials') lazy_import('sage.combinat.root_system.integrable_representations', 'IntegrableRepresentation') + diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index 49c0a9f05ac..3957ee889a3 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -2,7 +2,7 @@ Root systems ============ -See :ref:`sage.combinat.root_system` for an overview. +See :ref:`sage.combinat.root_system.all` for an overview. """ #***************************************************************************** # Copyright (C) 2007 Mike Hansen , diff --git a/src/sage/combinat/sf/__init__.py b/src/sage/combinat/sf/__init__.py index c12aa69ef92..8b137891791 100644 --- a/src/sage/combinat/sf/__init__.py +++ b/src/sage/combinat/sf/__init__.py @@ -1,31 +1 @@ -r""" -Symmetric Functions -=================== -- :class:`Introduction to Symmetric Functions ` - -- :ref:`sage.combinat.sf.sfa` -- :ref:`sage.combinat.sf.sf` -- :ref:`sage.combinat.sf.classical` -- :ref:`sage.combinat.sf.schur` -- :ref:`sage.combinat.sf.monomial` -- :ref:`sage.combinat.sf.multiplicative` -- :ref:`sage.combinat.sf.elementary` -- :ref:`sage.combinat.sf.homogeneous` -- :ref:`sage.combinat.sf.powersum` -- :ref:`sage.combinat.sf.character` -- :ref:`sage.combinat.sf.orthogonal` -- :ref:`sage.combinat.sf.symplectic` -- :ref:`sage.combinat.sf.dual` -- :ref:`sage.combinat.sf.orthotriang` -- :ref:`sage.combinat.sf.kfpoly` -- :ref:`sage.combinat.sf.hall_littlewood` -- :ref:`sage.combinat.sf.hecke` -- :ref:`sage.combinat.sf.jack` -- :ref:`k-Schur Functions ` -- :ref:`sage.combinat.sf.k_dual` -- :ref:`sage.combinat.sf.llt` -- :ref:`sage.combinat.sf.macdonald` -- :ref:`sage.combinat.sf.ns_macdonald` -- :ref:`sage.combinat.sf.witt` -""" diff --git a/src/sage/combinat/sf/all.py b/src/sage/combinat/sf/all.py index cc892e10e03..00f8e4f2bdf 100644 --- a/src/sage/combinat/sf/all.py +++ b/src/sage/combinat/sf/all.py @@ -1,6 +1,36 @@ r""" -Symmetric function features that are imported by default in the interpreter namespace +Symmetric Functions + +- :class:`Introduction to Symmetric Functions ` + +- :ref:`sage.combinat.sf.sfa` +- :ref:`sage.combinat.sf.sf` +- :ref:`sage.combinat.sf.classical` +- :ref:`sage.combinat.sf.schur` +- :ref:`sage.combinat.sf.monomial` +- :ref:`sage.combinat.sf.multiplicative` +- :ref:`sage.combinat.sf.elementary` +- :ref:`sage.combinat.sf.homogeneous` +- :ref:`sage.combinat.sf.powersum` +- :ref:`sage.combinat.sf.character` +- :ref:`sage.combinat.sf.orthogonal` +- :ref:`sage.combinat.sf.symplectic` +- :ref:`sage.combinat.sf.dual` +- :ref:`sage.combinat.sf.orthotriang` +- :ref:`sage.combinat.sf.kfpoly` +- :ref:`sage.combinat.sf.hall_littlewood` +- :ref:`sage.combinat.sf.hecke` +- :ref:`sage.combinat.sf.jack` +- :ref:`k-Schur Functions ` +- :ref:`sage.combinat.sf.k_dual` +- :ref:`sage.combinat.sf.llt` +- :ref:`sage.combinat.sf.macdonald` +- :ref:`sage.combinat.sf.ns_macdonald` +- :ref:`sage.combinat.sf.witt` """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 755c3cd51bd..5081f4760fe 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -21,7 +21,7 @@ from sage.combinat.partition import Partition from sage.misc.misc_c import prod from sage.arith.all import factorial, binomial -from sage.rings.all import infinity +from sage.rings.infinity import infinity ################################### # # diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 98162e978dc..3157a9bf0eb 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -27,7 +27,7 @@ #################################### from . import multiplicative, classical from sage.combinat.partition import Partition -from sage.rings.all import infinity +from sage.rings.infinity import infinity from sage.misc.misc_c import prod from sage.arith.all import factorial, binomial diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index b4181b239eb..a1926baf803 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -20,7 +20,7 @@ from . import sfa, multiplicative, classical from sage.combinat.partition import Partition from sage.arith.all import divisors -from sage.rings.all import infinity +from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.misc_c import prod diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 739b642ade1..baf6b62fd17 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -212,7 +212,11 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.rings.all import Integer, PolynomialRing, QQ, ZZ, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer +from sage.rings.infinity import infinity +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.rings.polynomial.multi_polynomial import is_MPolynomial from sage.combinat.partition import _Partitions, Partitions, Partitions_n, Partition diff --git a/src/sage/combinat/species/__init__.py b/src/sage/combinat/species/__init__.py index fcd4cab28c1..8b137891791 100644 --- a/src/sage/combinat/species/__init__.py +++ b/src/sage/combinat/species/__init__.py @@ -1,51 +1 @@ -r""" -Combinatorial Species -===================== -.. TODO:: Short blurb about species - -.. TODO:: Proofread / point to the main classes rather than the modules? - -Introductory material ---------------------- - -- :ref:`section-examples-catalan` -- :ref:`section-generic-species` - -Lazy Power Series ------------------ - -- :ref:`sage.combinat.species.stream` -- :ref:`sage.combinat.species.series_order` -- :ref:`sage.combinat.species.series` -- :ref:`sage.combinat.species.generating_series` - -Basic Species -------------- - -- :ref:`sage.combinat.species.species` -- :ref:`sage.combinat.species.empty_species` -- :ref:`sage.combinat.species.recursive_species` -- :ref:`sage.combinat.species.characteristic_species` -- :ref:`sage.combinat.species.cycle_species` -- :ref:`sage.combinat.species.partition_species` -- :ref:`sage.combinat.species.permutation_species` -- :ref:`sage.combinat.species.linear_order_species` -- :ref:`sage.combinat.species.set_species` -- :ref:`sage.combinat.species.subset_species` -- :ref:`sage.combinat.species.library` - -Operations on Species ---------------------- - -- :ref:`sage.combinat.species.sum_species` -- :ref:`sage.combinat.species.product_species` -- :ref:`sage.combinat.species.composition_species` -- :ref:`sage.combinat.species.functorial_composition_species` - -Miscellaneous -------------- - -- :ref:`sage.combinat.species.structure` -- :ref:`sage.combinat.species.misc` -""" diff --git a/src/sage/combinat/species/all.py b/src/sage/combinat/species/all.py index 8f2a6ede59e..65e18ade5d2 100644 --- a/src/sage/combinat/species/all.py +++ b/src/sage/combinat/species/all.py @@ -1,6 +1,56 @@ r""" -Combinatorial species features that are imported by default in the interpreter namespace +Combinatorial species + +.. TODO:: Short blurb about species + +.. TODO:: Proofread / point to the main classes rather than the modules? + +Introductory material +--------------------- + +- :ref:`section-examples-catalan` +- :ref:`section-generic-species` + +Lazy Power Series +----------------- + +- :ref:`sage.combinat.species.stream` +- :ref:`sage.combinat.species.series_order` +- :ref:`sage.combinat.species.series` +- :ref:`sage.combinat.species.generating_series` + +Basic Species +------------- + +- :ref:`sage.combinat.species.species` +- :ref:`sage.combinat.species.empty_species` +- :ref:`sage.combinat.species.recursive_species` +- :ref:`sage.combinat.species.characteristic_species` +- :ref:`sage.combinat.species.cycle_species` +- :ref:`sage.combinat.species.partition_species` +- :ref:`sage.combinat.species.permutation_species` +- :ref:`sage.combinat.species.linear_order_species` +- :ref:`sage.combinat.species.set_species` +- :ref:`sage.combinat.species.subset_species` +- :ref:`sage.combinat.species.library` + +Operations on Species +--------------------- + +- :ref:`sage.combinat.species.sum_species` +- :ref:`sage.combinat.species.product_species` +- :ref:`sage.combinat.species.composition_species` +- :ref:`sage.combinat.species.functorial_composition_species` + +Miscellaneous +------------- + +- :ref:`sage.combinat.species.structure` +- :ref:`sage.combinat.species.misc` """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) from .series import LazyPowerSeriesRing from .recursive_species import CombinatorialSpecies diff --git a/src/sage/combinat/words/__init__.py b/src/sage/combinat/words/__init__.py index 519fa41b0db..4dc6dd45dba 100644 --- a/src/sage/combinat/words/__init__.py +++ b/src/sage/combinat/words/__init__.py @@ -1,6 +1,5 @@ r""" -Combinatorics on Words -====================== +Combinatorics on words **Main modules and their methods:** diff --git a/src/sage/combinat/words/all.py b/src/sage/combinat/words/all.py index 1b23256de90..078ca4e48ab 100644 --- a/src/sage/combinat/words/all.py +++ b/src/sage/combinat/words/all.py @@ -1,7 +1,3 @@ -r""" -Word features that are imported by default in the interpreter namespace -""" - from .alphabet import Alphabet, build_alphabet from .morphism import WordMorphism from .paths import WordPaths diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 0070fe3f602..39cab2a6f90 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1498,11 +1498,11 @@ def inverse_key(self, A): """ S = self.plaintext_space() M = self.key_space() - if not A in M: + if A not in M: raise TypeError("A (= %s) must be a matrix in the key space of %s." % (A, self)) m = self.block_length() MatZZ = MatrixSpace(ZZ, m) - AZ = MatZZ([ [ A[i, j].lift() for j in range(m) ] for i in range(m) ]) + AZ = MatZZ([[A[i, j].lift() for j in range(m)] for i in range(m)]) AZ_adj = AZ.adjugate() u, r, s = xgcd(A.det().lift(), S.ngens()) if u != 1: @@ -3396,7 +3396,7 @@ def inverse_key(self, K, check=True): True """ if check: - if not K in self.key_space(): + if K not in self.key_space(): raise TypeError("Argument K (= %s) is not in the key space." % K) return K**-1 diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index 8d403b849f1..7ec59d4e501 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -80,6 +80,7 @@ class KnotInfoColumns(Enum): 'Unoriented Rank', 'PD Notation (vector)', 'PD Notation (KnotTheory)', + 'Braid Notation', 'Multivariable Alexander Polynomial', 'HOMFLYPT Polynomial', 'Unoriented', @@ -438,7 +439,7 @@ def version(self): sage: from sage.databases.knotinfo_db import KnotInfoDataBase sage: ki_db = KnotInfoDataBase() - sage: ki_db.version() >= '2021.7.21' # optional database_knotinfo + sage: ki_db.version() >= '2021.10.1' # optional database_knotinfo True """ self._feature.require() @@ -821,6 +822,7 @@ def _test_database(self, **options): 'braid_index': ['Braid Index', KnotInfoColumnTypes.OnlyKnots], 'braid_length': ['Braid Length', KnotInfoColumnTypes.OnlyKnots], 'braid_notation': ['Braid Notation', KnotInfoColumnTypes.KnotsAndLinks], + 'braid_notation_old': ['Braid Notation', KnotInfoColumnTypes.OnlyLinks], 'alternating': ['Alternating', KnotInfoColumnTypes.KnotsAndLinks], 'alexander_polynomial': ['Alexander', KnotInfoColumnTypes.OnlyKnots], 'jones_polynomial': ['Jones', KnotInfoColumnTypes.KnotsAndLinks], @@ -884,6 +886,19 @@ def _test_database(self, **options): '{1,1,-2,1,-2,-2}', '{1,1,1,1,1,1,1}', '{1,1,1,2,-1,2,3,-2,3}', + '{2, {-1, -1}}', + '{2, {1, 1}}', + '{3, {-2, -2, -1, 2, -1}}', + '{2, {1, 1, 1, 1}}', + '{3, {-1, 2, -1, 2, -1}}', + '{3, {-1, 2, -1, 2, -1}}', + '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', + '{3, {2, 2, 2, 1, 1, -2, 1}}', + '{3, {-1, 2, -1, -2, -2, -1, -1}}', + '{3, {1, -2, 1, 2, 2, 1, 1}}', + '{2, {-1, -1, -1, -1, -1, -1}}' + ], + dc.braid_notation_old: [ '{2, {-1, -1}}', '{2, {1, 1}}', '{4, {1, -2, 3, -2, -1, -2, -3, -2}}', diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 858d8cb5679..251e4f34a43 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -402,14 +402,17 @@ def __init__(self, options, args): options.optional.discard('optional') from sage.misc.package import list_packages for pkg in list_packages('optional', local=True).values(): - if pkg['installed'] and pkg['installed_version'] == pkg['remote_version']: - options.optional.add(pkg['name']) + if pkg.is_installed() and pkg.installed_version == pkg.remote_version: + options.optional.add(pkg.name) from sage.features import package_systems - options.optional.update(system.name for system in package_systems()) + options.optional.update(system.name + for system in package_systems()) + logger = sys.stderr if options.verbose else None from sage.features.sagemath import sage_features - options.optional.update(feature.name for feature in sage_features()) + options.optional.update(feature.name + for feature in sage_features(logger=logger)) # Check that all tags are valid for o in options.optional: diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 3b22670ec61..e74b3554e50 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -49,7 +49,7 @@ def has_internet(): EXAMPLES:: sage: from sage.doctest.external import has_internet - sage: has_internet() # random, optional -- internet + sage: has_internet() # random, optional -- internet FeatureTestResult('internet', True) """ from sage.features.internet import Internet @@ -62,20 +62,50 @@ def has_latex(): EXAMPLES:: sage: from sage.doctest.external import has_latex - sage: has_latex() # random, optional - latex - True + sage: has_latex() # optional - latex + FeatureTestResult('latex', True) """ - from sage.misc.latex import _run_latex_, _latex_file_ - from sage.misc.temporary_file import tmp_filename - try: - f = tmp_filename(ext='.tex') - O = open(f, 'w') - O.write(_latex_file_('2+3')) - O.close() - _run_latex_(f) - return True - except Exception: - return False + from sage.features.latex import latex + return latex().is_present() + +def has_xelatex(): + """ + Test if xelatex is available. + + EXAMPLES:: + + sage: from sage.doctest.external import has_xelatex + sage: has_xelatex() # optional - xelatex + FeatureTestResult('xelatex', True) + """ + from sage.features.latex import xelatex + return xelatex().is_present() + +def has_pdflatex(): + """ + Test if pdflatex is available. + + EXAMPLES:: + + sage: from sage.doctest.external import has_pdflatex + sage: has_pdflatex() # optional - pdflatex + FeatureTestResult('pdflatex', True) + """ + from sage.features.latex import pdflatex + return pdflatex().is_present() + +def has_lualatex(): + """ + Test if lualatex is available. + + EXAMPLES:: + + sage: from sage.doctest.external import has_lualatex + sage: has_lualatex() # optional - lualatex + FeatureTestResult('lualatex', True) + """ + from sage.features.latex import lualatex + return lualatex().is_present() def has_magma(): """ @@ -274,6 +304,32 @@ def has_imagemagick(): from sage.features.imagemagick import ImageMagick return ImageMagick().is_present() +def has_dvipng(): + """ + Test if dvipng is available. + + EXAMPLES:: + + sage: from sage.doctest.external import has_dvipng + sage: has_dvipng() # optional -- dvipng + FeatureTestResult('dvipng', True) + """ + from sage.features.dvipng import dvipng + return dvipng().is_present() + +def has_pdf2svg(): + """ + Test if pdf2svg is available. + + EXAMPLES:: + + sage: from sage.doctest.external import has_pdf2svg + sage: has_pdf2svg() # optional -- pdf2svg + FeatureTestResult('pdf2svg', True) + """ + from sage.features.pdf2svg import pdf2svg + return pdf2svg().is_present() + def has_rubiks(): """ Test if the rubiks package (``cu2``, ``cubex``, ``dikcube``, @@ -345,12 +401,14 @@ class AvailableSoftware(object): sage: external_software ['4ti2', 'cplex', + 'dvipng', 'ffmpeg', 'graphviz', 'gurobi', 'imagemagick', 'internet', 'latex', + 'lualatex', 'macaulay2', 'magma', 'maple', @@ -358,8 +416,11 @@ class AvailableSoftware(object): 'matlab', 'octave', 'pandoc', + 'pdf2svg', + 'pdflatex', 'rubiks', - 'scilab'] + 'scilab', + 'xelatex'] sage: 'internet' in available_software # random, optional - internet True sage: available_software.issuperset(set(['internet','latex'])) # random, optional - internet latex diff --git a/src/sage/dynamics/__init__.py b/src/sage/dynamics/__init__.py index dd754fe4154..e69de29bb2d 100644 --- a/src/sage/dynamics/__init__.py +++ b/src/sage/dynamics/__init__.py @@ -1,3 +0,0 @@ -r""" -Flat surfaces -""" diff --git a/src/sage/dynamics/all.py b/src/sage/dynamics/all.py index 71d15255985..20ca3b9d723 100644 --- a/src/sage/dynamics/all.py +++ b/src/sage/dynamics/all.py @@ -1,4 +1,6 @@ """ +Flat surfaces + Some code about flat surfaces and interval exchanges has been removed from Sage. The package ``surface_dynamics`` contains all that code and much more. For more information, see @@ -14,6 +16,10 @@ sage -pip install surface_dynamics --user """ +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + from sage.misc.lazy_import import lazy_import from sage.dynamics.arithmetic_dynamics.all import * diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 7cc72103736..6c2b4611a21 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -872,10 +872,9 @@ def dynatomic_polynomial(self, period): PHI = PHI(fm._polys) / PHI(fm1._polys) #even when the ring can be passed to singular in quo_rem, #it can't always do the division, so we call Maxima - from sage.rings.padics.generic_nodes import is_pAdicField, is_pAdicRing if period != [0,1]: #period==[0,1] we don't need to do any division BR = self.domain().base_ring().base_ring() - if not (is_pAdicRing(BR) or is_pAdicField(BR)): + if not isinstance(BR, (sage.rings.abc.pAdicRing, sage.rings.abc.pAdicField)): try: QR2 = PHI.numerator()._maxima_().divide(PHI.denominator()) if not QR2[1].sage(): @@ -6940,10 +6939,10 @@ def conjugating_set(self, other, R=None, num_cpus=2): sage: P. = ProjectiveSpace(GF(7), 1) sage: D6 = DynamicalSystem_projective([y^2, x^2]) - sage: D6.conjugating_set(D6) + sage: sorted(D6.conjugating_set(D6)) [ - [1 0] [0 1] [0 2] [4 0] [2 0] [0 4] - [0 1], [1 0], [1 0], [0 1], [0 1], [1 0] + [0 1] [0 2] [0 4] [1 0] [2 0] [4 0] + [1 0], [1 0], [1 0], [0 1], [0 1], [0 1] ] :: diff --git a/src/sage/env.py b/src/sage/env.py index e5af0374a2f..40ace135f0d 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -237,6 +237,9 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st OPENMP_CFLAGS = var("OPENMP_CFLAGS", "") OPENMP_CXXFLAGS = var("OPENMP_CXXFLAGS", "") +# Make sure mpmath uses Sage types +os.environ['MPMATH_SAGE'] = '1' + # misc SAGE_BANNER = var("SAGE_BANNER", "") SAGE_IMPORTALL = var("SAGE_IMPORTALL", "yes") diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 10acc5e3649..d49f1fcfdb4 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -302,9 +302,7 @@ AUTHOR: import operator from copy import copy -from sage.rings.real_mpfr cimport RealField_class, RealNumber -from sage.rings.complex_mpfr import ComplexField_class -from sage.rings.all import RDF, CDF +import sage.rings.abc from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.structure.element cimport parent @@ -466,41 +464,34 @@ def fast_callable(x, domain=None, vars=None, etb = ExpressionTreeBuilder(vars=vars, domain=domain) et = x._fast_callable_(etb) - if isinstance(domain, RealField_class): - import sage.ext.interpreters.wrapper_rr - builder = sage.ext.interpreters.wrapper_rr.Wrapper_rr - + if isinstance(domain, sage.rings.abc.RealField): + from sage.ext.interpreters.wrapper_rr import Wrapper_rr as builder str = InstructionStream(sage.ext.interpreters.wrapper_rr.metadata, len(vars), domain) - elif isinstance(domain, ComplexField_class): - import sage.ext.interpreters.wrapper_cc - builder = sage.ext.interpreters.wrapper_cc.Wrapper_cc + elif isinstance(domain, sage.rings.abc.ComplexField): + from sage.ext.interpreters.wrapper_cc import Wrapper_cc as builder str = InstructionStream(sage.ext.interpreters.wrapper_cc.metadata, len(vars), domain) - elif domain == RDF or domain is float: - import sage.ext.interpreters.wrapper_rdf - builder = sage.ext.interpreters.wrapper_rdf.Wrapper_rdf + elif isinstance(domain, sage.rings.abc.RealDoubleField) or domain is float: + from sage.ext.interpreters.wrapper_rdf import Wrapper_rdf as builder str = InstructionStream(sage.ext.interpreters.wrapper_rdf.metadata, len(vars), domain) - elif domain == CDF: - import sage.ext.interpreters.wrapper_cdf - builder = sage.ext.interpreters.wrapper_cdf.Wrapper_cdf + elif isinstance(domain, sage.rings.abc.ComplexDoubleField): + from sage.ext.interpreters.wrapper_cdf import Wrapper_cdf as builder str = InstructionStream(sage.ext.interpreters.wrapper_cdf.metadata, len(vars), domain) elif domain is None: - import sage.ext.interpreters.wrapper_py - builder = sage.ext.interpreters.wrapper_py.Wrapper_py + from sage.ext.interpreters.wrapper_py import Wrapper_py as builder str = InstructionStream(sage.ext.interpreters.wrapper_py.metadata, len(vars)) else: - import sage.ext.interpreters.wrapper_el - builder = sage.ext.interpreters.wrapper_el.Wrapper_el + from sage.ext.interpreters.wrapper_el import Wrapper_el as builder str = InstructionStream(sage.ext.interpreters.wrapper_el.metadata, len(vars), domain) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 25e4a40dcd2..71ab3c02633 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -842,6 +842,6 @@ def _is_present(self): import importlib try: importlib.import_module(self.name) - except ImportError: - return FeatureTestResult(self, False, reason="Failed to import `{name}`.".format(name=self.name)) - return FeatureTestResult(self, True, reason="Successfully imported `{name}`.".format(name=self.name)) + except ImportError as exception: + return FeatureTestResult(self, False, reason=f"Failed to import `{self.name}`: {exception}") + return FeatureTestResult(self, True, reason=f"Successfully imported `{self.name}`.") diff --git a/src/sage/features/dvipng.py b/src/sage/features/dvipng.py new file mode 100644 index 00000000000..27c5bddc059 --- /dev/null +++ b/src/sage/features/dvipng.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +r""" +Check for dvipng +""" +# **************************************************************************** +# Copyright (C) 2021 Sebastien Labbe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from . import Executable + +class dvipng(Executable): + r""" + A :class:`sage.features.Feature` describing the presence of ``dvipng`` + + EXAMPLES:: + + sage: from sage.features.dvipng import dvipng + sage: dvipng().is_present() # optional: dvipng + FeatureTestResult('dvipng', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.dvipng import dvipng + sage: isinstance(dvipng(), dvipng) + True + """ + Executable.__init__(self, "dvipng", executable="dvipng", + url="https://savannah.nongnu.org/projects/dvipng/") diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py new file mode 100644 index 00000000000..a0f0d6f4096 --- /dev/null +++ b/src/sage/features/latex.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +r""" +Check for pdflatex and equivalent programs +""" +# **************************************************************************** +# Copyright (C) 2021 Sebastien Labbe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from . import Executable, FeatureTestResult + +class latex(Executable): + r""" + A :class:`sage.features.Feature` describing the presence of ``latex`` + + EXAMPLES:: + + sage: from sage.features.latex import latex + sage: latex().is_present() # optional: latex + FeatureTestResult('latex', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latex import latex + sage: isinstance(latex(), latex) + True + """ + Executable.__init__(self, "latex", executable="latex", + url="https://www.latex-project.org/") + + def is_functional(self): + r""" + Return whether `latex` in the path is functional. + + EXAMPLES: + + sage: from sage.features.latex import latex + sage: latex().is_functional() # optional: latex + FeatureTestResult('latex', True) + """ + lines = [] + lines.append(r"\documentclass{article}") + lines.append(r"\begin{document}") + lines.append(r"$\alpha+2$") + lines.append(r"\end{document}") + content = '\n'.join(lines) + + # create a simple tex file with the content + from sage.misc.temporary_file import tmp_filename + base_filename_tex = tmp_filename(ext='.tex') + with open(base_filename_tex, 'w') as f: + f.write(content) + import os + base, filename_tex = os.path.split(base_filename_tex) + + # running latex + from subprocess import run + cmd = ['latex', '-interaction=nonstopmode', filename_tex] + cmd = ' '.join(cmd) + result = run(cmd, shell=True, cwd=base, capture_output=True, text=True) + + # return + if result.returncode == 0: + return FeatureTestResult(self, True) + else: + return FeatureTestResult(self, False, reason="Running latex on " + "a sample file returned non-zero " + "exit status {}".format(result.returncode)) + +class pdflatex(Executable): + r""" + A :class:`sage.features.Feature` describing the presence of ``pdflatex`` + + EXAMPLES:: + + sage: from sage.features.latex import pdflatex + sage: pdflatex().is_present() # optional: pdflatex + FeatureTestResult('pdflatex', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latex import pdflatex + sage: isinstance(pdflatex(), pdflatex) + True + """ + Executable.__init__(self, "pdflatex", executable="pdflatex", + url="https://www.latex-project.org/") + +class xelatex(Executable): + r""" + A :class:`sage.features.Feature` describing the presence of ``xelatex`` + + EXAMPLES:: + + sage: from sage.features.latex import xelatex + sage: xelatex().is_present() # optional: xelatex + FeatureTestResult('xelatex', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latex import xelatex + sage: isinstance(xelatex(), xelatex) + True + """ + Executable.__init__(self, "xelatex", executable="xelatex", + url="https://www.latex-project.org/") + +class lualatex(Executable): + r""" + A :class:`sage.features.Feature` describing the presence of ``lualatex`` + + EXAMPLES:: + + sage: from sage.features.latex import lualatex + sage: lualatex().is_present() # optional: lualatex + FeatureTestResult('lualatex', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latex import lualatex + sage: isinstance(lualatex(), lualatex) + True + """ + Executable.__init__(self, "lualatex", executable="lualatex", + url="https://www.latex-project.org/") diff --git a/src/sage/features/pdf2svg.py b/src/sage/features/pdf2svg.py new file mode 100644 index 00000000000..f0b634f5ff4 --- /dev/null +++ b/src/sage/features/pdf2svg.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +r""" +Check for pdf2svg +""" +# **************************************************************************** +# Copyright (C) 2021 Sebastien Labbe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from . import Executable + +class pdf2svg(Executable): + r""" + A :class:`sage.features.Feature` describing the presence of ``pdf2svg`` + + EXAMPLES:: + + sage: from sage.features.pdf2svg import pdf2svg + sage: pdf2svg().is_present() # optional: pdf2svg + FeatureTestResult('pdf2svg', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.pdf2svg import pdf2svg + sage: isinstance(pdf2svg(), pdf2svg) + True + """ + Executable.__init__(self, "pdf2svg", executable="pdf2svg", + spkg='pdf2svg', + url="http://www.cityinthesky.co.uk/opensource/pdf2svg/") diff --git a/src/sage/features/polymake.py b/src/sage/features/polymake.py new file mode 100644 index 00000000000..1e6d7b81b99 --- /dev/null +++ b/src/sage/features/polymake.py @@ -0,0 +1,25 @@ +from . import PythonModule +from .join_feature import JoinFeature + + +class JuPyMake(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of the ``JuPyMake`` + module, a Python interface to the polymake library. + + EXAMPLES:: + + sage: from sage.features.polymake import JuPyMake + sage: JuPyMake().is_present() # optional: jupymake + FeatureTestResult('jupymake', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.polymake import JuPyMake + sage: isinstance(JuPyMake(), JuPyMake) + True + """ + JoinFeature.__init__(self, "jupymake", + [PythonModule("JuPyMake", spkg="jupymake")]) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index dfc138e9126..2d7d6e9ab79 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -27,7 +27,7 @@ def __init__(self): # Testing whether sage.combinat itself can be imported is meaningless. # Hence, we test a Python module within the package. JoinFeature.__init__(self, 'sage.combinat', - [PythonModule('sage.combinat.combinations')]) + [PythonModule('sage.combinat.combination')]) class sage__geometry__polyhedron(PythonModule): @@ -162,7 +162,7 @@ def __init__(self): spkg="sagemath_symbolics") -def sage_features(): +def sage_features(logger=None): """ Return features corresponding to parts of the Sage library. @@ -193,5 +193,8 @@ def sage_features(): sage__rings__number_field(), sage__rings__real_double(), sage__symbolic()]: - if feature.is_present(): + result = feature.is_present() + if logger: + logger.write(f'{result}, reason: {result.reason}\n') + if result: yield feature diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index d9cec09210d..de8a18be031 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -2013,7 +2013,7 @@ def _eval_(self, n, a, b, x): return legendre_P(n, x) if SR(n).is_numeric() and not (n > -1): raise ValueError("n must be greater than -1, got n = {0}".format(n)) - if not n in ZZ: + if n not in ZZ: return from .gamma import gamma s = sum(binomial(n,m) * gamma(a+b+n+m+1) / gamma(a+m+1) * ((x-1)/2)**m for m in range(n+1)) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 3fd9048ea87..9fec4911120 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -2191,7 +2191,7 @@ def _eval_(self, x, s): ValueError: not a set: 0 """ from sage.categories.sets_cat import Sets - if not s in Sets(): + if s not in Sets(): raise ValueError("not a set: {}".format(s)) def _latex_(self): diff --git a/src/sage/geometry/abc.pyx b/src/sage/geometry/abc.pyx index 199db3ec6eb..4db85b7ace8 100644 --- a/src/sage/geometry/abc.pyx +++ b/src/sage/geometry/abc.pyx @@ -72,7 +72,7 @@ class Polyhedron: By design, there is a unique direct subclass:: sage: sage.geometry.abc.Polyhedron.__subclasses__() # optional - sage.geometry.polyhedron - [] + [] sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 True diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 5fbe3784b80..4a1b567a6b0 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -1098,7 +1098,7 @@ def plot(self, **options): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.plot() + sage: quadrant.plot() # optional - sage.plot Graphics object consisting of 9 graphics primitives """ tp = ToricPlotter(options, self.lattice().degree(), self.rays()) @@ -3475,7 +3475,7 @@ def plot(self, **options): EXAMPLES:: sage: quadrant = Cone([(1,0), (0,1)]) - sage: quadrant.plot() + sage: quadrant.plot() # optional - sage.plot Graphics object consisting of 9 graphics primitives """ # What to do with 3-d cones in 5-d? Use some projection method? diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index 5f8754941d4..9aa8fa24784 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -504,7 +504,7 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, sage: fan = Fan([c1, c2], allow_arrangement=True) sage: fan.ngenerating_cones() 7 - sage: fan.plot() + sage: fan.plot() # optional - sage.plot Graphics3d Object Cones of different dimension:: @@ -524,7 +524,7 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, sage: c3 = Cone([[0, 1, 1], [1, 0, 1], [0, -1, 1], [-1, 0, 1]]) sage: c1 = Cone([[0, 0, 1]]) sage: fan1 = Fan([c1, c3], allow_arrangement=True) - sage: fan1.plot() + sage: fan1.plot() # optional - sage.plot Graphics3d Object A 3-d cone and two 2-d cones:: @@ -2970,7 +2970,7 @@ def plot(self, **options): EXAMPLES:: sage: fan = toric_varieties.dP6().fan() - sage: fan.plot() + sage: fan.plot() # optional - sage.plot Graphics object consisting of 31 graphics primitives """ tp = ToricPlotter(options, self.lattice().degree(), self.rays()) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index bebe858bd28..13cd5c29996 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -24,7 +24,7 @@ :: - sage: g.plot(axes=True) + sage: g.plot(axes=True) # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -37,7 +37,7 @@ sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3 + I) sage: g.length() arccosh(11/2) - sage: g.plot(axes=True) + sage: g.plot(axes=True) # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -49,7 +49,7 @@ sage: g = HyperbolicPlane().UHP().get_geodesic(I, 3*I) sage: g Geodesic in UHP from I to 3*I - sage: g.plot() + sage: g.plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -888,7 +888,7 @@ def perpendicular_bisector(self): sage: PD = HyperbolicPlane().PD() sage: g = PD.get_geodesic(-0.3+0.4*I,+0.7-0.1*I) sage: h = g.perpendicular_bisector() - sage: P = g.plot(color='blue')+h.plot(color='orange');P + sage: P = g.plot(color='blue')+h.plot(color='orange');P # optional - sage.plot Graphics object consisting of 4 graphics primitives .. PLOT:: @@ -1108,7 +1108,7 @@ def plot(self, boundary=True, **options): EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() - sage: UHP.get_geodesic(0, 1).plot() + sage: UHP.get_geodesic(0, 1).plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1119,7 +1119,7 @@ def plot(self, boundary=True, **options): :: - sage: UHP.get_geodesic(I, 3+4*I).plot(linestyle="dashed", color="brown") + sage: UHP.get_geodesic(I, 3+4*I).plot(linestyle="dashed", color="brown") # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1130,7 +1130,7 @@ def plot(self, boundary=True, **options): :: - sage: UHP.get_geodesic(1, infinity).plot(color='orange') + sage: UHP.get_geodesic(1, infinity).plot(color='orange') # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -1144,25 +1144,25 @@ def plot(self, boundary=True, **options): Plotting a line with ``boundary=True``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(0, I) - sage: g.plot() + sage: g.plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives Plotting a line with ``boundary=False``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(0, I) - sage: g.plot(boundary=False) + sage: g.plot(boundary=False) # optional - sage.plot Graphics object consisting of 1 graphics primitive Plotting a circle with ``boundary=True``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(-3, 19) - sage: g.plot() + sage: g.plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives Plotting a circle with ``boundary=False``. :: sage: g = HyperbolicPlane().UHP().get_geodesic(3, 4) - sage: g.plot(boundary=False) + sage: g.plot(boundary=False) # optional - sage.plot Graphics object consisting of 1 graphics primitive """ @@ -1381,7 +1381,7 @@ def perpendicular_bisector(self): # UHP sage: UHP = HyperbolicPlane().UHP() sage: g = UHP.get_geodesic(1+I,2+0.5*I) sage: h = g.perpendicular_bisector() - sage: show(g.plot(color='blue')+h.plot(color='orange')) + sage: show(g.plot(color='blue')+h.plot(color='orange')) # optional - sage.plot .. PLOT:: @@ -2010,7 +2010,7 @@ def plot(self, boundary=True, **options): First some lines:: sage: PD = HyperbolicPlane().PD() - sage: PD.get_geodesic(0, 1).plot() + sage: PD.get_geodesic(0, 1).plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2019,7 +2019,7 @@ def plot(self, boundary=True, **options): :: - sage: PD.get_geodesic(0, 0.3+0.8*I).plot() + sage: PD.get_geodesic(0, 0.3+0.8*I).plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2029,15 +2029,15 @@ def plot(self, boundary=True, **options): Then some generic geodesics:: - sage: PD.get_geodesic(-0.5, 0.3+0.4*I).plot() + sage: PD.get_geodesic(-0.5, 0.3+0.4*I).plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives sage: g = PD.get_geodesic(-1, exp(3*I*pi/7)) - sage: G = g.plot(linestyle="dashed",color="red"); G + sage: G = g.plot(linestyle="dashed",color="red"); G # optional - sage.plot Graphics object consisting of 2 graphics primitives sage: h = PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11)) - sage: H = h.plot(thickness=6, color="orange"); H - Graphics object consisting of 2 graphics primitives - sage: show(G+H) + sage: H = h.plot(thickness=6, color="orange"); H # optional - sage.plot + Graphics object consisting of 2 graphics primitives # optional - sage.plot + sage: show(G+H) # optional - sage.plot .. PLOT:: @@ -2102,7 +2102,7 @@ class HyperbolicGeodesicKM(HyperbolicGeodesic): sage: g = KM.get_geodesic(KM.get_point((0.1,0.9)), KM.get_point((-0.1,-0.9))) sage: g = KM.get_geodesic((0.1,0.9),(-0.1,-0.9)) sage: h = KM.get_geodesic((-0.707106781,-0.707106781),(0.707106781,-0.707106781)) - sage: P = g.plot(color='orange')+h.plot(); P + sage: P = g.plot(color='orange')+h.plot(); P # optional - sage.plot Graphics object consisting of 4 graphics primitives @@ -2123,7 +2123,7 @@ def plot(self, boundary=True, **options): EXAMPLES:: - sage: HyperbolicPlane().KM().get_geodesic((0,0), (1,0)).plot() + sage: HyperbolicPlane().KM().get_geodesic((0,0), (1,0)).plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives .. PLOT:: @@ -2183,7 +2183,7 @@ def plot(self, show_hyperboloid=True, **graphics_options): sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic \ ....: import * sage: g = HyperbolicPlane().HM().random_geodesic() - sage: g.plot() + sage: g.plot() # optional - sage.plot Graphics3d Object .. PLOT:: diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 1914442251c..9b7163b525a 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -689,7 +689,7 @@ def plot(self, **kwds): EXAMPLES:: sage: L. = HyperplaneArrangements(QQ) - sage: L(x, y, x+y-2).plot() + sage: L(x, y, x+y-2).plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot @@ -1690,7 +1690,7 @@ def vertices(self, exclude_sandwiched=False): (6, 21, 16) sage: A.vertices() ((-2/3, 1/3), (-1/3, -1/3), (0, -1), (0, 0), (1/3, -2/3), (2/3, -1/3)) - sage: point2d(A.vertices(), size=20) + A.plot() + sage: point2d(A.vertices(), size=20) + A.plot() # optional - sage.plot Graphics object consisting of 7 graphics primitives sage: H. = HyperplaneArrangements(QQ) diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index fd5bb34da7f..589d45d0750 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -604,7 +604,7 @@ def plot(self, **kwds): EXAMPLES:: sage: L. = HyperplaneArrangements(QQ) - sage: (x+y-2).plot() + sage: (x+y-2).plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot_hyperplane diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index 59da4ee3d25..54bae6bec4f 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -56,25 +56,25 @@ sage: H3. = HyperplaneArrangements(QQ) sage: A = H3([(1,0,0), 0], [(0,0,1), 5]) - sage: A.plot(hyperplane_opacities=0.5, hyperplane_labels=True, hyperplane_legend=False) + sage: A.plot(hyperplane_opacities=0.5, hyperplane_labels=True, hyperplane_legend=False) # optional - sage.plot Graphics3d Object sage: c = H3([(1,0,0),0], [(0,0,1),5]) - sage: c.plot(ranges=10) + sage: c.plot(ranges=10) # optional - sage.plot Graphics3d Object - sage: c.plot(ranges=[[9.5,10], [-3,3]]) + sage: c.plot(ranges=[[9.5,10], [-3,3]]) # optional - sage.plot Graphics3d Object - sage: c.plot(ranges=[[[9.5,10], [-3,3]], [[-6,6], [-5,5]]]) + sage: c.plot(ranges=[[[9.5,10], [-3,3]], [[-6,6], [-5,5]]]) # optional - sage.plot Graphics3d Object sage: H2. = HyperplaneArrangements(QQ) sage: h = H2([(1,1),0], [(1,-1),0], [(0,1),2]) - sage: h.plot(ranges=20) + sage: h.plot(ranges=20) # optional - sage.plot Graphics object consisting of 3 graphics primitives - sage: h.plot(ranges=[-1, 10]) + sage: h.plot(ranges=[-1, 10]) # optional - sage.plot Graphics object consisting of 3 graphics primitives - sage: h.plot(ranges=[[-1, 1], [-5, 5], [-1, 10]]) + sage: h.plot(ranges=[[-1, 1], [-5, 5], [-1, 10]]) # optional - sage.plot Graphics object consisting of 3 graphics primitives sage: a = hyperplane_arrangements.coordinate(3) @@ -83,24 +83,24 @@ sage: opts['label_offsets'] = [(0,2,2), (2,0,2), (2,2,0)] sage: opts['hyperplane_legend'] = False sage: opts['hyperplane_opacities'] = 0.7 - sage: a.plot(**opts) + sage: a.plot(**opts) # optional - sage.plot Graphics3d Object sage: opts['hyperplane_labels'] = 'short' - sage: a.plot(**opts) + sage: a.plot(**opts) # optional - sage.plot Graphics3d Object sage: H. = HyperplaneArrangements(QQ) sage: pts = H(3*u+4, 2*u+5, 7*u+1) - sage: pts.plot(hyperplane_colors=['yellow','black','blue']) + sage: pts.plot(hyperplane_colors=['yellow','black','blue']) # optional - sage.plot Graphics object consisting of 3 graphics primitives - sage: pts.plot(point_sizes=[50,100,200], hyperplane_colors='blue') + sage: pts.plot(point_sizes=[50,100,200], hyperplane_colors='blue') # optional - sage.plot Graphics object consisting of 3 graphics primitives sage: H. = HyperplaneArrangements(QQ) sage: a = H(x, y+1, y+2) - sage: a.plot(hyperplane_labels=True,label_colors='blue',label_fontsize=18) + sage: a.plot(hyperplane_labels=True,label_colors='blue',label_fontsize=18) # optional - sage.plot Graphics3d Object - sage: a.plot(hyperplane_labels=True,label_colors=['red','green','black']) + sage: a.plot(hyperplane_labels=True,label_colors=['red','green','black']) # optional - sage.plot Graphics3d Object """ @@ -145,7 +145,7 @@ def plot(hyperplane_arrangement, **kwds): EXAMPLES:: sage: B = hyperplane_arrangements.semiorder(4) - sage: B.plot() + sage: B.plot() # optional - sage.plot Displaying the essentialization. Graphics3d Object """ @@ -333,34 +333,34 @@ def plot_hyperplane(hyperplane, **kwds): sage: H1. = HyperplaneArrangements(QQ) sage: a = 3*x + 4 - sage: a.plot() # indirect doctest + sage: a.plot() # indirect doctest # optional - sage.plot Graphics object consisting of 3 graphics primitives - sage: a.plot(point_size=100,hyperplane_label='hello') + sage: a.plot(point_size=100,hyperplane_label='hello') # optional - sage.plot Graphics object consisting of 3 graphics primitives sage: H2. = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 - sage: b.plot() + sage: b.plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives - sage: b.plot(ranges=(1,5),label_offset=(2,-1)) + sage: b.plot(ranges=(1,5),label_offset=(2,-1)) # optional - sage.plot Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label':True, 'label_color':'green', ....: 'label_fontsize':24, 'label_offset':(0,1.5)} - sage: b.plot(**opts) + sage: b.plot(**opts) # optional - sage.plot Graphics object consisting of 2 graphics primitives sage: H3. = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 - sage: c.plot() + sage: c.plot() # optional - sage.plot Graphics3d Object - sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) + sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) # optional - sage.plot Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 - sage: d.plot(opacity=0.8) + sage: d.plot(opacity=0.8) # optional - sage.plot Graphics3d Object sage: e = 4*x + 2*z + 3 - sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) + sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) # optional - sage.plot Graphics3d Object """ if hyperplane.base_ring().characteristic(): diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index 8db5599877f..28c256061b3 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -1196,8 +1196,8 @@ cdef class InequalityCollection: Check that :trac:`21037` is fixed:: sage: P = Polyhedron(vertices=((0, 0), (17,3))) - sage: P += 1/1000*polytopes.regular_polygon(5) - sage: P.integral_points() + sage: P += 1/1000*polytopes.regular_polygon(5) # optional - sage.rings.number_field + sage: P.integral_points() # optional - sage.rings.number_field ((0, 0), (17, 3)) """ cdef list A diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index ad977843958..6c12c0a01d3 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -464,7 +464,7 @@ def plot(self, **kwargs): sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]) - sage: polygon = NP.plot() + sage: polygon = NP.plot() # optional - sage.plot """ vertices = self.vertices() if len(vertices) == 0: diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 10e8c34f79d..948196fa306 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -203,7 +203,7 @@ class PolyhedralComplex(GenericCellComplex): (A vertex at (0, 1/4),), (A vertex at (1/7, 2/7),), (A vertex at (1/3, 1/3),)] - sage: pc.plot() + sage: pc.plot() # optional - sage.plot Graphics object consisting of 10 graphics primitives sage: pc.is_pure() True @@ -728,7 +728,7 @@ def plot(self, **kwds): sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) sage: pc = PolyhedralComplex([p1, p2]) - sage: pc.plot() + sage: pc.plot() # optional - sage.plot Graphics object consisting of 10 graphics primitives """ if self.dimension() > 3: @@ -937,7 +937,7 @@ def face_poset(self): sage: poset Finite poset containing 11 elements sage: d = {i: i.vertices_matrix() for i in poset} - sage: poset.plot(element_labels=d) + sage: poset.plot(element_labels=d) # optional - sage.plot Graphics object consisting of 28 graphics primitives For a nonbounded polyhedral complex:: diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 58af1b3059c..145feafcc7e 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -1381,7 +1381,7 @@ def integral_hull(self): sage: P = Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]], # optional - pynormaliz ....: backend='normaliz') sage: PI = P.integral_hull() # optional - pynormaliz - sage: P.plot(color='yellow') + PI.plot(color='green') # optional - pynormaliz + sage: P.plot(color='yellow') + PI.plot(color='green') # optional - pynormaliz # optional - sage.plot Graphics object consisting of 10 graphics primitives sage: PI.Vrepresentation() # optional - pynormaliz (A vertex at (-1, 0), A vertex at (0, 1), A ray in the direction (1, 0)) diff --git a/src/sage/geometry/polyhedron/backend_polymake.py b/src/sage/geometry/polyhedron/backend_polymake.py index 6f595395153..34082d9ee92 100644 --- a/src/sage/geometry/polyhedron/backend_polymake.py +++ b/src/sage/geometry/polyhedron/backend_polymake.py @@ -96,9 +96,12 @@ class Polyhedron_polymake(Polyhedron_base): Quadratic fields work:: - sage: V = polytopes.dodecahedron().vertices_list() - sage: Polyhedron(vertices=V, backend='polymake') # optional - polymake - A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 20 vertices + sage: V = polytopes.dodecahedron().vertices_list() # optional - sage.rings.number_field + sage: Polyhedron(vertices=V, backend='polymake') # optional - polymake # optional - sage.rings.number_field + A 3-dimensional polyhedron + in (Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790?)^3 + defined as the convex hull of 20 vertices TESTS: @@ -662,11 +665,11 @@ def __setstate__(self, state): sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - polymake sage: P._test_polymake_pickling(other=P2) # optional - polymake - sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') # optional - polymake + sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') # optional - polymake # optional - sage.rings.number_field Possible output... - sage: P1 = loads(dumps(P)) # optional - polymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - polymake - sage: P._test_polymake_pickling(other=P2) # optional - polymake + sage: P1 = loads(dumps(P)) # optional - polymake # optional - sage.rings.number_field + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - polymake # optional - sage.rings.number_field + sage: P._test_polymake_pickling(other=P2) # optional - polymake # optional - sage.rings.number_field """ if "_pickle_vertices" in state[1]: vertices = state[1].pop("_pickle_vertices") diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 5e2a62d37df..23e68890871 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -32,7 +32,7 @@ import itertools -from sage.structure.element import Element, coerce_binop, is_Vector, is_Matrix +from sage.structure.element import coerce_binop, is_Vector, is_Matrix from sage.structure.richcmp import rich_to_bool, op_NE from sage.cpython.string import bytes_to_str @@ -51,11 +51,10 @@ from sage.arith.misc import integer_ceil as ceil from sage.misc.lazy_import import lazy_import lazy_import('sage.groups.matrix_gps.finitely_generated', 'MatrixGroup') -from sage.geometry.convex_set import ConvexSet_closed, AffineHullProjectionData +from sage.geometry.convex_set import AffineHullProjectionData -import sage.geometry.abc from .constructor import Polyhedron -from sage.geometry.relative_interior import RelativeInterior +from .base1 import Polyhedron_base1 from sage.categories.sets_cat import EmptySetError ######################################################################### @@ -101,7 +100,7 @@ def is_Polyhedron(X): ######################################################################### -class Polyhedron_base(Element, ConvexSet_closed, sage.geometry.abc.Polyhedron): +class Polyhedron_base(Polyhedron_base1): """ Base class for Polyhedron objects @@ -174,141 +173,26 @@ class Polyhedron_base(Element, ConvexSet_closed, sage.geometry.abc.Polyhedron): sage: TestSuite(P).run() """ - def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds): + def _init_empty_polyhedron(self): """ - Initializes the polyhedron. - - See :class:`Polyhedron_base` for a description of the input - data. + Initializes an empty polyhedron. TESTS:: - sage: p = Polyhedron() # indirect doctests - - sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: from sage.geometry.polyhedron.parent import Polyhedra_field - sage: parent = Polyhedra_field(AA, 1, 'field') - sage: Vrep = [[[0], [1/2], [1]], [], []] - sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, - ....: Vrep_minimal=False, Hrep_minimal=True) - Traceback (most recent call last): - ... - ValueError: if both Vrep and Hrep are provided, they must be minimal... - - Illustration of ``pref_rep``. - Note that ``ppl`` doesn't support precomputed data:: - - sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_QQ_ppl - sage: from sage.geometry.polyhedron.parent import Polyhedra_QQ_ppl - sage: parent = Polyhedra_QQ_ppl(QQ, 1, 'ppl') - sage: p = Polyhedron_QQ_ppl(parent, Vrep, 'nonsense', - ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrep') - sage: p = Polyhedron_QQ_ppl(parent, 'nonsense', Hrep, - ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Hrep') - sage: p = Polyhedron_QQ_ppl(parent, 'nonsense', Hrep, - ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrepresentation') - Traceback (most recent call last): - ... - ValueError: ``pref_rep`` must be one of ``(None, 'Vrep', 'Hrep')`` - - If the backend supports precomputed data, ``pref_rep`` is ignored:: - - sage: p = Polyhedron_field(parent, Vrep, 'nonsense', - ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrep') - Traceback (most recent call last): - ... - TypeError: ..._init_Hrepresentation() takes 3 positional arguments but 9 were given - - The empty polyhedron is detected when the Vrepresentation is given with generator; - see :trac:`29899`:: - - sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd - sage: from sage.geometry.polyhedron.parent import Polyhedra_QQ_cdd - sage: parent = Polyhedra_QQ_cdd(QQ, 0, 'cdd') - sage: p = Polyhedron_QQ_cdd(parent, [iter([]), iter([]), iter([])], None) - """ - Element.__init__(self, parent=parent) - if Vrep is not None and Hrep is not None: - if not (Vrep_minimal is True and Hrep_minimal is True): - raise ValueError("if both Vrep and Hrep are provided, they must be minimal" - " and Vrep_minimal and Hrep_minimal must both be True") - if hasattr(self, "_init_from_Vrepresentation_and_Hrepresentation"): - self._init_from_Vrepresentation_and_Hrepresentation(Vrep, Hrep) - return - else: - if pref_rep is None: - # Initialize from Hrepresentation if this seems simpler. - Vrep = [tuple(Vrep[0]), tuple(Vrep[1]), Vrep[2]] - Hrep = [tuple(Hrep[0]), Hrep[1]] - if len(Hrep[0]) < len(Vrep[0]) + len(Vrep[1]): - pref_rep = 'Hrep' - else: - pref_rep = 'Vrep' - if pref_rep == 'Vrep': - Hrep = None - elif pref_rep == 'Hrep': - Vrep = None - else: - raise ValueError("``pref_rep`` must be one of ``(None, 'Vrep', 'Hrep')``") - if Vrep is not None: - vertices, rays, lines = Vrep - - # We build tuples out of generators now to detect the empty polyhedron. - - # The damage is limited: - # The backend will have to obtain all elements from the generator anyway. - # The generators are mainly for saving time with initializing from - # Vrepresentation and Hrepresentation. - # If we dispose of one of them (see above), it is wasteful to have generated it. - - # E.g. the dilate will be set up with new Vrepresentation and Hrepresentation - # regardless of the backend along with the argument ``pref_rep``. - # As we only use generators, there is no penalty to this approach - # (and the method ``dilation`` does not have to distinguish by backend). - - if not isinstance(vertices, (tuple, list)): - vertices = tuple(vertices) - if not isinstance(rays, (tuple, list)): - rays = tuple(rays) - if not isinstance(lines, (tuple, list)): - lines = tuple(lines) - - if vertices or rays or lines: - self._init_from_Vrepresentation(vertices, rays, lines, **kwds) - else: - self._init_empty_polyhedron() - elif Hrep is not None: - ieqs, eqns = Hrep - self._init_from_Hrepresentation(ieqs, eqns, **kwds) - else: - self._init_empty_polyhedron() + sage: Polyhedron().vertex_adjacency_matrix() # indirect doctest + [] + sage: Polyhedron().facet_adjacency_matrix() + [0] + """ + Polyhedron_base1._init_empty_polyhedron(self) - def __hash__(self): - r""" - TESTS:: + V_matrix = matrix(ZZ, 0, 0, 0) + V_matrix.set_immutable() + self.vertex_adjacency_matrix.set_cache(V_matrix) - sage: K. = QuadraticField(2) - sage: p = Polyhedron(vertices=[(0,1,a),(3,a,5)], - ....: rays=[(a,2,3), (0,0,1)], - ....: base_ring=K) - sage: q = Polyhedron(vertices=[(3,a,5),(0,1,a)], - ....: rays=[(0,0,1), (a,2,3)], - ....: base_ring=K) - sage: hash(p) == hash(q) - True - """ - # TODO: find something better *but* fast - return hash((self.dim(), - self.ambient_dim(), - self.n_Hrepresentation(), - self.n_Vrepresentation(), - self.n_equations(), - self.n_facets(), - self.n_inequalities(), - self.n_lines(), - self.n_rays(), - self.n_vertices())) + H_matrix = matrix(ZZ, 1, 1, 0) + H_matrix.set_immutable() + self.facet_adjacency_matrix.set_cache(H_matrix) def _sage_input_(self, sib, coerced): """ @@ -343,93 +227,6 @@ def _sage_input_(self, sib, coerced): kwds['lines'] = [sib(tuple(l)) for l in self.lines()] return sib.name('Polyhedron')(**kwds) - def _init_from_Vrepresentation(self, vertices, rays, lines, **kwds): - """ - Construct polyhedron from V-representation data. - - INPUT: - - - ``vertices`` -- list of point. Each point can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - - - ``rays`` -- list of rays. Each ray can be specified as any - iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - - - ``lines`` -- list of lines. Each line can be specified as - any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - - EXAMPLES:: - - sage: p = Polyhedron() - sage: from sage.geometry.polyhedron.base import Polyhedron_base - sage: Polyhedron_base._init_from_Vrepresentation(p, [], [], []) - Traceback (most recent call last): - ... - 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): - """ - Construct polyhedron from H-representation data. - - INPUT: - - - ``ieqs`` -- list of inequalities. Each line can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - - - ``eqns`` -- list of equalities. Each line can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - - EXAMPLES:: - - sage: p = Polyhedron() - sage: from sage.geometry.polyhedron.base import Polyhedron_base - sage: Polyhedron_base._init_from_Hrepresentation(p, [], []) - Traceback (most recent call last): - ... - NotImplementedError: a derived class must implement this method - """ - raise NotImplementedError('a derived class must implement this method') - - def _init_empty_polyhedron(self): - """ - Initializes an empty polyhedron. - - TESTS:: - - sage: empty = Polyhedron(); empty - The empty polyhedron in ZZ^0 - sage: empty.Vrepresentation() - () - sage: empty.Hrepresentation() - (An equation -1 == 0,) - sage: Polyhedron(vertices = []) - The empty polyhedron in ZZ^0 - sage: Polyhedron(vertices = [])._init_empty_polyhedron() - sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: Polyhedra(QQ,7)() - A 0-dimensional polyhedron in QQ^7 defined as the convex hull of 1 vertex - """ - self._Vrepresentation = [] - self._Hrepresentation = [] - self.parent()._make_Equation(self, [-1] + [0] * self.ambient_dim()) - self._Vrepresentation = tuple(self._Vrepresentation) - self._Hrepresentation = tuple(self._Hrepresentation) - - V_matrix = matrix(ZZ, 0, 0, 0) - V_matrix.set_immutable() - self.vertex_adjacency_matrix.set_cache(V_matrix) - - H_matrix = matrix(ZZ, 1, 1, 0) - H_matrix.set_immutable() - self.facet_adjacency_matrix.set_cache(H_matrix) - def _facet_adjacency_matrix(self): """ Compute the facet adjacency matrix in case it has not been @@ -533,126 +330,6 @@ def _test_basic_properties(self, tester=None, **options): if self.n_inequalities() < 40: tester.assertEqual(self, Polyhedron(ieqs=self.inequalities(), eqns=self.equations(), ambient_dim=self.ambient_dim())) - def base_extend(self, base_ring, backend=None): - """ - Return a new polyhedron over a larger base ring. - - This method can also be used to change the backend. - - INPUT: - - - ``base_ring`` -- the new base ring - - - ``backend`` -- the new backend, see - :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. - If ``None`` (the default), attempt to keep the same backend. - Otherwise, use the same defaulting behavior - as described there. - - OUTPUT: - - The same polyhedron, but over a larger base ring and possibly with a changed backend. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[(1,0), (0,1)], rays=[(1,1)], base_ring=ZZ); P - A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 1 ray - sage: P.base_extend(QQ) - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 1 ray - sage: P.base_extend(QQ) == P - True - - TESTS: - - Test that :trac:`22575` is fixed:: - - sage: Q = P.base_extend(ZZ, backend='field') - sage: Q.backend() - 'field' - - """ - new_parent = self.parent().base_extend(base_ring, backend) - return new_parent(self, copy=True) - - def change_ring(self, base_ring, backend=None): - """ - Return the polyhedron obtained by coercing the entries of the - vertices/lines/rays of this polyhedron into the given ring. - - This method can also be used to change the backend. - - INPUT: - - - ``base_ring`` -- the new base ring - - - ``backend`` -- the new backend or ``None`` (default), see - :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. - If ``None`` (the default), attempt to keep the same backend. - Otherwise, use the same defaulting behavior - as described there. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[(1,0), (0,1)], rays=[(1,1)], base_ring=QQ); P - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 1 ray - sage: P.change_ring(ZZ) - A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 1 ray - sage: P.change_ring(ZZ) == P - True - - sage: P = Polyhedron(vertices=[(-1.3,0), (0,2.3)], base_ring=RDF); P.vertices() - (A vertex at (-1.3, 0.0), A vertex at (0.0, 2.3)) - sage: P.change_ring(QQ).vertices() - (A vertex at (-13/10, 0), A vertex at (0, 23/10)) - sage: P == P.change_ring(QQ) - True - sage: P.change_ring(ZZ) - Traceback (most recent call last): - ... - TypeError: cannot change the base ring to the Integer Ring - - sage: P = polytopes.regular_polygon(3); P # optional - sage.rings.number_field - A 2-dimensional polyhedron in AA^2 defined as the convex hull of 3 vertices - sage: P.vertices() # optional - sage.rings.number_field - (A vertex at (0.?e-16, 1.000000000000000?), - A vertex at (0.866025403784439?, -0.500000000000000?), - A vertex at (-0.866025403784439?, -0.500000000000000?)) - sage: P.change_ring(QQ) # optional - sage.rings.number_field - Traceback (most recent call last): - ... - TypeError: cannot change the base ring to the Rational Field - - .. WARNING:: - - The base ring ``RDF`` should be used with care. As it is - not an exact ring, certain computations may break or - silently produce wrong results, for example changing the - base ring from an exact ring into ``RDF`` may cause a - loss of data:: - - sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P # optional - sage.rings.number_field - A 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: Q = P.change_ring(RDF); Q # optional - sage.rings.number_field - A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex - sage: P.n_vertices() == Q.n_vertices() # optional - sage.rings.number_field - False - """ - from sage.categories.rings import Rings - - if base_ring not in Rings(): - raise ValueError("invalid base ring") - - try: - vertices = [[base_ring(x) for x in vertex] for vertex in self.vertices_list()] - rays = [[base_ring(x) for x in ray] for ray in self.rays_list()] - lines = [[base_ring(x) for x in line] for line in self.lines_list()] - - except (TypeError, ValueError): - raise TypeError("cannot change the base ring to the {0}".format(base_ring)) - - new_parent = self.parent().change_ring(base_ring, backend) - return new_parent([vertices, rays, lines], None) - def _richcmp_(self, other, op): """ Compare ``self`` and ``other``. @@ -742,30 +419,6 @@ def _is_subpolyhedron(self, other): for other_H in other.Hrepresentation() for self_V in self.Vrepresentation()) - def is_mutable(self): - r""" - Return True if the polyhedron is mutable, i.e. it can be modified in place. - - EXAMPLES:: - - sage: p = polytopes.cube(backend='field') - sage: p.is_mutable() - False - """ - return False - - def is_immutable(self): - r""" - Return True if the polyhedron is immutable, i.e. it cannot be modified in place. - - EXAMPLES:: - - sage: p = polytopes.cube(backend='field') - sage: p.is_immutable() - True - """ - return True - @cached_method def vertex_facet_graph(self, labels=True): r""" @@ -896,55 +549,55 @@ def plot(self, By default, the wireframe is rendered in blue and the fill in green:: - sage: square.plot() + sage: square.plot() # optional - sage.plot Graphics object consisting of 6 graphics primitives - sage: point.plot() + sage: point.plot() # optional - sage.plot Graphics object consisting of 1 graphics primitive - sage: line.plot() + sage: line.plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives - sage: cube.plot() + sage: cube.plot() # optional - sage.plot Graphics3d Object - sage: hypercube.plot() + sage: hypercube.plot() # optional - sage.plot Graphics3d Object Draw the lines in red and nothing else:: - sage: square.plot(point=False, line='red', polygon=False) + sage: square.plot(point=False, line='red', polygon=False) # optional - sage.plot Graphics object consisting of 4 graphics primitives - sage: point.plot(point=False, line='red', polygon=False) + sage: point.plot(point=False, line='red', polygon=False) # optional - sage.plot Graphics object consisting of 0 graphics primitives - sage: line.plot(point=False, line='red', polygon=False) + sage: line.plot(point=False, line='red', polygon=False) # optional - sage.plot Graphics object consisting of 1 graphics primitive - sage: cube.plot(point=False, line='red', polygon=False) + sage: cube.plot(point=False, line='red', polygon=False) # optional - sage.plot Graphics3d Object - sage: hypercube.plot(point=False, line='red', polygon=False) + sage: hypercube.plot(point=False, line='red', polygon=False) # optional - sage.plot Graphics3d Object Draw points in red, no lines, and a blue polygon:: - sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) + sage: square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot Graphics object consisting of 2 graphics primitives - sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) + sage: point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot Graphics object consisting of 1 graphics primitive - sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) + sage: line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot Graphics object consisting of 1 graphics primitive - sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) + sage: cube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot Graphics3d Object - sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) + sage: hypercube.plot(point={'color':'red'}, line=False, polygon=(0,0,1)) # optional - sage.plot Graphics3d Object If we instead use the ``fill`` and ``wireframe`` options, the coloring depends on the dimension of the object:: - sage: square.plot(fill='green', wireframe='red') + sage: square.plot(fill='green', wireframe='red') # optional - sage.plot Graphics object consisting of 6 graphics primitives - sage: point.plot(fill='green', wireframe='red') + sage: point.plot(fill='green', wireframe='red') # optional - sage.plot Graphics object consisting of 1 graphics primitive - sage: line.plot(fill='green', wireframe='red') + sage: line.plot(fill='green', wireframe='red') # optional - sage.plot Graphics object consisting of 2 graphics primitives - sage: cube.plot(fill='green', wireframe='red') + sage: cube.plot(fill='green', wireframe='red') # optional - sage.plot Graphics3d Object - sage: hypercube.plot(fill='green', wireframe='red') + sage: hypercube.plot(fill='green', wireframe='red') # optional - sage.plot Graphics3d Object It is possible to draw polyhedra up to dimension 4, no matter what the @@ -953,12 +606,12 @@ def plot(self, sage: hcube = polytopes.hypercube(5) sage: facet = hcube.facets()[0].as_polyhedron();facet A 4-dimensional polyhedron in ZZ^5 defined as the convex hull of 16 vertices - sage: facet.plot() + sage: facet.plot() # optional - sage.plot Graphics3d Object TESTS:: - sage: for p in square.plot(): + sage: for p in square.plot(): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) blue Point set defined by 4 point(s) blue Line defined by 2 points @@ -967,18 +620,18 @@ def plot(self, blue Line defined by 2 points green Polygon defined by 4 points - sage: for p in line.plot(): + sage: for p in line.plot(): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) blue Point set defined by 2 point(s) green Line defined by 2 points - sage: for p in point.plot(): + sage: for p in point.plot(): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) green Point set defined by 1 point(s) Draw the lines in red and nothing else:: - sage: for p in square.plot(point=False, line='red', polygon=False): + sage: for p in square.plot(point=False, line='red', polygon=False): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Line defined by 2 points red Line defined by 2 points @@ -987,66 +640,66 @@ def plot(self, Draw vertices in red, no lines, and a blue polygon:: - sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): + sage: for p in square.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 4 point(s) (0, 0, 1) Polygon defined by 4 points - sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): + sage: for p in line.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 2 point(s) - sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): + sage: for p in point.plot(point={'color':'red'}, line=False, polygon=(0,0,1)): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 1 point(s) Draw in red without wireframe:: - sage: for p in square.plot(wireframe=False, fill="red"): + sage: for p in square.plot(wireframe=False, fill="red"): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Polygon defined by 4 points - sage: for p in line.plot(wireframe=False, fill="red"): + sage: for p in line.plot(wireframe=False, fill="red"): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Line defined by 2 points - sage: for p in point.plot(wireframe=False, fill="red"): + sage: for p in point.plot(wireframe=False, fill="red"): # optional - sage.plot ....: print("{} {}".format(p.options()['rgbcolor'], p)) red Point set defined by 1 point(s) We try to draw the polytope in 2 or 3 dimensions:: - sage: type(Polyhedron(ieqs=[(1,)]).plot()) + sage: type(Polyhedron(ieqs=[(1,)]).plot()) # optional - sage.plot - sage: type(polytopes.hypercube(1).plot()) + sage: type(polytopes.hypercube(1).plot()) # optional - sage.plot - sage: type(polytopes.hypercube(2).plot()) + sage: type(polytopes.hypercube(2).plot()) # optional - sage.plot - sage: type(polytopes.hypercube(3).plot()) + sage: type(polytopes.hypercube(3).plot()) # optional - sage.plot In 4d a projection to 3d is used:: - sage: type(polytopes.hypercube(4).plot()) + sage: type(polytopes.hypercube(4).plot()) # optional - sage.plot - sage: type(polytopes.hypercube(5).plot()) + sage: type(polytopes.hypercube(5).plot()) # optional - sage.plot Traceback (most recent call last): ... NotImplementedError: plotting of 5-dimensional polyhedra not implemented If the polyhedron is not full-dimensional, the :meth:`affine_hull_projection` is used if necessary:: - sage: type(Polyhedron([(0,), (1,)]).plot()) + sage: type(Polyhedron([(0,), (1,)]).plot()) # optional - sage.plot - sage: type(Polyhedron([(0,0), (1,1)]).plot()) + sage: type(Polyhedron([(0,0), (1,1)]).plot()) # optional - sage.plot - sage: type(Polyhedron([(0,0,0), (1,1,1)]).plot()) + sage: type(Polyhedron([(0,0,0), (1,1,1)]).plot()) # optional - sage.plot - sage: type(Polyhedron([(0,0,0,0), (1,1,1,1)]).plot()) + sage: type(Polyhedron([(0,0,0,0), (1,1,1,1)]).plot()) # optional - sage.plot - sage: type(Polyhedron([(0,0,0,0,0), (1,1,1,1,1)]).plot()) + sage: type(Polyhedron([(0,0,0,0,0), (1,1,1,1,1)]).plot()) # optional - sage.plot - sage: type(Polyhedron([(0,0,0,0), (1,1,1,1), (1,0,0,0)]).plot()) + sage: type(Polyhedron([(0,0,0,0), (1,1,1,1), (1,0,0,0)]).plot()) # optional - sage.plot TESTS: @@ -1227,59 +880,6 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, edge_color, facet_color, opacity, vertex_color, axis) - def _repr_(self): - """ - Return a description of the polyhedron. - - EXAMPLES:: - - sage: poly_test = Polyhedron(vertices = [[1,2,3,4],[2,1,3,4],[4,3,2,1]]) - sage: poly_test._repr_() - 'A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 3 vertices' - sage: grammar_test = Polyhedron(vertices = [[1,1,1,1,1,1]]) - sage: grammar_test._repr_() - 'A 0-dimensional polyhedron in ZZ^6 defined as the convex hull of 1 vertex' - """ - desc = '' - if self.n_vertices() == 0: - desc += 'The empty polyhedron' - else: - desc += 'A ' + repr(self.dim()) + '-dimensional polyhedron' - desc += ' in ' - desc += self.parent()._repr_ambient_module() - - if self.n_vertices() > 0: - desc += ' defined as the convex hull of ' - desc += repr(self.n_vertices()) - if self.n_vertices() == 1: - desc += ' vertex' - else: - desc += ' vertices' - - if self.n_rays() > 0: - if self.n_lines() > 0: - desc += ", " - else: - desc += " and " - desc += repr(self.n_rays()) - if self.n_rays() == 1: - desc += ' ray' - else: - desc += ' rays' - - if self.n_lines() > 0: - if self.n_rays() > 0: - desc += ", " - else: - desc += " and " - desc += repr(self.n_lines()) - if self.n_lines() == 1: - desc += ' line' - else: - desc += ' lines' - - return desc - def _rich_repr_(self, display_manager, **kwds): r""" Rich Output Magic Method @@ -1457,105 +1057,6 @@ def write_cdd_Vrepresentation(self, filename): with open(filename, 'w') as f: f.write(self.cdd_Vrepresentation()) - @cached_method - def n_equations(self): - """ - Return the number of equations. The representation will - always be minimal, so the number of equations is the - codimension of the polyhedron in the ambient space. - - EXAMPLES:: - - sage: p = Polyhedron(vertices = [[1,0,0],[0,1,0],[0,0,1]]) - sage: p.n_equations() - 1 - """ - return len(self.equations()) - - @cached_method - def n_inequalities(self): - """ - Return the number of inequalities. The representation will - always be minimal, so the number of inequalities is the - number of facets of the polyhedron in the ambient space. - - EXAMPLES:: - - sage: p = Polyhedron(vertices = [[1,0,0],[0,1,0],[0,0,1]]) - sage: p.n_inequalities() - 3 - - sage: p = Polyhedron(vertices = [[t,t^2,t^3] for t in range(6)]) - sage: p.n_facets() - 8 - """ - return len(self.inequalities()) - - n_facets = n_inequalities - - @cached_method - def n_vertices(self): - """ - Return the number of vertices. The representation will - always be minimal. - - .. WARNING:: - - If the polyhedron has lines, return the number of vertices in - the ``Vrepresentation``. As the represented polyhedron has - no 0-dimensional faces (i.e. vertices), ``n_vertices`` corresponds - to the number of `k`-faces, where `k` is the number of lines:: - - sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) - sage: P.n_vertices() - 1 - sage: P.faces(0) - () - sage: P.f_vector() - (1, 0, 1, 1) - - sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0],[0,1,1]]) - sage: P.n_vertices() - 1 - sage: P.f_vector() - (1, 0, 0, 1, 1) - - EXAMPLES:: - - sage: p = Polyhedron(vertices = [[1,0],[0,1],[1,1]], rays=[[1,1]]) - sage: p.n_vertices() - 2 - """ - return len(self.vertices()) - - @cached_method - def n_rays(self): - """ - Return the number of rays. The representation will - always be minimal. - - EXAMPLES:: - - sage: p = Polyhedron(vertices = [[1,0],[0,1]], rays=[[1,1]]) - sage: p.n_rays() - 1 - """ - return len(self.rays()) - - @cached_method - def n_lines(self): - """ - Return the number of lines. The representation will - always be minimal. - - EXAMPLES:: - - sage: p = Polyhedron(vertices = [[0,0]], rays=[[0,1],[0,-1]]) - sage: p.n_lines() - 1 - """ - return len(self.lines()) - def to_linear_program(self, solver=None, return_variable=False, base_ring=None): r""" Return a linear optimization problem over the polyhedron in the form of @@ -1675,561 +1176,54 @@ def to_linear_program(self, solver=None, return_variable=False, base_ring=None): else: return p - def Hrepresentation(self, index=None): + @cached_method + def vertices_matrix(self, base_ring=None): """ - Return the objects of the H-representation. Each entry is - either an inequality or a equation. + Return the coordinates of the vertices as the columns of a matrix. INPUT: - - ``index`` -- either an integer or ``None`` + - ``base_ring`` -- A ring or ``None`` (default). The base ring + of the returned matrix. If not specified, the base ring of + the polyhedron is used. OUTPUT: - The optional argument is an index running from ``0`` to - ``self.n_Hrepresentation()-1``. If present, the - H-representation object at the given index will be - returned. Without an argument, returns the list of all - H-representation objects. - - EXAMPLES:: - - sage: p = polytopes.hypercube(3, backend='field') - sage: p.Hrepresentation(0) - An inequality (-1, 0, 0) x + 1 >= 0 - sage: p.Hrepresentation(0) == p.Hrepresentation()[0] - True - """ - if index is None: - return self._Hrepresentation - else: - return self._Hrepresentation[index] - - def Hrepresentation_str(self, separator='\n', latex=False, style='>=', align=None, **kwds): - r""" - Return a human-readable string representation of the Hrepresentation of this - polyhedron. - - INPUT: - - - ``separator`` -- a string. Default is ``"\n"``. - - - ``latex`` -- a boolean. Default is ``False``. - - - ``style`` -- either ``"positive"`` (making all coefficients positive) - or ``"<="``, or ``">="``. Default is ``">="``. + A matrix over ``base_ring`` whose columns are the coordinates + of the vertices. A ``TypeError`` is raised if the coordinates + cannot be converted to ``base_ring``. - - ``align`` -- a boolean or ``None''. Default is ``None`` in which case - ``align`` is ``True`` if ``separator`` is the newline character. - If set, then the lines of the output string are aligned - by the comparison symbol by padding blanks. + .. WARNING:: - Keyword parameters of - :meth:`~sage.geometry.polyhedron.representation.Hrepresentation.repr_pretty` - are passed on: + If the polyhedron has lines, return the coordinates of the vertices + of the ``Vrepresentation``. However, the represented polyhedron + has no 0-dimensional faces (i.e. vertices):: - - ``prefix`` -- a string + sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) + sage: P.vertices_matrix() + [0] + [0] + [0] + sage: P.faces(0) + () - - ``indices`` -- a tuple or other iterable + EXAMPLES:: - OUTPUT: + sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) + sage: triangle.vertices_matrix() + [0 1 1] + [1 0 1] + sage: (triangle/2).vertices_matrix() + [ 0 1/2 1/2] + [1/2 0 1/2] + sage: (triangle/2).vertices_matrix(ZZ) + Traceback (most recent call last): + ... + TypeError: no conversion of this rational to integer - A string. + TESTS: - EXAMPLES:: - - sage: P = polytopes.permutahedron(3) - sage: print(P.Hrepresentation_str()) - x0 + x1 + x2 == 6 - x0 + x1 >= 3 - -x0 - x1 >= -5 - x1 >= 1 - -x0 >= -3 - x0 >= 1 - -x1 >= -3 - - sage: print(P.Hrepresentation_str(style='<=')) - -x0 - x1 - x2 == -6 - -x0 - x1 <= -3 - x0 + x1 <= 5 - -x1 <= -1 - x0 <= 3 - -x0 <= -1 - x1 <= 3 - - sage: print(P.Hrepresentation_str(style='positive')) - x0 + x1 + x2 == 6 - x0 + x1 >= 3 - 5 >= x0 + x1 - x1 >= 1 - 3 >= x0 - x0 >= 1 - 3 >= x1 - - sage: print(P.Hrepresentation_str(latex=True)) - \begin{array}{rcl} - x_{0} + x_{1} + x_{2} & = & 6 \\ - x_{0} + x_{1} & \geq & 3 \\ - -x_{0} - x_{1} & \geq & -5 \\ - x_{1} & \geq & 1 \\ - -x_{0} & \geq & -3 \\ - x_{0} & \geq & 1 \\ - -x_{1} & \geq & -3 - \end{array} - - sage: print(P.Hrepresentation_str(align=False)) - x0 + x1 + x2 == 6 - x0 + x1 >= 3 - -x0 - x1 >= -5 - x1 >= 1 - -x0 >= -3 - x0 >= 1 - -x1 >= -3 - - sage: c = polytopes.cube() - sage: c.Hrepresentation_str(separator=', ', style='positive') - '1 >= x0, 1 >= x1, 1 >= x2, 1 + x0 >= 0, 1 + x2 >= 0, 1 + x1 >= 0' - """ - pretty_hs = [h.repr_pretty(split=True, latex=latex, style=style, **kwds) for h in self.Hrepresentation()] - shift = any(pretty_h[2].startswith('-') for pretty_h in pretty_hs) - - if align is None: - align = separator == "\n" - if align: - lengths = [(len(s[0]), len(s[1]), len(s[2])) for s in pretty_hs] - from operator import itemgetter - length_left = max(lengths, key=itemgetter(0))[0] - length_middle = max(lengths, key=itemgetter(1))[1] - length_right = max(lengths, key=itemgetter(2))[2] - if shift: - length_right += 1 - if latex: - h_line = "{:>" + "{}".format(length_left) + "} & {:" + \ - "{}".format(length_middle) + "} & {:" + \ - "{}".format(length_right) + "}\\\\" - else: - h_line = "{:>" + "{}".format(length_left) \ - + "} {:" + "{}".format(length_middle) \ - + "} {:" + "{}".format(length_right) + "}" - elif latex: - h_line = "{} & {} & {}\\\\" - else: - h_line = "{} {} {}" - - def pad_non_minus(s): - if align and shift and not s.startswith('-'): - return ' ' + s - else: - return s - h_list = [h_line.format(pretty_h[0], pretty_h[1], pad_non_minus(pretty_h[2])) - for pretty_h in pretty_hs] - pretty_print = separator.join(h_list) - - if not latex: - return pretty_print - else: - # below we remove the 2 unnecessary backslashes at the end of pretty_print - return "\\begin{array}{rcl}\n" + pretty_print[:-2] + "\n\\end{array}" - - def Hrep_generator(self): - """ - Return an iterator over the objects of the H-representation - (inequalities or equations). - - EXAMPLES:: - - sage: p = polytopes.hypercube(3) - sage: next(p.Hrep_generator()) - An inequality (-1, 0, 0) x + 1 >= 0 - """ - for H in self.Hrepresentation(): - yield H - - @cached_method - def n_Hrepresentation(self): - """ - Return the number of objects that make up the - H-representation of the polyhedron. - - OUTPUT: - - Integer. - - EXAMPLES:: - - sage: p = polytopes.cross_polytope(4) - sage: p.n_Hrepresentation() - 16 - sage: p.n_Hrepresentation() == p.n_inequalities() + p.n_equations() - True - """ - return len(self.Hrepresentation()) - - def Vrepresentation(self, index=None): - """ - Return the objects of the V-representation. Each entry is - either a vertex, a ray, or a line. - - See :mod:`sage.geometry.polyhedron.constructor` for a - definition of vertex/ray/line. - - INPUT: - - - ``index`` -- either an integer or ``None`` - - OUTPUT: - - The optional argument is an index running from ``0`` to - ``self.n_Vrepresentation()-1``. If present, the - V-representation object at the given index will be - returned. Without an argument, returns the list of all - V-representation objects. - - EXAMPLES:: - - sage: p = polytopes.simplex(4, project=True) - sage: p.Vrepresentation(0) - A vertex at (0.7071067812, 0.4082482905, 0.2886751346, 0.2236067977) - sage: p.Vrepresentation(0) == p.Vrepresentation() [0] - True - """ - if index is None: - return self._Vrepresentation - else: - return self._Vrepresentation[index] - - @cached_method - def n_Vrepresentation(self): - """ - Return the number of objects that make up the - V-representation of the polyhedron. - - OUTPUT: - - Integer. - - EXAMPLES:: - - sage: p = polytopes.simplex(4) - sage: p.n_Vrepresentation() - 5 - sage: p.n_Vrepresentation() == p.n_vertices() + p.n_rays() + p.n_lines() - True - """ - return len(self.Vrepresentation()) - - def Vrep_generator(self): - """ - Return an iterator over the objects of the V-representation - (vertices, rays, and lines). - - EXAMPLES:: - - sage: p = polytopes.cyclic_polytope(3,4) - sage: vg = p.Vrep_generator() - sage: next(vg) - A vertex at (0, 0, 0) - sage: next(vg) - A vertex at (1, 1, 1) - """ - for V in self.Vrepresentation(): - yield V - - def inequality_generator(self): - """ - Return a generator for the defining inequalities of the - polyhedron. - - OUTPUT: - - A generator of the inequality Hrepresentation objects. - - EXAMPLES:: - - sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) - sage: for v in triangle.inequality_generator(): print(v) - An inequality (1, 1) x - 1 >= 0 - An inequality (0, -1) x + 1 >= 0 - An inequality (-1, 0) x + 1 >= 0 - sage: [ v for v in triangle.inequality_generator() ] - [An inequality (1, 1) x - 1 >= 0, - An inequality (0, -1) x + 1 >= 0, - An inequality (-1, 0) x + 1 >= 0] - sage: [ [v.A(), v.b()] for v in triangle.inequality_generator() ] - [[(1, 1), -1], [(0, -1), 1], [(-1, 0), 1]] - """ - for H in self.Hrepresentation(): - if H.is_inequality(): - yield H - - @cached_method - def inequalities(self): - """ - Return all inequalities. - - OUTPUT: - - A tuple of inequalities. - - EXAMPLES:: - - sage: p = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[1,0,0],[2,2,2]]) - sage: p.inequalities()[0:3] - (An inequality (1, 0, 0) x + 0 >= 0, - An inequality (0, 1, 0) x + 0 >= 0, - An inequality (0, 0, 1) x + 0 >= 0) - sage: p3 = Polyhedron(vertices = Permutations([1,2,3,4])) - sage: ieqs = p3.inequalities() - sage: ieqs[0] - An inequality (0, 1, 1, 1) x - 6 >= 0 - sage: list(_) - [-6, 0, 1, 1, 1] - """ - return tuple(self.inequality_generator()) - - def inequalities_list(self): - """ - Return a list of inequalities as coefficient lists. - - .. NOTE:: - - It is recommended to use :meth:`inequalities` or - :meth:`inequality_generator` instead to iterate over the - list of :class:`Inequality` objects. - - EXAMPLES:: - - sage: p = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[1,0,0],[2,2,2]]) - sage: p.inequalities_list()[0:3] - [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] - sage: p3 = Polyhedron(vertices = Permutations([1,2,3,4])) - sage: ieqs = p3.inequalities_list() - sage: ieqs[0] - [-6, 0, 1, 1, 1] - sage: ieqs[-1] - [-3, 0, 1, 0, 1] - sage: ieqs == [list(x) for x in p3.inequality_generator()] - True - """ - return [list(x) for x in self.inequality_generator()] - - def equation_generator(self): - """ - Return a generator for the linear equations satisfied by the - polyhedron. - - EXAMPLES:: - - sage: p = polytopes.regular_polygon(8,base_ring=RDF) - sage: p3 = Polyhedron(vertices = [x+[0] for x in p.vertices()], base_ring=RDF) - sage: next(p3.equation_generator()) - An equation (0.0, 0.0, 1.0) x + 0.0 == 0 - """ - for H in self.Hrepresentation(): - if H.is_equation(): - yield H - - @cached_method - def equations(self): - """ - Return all linear constraints of the polyhedron. - - OUTPUT: - - A tuple of equations. - - EXAMPLES:: - - sage: test_p = Polyhedron(vertices = [[1,2,3,4],[2,1,3,4],[4,3,2,1],[3,4,1,2]]) - sage: test_p.equations() - (An equation (1, 1, 1, 1) x - 10 == 0,) - """ - return tuple(self.equation_generator()) - - def equations_list(self): - """ - Return the linear constraints of the polyhedron. As with - inequalities, each constraint is given as [b -a1 -a2 ... an] - where for variables x1, x2,..., xn, the polyhedron satisfies - the equation b = a1*x1 + a2*x2 + ... + an*xn. - - .. NOTE:: - - It is recommended to use :meth:`equations` or - :meth:`equation_generator()` instead to iterate over the - list of - :class:`~sage.geometry.polyhedron.representation.Equation` - objects. - - EXAMPLES:: - - sage: test_p = Polyhedron(vertices = [[1,2,3,4],[2,1,3,4],[4,3,2,1],[3,4,1,2]]) - sage: test_p.equations_list() - [[-10, 1, 1, 1, 1]] - """ - return [list(eq) for eq in self.equation_generator()] - - def vertices_list(self): - """ - Return a list of vertices of the polyhedron. - - .. NOTE:: - - It is recommended to use :meth:`vertex_generator` instead to - iterate over the list of :class:`Vertex` objects. - - .. WARNING:: - - If the polyhedron has lines, return the vertices - of the ``Vrepresentation``. However, the represented polyhedron - has no 0-dimensional faces (i.e. vertices):: - - sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) - sage: P.vertices_list() - [[0, 0, 0]] - sage: P.faces(0) - () - - EXAMPLES:: - - sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) - sage: triangle.vertices_list() - [[0, 1], [1, 0], [1, 1]] - sage: a_simplex = Polyhedron(ieqs = [ - ....: [0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[0,0,0,0,1] - ....: ], eqns = [[1,-1,-1,-1,-1]]) - sage: a_simplex.vertices_list() - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] - sage: a_simplex.vertices_list() == [list(v) for v in a_simplex.vertex_generator()] - True - """ - return [list(x) for x in self.vertex_generator()] - - def vertex_generator(self): - """ - Return a generator for the vertices of the polyhedron. - - .. WARNING:: - - If the polyhedron has lines, return a generator for the vertices - of the ``Vrepresentation``. However, the represented polyhedron - has no 0-dimensional faces (i.e. vertices):: - - sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) - sage: list(P.vertex_generator()) - [A vertex at (0, 0, 0)] - sage: P.faces(0) - () - - EXAMPLES:: - - sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) - sage: for v in triangle.vertex_generator(): print(v) - A vertex at (0, 1) - A vertex at (1, 0) - A vertex at (1, 1) - sage: v_gen = triangle.vertex_generator() - sage: next(v_gen) # the first vertex - A vertex at (0, 1) - sage: next(v_gen) # the second vertex - A vertex at (1, 0) - sage: next(v_gen) # the third vertex - A vertex at (1, 1) - sage: try: next(v_gen) # there are only three vertices - ....: except StopIteration: print("STOP") - STOP - sage: type(v_gen) - <... 'generator'> - sage: [ v for v in triangle.vertex_generator() ] - [A vertex at (0, 1), A vertex at (1, 0), A vertex at (1, 1)] - """ - for V in self.Vrepresentation(): - if V.is_vertex(): - yield V - - @cached_method - def vertices(self): - """ - Return all vertices of the polyhedron. - - OUTPUT: - - A tuple of vertices. - - .. WARNING:: - - If the polyhedron has lines, return the vertices - of the ``Vrepresentation``. However, the represented polyhedron - has no 0-dimensional faces (i.e. vertices):: - - sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) - sage: P.vertices() - (A vertex at (0, 0, 0),) - sage: P.faces(0) - () - - EXAMPLES:: - - sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) - sage: triangle.vertices() - (A vertex at (0, 1), A vertex at (1, 0), A vertex at (1, 1)) - sage: a_simplex = Polyhedron(ieqs = [ - ....: [0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[0,0,0,0,1] - ....: ], eqns = [[1,-1,-1,-1,-1]]) - sage: a_simplex.vertices() - (A vertex at (1, 0, 0, 0), A vertex at (0, 1, 0, 0), - A vertex at (0, 0, 1, 0), A vertex at (0, 0, 0, 1)) - """ - return tuple(self.vertex_generator()) - - @cached_method - def vertices_matrix(self, base_ring=None): - """ - Return the coordinates of the vertices as the columns of a matrix. - - INPUT: - - - ``base_ring`` -- A ring or ``None`` (default). The base ring - of the returned matrix. If not specified, the base ring of - the polyhedron is used. - - OUTPUT: - - A matrix over ``base_ring`` whose columns are the coordinates - of the vertices. A ``TypeError`` is raised if the coordinates - cannot be converted to ``base_ring``. - - .. WARNING:: - - If the polyhedron has lines, return the coordinates of the vertices - of the ``Vrepresentation``. However, the represented polyhedron - has no 0-dimensional faces (i.e. vertices):: - - sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) - sage: P.vertices_matrix() - [0] - [0] - [0] - sage: P.faces(0) - () - - EXAMPLES:: - - sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) - sage: triangle.vertices_matrix() - [0 1 1] - [1 0 1] - sage: (triangle/2).vertices_matrix() - [ 0 1/2 1/2] - [1/2 0 1/2] - sage: (triangle/2).vertices_matrix(ZZ) - Traceback (most recent call last): - ... - TypeError: no conversion of this rational to integer - - TESTS: - - Check that :trac:`28828` is fixed:: + Check that :trac:`28828` is fixed:: sage: P.vertices_matrix().is_immutable() True @@ -2243,200 +1237,6 @@ def vertices_matrix(self, base_ring=None): m.set_immutable() return m - def an_affine_basis(self): - """ - Return points in ``self`` that are a basis for the affine span of the polytope. - - This implementation of the method :meth:`ConvexSet_base.an_affine_basis` - for polytopes guarantees the following: - - - All points are vertices. - - - The basis is obtained by considering a maximal chain of faces - in the face lattice and picking for each cover relation - one vertex that is in the difference. Thus this method - is independent of the concrete realization of the polytope. - - EXAMPLES:: - - sage: P = polytopes.cube() - sage: P.an_affine_basis() - [A vertex at (-1, -1, -1), - A vertex at (1, -1, -1), - A vertex at (1, -1, 1), - A vertex at (1, 1, -1)] - - sage: P = polytopes.permutahedron(5) - sage: P.an_affine_basis() - [A vertex at (1, 2, 3, 5, 4), - A vertex at (2, 1, 3, 5, 4), - A vertex at (1, 3, 2, 5, 4), - A vertex at (4, 1, 3, 5, 2), - A vertex at (4, 2, 5, 3, 1)] - - The method is not implemented for unbounded polyhedra:: - - sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)]) - sage: p.an_affine_basis() - Traceback (most recent call last): - ... - NotImplementedError: this function is not implemented for unbounded polyhedra - """ - if not self.is_compact(): - raise NotImplementedError("this function is not implemented for unbounded polyhedra") - - chain = self.a_maximal_chain()[1:] # we exclude the empty face - chain_indices = [face.ambient_V_indices() for face in chain] - basis_indices = [] - - # We use in the following that elements in ``chain_indices`` are sorted lists - # of V-indices. - # Thus for each two faces we can easily find the first vertex that differs. - for dim, face in enumerate(chain_indices): - if dim == 0: - # Append the vertex. - basis_indices.append(face[0]) - continue - - prev_face = chain_indices[dim-1] - for i in range(len(prev_face)): - if prev_face[i] != face[i]: - # We found a vertex that ``face`` has, but its facet does not. - basis_indices.append(face[i]) - break - else: # no break - # ``prev_face`` contains all the same vertices as ``face`` until now. - # But ``face`` is guaranteed to contain one more vertex (at least). - basis_indices.append(face[len(prev_face)]) - - return [self.Vrepresentation()[i] for i in basis_indices] - - def _test_an_affine_basis(self, tester=None, **options): - """ - Run tests on the method :meth:`.an_affine_basis` - - TESTS:: - - sage: polytopes.cross_polytope(3)._test_an_affine_basis() - """ - if tester is None: - tester = self._tester(**options) - if self.is_compact(): - b = self.an_affine_basis() - m = matrix([1] + list(v) for v in b) - tester.assertEqual(m.rank(), self.dim() + 1) - for v in b: - tester.assertIn(v, self.vertices()) - - def ray_generator(self): - """ - Return a generator for the rays of the polyhedron. - - EXAMPLES:: - - sage: pi = Polyhedron(ieqs = [[1,1,0],[1,0,1]]) - sage: pir = pi.ray_generator() - sage: [x.vector() for x in pir] - [(1, 0), (0, 1)] - """ - for V in self.Vrepresentation(): - if V.is_ray(): - yield V - - @cached_method - def rays(self): - """ - Return a list of rays of the polyhedron. - - OUTPUT: - - A tuple of rays. - - EXAMPLES:: - - sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0],[1,1,0,0]]) - sage: p.rays() - (A ray in the direction (1, 0, 0), - A ray in the direction (0, 1, 0), - A ray in the direction (0, 0, 1)) - """ - return tuple(self.ray_generator()) - - def rays_list(self): - """ - Return a list of rays as coefficient lists. - - .. NOTE:: - - It is recommended to use :meth:`rays` or - :meth:`ray_generator` instead to iterate over the list of - :class:`Ray` objects. - - OUTPUT: - - A list of rays as lists of coordinates. - - EXAMPLES:: - - sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0],[1,1,0,0]]) - sage: p.rays_list() - [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - sage: p.rays_list() == [list(r) for r in p.ray_generator()] - True - """ - return [list(x) for x in self.ray_generator()] - - def line_generator(self): - """ - Return a generator for the lines of the polyhedron. - - EXAMPLES:: - - sage: pr = Polyhedron(rays = [[1,0],[-1,0],[0,1]], vertices = [[-1,-1]]) - sage: next(pr.line_generator()).vector() - (1, 0) - """ - for V in self.Vrepresentation(): - if V.is_line(): - yield V - - @cached_method - def lines(self): - """ - Return all lines of the polyhedron. - - OUTPUT: - - A tuple of lines. - - EXAMPLES:: - - sage: p = Polyhedron(rays = [[1,0],[-1,0],[0,1],[1,1]], vertices = [[-2,-2],[2,3]]) - sage: p.lines() - (A line in the direction (1, 0),) - """ - return tuple(self.line_generator()) - - def lines_list(self): - """ - Return a list of lines of the polyhedron. The line data is given - as a list of coordinates rather than as a Hrepresentation object. - - .. NOTE:: - - It is recommended to use :meth:`line_generator` instead to - iterate over the list of :class:`Line` objects. - - EXAMPLES:: - - sage: p = Polyhedron(rays = [[1,0],[-1,0],[0,1],[1,1]], vertices = [[-2,-2],[2,3]]) - sage: p.lines_list() - [[1, 0]] - sage: p.lines_list() == [list(x) for x in p.line_generator()] - True - """ - return [list(x) for x in self.line_generator()] - def bounded_edges(self): """ Return the bounded edges (excluding rays and lines). @@ -2449,185 +1249,20 @@ def bounded_edges(self): sage: p = Polyhedron(vertices=[[1,0],[0,1]], rays=[[1,0],[0,1]]) sage: [ e for e in p.bounded_edges() ] - [(A vertex at (0, 1), A vertex at (1, 0))] - sage: for e in p.bounded_edges(): print(e) - (A vertex at (0, 1), A vertex at (1, 0)) - """ - obj = self.Vrepresentation() - for i in range(len(obj)): - if not obj[i].is_vertex(): - continue - for j in range(i+1, len(obj)): - if not obj[j].is_vertex(): - continue - if self.vertex_adjacency_matrix()[i, j] == 0: - continue - yield (obj[i], obj[j]) - - def Vrepresentation_space(self): - r""" - Return the ambient free module. - - OUTPUT: - - A free module over the base ring of dimension :meth:`ambient_dim`. - - EXAMPLES:: - - sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) - sage: poly_test.Vrepresentation_space() - Ambient free module of rank 4 over the principal ideal domain Integer Ring - sage: poly_test.ambient_space() is poly_test.Vrepresentation_space() - True - """ - return self.parent().Vrepresentation_space() - - ambient_space = Vrepresentation_space - - def ambient_vector_space(self, base_field=None): - r""" - Return the ambient vector space. - - It is the ambient free module (:meth:`Vrepresentation_space`) tensored - with a field. - - INPUT: - - - ``base_field`` -- (default: the fraction field of the base ring) a field. - - EXAMPLES:: - - sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) - sage: poly_test.ambient_vector_space() - Vector space of dimension 4 over Rational Field - sage: poly_test.ambient_vector_space() is poly_test.ambient() - True - - sage: poly_test.ambient_vector_space(AA) - Vector space of dimension 4 over Algebraic Real Field - sage: poly_test.ambient_vector_space(RR) - Vector space of dimension 4 over Real Field with 53 bits of precision - sage: poly_test.ambient_vector_space(SR) - Vector space of dimension 4 over Symbolic Ring - """ - return self.Vrepresentation_space().vector_space(base_field=base_field) - - ambient = ambient_vector_space - - def Hrepresentation_space(self): - r""" - Return the linear space containing the H-representation vectors. - - OUTPUT: - - A free module over the base ring of dimension :meth:`ambient_dim` + 1. - - EXAMPLES:: - - sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) - sage: poly_test.Hrepresentation_space() - Ambient free module of rank 5 over the principal ideal domain Integer Ring - """ - return self.parent().Hrepresentation_space() - - def ambient_dim(self): - r""" - Return the dimension of the ambient space. - - EXAMPLES:: - - sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) - sage: poly_test.ambient_dim() - 4 - """ - return self.parent().ambient_dim() - - def dim(self): - """ - Return the dimension of the polyhedron. - - OUTPUT: - - -1 if the polyhedron is empty, otherwise a non-negative integer. - - EXAMPLES:: - - sage: simplex = Polyhedron(vertices = [[1,0,0,0],[0,0,0,1],[0,1,0,0],[0,0,1,0]]) - sage: simplex.dim() - 3 - sage: simplex.ambient_dim() - 4 - - The empty set is a special case (:trac:`12193`):: - - sage: P1=Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]) - sage: P2=Polyhedron(vertices=[[2,0,0],[0,2,0],[0,0,2]]) - sage: P12 = P1.intersection(P2) - sage: P12 - The empty polyhedron in ZZ^3 - sage: P12.dim() - -1 - """ - if self.n_Vrepresentation() == 0: - return -1 # the empty set - else: - return self.ambient_dim() - self.n_equations() - - dimension = dim - - def is_empty(self): - """ - Test whether the polyhedron is the empty polyhedron - - OUTPUT: - - Boolean. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]); P - A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: P.is_empty(), P.is_universe() - (False, False) - - sage: Q = Polyhedron(vertices=()); Q - The empty polyhedron in ZZ^0 - sage: Q.is_empty(), Q.is_universe() - (True, False) - - sage: R = Polyhedron(lines=[(1,0),(0,1)]); R - A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 lines - sage: R.is_empty(), R.is_universe() - (False, True) - """ - return self.n_Vrepresentation() == 0 - - def is_universe(self): - """ - Test whether the polyhedron is the whole ambient space - - OUTPUT: - - Boolean. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]); P - A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: P.is_empty(), P.is_universe() - (False, False) - - sage: Q = Polyhedron(vertices=()); Q - The empty polyhedron in ZZ^0 - sage: Q.is_empty(), Q.is_universe() - (True, False) - - sage: R = Polyhedron(lines=[(1,0),(0,1)]); R - A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 lines - sage: R.is_empty(), R.is_universe() - (False, True) + [(A vertex at (0, 1), A vertex at (1, 0))] + sage: for e in p.bounded_edges(): print(e) + (A vertex at (0, 1), A vertex at (1, 0)) """ - return self.n_Hrepresentation() == 0 + obj = self.Vrepresentation() + for i in range(len(obj)): + if not obj[i].is_vertex(): + continue + for j in range(i+1, len(obj)): + if not obj[j].is_vertex(): + continue + if self.vertex_adjacency_matrix()[i, j] == 0: + continue + yield (obj[i], obj[j]) @cached_method def vertex_adjacency_matrix(self): @@ -3087,65 +1722,6 @@ def slack_matrix(self): slack_matrix.set_immutable() return slack_matrix - def base_ring(self): - """ - Return the base ring. - - OUTPUT: - - The ring over which the polyhedron is defined. Must be a - sub-ring of the reals to define a polyhedron, in particular - comparison must be defined. Popular choices are - - * ``ZZ`` (the ring of integers, lattice polytope), - - * ``QQ`` (exact arithmetic using gmp), - - * ``RDF`` (double precision floating-point arithmetic), or - - * ``AA`` (real algebraic field). - - EXAMPLES:: - - sage: triangle = Polyhedron(vertices = [[1,0],[0,1],[1,1]]) - sage: triangle.base_ring() == ZZ - True - """ - return self.parent().base_ring() - - def backend(self): - """ - Return the backend used. - - OUTPUT: - - The name of the backend used for computations. It will be one of - the following backends: - - * ``ppl`` the Parma Polyhedra Library - - * ``cdd`` CDD - - * ``normaliz`` normaliz - - * ``polymake`` polymake - - * ``field`` a generic Sage implementation - - EXAMPLES:: - - sage: triangle = Polyhedron(vertices = [[1, 0], [0, 1], [1, 1]]) - sage: triangle.backend() - 'ppl' - sage: D = polytopes.dodecahedron() - sage: D.backend() - 'field' - sage: P = Polyhedron([[1.23]]) - sage: P.backend() - 'cdd' - """ - return self.parent().backend() - @cached_method def center(self): """ @@ -3269,74 +1845,6 @@ def centroid(self, engine='auto', **kwds): pass return centroid - @cached_method - def representative_point(self): - """ - Return a "generic" point. - - .. SEEALSO:: - - :meth:`center`. - - OUTPUT: - - A point as a coordinate vector. The point is chosen to be - interior if possible. If the polyhedron is not - full-dimensional, the point is in the relative interior. If - the polyhedron is zero-dimensional, its single point is - returned. - - EXAMPLES:: - - sage: p = Polyhedron(vertices=[(3,2)], rays=[(1,-1)]) - sage: p.representative_point() - (4, 1) - sage: p.center() - (3, 2) - - sage: Polyhedron(vertices=[(3,2)]).representative_point() - (3, 2) - """ - accumulator = vector(self.base_ring(), [0]*self.ambient_dim()) - for v in self.vertex_generator(): - accumulator += v.vector() - accumulator /= self.n_vertices() - for r in self.ray_generator(): - accumulator += r.vector() - accumulator.set_immutable() - return accumulator - - def _some_elements_(self): - r""" - Generate some points of ``self``. - - If ``self`` is empty, no points are generated; no exception will be raised. - - EXAMPLES:: - - sage: P = polytopes.simplex() - sage: P.an_element() # indirect doctest - (1/4, 1/4, 1/4, 1/4) - sage: P.some_elements() # indirect doctest - [(1/4, 1/4, 1/4, 1/4), - (0, 0, 0, 1), - (0, 0, 1/2, 1/2), - (0, 1/2, 1/4, 1/4), - (1/2, 1/4, 1/8, 1/8)] - """ - if self.is_empty(): - return - yield self.representative_point() - vertex_iter = iter(self.vertex_generator()) - try: - p = next(vertex_iter).vector() - yield vector(p, immutable=True) - for i in range(4): - p = (p + next(vertex_iter).vector()) / 2 - yield vector(p, immutable=True) - except StopIteration: - pass - def a_maximal_chain(self): r""" Return a maximal chain of the face lattice in increasing order. @@ -4980,7 +3488,7 @@ def join(self, other): sage: C = polytopes.hypercube(5) sage: S = Polyhedron([[1]]) - sage: C.join(S).is_combinatorially_isomorphic(C.pyramid()) + sage: C.join(S).is_combinatorially_isomorphic(C.pyramid()) # optional - sage.graphs True sage: P = polytopes.simplex(backend='cdd') @@ -6065,11 +4573,11 @@ def wedge(self, face, width=1): EXAMPLES:: - sage: P_4 = polytopes.regular_polygon(4) - sage: W1 = P_4.wedge(P_4.faces(1)[0]); W1 + sage: P_4 = polytopes.regular_polygon(4) # optional - sage.rings.number_field + sage: W1 = P_4.wedge(P_4.faces(1)[0]); W1 # optional - sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 6 vertices - sage: triangular_prism = polytopes.regular_polygon(3).prism() - sage: W1.is_combinatorially_isomorphic(triangular_prism) + sage: triangular_prism = polytopes.regular_polygon(3).prism() # optional - sage.rings.number_field + sage: W1.is_combinatorially_isomorphic(triangular_prism) # optional - sage.graphs # optional - sage.rings.number_field True sage: Q = polytopes.hypersimplex(4,2) @@ -6101,9 +4609,9 @@ def wedge(self, face, width=1): A vertex at (0, 1, 1, 0, -1)) sage: C_3_7 = polytopes.cyclic_polytope(3,7) - sage: P_6 = polytopes.regular_polygon(6) - sage: W4 = P_6.wedge(P_6.faces(1)[0]) - sage: W4.is_combinatorially_isomorphic(C_3_7.polar()) + sage: P_6 = polytopes.regular_polygon(6) # optional - sage.rings.number_field + sage: W4 = P_6.wedge(P_6.faces(1)[0]) # optional - sage.rings.number_field + sage: W4.is_combinatorially_isomorphic(C_3_7.polar()) # optional - sage.graphs # optional - sage.rings.number_field True REFERENCES: @@ -6583,7 +5091,7 @@ def face_lattice(self): sage: c5_20_fl = c5_20.face_lattice() # long time sage: [len(x) for x in c5_20_fl.level_sets()] # long time [1, 20, 190, 580, 680, 272, 1] - sage: polytopes.hypercube(2).face_lattice().plot() + sage: polytopes.hypercube(2).face_lattice().plot() # optional - sage.plot Graphics object consisting of 27 graphics primitives sage: level_sets = polytopes.cross_polytope(2).face_lattice().level_sets() sage: level_sets[0][0].ambient_V_indices(), level_sets[-1][0].ambient_V_indices() @@ -8350,7 +6858,7 @@ def schlegel_projection(self, facet=None, position=None): sage: tfcube.facets()[-1] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 8 vertices sage: sp = tfcube.schlegel_projection(tfcube.facets()[-1]) - sage: sp.plot() + sage: sp.plot() # optional - sage.plot Graphics3d Object The same truncated cube but see inside the tetrahedral facet:: @@ -8358,16 +6866,16 @@ def schlegel_projection(self, facet=None, position=None): sage: tfcube.facets()[4] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices sage: sp = tfcube.schlegel_projection(tfcube.facets()[4]) - sage: sp.plot() + sage: sp.plot() # optional - sage.plot Graphics3d Object A different values of ``position`` changes the projection:: sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],1/2) - sage: sp.plot() + sage: sp.plot() # optional - sage.plot Graphics3d Object sage: sp = tfcube.schlegel_projection(tfcube.facets()[4],4) - sage: sp.plot() + sage: sp.plot() # optional - sage.plot Graphics3d Object A value which is too large give a projection point that sees more than @@ -9039,323 +7547,6 @@ def _integrate_latte_(self, polynomial, **kwds): polynomial, cdd=True, **kwds) - def contains(self, point): - """ - Test whether the polyhedron contains the given ``point``. - - .. SEEALSO:: - - :meth:`interior_contains`, :meth:`relative_interior_contains`. - - INPUT: - - - ``point`` -- coordinates of a point (an iterable) - - OUTPUT: - - Boolean. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[[1,1],[1,-1],[0,0]]) - sage: P.contains( [1,0] ) - True - sage: P.contains( P.center() ) # true for any convex set - True - - As a shorthand, one may use the usual ``in`` operator:: - - sage: P.center() in P - True - sage: [-1,-1] in P - False - - The point need not have coordinates in the same field as the - polyhedron:: - - sage: ray = Polyhedron(vertices=[(0,0)], rays=[(1,0)], base_ring=QQ) - sage: ray.contains([sqrt(2)/3,0]) # irrational coordinates are ok - True - sage: a = var('a') - sage: ray.contains([a,0]) # a might be negative! - False - sage: assume(a>0) - sage: ray.contains([a,0]) - True - sage: ray.contains(['hello', 'kitty']) # no common ring for coordinates - False - - The empty polyhedron needs extra care, see :trac:`10238`:: - - sage: empty = Polyhedron(); empty - The empty polyhedron in ZZ^0 - sage: empty.contains([]) - False - sage: empty.contains([0]) # not a point in QQ^0 - False - sage: full = Polyhedron(vertices=[()]); full - A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex - sage: full.contains([]) - True - sage: full.contains([0]) - False - - TESTS: - - Passing non-iterable objects does not cause an exception, see :trac:`32013`:: - - sage: None in Polyhedron(vertices=[(0,0)], rays=[(1,0)], base_ring=QQ) - False - """ - try: - p = vector(point) - except TypeError: # point not iterable or no common ring for elements - try: - l = len(point) - except TypeError: - return False - if l > 0: - return False - else: - p = vector(self.base_ring(), []) - - if len(p) != self.ambient_dim(): - return False - - for H in self.Hrep_generator(): - if not H.contains(p): - return False - return True - - __contains__ = contains - - @cached_method - def interior(self): - """ - The interior of ``self``. - - OUTPUT: - - - either an empty polyhedron or an instance of - :class:`~sage.geometry.relative_interior.RelativeInterior` - - EXAMPLES: - - If the polyhedron is full-dimensional, the result is the - same as that of :meth:`relative_interior`:: - - sage: P_full = Polyhedron(vertices=[[0,0],[1,1],[1,-1]]) - sage: P_full.interior() - Relative interior of - a 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices - - If the polyhedron is of strictly smaller dimension than the - ambient space, its interior is empty:: - - sage: P_lower = Polyhedron(vertices=[[0,1], [0,-1]]) - sage: P_lower.interior() - The empty polyhedron in ZZ^2 - - TESTS:: - - sage: Empty = Polyhedron(ambient_dim=2); Empty - The empty polyhedron in ZZ^2 - sage: Empty.interior() is Empty - True - """ - if self.is_open(): - return self - if not self.is_full_dimensional(): - return self.parent().element_class(self.parent(), None, None) - return self.relative_interior() - - def interior_contains(self, point): - """ - Test whether the interior of the polyhedron contains the - given ``point``. - - .. SEEALSO:: - - :meth:`contains`, :meth:`relative_interior_contains`. - - INPUT: - - - ``point`` -- coordinates of a point - - OUTPUT: - - ``True`` or ``False``. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[[0,0],[1,1],[1,-1]]) - sage: P.contains( [1,0] ) - True - sage: P.interior_contains( [1,0] ) - False - - If the polyhedron is of strictly smaller dimension than the - ambient space, its interior is empty:: - - sage: P = Polyhedron(vertices=[[0,1],[0,-1]]) - sage: P.contains( [0,0] ) - True - sage: P.interior_contains( [0,0] ) - False - - The empty polyhedron needs extra care, see :trac:`10238`:: - - sage: empty = Polyhedron(); empty - The empty polyhedron in ZZ^0 - sage: empty.interior_contains([]) - False - """ - try: - p = vector(point) - except TypeError: # point not iterable or no common ring for elements - try: - l = len(point) - except TypeError: - return False - if l > 0: - return False - else: - p = vector(self.base_ring(), []) - - if len(p) != self.ambient_dim(): - return False - - for H in self.Hrep_generator(): - if not H.interior_contains(p): - return False - return True - - def is_relatively_open(self): - r""" - Return whether ``self`` is relatively open. - - OUTPUT: - - Boolean. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[(1,0), (-1,0)]); P - A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices - sage: P.is_relatively_open() - False - - sage: P0 = Polyhedron(vertices=[[1, 2]]); P0 - A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex - sage: P0.is_relatively_open() - True - - sage: Empty = Polyhedron(ambient_dim=2); Empty - The empty polyhedron in ZZ^2 - sage: Empty.is_relatively_open() - True - - sage: Line = Polyhedron(vertices=[(1, 1)], lines=[(1, 0)]); Line - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line - sage: Line.is_relatively_open() - True - - """ - return not self.inequalities() - - @cached_method - def relative_interior(self): - """ - Return the relative interior of ``self``. - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[(1,0), (-1,0)]) - sage: ri_P = P.relative_interior(); ri_P - Relative interior of - a 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices - sage: (0, 0) in ri_P - True - sage: (1, 0) in ri_P - False - - sage: P0 = Polyhedron(vertices=[[1, 2]]) - sage: P0.relative_interior() is P0 - True - - sage: Empty = Polyhedron(ambient_dim=2) - sage: Empty.relative_interior() is Empty - True - - sage: Line = Polyhedron(vertices=[(1, 1)], lines=[(1, 0)]) - sage: Line.relative_interior() is Line - True - """ - if self.is_relatively_open(): - return self - return RelativeInterior(self) - - def relative_interior_contains(self, point): - """ - Test whether the relative interior of the polyhedron - contains the given ``point``. - - .. SEEALSO:: - - :meth:`contains`, :meth:`interior_contains`. - - INPUT: - - - ``point`` -- coordinates of a point - - OUTPUT: - - ``True`` or ``False`` - - EXAMPLES:: - - sage: P = Polyhedron(vertices=[(1,0), (-1,0)]) - sage: P.contains( (0,0) ) - True - sage: P.interior_contains( (0,0) ) - False - sage: P.relative_interior_contains( (0,0) ) - True - sage: P.relative_interior_contains( (1,0) ) - False - - The empty polyhedron needs extra care, see :trac:`10238`:: - - sage: empty = Polyhedron(); empty - The empty polyhedron in ZZ^0 - sage: empty.relative_interior_contains([]) - False - """ - try: - p = vector(point) - except TypeError: # point not iterable or no common ring for elements - try: - l = len(point) - except TypeError: - return False - if l > 0: - return False - else: - p = vector(self.base_ring(), []) - - if len(p) != self.ambient_dim(): - return False - - for eq in self.equation_generator(): - if not eq.contains(p): - return False - - for ine in self.inequality_generator(): - if not ine.interior_contains(p): - return False - - return True - def is_simplex(self): r""" Return whether the polyhedron is a simplex. @@ -10785,7 +8976,7 @@ def _affine_hull_projection(self, *, sage: P1 = Polyhedron(vertices=([[-1, 1], [0, -1], [0, 0], [-1, -1]])) sage: P2 = Polyhedron(vertices=[[1, 1], [1, -1], [0, -1], [0, 0]]) sage: P = P1.intersection(P2) - sage: A, b = P.affine_hull_projection(as_affine_map=True, orthonormal=True, extend=True) + sage: A, b = P.affine_hull_projection(as_affine_map=True, orthonormal=True, extend=True) # optional - sage.rings.number_field sage: Polyhedron([(2,3,4)]).affine_hull_projection() A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex @@ -10796,7 +8987,7 @@ def _affine_hull_projection(self, *, 'field' sage: P = Polyhedron(vertices=[[0,0], [1,0]], backend='field') - sage: P.affine_hull_projection(orthogonal=True, orthonormal=True, extend=True).backend() + sage: P.affine_hull_projection(orthogonal=True, orthonormal=True, extend=True).backend() # optional - sage.rings.number_field 'field' Check that :trac:`29116` is fixed:: @@ -10816,7 +9007,7 @@ def _affine_hull_projection(self, *, Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: P.affine_hull_projection(orthonormal=True, extend=True) + sage: P.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field A 4-dimensional polyhedron in AA^4 defined as the convex hull of 6 vertices """ result = AffineHullProjectionData() @@ -11030,13 +9221,13 @@ def affine_hull_projection(self, A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 2 vertices sage: A.vertices() (A vertex at (0), A vertex at (2)) - sage: A = L.affine_hull_projection(orthonormal=True) + sage: A = L.affine_hull_projection(orthonormal=True) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A + sage: A = L.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices - sage: A.vertices() + sage: A.vertices() # optional - sage.rings.number_field (A vertex at (1.414213562373095?), A vertex at (0.?e-18)) More generally:: @@ -11082,71 +9273,72 @@ def affine_hull_projection(self, More examples with the ``orthonormal`` parameter:: - sage: P = polytopes.permutahedron(3); P + sage: P = polytopes.permutahedron(3); P # optional - sage.combinat # optional - sage.rings.number_field A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 6 vertices - sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))} + sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection().faces(1)]) == {1, sqrt(AA(2))} # optional - sage.combinat # optional - sage.rings.number_field True - sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection(orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))} + sage: set([F.as_polyhedron().affine_hull_projection(orthonormal=True, extend=True).volume() for F in P.affine_hull_projection(orthonormal=True, extend=True).faces(1)]) == {sqrt(AA(2))} # optional - sage.combinat # optional - sage.rings.number_field True - sage: D = polytopes.dodecahedron() - sage: F = D.faces(2)[0].as_polyhedron() - sage: F.affine_hull_projection(orthogonal=True) + + sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: F = D.faces(2)[0].as_polyhedron() # optional - sage.rings.number_field + sage: F.affine_hull_projection(orthogonal=True) # optional - sage.rings.number_field A 2-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^2 defined as the convex hull of 5 vertices - sage: F.affine_hull_projection(orthonormal=True, extend=True) + sage: F.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field A 2-dimensional polyhedron in AA^2 defined as the convex hull of 5 vertices - sage: K. = QuadraticField(2) - sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]) - sage: K. = QuadraticField(2) - sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P + + sage: K. = QuadraticField(2) # optional - sage.rings.number_field + sage: P = Polyhedron([2*[K.zero()],2*[sqrt2]]); P # optional - sage.rings.number_field A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^2 defined as the convex hull of 2 vertices - sage: P.vertices() + sage: P.vertices() # optional - sage.rings.number_field (A vertex at (0, 0), A vertex at (sqrt2, sqrt2)) - sage: A = P.affine_hull_projection(orthonormal=True); A + sage: A = P.affine_hull_projection(orthonormal=True); A # optional - sage.rings.number_field A 1-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?)^1 defined as the convex hull of 2 vertices - sage: A.vertices() + sage: A.vertices() # optional - sage.rings.number_field (A vertex at (0), A vertex at (2)) - sage: K. = QuadraticField(3) - sage: P = Polyhedron([2*[K.zero()],2*[sqrt3]]); P + + sage: K. = QuadraticField(3) # optional - sage.rings.number_field + sage: P = Polyhedron([2*[K.zero()],2*[sqrt3]]); P # optional - sage.rings.number_field A 1-dimensional polyhedron in (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 defined as the convex hull of 2 vertices - sage: P.vertices() + sage: P.vertices() # optional - sage.rings.number_field (A vertex at (0, 0), A vertex at (sqrt3, sqrt3)) - sage: A = P.affine_hull_projection(orthonormal=True) + sage: A = P.affine_hull_projection(orthonormal=True) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: the base ring needs to be extended; try with "extend=True" - sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A + sage: A = P.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices - sage: A.vertices() + sage: A.vertices() # optional - sage.rings.number_field (A vertex at (0), A vertex at (2.449489742783178?)) - sage: sqrt(6).n() + sage: sqrt(6).n() # optional - sage.rings.number_field 2.44948974278318 The affine hull is combinatorially equivalent to the input:: - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection()) + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection()) # optional - sage.rings.number_field True - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthogonal=True)) + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthogonal=True)) # optional - sage.rings.number_field True - sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthonormal=True, extend=True)) + sage: P.is_combinatorially_isomorphic(P.affine_hull_projection(orthonormal=True, extend=True)) # optional - sage.rings.number_field True The ``orthonormal=True`` parameter preserves volumes; it provides an isometric copy of the polyhedron:: - sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() - sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True) - sage: _, c= P.is_inscribed(certificate=True) - sage: c + sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field + sage: P = Pentagon.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: _, c= P.is_inscribed(certificate=True) # optional - sage.rings.number_field + sage: c # optional - sage.rings.number_field (0.4721359549995794?, 0.6498393924658126?) - sage: circumradius = (c-vector(P.vertices()[0])).norm() - sage: p = polytopes.regular_polygon(5) - sage: p.volume() + sage: circumradius = (c-vector(P.vertices()[0])).norm() # optional - sage.rings.number_field + sage: p = polytopes.regular_polygon(5) # optional - sage.rings.number_field + sage: p.volume() # optional - sage.rings.number_field 2.377641290737884? - sage: P.volume() + sage: P.volume() # optional - sage.rings.number_field 1.53406271079097? - sage: p.volume()*circumradius^2 + sage: p.volume()*circumradius^2 # optional - sage.rings.number_field 1.534062710790965? - sage: P.volume() == p.volume()*circumradius^2 + sage: P.volume() == p.volume()*circumradius^2 # optional - sage.rings.number_field True One can also use ``orthogonal`` parameter to calculate volumes; @@ -11154,28 +9346,28 @@ def affine_hull_projection(self, by the square root of the determinant of the linear part of the affine transformation times its transpose:: - sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() - sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True, extend=True) - sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True) - sage: A, b = Pentagon.affine_hull_projection(orthogonal=True, as_affine_map=True) - sage: Adet = (A.matrix().transpose()*A.matrix()).det() - sage: Pnormal.volume() + sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field + sage: Pnormal = Pentagon.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: Pgonal = Pentagon.affine_hull_projection(orthogonal=True) # optional - sage.rings.number_field + sage: A, b = Pentagon.affine_hull_projection(orthogonal=True, as_affine_map=True) # optional - sage.rings.number_field + sage: Adet = (A.matrix().transpose()*A.matrix()).det() # optional - sage.rings.number_field + sage: Pnormal.volume() # optional - sage.rings.number_field 1.53406271079097? - sage: Pgonal.volume()/Adet.sqrt(extend=True) + sage: Pgonal.volume()/Adet.sqrt(extend=True) # optional - sage.rings.number_field -80*(55*sqrt(5) - 123)/sqrt(-6368*sqrt(5) + 14240) - sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20) + sage: Pgonal.volume()/AA(Adet).sqrt().n(digits=20) # optional - sage.rings.number_field 1.5340627107909646813 - sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet) + sage: AA(Pgonal.volume()^2) == (Pnormal.volume()^2)*AA(Adet) # optional - sage.rings.number_field True Another example with ``as_affine_map=True``:: - sage: P = polytopes.permutahedron(4) - sage: A, b = P.affine_hull_projection(orthonormal=True, as_affine_map=True, extend=True) - sage: Q = P.affine_hull_projection(orthonormal=True, extend=True) - sage: Q.center() + sage: P = polytopes.permutahedron(4) # optional - sage.combinat # optional - sage.rings.number_field + sage: A, b = P.affine_hull_projection(orthonormal=True, as_affine_map=True, extend=True) # optional - sage.combinat # optional - sage.rings.number_field + sage: Q = P.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.combinat # optional - sage.rings.number_field + sage: Q.center() # optional - sage.combinat # optional - sage.rings.number_field (0.7071067811865475?, 1.224744871391589?, 1.732050807568878?) - sage: A(P.center()) + b == Q.center() + sage: A(P.center()) + b == Q.center() # optional - sage.combinat # optional - sage.rings.number_field True For unbounded, non full-dimensional polyhedra, the ``orthogonal=True`` and ``orthonormal=True`` @@ -11438,7 +9630,7 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien sage: submanifolds = [ ....: F.as_polyhedron().affine_hull_manifold(name=f'F{i}', orthogonal=True, ambient_space=E3) ....: for i, F in enumerate(D.facets())] - sage: sum(FM.plot({}, srange(-2, 2, 0.1), srange(-2, 2, 0.1), opacity=0.2) # not tested + sage: sum(FM.plot({}, srange(-2, 2, 0.1), srange(-2, 2, 0.1), opacity=0.2) # not tested # optional - sage.plot ....: for FM in submanifolds) + D.plot() Graphics3d Object diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py new file mode 100644 index 00000000000..537a4c08bd7 --- /dev/null +++ b/src/sage/geometry/polyhedron/base0.py @@ -0,0 +1,1179 @@ +r""" +Base class for polyhedra, part 0 + +Initialization and access to Vrepresentation and Hrepresentation. +""" + +# **************************************************************************** +# Copyright (C) 2008-2012 Marshall Hampton +# Copyright (C) 2011-2015 Volker Braun +# Copyright (C) 2012-2018 Frederic Chapoton +# Copyright (C) 2013 Andrey Novoseltsev +# Copyright (C) 2014-2017 Moritz Firsching +# Copyright (C) 2014-2019 Thierry Monteil +# Copyright (C) 2015 Nathann Cohen +# Copyright (C) 2015-2017 Jeroen Demeyer +# Copyright (C) 2015-2017 Vincent Delecroix +# Copyright (C) 2015-2018 Dima Pasechnik +# Copyright (C) 2015-2020 Jean-Philippe Labbe +# Copyright (C) 2015-2021 Matthias Koeppe +# Copyright (C) 2016-2019 Daniel Krenn +# Copyright (C) 2017 Marcelo Forets +# Copyright (C) 2017-2018 Mark Bell +# Copyright (C) 2019 Julian Ritter +# Copyright (C) 2019-2020 Laith Rastanawi +# Copyright (C) 2019-2020 Sophia Elia +# Copyright (C) 2019-2021 Jonathan Kliem +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.structure.element import Element +import sage.geometry.abc + +class Polyhedron_base0(Element, sage.geometry.abc.Polyhedron): + """ + Initialization and basic access for polyhedra. + + See :class:`sage.geometry.polyhedron.base.Polyhedron_base`. + + TESTS:: + + sage: from sage.geometry.polyhedron.base0 import Polyhedron_base0 + sage: P = Polyhedron(rays=[[1, 0, 0]], lines=[[0, 1, 0]]) + sage: Polyhedron_base0.Vrepresentation(P) + (A line in the direction (0, 1, 0), + A vertex at (0, 0, 0), + A ray in the direction (1, 0, 0)) + sage: Polyhedron_base0.vertices.f(P) + (A vertex at (0, 0, 0),) + sage: Polyhedron_base0.rays.f(P) + (A ray in the direction (1, 0, 0),) + sage: Polyhedron_base0.lines.f(P) + (A line in the direction (0, 1, 0),) + sage: Polyhedron_base0.Hrepresentation(P) + (An equation (0, 0, 1) x + 0 == 0, An inequality (1, 0, 0) x + 0 >= 0) + sage: Polyhedron_base0.inequalities.f(P) + (An inequality (1, 0, 0) x + 0 >= 0,) + sage: Polyhedron_base0.equations.f(P) + (An equation (0, 0, 1) x + 0 == 0,) + sage: Polyhedron_base0.base_ring(P) + Integer Ring + sage: Polyhedron_base0.backend(P) + 'ppl' + sage: Polyhedron_base0.change_ring(P, ZZ, backend='field').backend() + 'field' + sage: Polyhedron_base0.base_extend(P, QQ) + A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line + """ + def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds): + """ + Initializes the polyhedron. + + See :class:`sage.geometry.polyhedron.base.Polyhedron_base` for a description of the input + data. + + TESTS:: + + sage: p = Polyhedron() # indirect doctests + + sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field + sage: from sage.geometry.polyhedron.parent import Polyhedra_field + sage: parent = Polyhedra_field(AA, 1, 'field') + sage: Vrep = [[[0], [1/2], [1]], [], []] + sage: Hrep = [[[0, 1], [1, -1]], []] + sage: p = Polyhedron_field(parent, Vrep, Hrep, + ....: Vrep_minimal=False, Hrep_minimal=True) + Traceback (most recent call last): + ... + ValueError: if both Vrep and Hrep are provided, they must be minimal... + + Illustration of ``pref_rep``. + Note that ``ppl`` doesn't support precomputed data:: + + sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_QQ_ppl + sage: from sage.geometry.polyhedron.parent import Polyhedra_QQ_ppl + sage: parent = Polyhedra_QQ_ppl(QQ, 1, 'ppl') + sage: p = Polyhedron_QQ_ppl(parent, Vrep, 'nonsense', + ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrep') + sage: p = Polyhedron_QQ_ppl(parent, 'nonsense', Hrep, + ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Hrep') + sage: p = Polyhedron_QQ_ppl(parent, 'nonsense', Hrep, + ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrepresentation') + Traceback (most recent call last): + ... + ValueError: ``pref_rep`` must be one of ``(None, 'Vrep', 'Hrep')`` + + If the backend supports precomputed data, ``pref_rep`` is ignored:: + + sage: p = Polyhedron_field(parent, Vrep, 'nonsense', + ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrep') + Traceback (most recent call last): + ... + TypeError: ..._init_Hrepresentation() takes 3 positional arguments but 9 were given + + The empty polyhedron is detected when the Vrepresentation is given with generator; + see :trac:`29899`:: + + sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd + sage: from sage.geometry.polyhedron.parent import Polyhedra_QQ_cdd + sage: parent = Polyhedra_QQ_cdd(QQ, 0, 'cdd') + sage: p = Polyhedron_QQ_cdd(parent, [iter([]), iter([]), iter([])], None) + """ + Element.__init__(self, parent=parent) + if Vrep is not None and Hrep is not None: + if not (Vrep_minimal is True and Hrep_minimal is True): + raise ValueError("if both Vrep and Hrep are provided, they must be minimal" + " and Vrep_minimal and Hrep_minimal must both be True") + if hasattr(self, "_init_from_Vrepresentation_and_Hrepresentation"): + self._init_from_Vrepresentation_and_Hrepresentation(Vrep, Hrep) + return + else: + if pref_rep is None: + # Initialize from Hrepresentation if this seems simpler. + Vrep = [tuple(Vrep[0]), tuple(Vrep[1]), Vrep[2]] + Hrep = [tuple(Hrep[0]), Hrep[1]] + if len(Hrep[0]) < len(Vrep[0]) + len(Vrep[1]): + pref_rep = 'Hrep' + else: + pref_rep = 'Vrep' + if pref_rep == 'Vrep': + Hrep = None + elif pref_rep == 'Hrep': + Vrep = None + else: + raise ValueError("``pref_rep`` must be one of ``(None, 'Vrep', 'Hrep')``") + if Vrep is not None: + vertices, rays, lines = Vrep + + # We build tuples out of generators now to detect the empty polyhedron. + + # The damage is limited: + # The backend will have to obtain all elements from the generator anyway. + # The generators are mainly for saving time with initializing from + # Vrepresentation and Hrepresentation. + # If we dispose of one of them (see above), it is wasteful to have generated it. + + # E.g. the dilate will be set up with new Vrepresentation and Hrepresentation + # regardless of the backend along with the argument ``pref_rep``. + # As we only use generators, there is no penalty to this approach + # (and the method ``dilation`` does not have to distinguish by backend). + + if not isinstance(vertices, (tuple, list)): + vertices = tuple(vertices) + if not isinstance(rays, (tuple, list)): + rays = tuple(rays) + if not isinstance(lines, (tuple, list)): + lines = tuple(lines) + + if vertices or rays or lines: + self._init_from_Vrepresentation(vertices, rays, lines, **kwds) + else: + self._init_empty_polyhedron() + elif Hrep is not None: + ieqs, eqns = Hrep + self._init_from_Hrepresentation(ieqs, eqns, **kwds) + else: + self._init_empty_polyhedron() + + def _init_from_Vrepresentation(self, vertices, rays, lines, **kwds): + """ + Construct polyhedron from V-representation data. + + INPUT: + + - ``vertices`` -- list of point. Each point can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``rays`` -- list of rays. Each ray can be specified as any + iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``lines`` -- list of lines. Each line can be specified as + any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + EXAMPLES:: + + sage: p = Polyhedron() + sage: from sage.geometry.polyhedron.base import Polyhedron_base + sage: Polyhedron_base._init_from_Vrepresentation(p, [], [], []) + Traceback (most recent call last): + ... + 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): + """ + Construct polyhedron from H-representation data. + + INPUT: + + - ``ieqs`` -- list of inequalities. Each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``eqns`` -- list of equalities. Each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + EXAMPLES:: + + sage: p = Polyhedron() + sage: from sage.geometry.polyhedron.base import Polyhedron_base + sage: Polyhedron_base._init_from_Hrepresentation(p, [], []) + Traceback (most recent call last): + ... + NotImplementedError: a derived class must implement this method + """ + raise NotImplementedError('a derived class must implement this method') + + def _init_empty_polyhedron(self): + """ + Initializes an empty polyhedron. + + TESTS:: + + sage: empty = Polyhedron(); empty + The empty polyhedron in ZZ^0 + sage: empty.Vrepresentation() + () + sage: empty.Hrepresentation() + (An equation -1 == 0,) + sage: Polyhedron(vertices = []) + The empty polyhedron in ZZ^0 + sage: Polyhedron(vertices = [])._init_empty_polyhedron() + sage: from sage.geometry.polyhedron.parent import Polyhedra + sage: Polyhedra(QQ,7)() + A 0-dimensional polyhedron in QQ^7 defined as the convex hull of 1 vertex + """ + self._Vrepresentation = [] + self._Hrepresentation = [] + self.parent()._make_Equation(self, [-1] + [0] * self.ambient_dim()) + self._Vrepresentation = tuple(self._Vrepresentation) + self._Hrepresentation = tuple(self._Hrepresentation) + + def base_extend(self, base_ring, backend=None): + """ + Return a new polyhedron over a larger base ring. + + This method can also be used to change the backend. + + INPUT: + + - ``base_ring`` -- the new base ring + + - ``backend`` -- the new backend, see + :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. + If ``None`` (the default), attempt to keep the same backend. + Otherwise, use the same defaulting behavior + as described there. + + OUTPUT: + + The same polyhedron, but over a larger base ring and possibly with a changed backend. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[(1,0), (0,1)], rays=[(1,1)], base_ring=ZZ); P + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 1 ray + sage: P.base_extend(QQ) + A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 1 ray + sage: P.base_extend(QQ) == P + True + + TESTS: + + Test that :trac:`22575` is fixed:: + + sage: Q = P.base_extend(ZZ, backend='field') + sage: Q.backend() + 'field' + + """ + new_parent = self.parent().base_extend(base_ring, backend) + return new_parent(self, copy=True) + + def change_ring(self, base_ring, backend=None): + """ + Return the polyhedron obtained by coercing the entries of the + vertices/lines/rays of this polyhedron into the given ring. + + This method can also be used to change the backend. + + INPUT: + + - ``base_ring`` -- the new base ring + + - ``backend`` -- the new backend or ``None`` (default), see + :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. + If ``None`` (the default), attempt to keep the same backend. + Otherwise, use the same defaulting behavior + as described there. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[(1,0), (0,1)], rays=[(1,1)], base_ring=QQ); P + A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 1 ray + sage: P.change_ring(ZZ) + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 1 ray + sage: P.change_ring(ZZ) == P + True + + sage: P = Polyhedron(vertices=[(-1.3,0), (0,2.3)], base_ring=RDF); P.vertices() + (A vertex at (-1.3, 0.0), A vertex at (0.0, 2.3)) + sage: P.change_ring(QQ).vertices() + (A vertex at (-13/10, 0), A vertex at (0, 23/10)) + sage: P == P.change_ring(QQ) + True + sage: P.change_ring(ZZ) + Traceback (most recent call last): + ... + TypeError: cannot change the base ring to the Integer Ring + + sage: P = polytopes.regular_polygon(3); P # optional - sage.rings.number_field + A 2-dimensional polyhedron in AA^2 defined as the convex hull of 3 vertices + sage: P.vertices() # optional - sage.rings.number_field + (A vertex at (0.?e-16, 1.000000000000000?), + A vertex at (0.866025403784439?, -0.500000000000000?), + A vertex at (-0.866025403784439?, -0.500000000000000?)) + sage: P.change_ring(QQ) # optional - sage.rings.number_field + Traceback (most recent call last): + ... + TypeError: cannot change the base ring to the Rational Field + + .. WARNING:: + + The base ring ``RDF`` should be used with care. As it is + not an exact ring, certain computations may break or + silently produce wrong results, for example changing the + base ring from an exact ring into ``RDF`` may cause a + loss of data:: + + sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P # optional - sage.rings.number_field + A 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices + sage: Q = P.change_ring(RDF); Q # optional - sage.rings.number_field + A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex + sage: P.n_vertices() == Q.n_vertices() # optional - sage.rings.number_field + False + """ + from sage.categories.rings import Rings + + if base_ring not in Rings(): + raise ValueError("invalid base ring") + + try: + vertices = [[base_ring(x) for x in vertex] for vertex in self.vertices_list()] + rays = [[base_ring(x) for x in ray] for ray in self.rays_list()] + lines = [[base_ring(x) for x in line] for line in self.lines_list()] + + except (TypeError, ValueError): + raise TypeError("cannot change the base ring to the {0}".format(base_ring)) + + new_parent = self.parent().change_ring(base_ring, backend) + return new_parent([vertices, rays, lines], None) + + def is_mutable(self): + r""" + Return True if the polyhedron is mutable, i.e. it can be modified in place. + + EXAMPLES:: + + sage: p = polytopes.cube(backend='field') + sage: p.is_mutable() + False + """ + return False + + def is_immutable(self): + r""" + Return True if the polyhedron is immutable, i.e. it cannot be modified in place. + + EXAMPLES:: + + sage: p = polytopes.cube(backend='field') + sage: p.is_immutable() + True + """ + return True + + @cached_method + def n_equations(self): + """ + Return the number of equations. The representation will + always be minimal, so the number of equations is the + codimension of the polyhedron in the ambient space. + + EXAMPLES:: + + sage: p = Polyhedron(vertices = [[1,0,0],[0,1,0],[0,0,1]]) + sage: p.n_equations() + 1 + """ + return len(self.equations()) + + @cached_method + def n_inequalities(self): + """ + Return the number of inequalities. The representation will + always be minimal, so the number of inequalities is the + number of facets of the polyhedron in the ambient space. + + EXAMPLES:: + + sage: p = Polyhedron(vertices = [[1,0,0],[0,1,0],[0,0,1]]) + sage: p.n_inequalities() + 3 + + sage: p = Polyhedron(vertices = [[t,t^2,t^3] for t in range(6)]) + sage: p.n_facets() + 8 + """ + return len(self.inequalities()) + + n_facets = n_inequalities + + @cached_method + def n_vertices(self): + """ + Return the number of vertices. The representation will + always be minimal. + + .. WARNING:: + + If the polyhedron has lines, return the number of vertices in + the ``Vrepresentation``. As the represented polyhedron has + no 0-dimensional faces (i.e. vertices), ``n_vertices`` corresponds + to the number of `k`-faces, where `k` is the number of lines:: + + sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) + sage: P.n_vertices() + 1 + sage: P.faces(0) + () + sage: P.f_vector() + (1, 0, 1, 1) + + sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0],[0,1,1]]) + sage: P.n_vertices() + 1 + sage: P.f_vector() + (1, 0, 0, 1, 1) + + EXAMPLES:: + + sage: p = Polyhedron(vertices = [[1,0],[0,1],[1,1]], rays=[[1,1]]) + sage: p.n_vertices() + 2 + """ + return len(self.vertices()) + + @cached_method + def n_rays(self): + """ + Return the number of rays. The representation will + always be minimal. + + EXAMPLES:: + + sage: p = Polyhedron(vertices = [[1,0],[0,1]], rays=[[1,1]]) + sage: p.n_rays() + 1 + """ + return len(self.rays()) + + @cached_method + def n_lines(self): + """ + Return the number of lines. The representation will + always be minimal. + + EXAMPLES:: + + sage: p = Polyhedron(vertices = [[0,0]], rays=[[0,1],[0,-1]]) + sage: p.n_lines() + 1 + """ + return len(self.lines()) + + def Hrepresentation(self, index=None): + """ + Return the objects of the H-representation. Each entry is + either an inequality or a equation. + + INPUT: + + - ``index`` -- either an integer or ``None`` + + OUTPUT: + + The optional argument is an index running from ``0`` to + ``self.n_Hrepresentation()-1``. If present, the + H-representation object at the given index will be + returned. Without an argument, returns the list of all + H-representation objects. + + EXAMPLES:: + + sage: p = polytopes.hypercube(3, backend='field') + sage: p.Hrepresentation(0) + An inequality (-1, 0, 0) x + 1 >= 0 + sage: p.Hrepresentation(0) == p.Hrepresentation()[0] + True + """ + if index is None: + return self._Hrepresentation + else: + return self._Hrepresentation[index] + + def Hrepresentation_str(self, separator='\n', latex=False, style='>=', align=None, **kwds): + r""" + Return a human-readable string representation of the Hrepresentation of this + polyhedron. + + INPUT: + + - ``separator`` -- a string. Default is ``"\n"``. + + - ``latex`` -- a boolean. Default is ``False``. + + - ``style`` -- either ``"positive"`` (making all coefficients positive) + or ``"<="``, or ``">="``. Default is ``">="``. + + - ``align`` -- a boolean or ``None''. Default is ``None`` in which case + ``align`` is ``True`` if ``separator`` is the newline character. + If set, then the lines of the output string are aligned + by the comparison symbol by padding blanks. + + Keyword parameters of + :meth:`~sage.geometry.polyhedron.representation.Hrepresentation.repr_pretty` + are passed on: + + - ``prefix`` -- a string + + - ``indices`` -- a tuple or other iterable + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: P = polytopes.permutahedron(3) + sage: print(P.Hrepresentation_str()) + x0 + x1 + x2 == 6 + x0 + x1 >= 3 + -x0 - x1 >= -5 + x1 >= 1 + -x0 >= -3 + x0 >= 1 + -x1 >= -3 + + sage: print(P.Hrepresentation_str(style='<=')) + -x0 - x1 - x2 == -6 + -x0 - x1 <= -3 + x0 + x1 <= 5 + -x1 <= -1 + x0 <= 3 + -x0 <= -1 + x1 <= 3 + + sage: print(P.Hrepresentation_str(style='positive')) + x0 + x1 + x2 == 6 + x0 + x1 >= 3 + 5 >= x0 + x1 + x1 >= 1 + 3 >= x0 + x0 >= 1 + 3 >= x1 + + sage: print(P.Hrepresentation_str(latex=True)) + \begin{array}{rcl} + x_{0} + x_{1} + x_{2} & = & 6 \\ + x_{0} + x_{1} & \geq & 3 \\ + -x_{0} - x_{1} & \geq & -5 \\ + x_{1} & \geq & 1 \\ + -x_{0} & \geq & -3 \\ + x_{0} & \geq & 1 \\ + -x_{1} & \geq & -3 + \end{array} + + sage: print(P.Hrepresentation_str(align=False)) + x0 + x1 + x2 == 6 + x0 + x1 >= 3 + -x0 - x1 >= -5 + x1 >= 1 + -x0 >= -3 + x0 >= 1 + -x1 >= -3 + + sage: c = polytopes.cube() + sage: c.Hrepresentation_str(separator=', ', style='positive') + '1 >= x0, 1 >= x1, 1 >= x2, 1 + x0 >= 0, 1 + x2 >= 0, 1 + x1 >= 0' + """ + pretty_hs = [h.repr_pretty(split=True, latex=latex, style=style, **kwds) for h in self.Hrepresentation()] + shift = any(pretty_h[2].startswith('-') for pretty_h in pretty_hs) + + if align is None: + align = separator == "\n" + if align: + lengths = [(len(s[0]), len(s[1]), len(s[2])) for s in pretty_hs] + from operator import itemgetter + length_left = max(lengths, key=itemgetter(0))[0] + length_middle = max(lengths, key=itemgetter(1))[1] + length_right = max(lengths, key=itemgetter(2))[2] + if shift: + length_right += 1 + if latex: + h_line = "{:>" + "{}".format(length_left) + "} & {:" + \ + "{}".format(length_middle) + "} & {:" + \ + "{}".format(length_right) + "}\\\\" + else: + h_line = "{:>" + "{}".format(length_left) \ + + "} {:" + "{}".format(length_middle) \ + + "} {:" + "{}".format(length_right) + "}" + elif latex: + h_line = "{} & {} & {}\\\\" + else: + h_line = "{} {} {}" + + def pad_non_minus(s): + if align and shift and not s.startswith('-'): + return ' ' + s + else: + return s + h_list = [h_line.format(pretty_h[0], pretty_h[1], pad_non_minus(pretty_h[2])) + for pretty_h in pretty_hs] + pretty_print = separator.join(h_list) + + if not latex: + return pretty_print + else: + # below we remove the 2 unnecessary backslashes at the end of pretty_print + return "\\begin{array}{rcl}\n" + pretty_print[:-2] + "\n\\end{array}" + + def Hrep_generator(self): + """ + Return an iterator over the objects of the H-representation + (inequalities or equations). + + EXAMPLES:: + + sage: p = polytopes.hypercube(3) + sage: next(p.Hrep_generator()) + An inequality (-1, 0, 0) x + 1 >= 0 + """ + for H in self.Hrepresentation(): + yield H + + @cached_method + def n_Hrepresentation(self): + """ + Return the number of objects that make up the + H-representation of the polyhedron. + + OUTPUT: + + Integer. + + EXAMPLES:: + + sage: p = polytopes.cross_polytope(4) + sage: p.n_Hrepresentation() + 16 + sage: p.n_Hrepresentation() == p.n_inequalities() + p.n_equations() + True + """ + return len(self.Hrepresentation()) + + def Vrepresentation(self, index=None): + """ + Return the objects of the V-representation. Each entry is + either a vertex, a ray, or a line. + + See :mod:`sage.geometry.polyhedron.constructor` for a + definition of vertex/ray/line. + + INPUT: + + - ``index`` -- either an integer or ``None`` + + OUTPUT: + + The optional argument is an index running from ``0`` to + ``self.n_Vrepresentation()-1``. If present, the + V-representation object at the given index will be + returned. Without an argument, returns the list of all + V-representation objects. + + EXAMPLES:: + + sage: p = polytopes.simplex(4, project=True) + sage: p.Vrepresentation(0) + A vertex at (0.7071067812, 0.4082482905, 0.2886751346, 0.2236067977) + sage: p.Vrepresentation(0) == p.Vrepresentation() [0] + True + """ + if index is None: + return self._Vrepresentation + else: + return self._Vrepresentation[index] + + @cached_method + def n_Vrepresentation(self): + """ + Return the number of objects that make up the + V-representation of the polyhedron. + + OUTPUT: + + Integer. + + EXAMPLES:: + + sage: p = polytopes.simplex(4) + sage: p.n_Vrepresentation() + 5 + sage: p.n_Vrepresentation() == p.n_vertices() + p.n_rays() + p.n_lines() + True + """ + return len(self.Vrepresentation()) + + def Vrep_generator(self): + """ + Return an iterator over the objects of the V-representation + (vertices, rays, and lines). + + EXAMPLES:: + + sage: p = polytopes.cyclic_polytope(3,4) + sage: vg = p.Vrep_generator() + sage: next(vg) + A vertex at (0, 0, 0) + sage: next(vg) + A vertex at (1, 1, 1) + """ + for V in self.Vrepresentation(): + yield V + + def inequality_generator(self): + """ + Return a generator for the defining inequalities of the + polyhedron. + + OUTPUT: + + A generator of the inequality Hrepresentation objects. + + EXAMPLES:: + + sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) + sage: for v in triangle.inequality_generator(): print(v) + An inequality (1, 1) x - 1 >= 0 + An inequality (0, -1) x + 1 >= 0 + An inequality (-1, 0) x + 1 >= 0 + sage: [ v for v in triangle.inequality_generator() ] + [An inequality (1, 1) x - 1 >= 0, + An inequality (0, -1) x + 1 >= 0, + An inequality (-1, 0) x + 1 >= 0] + sage: [ [v.A(), v.b()] for v in triangle.inequality_generator() ] + [[(1, 1), -1], [(0, -1), 1], [(-1, 0), 1]] + """ + for H in self.Hrepresentation(): + if H.is_inequality(): + yield H + + @cached_method + def inequalities(self): + """ + Return all inequalities. + + OUTPUT: + + A tuple of inequalities. + + EXAMPLES:: + + sage: p = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[1,0,0],[2,2,2]]) + sage: p.inequalities()[0:3] + (An inequality (1, 0, 0) x + 0 >= 0, + An inequality (0, 1, 0) x + 0 >= 0, + An inequality (0, 0, 1) x + 0 >= 0) + sage: p3 = Polyhedron(vertices = Permutations([1,2,3,4])) + sage: ieqs = p3.inequalities() + sage: ieqs[0] + An inequality (0, 1, 1, 1) x - 6 >= 0 + sage: list(_) + [-6, 0, 1, 1, 1] + """ + return tuple(self.inequality_generator()) + + def inequalities_list(self): + """ + Return a list of inequalities as coefficient lists. + + .. NOTE:: + + It is recommended to use :meth:`inequalities` or + :meth:`inequality_generator` instead to iterate over the + list of :class:`Inequality` objects. + + EXAMPLES:: + + sage: p = Polyhedron(vertices = [[0,0,0],[0,0,1],[0,1,0],[1,0,0],[2,2,2]]) + sage: p.inequalities_list()[0:3] + [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] + sage: p3 = Polyhedron(vertices = Permutations([1,2,3,4])) + sage: ieqs = p3.inequalities_list() + sage: ieqs[0] + [-6, 0, 1, 1, 1] + sage: ieqs[-1] + [-3, 0, 1, 0, 1] + sage: ieqs == [list(x) for x in p3.inequality_generator()] + True + """ + return [list(x) for x in self.inequality_generator()] + + def equation_generator(self): + """ + Return a generator for the linear equations satisfied by the + polyhedron. + + EXAMPLES:: + + sage: p = polytopes.regular_polygon(8,base_ring=RDF) + sage: p3 = Polyhedron(vertices = [x+[0] for x in p.vertices()], base_ring=RDF) + sage: next(p3.equation_generator()) + An equation (0.0, 0.0, 1.0) x + 0.0 == 0 + """ + for H in self.Hrepresentation(): + if H.is_equation(): + yield H + + @cached_method + def equations(self): + """ + Return all linear constraints of the polyhedron. + + OUTPUT: + + A tuple of equations. + + EXAMPLES:: + + sage: test_p = Polyhedron(vertices = [[1,2,3,4],[2,1,3,4],[4,3,2,1],[3,4,1,2]]) + sage: test_p.equations() + (An equation (1, 1, 1, 1) x - 10 == 0,) + """ + return tuple(self.equation_generator()) + + def equations_list(self): + """ + Return the linear constraints of the polyhedron. As with + inequalities, each constraint is given as [b -a1 -a2 ... an] + where for variables x1, x2,..., xn, the polyhedron satisfies + the equation b = a1*x1 + a2*x2 + ... + an*xn. + + .. NOTE:: + + It is recommended to use :meth:`equations` or + :meth:`equation_generator()` instead to iterate over the + list of + :class:`~sage.geometry.polyhedron.representation.Equation` + objects. + + EXAMPLES:: + + sage: test_p = Polyhedron(vertices = [[1,2,3,4],[2,1,3,4],[4,3,2,1],[3,4,1,2]]) + sage: test_p.equations_list() + [[-10, 1, 1, 1, 1]] + """ + return [list(eq) for eq in self.equation_generator()] + + def vertices_list(self): + """ + Return a list of vertices of the polyhedron. + + .. NOTE:: + + It is recommended to use :meth:`vertex_generator` instead to + iterate over the list of :class:`Vertex` objects. + + .. WARNING:: + + If the polyhedron has lines, return the vertices + of the ``Vrepresentation``. However, the represented polyhedron + has no 0-dimensional faces (i.e. vertices):: + + sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) + sage: P.vertices_list() + [[0, 0, 0]] + sage: P.faces(0) + () + + EXAMPLES:: + + sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) + sage: triangle.vertices_list() + [[0, 1], [1, 0], [1, 1]] + sage: a_simplex = Polyhedron(ieqs = [ + ....: [0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[0,0,0,0,1] + ....: ], eqns = [[1,-1,-1,-1,-1]]) + sage: a_simplex.vertices_list() + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] + sage: a_simplex.vertices_list() == [list(v) for v in a_simplex.vertex_generator()] + True + """ + return [list(x) for x in self.vertex_generator()] + + def vertex_generator(self): + """ + Return a generator for the vertices of the polyhedron. + + .. WARNING:: + + If the polyhedron has lines, return a generator for the vertices + of the ``Vrepresentation``. However, the represented polyhedron + has no 0-dimensional faces (i.e. vertices):: + + sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) + sage: list(P.vertex_generator()) + [A vertex at (0, 0, 0)] + sage: P.faces(0) + () + + EXAMPLES:: + + sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) + sage: for v in triangle.vertex_generator(): print(v) + A vertex at (0, 1) + A vertex at (1, 0) + A vertex at (1, 1) + sage: v_gen = triangle.vertex_generator() + sage: next(v_gen) # the first vertex + A vertex at (0, 1) + sage: next(v_gen) # the second vertex + A vertex at (1, 0) + sage: next(v_gen) # the third vertex + A vertex at (1, 1) + sage: try: next(v_gen) # there are only three vertices + ....: except StopIteration: print("STOP") + STOP + sage: type(v_gen) + <... 'generator'> + sage: [ v for v in triangle.vertex_generator() ] + [A vertex at (0, 1), A vertex at (1, 0), A vertex at (1, 1)] + """ + for V in self.Vrepresentation(): + if V.is_vertex(): + yield V + + @cached_method + def vertices(self): + """ + Return all vertices of the polyhedron. + + OUTPUT: + + A tuple of vertices. + + .. WARNING:: + + If the polyhedron has lines, return the vertices + of the ``Vrepresentation``. However, the represented polyhedron + has no 0-dimensional faces (i.e. vertices):: + + sage: P = Polyhedron(rays=[[1,0,0]],lines=[[0,1,0]]) + sage: P.vertices() + (A vertex at (0, 0, 0),) + sage: P.faces(0) + () + + EXAMPLES:: + + sage: triangle = Polyhedron(vertices=[[1,0],[0,1],[1,1]]) + sage: triangle.vertices() + (A vertex at (0, 1), A vertex at (1, 0), A vertex at (1, 1)) + sage: a_simplex = Polyhedron(ieqs = [ + ....: [0,1,0,0,0],[0,0,1,0,0],[0,0,0,1,0],[0,0,0,0,1] + ....: ], eqns = [[1,-1,-1,-1,-1]]) + sage: a_simplex.vertices() + (A vertex at (1, 0, 0, 0), A vertex at (0, 1, 0, 0), + A vertex at (0, 0, 1, 0), A vertex at (0, 0, 0, 1)) + """ + return tuple(self.vertex_generator()) + + def ray_generator(self): + """ + Return a generator for the rays of the polyhedron. + + EXAMPLES:: + + sage: pi = Polyhedron(ieqs = [[1,1,0],[1,0,1]]) + sage: pir = pi.ray_generator() + sage: [x.vector() for x in pir] + [(1, 0), (0, 1)] + """ + for V in self.Vrepresentation(): + if V.is_ray(): + yield V + + @cached_method + def rays(self): + """ + Return a list of rays of the polyhedron. + + OUTPUT: + + A tuple of rays. + + EXAMPLES:: + + sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0],[1,1,0,0]]) + sage: p.rays() + (A ray in the direction (1, 0, 0), + A ray in the direction (0, 1, 0), + A ray in the direction (0, 0, 1)) + """ + return tuple(self.ray_generator()) + + def rays_list(self): + """ + Return a list of rays as coefficient lists. + + .. NOTE:: + + It is recommended to use :meth:`rays` or + :meth:`ray_generator` instead to iterate over the list of + :class:`Ray` objects. + + OUTPUT: + + A list of rays as lists of coordinates. + + EXAMPLES:: + + sage: p = Polyhedron(ieqs = [[0,0,0,1],[0,0,1,0],[1,1,0,0]]) + sage: p.rays_list() + [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + sage: p.rays_list() == [list(r) for r in p.ray_generator()] + True + """ + return [list(x) for x in self.ray_generator()] + + def line_generator(self): + """ + Return a generator for the lines of the polyhedron. + + EXAMPLES:: + + sage: pr = Polyhedron(rays = [[1,0],[-1,0],[0,1]], vertices = [[-1,-1]]) + sage: next(pr.line_generator()).vector() + (1, 0) + """ + for V in self.Vrepresentation(): + if V.is_line(): + yield V + + @cached_method + def lines(self): + """ + Return all lines of the polyhedron. + + OUTPUT: + + A tuple of lines. + + EXAMPLES:: + + sage: p = Polyhedron(rays = [[1,0],[-1,0],[0,1],[1,1]], vertices = [[-2,-2],[2,3]]) + sage: p.lines() + (A line in the direction (1, 0),) + """ + return tuple(self.line_generator()) + + def lines_list(self): + """ + Return a list of lines of the polyhedron. The line data is given + as a list of coordinates rather than as a Hrepresentation object. + + .. NOTE:: + + It is recommended to use :meth:`line_generator` instead to + iterate over the list of :class:`Line` objects. + + EXAMPLES:: + + sage: p = Polyhedron(rays = [[1,0],[-1,0],[0,1],[1,1]], vertices = [[-2,-2],[2,3]]) + sage: p.lines_list() + [[1, 0]] + sage: p.lines_list() == [list(x) for x in p.line_generator()] + True + """ + return [list(x) for x in self.line_generator()] + + def base_ring(self): + """ + Return the base ring. + + OUTPUT: + + The ring over which the polyhedron is defined. Must be a + sub-ring of the reals to define a polyhedron, in particular + comparison must be defined. Popular choices are + + * ``ZZ`` (the ring of integers, lattice polytope), + + * ``QQ`` (exact arithmetic using gmp), + + * ``RDF`` (double precision floating-point arithmetic), or + + * ``AA`` (real algebraic field). + + EXAMPLES:: + + sage: triangle = Polyhedron(vertices = [[1,0],[0,1],[1,1]]) + sage: triangle.base_ring() == ZZ + True + """ + return self.parent().base_ring() + + def backend(self): + """ + Return the backend used. + + OUTPUT: + + The name of the backend used for computations. It will be one of + the following backends: + + * ``ppl`` the Parma Polyhedra Library + + * ``cdd`` CDD + + * ``normaliz`` normaliz + + * ``polymake`` polymake + + * ``field`` a generic Sage implementation + + EXAMPLES:: + + sage: triangle = Polyhedron(vertices = [[1, 0], [0, 1], [1, 1]]) + sage: triangle.backend() + 'ppl' + sage: D = polytopes.dodecahedron() + sage: D.backend() + 'field' + sage: P = Polyhedron([[1.23]]) + sage: P.backend() + 'cdd' + """ + return self.parent().backend() diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py new file mode 100644 index 00000000000..d580cb8924e --- /dev/null +++ b/src/sage/geometry/polyhedron/base1.py @@ -0,0 +1,802 @@ +r""" +Base class for polyhedra, part 1 + +Define methods that exist for convex sets, +but not constructions such as dilation or product. +""" + +# **************************************************************************** +# Copyright (C) 2008-2012 Marshall Hampton +# Copyright (C) 2011-2015 Volker Braun +# Copyright (C) 2012-2018 Frederic Chapoton +# Copyright (C) 2013 Andrey Novoseltsev +# Copyright (C) 2014-2017 Moritz Firsching +# Copyright (C) 2014-2019 Thierry Monteil +# Copyright (C) 2015 Nathann Cohen +# Copyright (C) 2015-2017 Jeroen Demeyer +# Copyright (C) 2015-2017 Vincent Delecroix +# Copyright (C) 2015-2018 Dima Pasechnik +# Copyright (C) 2015-2020 Jean-Philippe Labbe +# Copyright (C) 2015-2021 Matthias Koeppe +# Copyright (C) 2016-2019 Daniel Krenn +# Copyright (C) 2017 Marcelo Forets +# Copyright (C) 2017-2018 Mark Bell +# Copyright (C) 2019 Julian Ritter +# Copyright (C) 2019-2020 Laith Rastanawi +# Copyright (C) 2019-2020 Sophia Elia +# Copyright (C) 2019-2021 Jonathan Kliem +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.modules.free_module_element import vector +from .base0 import Polyhedron_base0 +from sage.geometry.convex_set import ConvexSet_closed +from sage.geometry.relative_interior import RelativeInterior + + +class Polyhedron_base1(Polyhedron_base0, ConvexSet_closed): + """ + Convex set methods for polyhedra, + but not constructions such as dilation or product. + + See :class:`sage.geometry.polyhedron.base.Polyhedron_base`. + + TESTS:: + + sage: from sage.geometry.polyhedron.base1 import Polyhedron_base1 + sage: P = polytopes.cube() + sage: Q = polytopes.cube() + sage: Polyhedron_base1.__hash__(P) == Polyhedron_base1.__hash__(Q) + True + sage: Polyhedron_base1.__repr__(P) + 'A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices' + sage: Polyhedron_base1.is_empty(P) + False + sage: Polyhedron_base1.is_universe(P) + False + sage: Polyhedron_base1.dim(P) + 3 + sage: Polyhedron_base1.ambient_vector_space(P) + Vector space of dimension 3 over Rational Field + sage: Polyhedron_base1.ambient_dim(P) + 3 + sage: Polyhedron_base1.an_affine_basis(P) + [A vertex at (-1, -1, -1), + A vertex at (1, -1, -1), + A vertex at (1, -1, 1), + A vertex at (1, 1, -1)] + sage: list(Polyhedron_base1._some_elements_(P)) + [(0, 0, 0), + (1, -1, -1), + (1, 0, -1), + (1, 1/2, 0), + (1, -1/4, 1/2), + (0, -5/8, 3/4)] + sage: Polyhedron_base1.contains(P, vector([1, 1, 1])) + True + sage: Polyhedron_base1.interior_contains(P, vector([1, 1, 1])) + False + sage: Polyhedron_base1.is_relatively_open(P) + False + sage: Polyhedron_base1.relative_interior.f(P) == Polyhedron_base1.interior.f(P) + True + """ + + def __hash__(self): + r""" + TESTS:: + + sage: K. = QuadraticField(2) + sage: p = Polyhedron(vertices=[(0,1,a),(3,a,5)], + ....: rays=[(a,2,3), (0,0,1)], + ....: base_ring=K) + sage: q = Polyhedron(vertices=[(3,a,5),(0,1,a)], + ....: rays=[(0,0,1), (a,2,3)], + ....: base_ring=K) + sage: hash(p) == hash(q) + True + """ + # TODO: find something better *but* fast + return hash((self.dim(), + self.ambient_dim(), + self.n_Hrepresentation(), + self.n_Vrepresentation(), + self.n_equations(), + self.n_facets(), + self.n_inequalities(), + self.n_lines(), + self.n_rays(), + self.n_vertices())) + + def _repr_(self): + """ + Return a description of the polyhedron. + + EXAMPLES:: + + sage: poly_test = Polyhedron(vertices = [[1,2,3,4],[2,1,3,4],[4,3,2,1]]) + sage: poly_test._repr_() + 'A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 3 vertices' + sage: grammar_test = Polyhedron(vertices = [[1,1,1,1,1,1]]) + sage: grammar_test._repr_() + 'A 0-dimensional polyhedron in ZZ^6 defined as the convex hull of 1 vertex' + """ + desc = '' + if self.n_vertices() == 0: + desc += 'The empty polyhedron' + else: + desc += 'A ' + repr(self.dim()) + '-dimensional polyhedron' + desc += ' in ' + desc += self.parent()._repr_ambient_module() + + if self.n_vertices() > 0: + desc += ' defined as the convex hull of ' + desc += repr(self.n_vertices()) + if self.n_vertices() == 1: + desc += ' vertex' + else: + desc += ' vertices' + + if self.n_rays() > 0: + if self.n_lines() > 0: + desc += ", " + else: + desc += " and " + desc += repr(self.n_rays()) + if self.n_rays() == 1: + desc += ' ray' + else: + desc += ' rays' + + if self.n_lines() > 0: + if self.n_rays() > 0: + desc += ", " + else: + desc += " and " + desc += repr(self.n_lines()) + if self.n_lines() == 1: + desc += ' line' + else: + desc += ' lines' + + return desc + + def is_empty(self): + """ + Test whether the polyhedron is the empty polyhedron + + OUTPUT: + + Boolean. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]); P + A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices + sage: P.is_empty(), P.is_universe() + (False, False) + + sage: Q = Polyhedron(vertices=()); Q + The empty polyhedron in ZZ^0 + sage: Q.is_empty(), Q.is_universe() + (True, False) + + sage: R = Polyhedron(lines=[(1,0),(0,1)]); R + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 lines + sage: R.is_empty(), R.is_universe() + (False, True) + """ + return self.n_Vrepresentation() == 0 + + def is_universe(self): + """ + Test whether the polyhedron is the whole ambient space + + OUTPUT: + + Boolean. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]); P + A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices + sage: P.is_empty(), P.is_universe() + (False, False) + + sage: Q = Polyhedron(vertices=()); Q + The empty polyhedron in ZZ^0 + sage: Q.is_empty(), Q.is_universe() + (True, False) + + sage: R = Polyhedron(lines=[(1,0),(0,1)]); R + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 lines + sage: R.is_empty(), R.is_universe() + (False, True) + """ + return self.n_Hrepresentation() == 0 + + def dim(self): + """ + Return the dimension of the polyhedron. + + OUTPUT: + + -1 if the polyhedron is empty, otherwise a non-negative integer. + + EXAMPLES:: + + sage: simplex = Polyhedron(vertices = [[1,0,0,0],[0,0,0,1],[0,1,0,0],[0,0,1,0]]) + sage: simplex.dim() + 3 + sage: simplex.ambient_dim() + 4 + + The empty set is a special case (:trac:`12193`):: + + sage: P1=Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]) + sage: P2=Polyhedron(vertices=[[2,0,0],[0,2,0],[0,0,2]]) + sage: P12 = P1.intersection(P2) + sage: P12 + The empty polyhedron in ZZ^3 + sage: P12.dim() + -1 + """ + if self.n_Vrepresentation() == 0: + return -1 # the empty set + else: + return self.ambient_dim() - self.n_equations() + + dimension = dim + + def Vrepresentation_space(self): + r""" + Return the ambient free module. + + OUTPUT: + + A free module over the base ring of dimension :meth:`ambient_dim`. + + EXAMPLES:: + + sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) + sage: poly_test.Vrepresentation_space() + Ambient free module of rank 4 over the principal ideal domain Integer Ring + sage: poly_test.ambient_space() is poly_test.Vrepresentation_space() + True + """ + return self.parent().Vrepresentation_space() + + def Hrepresentation_space(self): + r""" + Return the linear space containing the H-representation vectors. + + OUTPUT: + + A free module over the base ring of dimension :meth:`ambient_dim` + 1. + + EXAMPLES:: + + sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) + sage: poly_test.Hrepresentation_space() + Ambient free module of rank 5 over the principal ideal domain Integer Ring + """ + return self.parent().Hrepresentation_space() + + ambient_space = Vrepresentation_space + + def ambient_vector_space(self, base_field=None): + r""" + Return the ambient vector space. + + It is the ambient free module (:meth:`Vrepresentation_space`) tensored + with a field. + + INPUT: + + - ``base_field`` -- (default: the fraction field of the base ring) a field. + + EXAMPLES:: + + sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) + sage: poly_test.ambient_vector_space() + Vector space of dimension 4 over Rational Field + sage: poly_test.ambient_vector_space() is poly_test.ambient() + True + + sage: poly_test.ambient_vector_space(AA) + Vector space of dimension 4 over Algebraic Real Field + sage: poly_test.ambient_vector_space(RR) + Vector space of dimension 4 over Real Field with 53 bits of precision + sage: poly_test.ambient_vector_space(SR) + Vector space of dimension 4 over Symbolic Ring + """ + return self.Vrepresentation_space().vector_space(base_field=base_field) + + ambient = ambient_vector_space + + def ambient_dim(self): + r""" + Return the dimension of the ambient space. + + EXAMPLES:: + + sage: poly_test = Polyhedron(vertices = [[1,0,0,0],[0,1,0,0]]) + sage: poly_test.ambient_dim() + 4 + """ + return self.parent().ambient_dim() + + def an_affine_basis(self): + """ + Return points in ``self`` that are a basis for the affine span of the polytope. + + This implementation of the method :meth:`ConvexSet_base.an_affine_basis` + for polytopes guarantees the following: + + - All points are vertices. + + - The basis is obtained by considering a maximal chain of faces + in the face lattice and picking for each cover relation + one vertex that is in the difference. Thus this method + is independent of the concrete realization of the polytope. + + EXAMPLES:: + + sage: P = polytopes.cube() + sage: P.an_affine_basis() + [A vertex at (-1, -1, -1), + A vertex at (1, -1, -1), + A vertex at (1, -1, 1), + A vertex at (1, 1, -1)] + + sage: P = polytopes.permutahedron(5) + sage: P.an_affine_basis() + [A vertex at (1, 2, 3, 5, 4), + A vertex at (2, 1, 3, 5, 4), + A vertex at (1, 3, 2, 5, 4), + A vertex at (4, 1, 3, 5, 2), + A vertex at (4, 2, 5, 3, 1)] + + The method is not implemented for unbounded polyhedra:: + + sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)]) + sage: p.an_affine_basis() + Traceback (most recent call last): + ... + NotImplementedError: this function is not implemented for unbounded polyhedra + """ + if not self.is_compact(): + raise NotImplementedError("this function is not implemented for unbounded polyhedra") + + chain = self.a_maximal_chain()[1:] # we exclude the empty face + chain_indices = [face.ambient_V_indices() for face in chain] + basis_indices = [] + + # We use in the following that elements in ``chain_indices`` are sorted lists + # of V-indices. + # Thus for each two faces we can easily find the first vertex that differs. + for dim, face in enumerate(chain_indices): + if dim == 0: + # Append the vertex. + basis_indices.append(face[0]) + continue + + prev_face = chain_indices[dim-1] + for i in range(len(prev_face)): + if prev_face[i] != face[i]: + # We found a vertex that ``face`` has, but its facet does not. + basis_indices.append(face[i]) + break + else: # no break + # ``prev_face`` contains all the same vertices as ``face`` until now. + # But ``face`` is guaranteed to contain one more vertex (at least). + basis_indices.append(face[len(prev_face)]) + + return [self.Vrepresentation()[i] for i in basis_indices] + + @abstract_method + def a_maximal_chain(self): + r""" + Return a maximal chain of the face lattice in increasing order. + + Subclasses must provide an implementation of this method. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.base1 import Polyhedron_base1 + sage: P = polytopes.cube() + sage: Polyhedron_base1.a_maximal_chain + + """ + + @cached_method + def representative_point(self): + """ + Return a "generic" point. + + .. SEEALSO:: + + :meth:`center`. + + OUTPUT: + + A point as a coordinate vector. The point is chosen to be + interior if possible. If the polyhedron is not + full-dimensional, the point is in the relative interior. If + the polyhedron is zero-dimensional, its single point is + returned. + + EXAMPLES:: + + sage: p = Polyhedron(vertices=[(3,2)], rays=[(1,-1)]) + sage: p.representative_point() + (4, 1) + sage: p.center() + (3, 2) + + sage: Polyhedron(vertices=[(3,2)]).representative_point() + (3, 2) + """ + accumulator = vector(self.base_ring(), [0]*self.ambient_dim()) + for v in self.vertex_generator(): + accumulator += v.vector() + accumulator /= self.n_vertices() + for r in self.ray_generator(): + accumulator += r.vector() + accumulator.set_immutable() + return accumulator + + def _some_elements_(self): + r""" + Generate some points of ``self``. + + If ``self`` is empty, no points are generated; no exception will be raised. + + EXAMPLES:: + + sage: P = polytopes.simplex() + sage: P.an_element() # indirect doctest + (1/4, 1/4, 1/4, 1/4) + sage: P.some_elements() # indirect doctest + [(1/4, 1/4, 1/4, 1/4), + (0, 0, 0, 1), + (0, 0, 1/2, 1/2), + (0, 1/2, 1/4, 1/4), + (1/2, 1/4, 1/8, 1/8)] + """ + if self.is_empty(): + return + yield self.representative_point() + vertex_iter = iter(self.vertex_generator()) + try: + p = next(vertex_iter).vector() + yield vector(p, immutable=True) + for i in range(4): + p = (p + next(vertex_iter).vector()) / 2 + yield vector(p, immutable=True) + except StopIteration: + pass + + def contains(self, point): + """ + Test whether the polyhedron contains the given ``point``. + + .. SEEALSO:: + + :meth:`interior_contains`, :meth:`relative_interior_contains`. + + INPUT: + + - ``point`` -- coordinates of a point (an iterable) + + OUTPUT: + + Boolean. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[[1,1],[1,-1],[0,0]]) + sage: P.contains( [1,0] ) + True + sage: P.contains( P.center() ) # true for any convex set + True + + As a shorthand, one may use the usual ``in`` operator:: + + sage: P.center() in P + True + sage: [-1,-1] in P + False + + The point need not have coordinates in the same field as the + polyhedron:: + + sage: ray = Polyhedron(vertices=[(0,0)], rays=[(1,0)], base_ring=QQ) + sage: ray.contains([sqrt(2)/3,0]) # irrational coordinates are ok + True + sage: a = var('a') + sage: ray.contains([a,0]) # a might be negative! + False + sage: assume(a>0) + sage: ray.contains([a,0]) + True + sage: ray.contains(['hello', 'kitty']) # no common ring for coordinates + False + + The empty polyhedron needs extra care, see :trac:`10238`:: + + sage: empty = Polyhedron(); empty + The empty polyhedron in ZZ^0 + sage: empty.contains([]) + False + sage: empty.contains([0]) # not a point in QQ^0 + False + sage: full = Polyhedron(vertices=[()]); full + A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex + sage: full.contains([]) + True + sage: full.contains([0]) + False + + TESTS: + + Passing non-iterable objects does not cause an exception, see :trac:`32013`:: + + sage: None in Polyhedron(vertices=[(0,0)], rays=[(1,0)], base_ring=QQ) + False + """ + try: + p = vector(point) + except TypeError: # point not iterable or no common ring for elements + try: + l = len(point) + except TypeError: + return False + if l > 0: + return False + else: + p = vector(self.base_ring(), []) + + if len(p) != self.ambient_dim(): + return False + + for H in self.Hrep_generator(): + if not H.contains(p): + return False + return True + + __contains__ = contains + + @cached_method + def interior(self): + """ + The interior of ``self``. + + OUTPUT: + + - either an empty polyhedron or an instance of + :class:`~sage.geometry.relative_interior.RelativeInterior` + + EXAMPLES: + + If the polyhedron is full-dimensional, the result is the + same as that of :meth:`relative_interior`:: + + sage: P_full = Polyhedron(vertices=[[0,0],[1,1],[1,-1]]) + sage: P_full.interior() + Relative interior of + a 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices + + If the polyhedron is of strictly smaller dimension than the + ambient space, its interior is empty:: + + sage: P_lower = Polyhedron(vertices=[[0,1], [0,-1]]) + sage: P_lower.interior() + The empty polyhedron in ZZ^2 + + TESTS:: + + sage: Empty = Polyhedron(ambient_dim=2); Empty + The empty polyhedron in ZZ^2 + sage: Empty.interior() is Empty + True + """ + if self.is_open(): + return self + if not self.is_full_dimensional(): + return self.parent().element_class(self.parent(), None, None) + return self.relative_interior() + + def interior_contains(self, point): + """ + Test whether the interior of the polyhedron contains the + given ``point``. + + .. SEEALSO:: + + :meth:`contains`, :meth:`relative_interior_contains`. + + INPUT: + + - ``point`` -- coordinates of a point + + OUTPUT: + + ``True`` or ``False``. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[[0,0],[1,1],[1,-1]]) + sage: P.contains( [1,0] ) + True + sage: P.interior_contains( [1,0] ) + False + + If the polyhedron is of strictly smaller dimension than the + ambient space, its interior is empty:: + + sage: P = Polyhedron(vertices=[[0,1],[0,-1]]) + sage: P.contains( [0,0] ) + True + sage: P.interior_contains( [0,0] ) + False + + The empty polyhedron needs extra care, see :trac:`10238`:: + + sage: empty = Polyhedron(); empty + The empty polyhedron in ZZ^0 + sage: empty.interior_contains([]) + False + """ + try: + p = vector(point) + except TypeError: # point not iterable or no common ring for elements + try: + l = len(point) + except TypeError: + return False + if l > 0: + return False + else: + p = vector(self.base_ring(), []) + + if len(p) != self.ambient_dim(): + return False + + for H in self.Hrep_generator(): + if not H.interior_contains(p): + return False + return True + + def is_relatively_open(self): + r""" + Return whether ``self`` is relatively open. + + OUTPUT: + + Boolean. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[(1,0), (-1,0)]); P + A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices + sage: P.is_relatively_open() + False + + sage: P0 = Polyhedron(vertices=[[1, 2]]); P0 + A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex + sage: P0.is_relatively_open() + True + + sage: Empty = Polyhedron(ambient_dim=2); Empty + The empty polyhedron in ZZ^2 + sage: Empty.is_relatively_open() + True + + sage: Line = Polyhedron(vertices=[(1, 1)], lines=[(1, 0)]); Line + A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line + sage: Line.is_relatively_open() + True + + """ + return not self.inequalities() + + @cached_method + def relative_interior(self): + """ + Return the relative interior of ``self``. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[(1,0), (-1,0)]) + sage: ri_P = P.relative_interior(); ri_P + Relative interior of + a 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices + sage: (0, 0) in ri_P + True + sage: (1, 0) in ri_P + False + + sage: P0 = Polyhedron(vertices=[[1, 2]]) + sage: P0.relative_interior() is P0 + True + + sage: Empty = Polyhedron(ambient_dim=2) + sage: Empty.relative_interior() is Empty + True + + sage: Line = Polyhedron(vertices=[(1, 1)], lines=[(1, 0)]) + sage: Line.relative_interior() is Line + True + """ + if self.is_relatively_open(): + return self + return RelativeInterior(self) + + def relative_interior_contains(self, point): + """ + Test whether the relative interior of the polyhedron + contains the given ``point``. + + .. SEEALSO:: + + :meth:`contains`, :meth:`interior_contains`. + + INPUT: + + - ``point`` -- coordinates of a point + + OUTPUT: + + ``True`` or ``False`` + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[(1,0), (-1,0)]) + sage: P.contains( (0,0) ) + True + sage: P.interior_contains( (0,0) ) + False + sage: P.relative_interior_contains( (0,0) ) + True + sage: P.relative_interior_contains( (1,0) ) + False + + The empty polyhedron needs extra care, see :trac:`10238`:: + + sage: empty = Polyhedron(); empty + The empty polyhedron in ZZ^0 + sage: empty.relative_interior_contains([]) + False + """ + try: + p = vector(point) + except TypeError: # point not iterable or no common ring for elements + try: + l = len(point) + except TypeError: + return False + if l > 0: + return False + else: + p = vector(self.base_ring(), []) + + if len(p) != self.ambient_dim(): + return False + + for eq in self.equation_generator(): + if not eq.contains(p): + return False + + for ine in self.inequality_generator(): + if not ine.interior_contains(p): + return False + + return True diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 60f84246df6..ff697423d46 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -50,14 +50,14 @@ Obtaining edges and ridges:: Vertex-graph and facet-graph:: - sage: C.vertex_graph() + sage: C.vertex_graph() # optional - sage.graphs Graph on 16 vertices - sage: C.facet_graph() + sage: C.facet_graph() # optional - sage.graphs Graph on 8 vertices Face lattice:: - sage: C.face_lattice() + sage: C.face_lattice() # optional - sage.combinat Finite lattice containing 82 elements Face iterator:: @@ -2577,20 +2577,20 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.regular_polygon(4).pyramid() - sage: C = CombinatorialPolyhedron(P) - sage: D = C.hasse_diagram(); D + sage: P = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field + sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field + sage: D = C.hasse_diagram(); D # optional - sage.graphs # optional - sage.rings.number_field Digraph on 20 vertices - sage: D.average_degree() + sage: D.average_degree() # optional - sage.graphs # optional - sage.rings.number_field 21/5 - sage: D.relabel(C.face_by_face_lattice_index) - sage: dim_0_vert = D.vertices()[1:6]; dim_0_vert + sage: D.relabel(C.face_by_face_lattice_index) # optional - sage.graphs # optional - sage.rings.number_field + sage: dim_0_vert = D.vertices()[1:6]; dim_0_vert # optional - sage.graphs # optional - sage.rings.number_field [A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: sorted(D.out_degree(vertices=dim_0_vert)) + sage: sorted(D.out_degree(vertices=dim_0_vert)) # optional - sage.graphs # optional - sage.rings.number_field [3, 3, 3, 3, 4] """ if not self._face_lattice_incidences: @@ -2628,12 +2628,12 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() + sage: F = C.face_lattice() # optional - sage.combinat sage: def f(i): ....: return (i, C._face_lattice_dimension(i)) ....: - sage: G = F.relabel(f) - sage: set(G._elements) + sage: G = F.relabel(f) # optional - sage.combinat + sage: set(G._elements) # optional - sage.combinat {(0, -1), (1, 0), (2, 0), @@ -2684,13 +2684,13 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() - sage: F + sage: F = C.face_lattice() # optional - sage.combinat + sage: F # optional - sage.combinat Finite lattice containing 28 elements - sage: G = F.relabel(C.face_by_face_lattice_index) - sage: G.level_sets()[0] + sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat + sage: G.level_sets()[0] # optional - sage.combinat [A -1-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: G.level_sets()[3] + sage: G.level_sets()[3] # optional - sage.combinat [A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, @@ -2700,9 +2700,9 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = Polyhedron(rays=[[0,1], [1,0]]) sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() - sage: G = F.relabel(C.face_by_face_lattice_index) - sage: G._elements + sage: F = C.face_lattice() # optional - sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat + sage: G._elements # optional - sage.combinat (A -1-dimensional face of a 2-dimensional combinatorial polyhedron, A 0-dimensional face of a 2-dimensional combinatorial polyhedron, A 1-dimensional face of a 2-dimensional combinatorial polyhedron, @@ -2710,8 +2710,8 @@ cdef class CombinatorialPolyhedron(SageObject): A 2-dimensional face of a 2-dimensional combinatorial polyhedron) sage: def f(i): return C.face_by_face_lattice_index(i).ambient_V_indices() - sage: G = F.relabel(f) - sage: G._elements + sage: G = F.relabel(f) # optional - sage.combinat + sage: G._elements # optional - sage.combinat ((), (0,), (0, 1), (0, 2), (0, 1, 2)) """ self._record_all_faces() # Initialize ``_all_faces``, if not done yet. @@ -3058,7 +3058,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: D.f_vector() (1, 6, 12, 8, 1) sage: D1 = P.polar().combinatorial_polyhedron() - sage: D1.face_lattice().is_isomorphic(D.face_lattice()) + sage: D1.face_lattice().is_isomorphic(D.face_lattice()) # optional - sage.combinat True Polar is an alias to be consistent with :class:`~sage.geometry.polyhedron.base.Polyhedron_base`:: @@ -3108,7 +3108,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: C1 = C.pyramid() sage: P1 = P.pyramid() sage: C2 = P1.combinatorial_polyhedron() - sage: C2.vertex_facet_graph().is_isomorphic(C1.vertex_facet_graph()) + sage: C2.vertex_facet_graph().is_isomorphic(C1.vertex_facet_graph()) # optional - sage.combinat True One can specify a name for the new vertex:: @@ -3127,10 +3127,10 @@ cdef class CombinatorialPolyhedron(SageObject): One can specify a name for the new facets:: - sage: P = polytopes.regular_polygon(4) - sage: C = P.combinatorial_polyhedron() - sage: C1 = C.pyramid(new_facet='base') - sage: C1.Hrepresentation() + sage: P = polytopes.regular_polygon(4) # optional - sage.rings.number_field + sage: C = P.combinatorial_polyhedron() # optional - sage.rings.number_field + sage: C1 = C.pyramid(new_facet='base') # optional - sage.rings.number_field + sage: C1.Hrepresentation() # optional - sage.rings.number_field (An inequality (-1/2, 1/2) x + 1/2 >= 0, An inequality (-1/2, -1/2) x + 1/2 >= 0, An inequality (1/2, 0.50000000000000000?) x + 1/2 >= 0, diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 91d8878cfb4..2f300cebfc1 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -22,9 +22,9 @@ Obtain a face from a face lattice index: sage: P = polytopes.simplex(2) sage: C = CombinatorialPolyhedron(P) - sage: sorted(C.face_lattice()._elements) + sage: sorted(C.face_lattice()._elements) # optional - sage.combinat [0, 1, 2, 3, 4, 5, 6, 7] - sage: face = C.face_by_face_lattice_index(0); face + sage: face = C.face_by_face_lattice_index(0); face # optional - sage.combinat A -1-dimensional face of a 2-dimensional combinatorial polyhedron Obtain further information regarding a face:: @@ -95,8 +95,8 @@ cdef class CombinatorialFace(SageObject): Obtain a combinatorial face from an index of the face lattice:: - sage: F = C.face_lattice() - sage: F._elements[3] + sage: F = C.face_lattice() # optional - sage.combinat + sage: F._elements[3] # optional - sage.combinat 34 sage: C.face_by_face_lattice_index(29) A 1-dimensional face of a 5-dimensional combinatorial polyhedron @@ -242,15 +242,15 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(6) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(dimension=3, dual=False) - sage: face = next(it) - sage: face.__repr__() + sage: P = polytopes.permutahedron(6) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter(dimension=3, dual=False) # optional - sage.combinat + sage: face = next(it) # optional - sage.combinat + sage: face.__repr__() # optional - sage.combinat 'A 3-dimensional face of a 5-dimensional combinatorial polyhedron' - sage: it = C.face_iter(dimension=3, dual=True) - sage: face = next(it) - sage: face.__repr__() + sage: it = C.face_iter(dimension=3, dual=True) # optional - sage.combinat + sage: face = next(it) # optional - sage.combinat + sage: face.__repr__() # optional - sage.combinat 'A 3-dimensional face of a 5-dimensional combinatorial polyhedron' """ return "A {}-dimensional face of a {}-dimensional combinatorial polyhedron"\ @@ -300,15 +300,15 @@ cdef class CombinatorialFace(SageObject): TESTS:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() - sage: G = F.relabel(C.face_by_face_lattice_index) + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: F = C.face_lattice() # optional - sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat sage: P = polytopes.cyclic_polytope(4,10) sage: C = CombinatorialPolyhedron(P) - sage: F = C.face_lattice() - sage: G = F.relabel(C.face_by_face_lattice_index) + sage: F = C.face_lattice() # optional - sage.combinat + sage: G = F.relabel(C.face_by_face_lattice_index) # optional - sage.combinat """ return self._hash_index @@ -331,7 +331,7 @@ cdef class CombinatorialFace(SageObject): sage: F2 = C.face_by_face_lattice_index(1) sage: F1 < F2 True - sage: for i,j in Combinations(range(28), 2): + sage: for i,j in Combinations(range(28), 2): # optional - sage.combinat ....: F1 = C.face_by_face_lattice_index(i) ....: F2 = C.face_by_face_lattice_index(j) ....: if F1.dim() != F2.dim(): @@ -343,7 +343,7 @@ cdef class CombinatorialFace(SageObject): sage: F2 = C.face_by_face_lattice_index(1) sage: F1 < F2 True - sage: for i,j in Combinations(range(28), 2): + sage: for i,j in Combinations(range(28), 2): # optional - sage.combinat ....: F1 = C.face_by_face_lattice_index(i) ....: F2 = C.face_by_face_lattice_index(j) ....: if F1.dim() != F2.dim(): @@ -416,7 +416,7 @@ cdef class CombinatorialFace(SageObject): sage: v5.is_subface(face2) True - Only implemented for faces of the same combintatorial polyhedron:: + Only implemented for faces of the same combinatorial polyhedron:: sage: P1 = polytopes.cube() sage: C1 = P1.combinatorial_polyhedron() @@ -483,16 +483,16 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.associahedron(['A', 3]) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter() - sage: face = next(it) - sage: face.dimension() + sage: P = polytopes.associahedron(['A', 3]) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter() # optional - sage.combinat + sage: face = next(it) # optional - sage.combinat + sage: face.dimension() # optional - sage.combinat 2 ``dim`` is an alias:: - sage: face.dim() + sage: face.dim() # optional - sage.combinat 2 """ if self._dual: @@ -527,19 +527,19 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(dimension=2) - sage: face = next(it) - sage: face.ambient_Vrepresentation() + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter(dimension=2) # optional - sage.combinat + sage: face = next(it) # optional - sage.combinat + sage: face.ambient_Vrepresentation() # optional - sage.combinat (A vertex at (1, 3, 2, 5, 4), A vertex at (2, 3, 1, 5, 4), A vertex at (3, 1, 2, 5, 4), A vertex at (3, 2, 1, 5, 4), A vertex at (2, 1, 3, 5, 4), A vertex at (1, 2, 3, 5, 4)) - sage: face = next(it) - sage: face.ambient_Vrepresentation() + sage: face = next(it) # optional - sage.combinat + sage: face.ambient_Vrepresentation() # optional - sage.combinat (A vertex at (2, 1, 4, 5, 3), A vertex at (3, 2, 4, 5, 1), A vertex at (3, 1, 4, 5, 2), @@ -591,13 +591,13 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(dimension=2) - sage: face = next(it) - sage: next(it).ambient_V_indices() + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter(dimension=2) # optional - sage.combinat + sage: face = next(it) # optional - sage.combinat + sage: next(it).ambient_V_indices() # optional - sage.combinat (32, 91, 92, 93, 94, 95) - sage: next(it).ambient_V_indices() + sage: next(it).ambient_V_indices() # optional - sage.combinat (32, 89, 90, 94) sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3],[0,2,3],[1,2,3]]) @@ -677,7 +677,7 @@ cdef class CombinatorialFace(SageObject): r""" Return the length of the :meth:`CombinatorialFace.ambient_V_indices`. - Might be faster than then using ``len``. + Might be faster than using ``len``. EXAMPLES:: @@ -714,14 +714,14 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(2) - sage: next(it).ambient_Hrepresentation() + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter(2) # optional - sage.combinat + sage: next(it).ambient_Hrepresentation() # optional - sage.combinat (An inequality (1, 1, 1, 0, 0) x - 6 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) - sage: next(it).ambient_Hrepresentation() + sage: next(it).ambient_Hrepresentation() # optional - sage.combinat (An inequality (0, 0, -1, -1, 0) x + 9 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) @@ -774,21 +774,21 @@ cdef class CombinatorialFace(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(2) - sage: face = next(it) - sage: face.ambient_H_indices(add_equations=False) + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter(2) # optional - sage.combinat + sage: face = next(it) # optional - sage.combinat + sage: face.ambient_H_indices(add_equations=False) # optional - sage.combinat (28, 29) - sage: face2 = next(it) - sage: face2.ambient_H_indices(add_equations=False) + sage: face2 = next(it) # optional - sage.combinat + sage: face2.ambient_H_indices(add_equations=False) # optional - sage.combinat (25, 29) Add the indices of the equation:: - sage: face.ambient_H_indices(add_equations=True) + sage: face.ambient_H_indices(add_equations=True) # optional - sage.combinat (28, 29, 30) - sage: face2.ambient_H_indices(add_equations=True) + sage: face2.ambient_H_indices(add_equations=True) # optional - sage.combinat (25, 29, 30) Another example:: @@ -894,13 +894,13 @@ cdef class CombinatorialFace(SageObject): Specifying whether to count the equations or not:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(2) - sage: f = next(it) - sage: f.n_ambient_Hrepresentation(add_equations=True) + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter(2) # optional - sage.combinat + sage: f = next(it) # optional - sage.combinat + sage: f.n_ambient_Hrepresentation(add_equations=True) # optional - sage.combinat 3 - sage: f.n_ambient_Hrepresentation(add_equations=False) + sage: f.n_ambient_Hrepresentation(add_equations=False) # optional - sage.combinat 2 TESTS:: @@ -948,7 +948,7 @@ cdef class CombinatorialFace(SageObject): sage: F.f_vector() (1, 5, 10, 10, 5, 1) sage: F_alt = polytopes.cyclic_polytope(4,5).combinatorial_polyhedron() - sage: F_alt.vertex_facet_graph().is_isomorphic(F.vertex_facet_graph()) + sage: F_alt.vertex_facet_graph().is_isomorphic(F.vertex_facet_graph()) # optional - sage.graphs True Obtaining the quotient:: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 6b7f436e956..8cdedf29ca6 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -207,13 +207,13 @@ cdef class FaceIterator_base(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(4) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter() # indirect doctest + sage: P = polytopes.permutahedron(4) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter() # indirect doctest # optional - sage.combinat sage: f_vector = [1, 0, 0, 0, 1] - sage: for face in it: f_vector[face.dimension()+1] += 1 - sage: print ('f_vector of permutahedron(4): ', f_vector) + sage: for face in it: f_vector[face.dimension()+1] += 1 # optional - sage.combinat + sage: print ('f_vector of permutahedron(4): ', f_vector) # optional - sage.combinat f_vector of permutahedron(4): [1, 24, 36, 14, 1] sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator.FaceIterator).run() @@ -601,17 +601,17 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() - sage: it = P.face_generator() - sage: _ = next(it), next(it) - sage: next(it).ambient_V_indices() + sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: it = P.face_generator() # optional - sage.rings.number_field + sage: _ = next(it), next(it) # optional - sage.rings.number_field + sage: next(it).ambient_V_indices() # optional - sage.rings.number_field (15, 16, 17, 18, 19) - sage: it.meet_of_Hrep(9,11) + sage: it.meet_of_Hrep(9,11) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() - sage: it.meet_of_Hrep(9,11).ambient_H_indices() + sage: it.reset() # optional - sage.rings.number_field + sage: it.meet_of_Hrep(9,11).ambient_H_indices() # optional - sage.rings.number_field (9, 11) TESTS: @@ -686,17 +686,17 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() - sage: it = P.face_generator() - sage: _ = next(it), next(it) - sage: next(it).ambient_V_indices() + sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: it = P.face_generator() # optional - sage.rings.number_field + sage: _ = next(it), next(it) # optional - sage.rings.number_field + sage: next(it).ambient_V_indices() # optional - sage.rings.number_field (15, 16, 17, 18, 19) - sage: it.join_of_Vrep(1,10) + sage: it.join_of_Vrep(1,10) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() - sage: it.join_of_Vrep(1,10).ambient_V_indices() + sage: it.reset() # optional - sage.rings.number_field + sage: it.join_of_Vrep(1,10).ambient_V_indices() # optional - sage.rings.number_field (1, 10) In the case of an unbounded polyhedron, we try to make sense of the input:: @@ -810,9 +810,9 @@ cdef class FaceIterator_base(SageObject): The face iterator must not have the output dimension specified:: - sage: P = polytopes.dodecahedron() - sage: it = P.face_generator(2) - sage: it._meet_of_coatoms(1,2) + sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: it = P.face_generator(2) # optional - sage.rings.number_field + sage: it._meet_of_coatoms(1,2) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: face iterator must not have the output dimension specified @@ -919,24 +919,24 @@ cdef class FaceIterator_base(SageObject): If the iterator has already been used, it must be reset before:: - sage: P = polytopes.dodecahedron() - sage: it = P.face_generator() - sage: _ = next(it), next(it) - sage: next(it).ambient_V_indices() + sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: it = P.face_generator() # optional - sage.rings.number_field + sage: _ = next(it), next(it) # optional - sage.rings.number_field + sage: next(it).ambient_V_indices() # optional - sage.rings.number_field (15, 16, 17, 18, 19) - sage: it._join_of_atoms(1,10) + sage: it._join_of_atoms(1,10) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: please reset the face iterator - sage: it.reset() - sage: it._join_of_atoms(1,10).ambient_V_indices() + sage: it.reset() # optional - sage.rings.number_field + sage: it._join_of_atoms(1,10).ambient_V_indices() # optional - sage.rings.number_field (1, 10) The face iterator must not have the output dimension specified:: - sage: P = polytopes.dodecahedron() - sage: it = P.face_generator(2) - sage: it._join_of_atoms(1,2) + sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: it = P.face_generator(2) # optional - sage.rings.number_field + sage: it._join_of_atoms(1,2) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: face iterator must not have the output dimension specified @@ -1530,12 +1530,12 @@ cdef class FaceIterator(FaceIterator_base): r""" EXAMPLES:: - sage: P = polytopes.associahedron(['A',3]) - sage: C = CombinatorialPolyhedron(P) - sage: C.face_iter() + sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.face_iter() # optional - sage.combinat Iterator over the proper faces of a 3-dimensional combinatorial polyhedron - sage: C.face_iter(1) + sage: C.face_iter(1) # optional - sage.combinat Iterator over the 1-faces of a 3-dimensional combinatorial polyhedron """ if self.structure.output_dimension != -2: @@ -1813,11 +1813,11 @@ cdef class FaceIterator_geom(FaceIterator_base): r""" EXAMPLES:: - sage: P = polytopes.associahedron(['A',3]) - sage: P.face_generator() + sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat + sage: P.face_generator() # optional - sage.combinat Iterator over the faces of a 3-dimensional polyhedron in QQ^3 - sage: P.face_generator(1) + sage: P.face_generator(1) # optional - sage.combinat Iterator over the 1-faces of a 3-dimensional polyhedron in QQ^3 """ if self._requested_dim is not None: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index 5ea9711090d..a7794cb315c 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -41,9 +41,9 @@ Obtain the Vrepresentation of a polyhedron as facet-incidences:: sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \ ....: import incidence_matrix_to_bit_rep_of_Vrep - sage: P = polytopes.associahedron(['A',3]) - sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) - sage: face_list.compute_dimension() + sage: P = polytopes.associahedron(['A',3]) # optional - sage.combinat + sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) # optional - sage.combinat + sage: face_list.compute_dimension() # optional - sage.combinat 3 Obtain the facets of a polyhedron as :class:`ListOfFaces` from a facet list:: diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 31cec880ccf..d1f6e7333b0 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -2522,7 +2522,7 @@ def permutahedron(self, n, project=False, backend=None): sage: perm4 = polytopes.permutahedron(4, project=True) sage: perm4 A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 vertices - sage: perm4.plot() + sage: perm4.plot() # optional - sage.plot Graphics3d Object sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) True @@ -3305,7 +3305,7 @@ def cube(self, intervals=None, backend=None): (1, 8, 12, 6, 1) sage: c.volume() 8 - sage: c.plot() + sage: c.plot() # optional - sage.plot Graphics3d Object Return the `0/1`-cube:: diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 8ac51827d61..2ff20fe5a8e 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -584,7 +584,7 @@ def _element_constructor_(self, *args, **kwds): sage: lp.set_objective(x[0] + x[1]) sage: b = lp.get_backend() sage: P = b.interactive_lp_problem() - sage: p = P.plot() + sage: p = P.plot() # optional - sage.plot sage: Q = Polyhedron(ieqs=[[-499999, 1000000], [1499999, -1000000]]) sage: P = Polyhedron(ieqs=[[0, 1.0], [1.0, -1.0]], base_ring=RDF) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 9a6a759eb93..803023bc2db 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -348,12 +348,12 @@ def __init__(self, polyhedron, proj=projection_func_identity): The projection of a polyhedron into 2 dimensions sage: Projection(p, lambda x: [x[1],x[2]] ) # another way of doing the same projection The projection of a polyhedron into 2 dimensions - sage: _.plot() # plot of the projected icosahedron in 2d + sage: _.plot() # plot of the projected icosahedron in 2d # optional - sage.plot Graphics object consisting of 51 graphics primitives sage: proj = Projection(p) sage: proj.stereographic([1,2,3]) The projection of a polyhedron into 2 dimensions - sage: proj.plot() + sage: proj.plot() # optional - sage.plot Graphics object consisting of 51 graphics primitives sage: TestSuite(proj).run(skip='_test_pickling') """ @@ -452,7 +452,7 @@ def stereographic(self, projection_point=None): sage: proj = Projection(polytopes.buckyball()) #long time sage: proj #long time The projection of a polyhedron into 3 dimensions - sage: proj.stereographic([5,2,3]).plot() #long time + sage: proj.stereographic([5,2,3]).plot() #long time # optional - sage.plot Graphics object consisting of 123 graphics primitives sage: Projection( polytopes.twenty_four_cell() ).stereographic([2,0,0,0]) The projection of a polyhedron into 3 dimensions @@ -489,7 +489,7 @@ def schlegel(self, facet=None, position=None): sage: from sage.geometry.polyhedron.plot import Projection sage: Projection(cube4).schlegel() The projection of a polyhedron into 3 dimensions - sage: _.plot() + sage: _.plot() # optional - sage.plot Graphics3d Object The 4-cube with a truncated vertex seen into the resulting tetrahedron @@ -499,13 +499,13 @@ def schlegel(self, facet=None, position=None): sage: tcube4.facets()[4] A 3-dimensional face of a Polyhedron in QQ^4 defined as the convex hull of 4 vertices sage: into_tetra = Projection(tcube4).schlegel(tcube4.facets()[4]) - sage: into_tetra.plot() + sage: into_tetra.plot() # optional - sage.plot Graphics3d Object Taking a larger value for the position changes the image:: sage: into_tetra_far = Projection(tcube4).schlegel(tcube4.facets()[4],4) - sage: into_tetra_far.plot() + sage: into_tetra_far.plot() # optional - sage.plot Graphics3d Object A value which is too large or negative give a projection point that @@ -881,8 +881,8 @@ def render_points_1d(self, **kwds): sage: cube1 = polytopes.hypercube(1) sage: proj = cube1.projection() - sage: points = proj.render_points_1d() - sage: points._objects + sage: points = proj.render_points_1d() # optional - sage.plot + sage: points._objects # optional - sage.plot [Point set defined by 2 point(s)] """ return point2d([c + [0] for c in self.coordinates_of(self.points)], **kwds) @@ -902,8 +902,8 @@ def render_line_1d(self, **kwds): EXAMPLES:: - sage: outline = polytopes.hypercube(1).projection().render_line_1d() - sage: outline._objects[0] + sage: outline = polytopes.hypercube(1).projection().render_line_1d() # optional - sage.plot + sage: outline._objects[0] # optional - sage.plot Line defined by 2 points """ if len(self.lines) == 0: @@ -922,8 +922,8 @@ def render_points_2d(self, **kwds): sage: hex = polytopes.regular_polygon(6) sage: proj = hex.projection() - sage: hex_points = proj.render_points_2d() - sage: hex_points._objects + sage: hex_points = proj.render_points_2d() # optional - sage.plot + sage: hex_points._objects # optional - sage.plot [Point set defined by 6 point(s)] """ return point2d(self.coordinates_of(self.points), **kwds) @@ -935,8 +935,8 @@ def render_outline_2d(self, **kwds): EXAMPLES:: sage: penta = polytopes.regular_polygon(5) - sage: outline = penta.projection().render_outline_2d() - sage: outline._objects[0] + sage: outline = penta.projection().render_outline_2d() # optional - sage.plot + sage: outline._objects[0] # optional - sage.plot Line defined by 2 points """ wireframe = [] @@ -957,8 +957,8 @@ def render_fill_2d(self, **kwds): sage: cps = [i^3 for i in srange(-2,2,1/5)] sage: p = Polyhedron(vertices = [[(t^2-1)/(t^2+1),2*t/(t^2+1)] for t in cps]) sage: proj = p.projection() - sage: filled_poly = proj.render_fill_2d() - sage: filled_poly.axes_width() + sage: filled_poly = proj.render_fill_2d() # optional - sage.plot + sage: filled_poly.axes_width() # optional - sage.plot 0.8 """ poly = [polygon2d(self.coordinates_of(p), **kwds) @@ -973,8 +973,8 @@ def render_vertices_3d(self, **kwds): sage: p = polytopes.cross_polytope(3) sage: proj = p.projection() - sage: verts = proj.render_vertices_3d() - sage: verts.bounding_box() + sage: verts = proj.render_vertices_3d() # optional - sage.plot + sage: verts.bounding_box() # optional - sage.plot ((-1.0, -1.0, -1.0), (1.0, 1.0, 1.0)) """ return point3d(self.coordinates_of(self.points), **kwds) @@ -987,8 +987,8 @@ def render_wireframe_3d(self, **kwds): sage: cube = polytopes.hypercube(3) sage: cube_proj = cube.projection() - sage: wire = cube_proj.render_wireframe_3d() - sage: print(wire.tachyon().split('\n')[77]) # for testing + sage: wire = cube_proj.render_wireframe_3d() # optional - sage.plot + sage: print(wire.tachyon().split('\n')[77]) # for testing # optional - sage.plot FCylinder base 1.0 1.0 -1.0 apex -1.0 1.0 -1.0 rad 0.005 texture... """ wireframe = [] @@ -1007,8 +1007,8 @@ def render_solid_3d(self, **kwds): EXAMPLES:: sage: p = polytopes.hypercube(3).projection() - sage: p_solid = p.render_solid_3d(opacity = .7) - sage: type(p_solid) + sage: p_solid = p.render_solid_3d(opacity=.7) # optional - sage.plot + sage: type(p_solid) # optional - sage.plot """ polys = self.polygons @@ -1031,9 +1031,9 @@ def render_0d(self, point_opts=None, line_opts=None, polygon_opts=None): EXAMPLES:: - sage: print(Polyhedron([]).projection().render_0d().description()) + sage: print(Polyhedron([]).projection().render_0d().description()) # optional - sage.plot - sage: print(Polyhedron(ieqs=[(1,)]).projection().render_0d().description()) + sage: print(Polyhedron(ieqs=[(1,)]).projection().render_0d().description()) # optional - sage.plot Point set defined by 1 point(s): [(0.0, 0.0)] """ if point_opts is None: @@ -1062,7 +1062,7 @@ def render_1d(self, point_opts=None, line_opts=None, polygon_opts=None): EXAMPLES:: - sage: Polyhedron([(0,), (1,)]).projection().render_1d() + sage: Polyhedron([(0,), (1,)]).projection().render_1d() # optional - sage.plot Graphics object consisting of 2 graphics primitives """ plt = Graphics() @@ -1094,7 +1094,7 @@ def render_2d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: q3 = p3.projection() sage: p4 = Polyhedron(vertices=[[2,0]], rays=[[1,-1]], lines=[[1,1]]) sage: q4 = p4.projection() - sage: q1.plot() + q2.plot() + q3.plot() + q4.plot() + sage: q1.plot() + q2.plot() + q3.plot() + q4.plot() # optional - sage.plot Graphics object consisting of 17 graphics primitives """ plt = Graphics() @@ -1126,28 +1126,28 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: p1 = Polyhedron(vertices=[[1,1,1]], rays=[[1,1,1]]) sage: p2 = Polyhedron(vertices=[[2,0,0], [0,2,0], [0,0,2]]) sage: p3 = Polyhedron(vertices=[[1,0,0], [0,1,0], [0,0,1]], rays=[[-1,-1,-1]]) - sage: p1.projection().plot() + p2.projection().plot() + p3.projection().plot() + sage: p1.projection().plot() + p2.projection().plot() + p3.projection().plot() # optional - sage.plot Graphics3d Object It correctly handles various degenerate cases:: - sage: Polyhedron(lines=[[1,0,0],[0,1,0],[0,0,1]]).plot() # whole space + sage: Polyhedron(lines=[[1,0,0],[0,1,0],[0,0,1]]).plot() # whole space # optional - sage.plot Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], + sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], # optional - sage.plot ....: lines=[[0,1,0],[0,0,1]]).plot() # half space Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]], + sage: Polyhedron(vertices=[[1,1,1]], # optional - sage.plot ....: lines=[[0,1,0],[0,0,1]]).plot() # R^2 in R^3 Graphics3d Object - sage: Polyhedron(rays=[[0,1,0],[0,0,1]], lines=[[1,0,0]]).plot() # quadrant wedge in R^2 + sage: Polyhedron(rays=[[0,1,0],[0,0,1]], lines=[[1,0,0]]).plot() # quadrant wedge in R^2 # optional - sage.plot Graphics3d Object - sage: Polyhedron(rays=[[0,1,0]], lines=[[1,0,0]]).plot() # upper half plane in R^3 + sage: Polyhedron(rays=[[0,1,0]], lines=[[1,0,0]]).plot() # upper half plane in R^3 # optional - sage.plot Graphics3d Object - sage: Polyhedron(lines=[[1,0,0]]).plot() # R^1 in R^2 + sage: Polyhedron(lines=[[1,0,0]]).plot() # R^1 in R^2 # optional - sage.plot Graphics3d Object - sage: Polyhedron(rays=[[0,1,0]]).plot() # Half-line in R^3 + sage: Polyhedron(rays=[[0,1,0]]).plot() # Half-line in R^3 # optional - sage.plot Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]]).plot() # point in R^3 + sage: Polyhedron(vertices=[[1,1,1]]).plot() # point in R^3 # optional - sage.plot Graphics3d Object The origin is not included, if it is not in the polyhedron (:trac:`23555`):: @@ -1155,8 +1155,8 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): sage: Q = Polyhedron([[100],[101]]) sage: P = Q*Q*Q; P A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices - sage: p = P.plot() - sage: p.bounding_box() + sage: p = P.plot() # optional - sage.plot + sage: p.bounding_box() # optional - sage.plot ((100.0, 100.0, 100.0), (101.0, 101.0, 101.0)) """ pplt = None diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py index 03343dc6f9f..c7eac168fad 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py @@ -407,11 +407,11 @@ def plot(self): sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL((1,0), (0,1), (0,0), (2,2)) - sage: P.plot() + sage: P.plot() # optional - sage.plot Graphics object consisting of 6 graphics primitives - sage: LatticePolytope_PPL([0], [1]).plot() + sage: LatticePolytope_PPL([0], [1]).plot() # optional - sage.plot Graphics object consisting of 3 graphics primitives - sage: LatticePolytope_PPL([0]).plot() + sage: LatticePolytope_PPL([0]).plot() # optional - sage.plot Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point2d diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 443bea9224a..333f18e1787 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -791,8 +791,8 @@ def is_facet_defining_inequality(self, other): sage: Q = Polyhedron(ieqs=[[0,2,0,3]]) sage: Q.inequalities()[0].is_facet_defining_inequality(P) True - sage: Q = Polyhedron(ieqs=[[0,AA(2).sqrt(),0,3]]) - sage: Q.inequalities()[0].is_facet_defining_inequality(P) + sage: Q = Polyhedron(ieqs=[[0,AA(2).sqrt(),0,3]]) # optional - sage.rings.number_field + sage: Q.inequalities()[0].is_facet_defining_inequality(P) # optional - sage.rings.number_field True sage: Q = Polyhedron(ieqs=[[1,1,0,0]]) sage: Q.inequalities()[0].is_facet_defining_inequality(P) @@ -893,9 +893,9 @@ def _repr_(self): Test that :trac:`21105` has been fixed:: - sage: K. = NumberField(x^3 - 2, 'a', embedding=1.26) - sage: P = Polyhedron(vertices=[(1,1,cbrt2),(cbrt2,1,1)]) - sage: P.inequalities() + sage: K. = NumberField(x^3 - 2, 'a', embedding=1.26) # optional - sage.rings.number_field + sage: P = Polyhedron(vertices=[(1,1,cbrt2),(cbrt2,1,1)]) # optional - sage.rings.number_field + sage: P.inequalities() # optional - sage.rings.number_field (An inequality (-cbrt2^2 - cbrt2 - 1, 0, 0) x + cbrt2^2 + cbrt2 + 2 >= 0, An inequality (cbrt2^2 + cbrt2 + 1, 0, 0) x - cbrt2^2 + cbrt2 + 1 >= 0) """ diff --git a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py index 10ea1e48e2d..acd70e6bc75 100644 --- a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py +++ b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py @@ -97,7 +97,7 @@ class ParametrizedSurface3D(SageObject): sage: ellipsoid_eq = (cos(u1)*cos(u2), 2*sin(u1)*cos(u2), 3*sin(u2)) sage: ellipsoid = ParametrizedSurface3D(ellipsoid_eq, coords, 'ellipsoid'); ellipsoid Parametrized surface ('ellipsoid') with equation (cos(u1)*cos(u2), 2*cos(u2)*sin(u1), 3*sin(u2)) - sage: ellipsoid.plot() + sage: ellipsoid.plot() # optional - sage.plot Graphics3d Object Standard surfaces can be constructed using the ``surfaces`` generator:: @@ -120,7 +120,7 @@ class ParametrizedSurface3D(SageObject): sage: enneper = surfaces.Enneper(); enneper Parametrized surface ('Enneper's surface') with equation (-1/9*(u^2 - 3*v^2 - 3)*u, -1/9*(3*u^2 - v^2 + 3)*v, 1/3*u^2 - 1/3*v^2) - sage: enneper.plot(aspect_ratio='automatic') + sage: enneper.plot(aspect_ratio='automatic') # optional - sage.plot Graphics3d Object We construct an ellipsoid whose axes are given by symbolic variables `a`, @@ -314,7 +314,7 @@ class ParametrizedSurface3D(SageObject): sage: g1 = [c[-1] for c in S.geodesics_numerical((0,0),(1,0),(0,2*pi,100))] sage: g2 = [c[-1] for c in S.geodesics_numerical((0,0),(cos(pi/3),sin(pi/3)),(0,2*pi,100))] sage: g3 = [c[-1] for c in S.geodesics_numerical((0,0),(cos(2*pi/3),sin(2*pi/3)),(0,2*pi,100))] - sage: (S.plot(opacity=0.3) + line3d(g1,color='red') + line3d(g2,color='red') + line3d(g3,color='red')).show() + sage: (S.plot(opacity=0.3) + line3d(g1,color='red') + line3d(g2,color='red') + line3d(g3,color='red')).show() # optional - sage.plot """ @@ -488,7 +488,7 @@ def plot(self, urange=None, vrange=None, **kwds): sage: u, v = var('u, v', domain='real') sage: eq = (3*u + 3*u*v^2 - u^3, 3*v + 3*u^2*v - v^3, 3*(u^2-v^2)) sage: enneper = ParametrizedSurface3D(eq, (u, v), 'Enneper Surface') - sage: enneper.plot((-5, 5), (-5, 5)) + sage: enneper.plot((-5, 5), (-5, 5)) # optional - sage.plot Graphics3d Object """ diff --git a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py index 078af43b338..3619c6c2952 100644 --- a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py +++ b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py @@ -53,7 +53,7 @@ def Catenoid(c=1, name="Catenoid"): sage: cat = surfaces.Catenoid(); cat Parametrized surface ('Catenoid') with equation (cos(u)*cosh(v), cosh(v)*sin(u), v) - sage: cat.plot() + sage: cat.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -86,7 +86,7 @@ def Crosscap(r=1, name="Crosscap"): sage: crosscap = surfaces.Crosscap(); crosscap Parametrized surface ('Crosscap') with equation ((cos(v) + 1)*cos(u), (cos(v) + 1)*sin(u), -sin(v)*tanh(-pi + u)) - sage: crosscap.plot() + sage: crosscap.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -120,7 +120,7 @@ def Dini(a=1, b=1, name="Dini's surface"): sage: dini = surfaces.Dini(a=3, b=4); dini Parametrized surface ('Dini's surface') with equation (3*cos(u)*sin(v), 3*sin(u)*sin(v), 4*u + 3*cos(v) + 3*log(tan(1/2*v))) - sage: dini.plot() + sage: dini.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -158,7 +158,7 @@ def Ellipsoid(center=(0, 0, 0), axes=(1, 1, 1), name="Ellipsoid"): sage: ell = surfaces.Ellipsoid(axes=(1, 2, 3)); ell Parametrized surface ('Ellipsoid') with equation (cos(u)*cos(v), 2*cos(v)*sin(u), 3*sin(v)) - sage: ell.plot() + sage: ell.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -193,7 +193,7 @@ def Enneper(name="Enneper's surface"): sage: enn = surfaces.Enneper(); enn Parametrized surface ('Enneper's surface') with equation (-1/9*(u^2 - 3*v^2 - 3)*u, -1/9*(3*u^2 - v^2 + 3)*v, 1/3*u^2 - 1/3*v^2) - sage: enn.plot() + sage: enn.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -227,7 +227,7 @@ def Helicoid(h=1, name="Helicoid"): sage: helicoid = surfaces.Helicoid(h=2); helicoid Parametrized surface ('Helicoid') with equation (rho*cos(theta), rho*sin(theta), theta/pi) - sage: helicoid.plot() + sage: helicoid.plot() # optional - sage.plot Graphics3d Object """ rho, theta = var('rho, theta') @@ -260,7 +260,7 @@ def Klein(r=1, name="Klein bottle"): sage: klein = surfaces.Klein(); klein Parametrized surface ('Klein bottle') with equation (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v)) - sage: klein.plot() + sage: klein.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -291,7 +291,7 @@ def MonkeySaddle(name="Monkey saddle"): sage: saddle = surfaces.MonkeySaddle(); saddle Parametrized surface ('Monkey saddle') with equation (u, v, u^3 - 3*u*v^2) - sage: saddle.plot() + sage: saddle.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -327,12 +327,12 @@ def Paraboloid(a=1, b=1, c=1, elliptic=True, name=None): sage: epar = surfaces.Paraboloid(1, 3, 2); epar Parametrized surface ('Elliptic paraboloid') with equation (u, v, 2*u^2 + 2/9*v^2) - sage: epar.plot() + sage: epar.plot() # optional - sage.plot Graphics3d Object sage: hpar = surfaces.Paraboloid(2, 3, 1, elliptic=False); hpar Parametrized surface ('Hyperbolic paraboloid') with equation (u, v, -1/4*u^2 + 1/9*v^2) - sage: hpar.plot() + sage: hpar.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -372,7 +372,7 @@ def Sphere(center=(0, 0, 0), R=1, name="Sphere"): sage: sphere = surfaces.Sphere(center=(0, 1, -1), R=2); sphere Parametrized surface ('Sphere') with equation (2*cos(u)*cos(v), 2*cos(v)*sin(u) + 1, 2*sin(v) - 1) - sage: sphere.plot() + sage: sphere.plot() # optional - sage.plot Graphics3d Object Note that the radius of the sphere can be negative. The surface thus @@ -382,14 +382,14 @@ def Sphere(center=(0, 0, 0), R=1, name="Sphere"): sage: octant1 = surfaces.Sphere(R=1); octant1 Parametrized surface ('Sphere') with equation (cos(u)*cos(v), cos(v)*sin(u), sin(v)) - sage: octant1.plot((0, pi/2), (0, pi/2)) + sage: octant1.plot((0, pi/2), (0, pi/2)) # optional - sage.plot Graphics3d Object with the first octant of the unit sphere with negative radius:: sage: octant2 = surfaces.Sphere(R=-1); octant2 Parametrized surface ('Sphere') with equation (-cos(u)*cos(v), -cos(v)*sin(u), -sin(v)) - sage: octant2.plot((0, pi/2), (0, pi/2)) + sage: octant2.plot((0, pi/2), (0, pi/2)) # optional - sage.plot Graphics3d Object """ return SurfaceGenerators.Ellipsoid(center, (R, R, R), name) @@ -421,7 +421,7 @@ def Torus(r=2, R=3, name="Torus"): sage: torus = surfaces.Torus(); torus Parametrized surface ('Torus') with equation ((2*cos(v) + 3)*cos(u), (2*cos(v) + 3)*sin(u), 2*sin(v)) - sage: torus.plot() + sage: torus.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') @@ -448,7 +448,7 @@ def WhitneyUmbrella(name="Whitney's umbrella"): sage: whitney = surfaces.WhitneyUmbrella(); whitney Parametrized surface ('Whitney's umbrella') with equation (u*v, u, v^2) - sage: whitney.plot() + sage: whitney.plot() # optional - sage.plot Graphics3d Object """ u, v = var('u, v') diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index e8920bfb701..87b32ec2fca 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -1048,7 +1048,7 @@ def plot(self, **options): EXAMPLES:: sage: N = ToricLattice(3) - sage: N.plot() + sage: N.plot() # optional - sage.plot Graphics3d Object """ if "show_lattice" not in options: @@ -1195,12 +1195,12 @@ def plot(self, **options): sage: N = ToricLattice(3) sage: sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)]) - sage: sublattice.plot() + sage: sublattice.plot() # optional - sage.plot Graphics3d Object Now we plot both the ambient lattice and its sublattice:: - sage: N.plot() + sublattice.plot(point_color="red") + sage: N.plot() + sublattice.plot(point_color="red") # optional - sage.plot Graphics3d Object """ if "show_lattice" not in options: diff --git a/src/sage/geometry/toric_lattice_element.pyx b/src/sage/geometry/toric_lattice_element.pyx index 5e858f8773d..caaf1c2be93 100644 --- a/src/sage/geometry/toric_lattice_element.pyx +++ b/src/sage/geometry/toric_lattice_element.pyx @@ -394,7 +394,7 @@ cdef class ToricLatticeElement(Vector_integer_dense): sage: N = ToricLattice(3) sage: n = N(1,2,3) - sage: n.plot() + sage: n.plot() # optional - sage.plot Graphics3d Object """ tp = ToricPlotter(options, self.parent().degree()) diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 6a973c4d230..27c5913b5fa 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -15,7 +15,7 @@ In most cases, this module is used indirectly, e.g. :: sage: fan = toric_varieties.dP6().fan() - sage: fan.plot() + sage: fan.plot() # optional - sage.plot Graphics object consisting of 31 graphics primitives You may change default plotting options as follows:: @@ -25,12 +25,12 @@ sage: toric_plotter.options(show_rays=False) sage: toric_plotter.options("show_rays") False - sage: fan.plot() + sage: fan.plot() # optional - sage.plot Graphics object consisting of 19 graphics primitives sage: toric_plotter.reset_options() sage: toric_plotter.options("show_rays") True - sage: fan.plot() + sage: fan.plot() # optional - sage.plot Graphics object consisting of 31 graphics primitives """ @@ -134,9 +134,9 @@ class ToricPlotter(SageObject): plot, e.g. :: sage: fan = toric_varieties.dP6().fan() - sage: fan.plot() + sage: fan.plot() # optional - sage.plot Graphics object consisting of 31 graphics primitives - sage: print(fan.plot()) + sage: print(fan.plot()) # optional - sage.plot Graphics object consisting of 31 graphics primitives If you do want to create your own plotting function for some toric diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 9aea06b7fb5..c9a43dca642 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -23,7 +23,7 @@ sage: points = PointConfiguration(p) sage: triang = points.triangulate(); triang (<0,1,2,5>, <0,1,3,5>, <1,3,4,5>) - sage: triang.plot(axes=False) + sage: triang.plot(axes=False) # optional - sage.plot Graphics3d Object See :mod:`sage.geometry.triangulation.point_configuration` for more details. @@ -68,7 +68,7 @@ def triangulation_render_2d(triangulation, **kwds): sage: points = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) sage: triang = points.triangulate() - sage: triang.plot(axes=False, aspect_ratio=1) # indirect doctest + sage: triang.plot(axes=False, aspect_ratio=1) # indirect doctest # optional - sage.plot Graphics object consisting of 12 graphics primitives """ from sage.plot.all import point2d, line2d, polygon2d @@ -132,7 +132,7 @@ def triangulation_render_3d(triangulation, **kwds): sage: p = [[0,-1,-1],[0,0,1],[0,1,0], [1,-1,-1],[1,0,1],[1,1,0]] sage: points = PointConfiguration(p) sage: triang = points.triangulate() - sage: triang.plot(axes=False) # indirect doctest + sage: triang.plot(axes=False) # indirect doctest # optional - sage.plot Graphics3d Object """ from sage.plot.plot3d.all import point3d, line3d, polygon3d @@ -416,7 +416,7 @@ def plot(self, **kwds): sage: triangulation = p.triangulate() sage: triangulation (<1,3,4>, <2,3,4>) - sage: triangulation.plot(axes=False) + sage: triangulation.plot(axes=False) # optional - sage.plot Graphics object consisting of 12 graphics primitives """ dim = self.point_configuration().dim() diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index 0346c9cdac4..3d900609d4a 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -67,7 +67,7 @@ (2, 3, 4) sage: list(t) [(1, 3, 4), (2, 3, 4)] - sage: t.plot(axes=False) + sage: t.plot(axes=False) # optional - sage.plot Graphics object consisting of 12 graphics primitives .. PLOT:: @@ -98,7 +98,7 @@ sage: p = [[0,-1,-1],[0,0,1],[0,1,0], [1,-1,-1],[1,0,1],[1,1,0]] sage: points = PointConfiguration(p) sage: triang = points.triangulate() - sage: triang.plot(axes=False) + sage: triang.plot(axes=False) # optional - sage.plot Graphics3d Object .. PLOT:: @@ -119,7 +119,7 @@ 16 sage: len(nonregular) # optional - topcom 2 - sage: nonregular[0].plot(aspect_ratio=1, axes=False) # optional - topcom + sage: nonregular[0].plot(aspect_ratio=1, axes=False) # optional - topcom # optional - sage.plot Graphics object consisting of 25 graphics primitives sage: PointConfiguration.set_engine('internal') # to make doctests independent of TOPCOM @@ -1555,9 +1555,9 @@ def bistellar_flips(self): sage: pc.bistellar_flips() (((<0,1,3>, <0,2,3>), (<0,1,2>, <1,2,3>)),) sage: Tpos, Tneg = pc.bistellar_flips()[0] - sage: Tpos.plot(axes=False) + sage: Tpos.plot(axes=False) # optional - sage.plot Graphics object consisting of 11 graphics primitives - sage: Tneg.plot(axes=False) + sage: Tneg.plot(axes=False) # optional - sage.plot Graphics object consisting of 11 graphics primitives The 3d analog:: @@ -1572,7 +1572,7 @@ def bistellar_flips(self): sage: pc.bistellar_flips() (((<0,1,3>, <0,2,3>), (<0,1,2>, <1,2,3>)),) sage: Tpos, Tneg = pc.bistellar_flips()[0] - sage: Tpos.plot(axes=False) + sage: Tpos.plot(axes=False) # optional - sage.plot Graphics3d Object """ flips = [] @@ -2114,7 +2114,7 @@ def plot(self, **kwds): EXAMPLES:: sage: p = PointConfiguration([[0,0],[0,1],[1,0],[1,1],[-1,-1]]) - sage: p.plot(axes=False) + sage: p.plot(axes=False) # optional - sage.plot Graphics object consisting of 5 graphics primitives .. PLOT:: diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 1859a5e0c1a..6afd850ae0d 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -17,8 +17,7 @@ from sage.geometry.polyhedron.constructor import Polyhedron from sage.rings.qqbar import AA from sage.rings.rational_field import QQ -from sage.rings.real_double import RDF -from sage.rings.real_mpfr import RealField_class +import sage.rings.abc from sage.geometry.triangulation.point_configuration import PointConfiguration from sage.modules.free_module_element import vector from sage.plot.all import line, point, rainbow, plot @@ -52,18 +51,18 @@ class VoronoiDiagram(SageObject): Get the Voronoi diagram of a regular pentagon in ``AA^2``. All cells meet at the origin:: - sage: DV = VoronoiDiagram([[AA(c) for c in v] for v in polytopes.regular_polygon(5).vertices_list()]); DV + sage: DV = VoronoiDiagram([[AA(c) for c in v] for v in polytopes.regular_polygon(5).vertices_list()]); DV # optional - sage.rings.number_field The Voronoi diagram of 5 points of dimension 2 in the Algebraic Real Field - sage: all(P.contains([0, 0]) for P in DV.regions().values()) + sage: all(P.contains([0, 0]) for P in DV.regions().values()) # optional - sage.rings.number_field True - sage: any(P.interior_contains([0, 0]) for P in DV.regions().values()) + sage: any(P.interior_contains([0, 0]) for P in DV.regions().values()) # optional - sage.rings.number_field False If the vertices are not converted to ``AA`` before, the method throws an error:: - sage: polytopes.dodecahedron().vertices_list()[0][0].parent() + sage: polytopes.dodecahedron().vertices_list()[0][0].parent() # optional - sage.rings.number_field Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: VoronoiDiagram(polytopes.dodecahedron().vertices_list()) + sage: VoronoiDiagram(polytopes.dodecahedron().vertices_list()) # optional - sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: Base ring of the Voronoi diagram must be @@ -103,9 +102,10 @@ def __init__(self, points): self._n = self._points.n_points() if not self._n or self._points.base_ring().is_subring(QQ): self._base_ring = QQ - elif self._points.base_ring() in [RDF, AA]: + elif isinstance(self._points.base_ring(), sage.rings.abc.RealDoubleField) or self._points.base_ring() == AA: self._base_ring = self._points.base_ring() - elif isinstance(self._points.base_ring(), RealField_class): + elif isinstance(self._points.base_ring(), sage.rings.abc.RealField): + from sage.rings.real_double import RDF self._base_ring = RDF self._points = PointConfiguration([[RDF(cor) for cor in poi] for poi in self._points]) @@ -232,9 +232,9 @@ def _repr_(self): EXAMPLES:: - sage: V = VoronoiDiagram(polytopes.regular_polygon(3).vertices()); V + sage: V = VoronoiDiagram(polytopes.regular_polygon(3).vertices()); V # optional - sage.rings.number_field The Voronoi diagram of 3 points of dimension 2 in the Algebraic Real Field - sage: VoronoiDiagram([]) + sage: VoronoiDiagram([]) # optional - sage.rings.number_field The empty Voronoi diagram. """ if self._n: @@ -264,16 +264,16 @@ def plot(self, cell_colors=None, **kwds): sage: P = [[0.671, 0.650], [0.258, 0.767], [0.562, 0.406], [0.254, 0.709], [0.493, 0.879]] - sage: V = VoronoiDiagram(P); S=V.plot() - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: V = VoronoiDiagram(P); S=V.plot() # optional - sage.plot + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - sage: S=V.plot(cell_colors={0:'red', 1:'blue', 2:'green', 3:'white', 4:'yellow'}) - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S=V.plot(cell_colors={0:'red', 1:'blue', 2:'green', 3:'white', 4:'yellow'}) # optional - sage.plot + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - sage: S=V.plot(cell_colors=['red','blue','red','white', 'white']) - sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) + sage: S=V.plot(cell_colors=['red','blue','red','white', 'white']) # optional - sage.plot + sage: show(S, xmin=0, xmax=1, ymin=0, ymax=1, aspect_ratio=1, axes=false) # optional - sage.plot - sage: S=V.plot(cell_colors='something else') + sage: S=V.plot(cell_colors='something else') # optional - sage.plot Traceback (most recent call last): ... AssertionError: 'cell_colors' must be a list or a dictionary @@ -282,7 +282,7 @@ def plot(self, cell_colors=None, **kwds): Trying to plot a Voronoi diagram of dimension other than 2 gives an error:: - sage: VoronoiDiagram([[1, 2, 3], [6, 5, 4]]).plot() + sage: VoronoiDiagram([[1, 2, 3], [6, 5, 4]]).plot() # optional - sage.plot Traceback (most recent call last): ... NotImplementedError: Plotting of 3-dimensional Voronoi diagrams not diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index 19006ceb808..b606a9aa0d1 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -1167,8 +1167,10 @@ def _test_adjacency_sequence_out(): from sage.misc.prandom import randint, random low = 0 high = 1000 - randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random())) - n = randg.order() + n = 0 + while not n: + randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random())) + n = randg.order() # set all labels to 0 E = [(u, v, 0) for u, v in randg.edges(labels=False)] cdef SparseGraph g = SparseGraph(n, diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index bcf919c4a7d..4047a09c127 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -419,12 +419,12 @@ class DiGraph(GenericGraph): RuntimeError: the string seems corrupt: valid characters are ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ - #. A NetworkX XDiGraph:: + #. A NetworkX MultiDiGraph:: sage: import networkx sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) sage: DiGraph(g) - Digraph on 5 vertices + Multi-digraph on 5 vertices #. A NetworkX digraph:: @@ -697,12 +697,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, else: format = 'dict_of_lists' if format is None and hasattr(data, 'adj'): - import networkx - if isinstance(data, (networkx.Graph, networkx.MultiGraph)): - data = data.to_directed() - format = 'NX' - elif isinstance(data, (networkx.DiGraph, networkx.MultiDiGraph)): - format = 'NX' + # the input is a networkx (Multi)(Di)Graph + format = 'NX' + if (format is None and hasattr(data, 'vcount') and hasattr(data, 'get_edgelist')): @@ -804,34 +801,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, from_dict_of_lists(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'NX': - # adjust for empty dicts instead of None in NetworkX default edge - # labels - if convert_empty_dict_labels_to_None is None: - convert_empty_dict_labels_to_None = (format == 'NX') - + from sage.graphs.graph_input import from_networkx_graph + from_networkx_graph(self, data, + weighted=weighted, multiedges=multiedges, loops=loops, + convert_empty_dict_labels_to_None=convert_empty_dict_labels_to_None) if weighted is None: - import networkx - if isinstance(data, networkx.DiGraph): - weighted = False - if multiedges is None: - multiedges = False - if loops is None: - loops = False - else: - weighted = True - if multiedges is None: - multiedges = data.multiedges - if loops is None: - loops = data.selfloops - if convert_empty_dict_labels_to_None: - r = lambda x: None if x == {} else x - else: - r = lambda x: x + weighted = self.allows_multiple_edges() - self.allow_multiple_edges(multiedges, check=False) - self.allow_loops(loops, check=False) - self.add_vertices(data.nodes()) - self.add_edges((u, v, r(l)) for u, v, l in data.edges(data=True)) elif format == 'igraph': if not data.is_directed(): raise ValueError("a *directed* igraph graph was expected. To " diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index f68788aaddb..9bf3508481d 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -1171,7 +1171,7 @@ def CubeGraph(n, embedding=1): vertices in each column represents rows in Pascal's triangle. See for instance the :wikipedia:`10-cube` for more details. - - ``None`` or ``O``: no embedding is provided + - ``None`` or ``O``: no embedding is provided EXAMPLES: @@ -1268,7 +1268,7 @@ def CubeGraph(n, embedding=1): for u, d in G.breadth_first_search(s, report_distance=True): L[d].append(u) - p = G._circle_embedding(list(range(2*n)), radius=(n + 1)//2, angle=pi, return_dict=True) + p = G._circle_embedding(list(range(2*n)), radius=(n + 1)//2, angle=pi, return_dict=True) for i in range(n + 1): y = p[i][1] / 1.5 G._line_embedding(L[i], first=(i, y), last=(i, -y), return_dict=False) @@ -1462,11 +1462,11 @@ def FriendshipGraph(n): sage: G.is_isomorphic(graphs.ButterflyGraph()) True - If `n \geq 1`, then the friendship graph `F_n` has `2n + 1` vertices + If `n \geq 2`, then the friendship graph `F_n` has `2n + 1` vertices and `3n` edges. It has radius 1, diameter 2, girth 3, and chromatic number 3. Furthermore, `F_n` is planar and Eulerian. :: - sage: n = randint(1, 10^3) + sage: n = randint(2, 10^3) sage: G = graphs.FriendshipGraph(n) sage: G.order() == 2*n + 1 True @@ -4016,7 +4016,7 @@ def CubeConnectedCycle(d): For each vertex, `(x,y)`, add an edge between it and `(x, (y-1) \mod d))`, `(x,(y+1) \mod d)`, and `(x \oplus 2^y, y)`, where `\oplus` is the bitwise xor operator. - + For `d=1` and `2`, the cube-connected cycle graph contains self-loops or multiple edges between a pair of vertices, but for all other `d`, it is simple. diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b7f8048f1d4..0df574c5721 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -574,7 +574,7 @@ def __eq__(self, other): True sage: G = graphs.RandomGNP(8, .9999) sage: H = graphs.CompleteGraph(8) - sage: G == H # most often true + sage: G == H # random - most often true True sage: G = Graph({0: [1, 2, 3, 4, 5, 6, 7]} ) sage: H = Graph({1: [0], 2: [0], 3: [0], 4: [0], 5: [0], 6: [0], 7: [0]} ) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 4d37caa6bbb..75fb6241f23 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -797,7 +797,7 @@ class Graph(GenericGraph): sage: import networkx sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) sage: Graph(g) - Graph on 5 vertices + Multi-graph on 5 vertices #. A NetworkX graph:: @@ -1096,11 +1096,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif isinstance(val, dict): format = 'dict_of_dicts' if format is None and hasattr(data, 'adj'): - import networkx - if isinstance(data, (networkx.DiGraph, networkx.MultiDiGraph)): - data = data.to_undirected() - elif isinstance(data, (networkx.Graph, networkx.MultiGraph)): - format = 'NX' + # the input is a networkx (Multi)(Di)Graph + format = 'NX' if (format is None and hasattr(data, 'vcount') and @@ -1183,29 +1180,15 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.name(data.name()) self.set_vertices(data.get_vertices()) data._backend.subgraph_given_vertices(self._backend, data) + elif format == 'NX': - if convert_empty_dict_labels_to_None is not False: - r = lambda x: None if x=={} else x - else: - r = lambda x: x + from sage.graphs.graph_input import from_networkx_graph + from_networkx_graph(self, data, + weighted=weighted, multiedges=multiedges, loops=loops, + convert_empty_dict_labels_to_None=convert_empty_dict_labels_to_None) if weighted is None: - import networkx - if isinstance(data, networkx.Graph): - weighted = False - if multiedges is None: - multiedges = False - if loops is None: - loops = False - else: - weighted = True - if multiedges is None: - multiedges = True - if loops is None: - loops = True - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - self.add_vertices(data.nodes()) - self.add_edges((u,v,r(l)) for u,v,l in data.edges(data=True)) + weighted = self.allows_multiple_edges() + elif format == 'igraph': if data.is_directed(): raise ValueError("An *undirected* igraph graph was expected. "+ @@ -6392,7 +6375,8 @@ def cliques_get_max_clique_graph(self): sage: (G.cliques_get_max_clique_graph()).show(figsize=[2,2]) """ import networkx - return Graph(networkx.make_max_clique_graph(self.networkx_graph(), create_using=networkx.MultiGraph())) + return Graph(networkx.make_max_clique_graph(self.networkx_graph(), create_using=networkx.MultiGraph()), + multiedges=False) @doc_index("Clique-related methods") def cliques_get_clique_bipartite(self, **kwds): diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 77f93b96bf4..35caebb8c25 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -561,6 +561,195 @@ def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): for v in D[u]: G._backend.add_edge(u, v, None, is_directed) +def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, + convert_empty_dict_labels_to_None=None): + r""" + Fill `G` with the data of a NetworkX (di)graph. + + INPUT: + + - ``G`` -- a :class:`Graph` or :class:`DiGraph` + + - ``gnx`` -- a NetworkX ``Graph``, ``MultiGraph``, ``DiGraph`` or + ``MultiDiGraph`` + + - ``weighted`` -- boolean (default: ``None``); whether graph thinks of + itself as weighted or not. See + :meth:`~sage.graphs.generic_graph.GenericGraph.weighted`. + + - ``loops`` -- boolean (default: ``None``); whether to allow loops + + - ``multiedges`` -- boolean (default: ``None``); whether to allow multiple + edges + + - ``convert_empty_dict_labels_to_None`` -- boolean (default: ``None``); + whether to replace the default edge labels used by NetworkX (empty + dictionaries) by ``None``, the default Sage edge label. When set to + ``False``, empty dictionaries are not converted to ``None``. + + EXAMPLES: + + Feeding a :class:`Graph` with a NetworkX ``Graph``:: + + sage: from sage.graphs.graph_input import from_networkx_graph + sage: import networkx + sage: G = Graph() + sage: _ = gnx = networkx.Graph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(1, 2) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) + [(0, 1), (1, 2)] + + Feeding a :class:`Graph` with a NetworkX ``MultiGraph``:: + + sage: G = Graph() + sage: gnx = networkx.MultiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(0, 1) + sage: from_networkx_graph(G, gnx) + sage: G.edges(labels=False) + [(0, 1), (0, 1)] + sage: G = Graph() + sage: from_networkx_graph(G, gnx, multiedges=False) + sage: G.edges(labels=False) + [(0, 1)] + + When feeding a :class:`Graph` `G` with a NetworkX ``DiGraph`` `D`, `G` has + one edge `(u, v)` whenever `D` has arc `(u, v)` or `(v, u)` or both:: + + sage: G = Graph() + sage: D = networkx.DiGraph() + sage: _ = D.add_edge(0, 1) + sage: from_networkx_graph(G, D) + sage: G.edges(labels=False) + [(0, 1)] + sage: G = Graph() + sage: _ = D.add_edge(1, 0) + sage: from_networkx_graph(G, D) + sage: G.edges(labels=False) + [(0, 1)] + + When feeding a :class:`Graph` `G` with a NetworkX ``MultiDiGraph`` `D`, the + number of edges between `u` and `v` in `G` is the maximum between the number + of arcs `(u, v)` and the number of arcs `(v, u)` in D`:: + + sage: G = Graph() + sage: D = networkx.MultiDiGraph() + sage: _ = D.add_edge(0, 1) + sage: _ = D.add_edge(1, 0) + sage: _ = D.add_edge(1, 0) + sage: D.edges() + OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)]) + sage: from_networkx_graph(G, D) + sage: G.edges(labels=False) + [(0, 1), (0, 1)] + + Feeding a :class:`DiGraph` with a NetworkX ``DiGraph``:: + + sage: from sage.graphs.graph_input import from_networkx_graph + sage: import networkx + sage: G = DiGraph() + sage: _ = gnx = networkx.DiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(1, 2) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) + [(0, 1), (1, 2)] + + Feeding a :class:`DiGraph` with a NetworkX ``MultiDiGraph``:: + + sage: G = DiGraph() + sage: gnx = networkx.MultiDiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(0, 1) + sage: from_networkx_graph(G, gnx) + sage: G.edges(labels=False) + [(0, 1), (0, 1)] + sage: G = DiGraph() + sage: from_networkx_graph(G, gnx, multiedges=False) + sage: G.edges(labels=False) + [(0, 1)] + + When feeding a :class:`DiGraph` `G` with a NetworkX ``Graph`` `H`, `G` has + both arcs `(u, v)` and `(v, u)` if `G` has edge `(u, v)`:: + + sage: G = DiGraph() + sage: H = networkx.Graph() + sage: _ = H.add_edge(0, 1) + sage: from_networkx_graph(G, H) + sage: G.edges(labels=False, sort=True) + [(0, 1), (1, 0)] + + When feeding a :class:`DiGraph` `G` with a NetworkX ``MultiGraph`` `H`, `G` + has `k` arcs `(u, v)` and `k` arcs `(v, u)` if `H` has `k` edges `(u, v)`, + unless parameter ``multiedges`` is set to ``False``:: + + sage: G = DiGraph() + sage: H = networkx.MultiGraph() + sage: _ = H.add_edge(0, 1) + sage: _ = H.add_edge(0, 1) + sage: _ = H.add_edge(0, 1) + sage: H.edges() + MultiEdgeDataView([(0, 1), (0, 1), (0, 1)]) + sage: from_networkx_graph(G, H) + sage: G.edges(labels=False, sort=True) + [(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)] + sage: G = DiGraph() + sage: from_networkx_graph(G, H, multiedges=False) + sage: G.edges(labels=False, sort=True) + [(0, 1), (1, 0)] + + TESTS: + + The first parameter must be a :class:`Graph` or :class:`DiGraph`:: + + sage: from sage.graphs.graph_input import from_networkx_graph + sage: from_networkx_graph("foo", "bar") + Traceback (most recent call last): + ... + ValueError: the first parameter must a Sage Graph or DiGraph + + The second parameter must be a NetworkX ``Graph``, ``MultiGraph``, + ``DiGraph`` or ``MultiDiGraph``:: + + sage: from sage.graphs.graph_input import from_networkx_graph + sage: from_networkx_graph(Graph(), "bar") + Traceback (most recent call last): + ... + ValueError: the second parameter must be a NetworkX (Multi)(Di)Graph + """ + from sage.graphs.graph import Graph + from sage.graphs.digraph import DiGraph + if not isinstance(G, (Graph, DiGraph)): + raise ValueError("the first parameter must a Sage Graph or DiGraph") + import networkx + if not isinstance(gnx, (networkx.Graph, networkx.DiGraph)): + raise ValueError("the second parameter must be a NetworkX (Multi)(Di)Graph") + + if G.is_directed() != gnx.is_directed(): + if gnx.is_directed(): + gnx = gnx.to_undirected() + else: + gnx = gnx.to_directed() + + if weighted is None: + if multiedges is None: + multiedges = gnx.is_multigraph() + if loops is None: + loops = any(u == v for u, v in gnx.edges()) + + G.allow_loops(loops, check=False) + G.allow_multiple_edges(multiedges, check=False) + G.add_vertices(gnx.nodes()) + G.set_vertices(gnx.nodes(data=True)) + if convert_empty_dict_labels_to_None is not False: + def r(l): + return None if l == {} else l + G.add_edges((u, v, r(l)) for u, v, l in gnx.edges(data=True)) + else: + G.add_edges(gnx.edges(data=True)) + from sage.misc.rest_index_of_methods import gen_rest_table_index import sys __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 0089412092b..cdbd9e3b345 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -2628,13 +2628,20 @@ def SRG_1288_792_476_504(): cdef bint seems_feasible(int v, int k, int l, int mu): r""" - Tests is the set of parameters seems feasible + Check if the set of parameters seems feasible. INPUT: - ``v,k,l,mu`` (integers) + + TESTS: + + :trac:`32306` is fixed:: + + sage: from sage.graphs.strongly_regular_db import strongly_regular_graph + sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) + True """ - cdef int r,s,f,g cdef uint_fast32_t tmp[2] if (v<0 or k<=0 or l<0 or mu<0 or diff --git a/src/sage/groups/abelian_gps/abelian_aut.py b/src/sage/groups/abelian_gps/abelian_aut.py index 18afe029eda..33defb5b271 100644 --- a/src/sage/groups/abelian_gps/abelian_aut.py +++ b/src/sage/groups/abelian_gps/abelian_aut.py @@ -115,7 +115,7 @@ def __init__(self, parent, x, check=True): sage: TestSuite(f).run() """ if check: - if not x in parent.gap(): + if x not in parent.gap(): raise ValueError("%s is not in the group %s" % (x, parent)) ElementLibGAP.__init__(self, parent, x) diff --git a/src/sage/groups/abelian_gps/abelian_group_gap.py b/src/sage/groups/abelian_gps/abelian_group_gap.py index 1a6583dac03..48d7eb39cb1 100644 --- a/src/sage/groups/abelian_gps/abelian_group_gap.py +++ b/src/sage/groups/abelian_gps/abelian_group_gap.py @@ -161,10 +161,10 @@ def exponents(self): orders = P.gens_orders() i = 0 for k in range(len(P.gens())): - if not k+1 in Lgens: + if k + 1 not in Lgens: exp.append(0) else: - i = Lgens.index(k+1) + i = Lgens.index(k + 1) exp.append(Lexpo[i] % orders[k]) return tuple(exp) diff --git a/src/sage/groups/fqf_orthogonal.py b/src/sage/groups/fqf_orthogonal.py index 184efa9be0b..05f76e582d1 100644 --- a/src/sage/groups/fqf_orthogonal.py +++ b/src/sage/groups/fqf_orthogonal.py @@ -558,7 +558,7 @@ def orbits(G, L): if not automorphisms: return f g = ambient(matrix(f)) - if not g in G: + if g not in G: G = B.orthogonal_group(tuple(ambient(s.matrix()) for s in G.gens())+(g,)) waiting = orbits(G, waiting) continue diff --git a/src/sage/groups/group_exp.py b/src/sage/groups/group_exp.py index bf0db4aa837..3fa83c6ff86 100644 --- a/src/sage/groups/group_exp.py +++ b/src/sage/groups/group_exp.py @@ -257,7 +257,6 @@ class GroupExp_Class(UniqueRepresentation, Parent): sage: GroupExp()(QQ) Multiplicative form of Rational Field - """ def __init__(self, G): r""" @@ -268,8 +267,7 @@ def __init__(self, G): sage: TestSuite(EG).run(skip = "_test_elements") """ - - if not G in CommutativeAdditiveGroups(): + if G not in CommutativeAdditiveGroups(): raise TypeError("%s must be a commutative additive group" % G) self._G = G Parent.__init__(self, category=Groups()) diff --git a/src/sage/groups/libgap_morphism.py b/src/sage/groups/libgap_morphism.py index 75785e2e382..77ba764a4f7 100644 --- a/src/sage/groups/libgap_morphism.py +++ b/src/sage/groups/libgap_morphism.py @@ -507,7 +507,7 @@ def lift(self, h): ValueError: f2 is not an element of the image of Group endomorphism of Abelian group with gap, generator orders (2, 4) """ - if not h in self.codomain(): + if h not in self.codomain(): raise TypeError("h (={}) must be an element of the codomain".format(h)) h = self.codomain()(h) phi = self.gap() diff --git a/src/sage/groups/lie_gps/nilpotent_lie_group.py b/src/sage/groups/lie_gps/nilpotent_lie_group.py index ea88fe46d99..55740317caa 100644 --- a/src/sage/groups/lie_gps/nilpotent_lie_group.py +++ b/src/sage/groups/lie_gps/nilpotent_lie_group.py @@ -26,7 +26,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.repr import repr_lincomb from sage.modules.free_module_element import vector -from sage.rings.real_mpfr import RealField_class +import sage.rings.abc from sage.structure.element import MultiplicativeGroupElement from sage.misc.lazy_import import lazy_import lazy_import("sage.symbolic.ring", "SR", "var") @@ -230,7 +230,7 @@ def __init__(self, L, name, **kwds): R = L.base_ring() category = kwds.pop('category', None) category = LieGroups(R).or_subcategory(category) - if isinstance(R, RealField_class): + if isinstance(R, sage.rings.abc.RealField): structure = RealDifferentialStructure() else: structure = DifferentialStructure() diff --git a/src/sage/groups/matrix_gps/isometries.py b/src/sage/groups/matrix_gps/isometries.py index 55d6c52b632..ab611b4ce7f 100644 --- a/src/sage/groups/matrix_gps/isometries.py +++ b/src/sage/groups/matrix_gps/isometries.py @@ -116,9 +116,9 @@ def __init__(self, degree, base_ring, Q = invariant_quotient_module for f in gens: self._check_matrix(f) - if (not I is None) and I*f != I: + if (I is not None) and I * f != I: raise ValueError("the submodule is not preserved") - if not Q is None and (Q.W() != Q.W()*f or Q.V()*f != Q.V()): + if Q is not None and (Q.W() != Q.W()*f or Q.V()*f != Q.V()): raise ValueError("the quotient module is not preserved") if len(gens) == 0: # handle the trivial group gens = [G.parent().identity_matrix()] diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 678cc042adf..199a6a3f678 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -46,7 +46,7 @@ from sage.structure.parent import Parent from sage.structure.richcmp import richcmp_by_eq_and_lt from sage.structure.unique_representation import UniqueRepresentation - +import sage.rings.abc class AbstractArgument(MultiplicativeGroupElement): r""" @@ -1870,13 +1870,13 @@ def create_key_and_extra_args(self, if domain is not None: if domain in (ZZ, QQ, AA) \ - or isinstance(domain, (RealField_class, - RealIntervalField_class, - RealBallField)): + or isinstance(domain, (sage.rings.abc.RealField, + sage.rings.abc.RealIntervalField, + sage.rings.abc.RealBallField)): return (SignGroup, ()), kwds - elif isinstance(domain, (ComplexField_class, - ComplexIntervalField_class, - ComplexBallField)): + elif isinstance(domain, (sage.rings.abc.ComplexField, + sage.rings.abc.ComplexIntervalField, + sage.rings.abc.ComplexBallField)): return (UnitCircleGroup, (domain._real_field(),)), kwds else: return (ArgumentByElementGroup, (domain,)), kwds diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index dfdd6d52e74..807cd92ad02 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -735,7 +735,7 @@ def parse(self, mv, check=True): return mv if mv.parent() is self else PermutationGroup_generic.__call__(self, mv, check) elif isinstance(mv, str): # It is a string: may be in cycle notation or Rubik's notation - if '(' in mv and not '^' in mv: + if '(' in mv and '^' not in mv: return PermutationGroup_generic.__call__(self, mv, check) else: gens = self.gens() diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index f91dcd8fcca..3b8ab1fcd4a 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -1910,7 +1910,7 @@ def strong_generating_system(self, base_of_group=None, implementation="sage"): True """ if implementation == "gap": - if not base_of_group is None: + if base_of_group is not None: raise ValueError("the optional argument 'base_of_group'" " (='%s') must be None if 'implementation'='gap'" % base_of_group) @@ -3823,9 +3823,9 @@ def cosets(self, S, side='right'): from copy import copy from sage.categories.finite_permutation_groups import FinitePermutationGroups - if not side in ['right','left']: + if side not in ['right', 'left']: raise ValueError("side should be 'right' or 'left', not %s" % side) - if not S in FinitePermutationGroups(): + if S not in FinitePermutationGroups(): raise TypeError("%s is not a permutation group" % S) if not S.is_subgroup(self): raise ValueError("%s is not a subgroup of %s" % (S, self)) @@ -3836,9 +3836,9 @@ def cosets(self, S, side='right'): while group: rep = group[0] if side == 'right': - coset = [e*rep for e in subgroup] + coset = [e * rep for e in subgroup] if side == 'left': - coset = [rep*e for e in subgroup] + coset = [rep * e for e in subgroup] for e in coset: group.remove(e) decomposition.append(coset) diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 5010e958a3c..a7445145282 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -1552,13 +1552,11 @@ def __init__(self, p, m): AUTHOR: - Kevin Halasz (2012-8-7) - """ - if not isinstance(p, Integer) or not isinstance(m, Integer): raise TypeError('both p and m must be integers') - if not p in Primes(): + if p not in Primes(): raise ValueError('p must be prime, %s is not prime' % p) if p == 2 and m <= 3: diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 238f2061181..9aed0ea413d 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -373,7 +373,7 @@ def set_seed(self, seed=None): sage: m.set_seed(1) # optional - magma 1 sage: [m.Random(100) for i in range(5)] # optional - magma - [13, 55, 84, 100, 37] + [14, 81, 45, 75, 67] """ if seed is None: seed = self.rand_seed() @@ -2318,7 +2318,7 @@ def _polynomial_(self, R): sage: R. = QQ[] sage: f = magma(x^2 + 2/3*x + 5) # optional - magma sage: f # optional - magma - x^2 + 2/3*x + 5 + t^2 + 2/3*t + 5 sage: f.Type() # optional - magma RngUPolElt sage: f._polynomial_(R) # optional - magma @@ -2626,13 +2626,27 @@ def __bool__(self): True sage: bool(magma(0)) # optional - magma False + + TESTS:: + + Verify that :trac:`32602` is fixed:: + + sage: magma("1 eq 0").bool() # optional - magma + False + sage: magma("1 eq 1").bool() # optional - magma + True + sage: Q. = PolynomialRing(GF(3)) + sage: u = x^6+x^4+2*x^3+2*x+1 + sage: F0 = magma.FunctionField(GF(3)) # optional - magma + sage: bool(F0.1) # optional - magma + True """ try: - return not self.parent()("%s eq 0" % self.name()).bool() + return str(self.parent()("%s eq 0" % self.name())) == "false" except TypeError: - # comparing with 0 didn't work; try comparing with + # comparing with 0 didn't work; try comparing with false try: - return not self.parent()("%s eq false" % self.name()).bool() + return str(self.parent()("%s eq false" % self.name())) == "false" except TypeError: pass return True diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index c28476fe7c9..745aff077ab 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -2133,7 +2133,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if If polymake raises an error, the polymake *interface* raises a :class:`PolymakeError`:: - sage: polymake.eval('FOOBAR(3);') # optional - polymake + sage: polymake.eval('FOOBAR(3);') # optional - polymake_expect Traceback (most recent call last): ... PolymakeError: Undefined subroutine &Polymake::User::FOOBAR called... @@ -2141,17 +2141,17 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if 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 + sage: polymake.eval('print 3') # optional - polymake_expect Traceback (most recent call last): ... SyntaxError: Incomplete polymake command 'print 3' - sage: polymake.eval('print 3;') # optional - polymake + sage: polymake.eval('print 3;') # optional - polymake_expect '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 + sage: print(polymake.eval('$tmp="abc";\nprint $tmp;')) # optional - polymake_expect abc When requesting help, polymake sometimes expect the user to choose @@ -2159,7 +2159,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if 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 + sage: print(polymake.eval('help "TRIANGULATION";')) # optional - polymake_expect # random doctest:warning ... UserWarning: Polymake expects user interaction. We abort and return diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index d74b433c439..facc4ad667e 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -14,6 +14,11 @@ - ``sage -i database_knotinfo`` (does not install if the current version is present) - ``sage -f database_knotinfo`` (installs even if the current version is present) +This will install a `Python wrapper `__ +for the original databases in Sage. This wrapper perfoms an automatic progress +of version numbers. For more details and further install instructions please see +the correspondig web-page. + To perform all the doctests concerning the usage of the database on the installation add the option ``-c``. In this case (for instance ``sage -f -c database_knotinfo``) the installation breaks on failing tests. @@ -79,7 +84,7 @@ Obtaining an instance of :class:`~sage.groups.braid.Braid`:: sage: L.braid() - s0*s1^-1*s2*s1^-1*s0^-1*s1^-1*s2^-1*s1^-1 + s1^-2*s0^-1*s1*s0^-1 sage: type(_) @@ -255,9 +260,9 @@ def eval_knotinfo(string, locals={}, to_tuple=True): sage: from sage.knots.knotinfo import KnotInfo, eval_knotinfo sage: L = KnotInfo.L4a1_0 sage: L.braid_notation(original=True) - '{4, {1, -2, 3, -2, -1, -2, -3, -2}}' + '{3, {-2, -2, -1, 2, -1}}' sage: eval_knotinfo(_) - (4, (1, -2, 3, -2, -1, -2, -3, -2)) + (3, (-2, -2, -1, 2, -1)) """ if to_tuple: new_string = string.replace('{', '(') @@ -348,7 +353,7 @@ def items(self): sage: L = KnotInfo.L4a1_0 sage: it = L.items sage: [i.name for i in it if i.name.startswith('braid')] - ['braid_index', 'braid_length', 'braid_notation'] + ['braid_index', 'braid_length', 'braid_notation', 'braid_notation_old'] sage: L.items.dt_notation.column_name() 'DT Notation' @@ -376,7 +381,7 @@ def __getitem__(self, item): sage: L[L.items.arc_notation] '{{6, 4}, {3, 5}, {4, 2}, {1, 3}, {2, 6}, {5, 1}}' sage: L[L.items.braid_notation] - '{4, {1, -2, 3, -2, -1, -2, -3, -2}}' + '{3, {-2, -2, -1, 2, -1}}' sage: L[0] Traceback (most recent call last): ... @@ -425,7 +430,7 @@ def _braid_group(self): sage: from sage.knots.knotinfo import KnotInfo sage: L = KnotInfo.L4a1_0 sage: L._braid_group() - Braid group on 4 strands + Braid group on 3 strands """ n = self.braid_index() if n == 1: @@ -589,13 +594,22 @@ def braid_notation(self, original=False): Python tuple representing the braid whose closure is ``self`` in Tietze form. + ..NOTE:: + + There has been a major change to braid representatives for + proper links since version 2021.10.1. The former braid + reresentatives can be obtained by the column + ``braid_notation_old`` (see the final example below). + EXAMPLES:: sage: from sage.knots.knotinfo import KnotInfo sage: L = KnotInfo.L4a1_0 sage: L.braid_notation() - (1, -2, 3, -2, -1, -2, -3, -2) + (-2, -2, -1, 2, -1) sage: L.braid_notation(original=True) + '{3, {-2, -2, -1, 2, -1}}' + sage: L[L.items.braid_notation_old] '{4, {1, -2, 3, -2, -1, -2, -3, -2}}' """ braid_notation = self[self.items.braid_notation] @@ -640,7 +654,7 @@ def braid_index(self): sage: from sage.knots.knotinfo import KnotInfo sage: L = KnotInfo.L4a1_0 sage: L.braid_index() - 4 + 3 """ if self.is_knot(): return int(self[self.items.braid_index]) @@ -720,7 +734,7 @@ def crossing_number(self): sage: KnotInfo.K3_1.crossing_number() 3 sage: Link(KnotInfo.L4a1_0.braid()) - Link with 2 components represented by 8 crossings + Link with 2 components represented by 5 crossings """ return int(self[self.items.crossing_number]) @@ -946,9 +960,9 @@ def is_amphicheiral(self, positive=False): False sage: KnotInfo.L10n59_1.is_amphicheiral() # optional - database_knotinfo True - sage: KnotInfo.L10n59_0.inject() # optional - database_knotinfo - Defining L10n59_0 - sage: L10n59_0.is_amphicheiral() is None # optional - database_knotinfo + sage: KnotInfo.L10n36_0.inject() # optional - database_knotinfo + Defining L10n36_0 + sage: L10n36_0.is_amphicheiral() is None # optional - database_knotinfo True """ if self.is_knot(): @@ -1705,7 +1719,7 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): observe:: sage: L.link(use_item=L.items.braid_notation) - Link with 2 components represented by 8 crossings + Link with 2 components represented by 5 crossings sage: K6_1 = KnotInfo.K6_1 sage: K6_1.link().braid() == K6_1.braid() @@ -1776,14 +1790,14 @@ def is_unique(self): True sage: KnotInfo.L5a1_0.is_unique() False - sage: L = KnotInfo.L7a7_0_0 # optional - database_knotinfo + sage: L = KnotInfo.L9a43_0_1 # optional - database_knotinfo sage: L.series(oriented=True).inject() # optional - database_knotinfo - Defining L7a7 - sage: [(L,L.is_unique()) for L in L7a7] # optional - database_knotinfo - [(, False), - (, None), - (, False), - (, True)] + Defining L9a43 + sage: [(L,L.is_unique()) for L in L9a43] # optional - database_knotinfo + [(, True), + (, False), + (, None), + (, False)] """ # an isotopic pair must have the same unoriented name. So, we can focus # on such series diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index eadb7f9f7c7..90289e29d66 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -3746,40 +3746,41 @@ def get_knotinfo(self, mirror_version=True, unique=True): sage: k11 = KnotInfo.K11n_82.link() # optional - database_knotinfo sage: k11m = k11.mirror_image() # optional - database_knotinfo - sage: k11m.braid() # optional - database_knotinfo - s0*s1^-1*s0*s2^-1*s1*(s1*s2^-1)^2*s2^-2 - sage: k11m.get_knotinfo() # optional - database_knotinfo + sage: k11mr = k11m.reverse() # optional - database_knotinfo + sage: k11mr.get_knotinfo() # optional - database_knotinfo Traceback (most recent call last): ... NotImplementedError: mirror type of this link cannot be uniquely determined use keyword argument `unique` to obtain more details - sage: k11m.get_knotinfo(unique=False) # optional - database_knotinfo + sage: k11mr.get_knotinfo(unique=False) # optional - database_knotinfo [(, '?')] - sage: t = (-1, 2, -1, 2, -1, 3, -2, 3, -2) - sage: l9 = Link(BraidGroup(4)(t)) - sage: l9.get_knotinfo() # optional - database_knotinfo + sage: t = (1, -2, 1, 1, -2, 1, -2, -2) + sage: l8 = Link(BraidGroup(3)(t)) + sage: l8.get_knotinfo() # optional - database_knotinfo Traceback (most recent call last): ... NotImplementedError: this link cannot be uniquely determined use keyword argument `unique` to obtain more details - sage: l9.get_knotinfo(unique=False) # optional - database_knotinfo - [(, False), - (, False)] + sage: l8.get_knotinfo(unique=False) # optional - database_knotinfo + [(, None), + (, None)] - sage: t = (1, 2, 3, -4, 3, -2, -1, 3, -2, 3, -2, 3, -4, 3, -2) - sage: l15 = Link(BraidGroup(5)(t)) - sage: l15.get_knotinfo() # optional - database_knotinfo + sage: t = (2, -3, -3, -2, 3, 3, -2, 3, 1, -2, -2, 1) + sage: l12 = Link(BraidGroup(5)(t)) + sage: l12.get_knotinfo() # optional - database_knotinfo Traceback (most recent call last): ... NotImplementedError: this link having more than 11 crossings cannot be uniquely determined use keyword argument `unique` to obtain more details - sage:l15.get_knotinfo(unique=False) # optional - database_knotinfo - [(, False), - (, False)] + sage: l12.get_knotinfo(unique=False) # optional - database_knotinfo + [(, '?'), + (, None), + (, None), + (, None)] Furthermore, if the result is a complete series of oriented links having the same unoriented name (according to the note above) the option can be diff --git a/src/sage/libs/mpmath/utils.pyx b/src/sage/libs/mpmath/utils.pyx index ea5aa54bfc8..ed771bb1958 100644 --- a/src/sage/libs/mpmath/utils.pyx +++ b/src/sage/libs/mpmath/utils.pyx @@ -406,7 +406,7 @@ def call(func, *args, **kwargs): sage: a.call(a.polylog, 2, 1/2, parent=RDF) 0.5822405264650125 sage: type(_) - + Check that :trac:`11885` is fixed:: diff --git a/src/sage/libs/pari/__init__.py b/src/sage/libs/pari/__init__.py index bc20d9bdf3d..ba4c5ad0efd 100644 --- a/src/sage/libs/pari/__init__.py +++ b/src/sage/libs/pari/__init__.py @@ -173,6 +173,12 @@ """ def _get_pari_instance(): + """ + TESTS:: + + sage: pari # indirect doctest + Interface to the PARI C library + """ from cypari2 import Pari stack_initial = 1024*1024 stack_max = 1024*stack_initial diff --git a/src/sage/libs/pari/convert_sage_complex_double.pxd b/src/sage/libs/pari/convert_sage_complex_double.pxd new file mode 100644 index 00000000000..51299d77759 --- /dev/null +++ b/src/sage/libs/pari/convert_sage_complex_double.pxd @@ -0,0 +1,13 @@ +from cypari2.gen cimport Gen +from sage.rings.complex_double cimport ComplexDoubleElement + +cpdef ComplexDoubleElement pari_to_cdf(Gen g) + +cpdef Gen new_gen_from_complex_double_element(ComplexDoubleElement self) + +cpdef ComplexDoubleElement complex_double_element_eta(ComplexDoubleElement self, int flag) +cpdef ComplexDoubleElement complex_double_element_agm(ComplexDoubleElement self, right) +cpdef ComplexDoubleElement complex_double_element_dilog(ComplexDoubleElement self) +cpdef ComplexDoubleElement complex_double_element_gamma(ComplexDoubleElement self) +cpdef ComplexDoubleElement complex_double_element_gamma_inc(ComplexDoubleElement self, t) +cpdef ComplexDoubleElement complex_double_element_zeta(ComplexDoubleElement self) diff --git a/src/sage/libs/pari/convert_sage_complex_double.pyx b/src/sage/libs/pari/convert_sage_complex_double.pyx new file mode 100644 index 00000000000..ef12c81f5e2 --- /dev/null +++ b/src/sage/libs/pari/convert_sage_complex_double.pyx @@ -0,0 +1,129 @@ +from cysignals.signals cimport sig_on, sig_off + +from sage.libs.gsl.complex cimport * + +from cypari2.paridecl cimport * +from cypari2.convert cimport new_gen_from_double, new_t_COMPLEX_from_double + + +cpdef ComplexDoubleElement pari_to_cdf(Gen g): + """ + Create a CDF element from a PARI ``gen``. + + EXAMPLES:: + + sage: CDF(pari("Pi")) # indirect doctest + 3.141592653589793 + sage: CDF(pari("1 + I/2")) + 1.0 + 0.5*I + + TESTS: + + Check that we handle PARI errors gracefully, see :trac:`17329`:: + + sage: CDF(-151.386325246 + 992.34771962*I).zeta() + Traceback (most recent call last): + ... + PariError: overflow in t_REAL->double conversion + sage: CDF(pari(x^2 + 5)) + Traceback (most recent call last): + ... + PariError: incorrect type in gtofp (t_POL) + """ + cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) + sig_on() + if typ(g.g) == t_COMPLEX: + z._complex = gsl_complex_rect(gtodouble(gel(g.g, 1)), gtodouble(gel(g.g, 2))) + else: + z._complex = gsl_complex_rect(gtodouble(g.g), 0.0) + sig_off() + return z + + +cpdef Gen new_gen_from_complex_double_element(ComplexDoubleElement self): + """ + Return PARI version of ``self``, as ``t_COMPLEX`` or ``t_REAL``. + + EXAMPLES:: + + sage: from sage.libs.pari.convert_sage_complex_double import new_gen_from_complex_double_element + sage: new_gen_from_complex_double_element(CDF(1,0)) + 1.00000000000000 + sage: new_gen_from_complex_double_element(CDF(0,1)) + 1.00000000000000*I + sage: new_gen_from_complex_double_element(CDF(1,1)) + 1.00000000000000 + 1.00000000000000*I + """ + if not GSL_IMAG(self._complex): + return new_gen_from_double(GSL_REAL(self._complex)) + else: + return new_t_COMPLEX_from_double(GSL_REAL(self._complex), GSL_IMAG(self._complex)) + + +cpdef ComplexDoubleElement complex_double_element_eta(ComplexDoubleElement self, int flag): + """ + TESTS:: + + sage: from sage.libs.pari.convert_sage_complex_double import complex_double_element_eta + sage: a = CDF(1,1) + sage: complex_double_element_eta(a, 0) + 0.9981290699259585 + sage: complex_double_element_eta(a, 1) + 0.7420487758365647 + 0.1988313702299107*I + """ + return pari_to_cdf(new_gen_from_complex_double_element(self).eta(flag)) + + +cpdef ComplexDoubleElement complex_double_element_agm(ComplexDoubleElement self, right): + """ + TESTS:: + + sage: from sage.libs.pari.convert_sage_complex_double import complex_double_element_agm + sage: complex_double_element_agm(CDF(1, 1), CDF(2, 2)) + 1.4567910310469068 + 1.4567910310469068*I + """ + return pari_to_cdf(new_gen_from_complex_double_element(self).agm(right)) + + +cpdef ComplexDoubleElement complex_double_element_dilog(ComplexDoubleElement self): + """ + TESTS:: + + sage: from sage.libs.pari.convert_sage_complex_double import complex_double_element_dilog + sage: complex_double_element_dilog(CDF(1, 1)) + 0.6168502750680849 + 1.4603621167531196*I + """ + return pari_to_cdf(new_gen_from_complex_double_element(self).dilog()) + + +cpdef ComplexDoubleElement complex_double_element_gamma(ComplexDoubleElement self): + """ + TESTS:: + + sage: from sage.libs.pari.convert_sage_complex_double import complex_double_element_gamma + sage: complex_double_element_gamma(CDF(1, 1)) + 0.49801566811835607 - 0.15494982830181067*I + """ + return pari_to_cdf(new_gen_from_complex_double_element(self).gamma()) + + +cpdef ComplexDoubleElement complex_double_element_gamma_inc(ComplexDoubleElement self, t): + """ + TESTS:: + + sage: from sage.libs.pari.convert_sage_complex_double import complex_double_element_gamma_inc + sage: complex_double_element_gamma_inc(CDF(1, 1), CDF(2, 2)) + 0.054695987717541285 - 0.04676800059213122*I + """ + return pari_to_cdf(new_gen_from_complex_double_element(self).incgam(t)) + + +cpdef ComplexDoubleElement complex_double_element_zeta(ComplexDoubleElement self): + """ + TESTS:: + + sage: from sage.libs.pari.convert_sage_complex_double import complex_double_element_zeta + sage: complex_double_element_zeta(CDF(1, 2)) + 0.5981655697623818 - 0.35185474521784527*I + """ + return pari_to_cdf(new_gen_from_complex_double_element(self).zeta()) diff --git a/src/sage/libs/pari/convert_sage_real_double.pxd b/src/sage/libs/pari/convert_sage_real_double.pxd new file mode 100644 index 00000000000..12fa7418e69 --- /dev/null +++ b/src/sage/libs/pari/convert_sage_real_double.pxd @@ -0,0 +1,4 @@ +from cypari2.gen cimport Gen +from sage.rings.real_double cimport RealDoubleElement + +cpdef Gen new_gen_from_real_double_element(RealDoubleElement self) diff --git a/src/sage/libs/pari/convert_sage_real_double.pyx b/src/sage/libs/pari/convert_sage_real_double.pyx new file mode 100644 index 00000000000..6d7ffe7038e --- /dev/null +++ b/src/sage/libs/pari/convert_sage_real_double.pyx @@ -0,0 +1,13 @@ +from cypari2.convert cimport new_gen_from_double + +cpdef Gen new_gen_from_real_double_element(RealDoubleElement self): + """ + Return a PARI representation of ``self``. + + EXAMPLES:: + + sage: from sage.libs.pari.convert_sage_real_double import new_gen_from_real_double_element + sage: new_gen_from_real_double_element(RDF(-2.5)) + -2.50000000000000 + """ + return new_gen_from_double(self._value) diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index ce93c3b8cb2..4e85f2158c5 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -803,8 +803,11 @@ cdef init_libsingular(): error_messages = [] -# call the init routine +# Save/restore the PATH because libSingular clobbers it: +# https://github.com/Singular/Singular/issues/1119 +saved_PATH = os.environ["PATH"] init_libsingular() +os.environ["PATH"] = saved_PATH cdef void libsingular_error_callback(const_char_ptr s): _s = char_to_str(s) diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index 1b62341fc84..70250784db8 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -328,9 +328,9 @@ from sage.categories.fields import Fields from sage.categories.manifolds import Manifolds from sage.categories.homset import Hom +import sage.rings.abc from sage.rings.all import CC -from sage.rings.real_mpfr import RR, RealField_class -from sage.rings.complex_mpfr import ComplexField_class +from sage.rings.real_mpfr import RR from sage.misc.prandom import getrandbits from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer @@ -545,9 +545,9 @@ def __init__(self, n, name, field, structure, base_manifold=None, if field not in Fields(): raise TypeError("the argument 'field' must be a field") self._field = field - if isinstance(field, RealField_class): + if isinstance(field, sage.rings.abc.RealField): self._field_type = 'real' - elif isinstance(field, ComplexField_class): + elif isinstance(field, sage.rings.abc.ComplexField): self._field_type = 'complex' else: self._field_type = 'neither_real_nor_complex' @@ -2957,7 +2957,7 @@ def Manifold(dim, name, latex_name=None, field='real', structure='smooth', unique_tag = lambda: getrandbits(128)*_manifold_id if structure in ['topological', 'top']: - if field == 'real' or isinstance(field, RealField_class): + if field == 'real' or isinstance(field, sage.rings.abc.RealField): structure = RealTopologicalStructure() else: structure = TopologicalStructure() @@ -2985,7 +2985,7 @@ def Manifold(dim, name, latex_name=None, field='real', structure='smooth', "not compatible with a smooth structure") else: diff_degree = infinity - if field == 'real' or isinstance(field, RealField_class): + if field == 'real' or isinstance(field, sage.rings.abc.RealField): structure = RealDifferentialStructure() else: structure = DifferentialStructure() diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index 42a77c9f87e..49c0b72f1bd 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -37,9 +37,9 @@ from sage.structure.category_object import CategoryObject from sage.categories.vector_bundles import VectorBundles from sage.structure.unique_representation import UniqueRepresentation +import sage.rings.abc from sage.rings.all import CC -from sage.rings.real_mpfr import RR, RealField_class -from sage.rings.complex_mpfr import ComplexField_class +from sage.rings.real_mpfr import RR from sage.rings.integer import Integer from sage.manifolds.vector_bundle_fiber import VectorBundleFiber @@ -218,9 +218,9 @@ def __init__(self, rank, name, base_space, field='real', self._field_type = field else: self._field = field - if isinstance(field, RealField_class): + if isinstance(field, sage.rings.abc.RealField): self._field_type = 'real' - elif isinstance(field, ComplexField_class): + elif isinstance(field, sage.rings.abc.ComplexField): self._field_type = 'complex' else: self._field_type = 'neither_real_nor_complex' diff --git a/src/sage/matrix/args.pyx b/src/sage/matrix/args.pyx index 4d2a114328e..66bde8aa9e0 100644 --- a/src/sage/matrix/args.pyx +++ b/src/sage/matrix/args.pyx @@ -21,8 +21,6 @@ from cysignals.signals cimport sig_check MatrixSpace = None from sage.rings.integer_ring import ZZ -from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF from sage.structure.coerce cimport (coercion_model, is_numpy_type, py_scalar_parent) from sage.structure.element cimport Element, RingElement, Vector @@ -1070,6 +1068,9 @@ cdef class MatrixArgs: raise TypeError('numpy matrix must be either c_contiguous or f_contiguous') from .constructor import matrix + from sage.rings.real_double import RDF + from sage.rings.complex_double import CDF + if 'float32' in str_dtype: m = matrix(RDF, inrows, incols, 0) m._replace_self_with_numpy32(e) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 3a9fc7d802a..ad81b86142c 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -90,11 +90,6 @@ from sage.rings.number_field.number_field_base import is_NumberField from sage.rings.integer_ring import ZZ, is_IntegerRing from sage.rings.integer import Integer from sage.rings.rational_field import QQ, is_RationalField -from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF -from sage.rings.real_mpfr import RealField -from sage.rings.complex_mpfr import ComplexField -from sage.rings.finite_rings.integer_mod_ring import IntegerModRing import sage.rings.abc from sage.arith.numerical_approx cimport digits_to_bits from copy import copy @@ -1545,6 +1540,8 @@ cdef class Matrix(Matrix1): ring = self.base_ring() if algorithm is None: # Choose algorithm depending on base ring + from sage.rings.real_mpfr import RealField + from sage.rings.complex_mpfr import ComplexField is_complex = ComplexField(2).has_coerce_map_from(ring) if is_complex: if ring.is_exact(): @@ -15019,6 +15016,8 @@ cdef class Matrix(Matrix1): sage: matrix(CDF, 2, 2, sparse=True).norm(1) 0.0 """ + from sage.rings.real_double import RDF + from sage.rings.complex_double import CDF if self._nrows == 0 or self._ncols == 0: return RDF(0) @@ -15123,14 +15122,17 @@ cdef class Matrix(Matrix1): sage: _ = A.n() """ + from sage.rings.real_mpfr import RealField + from sage.rings.complex_mpfr import ComplexField + if prec is None: prec = digits_to_bits(digits) try: - return self.change_ring(sage.rings.real_mpfr.RealField(prec)) + return self.change_ring(RealField(prec)) except (TypeError, ValueError): # try to return a complex result - return self.change_ring(sage.rings.complex_mpfr.ComplexField(prec)) + return self.change_ring(ComplexField(prec)) def plot(self, *args, **kwds): """ diff --git a/src/sage/matrix/matrix_integer_dense_saturation.py b/src/sage/matrix/matrix_integer_dense_saturation.py index 87b55b6d7e6..b88e7b23472 100644 --- a/src/sage/matrix/matrix_integer_dense_saturation.py +++ b/src/sage/matrix/matrix_integer_dense_saturation.py @@ -111,7 +111,7 @@ def random_sublist_of_size(k, n): w = set([]) while len(w) < n: z = randrange(k) - if not z in w: + if z not in w: w.add(z) return sorted(w) diff --git a/src/sage/matrix/matrix_misc.py b/src/sage/matrix/matrix_misc.py index 72986685c1f..e68ba3ad0bc 100644 --- a/src/sage/matrix/matrix_misc.py +++ b/src/sage/matrix/matrix_misc.py @@ -19,7 +19,6 @@ #***************************************************************************** from sage.categories.fields import Fields -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing _Fields = Fields() @@ -270,6 +269,8 @@ def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): if prec == 0: raise ValueError('the argument `prec` must be a positive integer') + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + K = PolynomialRing(A.base_ring(), var) nrows = A.nrows() ncols = A.ncols() diff --git a/src/sage/matrix/misc.pyx b/src/sage/matrix/misc.pyx index c7fc1c70161..220f8866b0e 100644 --- a/src/sage/matrix/misc.pyx +++ b/src/sage/matrix/misc.pyx @@ -40,7 +40,7 @@ from sage.rings.rational_field import QQ from sage.rings.integer cimport Integer from sage.arith.all import previous_prime, CRT_basis -from sage.rings.real_mpfr cimport RealField_class +cimport sage.rings.abc from sage.rings.real_mpfr cimport RealNumber @@ -510,7 +510,7 @@ def hadamard_row_bound_mpfr(Matrix A): ... OverflowError: cannot convert float infinity to integer """ - if not isinstance(A.base_ring(), RealField_class): + if not isinstance(A.base_ring(), sage.rings.abc.RealField): raise TypeError("A must have base field an mpfr real field.") cdef RealNumber a, b diff --git a/src/sage/matroids/all.py b/src/sage/matroids/all.py index 27576e6889e..e647629c988 100644 --- a/src/sage/matroids/all.py +++ b/src/sage/matroids/all.py @@ -1,3 +1,10 @@ +""" +Matroids +""" +# install the docstring of this module to the containing package +from sage.misc.namespace_package import install_doc +install_doc(__package__, __doc__) + from sage.misc.lazy_import import lazy_import # from constructor import Matroid # import matroids_catalog as matroids diff --git a/src/sage/matroids/circuit_closures_matroid.pyx b/src/sage/matroids/circuit_closures_matroid.pyx index 4f8844ac5fc..2411e52fa81 100644 --- a/src/sage/matroids/circuit_closures_matroid.pyx +++ b/src/sage/matroids/circuit_closures_matroid.pyx @@ -276,9 +276,7 @@ cdef class CircuitClosuresMatroid(Matroid): sage: M = matroids.named_matroids.Vamos() sage: X = M._max_independent(set(['a', 'c', 'd', 'e', 'f'])) - sage: sorted(X) # py2 - ['a', 'd', 'e', 'f'] - sage: sorted(X) # py3 random + sage: sorted(X) # random ['a', 'd', 'e', 'f'] sage: M.is_independent(X) True diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index bdf12b12891..a2de93f9817 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -323,9 +323,7 @@ def Matroid(groundset=None, data=None, **kwds): sage: M = Matroid('abcd', circuits=['ab', 'acd']) sage: M.is_valid() True - sage: [sorted(C) for C in M.circuits()] # py2 - [['a']] - sage: [sorted(C) for C in M.circuits()] # py3 random + sage: [sorted(C) for C in M.circuits()] # random [['a']] @@ -609,11 +607,7 @@ def Matroid(groundset=None, data=None, **kwds): False sage: M.is_isomorphic(N) True - sage: Matrix(N) # py2 - [1 0 0 1 1 0] - [0 1 0 1 1 1] - [0 0 1 0 1 1] - sage: Matrix(N) # py3 random + sage: Matrix(N) # random [1 0 0 1 1 0] [0 1 0 1 1 1] [0 0 1 0 1 1] diff --git a/src/sage/matroids/dual_matroid.py b/src/sage/matroids/dual_matroid.py index a15117402ef..804e43f035b 100644 --- a/src/sage/matroids/dual_matroid.py +++ b/src/sage/matroids/dual_matroid.py @@ -188,9 +188,7 @@ def _max_independent(self, X): sage: M = matroids.named_matroids.Vamos().dual() sage: X = M._max_independent(set(['a', 'c', 'd', 'e', 'f'])) - sage: sorted(X) # py2 - ['a', 'c', 'd', 'e'] - sage: sorted(X) # py3 random + sage: sorted(X) # random ['a', 'c', 'd', 'e'] sage: M.is_independent(X) True @@ -267,9 +265,7 @@ def _max_coindependent(self, X): sage: M = matroids.named_matroids.Vamos().dual() sage: X = M._max_coindependent(set(['a', 'c', 'd', 'e', 'f'])) - sage: sorted(X) # py2 - ['a', 'd', 'e', 'f'] - sage: sorted(X) # py3 random + sage: sorted(X) # random ['a', 'd', 'e', 'f'] sage: M.is_coindependent(X) True diff --git a/src/sage/matroids/minor_matroid.py b/src/sage/matroids/minor_matroid.py index 88dea9cf1de..bc567d1d4ce 100644 --- a/src/sage/matroids/minor_matroid.py +++ b/src/sage/matroids/minor_matroid.py @@ -225,9 +225,7 @@ def _max_independent(self, X): sage: M = MinorMatroid(matroids.named_matroids.Vamos(), ....: contractions=set('c'), deletions={'b', 'f'}) sage: X = M._max_independent(set(['a', 'd', 'e', 'g'])) - sage: sorted(X) # py2 - ['a', 'd', 'e'] - sage: sorted(X) # py3 # random + sage: sorted(X) # random ['a', 'd', 'e'] sage: M.is_independent(X) True @@ -279,9 +277,7 @@ def _max_coindependent(self, X): sage: M = MinorMatroid(matroids.named_matroids.Vamos(), ....: contractions=set('c'), deletions={'b', 'f'}) sage: X = M._max_coindependent(set(['a', 'd', 'e', 'g'])) - sage: sorted(X) # py2 - ['d', 'g'] - sage: sorted(X) # py3 random + sage: sorted(X) # random ['d', 'g'] sage: M.is_coindependent(X) True diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index 62742ede0bf..f856e32c87d 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -62,9 +62,7 @@ def setprint(X): sage: from sage.matroids.advanced import setprint sage: L = [{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {4, 1, 3}] - sage: print(L) # py2 - [set([1, 2, 3]), set([1, 2, 4]), set([2, 3, 4]), set([1, 3, 4])] - sage: print(L) # py3 + sage: print(L) [{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {1, 3, 4}] sage: setprint(L) [{1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}] @@ -538,11 +536,7 @@ def lift_cross_ratios(A, lift_map=None): [6 1 0 0 1] [0 6 3 6 0] sage: Z = lift_cross_ratios(A, to_sixth_root_of_unity) - sage: Z # py2 - [ 1 0 1 1 1] - [ 1 1 0 0 z] - [ 0 1 -z -1 0] - sage: Z # py3 + sage: Z [ 1 0 1 1 1] [ 1 1 0 0 z] [ 0 -1 z 1 0] diff --git a/src/sage/misc/allocator.pxd b/src/sage/misc/allocator.pxd index fce3179c626..7945a75241f 100644 --- a/src/sage/misc/allocator.pxd +++ b/src/sage/misc/allocator.pxd @@ -1,3 +1,5 @@ from cpython.object cimport * +cdef hook_tp_functions_type(object t, newfunc tp_new, destructor tp_dealloc, bint useGC) + cdef hook_tp_functions(object global_dummy, newfunc tp_new, destructor tp_dealloc, bint useGC) diff --git a/src/sage/misc/allocator.pyx b/src/sage/misc/allocator.pyx index 1277f5a61d3..b7fafdce286 100644 --- a/src/sage/misc/allocator.pyx +++ b/src/sage/misc/allocator.pyx @@ -1,22 +1,11 @@ from cpython.ref cimport Py_INCREF -cdef hook_tp_functions(object global_dummy, newfunc tp_new, destructor tp_dealloc, bint useGC): +cdef _hook_tp_functions_type(PyTypeObject *t, newfunc tp_new, destructor tp_dealloc, bint useGC): """ Initialize the fast integer creation functions. """ cdef long flag - cdef PyObject* o = global_dummy - cdef PyTypeObject* t = Py_TYPE(global_dummy) - - # Make sure this never, ever gets collected. - # This is not necessary for cdef'ed variables as the global - # dummy integer, as such objects do not get automatically collected. - # In fact there is no obvious reason to prevent collection when Sage quits - # and we are certain no further call to the allocation function will be - # made; so this could be removed when the code is clean enough. - Py_INCREF(global_dummy) - # By default every object created in Pyrex is garbage # collected. This means it may have references to other objects # the Garbage collector has to look out for. We remove this flag @@ -34,3 +23,24 @@ cdef hook_tp_functions(object global_dummy, newfunc tp_new, destructor tp_deallo # to be constructed/destructed. t.tp_new = tp_new t.tp_dealloc = tp_dealloc + + +cdef hook_tp_functions_type(object tp, newfunc tp_new, destructor tp_dealloc, bint useGC): + cdef PyTypeObject *t = tp + _hook_tp_functions_type(t, tp_new, tp_dealloc, useGC) + + +cdef hook_tp_functions(object global_dummy, newfunc tp_new, destructor tp_dealloc, bint useGC): + """ + Initialize the fast integer creation functions. + """ + # Make sure this never, ever gets collected. + # This is not necessary for cdef'ed variables as the global + # dummy integer, as such objects do not get automatically collected. + # In fact there is no obvious reason to prevent collection when Sage quits + # and we are certain no further call to the allocation function will be + # made; so this could be removed when the code is clean enough. + Py_INCREF(global_dummy) + + cdef PyTypeObject* t = Py_TYPE(global_dummy) + _hook_tp_functions_type(t, tp_new, tp_dealloc, useGC) diff --git a/src/sage/misc/decorators.py b/src/sage/misc/decorators.py index 6810915ba6c..a41c8413bb8 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -416,10 +416,10 @@ def argspec(): argspec = sage_getargspec(func) def listForNone(l): - return l if not l is None else [] + return l if l is not None else [] newArgs = [self.name + opt for opt in self.options.keys()] - args = (argspec.args if not argspec.args is None else []) + newArgs - defaults = (argspec.defaults if not argspec.defaults is None else ()) \ + args = (argspec.args if argspec.args is not None else []) + newArgs + defaults = (argspec.defaults if argspec.defaults is not None else ()) \ + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason return ArgSpec(args, argspec.varargs, argspec.keywords, defaults) @@ -495,7 +495,7 @@ def wrapper(*args, **kwds): #special attribute _sage_argspec_ (see e.g. sage.misc.sageinspect) def argspec(): argspec = sage_getargspec(func) - args = ((argspec.args if not argspec.args is None else []) + + args = ((argspec.args if argspec.args is not None else []) + list(self.options)) defaults = (argspec.defaults or ()) + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 6ab5c6eeeab..09d1b05ced9 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -1680,7 +1680,7 @@ def round(x, ndigits=0): sage: q = round(sqrt(2),5); q 1.41421 sage: type(q) - + sage: q = round(sqrt(2)); q 1 sage: type(q) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index b7dbccdbcd8..5d5ac4e6fb3 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -80,8 +80,11 @@ def have_latex() -> bool: sage: have_latex() # random True """ - from sage.misc.sage_ostools import have_program - return have_program('latex') + from .superseded import deprecation + deprecation(32650, 'the function have_latex() is replaced by: ' + 'from sage.features.latex import latex;latex().is_present()') + from sage.features.latex import latex + return latex().is_present() @cached_function @@ -98,8 +101,11 @@ def have_pdflatex() -> bool: sage: have_pdflatex() # random True """ - from sage.misc.sage_ostools import have_program - return have_program('pdflatex') + from .superseded import deprecation + deprecation(32650, 'the function have_pdflatex() is replaced by: ' + 'from sage.features.latex import pdflatex;pdflatex().is_present()') + from sage.features.latex import pdflatex + return pdflatex().is_present() @cached_function @@ -116,8 +122,11 @@ def have_xelatex() -> bool: sage: have_xelatex() # random True """ - from sage.misc.sage_ostools import have_program - return have_program('xelatex') + from .superseded import deprecation + deprecation(32650, 'the function have_xelatex() is replaced by: ' + 'from sage.features.latex import xelatex;xelatex().is_present()') + from sage.features.latex import xelatex + return xelatex().is_present() @cached_function @@ -134,9 +143,11 @@ def have_dvipng() -> bool: sage: have_dvipng() # random True """ - from sage.misc.sage_ostools import have_program - return have_program('dvipng') - + from .superseded import deprecation + deprecation(32650, 'the function have_dvipng() is replaced by: ' + 'from sage.features.dvipng import dvipng;dvipng().is_present()') + from sage.features.dvipng import dvipng + return dvipng().is_present() @cached_function def have_convert() -> bool: @@ -153,8 +164,11 @@ def have_convert() -> bool: sage: have_convert() # random True """ - from sage.misc.sage_ostools import have_program - return have_program('convert') + from .superseded import deprecation + deprecation(32650, 'the function have_convert() is replaced by: ' + 'from sage.features.imagemagick import imagemagick;imagemagick().is_present()') + from sage.features.imagemagick import ImageMagick + return ImageMagick().is_present() def list_function(x): @@ -693,34 +707,28 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i sage: file = os.path.join(SAGE_TMP, "temp.tex") sage: with open(file, 'w') as O: ....: _ = O.write(_latex_file_([ZZ['x'], RR])) - sage: _run_latex_(file) # random - depends on whether latex is installed + sage: _run_latex_(file) # random, optional - latex 'dvi' """ if engine is None: engine = _Latex_prefs._option["engine"] if not engine or engine == "latex": - if not have_latex(): - print("Error: LaTeX does not seem to be installed. Download it from") - print("ctan.org and try again.") - return "Error" + from sage.features.latex import latex + latex().require() command = "latex" # 'suffix' is used in the 'convert' command list suffix = "ps" return_suffix = "dvi" elif engine == "pdflatex": - if not have_pdflatex(): - print("Error: PDFLaTeX does not seem to be installed. Download it from") - print("ctan.org and try again.") - return "Error" + from sage.features.latex import pdflatex + pdflatex().require() command = "pdflatex" suffix = "pdf" return_suffix = "pdf" elif engine == "xelatex": - if not have_xelatex(): - print("Error: XeLaTeX does not seem to be installed. Download it from") - print("ctan.org and try again.") - return "Error" + from sage.features.latex import xelatex + xelatex().require() command = "xelatex" suffix = "pdf" return_suffix = "pdf" @@ -728,8 +736,11 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i raise ValueError("Unsupported LaTeX engine.") # if png output + latex, check to see if dvipng or convert is installed. + from sage.features.imagemagick import ImageMagick + from sage.features.dvipng import dvipng if png: - if (not engine or engine == "latex") and not (have_dvipng() or have_convert()): + if ((not engine or engine == "latex") + and not (dvipng().is_present() or ImageMagick().is_present())): print() print("Error: neither dvipng nor convert (from the ImageMagick suite)") print("appear to be installed. Displaying LaTeX, PDFLaTeX output") @@ -740,22 +751,10 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i print("http://www.imagemagick.org to download these programs.") return "Error" # if png output + pdflatex, check to see if convert is installed. - elif engine == "pdflatex" and not have_convert(): - print() - print("Error: convert (from the ImageMagick suite) does not") - print("appear to be installed. Displaying PDFLaTeX output") - print("requires this program, so please install and try again.") - print() - print("Go to http://www.imagemagick.org to download it.") - return "Error" - elif engine == "xelatex" and not have_convert(): - print() - print("Error: convert (from the ImageMagick suite) does not") - print("appear to be installed. Displaying XeLaTeX output") - print("requires this program, so please install and try again.") - print() - print("Go to http://www.imagemagick.org to download it.") - return "Error" + elif engine == "pdflatex": + ImageMagick().require() + elif engine == "xelatex": + ImageMagick().require() # check_validity: check to see if the dvi file is okay by trying # to convert to a png file. if this fails, return_suffix will be # set to "pdf". return_suffix is the return value for this @@ -764,7 +763,7 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i # thus if not png output, check validity of dvi output if dvipng # or convert is installed. else: - check_validity = have_dvipng() + check_validity = dvipng().is_present() # set up filenames, other strings: base, filename = os.path.split(filename) filename = os.path.splitext(filename)[0] # get rid of extension @@ -817,7 +816,7 @@ def subpcall(x): e = e and subpcall(convert) else: # latex if (png or check_validity): - if have_dvipng(): + if dvipng().is_present(): if debug: print(lt) print(dvipng) @@ -830,7 +829,7 @@ def subpcall(x): # fail also, so we'll still catch the error.) if dvipng_error: if png: - if have_convert(): + if ImageMagick().is_present(): if debug: print("'dvipng' failed; trying 'convert' instead...") print(dvips) @@ -1966,7 +1965,7 @@ def png(x, filename, density=150, debug=False, EXAMPLES:: sage: from sage.misc.latex import png - sage: png(ZZ[x], os.path.join(SAGE_TMP, "zz.png")) # random - error if no latex + sage: png(ZZ[x], os.path.join(SAGE_TMP, "zz.png")) # random, optional - latex """ if not pdflatex: engine = "latex" diff --git a/src/sage/misc/namespace_package.py b/src/sage/misc/namespace_package.py new file mode 100644 index 00000000000..75d9f1d8dcc --- /dev/null +++ b/src/sage/misc/namespace_package.py @@ -0,0 +1,20 @@ +""" +Utility functions for namespace packages in Sage +""" +from importlib import import_module + +def install_doc(package, doc): + """ + Install the docstring ``doc`` to the package. + + TESTS: + + sage: from sage.misc.namespace_package import install_doc + sage: install_doc('sage', 'hello') + sage: from inspect import getdoc + sage: getdoc(sage) + 'hello' + """ + pkg = import_module(package) + pkg.__doc__ = doc # enable sage.package? + pkg.getdoc = lambda: doc # enable help(sage.package) diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index c42435101c5..0d2c2f5818f 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -40,6 +40,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from typing import Dict, List, NamedTuple, Optional, Union import sage.env @@ -160,14 +161,13 @@ def pip_installed_packages(normalization=None): ) stdout = proc.communicate()[0].decode() - def normalize(name): + def normalize(name: str) -> str: if normalization is None: return name elif normalization == 'spkg': return name.lower().replace('-', '_').replace('.', '_') else: raise NotImplementedError(f'normalization {normalization} is not implemented') - try: return {normalize(package['name']): package['version'] for package in json.loads(stdout)} @@ -176,12 +176,56 @@ def normalize(name): # This may happen if pip is not correctly installed. return {} -def list_packages(*pkg_types, **opts): + +class PackageInfo(NamedTuple): + """Represents information about a package.""" + name: str + type: Optional[str] = None + source: Optional[str] = None + installed_version: Optional[str] = None + remote_version: Optional[str] = None + + def is_installed(self) -> bool: + r""" + Whether the package is installed in the system. + """ + return self.installed_version is not None + + def __getitem__(self, key: Union[int, str]): + r""" + Only for backwards compatibility to allow dict-like access. + + TESTS:: + + sage: from sage.misc.package import PackageInfo + sage: package = PackageInfo("test_package") + sage: package["name"] + doctest:warning... + dict-like access is deprecated, use pkg.name instead of pkg['name'], for example + See https://trac.sagemath.org/31013 for details. + 'test_package' + sage: package[0] + 'test_package' + """ + if isinstance(key, str): + from sage.misc.superseded import deprecation + + if key == "installed": + deprecation(31013, "dict-like access via 'installed' is deprecated, use method is_installed instead") + return self.is_installed() + else: + deprecation(31013, "dict-like access is deprecated, use pkg.name instead of pkg['name'], for example") + return self.__getattribute__(key) + else: + return tuple.__getitem__(self, key) + + +def list_packages(*pkg_types: str, pkg_sources: List[str] = ['normal', 'pip', 'script'], + local: bool = False, ignore_URLError: bool = False, exclude_pip: bool = False) -> Dict[str, PackageInfo]: r""" Return a dictionary of information about each package. - The keys are package names and values are dictionaries with the following - keys: + The keys are package names and values are named tuples with the following keys: - ``'type'``: either ``'base``, ``'standard'``, ``'optional'``, or ``'experimental'`` - ``'source'``: either ``'normal', ``'pip'``, or ``'script'`` @@ -213,32 +257,32 @@ def list_packages(*pkg_types, **opts): EXAMPLES:: sage: from sage.misc.package import list_packages - sage: L = list_packages('standard') # optional - build - sage: sorted(L.keys()) # optional - build, random + sage: L = list_packages('standard') # optional - build + sage: sorted(L.keys()) # optional - build, random ['alabaster', 'arb', 'babel', ... 'zn_poly'] sage: sage_conf_info = L['sage_conf'] # optional - build - sage: sage_conf_info['type'] # optional - build + sage: sage_conf_info.type # optional - build 'standard' - sage: sage_conf_info['installed'] # optional - build + sage: sage_conf_info.is_installed() # optional - build True - sage: sage_conf_info['source'] # optional - build + sage: sage_conf_info.source # optional - build 'script' sage: L = list_packages(pkg_sources=['pip'], local=True) # optional - build internet sage: bs4_info = L['beautifulsoup4'] # optional - build internet - sage: bs4_info['type'] # optional - build internet + sage: bs4_info.type # optional - build internet 'optional' - sage: bs4_info['source'] # optional - build internet + sage: bs4_info.source # optional - build internet 'pip' Check the option ``exclude_pip``:: sage: [p for p, d in list_packages('optional', exclude_pip=True).items() # optional - build - ....: if d['source'] == 'pip'] + ....: if d.source == 'pip'] [] """ if not pkg_types: @@ -246,21 +290,13 @@ def list_packages(*pkg_types, **opts): elif any(pkg_type not in ('base', 'standard', 'optional', 'experimental') for pkg_type in pkg_types): raise ValueError("Each pkg_type must be one of 'base', 'standard', 'optional', 'experimental'") - pkg_sources = opts.pop('pkg_sources', - ('normal', 'pip', 'script')) - - local = opts.pop('local', False) - ignore_URLError = opts.pop('ignore_URLError', False) - exclude_pip = opts.pop('exclude_pip', False) if exclude_pip: pkg_sources = [s for s in pkg_sources if s != 'pip'] - if opts: - raise ValueError("{} are not valid options".format(sorted(opts))) - pkgs = {p: {'name': p, 'installed_version': v, 'installed': True, - 'remote_version': None, 'source': None} + pkgs = {p: PackageInfo(name=p, installed_version=v) for p, v in installed_packages('pip' not in pkg_sources).items()} + # Add additional information based on Sage's package repository lp = [] SAGE_PKGS = sage.env.SAGE_PKGS if not SAGE_PKGS: @@ -289,33 +325,29 @@ def list_packages(*pkg_types, **opts): else: src = 'script' - pkg = pkgs.get(p, dict()) - pkgs[p] = pkg - if typ not in pkg_types or src not in pkg_sources: - del pkgs[p] + try: + del pkgs[p] + except KeyError: + pass continue - pkg.update({'name': p, 'type': typ, 'source': src}) - if pkg.get('installed_version', None): - pkg['installed'] = True - else: - pkg['installed'] = False - pkg['installed_version'] = None - - if pkg['source'] == 'pip': + if src == 'pip': if not local: - pkg['remote_version'] = pip_remote_version(p, ignore_URLError=ignore_URLError) + remote_version = pip_remote_version(p, ignore_URLError=ignore_URLError) else: - pkg['remote_version'] = None - elif pkg['source'] == 'normal': + remote_version = None + elif src == 'normal': # If package-version.txt does not exist, that is an error # in the build system => we just propagate the exception package_filename = os.path.join(SAGE_PKGS, p, "package-version.txt") with open(package_filename) as f: - pkg['remote_version'] = f.read().strip() + remote_version = f.read().strip() else: - pkg['remote_version'] = 'none' + remote_version = None + + pkg = pkgs.get(p, PackageInfo(name=p)) + pkgs[p] = PackageInfo(p, typ, src, pkg.installed_version, remote_version) return pkgs @@ -444,7 +476,7 @@ def package_versions(package_type, local=False): sage: std['zn_poly'] # optional - build, random ('0.9.p12', '0.9.p12') """ - return {pkg['name']: (pkg['installed_version'], pkg['remote_version']) for pkg in list_packages(package_type, local=local).values()} + return {pkg.name: (pkg.installed_version, pkg.remote_version) for pkg in list_packages(package_type, local=local).values()} def standard_packages(): @@ -477,8 +509,8 @@ def standard_packages(): 'the functions standard_packages, optional_packages, experimental_packages' 'are deprecated, use sage.features instead') pkgs = list_packages('standard', local=True).values() - return (sorted(pkg['name'] for pkg in pkgs if pkg['installed']), - sorted(pkg['name'] for pkg in pkgs if not pkg['installed'])) + return (sorted(pkg.name for pkg in pkgs if pkg.is_installed()), + sorted(pkg.name for pkg in pkgs if not pkg.is_installed())) def optional_packages(): @@ -515,8 +547,8 @@ def optional_packages(): 'are deprecated, use sage.features instead') pkgs = list_packages('optional', local=True) pkgs = pkgs.values() - return (sorted(pkg['name'] for pkg in pkgs if pkg['installed']), - sorted(pkg['name'] for pkg in pkgs if not pkg['installed'])) + return (sorted(pkg.name for pkg in pkgs if pkg.is_installed()), + sorted(pkg.name for pkg in pkgs if not pkg.is_installed())) def experimental_packages(): @@ -547,8 +579,8 @@ def experimental_packages(): 'the functions standard_packages, optional_packages, experimental_packages' 'are deprecated, use sage.features instead') pkgs = list_packages('experimental', local=True).values() - return (sorted(pkg['name'] for pkg in pkgs if pkg['installed']), - sorted(pkg['name'] for pkg in pkgs if not pkg['installed'])) + return (sorted(pkg.name for pkg in pkgs if pkg.is_installed()), + sorted(pkg.name for pkg in pkgs if not pkg.is_installed())) def package_manifest(package): """ diff --git a/src/sage/misc/sage_input.py b/src/sage/misc/sage_input.py index ead63fd68b1..0f0d0a788fb 100644 --- a/src/sage/misc/sage_input.py +++ b/src/sage/misc/sage_input.py @@ -1011,9 +1011,9 @@ def gen(self, parent, n=0): R. = ZZ[] y """ - if not parent in self._parent_gens: + if parent not in self._parent_gens: self(parent) - if not parent in self._parent_gens: + if parent not in self._parent_gens: raise ValueError("{} did not register generators for sage_input".format(parent)) gens = self._parent_gens[parent] diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index e3821e84e76..e6f4ccfb514 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -571,7 +571,6 @@ def process_mathtt(s): s = s[:start] + s[start+8:end] + s[end+1:] return s - def format(s, embedded=False): r"""noreplace Format Sage documentation ``s`` for viewing with IPython. @@ -747,7 +746,6 @@ def format(s, embedded=False): s = detex(s, embedded=embedded) return s - def format_src(s): """ Format Sage source code ``s`` for viewing with IPython. @@ -959,7 +957,6 @@ def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', # formatted for Jupyter use }) - def search_src(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds): r""" @@ -1136,7 +1133,6 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', extra3=extra3, extra4=extra4, extra5=extra5, **kwds) - def search_doc(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds): r""" @@ -1306,7 +1302,6 @@ def format_search_as_html(what, results, search): return ''.join(s) - ####################################### ## Add detex'ing of documentation ####################################### diff --git a/src/sage/modular/abvar/lseries.py b/src/sage/modular/abvar/lseries.py index 046b305f3ff..11ca70142a5 100644 --- a/src/sage/modular/abvar/lseries.py +++ b/src/sage/modular/abvar/lseries.py @@ -22,7 +22,11 @@ ########################################################################### from sage.structure.sage_object import SageObject -from sage.rings.all import Integer, infinity, ZZ, QQ, CC +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer +from sage.rings.infinity import infinity +from sage.rings.all import CC from sage.modules.free_module import span from sage.misc.misc_c import prod diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index fc70a66e4e1..315af89f38b 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -1819,7 +1819,7 @@ def cusp_widths(self,exp=False): else: c2 = len(c) // 2 if exp: - if not c2 in widths: + if c2 not in widths: widths[c2] = 0 widths[c2] += 1 else: diff --git a/src/sage/modular/arithgroup/congroup_gammaH.py b/src/sage/modular/arithgroup/congroup_gammaH.py index 2a292556944..06b42989139 100644 --- a/src/sage/modular/arithgroup/congroup_gammaH.py +++ b/src/sage/modular/arithgroup/congroup_gammaH.py @@ -930,7 +930,7 @@ def _find_cusps(self): a += w c = self.reduce_cusp(Cusp(a,d)) h = hash(c) - if not h in hashes: + if h not in hashes: hashes.append(h) s.append(c) return sorted(s) @@ -1427,13 +1427,14 @@ def _GammaH_coset_helper(N, H): for i in range(1, N): if gcd(i, N) != 1: continue - if not i in W: + if i not in W: t.append(t[0]*i) - W = W + [i*h for h in HH] + W += [i*h for h in HH] if len(W) == k: break return t + def mumu(N): """ Return 0 if any cube divides `N`. Otherwise return @@ -1464,9 +1465,9 @@ def mumu(N): if N < 1: raise ValueError("N must be at least 1") p = 1 - for _,r in factor(N): + for _, r in factor(N): if r > 2: - return ZZ(0) + return ZZ.zero() elif r == 1: p *= -2 return ZZ(p) diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index 186f08e1998..c3d54a7d030 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -158,7 +158,7 @@ def _element_constructor_(self, x, check=True): (1,23) """ z = self.ambient_hecke_module()(x).element() - if check and not z in self.__submodule: + if check and z not in self.__submodule: raise TypeError("x does not coerce to an element of this Hecke module") return self.element_class(self, z) diff --git a/src/sage/modular/modform/ambient.py b/src/sage/modular/modform/ambient.py index daf783f8fe8..febb0be8d37 100644 --- a/src/sage/modular/modform/ambient.py +++ b/src/sage/modular/modform/ambient.py @@ -58,15 +58,15 @@ True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet @@ -86,6 +86,7 @@ from . import space from . import submodule + class ModularFormsAmbient(space.ModularFormsSpace, hecke.AmbientHeckeModule): """ @@ -103,13 +104,13 @@ def __init__(self, group, weight, base_ring, character=None, eis_only=False): True """ if not arithgroup.is_CongruenceSubgroup(group): - raise TypeError('group (=%s) must be a congruence subgroup'%group) + raise TypeError('group (=%s) must be a congruence subgroup' % group) weight = rings.Integer(weight) if character is None and arithgroup.is_Gamma0(group): character = dirichlet.TrivialCharacter(group.level(), base_ring) - self._eis_only=eis_only + self._eis_only = eis_only space.ModularFormsSpace.__init__(self, group, weight, character, base_ring) if eis_only: d = self._dim_eisenstein() @@ -135,10 +136,10 @@ def _repr_(self): 'Modular Forms space of dimension 1198 for Congruence Subgroup Gamma1(20) of weight 100 over Rational Field' """ if self._eis_only: - return "Modular Forms space for %s of weight %s over %s"%( + return "Modular Forms space for %s of weight %s over %s" % ( self.group(), self.weight(), self.base_ring()) else: - return "Modular Forms space of dimension %s for %s of weight %s over %s"%( + return "Modular Forms space of dimension %s for %s of weight %s over %s" % ( self.dimension(), self.group(), self.weight(), self.base_ring()) def _submodule_class(self): @@ -255,7 +256,7 @@ def _degeneracy_raising_matrix(self, M, t): im_gens = [] for x in self.basis(): fq = x.qexp(d) - fqt = fq(q**t).add_bigoh(d) # silly workaround for #5367 + fqt = fq(q**t).add_bigoh(d) # silly workaround for trac #5367 im_gens.append(M(fqt)) return A([M.coordinate_vector(u) for u in im_gens]) @@ -301,7 +302,7 @@ def is_ambient(self): """ return True - @cached_method(key=lambda self, sign: rings.Integer(sign)) # convert sign to an Integer before looking this up in the cache + @cached_method(key=lambda self, sign: rings.Integer(sign)) # convert sign to an Integer before looking this up in the cache def modular_symbols(self, sign=0): """ Return the corresponding space of modular symbols with the given @@ -323,10 +324,10 @@ def modular_symbols(self, sign=0): Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field """ sign = rings.Integer(sign) - return modsym.ModularSymbols(group = self.group(), - weight = self.weight(), - sign = sign, - base_ring = self.base_ring()) + return modsym.ModularSymbols(group=self.group(), + weight=self.weight(), + sign=sign, + base_ring=self.base_ring()) @cached_method def module(self): @@ -426,7 +427,7 @@ def set_precision(self, n): ] """ if n < 0: - raise ValueError("n (=%s) must be >= 0"%n) + raise ValueError("n (=%s) must be >= 0" % n) self.__prec = rings.Integer(n) #################################################################### @@ -460,7 +461,7 @@ def eisenstein_submodule(self): """ return eisenstein_submodule.EisensteinSubmodule(self) - @cached_method(key=lambda self, p: (rings.Integer(p) if p is not None else p)) # convert p to an Integer before looking this up in the cache + @cached_method(key=lambda self, p: (rings.Integer(p) if p is not None else p)) # convert p to an Integer before looking this up in the cache def new_submodule(self, p=None): """ Return the new or `p`-new submodule of this ambient @@ -510,10 +511,10 @@ def new_submodule(self, p=None): ... NotImplementedError """ - if not p is None: + if p is not None: p = rings.Integer(p) if not p.is_prime(): - raise ValueError("p (=%s) must be a prime or None."%p) + raise ValueError("p (=%s) must be a prime or None." % p) return self.cuspidal_submodule().new_submodule(p) + self.eisenstein_submodule().new_submodule(p) def _q_expansion(self, element, prec): @@ -798,9 +799,10 @@ def _compute_hecke_matrix(self, n): if d == 0: return matrix(self.base_ring(), 0, 0, []) from sage.modular.all import victor_miller_basis, hecke_operator_on_basis - vmb = victor_miller_basis(k, prec=d*n+1)[1:] + vmb = victor_miller_basis(k, prec=d * n + 1)[1:] Tcusp = hecke_operator_on_basis(vmb, n, k) - return Tcusp.block_sum(matrix(self.base_ring(), 1, 1, [sigma(n, k-1)])) + return Tcusp.block_sum(matrix(self.base_ring(), 1, 1, + [sigma(n, k - 1)])) else: return space.ModularFormsSpace._compute_hecke_matrix(self, n) @@ -844,4 +846,4 @@ def hecke_polynomial(self, n, var='x'): sage: ModularForms(17,4).hecke_matrix(2).charpoly() x^6 - 16*x^5 + 18*x^4 + 608*x^3 - 1371*x^2 - 4968*x + 7776 """ - return self.cuspidal_submodule().hecke_polynomial(n,var) * self.eisenstein_submodule().hecke_polynomial(n,var) + return self.cuspidal_submodule().hecke_polynomial(n, var) * self.eisenstein_submodule().hecke_polynomial(n, var) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 05abc12e1e5..505e7b324bf 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -3590,7 +3590,8 @@ def weight(self): def weights_list(self): r""" - Return the list of the weights of all the graded components of the given graded modular form. + Return the list of the weights of all the homogeneous components of the + given graded modular form. EXAMPLES:: @@ -3628,7 +3629,8 @@ def is_homogeneous(self): def _homogeneous_to_polynomial(self, names, gens): r""" - If ``self`` is a homogeneous form, return a polynomial `P(x_0,..., x_n)` corresponding to ``self``. + Return a polynomial `P(x_0,..., x_n)` corresponding to the given homogeneous graded form. + Each variable `x_i` of the returned polynomial correspond to a generator `g_i` of the list ``gens`` (following the order of the list) @@ -3744,3 +3746,66 @@ def to_polynomial(self, names='x', gens=None): # sum the polynomial of each homogeneous part return sum(M(self[k])._homogeneous_to_polynomial(names, gens) for k in self.weights_list()) + + def serre_derivative(self): + r""" + Return the Serre derivative of the given graded modular form. + + If ``self`` is a modular form of weight `k`, then the returned modular + form will be of weight `k + 2`. If the form is not homogeneous, then + this method sums the Serre derivative of each homogeneous component. + + EXAMPLES:: + + sage: M = ModularFormsRing(1) + sage: E4 = M.0 + sage: E6 = M.1 + sage: DE4 = E4.serre_derivative(); DE4 + -1/3 + 168*q + 5544*q^2 + 40992*q^3 + 177576*q^4 + 525168*q^5 + O(q^6) + sage: DE4 == (-1/3) * E6 + True + sage: DE6 = E6.serre_derivative(); DE6 + -1/2 - 240*q - 30960*q^2 - 525120*q^3 - 3963120*q^4 - 18750240*q^5 + O(q^6) + sage: DE6 == (-1/2) * E4^2 + True + sage: f = E4 + E6 + sage: Df = f.serre_derivative(); Df + -5/6 - 72*q - 25416*q^2 - 484128*q^3 - 3785544*q^4 - 18225072*q^5 + O(q^6) + sage: Df == (-1/3) * E6 + (-1/2) * E4^2 + True + sage: M(1/2).serre_derivative() + 0 + """ + M = self.parent() + return M(sum(M(f.serre_derivative()) for k, f in self._forms_dictionary.items() if k != 0)) + + def derivative(self, name='E2'): + r""" + Return the derivative `q \frac{d}{dq}` of the given graded form. + + Note that this method returns an element of a new parent, that is a + quasimodular form. If the form is not homogeneous, then this method sums + the derivative of each homogeneous component. + + INPUT: + + - ``name`` (str, default: 'E2') - the name of the weight 2 Eisenstein + series generating the graded algebra of quasimodular forms over the + ring of modular forms. + + OUTPUT: a :class:`sage.modular.quasimodform.element.QuasiModularFormsElement` + + EXAMPLES:: + + sage: M = ModularFormsRing(1) + sage: E4 = M.0; E6 = M.1 + sage: dE4 = E4.derivative(); dE4 + 240*q + 4320*q^2 + 20160*q^3 + 70080*q^4 + 151200*q^5 + O(q^6) + sage: dE4.parent() + Ring of Quasimodular Forms for Modular Group SL(2,Z) over Rational Field + sage: dE4.is_modular_form() + False + """ + from sage.modular.quasimodform.ring import QuasiModularForms + F = QuasiModularForms(self.group(), self.base_ring(), name)(self) + return F.derivative() diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 6d22fe7ab01..387d87f1b05 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -16,7 +16,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import FractionField, PolynomialRing, PowerSeriesRing, ZZ, QQ, infinity +from sage.rings.infinity import infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.all import FractionField, PolynomialRing, PowerSeriesRing from sage.algebras.free_algebra import FreeAlgebra from sage.structure.parent import Parent diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index fcfaab1e788..e073fc1b42c 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -16,7 +16,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ, QQ, infinity, AlgebraicField, I +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity +from sage.rings.all import AlgebraicField, I from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.power_series_ring import is_PowerSeriesRing from sage.rings.laurent_series_ring import is_LaurentSeriesRing diff --git a/src/sage/modular/modform_hecketriangle/constructor.py b/src/sage/modular/modform_hecketriangle/constructor.py index 6a292e63b3f..5423fc47564 100644 --- a/src/sage/modular/modform_hecketriangle/constructor.py +++ b/src/sage/modular/modform_hecketriangle/constructor.py @@ -16,7 +16,10 @@ # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ, QQ, infinity, PolynomialRing, FractionField +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity +from sage.rings.all import PolynomialRing, FractionField def rational_type(f, n=ZZ(3), base_ring=ZZ): diff --git a/src/sage/modular/modform_hecketriangle/functors.py b/src/sage/modular/modform_hecketriangle/functors.py index 103915c1af2..989f7b8e30e 100644 --- a/src/sage/modular/modform_hecketriangle/functors.py +++ b/src/sage/modular/modform_hecketriangle/functors.py @@ -16,7 +16,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ, QQ, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity from sage.categories.functor import Functor from sage.categories.pushout import ConstructionFunctor diff --git a/src/sage/modular/modform_hecketriangle/graded_ring.py b/src/sage/modular/modform_hecketriangle/graded_ring.py index 03552c409ad..42325e3423e 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring.py @@ -16,7 +16,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity from sage.rings.ring import CommutativeAlgebra from sage.categories.all import CommutativeAlgebras diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index 9aa07153f3e..8e6ccad2491 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -16,11 +16,12 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ, infinity, LaurentSeries, O +from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity +from sage.rings.all import LaurentSeries, O from sage.misc.lazy_import import lazy_import lazy_import("sage.functions.all", "exp") from sage.rings.number_field.number_field import QuadraticField -from sage.misc.lazy_import import lazy_import lazy_import("sage.symbolic.all", "pi") from sage.structure.parent_gens import localvars diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index c2b9899602d..cf230339323 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -20,7 +20,9 @@ from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method -from sage.rings.all import AA, QQbar, ZZ, infinity, CC +from sage.rings.integer_ring import ZZ +from sage.rings.infinity import infinity +from sage.rings.all import AA, QQbar, CC from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index f7ced901783..6fe3ebd56b1 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -16,12 +16,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ, QQ, AA, AlgebraicField, infinity, I, PolynomialRing, NumberField +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity +from sage.rings.all import AA, AlgebraicField, I, PolynomialRing, NumberField from sage.misc.lazy_import import lazy_import lazy_import("sage.functions.all", "cos", "exp, sec") -from sage.misc.lazy_import import lazy_import lazy_import("sage.functions.gamma", "psi1") -from sage.misc.lazy_import import lazy_import lazy_import("sage.symbolic.all", "pi") from sage.matrix.constructor import matrix from sage.misc.latex import latex diff --git a/src/sage/modular/modform_hecketriangle/series_constructor.py b/src/sage/modular/modform_hecketriangle/series_constructor.py index 7a19f1a639e..3ed32e7d77e 100644 --- a/src/sage/modular/modform_hecketriangle/series_constructor.py +++ b/src/sage/modular/modform_hecketriangle/series_constructor.py @@ -20,7 +20,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ, QQ, infinity, PowerSeriesRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity +from sage.rings.all import PowerSeriesRing from sage.rings.big_oh import O from sage.arith.all import bernoulli, sigma, rising_factorial diff --git a/src/sage/modular/modform_hecketriangle/space.py b/src/sage/modular/modform_hecketriangle/space.py index 758b33420af..84323cf0ab9 100644 --- a/src/sage/modular/modform_hecketriangle/space.py +++ b/src/sage/modular/modform_hecketriangle/space.py @@ -16,7 +16,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ, QQ, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity from sage.modules.module import Module from sage.modules.free_module import FreeModule diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index a4b1378547e..4d818262a1c 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -31,7 +31,11 @@ import sage.modular.hecke.all as hecke from sage.arith.all import divisors, next_prime from sage.rings.fast_arith import prime_range -from sage.rings.all import PowerSeriesRing, Integer, QQ, ZZ, infinity, Zmod +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.integer import Integer +from sage.rings.infinity import infinity +from sage.rings.all import PowerSeriesRing, Zmod from sage.rings.number_field.number_field_base import is_NumberField from sage.structure.all import Sequence, SageObject from sage.structure.richcmp import (richcmp_method, richcmp, diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index 1a39e7fea33..8c5f36fa933 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -184,7 +184,10 @@ from sage.structure.element import Vector, ModuleElement from sage.structure.richcmp import richcmp from sage.plot.plot import plot -from sage.rings.all import (O, Infinity, ZZ, QQ, pAdicField, PolynomialRing, PowerSeriesRing, is_pAdicField) +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +import sage.rings.abc +from sage.rings.all import (O, Infinity, pAdicField, PolynomialRing, PowerSeriesRing) import weakref from .weightspace import WeightSpace_constructor as WeightSpace, WeightCharacter @@ -295,7 +298,7 @@ def __init__(self, prime, weight, radius, base_ring, prec, char): self._p = prime - if not ( base_ring == QQ or is_pAdicField(base_ring) ): + if not ( base_ring == QQ or isinstance(base_ring, sage.rings.abc.pAdicField) ): raise TypeError("Base ring must be QQ or a p-adic field") if base_ring != QQ and base_ring.prime() != self._p: @@ -1033,9 +1036,9 @@ def slopes(self, n, use_recurrence=False): [0, 2, 4, 6, 8] """ if self.base_ring() == QQ: - slopelist=self.cps_u(n).truncate().newton_slopes(self.prime()) - elif is_pAdicField(self.base_ring()): - slopelist=self.cps_u(n).truncate().newton_slopes() + slopelist = self.cps_u(n).truncate().newton_slopes(self.prime()) + elif isinstance(self.base_ring(), sage.rings.abc.pAdicField): + slopelist = self.cps_u(n).truncate().newton_slopes() else: print("slopes are only defined for base field QQ or a p-adic field") return [-i for i in slopelist] @@ -1574,7 +1577,7 @@ def r_ord(self, r): s = self.parent().radius() F = self.parent().base_ring() - if not is_pAdicField(F): + if not isinstance(F, sage.rings.abc.pAdicField): F = pAdicField(p) for i in range(self.prec()): @@ -1595,7 +1598,7 @@ def valuation(self): sage: (3^18 * (M.2)).valuation() 18 """ - if is_pAdicField(self.parent().base_ring()): + if isinstance(self.parent().base_ring(), sage.rings.abc.pAdicField): v = lambda u: u.normalized_valuation() else: v = lambda u: u.valuation(self.parent().prime()) @@ -1614,7 +1617,7 @@ def governing_term(self, r): """ p = self.prime() F = self.parent().base_ring() - if not is_pAdicField(F): + if not isinstance(F, sage.rings.abc.pAdicField): F = pAdicField(p) s = self.parent().radius() p = self.prime() diff --git a/src/sage/modular/pollack_stevens/manin_map.py b/src/sage/modular/pollack_stevens/manin_map.py index ccb89aa8d98..21defc771d6 100644 --- a/src/sage/modular/pollack_stevens/manin_map.py +++ b/src/sage/modular/pollack_stevens/manin_map.py @@ -367,7 +367,7 @@ def compute_full_data(self): 38 """ for B in self._manin.reps(): - if not B in self._dict: + if B not in self._dict: self._dict[B] = self._compute_image_from_gens(B) def __add__(self, right): diff --git a/src/sage/modular/pollack_stevens/space.py b/src/sage/modular/pollack_stevens/space.py index f52d609b6e7..47097c27305 100644 --- a/src/sage/modular/pollack_stevens/space.py +++ b/src/sage/modular/pollack_stevens/space.py @@ -749,7 +749,7 @@ def random_element(self, M=None): ## now we compute nu_infty of Prop 5.1 of [PS1] t = self.coefficient_module().zero() for g in manin.gens()[1:]: - if (not g in manin.reps_with_two_torsion()) and (not g in manin.reps_with_three_torsion()): + if (g not in manin.reps_with_two_torsion()) and (g not in manin.reps_with_three_torsion()): t += D[g] * manin.gammas[g] - D[g] else: # this was previously MR.reps_with_two_torsion() but there is no variable MR defined... diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index cbc80e7024b..dfb68d53f58 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -293,7 +293,7 @@ def is_one(self): def is_graded_modular_form(self): r""" - Return ``True`` if the given quasiform is a graded modular forms element + Return ``True`` if the given quasimodular form is a graded modular forms element and ``False`` otherwise. EXAMPLES:: @@ -325,8 +325,8 @@ def is_graded_modular_form(self): def is_modular_form(self): r""" - Return ``True`` if the given quasiform is a modular form and ``False`` - otherwise. + Return ``True`` if the given quasimodular form is a modular form and + ``False`` otherwise. EXAMPLES:: @@ -415,8 +415,9 @@ def is_homogeneous(self): def weight(self): r""" - Return the weight of the given quasiform. Note that the given form must - be homogeneous. + Return the weight of the given quasimodular form. + + Note that the given form must be homogeneous. EXAMPLES:: @@ -458,3 +459,99 @@ def homogeneous_components(self): poly_self = self.to_polynomial() pol_hom_comp = poly_self.homogeneous_components() return { k : QM.from_polynomial(pol) for k, pol in pol_hom_comp.items()} + + def serre_derivative(self): + r""" + Return the Serre derivative of the given quasimodular form. + + If the form is not homogeneous, then this method sums the serre + derivative of each homogeneous component. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: E2, E4, E6 = QM.gens() + sage: DE2 = E2.serre_derivative(); DE2 + -1/6 - 16*q - 216*q^2 - 832*q^3 - 2248*q^4 - 4320*q^5 + O(q^6) + sage: DE2 == (-E2^2 - E4)/12 + True + sage: DE4 = E4.serre_derivative(); DE4 + -1/3 + 168*q + 5544*q^2 + 40992*q^3 + 177576*q^4 + 525168*q^5 + O(q^6) + sage: DE4 == (-1/3) * E6 + True + sage: DE6 = E6.serre_derivative(); DE6 + -1/2 - 240*q - 30960*q^2 - 525120*q^3 - 3963120*q^4 - 18750240*q^5 + O(q^6) + sage: DE6 == (-1/2) * E4^2 + True + + The Serre derivative raises the weight of homogeneous elements by 2:: + + sage: F = E6 + E4 * E2 + sage: F.weight() + 6 + sage: F.serre_derivative().weight() + 8 + """ + # initial variables: + QM = self.parent() + R = QM.base_ring() + E2 = QM.gen(0) + E4 = QM.gen(1) + + # compute the derivative of E2: q*dE2/dq + E2deriv = R(12).inverse_of_unit() * (E2 ** 2 - E4) + + # sum the Serre derivative of each monomial of the form: f * E2^n + # they are equal to: + # [E2^n * serre_deriv(f)] + [n * f * E2^(n-1) * D(E2)] - [n/6 * f * E2^(n+1)] + # = A + B - C + der = QM.zero() + u6 = R(6).inverse_of_unit() + for n, f in enumerate(self._polynomial.coefficients(sparse=False)): + if n == 0: + der += QM(f.serre_derivative()) + else: + A = (E2 ** n) * f.serre_derivative() + B = R(n) * f * E2 ** (n - 1) * E2deriv + C = R(n) * u6 * E2 ** (n + 1) * f + der += QM(A + B - C) + return der + + def derivative(self): + r""" + Return the derivative `q \frac{d}{dq}` of the given quasimodular form. + + If the form is not homogeneous, then this method sums the derivative of + each homogeneous component. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: E2, E4, E6 = QM.gens() + sage: dE2 = E2.derivative(); dE2 + -24*q - 144*q^2 - 288*q^3 - 672*q^4 - 720*q^5 + O(q^6) + sage: dE2 == (E2^2 - E4)/12 # Ramanujan identity + True + sage: dE4 = E4.derivative(); dE4 + 240*q + 4320*q^2 + 20160*q^3 + 70080*q^4 + 151200*q^5 + O(q^6) + sage: dE4 == (E2 * E4 - E6)/3 # Ramanujan identity + True + sage: dE6 = E6.derivative(); dE6 + -504*q - 33264*q^2 - 368928*q^3 - 2130912*q^4 - 7877520*q^5 + O(q^6) + sage: dE6 == (E2 * E6 - E4^2)/2 # Ramanujan identity + True + + Note that the derivative of a modular form is not necessarily a modular form:: + + sage: dE4.is_modular_form() + False + sage: dE4.weight() + 6 + """ + QM = self.parent() + E2 = QM.gen(0) + R = self.base_ring() + u = R(12).inverse_of_unit() + hom_comp = self.homogeneous_components() + + return sum(f.serre_derivative() + R(k) * u * f * E2 for k, f in hom_comp.items()) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index ba5e1eb6ccb..8ede61e1fc2 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -242,10 +242,10 @@ def create_object(self, version, key): # raise TypeError, "The base_ring must be a commutative ring." try: - if not sparse and isinstance(base_ring,sage.rings.real_double.RealDoubleField_class): + if not sparse and isinstance(base_ring, sage.rings.abc.RealDoubleField): return RealDoubleVectorSpace_class(rank) - elif not sparse and isinstance(base_ring,sage.rings.complex_double.ComplexDoubleField_class): + elif not sparse and isinstance(base_ring, sage.rings.abc.ComplexDoubleField): return ComplexDoubleVectorSpace_class(rank) elif base_ring.is_field(): @@ -512,8 +512,8 @@ def VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_mat """ if not K.is_field(): raise TypeError("Argument K (= %s) must be a field." % K) - if not sparse in (True,False): - raise TypeError("Argument sparse (= %s) must be a boolean."%sparse) + if sparse not in (True, False): + raise TypeError("Argument sparse (= %s) must be a boolean." % sparse) return FreeModule(K, dimension_or_basis_keys, sparse, inner_product_matrix, with_basis=with_basis, rank=dimension, basis_keys=basis_keys, **args) @@ -2932,7 +2932,7 @@ def index_in(self, other): a = sage.matrix.matrix_space.MatrixSpace(self.base_field(), self.rank())(C).determinant() if sage.rings.integer_ring.is_IntegerRing(self.base_ring()): return a.abs() - elif isinstance(self.base_ring, sage.rings.number_field.order.Order): + elif isinstance(self.base_ring, sage.rings.abc.Order): return self.base_ring().ideal(a).norm() else: raise NotImplementedError @@ -4449,7 +4449,7 @@ def linear_dependence(self, vectors, zeros='left', check=True): """ if check: for v in vectors: - if not v in self: + if v not in self: raise ValueError('vector %s is not an element of %s' % (v, self)) if zeros == 'left': basis = 'echelon' @@ -7426,9 +7426,7 @@ def element_class(R, is_sparse): sage: sage.modules.free_module.element_class(P, is_sparse=False) """ - import sage.modules.vector_real_double_dense - import sage.modules.vector_complex_double_dense - + import sage.rings.integer_ring if sage.rings.integer_ring.is_IntegerRing(R) and not is_sparse: from .vector_integer_dense import Vector_integer_dense return Vector_integer_dense @@ -7445,21 +7443,30 @@ def element_class(R, is_sparse): else: return free_module_element.FreeModuleElement_generic_dense elif isinstance(R, sage.rings.abc.RealDoubleField) and not is_sparse: - return sage.modules.vector_real_double_dense.Vector_real_double_dense + try: + from sage.modules.vector_real_double_dense import Vector_real_double_dense + except ImportError: + pass + else: + return Vector_real_double_dense elif isinstance(R, sage.rings.abc.ComplexDoubleField) and not is_sparse: - return sage.modules.vector_complex_double_dense.Vector_complex_double_dense + try: + from sage.modules.vector_complex_double_dense import Vector_complex_double_dense + except ImportError: + pass + else: + return Vector_complex_double_dense elif isinstance(R, sage.rings.abc.CallableSymbolicExpressionRing) and not is_sparse: import sage.modules.vector_callable_symbolic_dense return sage.modules.vector_callable_symbolic_dense.Vector_callable_symbolic_dense elif isinstance(R, sage.rings.abc.SymbolicRing) and not is_sparse: import sage.modules.vector_symbolic_dense return sage.modules.vector_symbolic_dense.Vector_symbolic_dense + + if is_sparse: + return free_module_element.FreeModuleElement_generic_sparse else: - if is_sparse: - return free_module_element.FreeModuleElement_generic_sparse - else: - return free_module_element.FreeModuleElement_generic_dense - raise NotImplementedError + return free_module_element.FreeModuleElement_generic_dense @richcmp_method class EchelonMatrixKey(object): diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index de44743651e..e9137f78613 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -122,8 +122,7 @@ import sage.rings.abc from sage.rings.ring import is_Ring from sage.rings.infinity import Infinity, AnInfinity from sage.rings.integer_ring import ZZ -from sage.rings.real_double import RDF -from sage.rings.complex_double import CDF +from sage.rings.abc import RealDoubleField, ComplexDoubleField from sage.rings.ring cimport Ring from sage.rings.integer cimport Integer, smallInteger @@ -476,23 +475,32 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): # We first efficiently handle the important special case of the zero vector # over a ring. See trac 11657. # !! PLEASE DO NOT MOVE THIS CODE LOWER IN THIS FUNCTION !! - if arg2 is None and is_Ring(arg0) and (isinstance(arg1, (int, long, Integer))): + arg1_integer = isinstance(arg1, (int, long, Integer)) + if arg2 is None and is_Ring(arg0) and arg1_integer: M = FreeModule(arg0, arg1, bool(sparse)) v = M.zero_vector() if immutable: v.set_immutable() return v - # WARNING TO FUTURE OPTIMIZERS: The following two hasattr's take + # The try...except is slightly faster than testing with hasattr first # quite a significant amount of time. - if hasattr(arg0, '_vector_'): - v = arg0._vector_(arg1) + try: + arg0_vector_ = arg0._vector_ + except AttributeError: + pass + else: + v = arg0_vector_(arg1) if immutable: v.set_immutable() return v - if hasattr(arg1, '_vector_'): - v = arg1._vector_(arg0) + try: + arg1_vector_ = arg1._vector_ + except AttributeError: + pass + else: + v = arg1_vector_(arg0) if immutable: v.set_immutable() return v @@ -500,7 +508,7 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): # consider a possible degree specified in second argument degree = None maxindex = None - if isinstance(arg1, (Integer, int, long)): + if arg1_integer: if arg1 < 0: raise ValueError("cannot specify the degree of a vector as a negative integer (%s)" % arg1) if isinstance(arg2, dict): @@ -531,27 +539,33 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): v = arg0 R = None - from numpy import ndarray - if isinstance(v, ndarray): - if len(v.shape) != 1: - raise TypeError("cannot convert %r-dimensional array to a vector" % len(v.shape)) - from .free_module import VectorSpace - if (R is None or R is RDF) and v.dtype.kind == 'f': - V = VectorSpace(RDF, v.shape[0]) - from .vector_real_double_dense import Vector_real_double_dense - v = Vector_real_double_dense(V, v) - if immutable: - v.set_immutable() - return v - if (R is None or R is CDF) and v.dtype.kind == 'c': - V = VectorSpace(CDF, v.shape[0]) - from .vector_complex_double_dense import Vector_complex_double_dense - v = Vector_complex_double_dense(V, v) - if immutable: - v.set_immutable() - return v - # Use slower conversion via list - v = list(v) + try: + from numpy import ndarray + except ImportError: + pass + else: + if isinstance(v, ndarray): + if len(v.shape) != 1: + raise TypeError("cannot convert %r-dimensional array to a vector" % len(v.shape)) + from .free_module import VectorSpace + if (R is None or isinstance(R, RealDoubleField)) and v.dtype.kind == 'f': + from sage.rings.real_double import RDF + V = VectorSpace(RDF, v.shape[0]) + from .vector_real_double_dense import Vector_real_double_dense + v = Vector_real_double_dense(V, v) + if immutable: + v.set_immutable() + return v + if (R is None or isinstance(R, ComplexDoubleField)) and v.dtype.kind == 'c': + from sage.rings.complex_double import CDF + V = VectorSpace(CDF, v.shape[0]) + from .vector_complex_double_dense import Vector_complex_double_dense + v = Vector_complex_double_dense(V, v) + if immutable: + v.set_immutable() + return v + # Use slower conversion via list + v = list(v) if isinstance(v, dict): if degree is None: diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index a1e8a05fb50..66d4db2f9df 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -364,10 +364,10 @@ def LLL(self, *args, **kwds): ... sage: L.reduced_basis == A True - sage: old_min = min(v.norm().n() for v in L.reduced_basis) + sage: old = L.reduced_basis[0].norm().n() sage: _ = L.LLL() - sage: new_min = L.reduced_basis[0].norm().n() - sage: new_min <= old_min + sage: new = L.reduced_basis[0].norm().n() + sage: new <= old True """ basis = self.reduced_basis diff --git a/src/sage/modules/matrix_morphism.py b/src/sage/modules/matrix_morphism.py index 58e670812ff..a01999eb3c8 100644 --- a/src/sage/modules/matrix_morphism.py +++ b/src/sage/modules/matrix_morphism.py @@ -93,7 +93,7 @@ def __init__(self, parent, side='left'): """ if not sage.categories.homset.is_Homset(parent): raise TypeError("parent must be a Hom space") - if not side in ["left", "right"]: + if side not in ["left", "right"]: raise ValueError("the argument side must be either 'left' or 'right'") self._side = side sage.categories.morphism.Morphism.__init__(self, parent) @@ -1695,13 +1695,11 @@ def matrix(self, side=None): ... ValueError: side must be 'left' or 'right', not junk """ - - if not side in ['left', 'right', None]: + if side not in ['left', 'right', None]: raise ValueError("side must be 'left' or 'right', not {0}".format(side)) if side == self.side() or side is None: return self._matrix - else: - return self._matrix.transpose() + return self._matrix.transpose() def is_injective(self): """ diff --git a/src/sage/modules/vector_space_morphism.py b/src/sage/modules/vector_space_morphism.py index 1a1fde6eb5a..c3725fbdabd 100644 --- a/src/sage/modules/vector_space_morphism.py +++ b/src/sage/modules/vector_space_morphism.py @@ -693,7 +693,7 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): except ImportError: Vector_callable_symbolic_dense = () - if not side in ['left', 'right']: + if side not in ['left', 'right']: raise ValueError("side must be 'left' or 'right', not {0}".format(side)) if not (is_Matrix(arg0) or is_VectorSpace(arg0)): raise TypeError('first argument must be a matrix or a vector space, not {0}'.format(arg0)) diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 184b09a94e3..7972927406d 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -175,12 +175,12 @@ def __init__(self, domain, codomain=None, category=None, affine=False): sage: TestSuite(phi).run() """ if category is None: - if not domain in ModulesWithBasis: - raise ValueError("domain(=%s) should be a module with basis"%(codomain)) + if domain not in ModulesWithBasis: + raise ValueError("domain(=%s) should be a module with basis" % codomain) base_ring = domain.base_ring() - if not hasattr( codomain, 'base_ring' ): - raise ValueError("codomain(=%s) needs to have a base_ring attribute"%(codomain)) + if not hasattr(codomain, 'base_ring'): + raise ValueError("codomain(=%s) needs to have a base_ring attribute" % codomain) # codomain should be a module over base_ring # The natural test would be ``codomains in Modules(base_ring)`` # But this is not properly implemented yet:: @@ -227,6 +227,7 @@ def __init__(self, domain, codomain=None, category=None, affine=False): if not issubclass(self.__class__, H._abstract_element_class): self.__class__ = H.__make_element_class__(self.__class__) + class ModuleMorphismFromFunction(ModuleMorphism, SetMorphism): """ A class for module morphisms implemented by a plain function. @@ -264,6 +265,7 @@ def __init__(self, domain, function, codomain=None, category=None): ModuleMorphism.__init__(self, domain, codomain, category=category) SetMorphism.__init__(self, self.parent(), function) + class ModuleMorphismByLinearity(ModuleMorphism): """ A class for module morphisms obtained by extending a function by linearity. @@ -318,7 +320,7 @@ def __init__(self, domain, on_basis=None, codomain=None, category=None, self._on_basis = on_basis self._is_module_with_basis_over_same_base_ring = \ - codomain in ModulesWithBasis( base_ring ) and zero == codomain.zero() + codomain in ModulesWithBasis(base_ring) and zero == codomain.zero() ModuleMorphism.__init__(self, domain, codomain, category=category, @@ -954,7 +956,7 @@ def preimage(self, f): F = self.domain() G = self.codomain() on_basis = self.on_basis() - if not f in G: + if f not in G: raise ValueError("f(={}) must be in the codomain of the morphism to have a preimage under the latter".format(f)) remainder = f @@ -1333,17 +1335,17 @@ def __init__(self, domain, matrix, codomain=None, category=None, side="left"): [2 5] """ C = ModulesWithBasis(domain.base_ring()).FiniteDimensional() - if not domain in C: - raise ValueError("The domain %s should be finite dimensional"%domain) + if domain not in C: + raise ValueError("The domain %s should be finite dimensional" % domain) if codomain is None: raise ValueError("The codomain %s should be specified") - if not codomain in C: - raise ValueError("The codomain %s should be finite dimensional"%codomain) + if codomain not in C: + raise ValueError("The codomain %s should be finite dimensional" % codomain) if not is_Matrix(matrix): - raise ValueError("matrix (=%s) should be a matrix"%matrix) + raise ValueError("matrix (=%s) should be a matrix" % matrix) import sage.combinat.ranker indices = tuple(domain.basis().keys()) - rank_domain = sage.combinat.ranker.rank_from_list(indices) + rank_domain = sage.combinat.ranker.rank_from_list(indices) if side == "left": matrix = matrix.transpose() if matrix.nrows() != len(indices): diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index 5b5c52b2752..02651233a9c 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -1,12 +1,12 @@ r""" Quotients of Modules With Basis """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010-2015 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.sets.family import Family @@ -14,6 +14,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.categories.all import ModulesWithBasis + class QuotientModuleWithBasis(CombinatorialFreeModule): r""" A class for quotients of a module with basis by a submodule. @@ -376,7 +377,7 @@ def is_submodule(self, other): return True if not isinstance(self, SubmoduleWithBasis) and self.ambient() is other.ambient(): raise ValueError("other (=%s) should be a submodule of the same ambient space" % other) - if not self in ModulesWithBasis.FiniteDimensional: + if self not in ModulesWithBasis.FiniteDimensional: raise NotImplementedError("is_submodule for infinite dimensional modules") for b in self.basis(): try: @@ -384,4 +385,3 @@ def is_submodule(self, other): except ValueError: return False return True - diff --git a/src/sage/monoids/string_monoid_element.py b/src/sage/monoids/string_monoid_element.py index 6da34db7175..c3032e463f9 100644 --- a/src/sage/monoids/string_monoid_element.py +++ b/src/sage/monoids/string_monoid_element.py @@ -497,7 +497,7 @@ def frequency_distribution(self, length=1, prec=0): [(AB, 0.333333333333333), (BC, 0.333333333333333), (CD, 0.333333333333333)] """ from sage.probability.random_variable import DiscreteProbabilitySpace - if not length in (1, 2): + if length not in (1, 2): raise NotImplementedError("Not implemented") if prec == 0: RR = RealField() @@ -510,7 +510,7 @@ def frequency_distribution(self, length=1, prec=0): Alph = tuple(x * y for x in S.gens() for y in S.gens()) X = {} N = len(self) - length + 1 - eps = RR(Integer(1)/N) + eps = RR(Integer(1) / N) for i in range(N): c = self[i:i+length] if c in X: diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index bc4cc83741b..5e0adb0a915 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -1691,18 +1691,18 @@ cpdef GenericBackend get_solver(constraint_generation = False, solver = None, ba <...sage.numerical.backends.ppl_backend.PPLBackend...> sage: p.base_ring() Rational Field - sage: p = get_solver(base_ring=AA); p + sage: p = get_solver(base_ring=AA); p # optional - sage.rings.number_field <...sage.numerical.backends.interactivelp_backend.InteractiveLPBackend...> - sage: p.base_ring() + sage: p.base_ring() # optional - sage.rings.number_field Algebraic Real Field - sage: d = polytopes.dodecahedron() - sage: p = get_solver(base_ring=d.base_ring()); p + sage: d = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: p = get_solver(base_ring=d.base_ring()); p # optional - sage.rings.number_field <...sage.numerical.backends.interactivelp_backend.InteractiveLPBackend...> - sage: p.base_ring() + sage: p.base_ring() # optional - sage.rings.number_field Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - sage: p = get_solver(solver='InteractiveLP', base_ring=QQ); p + sage: p = get_solver(solver='InteractiveLP', base_ring=QQ); p # optional - sage.rings.number_field <...sage.numerical.backends.interactivelp_backend.InteractiveLPBackend...> - sage: p.base_ring() + sage: p.base_ring() # optional - sage.rings.number_field Rational Field Passing a callable as the 'solver':: diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 26f037647ed..3a60b981b43 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -1646,11 +1646,7 @@ cdef class GLPKBackend(GenericBackend): sage: p.add_variable() 0 - sage: p.variable_upper_bound(0, 'hey!') # py2 - Traceback (most recent call last): - ... - TypeError: a float is required - sage: p.variable_upper_bound(0, 'hey!') # py3 + sage: p.variable_upper_bound(0, 'hey!') Traceback (most recent call last): ... TypeError: must be real number, not str @@ -1750,11 +1746,7 @@ cdef class GLPKBackend(GenericBackend): sage: p.add_variable() 0 - sage: p.variable_lower_bound(0, 'hey!') # py2 - Traceback (most recent call last): - ... - TypeError: a float is required - sage: p.variable_lower_bound(0, 'hey!') # py3 + sage: p.variable_lower_bound(0, 'hey!') Traceback (most recent call last): ... TypeError: must be real number, not str diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index 6b26a21f1e2..366baf4da26 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -53,17 +53,17 @@ cdef class InteractiveLPBackend: This backend can work with irrational algebraic numbers:: - sage: poly = polytopes.dodecahedron(base_ring=AA) - sage: lp, x = poly.to_linear_program(solver='InteractiveLP', return_variable=True) - sage: lp.set_objective(x[0] + x[1] + x[2]) - sage: lp.solve() + sage: poly = polytopes.dodecahedron(base_ring=AA) # optional - sage.rings.number_field + sage: lp, x = poly.to_linear_program(solver='InteractiveLP', return_variable=True) # optional - sage.rings.number_field + sage: lp.set_objective(x[0] + x[1] + x[2]) # optional - sage.rings.number_field + sage: lp.solve() # optional - sage.rings.number_field 2.291796067500631? - sage: lp.get_values(x[0], x[1], x[2]) + sage: lp.get_values(x[0], x[1], x[2]) # optional - sage.rings.number_field [0.763932022500211?, 0.763932022500211?, 0.763932022500211?] - sage: lp.set_objective(x[0] - x[1] - x[2]) - sage: lp.solve() + sage: lp.set_objective(x[0] - x[1] - x[2]) # optional - sage.rings.number_field + sage: lp.solve() # optional - sage.rings.number_field 2.291796067500631? - sage: lp.get_values(x[0], x[1], x[2]) + sage: lp.get_values(x[0], x[1], x[2]) # optional - sage.rings.number_field [0.763932022500211?, -0.763932022500211?, -0.763932022500211?] """ diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index 47f89dbef39..4180f3f6b9f 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -663,13 +663,13 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: p = MixedIntegerLinearProgram(solver='ppl') sage: p.base_ring() Rational Field - sage: from sage.rings.all import AA - sage: p = MixedIntegerLinearProgram(solver='InteractiveLP', base_ring=AA) - sage: p.base_ring() + sage: from sage.rings.qqbar import AA # optional - sage.rings.number_field + sage: p = MixedIntegerLinearProgram(solver='InteractiveLP', base_ring=AA) # optional - sage.rings.number_field + sage: p.base_ring() # optional - sage.rings.number_field Algebraic Real Field - sage: d = polytopes.dodecahedron() - sage: p = MixedIntegerLinearProgram(base_ring=d.base_ring()) - sage: p.base_ring() + sage: d = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: p = MixedIntegerLinearProgram(base_ring=d.base_ring()) # optional - sage.rings.number_field + sage: p.base_ring() # optional - sage.rings.number_field Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? """ return self._backend.base_ring() diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index 82632fefcb8..e3557569e78 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -565,7 +565,7 @@ def gif(self, delay=20, savefile=None, iterations=0, show_path=False, sage: a.gif(savefile=td + 'my_animation_2.gif', show_path=True, use_ffmpeg=True) # optional -- ffmpeg Animation saved to .../my_animation_2.gif. - .. note:: + .. NOTE:: If neither ffmpeg nor ImageMagick is installed, you will get an error message like this:: @@ -576,50 +576,100 @@ def gif(self, delay=20, savefile=None, iterations=0, show_path=False, See www.imagemagick.org and www.ffmpeg.org for more information. """ - from sage.misc.sage_ostools import have_program - have_convert = have_program('convert') - have_ffmpeg = self._have_ffmpeg() - if use_ffmpeg or not have_convert: - if have_ffmpeg: - self.ffmpeg(savefile=savefile, show_path=show_path, - output_format='.gif', delay=delay, - iterations=iterations) - else: - if not have_convert: - msg = """ -Error: Neither ImageMagick nor ffmpeg appears to be installed. Saving an -animation to a GIF file or displaying an animation requires one of these -packages, so please install one of them and try again. - -See www.imagemagick.org and www.ffmpeg.org for more information.""" - else: - msg = """ -Error: ffmpeg does not appear to be installed. Download it from -www.ffmpeg.org, or use 'convert' to produce gifs instead.""" - raise OSError(msg) + from sage.features.imagemagick import ImageMagick + from sage.features.ffmpeg import FFmpeg + + if not ImageMagick().is_present() and not FFmpeg().is_present(): + raise OSError("Error: Neither ImageMagick nor ffmpeg appear to " + "be installed. Saving an animation to a GIF file or " + "displaying an animation requires one of these " + "packages, so please install one of them and try " + "again. See www.imagemagick.org and www.ffmpeg.org " + "for more information.") + + if use_ffmpeg or not ImageMagick().is_present(): + self.ffmpeg(savefile=savefile, show_path=show_path, + output_format='.gif', delay=delay, + iterations=iterations) else: - if not savefile: - savefile = tmp_filename(ext='.gif') - if not savefile.endswith('.gif'): - savefile += '.gif' - savefile = os.path.abspath(savefile) - d = self.png() - cmd = ( 'cd "%s"; sage-native-execute convert -dispose Background ' - '-delay %s -loop %s *.png "%s"' ) % ( d, int(delay), - int(iterations), savefile ) - from subprocess import check_call, CalledProcessError - try: - check_call(cmd, shell=True) - if show_path: - print("Animation saved to file %s." % savefile) - except (CalledProcessError, OSError): - msg = """ -Error: Cannot generate GIF animation. Verify that convert -(ImageMagick) or ffmpeg is installed, and that the objects passed to -the animate command can be saved in PNG image format. - -See www.imagemagick.org and www.ffmpeg.org for more information.""" - raise OSError(msg) + self._gif_from_imagemagick(savefile=savefile, show_path=show_path, + delay=delay, iterations=iterations) + + def _gif_from_imagemagick(self, savefile=None, show_path=False, + delay=20, iterations=0): + r""" + Return a movie showing an animation composed from rendering + the frames in ``self``. + + This method will only work if ``imagemagick`` is installed (command + ``convert``). See https://www.imagemagick.org for information + about ``imagemagick``. + + INPUT: + + - ``savefile`` -- file that the mpeg gets saved to. + + .. warning:: + + This will overwrite ``savefile`` if it already exists. + + - ``show_path`` -- boolean (default: ``False``); if ``True``, + print the path to the saved file + + - ``delay`` - (default: 20) delay in hundredths of a + second between frames + + - ``iterations`` - integer (default: 0); number of iterations + of animation. If 0, loop forever. + + If ``savefile`` is not specified: in notebook mode, display + the animation; otherwise, save it to a default file name. Use + :func:`sage.misc.verbose.set_verbose` with ``level=1`` to see + additional output. + + EXAMPLES:: + + sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)], + ....: xmin=0, xmax=2*pi, ymin=-1, ymax=1, figsize=[2,1]) + sage: td = tmp_dir() + sage: a._gif_from_imagemagick(savefile=td + 'new.gif') # optional -- imagemagick + + .. NOTE:: + + If imagemagick is not installed, you will get an error message + like this:: + + FeatureNotPresentError: imagemagick is not available. + Executable 'convert' not found on PATH. + Further installation instructions might be available at + https://www.imagemagick.org/. + + """ + from sage.features.imagemagick import ImageMagick + ImageMagick().require() + + if not savefile: + savefile = tmp_filename(ext='.gif') + if not savefile.endswith('.gif'): + savefile += '.gif' + savefile = os.path.abspath(savefile) + + d = self.png() + cmd = ( 'cd "%s"; sage-native-execute convert -dispose Background ' + '-delay %s -loop %s *.png "%s"' ) % ( d, int(delay), + int(iterations), savefile ) + from subprocess import check_call, CalledProcessError + try: + check_call(cmd, shell=True) + if show_path: + print("Animation saved to file %s." % savefile) + except (CalledProcessError, OSError): + raise OSError("Error: Cannot generate GIF animation. " + "Verify that convert (ImageMagick) or ffmpeg is " + "installed, and that the objects passed to the " + "animate command can be saved in PNG image format. " + "See www.imagemagick.org and www.ffmpeg.org for " + "more information.") def _rich_repr_(self, display_manager, **kwds): """ @@ -710,7 +760,7 @@ def show(self, delay=None, iterations=None, **kwds): This method does not return anything. Use :meth:`save` if you want to save the figure as an image. - .. note:: + .. NOTE:: Currently this is done using an animated gif, though this could change in the future. This requires that either @@ -756,7 +806,7 @@ def show(self, delay=None, iterations=None, **kwds): sage: a.show(50, 3) # optional -- ImageMagick - .. note:: + .. NOTE:: If you don't have ffmpeg or ImageMagick installed, you will get an error message like this:: @@ -778,19 +828,6 @@ def show(self, delay=None, iterations=None, **kwds): dm = get_display_manager() dm.display_immediately(self, **kwds) - def _have_ffmpeg(self): - """ - Return True if the program 'ffmpeg' is installed. See - www.ffmpeg.org to download ffmpeg. - - EXAMPLES:: - - sage: a = animate([plot(sin, -1,1)], xmin=0, ymin=0) - sage: a._have_ffmpeg() # random: depends on whether ffmpeg is installed - False - """ - from sage.misc.sage_ostools import have_program - return have_program('ffmpeg') def ffmpeg(self, savefile=None, show_path=False, output_format=None, ffmpeg_options='', delay=None, iterations=0, pix_fmt='rgb24'): @@ -855,91 +892,85 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, sage: a.ffmpeg(savefile=td + 'new.mpg', show_path=True) # optional -- ffmpeg Animation saved to .../new.mpg. - .. note:: + .. NOTE:: If ffmpeg is not installed, you will get an error message like this:: - Error: ffmpeg does not appear to be installed. Saving an animation to - a movie file in any format other than GIF requires this software, so - please install it and try again. - - See www.ffmpeg.org for more information. - + FeatureNotPresentError: ffmpeg is not available. + Executable 'ffmpeg' not found on PATH. + Further installation instructions might be available at https://www.ffmpeg.org/. TESTS:: sage: a.ffmpeg(output_format='gif',delay=30,iterations=5) # optional -- ffmpeg """ - if not self._have_ffmpeg(): - msg = """Error: ffmpeg does not appear to be installed. Saving an animation to -a movie file in any format other than GIF requires this software, so -please install it and try again.""" - raise OSError(msg) + from sage.features.ffmpeg import FFmpeg + FFmpeg().require() + + if savefile is None: + if output_format is None: + output_format = '.mpg' + else: + if output_format[0] != '.': + output_format = '.'+output_format + savefile = tmp_filename(ext=output_format) else: - if savefile is None: - if output_format is None: - output_format = '.mpg' + if output_format is None: + suffix = os.path.splitext(savefile)[1] + if len(suffix) > 0: + output_format = suffix else: - if output_format[0] != '.': - output_format = '.'+output_format - savefile = tmp_filename(ext=output_format) + output_format = '.mpg' + if not savefile.endswith(output_format): + savefile += output_format + early_options = '' + if output_format == '.gif': + # We try to set reasonable options for gif output. + # + # Older versions of ffmpeg (before 0.9, summer 2011) + # use the option -loop_output instead of -loop. + # Setting iterations=None is a way of preventing sage + # from adding the -loop option. A separate + # -loop_output option can be added with the + # ffmpeg_options argument. + if iterations is not None: + loop_cmd = '-loop {0} '.format(iterations) else: - if output_format is None: - suffix = os.path.splitext(savefile)[1] - if len(suffix) > 0: - output_format = suffix - else: - output_format = '.mpg' - if not savefile.endswith(output_format): - savefile += output_format - early_options = '' - if output_format == '.gif': - # We try to set reasonable options for gif output. - # - # Older versions of ffmpeg (before 0.9, summer 2011) - # use the option -loop_output instead of -loop. - # Setting iterations=None is a way of preventing sage - # from adding the -loop option. A separate - # -loop_output option can be added with the - # ffmpeg_options argument. - if iterations is not None: - loop_cmd = '-loop {0} '.format(iterations) - else: - loop_cmd = '' - # A pix_fmt value is required for some but not all - # ffmpeg installations. Setting pix_fmt=None will - # prevent sage from adding this option, and it may be - # controlled separately through ffmpeg_options. - if pix_fmt is not None: - pix_fmt_cmd = '-pix_fmt {0} '.format(pix_fmt) - else: - pix_fmt_cmd = '' - ffmpeg_options += ' {0}{1}'.format(pix_fmt_cmd,loop_cmd) - if delay is not None and output_format != '.mpeg' and output_format != '.mpg': - early_options += ' -r %s ' % int(100/delay) - savefile = os.path.abspath(savefile) - pngdir = self.png() - pngs = os.path.join(pngdir, "%08d.png") - # For ffmpeg, it seems that some options, like '-g ... -r - # ...', need to come before the input file names, while - # some options, like '-pix_fmt rgb24', need to come - # afterwards. Hence 'early_options' and 'ffmpeg_options' - cmd = 'cd "%s"; sage-native-execute ffmpeg -y -f image2 %s -i %s %s %s' % (pngdir, early_options, pngs, ffmpeg_options, savefile) - from subprocess import check_call, CalledProcessError, PIPE - try: - if sage.misc.verbose.get_verbose() > 0: - set_stderr = None - else: - set_stderr = PIPE - sage.misc.verbose.verbose("Executing '%s'" % cmd,level=1) - sage.misc.verbose.verbose("\n---- ffmpeg output below ----\n") - check_call(cmd, shell=True, stderr=set_stderr) - if show_path: - print("Animation saved to file %s." % savefile) - except (CalledProcessError, OSError): - print("Error running ffmpeg.") - raise + loop_cmd = '' + # A pix_fmt value is required for some but not all + # ffmpeg installations. Setting pix_fmt=None will + # prevent sage from adding this option, and it may be + # controlled separately through ffmpeg_options. + if pix_fmt is not None: + pix_fmt_cmd = '-pix_fmt {0} '.format(pix_fmt) + else: + pix_fmt_cmd = '' + ffmpeg_options += ' {0}{1}'.format(pix_fmt_cmd,loop_cmd) + if delay is not None and output_format != '.mpeg' and output_format != '.mpg': + early_options += ' -r %s ' % int(100/delay) + savefile = os.path.abspath(savefile) + pngdir = self.png() + pngs = os.path.join(pngdir, "%08d.png") + # For ffmpeg, it seems that some options, like '-g ... -r + # ...', need to come before the input file names, while + # some options, like '-pix_fmt rgb24', need to come + # afterwards. Hence 'early_options' and 'ffmpeg_options' + cmd = 'cd "%s"; sage-native-execute ffmpeg -y -f image2 %s -i %s %s %s' % (pngdir, early_options, pngs, ffmpeg_options, savefile) + from subprocess import check_call, CalledProcessError, PIPE + try: + if sage.misc.verbose.get_verbose() > 0: + set_stderr = None + else: + set_stderr = PIPE + sage.misc.verbose.verbose("Executing '%s'" % cmd,level=1) + sage.misc.verbose.verbose("\n---- ffmpeg output below ----\n") + check_call(cmd, shell=True, stderr=set_stderr) + if show_path: + print("Animation saved to file %s." % savefile) + except (CalledProcessError, OSError): + print("Error running ffmpeg.") + raise def apng(self, savefile=None, show_path=False, delay=20, iterations=0): r""" diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 84f2ed0b778..755e4e75172 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -3310,10 +3310,14 @@ def save(self, filename, **kwds): # on the file extension. # PGF is handled by a different backend if ext == '.pgf': - from sage.misc.sage_ostools import have_program - latex_implementations = [i for i in ["xelatex", "pdflatex", - "lualatex"] - if have_program(i)] + from sage.features.latex import xelatex,pdflatex,lualatex + latex_implementations = [] + if xelatex().is_present(): + latex_implementations.append('xelatex') + if pdflatex().is_present(): + latex_implementations.append('pdflatex') + if lualatex().is_present(): + latex_implementations.append('lualatex') if not latex_implementations: raise ValueError("Matplotlib requires either xelatex, " "lualatex, or pdflatex.") diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index 6fa90dd6bbc..6f441561a99 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -453,10 +453,14 @@ def save(self, filename, figsize=None, **kwds): # depending on the file extension. # PGF is handled by a different backend if ext == '.pgf': - from sage.misc.sage_ostools import have_program - latex_implementations = [i for i in ["xelatex", "pdflatex", - "lualatex"] - if have_program(i)] + from sage.features.latex import xelatex,pdflatex,lualatex + latex_implementations = [] + if xelatex().is_present(): + latex_implementations.append('xelatex') + if pdflatex().is_present(): + latex_implementations.append('pdflatex') + if lualatex().is_present(): + latex_implementations.append('lualatex') if not latex_implementations: raise ValueError("Matplotlib requires either xelatex, " "lualatex, or pdflatex.") diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 48b26885948..7bec1ca4dce 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -580,7 +580,6 @@ def f(x): return (x-3)*(x-5)*(x-7)+40 from math import sin, cos, pi, log, exp #for polar_plot and log scaling from sage.ext.fast_eval import fast_float, is_fast_float -from sage.misc.lazy_import import lazy_import from sage.structure.element import Expression from sage.misc.decorators import options diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index 6efc85eb10f..a9212bbed3a 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -88,7 +88,7 @@ from sage.rings.real_double import RDF from sage.plot.misc import setup_for_eval_on_grid from sage.plot.colors import check_color_data -from sage.libs.gsl.math cimport gsl_isnan +from libc.math cimport isnan include "point_c.pxi" @@ -99,9 +99,7 @@ DEFAULT_PLOT_POINTS = 40 cdef double nan = float(RDF('NaN')) cdef inline bint marching_has_edge(double a, double b, double contour, double *f, bint *has_nan): - # XXX Would be nicer to use isnan(), because it's inlined. - # Is it portable enough? - if gsl_isnan(a) or gsl_isnan(b): + if isnan(a) or isnan(b): has_nan[0] = True return False @@ -115,7 +113,7 @@ cdef inline bint marching_has_edge(double a, double b, double contour, double *f # Returns 0 or 1 cdef inline int marching_is_inside(double v, double contour): - return gsl_isnan(v) or v < contour + return isnan(v) or v < contour cdef void interpolate_point_c(point_c *result, double frac, point_c *inputs): result[0].x = inputs[0].x + frac*(inputs[1].x - inputs[0].x) diff --git a/src/sage/quadratic_forms/genera/normal_form.py b/src/sage/quadratic_forms/genera/normal_form.py index db46afe0d76..2dd43567591 100644 --- a/src/sage/quadratic_forms/genera/normal_form.py +++ b/src/sage/quadratic_forms/genera/normal_form.py @@ -531,7 +531,7 @@ def _homogeneous_normal_form(G, w): e2 = D[-1,-1].unit_part() e = {e1, e2} E = [{1,3}, {1,7}, {5,7}, {3,5}] - if not e in E: + if e not in E: B[-4:,:] = _relations(D[-4:,-4:], 5) * B[-4:,:] D = B * G * B.T e1 = D[-2,-2].unit_part() diff --git a/src/sage/quadratic_forms/genera/spinor_genus.py b/src/sage/quadratic_forms/genera/spinor_genus.py index 6c6cf17f831..e4284fe4d31 100644 --- a/src/sage/quadratic_forms/genera/spinor_genus.py +++ b/src/sage/quadratic_forms/genera/spinor_genus.py @@ -162,12 +162,12 @@ def to_square_class(self, x, p): x = QQ(x) if x == 0: raise ValueError("x must be non zero") - if not p in self._primes: + if p not in self._primes: raise ValueError("not a coordinate prime") v, u = x.val_unit(p) v = v % 2 if v != 0: - raise ValueError("x(=%s) must be a p-adic unit" %x) + raise ValueError("x(=%s) must be a p-adic unit" % x) y = self.one() if p == 2: u = u % 8 diff --git a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py index e1de84c9037..4226acb972b 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py +++ b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py @@ -570,19 +570,19 @@ def is_locally_represented_at_place(self, m, p): True """ - ## Sanity Check - if not m in QQ: - raise TypeError("Oops! m = " + str(m) + " is not a rational number!") + # Sanity Check + if m not in QQ: + raise TypeError("Oops! m = " + str(m) + " is not a rational number!") - ## Representing zero + # Representing zero if m == 0: return True - ## 0-dim'l forms - if self.dim == 0: ## Here m != 0 + # 0-dim'l forms + if self.dim == 0: # Here m != 0 return False - ## 1-dim'l forms + # 1-dim'l forms if self.dim == 1: m1 = QQ(m) / self.coeff if p == infinity: @@ -642,33 +642,33 @@ def is_locally_represented(self, m): False """ - ## Representing zero + # Representing zero if m == 0: return True - ## 0-dim'l forms - if self.dim == 0: ## Here m != 0 + # 0-dim'l forms + if self.dim == 0: # Here m != 0 return False - ## 1-dim'l forms + # 1-dim'l forms if self.dim == 1: m1 = m / self.coeff return (m1 in ZZ) and is_square(m1) - ## Check the generic primes (when n = 2 or n >= 3) + # Check the generic primes (when n = 2 or n >= 3) m_primes = prime_divisors(numerator(m) * denominator(m)) for p in m_primes: - if not p in self.exceptional_primes: - val = valuation(m, p) - if (val < 0): - return False + if p not in self.exceptional_primes: + val = valuation(m, p) + if val < 0: + return False - ## Check the non-generic primes (when n = 2 or n >= 3) + # Check the non-generic primes (when n = 2 or n >= 3) for p in self.exceptional_primes: if not self.is_locally_represented_at_place(m, p): return False - ## If we got here, we're locally represented! + # If we got here, we're locally represented! return True diff --git a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py index d6ccde1d292..85df0a3bf98 100644 --- a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py +++ b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py @@ -11,7 +11,8 @@ from sage.quadratic_forms.extras import extend_to_primitive from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor, is_QuadraticForm -from sage.rings.real_mpfr import RealField_class, RealField +import sage.rings.abc +from sage.rings.real_mpfr import RealField from sage.rings.real_double import RDF from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix @@ -85,7 +86,7 @@ def cholesky_decomposition(self, bit_prec = 53): """ ## Check that the precision passed is allowed. - if isinstance(self.base_ring(), RealField_class) and (self.base_ring().prec() < bit_prec): + if isinstance(self.base_ring(), sage.rings.abc.RealField) and (self.base_ring().prec() < bit_prec): raise RuntimeError("Oops! The precision requested is greater than that of the given quadratic form!") ## 1. Initialization diff --git a/src/sage/repl/attach.py b/src/sage/repl/attach.py index b4c4e63c699..8cbe64c1f94 100644 --- a/src/sage/repl/attach.py +++ b/src/sage/repl/attach.py @@ -249,8 +249,7 @@ def reset_load_attach_path(): sage: reset_load_attach_path(); load_attach_path() ['.'] sage: os.environ['SAGE_LOAD_ATTACH_PATH'] = '/veni/vidi:vici:' - sage: from imp import reload # py2 - sage: from importlib import reload # py3 + sage: from importlib import reload sage: reload(sage.repl.attach) # Simulate startup sage: load_attach_path() diff --git a/src/sage/repl/ipython_kernel/interact.py b/src/sage/repl/ipython_kernel/interact.py index b9970f551a7..ceea40e5863 100644 --- a/src/sage/repl/ipython_kernel/interact.py +++ b/src/sage/repl/ipython_kernel/interact.py @@ -140,9 +140,7 @@ def signature(self): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: def myfunc(x=[1,2,3], auto_update=False): pass - sage: sage_interactive(myfunc).signature().parameters # py2 - OrderedDict([('x', )]) - sage: sage_interactive(myfunc).signature().parameters # py3 + sage: sage_interactive(myfunc).signature().parameters mappingproxy({'x': }) """ return self.__signature @@ -203,9 +201,7 @@ def widget_from_tuple(cls, abbrev, *args, **kwds): IntSlider(value=5, description=u'number', max=10) sage: sage_interactive.widget_from_tuple( (3, (0, 10)) ) IntSlider(value=3, max=10) - sage: sage_interactive.widget_from_tuple((2, dict(one=1, two=2, three=3))) # py2 - Dropdown(index=1, options={'three': 3, 'two': 2, 'one': 1}, value=2) - sage: sage_interactive.widget_from_tuple((2, dict(one=1, two=2, three=3))) # py3 + sage: sage_interactive.widget_from_tuple((2, dict(one=1, two=2, three=3))) Dropdown(index=1, options={'one': 1, 'two': 2, 'three': 3}, value=2) sage: sage_interactive.widget_from_tuple( (sqrt(2), pi) ) FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) diff --git a/src/sage/repl/ipython_kernel/widgets_sagenb.py b/src/sage/repl/ipython_kernel/widgets_sagenb.py index 45c2d9350ce..169a98ab2a5 100644 --- a/src/sage/repl/ipython_kernel/widgets_sagenb.py +++ b/src/sage/repl/ipython_kernel/widgets_sagenb.py @@ -466,13 +466,9 @@ def selector(values, label=None, default=None, nrows=None, ncols=None, width=Non is not ordered, it is better to use an :class:`OrderedDict`:: sage: from collections import OrderedDict - sage: selector(OrderedDict(one=1, two=2, three=3)) # py2 - Dropdown(options=OrderedDict([('one', 1), ('three', 3), ('two', 2)]), value=1) - sage: selector(OrderedDict(one=1, two=2, three=3)) # py3 + sage: selector(OrderedDict(one=1, two=2, three=3)) Dropdown(options=OrderedDict([('one', 1), ('two', 2), ('three', 3)]), value=1) - sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True) # py2 - ToggleButtons(options=OrderedDict([('one', 1), ('three', 3), ('two', 2)]), value=1) - sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True) # py3 + sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True) ToggleButtons(options=OrderedDict([('one', 1), ('two', 2), ('three', 3)]), value=1) The values can be any kind of object: diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 63430b23c75..4d4e9bfd104 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -1,10 +1,30 @@ """ Abstract base classes for rings """ +from sage.rings.ring import EuclideanDomain + class NumberField_quadratic(Field): r""" Abstract base class for :class:`~sage.rings.number_field.number_field.NumberField_quadratic`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: K. = QuadraticField(2) # optional - sage.rings.number_field + sage: isinstance(K, sage.rings.abc.NumberField_quadratic) # optional - sage.rings.number_field + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.NumberField_quadratic.__subclasses__() # optional - sage.rings.number_field + [] + + sage: len(sage.rings.abc.NumberField_quadratic.__subclasses__()) <= 1 + True """ pass @@ -13,6 +33,24 @@ class NumberField_quadratic(Field): class NumberField_cyclotomic(Field): r""" Abstract base class for :class:`~sage.rings.number_field.number_field.NumberField_cyclotomic`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: K. = CyclotomicField(15) # optional - sage.rings.number_field + sage: isinstance(K, sage.rings.abc.NumberField_cyclotomic) # optional - sage.rings.number_field + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.NumberField_cyclotomic.__subclasses__() # optional - sage.rings.number_field + [] + + sage: len(sage.rings.abc.NumberField_cyclotomic.__subclasses__()) <= 1 + True """ pass @@ -21,6 +59,29 @@ class NumberField_cyclotomic(Field): class AlgebraicField_common(Field): r""" Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField_common`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(QQbar, sage.rings.abc.AlgebraicField_common) # optional - sage.rings.number_field + True + sage: isinstance(AA, sage.rings.abc.AlgebraicField_common) # optional - sage.rings.number_field + True + + By design, other than the abstract subclasses :class:`~sage.rings.abc.AlgebraicField` + and :class:`~sage.rings.abc.AlgebraicRealField`, there is only one direct implementation + subclass:: + + sage: sage.rings.abc.AlgebraicField_common.__subclasses__() # optional - sage.rings.number_field + [, + , + ] + + sage: len(sage.rings.abc.AlgebraicField_common.__subclasses__()) <= 3 + True """ pass @@ -29,6 +90,25 @@ class AlgebraicField_common(Field): class AlgebraicField(AlgebraicField_common): r""" Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(QQbar, sage.rings.abc.AlgebraicField) # optional - sage.rings.number_field + True + sage: isinstance(AA, sage.rings.abc.AlgebraicField) # optional - sage.rings.number_field + False + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.AlgebraicField.__subclasses__() # optional - sage.rings.number_field + [] + + sage: len(sage.rings.abc.AlgebraicField.__subclasses__()) <= 1 + True """ pass @@ -37,6 +117,25 @@ class AlgebraicField(AlgebraicField_common): class AlgebraicRealField(AlgebraicField_common): r""" Abstract base class for :class:`~sage.rings.qqbar.AlgebraicRealField`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(QQbar, sage.rings.abc.AlgebraicRealField) # optional - sage.rings.number_field + False + sage: isinstance(AA, sage.rings.abc.AlgebraicRealField) # optional - sage.rings.number_field + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.AlgebraicRealField.__subclasses__() # optional - sage.rings.number_field + [] + + sage: len(sage.rings.abc.AlgebraicRealField.__subclasses__()) <= 1 + True """ pass @@ -45,6 +144,23 @@ class AlgebraicRealField(AlgebraicField_common): cdef class RealField(Field): r""" Abstract base class for :class:`~sage.rings.real_mpfr.RealField_class`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(RR, sage.rings.abc.RealField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.RealField.__subclasses__() + [] + + sage: len(sage.rings.abc.RealField.__subclasses__()) <= 1 + True """ pass @@ -53,6 +169,23 @@ cdef class RealField(Field): class RealBallField(Field): r""" Abstract base class for :class:`~sage.rings.real_arb.RealBallField`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(RBF, sage.rings.abc.RealBallField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.RealBallField.__subclasses__() + [] + + sage: len(sage.rings.abc.RealBallField.__subclasses__()) <= 1 + True """ pass @@ -61,6 +194,23 @@ class RealBallField(Field): cdef class RealIntervalField(Field): r""" Abstract base class for :class:`~sage.rings.real_mpfi.RealIntervalField_class`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(RIF, sage.rings.abc.RealIntervalField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.RealIntervalField.__subclasses__() + [] + + sage: len(sage.rings.abc.RealIntervalField.__subclasses__()) <= 1 + True """ pass @@ -69,6 +219,23 @@ cdef class RealIntervalField(Field): cdef class RealDoubleField(Field): r""" Abstract base class for :class:`~sage.rings.real_double.RealDoubleField_class`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(RDF, sage.rings.abc.RealDoubleField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.RealDoubleField.__subclasses__() + [] + + sage: len(sage.rings.abc.RealDoubleField.__subclasses__()) <= 1 + True """ pass @@ -77,6 +244,23 @@ cdef class RealDoubleField(Field): cdef class ComplexField(Field): r""" Abstract base class for :class:`~sage.rings.complex_mpfr.ComplexField_class`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(CC, sage.rings.abc.ComplexField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.ComplexField.__subclasses__() + [] + + sage: len(sage.rings.abc.ComplexField.__subclasses__()) <= 1 + True """ pass @@ -85,6 +269,23 @@ cdef class ComplexField(Field): class ComplexBallField(Field): r""" Abstract base class for :class:`~sage.rings.complex_arb.ComplexBallField`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(CBF, sage.rings.abc.ComplexBallField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.ComplexBallField.__subclasses__() + [] + + sage: len(sage.rings.abc.ComplexBallField.__subclasses__()) <= 1 + True """ pass @@ -93,6 +294,23 @@ class ComplexBallField(Field): class ComplexIntervalField(Field): r""" Abstract base class for :class:`~sage.rings.complex_interval_field.ComplexIntervalField_class`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(CIF, sage.rings.abc.ComplexIntervalField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.ComplexIntervalField.__subclasses__() + [] + + sage: len(sage.rings.abc.ComplexIntervalField.__subclasses__()) <= 1 + True """ pass @@ -101,6 +319,23 @@ class ComplexIntervalField(Field): cdef class ComplexDoubleField(Field): r""" Abstract base class for :class:`~sage.rings.complex_double.ComplexDoubleField_class`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(CDF, sage.rings.abc.ComplexDoubleField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.ComplexDoubleField.__subclasses__() + [] + + sage: len(sage.rings.abc.ComplexDoubleField.__subclasses__()) <= 1 + True """ pass @@ -109,13 +344,103 @@ cdef class ComplexDoubleField(Field): class IntegerModRing: r""" Abstract base class for :class:`~sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(Integers(7), sage.rings.abc.IntegerModRing) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.IntegerModRing.__subclasses__() + [] + + sage: len(sage.rings.abc.IntegerModRing.__subclasses__()) <= 1 + True """ pass + class Order: r""" Abstract base class for :class:`~sage.rings.number_field.order.Order`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: K. = NumberField(x^2 + 1); O = K.order(2*a) # optional - sage.rings.number_field + sage: isinstance(O, sage.rings.abc.Order) # optional - sage.rings.number_field + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.Order.__subclasses__() # optional - sage.rings.number_field + [] + + sage: len(sage.rings.abc.Order.__subclasses__()) <= 1 + True + """ + + pass + + +class pAdicRing(EuclideanDomain): + r""" + Abstract base class for :class:`~sage.rings.padics.generic_nodes.pAdicRingGeneric`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(Zp(5), sage.rings.abc.pAdicRing) + True + sage: isinstance(Qp(5), sage.rings.abc.pAdicRing) + False + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.pAdicRing.__subclasses__() + [] + + sage: len(sage.rings.abc.pAdicRing.__subclasses__()) <= 1 + True + """ + + pass + + +class pAdicField(Field): + r""" + Abstract base class for :class:`~sage.rings.padics.generic_nodes.pAdicFieldGeneric`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(Zp(5), sage.rings.abc.pAdicField) + False + sage: isinstance(Qp(5), sage.rings.abc.pAdicField) + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.pAdicField.__subclasses__() + [] + + sage: len(sage.rings.abc.pAdicField.__subclasses__()) <= 1 + True """ pass @@ -124,6 +449,25 @@ class Order: cdef class SymbolicRing(CommutativeRing): r""" Abstract base class for :class:`~sage.rings.symbolic.ring.SymbolicRing`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: isinstance(SR, sage.rings.abc.SymbolicRing) # optional - sage.symbolic + True + + By design, other than the abstract subclass :class:`~sage.rings.abc.CallableSymbolicExpressionRing`, + there is only one direct implementation subclass:: + + sage: sage.rings.abc.SymbolicRing.__subclasses__() # optional - sage.symbolic + [, + ] + + sage: len(sage.rings.abc.SymbolicRing.__subclasses__()) <= 2 + True """ pass @@ -132,6 +476,24 @@ cdef class SymbolicRing(CommutativeRing): class CallableSymbolicExpressionRing(SymbolicRing): r""" Abstract base class for :class:`~sage.rings.symbolic.callable.CallableSymbolicExpressionRing_class`. + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.rings.abc + sage: f = x.function(x).parent() # optional - sage.symbolic + sage: isinstance(f, sage.rings.abc.CallableSymbolicExpressionRing) # optional - sage.symbolic + True + + By design, there is a unique direct subclass:: + + sage: sage.rings.abc.CallableSymbolicExpressionRing.__subclasses__() # optional - sage.symbolic + [] + + sage: len(sage.rings.abc.CallableSymbolicExpressionRing.__subclasses__()) <= 1 + True """ pass diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 0ecaff62f65..95022e34c4a 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -418,6 +418,7 @@ from sage.structure.element import CommutativeAlgebraElement from sage.structure.unique_representation import UniqueRepresentation from sage.misc.defaults import series_precision +import sage.rings.abc from sage.rings.all import RIF from .misc import WithLocals @@ -2964,8 +2965,7 @@ def plot_comparison(self, variable, function, values, rescaled=True, points = self.compare_with_values(variable, function, values, rescaled=rescaled, ring=ring) - from sage.rings.real_mpfi import RealIntervalField_class - if isinstance(ring, RealIntervalField_class): + if isinstance(ring, sage.rings.abc.RealIntervalField): if not all(p[1].relative_diameter() <= relative_tolerance for p in points): raise ValueError('Numerical noise is too high, the ' 'comparison is inaccurate') diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 28e359dbf00..ba7e6848ea3 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -240,6 +240,7 @@ from sage.structure.unique_representation import (CachedRepresentation, UniqueRepresentation) from sage.structure.richcmp import richcmp_by_eq_and_lt +import sage.rings.abc from .misc import WithLocals @@ -3622,13 +3623,12 @@ def _convert_(self, data): from sage.symbolic.ring import SR return self._convert_(SR(data)) - from sage.symbolic.ring import SymbolicRing from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.polynomial.multi_polynomial_ring_base import \ MPolynomialRing_base from sage.rings.power_series_ring import PowerSeriesRing_generic import operator - if isinstance(P, SymbolicRing): + if isinstance(P, sage.rings.abc.SymbolicRing): if data.operator() == operator.pow: base, exponent = data.operands() if str(base) == var: @@ -4419,10 +4419,9 @@ def __init__(self, base, *args, **kwds): sage: forget() """ from warnings import warn - from sage.symbolic.ring import SymbolicRing super(ExponentialGrowthGroup, self).__init__(base, *args, **kwds) - if isinstance(base, SymbolicRing) and not self._an_element_base_() > 0: + if isinstance(base, sage.rings.abc.SymbolicRing) and not self._an_element_base_() > 0: warn("When using the Exponential {}, make " "assumptions on the used symbolic elements.\n" "In particular, use something like " @@ -4552,9 +4551,8 @@ def _convert_(self, data): import operator from sage.functions.log import Function_exp from sage.symbolic.operators import mul_vararg - from sage.symbolic.ring import SymbolicRing - if isinstance(P, SymbolicRing): + if isinstance(P, sage.rings.abc.SymbolicRing): op = data.operator() if op == operator.pow: base, exponent = data.operands() @@ -4654,20 +4652,13 @@ def _split_raw_element_(base): (-x, -1) sage: forget() """ - from sage.rings.complex_arb import ComplexBallField - from sage.rings.complex_mpfr import ComplexField_class - from sage.rings.complex_interval_field import ComplexIntervalField_class from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ - from sage.rings.real_arb import RealBallField - from sage.rings.real_mpfr import RealField_class - from sage.rings.real_mpfi import RealIntervalField_class from sage.rings.qqbar import AA from sage.structure.element import parent - from sage.symbolic.ring import SymbolicRing P = base.parent() - if isinstance(P, SymbolicRing): + if isinstance(P, sage.rings.abc.SymbolicRing): try: base = base.pyobject() except TypeError: @@ -4675,17 +4666,17 @@ def _split_raw_element_(base): else: P = base.parent() - if P in (ZZ, QQ, AA) or isinstance(P, (SymbolicRing, - RealField_class, - RealIntervalField_class, - RealBallField)): + if P in (ZZ, QQ, AA) or isinstance(P, (sage.rings.abc.SymbolicRing, + sage.rings.abc.RealField, + sage.rings.abc.RealIntervalField, + sage.rings.abc.RealBallField)): if base > 0: return base, None if base < 0: return -base, -1 - elif isinstance(P, (ComplexField_class, - ComplexIntervalField_class, - ComplexBallField)): + elif isinstance(P, (sage.rings.abc.ComplexField, + sage.rings.abc.ComplexIntervalField, + sage.rings.abc.ComplexBallField)): size = abs(base) direction = base / size return size, direction @@ -4847,9 +4838,6 @@ def factory(cls, from sage.categories.cartesian_product import cartesian_product from sage.groups.misc_gps.argument_groups import AbstractArgumentGroup from sage.groups.misc_gps.argument_groups import ArgumentGroup - from sage.rings.complex_arb import ComplexBallField - from sage.rings.complex_mpfr import ComplexField_class - from sage.rings.complex_interval_field import ComplexIntervalField_class from sage.rings.number_field.number_field import NumberField_cyclotomic from sage.rings.qqbar import QQbar, AA @@ -4861,9 +4849,9 @@ def factory(cls, UU = cls._non_growth_group_class_( ArgumentGroup(domain=base), var) groups = (EE, UU) - elif isinstance(base, (ComplexField_class, - ComplexIntervalField_class, - ComplexBallField)): + elif isinstance(base, (sage.rings.abc.ComplexField, + sage.rings.abc.ComplexIntervalField, + sage.rings.abc.ComplexBallField)): EE = cls(base._real_field(), var, **kwds) UU = cls._non_growth_group_class_( ArgumentGroup(exponents=base._real_field()), var) diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 0e94161063c..466784c62df 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -70,18 +70,16 @@ AUTHORS: import operator from cpython.object cimport Py_NE -from cysignals.signals cimport sig_on, sig_off from sage.misc.randstate cimport randstate, current_randstate -from cypari2.paridecl cimport * - from sage.libs.gsl.complex cimport * cdef extern from "": double complex csqrt(double complex) double cabs(double complex) +import sage.rings.abc cimport sage.rings.ring cimport sage.rings.integer @@ -92,8 +90,22 @@ from sage.structure.richcmp cimport rich_to_bool from sage.categories.morphism cimport Morphism from sage.structure.coerce cimport is_numpy_type -from cypari2.gen cimport Gen as pari_gen -from cypari2.convert cimport new_gen_from_double, new_t_COMPLEX_from_double +try: + from cypari2.gen import Gen as pari_gen + from sage.libs.pari.convert_sage_complex_double import pari_to_cdf + +except ImportError: + pari_gen = () + + +new_gen_from_complex_double_element = None +complex_double_element_eta = None +complex_double_element_agm = None +complex_double_element_dilog = None +complex_double_element_gamma = None +complex_double_element_gamma_inc = None +complex_double_element_zeta = None + from . import complex_mpfr @@ -436,11 +448,10 @@ cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): return FloatToCDF(S) from .rational_field import QQ from .real_lazy import RLF - from .real_mpfr import RR, RealField_class - from .complex_mpfr import ComplexField_class + from .real_mpfr import RR if S is ZZ or S is QQ or S is RDF or S is RLF: return FloatToCDF(S) - if isinstance(S, RealField_class): + if isinstance(S, sage.rings.abc.RealField): if S.prec() >= 53: return FloatToCDF(S) else: @@ -455,7 +466,7 @@ cdef class ComplexDoubleField_class(sage.rings.abc.ComplexDoubleField): return None elif RR.has_coerce_map_from(S): return FloatToCDF(RR) * RR._internal_coerce_map_from(S) - elif isinstance(S, ComplexField_class) and S.prec() >= 53: + elif isinstance(S, sage.rings.abc.ComplexField) and S.prec() >= 53: return complex_mpfr.CCtoCDF(S, self) elif CC.has_coerce_map_from(S): return complex_mpfr.CCtoCDF(CC, self) * CC._internal_coerce_map_from(S) @@ -728,38 +739,6 @@ def is_ComplexDoubleElement(x): """ return isinstance(x, ComplexDoubleElement) -cdef inline ComplexDoubleElement pari_to_cdf(pari_gen g): - """ - Create a CDF element from a PARI ``gen``. - - EXAMPLES:: - - sage: CDF(pari("Pi")) - 3.141592653589793 - sage: CDF(pari("1 + I/2")) - 1.0 + 0.5*I - - TESTS: - - Check that we handle PARI errors gracefully, see :trac:`17329`:: - - sage: CDF(-151.386325246 + 992.34771962*I).zeta() - Traceback (most recent call last): - ... - PariError: overflow in t_REAL->double conversion - sage: CDF(pari(x^2 + 5)) - Traceback (most recent call last): - ... - PariError: incorrect type in gtofp (t_POL) - """ - cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) - sig_on() - if typ(g.g) == t_COMPLEX: - z._complex = gsl_complex_rect(gtodouble(gel(g.g, 1)), gtodouble(gel(g.g, 2))) - else: - z._complex = gsl_complex_rect(gtodouble(g.g), 0.0) - sig_off() - return z cdef class ComplexDoubleElement(FieldElement): """ @@ -1175,10 +1154,10 @@ cdef class ComplexDoubleElement(FieldElement): sage: pari(CDF(I)) 1.00000000000000*I """ - if not GSL_IMAG(self._complex): - return new_gen_from_double(GSL_REAL(self._complex)) - else: - return new_t_COMPLEX_from_double(GSL_REAL(self._complex), GSL_IMAG(self._complex)) + global new_gen_from_complex_double_element + if new_gen_from_complex_double_element is None: + from sage.libs.pari.convert_sage_complex_double import new_gen_from_complex_double_element + return new_gen_from_complex_double_element(self) def __mpc__(self): """ @@ -2269,8 +2248,6 @@ cdef class ComplexDoubleElement(FieldElement): sage: eta(z) 0.7420487758365647 + 0.1988313702299107*I """ - cdef GEN a, b, c, y, t - if GSL_IMAG(self._complex) <= 0: raise ValueError("value must be in the upper half plane") @@ -2280,8 +2257,12 @@ cdef class ComplexDoubleElement(FieldElement): # this, PARI can easily underflow. return ComplexDoubleElement(0,0) + global complex_double_element_eta + if complex_double_element_eta is None: + from sage.libs.pari.convert_sage_complex_double import complex_double_element_eta + cdef int flag = 0 if omit_frac else 1 - return pari_to_cdf(self.__pari__().eta(flag)) + return complex_double_element_eta(self, flag) def agm(self, right, algorithm="optimal"): r""" @@ -2346,7 +2327,10 @@ cdef class ComplexDoubleElement(FieldElement): cdef double d, e, eps = 2.0**-51 if algorithm == "pari": - return pari_to_cdf(self.__pari__().agm(right)) + global complex_double_element_agm + if complex_double_element_agm is None: + from sage.libs.pari.convert_sage_complex_double import complex_double_element_agm + return complex_double_element_agm(self, right) if not isinstance(right, ComplexDoubleElement): right = CDF(right) @@ -2396,7 +2380,10 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(10000000,10000000).dilog() -134.411774490731 + 38.79396299904504*I """ - return pari_to_cdf(self.__pari__().dilog()) + global complex_double_element_dilog + if complex_double_element_dilog is None: + from sage.libs.pari.convert_sage_complex_double import complex_double_element_dilog + return complex_double_element_dilog(self) def gamma(self): r""" @@ -2424,7 +2411,10 @@ cdef class ComplexDoubleElement(FieldElement): return CC(self).gamma() except TypeError: pass - return pari_to_cdf(self.__pari__().gamma()) + global complex_double_element_gamma + if complex_double_element_gamma is None: + from sage.libs.pari.convert_sage_complex_double import complex_double_element_gamma + return complex_double_element_gamma(self) def gamma_inc(self, t): r""" @@ -2439,7 +2429,10 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(2,0).gamma_inc(CDF(1,1)) 0.7070920963459381 - 0.4203536409598115*I """ - return pari_to_cdf(self.__pari__().incgam(t)) + global complex_double_element_gamma_inc + if complex_double_element_gamma_inc is None: + from sage.libs.pari.convert_sage_complex_double import complex_double_element_gamma_inc + return complex_double_element_gamma_inc(self, t) def zeta(self): """ @@ -2458,7 +2451,11 @@ cdef class ComplexDoubleElement(FieldElement): if GSL_REAL(self._complex) == 1 and GSL_IMAG(self._complex) == 0: from .infinity import unsigned_infinity return unsigned_infinity - return pari_to_cdf(self.__pari__().zeta()) + + global complex_double_element_zeta + if complex_double_element_zeta is None: + from sage.libs.pari.convert_sage_complex_double import complex_double_element_zeta + return complex_double_element_zeta(self) def algdep(self, long n): """ @@ -2660,3 +2657,8 @@ cdef inline ComplexDoubleElement ComplexDoubleElement_from_doubles(double re, do z = ComplexDoubleElement.__new__(ComplexDoubleElement) GSL_SET_COMPLEX(&z._complex, re, im) return z + + +# Support Python's numbers abstract base class +import numbers +numbers.Complex.register(ComplexDoubleElement) diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index e7f287aa9c9..b6780014030 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -2575,3 +2575,8 @@ cdef class CCtoMPC(Map): y = (self.codomain())._new() mpc_set_fr_fr(y.value, (z).__re, (z).__im, rnd) return y + + +# Support Python's numbers abstract base class +import numbers +from sage.rings.complex_mpc import MPComplexNumber diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index ed5165f8bdc..0de4d91878f 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -3626,3 +3626,8 @@ def _format_complex_number(real, imag, format_spec): "complex format specifier") result = format(result, align + width) return result + + +# Support Python's numbers abstract base class +import numbers +numbers.Complex.register(ComplexNumber) diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index d7d77afb8a7..07d75b18565 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -264,11 +264,13 @@ def rat_interval_cf_list(r1, r2): sage: rat_interval_cf_list(257/113, 5224/2297) [2, 3, 1, 1, 1, 4] sage: for prec in range(10,54): - ....: R = RealIntervalField(20) + ....: R = RealIntervalField(prec) ....: for _ in range(100): ....: x = R.random_element() * R.random_element() + R.random_element() / 100 ....: l = x.lower().exact_rational() ....: u = x.upper().exact_rational() + ....: if l.floor() != u.floor(): + ....: continue ....: cf = rat_interval_cf_list(l,u) ....: a = continued_fraction(cf).value() ....: b = continued_fraction(cf+[1]).value() @@ -2452,12 +2454,11 @@ def continued_fraction_list(x, type="std", partial_convergents=False, cf = None - from sage.rings.real_arb import RealBallField - from sage.rings.real_mpfi import RealIntervalField, RealIntervalField_class from sage.rings.real_mpfr import RealLiteral if isinstance(x, RealLiteral): + from sage.rings.real_mpfi import RealIntervalField x = RealIntervalField(x.prec())(x) - if isinstance(x.parent(), (RealIntervalField_class, RealBallField)): + if isinstance(x.parent(), (sage.rings.abc.RealIntervalField, sage.rings.abc.RealBallField)): cf = continued_fraction(rat_interval_cf_list( x.lower().exact_rational(), x.upper().exact_rational())) @@ -2665,8 +2666,8 @@ def continued_fraction(x, value=None): except AttributeError: pass - from .real_mpfi import RealIntervalField if is_real is False: + from .real_mpfi import RealIntervalField # we cannot rely on the answer of .is_real() for elements of the # symbolic ring. The thing below is a dirty temporary hack. RIF = RealIntervalField(53) diff --git a/src/sage/rings/convert/mpfi.pyx b/src/sage/rings/convert/mpfi.pyx index 0e5e68c8825..2ddd972e221 100644 --- a/src/sage/rings/convert/mpfi.pyx +++ b/src/sage/rings/convert/mpfi.pyx @@ -21,10 +21,10 @@ from sage.libs.gsl.complex cimport * from sage.arith.long cimport integer_check_long from sage.cpython.string cimport bytes_to_str from sage.structure.element cimport Element, parent +import sage.rings.abc from ..integer cimport Integer from ..rational cimport Rational from ..real_mpfi cimport RealIntervalFieldElement, RealIntervalField_class -from ..complex_interval_field import ComplexIntervalField_class from ..real_mpfr cimport RealNumber from ..real_double cimport RealDoubleElement from ..complex_mpfr cimport ComplexNumber @@ -189,7 +189,7 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: except AttributeError: pass else: - if not isinstance(field, ComplexIntervalField_class): + if not isinstance(field, sage.rings.abc.ComplexIntervalField): field = field.complex_field() e = m(field) mpfi_swap(re, e.__re) diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 91b8d57e552..a07c9aa019f 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -1892,7 +1892,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): r += 1 power *= p if not power.divides(self.__modulus.sageInteger): - from sage.rings.all import infinity + from sage.rings.infinity import infinity return infinity return r diff --git a/src/sage/rings/function_field/function_field_valuation.py b/src/sage/rings/function_field/function_field_valuation.py index bff8ad4b1b3..40d82791499 100644 --- a/src/sage/rings/function_field/function_field_valuation.py +++ b/src/sage/rings/function_field/function_field_valuation.py @@ -923,7 +923,7 @@ def simplify(self, f, error=None, force=False): # if the caller was sure that we should simplify, then we should try to do the best simplification possible error = self(f) if force else self.upper_bound(f) - from sage.all import infinity + from sage.rings.infinity import infinity if error is infinity: return f diff --git a/src/sage/rings/infinity.py b/src/sage/rings/infinity.py index dfa0b9b6423..6bbacbe31e9 100644 --- a/src/sage/rings/infinity.py +++ b/src/sage/rings/infinity.py @@ -220,6 +220,7 @@ from sage.structure.element import RingElement, InfinityElement from sage.structure.richcmp import rich_to_bool, richcmp from sage.misc.fast_methods import Singleton +import sage.rings.abc import sage.rings.integer import sage.rings.rational @@ -1261,15 +1262,8 @@ def _coerce_map_from_(self, R): from sage.structure.coerce import parent_is_real_numerical if parent_is_real_numerical(R): return True - from sage.rings.real_mpfi import RealIntervalField_class - if isinstance(R, RealIntervalField_class): + if isinstance(R, (sage.rings.abc.RealIntervalField, sage.rings.abc.RealBallField)): return True - try: - from sage.rings.real_arb import RealBallField - if isinstance(R, RealBallField): - return True - except ImportError: - pass return False def _pushout_(self, other): diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index b0d1278b308..9dad670c8df 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -198,6 +198,15 @@ except ImportError: pari_gen = () +set_integer_from_gen = None +pari_divisors_small = None +n_factor_to_list = None +pari_is_prime_power = None +pari_is_prime = None +objtogen = None +new_gen_from_integer = None + + cdef extern from *: int unlikely(int) nogil # Defined by Cython @@ -637,7 +646,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): raise TypeError("Cannot convert non-integral float to integer") elif isinstance(x, pari_gen): - from sage.libs.pari.convert_sage import set_integer_from_gen + global set_integer_from_gen + if set_integer_from_gen is None: + from sage.libs.pari.convert_sage import set_integer_from_gen set_integer_from_gen(self, x) else: @@ -3046,12 +3057,14 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): raise ValueError("n must be nonzero") if (method is None or method == 'pari') and mpz_fits_slong_p(self.value): - try: - from sage.libs.pari.convert_sage import pari_divisors_small - except ImportError: - if method == 'pari': - raise ImportError("method `pari` requested, but cypari2 not present") - else: + global pari_divisors_small + if pari_divisors_small is None: + try: + from sage.libs.pari.convert_sage import pari_divisors_small + except ImportError: + if method == 'pari': + raise ImportError("method `pari` requested, but cypari2 not present") + if pari_divisors_small is not None: if mpz_sgn(self.value) > 0: return pari_divisors_small(self) else: @@ -3909,11 +3922,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return factor_trial_division(self, limit) if mpz_fits_slong_p(n.value): - try: - from sage.libs.flint.ulong_extras import n_factor_to_list - except ImportError: - pass - else: + global n_factor_to_list + if n_factor_to_list is None: + try: + from sage.libs.flint.ulong_extras import n_factor_to_list + except ImportError: + pass + if n_factor_to_list is not None: if proof is None: from sage.structure.proof.proof import get_flag proof = get_flag(proof, "arithmetic") @@ -5108,11 +5123,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return (self, zero) if get_data else False if mpz_fits_slong_p(self.value): - try: - from sage.libs.pari.convert_sage import pari_is_prime_power - except ImportError: - pass - else: + global pari_is_prime_power + if pari_is_prime_power is None: + try: + from sage.libs.pari.convert_sage import pari_is_prime_power + except ImportError: + pass + if pari_is_prime_power is not None: return pari_is_prime_power(self, get_data) cdef long n @@ -5194,11 +5211,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return False if mpz_fits_ulong_p(self.value): - try: - from sage.libs.pari.convert_sage import pari_is_prime - except ImportError: - pass - else: + global pari_is_prime + if pari_is_prime is None: + try: + from sage.libs.pari.convert_sage import pari_is_prime + except ImportError: + pass + if pari_is_prime is not None: return pari_is_prime(self) if proof is None: @@ -5550,7 +5569,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): """ - from cypari2.gen import objtogen + global objtogen + if objtogen is None: + from cypari2.gen import objtogen if self.is_square(): raise ValueError("class_number not defined for square integers") if not self%4 in [0,1]: @@ -5958,7 +5979,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 1041334 """ - from sage.libs.pari.convert_sage import new_gen_from_integer + global new_gen_from_integer + if new_gen_from_integer is None: + from sage.libs.pari.convert_sage import new_gen_from_integer return new_gen_from_integer(self) def _interface_init_(self, I=None): @@ -7564,3 +7587,8 @@ cdef double mpz_get_d_nearest(mpz_t x) except? -648555075988944.5: if resultsign < 0: d = -d return ldexp(d, shift) + + +# Support Python's numbers abstract base class +import numbers +numbers.Integral.register(Integer) diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index 8cf7181feed..6a96df172d8 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -1640,14 +1640,13 @@ cdef class RingHomomorphism_coercion(RingHomomorphism): sage: TestSuite(f).run() """ - def __init__(self, parent, check = True): + def __init__(self, parent, check=True): r""" TESTS: sage: from sage.rings.morphism import RingHomomorphism_coercion sage: parent = Hom(ZZ,ZZ) - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) # py2 - sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) # py3 + sage: f = parent.__make_element_class__(RingHomomorphism_coercion)(parent) doctest:warning ... DeprecationWarning: Set the category of your morphism to a subcategory of Rings instead. diff --git a/src/sage/rings/numbers_abc.py b/src/sage/rings/numbers_abc.py index 17290651196..478a0b36408 100644 --- a/src/sage/rings/numbers_abc.py +++ b/src/sage/rings/numbers_abc.py @@ -14,8 +14,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -import numbers - def register_sage_classes(): """ @@ -65,23 +63,5 @@ def register_sage_classes(): sage: isscalar(4/17) True """ - from sage.rings.integer import Integer - from sage.rings.rational import Rational - from sage.rings.real_mpfr import RealNumber - from sage.rings.real_double import RealDoubleElement - from sage.rings.complex_mpfr import ComplexNumber - from sage.rings.complex_double import ComplexDoubleElement - from sage.rings.complex_mpc import MPComplexNumber - from sage.rings.qqbar import AlgebraicReal, AlgebraicNumber - - numbers.Integral.register(Integer) - numbers.Rational.register(Rational) - numbers.Real.register(RealNumber) - numbers.Real.register(RealDoubleElement) - numbers.Real.register(AlgebraicReal) - numbers.Complex.register(ComplexNumber) - numbers.Complex.register(MPComplexNumber) - numbers.Complex.register(ComplexDoubleElement) - numbers.Complex.register(AlgebraicNumber) - -register_sage_classes() + from sage.misc.superseded import deprecation + deprecation(32641, "register_sage_classes is a deprecated no-op") diff --git a/src/sage/rings/padics/CR_template.pxi b/src/sage/rings/padics/CR_template.pxi index 7318873f9c5..3b9811827f3 100644 --- a/src/sage/rings/padics/CR_template.pxi +++ b/src/sage/rings/padics/CR_template.pxi @@ -1528,12 +1528,9 @@ cdef class CRElement(pAdicTemplateElement): sage: hash(R(17)) #indirect doctest 17 - sage: hash(R(-1)) # py3 + sage: hash(R(-1)) 1977844648 # 32-bit 95367431640624 # 64-bit - sage: hash(R(-1)) # py2 - 1977822444 # 32-bit - 95367431640624 # 64-bit """ if exactzero(self.ordp): return 0 diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index 00c6b63f5df..53496a522ec 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -23,7 +23,7 @@ from sage.rings.padics.local_generic import LocalGeneric from sage.rings.padics.padic_generic import pAdicGeneric -from sage.rings.ring import EuclideanDomain, Field +import sage.rings.abc from sage.rings.padics.padic_base_generic import pAdicBaseGeneric from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -1187,13 +1187,19 @@ def is_pAdicRing(R): EXAMPLES:: sage: is_pAdicRing(Zp(5)) + doctest:warning... + DeprecationWarning: is_pAdicRing is deprecated; use isinstance(..., sage.rings.abc.pAdicRing) instead + See https://trac.sagemath.org/32750 for details. True sage: is_pAdicRing(RR) False """ + from sage.misc.superseded import deprecation + deprecation(32750, "is_pAdicRing is deprecated; use isinstance(..., sage.rings.abc.pAdicRing) instead") return isinstance(R, pAdicRingGeneric) -class pAdicRingGeneric(pAdicGeneric, EuclideanDomain): + +class pAdicRingGeneric(pAdicGeneric, sage.rings.abc.pAdicRing): def is_field(self, proof = True): """ Return whether this ring is actually a field, ie ``False``. @@ -1327,14 +1333,19 @@ def is_pAdicField(R): EXAMPLES:: sage: is_pAdicField(Zp(17)) + doctest:warning... + DeprecationWarning: is_pAdicField is deprecated; use isinstance(..., sage.rings.abc.pAdicField) instead + See https://trac.sagemath.org/32750 for details. False sage: is_pAdicField(Qp(17)) True """ + from sage.misc.superseded import deprecation + deprecation(32750, "is_pAdicField is deprecated; use isinstance(..., sage.rings.abc.pAdicField) instead") return isinstance(R, pAdicFieldGeneric) -class pAdicFieldGeneric(pAdicGeneric, Field): +class pAdicFieldGeneric(pAdicGeneric, sage.rings.abc.pAdicField): pass #def class_field(self, group=None, map=None, generators=None): diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 69cc9026bb9..a468efdbdec 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -1055,7 +1055,7 @@ def _test_add_bigoh(self, **options): tester = self._tester(**options) for x in tester.some_elements(): tester.assertEqual(x.add_bigoh(x.precision_absolute()), x) - from sage.rings.all import infinity + from sage.rings.infinity import infinity tester.assertEqual(x.add_bigoh(infinity), x) tester.assertEqual(x.add_bigoh(x.precision_absolute()+1), x) @@ -1276,7 +1276,7 @@ def _matrix_smith_form(self, M, transformation, integral, exact): [O(5^10) O(5^10)] [O(5^10) O(5^10)] """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity from .precision_error import PrecisionError from copy import copy n = M.nrows() diff --git a/src/sage/rings/padics/local_generic_element.pyx b/src/sage/rings/padics/local_generic_element.pyx index 81f2fd7bc25..da753af83c1 100644 --- a/src/sage/rings/padics/local_generic_element.pyx +++ b/src/sage/rings/padics/local_generic_element.pyx @@ -997,7 +997,7 @@ cdef class LocalGenericElement(CommutativeRingElement): from sage.categories.all import Fields if self.parent() in Fields(): v = self.valuation() - from sage.rings.all import infinity + from sage.rings.infinity import infinity if self.valuation() is not infinity: shift = shift << v diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index 190c7cd5f89..f0d576cff66 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -48,7 +48,7 @@ from sage.structure.factory import UniqueFactory from sage.misc.cachefunc import cached_method -from sage.rings.all import infinity +from sage.rings.infinity import infinity class PadicValuationFactory(UniqueFactory): r""" @@ -1068,7 +1068,7 @@ def simplify(self, x, error=None, force=False): if error is None: error = self(x) - from sage.rings.all import infinity + from sage.rings.infinity import infinity if error is infinity: return x # we need to scale by the ramification index because p-adics use a @@ -1245,7 +1245,7 @@ def simplify(self, x, error=None, force=False, size_heuristic_bound=32): v = self(x) if error is None: error = v - from sage.rings.all import infinity + from sage.rings.infinity import infinity if error is infinity: return x if error < v: @@ -1326,7 +1326,7 @@ def inverse(self, x, precision): if precision <= 0: return self.domain().one() - from sage.rings.all import infinity + from sage.rings.infinity import infinity if self(x) > 0 or precision is infinity: raise ValueError("element has no approximate inverse in this ring") diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 07e0656baa5..70f21387412 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2367,10 +2367,7 @@ def variety(self, ring=None): sage: sorted(I.variety(ring=RR), key=str) [{y: 0.361103080528647, x: 2.76929235423863}, {y: 1.00000000000000, x: 1.00000000000000}] - sage: I.variety(ring=AA) # py2 - [{x: 1, y: 1}, - {x: 2.769292354238632?, y: 0.3611030805286474?}] - sage: I.variety(ring=AA) # py3 + sage: I.variety(ring=AA) [{y: 1, x: 1}, {y: 0.3611030805286474?, x: 2.769292354238632?}] @@ -2573,8 +2570,7 @@ def _variety(T, V, v=None): if d == -1: return [] - import sage.rings.complex_mpfr as CCmod - if isinstance(self.base_ring(), CCmod.ComplexField_class): + if isinstance(self.base_ring(), sage.rings.abc.ComplexField): verbose("Warning: computations in the complex field are inexact; variety may be computed partially or incorrectly.", level=0) P = self.ring() if ring is not None: @@ -5012,9 +5008,7 @@ def weil_restriction(self): Multivariate Polynomial Ring in x0, x1, y0, y1 over Finite Field of size 2 sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal - sage: J.variety() # py2 - [{y1: 1, x1: 1, x0: 1, y0: 0}] - sage: J.variety() # py3 + sage: J.variety() [{y1: 1, y0: 0, x1: 1, x0: 1}] sage: J.weil_restriction() # returns J @@ -5027,9 +5021,7 @@ def weil_restriction(self): sage: I = sage.rings.ideal.Katsura(P) sage: I.dimension() 0 - sage: I.variety() # py2 - [{y: 0, z: 0, x: 1}] - sage: I.variety() # py3 + sage: I.variety() [{z: 0, y: 0, x: 1}] sage: J = I.weil_restriction(); J diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 4378d955880..5b99c540de2 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -990,7 +990,7 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): sage: R = QQ['x,y'] sage: S = R['t,u'] - sage: f = S.random_element(degree=2, terms=1) + sage: f = S._random_nonzero_element(degree=2, terms=1) sage: len(list(f)) 1 sage: f.degree() <= 2 diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index 615357f9aac..fafe1b30e72 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -1378,9 +1378,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): EXAMPLES:: sage: P. = BooleanPolynomialRing(3) - sage: [P._random_monomial_dfirst(3, (0,1,2)) for _ in range(10)] # py2 - [x*y*z, x*y*z, x*y*z, y*z, x*z, z, z, y*z, x*y*z, 1] - sage: [P._random_monomial_dfirst(3, (0,1,2)) for _ in range(10)] # py3 random + sage: [P._random_monomial_dfirst(3, (0,1,2)) for _ in range(10)] # random [x*y*z, x*y*z, x*y*z, x*y, x*z, x, x, y*z, x*y*z, 1] """ from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 05401515069..2dfcaf2c735 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -104,7 +104,6 @@ from sage.rings.integer_ring import ZZ, is_IntegerRing from sage.rings.integer cimport Integer, smallInteger from sage.libs.gmp.mpz cimport * from sage.rings.fraction_field import is_FractionField -from sage.rings.padics.generic_nodes import is_pAdicRing, is_pAdicField from sage.rings.padics.padic_generic import pAdicGeneric from sage.structure.category_object cimport normalize_names @@ -7997,7 +7996,7 @@ cdef class Polynomial(CommutativeAlgebraElement): real_field = RealField(L.prec()) return self.change_ring(real_field).roots(ring=L, multiplicities=multiplicities, algorithm=algorithm) - elif (is_pAdicRing(L) or is_pAdicField(L)) and L.absolute_degree() == 1: + elif isinstance(L, (sage.rings.abc.pAdicRing, sage.rings.abc.pAdicField)) and L.absolute_degree() == 1: p = L.prime() n = L.precision_cap() try: diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 02b56f18f41..e6c8d400c2e 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1997,7 +1997,7 @@ def __init__(self, base_ring, name="x", sparse=False, element_class=None, catego element_class = Polynomial_relative_number_field_dense elif isinstance(base_ring, sage.rings.abc.RealField): element_class = PolynomialRealDense - elif isinstance(base_ring, sage.rings.complex_arb.ComplexBallField): + elif isinstance(base_ring, sage.rings.abc.ComplexBallField): from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb element_class = Polynomial_complex_arb else: diff --git a/src/sage/rings/polynomial/real_roots.pyx b/src/sage/rings/polynomial/real_roots.pyx index ba57c1ba4f6..ccebbfba87f 100644 --- a/src/sage/rings/polynomial/real_roots.pyx +++ b/src/sage/rings/polynomial/real_roots.pyx @@ -134,7 +134,10 @@ from https://wiki.sagemath.org/days4schedule . from copy import copy import time -from sage.rings.all import ZZ, QQ, RR, AA, RealField, RealIntervalField, RIF, RDF, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity +from sage.rings.all import RR, AA, RealField, RealIntervalField, RIF, RDF from sage.arith.all import binomial, factorial from sage.misc.randstate import randstate from sage.modules.all import vector, FreeModule diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index faaaac899a4..25f814a9dbd 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -8574,3 +8574,9 @@ def get_AA_golden_ratio(): AA_golden_ratio_generator = AlgebraicGenerator(AA_golden_ratio_nf, ANRoot(AAPoly.gen()**2 - AAPoly.gen() - 1, RIF(1.618, 1.6181))) AA_golden_ratio = AlgebraicReal(ANExtensionElement(AA_golden_ratio_generator, AA_golden_ratio_nf.gen())) return AA_golden_ratio + + +# Support Python's numbers abstract base class +import numbers +numbers.Real.register(AlgebraicReal) +numbers.Complex.register(AlgebraicNumber) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index d4a6b69e361..e2c09e6d6ce 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -110,6 +110,10 @@ except ImportError: pari_gen = () +set_rational_from_gen = None +new_gen_from_rational = None + + cdef sage.rings.fast_arith.arith_int ai ai = sage.rings.fast_arith.arith_int() @@ -650,7 +654,9 @@ cdef class Rational(sage.structure.element.FieldElement): mpq_canonicalize(self.value) elif isinstance(x, pari_gen): - from sage.libs.pari.convert_sage import set_rational_from_gen + global set_rational_from_gen + if set_rational_from_gen is None: + from sage.libs.pari.convert_sage import set_rational_from_gen set_rational_from_gen(self, x) elif isinstance(x, list) and len(x) == 1: @@ -3777,7 +3783,9 @@ cdef class Rational(sage.structure.element.FieldElement): sage: m.type() 't_FRAC' """ - from sage.libs.pari.convert_sage import new_gen_from_rational + global new_gen_from_rational + if new_gen_from_rational is None: + from sage.libs.pari.convert_sage import new_gen_from_rational return new_gen_from_rational(self) def _interface_init_(self, I=None): @@ -4297,3 +4305,8 @@ cdef class long_to_Q(Morphism): 'Native' """ return "Native" + + +# Support Python's numbers abstract base class +import numbers +numbers.Rational.register(Rational) diff --git a/src/sage/rings/real_double.pxd b/src/sage/rings/real_double.pxd index 27889ea7f83..06d4121ef26 100644 --- a/src/sage/rings/real_double.pxd +++ b/src/sage/rings/real_double.pxd @@ -11,8 +11,5 @@ cdef class RealDoubleElement(FieldElement): cpdef _add_(self, other) cpdef _mul_(self, other) cpdef RealDoubleElement abs(RealDoubleElement self) - cdef __pow_double(self, double exponent, double sign) - cpdef _pow_(self, other) - cdef _log_base(self, double log_of_base) cdef double_repr(double x) diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 405153db6b9..89f50519173 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -50,14 +50,8 @@ from cysignals.signals cimport sig_on, sig_off from sage.ext.stdsage cimport PY_NEW from sage.cpython.python_debug cimport if_Py_TRACE_REFS_then_PyObject_INIT -from sage.libs.gsl.all cimport * - -gsl_set_error_handler_off() - import math, operator -from cypari2.convert cimport new_gen_from_double - import sage.rings.integer import sage.rings.rational @@ -73,6 +67,9 @@ from sage.arith.constants cimport * cimport gmpy2 +new_gen_from_real_double_element = None + + def is_RealDoubleField(x): """ Returns ``True`` if ``x`` is the field of real double precision numbers. @@ -360,8 +357,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): if S is ZZ or S is QQ or S is RLF: return ToRDF(S) - from .real_mpfr import RR, RealField_class - if isinstance(S, RealField_class): + if isinstance(S, sage.rings.abc.RealField): if S.prec() >= 53: return ToRDF(S) else: @@ -373,6 +369,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): else: return None + from .real_mpfr import RR connecting = RR._internal_coerce_map_from(S) if connecting is not None: return ToRDF(RR) * connecting @@ -588,9 +585,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): sage: RDF.factorial(100) 9.332621544394415e+157 """ - if n < 0: - raise ArithmeticError("n must be nonnegative") - return self(gsl_sf_fact(n)) + return global_dummy_element._factorial(n) def zeta(self, n=2): """ @@ -777,7 +772,6 @@ cdef class RealDoubleElement(FieldElement): sage: RDF(0).prec() 53 """ - return 53 def ulp(self): @@ -868,9 +862,9 @@ cdef class RealDoubleElement(FieldElement): # First, check special values if self._value == 0: return RealDoubleElement(libc.math.ldexp(1.0, -1074)) - if gsl_isnan(self._value): + if libc.math.isnan(self._value): return self - if gsl_isinf(self._value): + if libc.math.isinf(self._value): return self.abs() # Normal case @@ -1032,15 +1026,15 @@ cdef class RealDoubleElement(FieldElement): sage: RDF(22/7)._sage_input_(sib, False) {call: {atomic:RDF}({atomic:3.1428571428571428})} """ - cdef int isinf = gsl_isinf(self._value) - cdef bint isnan = gsl_isnan(self._value) + cdef bint isinf = libc.math.isinf(self._value) + cdef bint isnan = libc.math.isnan(self._value) if isinf or isnan: if isnan: v = sib.name('NaN') else: v = sib.name('infinity') v = sib(self.parent())(v) - if isinf < 0: + if self._value < 0: v = -v return v @@ -1240,7 +1234,7 @@ cdef class RealDoubleElement(FieldElement): ... TypeError: Attempt to get integer part of NaN """ - if gsl_isnan(self._value): + if libc.math.isnan(self._value): raise TypeError("Attempt to get integer part of NaN") else: return Integer(int(self._value)) @@ -1679,7 +1673,10 @@ cdef class RealDoubleElement(FieldElement): sage: RDF(1.5).__pari__() 1.50000000000000 """ - return new_gen_from_double(self._value) + global new_gen_from_real_double_element + if new_gen_from_real_double_element is None: + from sage.libs.pari.convert_sage_real_double import new_gen_from_real_double_element + return new_gen_from_real_double_element(self) ########################################### @@ -1698,7 +1695,7 @@ cdef class RealDoubleElement(FieldElement): sage: a.is_NaN() True """ - return gsl_isnan(self._value) + return bool(libc.math.isnan(self._value)) def is_positive_infinity(self): r""" @@ -1713,7 +1710,9 @@ cdef class RealDoubleElement(FieldElement): sage: a.is_positive_infinity() False """ - return gsl_isinf(self._value) > 0 + if not libc.math.isinf(self._value): + return False + return self._value > 0 def is_negative_infinity(self): r""" @@ -1728,7 +1727,9 @@ cdef class RealDoubleElement(FieldElement): sage: a.is_negative_infinity() True """ - return gsl_isinf(self._value) < 0 + if not libc.math.isinf(self._value): + return False + return self._value < 0 def is_infinity(self): r""" @@ -1742,7 +1743,7 @@ cdef class RealDoubleElement(FieldElement): sage: (b/a).is_infinity() False """ - return gsl_isinf(self._value) + return bool(libc.math.isinf(self._value)) cpdef _richcmp_(left, right, int op): """ @@ -1890,7 +1891,6 @@ cdef class RealDoubleElement(FieldElement): """ return self._value in ZZ - def cube_root(self): """ Return the cubic root (defined over the real numbers) of ``self``. @@ -1905,710 +1905,6 @@ cdef class RealDoubleElement(FieldElement): """ return self.nth_root(3) - - def nth_root(self, int n): - """ - Return the `n^{th}` root of ``self``. - - INPUT: - - - ``n`` -- an integer - - OUTPUT: - - The output is a complex double if ``self`` is negative and `n` is even, - otherwise it is a real double. - - EXAMPLES:: - - sage: r = RDF(-125.0); r.nth_root(3) - -5.000000000000001 - sage: r.nth_root(5) - -2.6265278044037674 - sage: RDF(-2).nth_root(5)^5 # rel tol 1e-15 - -2.000000000000001 - sage: RDF(-1).nth_root(5)^5 - -1.0 - sage: RDF(3).nth_root(10)^10 - 2.9999999999999982 - sage: RDF(-1).nth_root(2) - 6.123233995736757e-17 + 1.0*I - sage: RDF(-1).nth_root(4) - 0.7071067811865476 + 0.7071067811865475*I - """ - if n == 0: - return RealDoubleElement(float('nan')) - if self._value < 0: - if GSL_IS_EVEN(n): - return self._complex_double_(sage.rings.complex_double.CDF).nth_root(n) - else: - return - ( (-self) ** (float(1)/n) ) - else: - return self ** (float(1)/n) - - cdef __pow_double(self, double exponent, double sign): - """ - If ``sign == 1`` or ``self >= 0``, return ``self ^ exponent``. - If ``sign == -1`` and ``self < 0``, return ``- abs(self) ^ exponent``. - """ - cdef double v = self._value - if v >= 0: - if v == 1: - return self - elif exponent == 0: - return self._new_c(1.0) - elif v == 0: - if exponent < 0: - raise ZeroDivisionError("0.0 cannot be raised to a negative power") - return self - sign = 1.0 - else: # v < 0 - expmod2 = libc.math.fmod(exponent, 2.0) - if expmod2 == 0.0: - pass - elif expmod2 == 1.0: - sign = -1.0 - else: - raise ValueError("negative number cannot be raised to a fractional power") - v = -v - return self._new_c(sign * gsl_sf_exp(gsl_sf_log(v) * exponent)) - - cpdef _pow_(self, other): - """ - Return ``self`` raised to the real double power ``other``. - - EXAMPLES:: - - sage: a = RDF('1.23456') - sage: a^a - 1.2971114817819216 - - TESTS:: - - sage: RDF(0) ^ RDF(0.5) - 0.0 - sage: RDF(0) ^ (1/2) - 0.0 - sage: RDF(0) ^ RDF(0) - 1.0 - sage: RDF(0) ^ RDF(-1) - Traceback (most recent call last): - ... - ZeroDivisionError: 0.0 cannot be raised to a negative power - sage: RDF(-1) ^ RDF(0) - 1.0 - sage: RDF(-1) ^ RDF(1) - -1.0 - sage: RDF(-1) ^ RDF(0.5) - Traceback (most recent call last): - ... - ValueError: negative number cannot be raised to a fractional power - """ - return self.__pow_double((other)._value, 1) - - cpdef _pow_int(self, n): - """ - Return ``self`` raised to the integer power ``n``. - - TESTS:: - - sage: RDF(1) ^ (2^1000) - 1.0 - sage: RDF(1) ^ (2^1000 + 1) - 1.0 - sage: RDF(1) ^ (-2^1000) - 1.0 - sage: RDF(1) ^ (-2^1000 + 1) - 1.0 - sage: RDF(-1) ^ (2^1000) - 1.0 - sage: RDF(-1) ^ (2^1000 + 1) - -1.0 - sage: RDF(-1) ^ (-2^1000) - 1.0 - sage: RDF(-1) ^ (-2^1000 + 1) - -1.0 - - :: - - sage: base = RDF(1.0000000000000002) - sage: base._pow_int(0) - 1.0 - sage: base._pow_int(1) - 1.0000000000000002 - sage: base._pow_int(2) - 1.0000000000000004 - sage: base._pow_int(3) - 1.0000000000000007 - sage: base._pow_int(2^57) - 78962960182680.42 - sage: base._pow_int(2^57 + 1) - 78962960182680.42 - - :: - - sage: base = RDF(-1.0000000000000002) - sage: base._pow_int(0) - 1.0 - sage: base._pow_int(1) - -1.0000000000000002 - sage: base._pow_int(2) - 1.0000000000000004 - sage: base._pow_int(3) - -1.0000000000000007 - sage: base._pow_int(2^57) - 78962960182680.42 - sage: base._pow_int(2^57 + 1) - -78962960182680.42 - """ - return self.__pow_double(n, -1.0 if (n & 1) else 1.0) - - cdef _pow_long(self, long n): - """ - Compute ``self`` raised to the power ``n``. - - EXAMPLES:: - - sage: RDF('1.23456') ^ 20 - 67.64629770385... - sage: RDF(3) ^ 32 - 1853020188851841.0 - sage: RDF(2)^(-1024) - 5.562684646268003e-309 - - TESTS:: - - sage: base = RDF(1.0000000000000002) - sage: base ^ RDF(2^31) - 1.000000476837272 - sage: base ^ (2^57) - 78962960182680.42 - sage: base ^ RDF(2^57) - 78962960182680.42 - """ - if -2048 <= n <= 2048: - # For small exponents, it is possible that the powering - # is exact either because the base is a power of 2 - # (e.g. 2.0^1000) or because the exact result has few - # significant digits (e.g. 3.0^10). Here, we use the - # square-and-multiply algorithm by GSL. - return self._new_c(gsl_pow_int(self._value, n)) - # If the exponent is sufficiently large in absolute value, the - # result cannot be exact (except if the base is -1.0, 0.0 or - # 1.0 but those cases are handled by __pow_double too). The - # log-and-exp algorithm from __pow_double will be more precise - # than square-and-multiply. - - # We do need to take care of the sign since the conversion - # of n to double might change an odd number to an even number. - return self.__pow_double(n, -1.0 if (n & 1) else 1.0) - - cdef _log_base(self, double log_of_base): - if self._value == 0: - return RDF(-1)/RDF(0) - elif self._value < 0: - return RDF.NaN() - sig_on() - a = self._new_c(gsl_sf_log(self._value) / log_of_base) - sig_off() - return a - - def log(self, base=None): - """ - Return the logarithm. - - INPUT: - - - ``base`` -- integer or ``None`` (default). The base of the - logarithm. If ``None`` is specified, the base is `e` (the so-called - natural logarithm). - - OUTPUT: - - The logarithm of ``self``. If ``self`` is positive, a double - floating point number. Infinity if ``self`` is zero. A - imaginary complex floating point number if ``self`` is - negative. - - EXAMPLES:: - - sage: RDF(2).log() - 0.6931471805599453 - sage: RDF(2).log(2) - 1.0 - sage: RDF(2).log(pi) - 0.6055115613982801 - sage: RDF(2).log(10) - 0.30102999566398114 - sage: RDF(2).log(1.5) - 1.7095112913514547 - sage: RDF(0).log() - -infinity - sage: RDF(-1).log() - 3.141592653589793*I - sage: RDF(-1).log(2) # rel tol 1e-15 - 4.532360141827194*I - - TESTS: - - Make sure that we can take the log of small numbers accurately - and the fix doesn't break preexisting values (:trac:`12557`):: - - sage: R = RealField(128) - sage: def check_error(x): - ....: x = RDF(x) - ....: log_RDF = x.log() - ....: log_RR = R(x).log() - ....: diff = R(log_RDF) - log_RR - ....: if abs(diff) < log_RDF.ulp(): - ....: return True - ....: print("logarithm check failed for %s (diff = %s ulp)"% \ - ....: (x, diff/log_RDF.ulp())) - ....: return False - sage: all( check_error(2^x) for x in range(-100,100) ) - True - sage: all( check_error(x) for x in sxrange(0.01, 2.00, 0.01) ) - True - sage: all( check_error(x) for x in sxrange(0.99, 1.01, 0.001) ) - True - sage: RDF(1.000000001).log() - 1.000000082240371e-09 - sage: RDF(1e-17).log() - -39.14394658089878 - sage: RDF(1e-50).log() - -115.12925464970229 - """ - if self < 0: - from sage.rings.complex_double import CDF - return CDF(self).log(base) - if base is None: - return self._log_base(1) - else: - if isinstance(base, RealDoubleElement): - return self._log_base(base._log_base(1)) - else: - return self._log_base(gsl_sf_log(float(base))) - - def log2(self): - """ - Return log to the base 2 of ``self``. - - EXAMPLES:: - - sage: r = RDF(16.0) - sage: r.log2() - 4.0 - - :: - - sage: r = RDF(31.9); r.log2() - 4.9954845188775066 - """ - if self < 0: - from sage.rings.complex_double import CDF - return CDF(self).log(2) - sig_on() - a = self._new_c(gsl_sf_log(self._value) * M_1_LN2) - sig_off() - return a - - - def log10(self): - """ - Return log to the base 10 of ``self``. - - EXAMPLES:: - - sage: r = RDF('16.0'); r.log10() - 1.2041199826559248 - sage: r.log() / RDF(log(10)) - 1.2041199826559246 - sage: r = RDF('39.9'); r.log10() - 1.6009728956867482 - """ - if self < 0: - from sage.rings.complex_double import CDF - return CDF(self).log(10) - sig_on() - a = self._new_c(gsl_sf_log(self._value) * M_1_LN10) - sig_off() - return a - - def logpi(self): - r""" - Return log to the base `\pi` of ``self``. - - EXAMPLES:: - - sage: r = RDF(16); r.logpi() - 2.4220462455931204 - sage: r.log() / RDF(log(pi)) - 2.4220462455931204 - sage: r = RDF('39.9'); r.logpi() - 3.2203023346075152 - """ - if self < 0: - from sage.rings.complex_double import CDF - return CDF(self).log(M_PI) - sig_on() - a = self._new_c(gsl_sf_log(self._value) * M_1_LNPI) - sig_off() - return a - - def exp(self): - r""" - Return `e^\mathtt{self}`. - - EXAMPLES:: - - sage: r = RDF(0.0) - sage: r.exp() - 1.0 - - :: - - sage: r = RDF('32.3') - sage: a = r.exp(); a - 106588847274864.47 - sage: a.log() - 32.3 - - :: - - sage: r = RDF('-32.3') - sage: r.exp() - 9.381844588498685e-15 - - :: - - sage: RDF(1000).exp() - +infinity - """ - sig_on() - a = self._new_c(gsl_sf_exp(self._value)) - sig_off() - return a - - def exp2(self): - """ - Return `2^\mathtt{self}`. - - EXAMPLES:: - - sage: r = RDF(0.0) - sage: r.exp2() - 1.0 - - :: - - sage: r = RDF(32.0) - sage: r.exp2() - 4294967295.9999967 - - :: - - sage: r = RDF(-32.3) - sage: r.exp2() - 1.8911724825302065e-10 - """ - sig_on() - a = self._new_c(gsl_sf_exp(self._value * M_LN2)) - sig_off() - return a - - def exp10(self): - r""" - Return `10^\mathtt{self}`. - - EXAMPLES:: - - sage: r = RDF(0.0) - sage: r.exp10() - 1.0 - - :: - - sage: r = RDF(32.0) - sage: r.exp10() - 1.0000000000000069e+32 - - :: - - sage: r = RDF(-32.3) - sage: r.exp10() - 5.011872336272702e-33 - """ - sig_on() - a = self._new_c(gsl_sf_exp(self._value * M_LN10)) - sig_off() - return a - - def cos(self): - """ - Return the cosine of ``self``. - - EXAMPLES:: - - sage: t=RDF.pi()/2 - sage: t.cos() - 6.123233995736757e-17 - """ - return self._new_c(gsl_sf_cos(self._value)) - - def sin(self): - """ - Return the sine of ``self``. - - EXAMPLES:: - - sage: RDF(2).sin() - 0.9092974268256817 - """ - return self._new_c(gsl_sf_sin(self._value)) - - def dilog(self): - r""" - Return the dilogarithm of ``self``. - - This is defined by the - series `\sum_n x^n/n^2` for `|x| \le 1`. When the absolute - value of ``self`` is greater than 1, the returned value is the - real part of (the analytic continuation to `\CC` of) the - dilogarithm of ``self``. - - EXAMPLES:: - - sage: RDF(1).dilog() # rel tol 1.0e-13 - 1.6449340668482264 - sage: RDF(2).dilog() # rel tol 1.0e-13 - 2.46740110027234 - """ - return self._new_c(gsl_sf_dilog(self._value)) - - def restrict_angle(self): - r""" - Return a number congruent to ``self`` mod `2\pi` that lies in - the interval `(-\pi, \pi]`. - - Specifically, it is the unique `x \in (-\pi, \pi]` such - that ```self`` `= x + 2\pi n` for some `n \in \ZZ`. - - EXAMPLES:: - - sage: RDF(pi).restrict_angle() - 3.141592653589793 - sage: RDF(pi + 1e-10).restrict_angle() - -3.1415926534897936 - sage: RDF(1+10^10*pi).restrict_angle() - 0.9999977606... - """ - return self._new_c(gsl_sf_angle_restrict_symm(self._value)) - - def tan(self): - """ - Return the tangent of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/3 - sage: q.tan() - 1.7320508075688767 - sage: q = RDF.pi()/6 - sage: q.tan() - 0.5773502691896256 - """ - cdef double denom - cos = gsl_sf_cos(self._value) - a = self._new_c(gsl_sf_sin(self._value) / cos) - return a - - def sincos(self): - """ - Return a pair consisting of the sine and cosine of ``self``. - - EXAMPLES:: - - sage: t = RDF.pi()/6 - sage: t.sincos() - (0.49999999999999994, 0.8660254037844387) - """ - return self.sin(), self.cos() - - def hypot(self, other): - r""" - Computes the value `\sqrt{s^2 + o^2}` where `s` is ``self`` and `o` - is ``other`` in such a way as to avoid overflow. - - EXAMPLES:: - - sage: x = RDF(4e300); y = RDF(3e300) - sage: x.hypot(y) - 5e+300 - sage: sqrt(x^2+y^2) # overflow - +infinity - """ - sig_on() - a = self._new_c(gsl_sf_hypot(self._value, float(other))) - sig_off() - return a - - def arccos(self): - """ - Return the inverse cosine of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/3 - sage: i = q.cos() - sage: i.arccos() == q - True - """ - return self._new_c(libc.math.acos(self._value)) - - def arcsin(self): - """ - Return the inverse sine of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/5 - sage: i = q.sin() - sage: i.arcsin() == q - True - """ - return self._new_c(libc.math.asin(self._value)) - - def arctan(self): - """ - Return the inverse tangent of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/5 - sage: i = q.tan() - sage: i.arctan() == q - True - """ - return self._new_c(libc.math.atan(self._value)) - - - def cosh(self): - """ - Return the hyperbolic cosine of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/12 - sage: q.cosh() - 1.0344656400955106 - """ - return self._new_c(gsl_ldexp( gsl_sf_exp(self._value) + gsl_sf_exp(-self._value), -1)) # (e^x + e^-x)/2 - - def sinh(self): - """ - Return the hyperbolic sine of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/12 - sage: q.sinh() - 0.26480022760227073 - """ - return self._new_c(gsl_ldexp( gsl_sf_expm1(self._value) - gsl_sf_expm1(-self._value), -1)) # (e^x - e^-x)/2 - - def tanh(self): - """ - Return the hyperbolic tangent of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/12 - sage: q.tanh() - 0.25597778924568454 - """ - return self.sinh() / self.cosh() - - def acosh(self): - """ - Return the hyperbolic inverse cosine of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/2 - sage: i = q.cosh(); i - 2.5091784786580567 - sage: abs(i.acosh()-q) < 1e-15 - True - """ - return self._new_c(gsl_acosh(self._value)) - - def arcsinh(self): - """ - Return the hyperbolic inverse sine of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/2 - sage: i = q.sinh(); i - 2.3012989023072947 - sage: abs(i.arcsinh()-q) < 1e-15 - True - """ - return self._new_c(gsl_asinh(self._value)) - - def arctanh(self): - """ - Return the hyperbolic inverse tangent of ``self``. - - EXAMPLES:: - - sage: q = RDF.pi()/2 - sage: i = q.tanh(); i - 0.9171523356672744 - sage: i.arctanh() - q # rel tol 1 - 4.440892098500626e-16 - """ - return self._new_c(gsl_atanh(self._value)) - - def sech(self): - r""" - Return the hyperbolic secant of ``self``. - - EXAMPLES:: - - sage: RDF(pi).sech() - 0.08626673833405443 - sage: CDF(pi).sech() - 0.08626673833405443 - """ - return 1/self.cosh() - - def csch(self): - r""" - Return the hyperbolic cosecant of ``self``. - - EXAMPLES:: - - sage: RDF(pi).csch() - 0.08658953753004694 - sage: CDF(pi).csch() # rel tol 1e-15 - 0.08658953753004696 - """ - return 1/self.sinh() - - def coth(self): - r""" - Return the hyperbolic cotangent of ``self``. - - EXAMPLES:: - - sage: RDF(pi).coth() - 1.003741873197321 - sage: CDF(pi).coth() - 1.0037418731973213 - """ - return self.cosh() / self.sinh() - def agm(self, other): r""" Return the arithmetic-geometric mean of ``self`` and ``other``. The @@ -2643,57 +1939,6 @@ cdef class RealDoubleElement(FieldElement): if abs((b1/a1)-1) < eps: return self._new_c(a1) a, b = a1, b1 - def erf(self): - """ - Return the value of the error function on ``self``. - - EXAMPLES:: - - sage: RDF(6).erf() - 1.0 - """ - return self._new_c(gsl_sf_erf(self._value)) - - def gamma(self): - """ - Return the value of the Euler gamma function on ``self``. - - EXAMPLES:: - - sage: RDF(6).gamma() - 120.0 - sage: RDF(1.5).gamma() # rel tol 1e-15 - 0.8862269254527584 - """ - sig_on() - a = self._new_c(gsl_sf_gamma(self._value)) - sig_off() - return a - - def zeta(self): - r""" - Return the Riemann zeta function evaluated at this real number. - - .. NOTE:: - - PARI is vastly more efficient at computing the Riemann zeta - function. See the example below for how to use it. - - EXAMPLES:: - - sage: RDF(2).zeta() # rel tol 1e-15 - 1.6449340668482269 - sage: RDF.pi()^2/6 - 1.6449340668482264 - sage: RDF(-2).zeta() - 0.0 - sage: RDF(1).zeta() - +infinity - """ - if self._value == 1: - return self._new_c(1)/self._new_c(0) - return self._new_c(gsl_sf_zeta(self._value)) - def algebraic_dependency(self, n): """ Return a polynomial of degree at most `n` which is @@ -2828,7 +2073,13 @@ def is_RealDoubleElement(x): # We use a global element to steal all the references # from. DO NOT INITIALIZE IT AGAIN and DO NOT REFERENCE IT! cdef RealDoubleElement global_dummy_element -global_dummy_element = RealDoubleElement(0) + +try: + from .real_double_element_gsl import RealDoubleElement_gsl +except ImportError: + global_dummy_element = RealDoubleElement(0) +else: + global_dummy_element = RealDoubleElement_gsl(0) # A global pool for performance when elements are rapidly created and destroyed. # It operates on the following principles: @@ -2896,7 +2147,7 @@ cdef PyObject* fast_tp_new(type t, args, kwds): # The global_dummy_element may have a reference count larger than # one, but it is expected that newly created objects have a # reference count of one. This is potentially unneeded if - # everybody plays nice, because the gobal_dummy_element has only + # everybody plays nice, because the global_dummy_element has only # one reference in that case. # Objects from the pool have reference count zero, so this @@ -2927,19 +2178,33 @@ cdef void fast_tp_dealloc(PyObject* o): PyObject_Free(o) -from sage.misc.allocator cimport hook_tp_functions +from sage.misc.allocator cimport hook_tp_functions, hook_tp_functions_type hook_tp_functions(global_dummy_element, (&fast_tp_new), (&fast_tp_dealloc), False) +try: + from .real_double_element_gsl import RealDoubleElement_gsl +except Exception: + pass +else: + # global_dummy_element is of type RealDoubleElement_gsl, + # so hook the base class now. + hook_tp_functions_type(RealDoubleElement, (&fast_tp_new), (&fast_tp_dealloc), False) + # From here on, calling PY_NEW(RealDoubleElement) actually creates an instance of RealDoubleElement_gsl cdef double_repr(double x): """ Convert a double to a string with maximum precision. """ - if gsl_finite(x): + if libc.math.isfinite(x): return repr(x) - cdef int v = gsl_isinf(x) - if v > 0: - return "+infinity" - if v < 0: - return "-infinity" + if libc.math.isinf(x): + if x > 0: + return "+infinity" + if x < 0: + return "-infinity" return "NaN" + + +# Support Python's numbers abstract base class +import numbers +numbers.Real.register(RealDoubleElement) diff --git a/src/sage/rings/real_double_element_gsl.pxd b/src/sage/rings/real_double_element_gsl.pxd new file mode 100644 index 00000000000..4ddc886cdf1 --- /dev/null +++ b/src/sage/rings/real_double_element_gsl.pxd @@ -0,0 +1,7 @@ +from .real_double cimport RealDoubleElement + + +cdef class RealDoubleElement_gsl(RealDoubleElement): + cdef __pow_double(self, double exponent, double sign) + cpdef _pow_(self, other) + cdef _log_base(self, double log_of_base) diff --git a/src/sage/rings/real_double_element_gsl.pyx b/src/sage/rings/real_double_element_gsl.pyx new file mode 100644 index 00000000000..f5d62d89d58 --- /dev/null +++ b/src/sage/rings/real_double_element_gsl.pyx @@ -0,0 +1,788 @@ +r""" +Double Precision Real Numbers, implementation using GSL +""" + +cimport libc.math + +from cysignals.signals cimport sig_on, sig_off + +from sage.arith.constants cimport * + +from sage.libs.gsl.all cimport * + +gsl_set_error_handler_off() + + +cdef class RealDoubleElement_gsl(RealDoubleElement): + + + def nth_root(self, int n): + """ + Return the `n^{th}` root of ``self``. + + INPUT: + + - ``n`` -- an integer + + OUTPUT: + + The output is a complex double if ``self`` is negative and `n` is even, + otherwise it is a real double. + + EXAMPLES:: + + sage: r = RDF(-125.0); r.nth_root(3) + -5.000000000000001 + sage: r.nth_root(5) + -2.6265278044037674 + sage: RDF(-2).nth_root(5)^5 # rel tol 1e-15 + -2.000000000000001 + sage: RDF(-1).nth_root(5)^5 + -1.0 + sage: RDF(3).nth_root(10)^10 + 2.9999999999999982 + sage: RDF(-1).nth_root(2) + 6.123233995736757e-17 + 1.0*I + sage: RDF(-1).nth_root(4) + 0.7071067811865476 + 0.7071067811865475*I + """ + if n == 0: + return RealDoubleElement(float('nan')) + if self._value < 0: + if GSL_IS_EVEN(n): + from sage.rings.complex_double import CDF + return self._complex_double_(CDF).nth_root(n) + else: + return - ( (-self) ** (float(1)/n) ) + else: + return self ** (float(1)/n) + + cdef __pow_double(self, double exponent, double sign): + """ + If ``sign == 1`` or ``self >= 0``, return ``self ^ exponent``. + If ``sign == -1`` and ``self < 0``, return ``- abs(self) ^ exponent``. + """ + cdef double v = self._value + if v >= 0: + if v == 1: + return self + elif exponent == 0: + return self._new_c(1.0) + elif v == 0: + if exponent < 0: + raise ZeroDivisionError("0.0 cannot be raised to a negative power") + return self + sign = 1.0 + else: # v < 0 + expmod2 = libc.math.fmod(exponent, 2.0) + if expmod2 == 0.0: + pass + elif expmod2 == 1.0: + sign = -1.0 + else: + raise ValueError("negative number cannot be raised to a fractional power") + v = -v + return self._new_c(sign * gsl_sf_exp(gsl_sf_log(v) * exponent)) + + cpdef _pow_(self, other): + """ + Return ``self`` raised to the real double power ``other``. + + EXAMPLES:: + + sage: a = RDF('1.23456') + sage: a^a + 1.2971114817819216 + + TESTS:: + + sage: RDF(0) ^ RDF(0.5) + 0.0 + sage: RDF(0) ^ (1/2) + 0.0 + sage: RDF(0) ^ RDF(0) + 1.0 + sage: RDF(0) ^ RDF(-1) + Traceback (most recent call last): + ... + ZeroDivisionError: 0.0 cannot be raised to a negative power + sage: RDF(-1) ^ RDF(0) + 1.0 + sage: RDF(-1) ^ RDF(1) + -1.0 + sage: RDF(-1) ^ RDF(0.5) + Traceback (most recent call last): + ... + ValueError: negative number cannot be raised to a fractional power + """ + return self.__pow_double((other)._value, 1) + + cpdef _pow_int(self, n): + """ + Return ``self`` raised to the integer power ``n``. + + TESTS:: + + sage: RDF(1) ^ (2^1000) + 1.0 + sage: RDF(1) ^ (2^1000 + 1) + 1.0 + sage: RDF(1) ^ (-2^1000) + 1.0 + sage: RDF(1) ^ (-2^1000 + 1) + 1.0 + sage: RDF(-1) ^ (2^1000) + 1.0 + sage: RDF(-1) ^ (2^1000 + 1) + -1.0 + sage: RDF(-1) ^ (-2^1000) + 1.0 + sage: RDF(-1) ^ (-2^1000 + 1) + -1.0 + + :: + + sage: base = RDF(1.0000000000000002) + sage: base._pow_int(0) + 1.0 + sage: base._pow_int(1) + 1.0000000000000002 + sage: base._pow_int(2) + 1.0000000000000004 + sage: base._pow_int(3) + 1.0000000000000007 + sage: base._pow_int(2^57) + 78962960182680.42 + sage: base._pow_int(2^57 + 1) + 78962960182680.42 + + :: + + sage: base = RDF(-1.0000000000000002) + sage: base._pow_int(0) + 1.0 + sage: base._pow_int(1) + -1.0000000000000002 + sage: base._pow_int(2) + 1.0000000000000004 + sage: base._pow_int(3) + -1.0000000000000007 + sage: base._pow_int(2^57) + 78962960182680.42 + sage: base._pow_int(2^57 + 1) + -78962960182680.42 + """ + return self.__pow_double(n, -1.0 if (n & 1) else 1.0) + + cdef _pow_long(self, long n): + """ + Compute ``self`` raised to the power ``n``. + + EXAMPLES:: + + sage: RDF('1.23456') ^ 20 + 67.64629770385... + sage: RDF(3) ^ 32 + 1853020188851841.0 + sage: RDF(2)^(-1024) + 5.562684646268003e-309 + + TESTS:: + + sage: base = RDF(1.0000000000000002) + sage: base ^ RDF(2^31) + 1.000000476837272 + sage: base ^ (2^57) + 78962960182680.42 + sage: base ^ RDF(2^57) + 78962960182680.42 + """ + if -2048 <= n <= 2048: + # For small exponents, it is possible that the powering + # is exact either because the base is a power of 2 + # (e.g. 2.0^1000) or because the exact result has few + # significant digits (e.g. 3.0^10). Here, we use the + # square-and-multiply algorithm by GSL. + return self._new_c(gsl_pow_int(self._value, n)) + # If the exponent is sufficiently large in absolute value, the + # result cannot be exact (except if the base is -1.0, 0.0 or + # 1.0 but those cases are handled by __pow_double too). The + # log-and-exp algorithm from __pow_double will be more precise + # than square-and-multiply. + + # We do need to take care of the sign since the conversion + # of n to double might change an odd number to an even number. + return self.__pow_double(n, -1.0 if (n & 1) else 1.0) + + cdef _log_base(self, double log_of_base): + if self._value == 0: + from .real_double import RDF + return RDF(-1)/RDF(0) + elif self._value < 0: + from .real_double import RDF + return RDF.NaN() + sig_on() + a = self._new_c(gsl_sf_log(self._value) / log_of_base) + sig_off() + return a + + def log(self, base=None): + """ + Return the logarithm. + + INPUT: + + - ``base`` -- integer or ``None`` (default). The base of the + logarithm. If ``None`` is specified, the base is `e` (the so-called + natural logarithm). + + OUTPUT: + + The logarithm of ``self``. If ``self`` is positive, a double + floating point number. Infinity if ``self`` is zero. A + imaginary complex floating point number if ``self`` is + negative. + + EXAMPLES:: + + sage: RDF(2).log() + 0.6931471805599453 + sage: RDF(2).log(2) + 1.0 + sage: RDF(2).log(pi) + 0.6055115613982801 + sage: RDF(2).log(10) + 0.30102999566398114 + sage: RDF(2).log(1.5) + 1.7095112913514547 + sage: RDF(0).log() + -infinity + sage: RDF(-1).log() + 3.141592653589793*I + sage: RDF(-1).log(2) # rel tol 1e-15 + 4.532360141827194*I + + TESTS: + + Make sure that we can take the log of small numbers accurately + and the fix doesn't break preexisting values (:trac:`12557`):: + + sage: R = RealField(128) + sage: def check_error(x): + ....: x = RDF(x) + ....: log_RDF = x.log() + ....: log_RR = R(x).log() + ....: diff = R(log_RDF) - log_RR + ....: if abs(diff) < log_RDF.ulp(): + ....: return True + ....: print("logarithm check failed for %s (diff = %s ulp)"% \ + ....: (x, diff/log_RDF.ulp())) + ....: return False + sage: all( check_error(2^x) for x in range(-100,100) ) + True + sage: all( check_error(x) for x in sxrange(0.01, 2.00, 0.01) ) + True + sage: all( check_error(x) for x in sxrange(0.99, 1.01, 0.001) ) + True + sage: RDF(1.000000001).log() + 1.000000082240371e-09 + sage: RDF(1e-17).log() + -39.14394658089878 + sage: RDF(1e-50).log() + -115.12925464970229 + """ + if self < 0: + from sage.rings.complex_double import CDF + return CDF(self).log(base) + if base is None: + return self._log_base(1) + else: + if isinstance(base, RealDoubleElement): + return self._log_base(base._log_base(1)) + else: + return self._log_base(gsl_sf_log(float(base))) + + def log2(self): + """ + Return log to the base 2 of ``self``. + + EXAMPLES:: + + sage: r = RDF(16.0) + sage: r.log2() + 4.0 + + :: + + sage: r = RDF(31.9); r.log2() + 4.9954845188775066 + """ + if self < 0: + from sage.rings.complex_double import CDF + return CDF(self).log(2) + sig_on() + a = self._new_c(gsl_sf_log(self._value) * M_1_LN2) + sig_off() + return a + + + def log10(self): + """ + Return log to the base 10 of ``self``. + + EXAMPLES:: + + sage: r = RDF('16.0'); r.log10() + 1.2041199826559248 + sage: r.log() / RDF(log(10)) + 1.2041199826559246 + sage: r = RDF('39.9'); r.log10() + 1.6009728956867482 + """ + if self < 0: + from sage.rings.complex_double import CDF + return CDF(self).log(10) + sig_on() + a = self._new_c(gsl_sf_log(self._value) * M_1_LN10) + sig_off() + return a + + def logpi(self): + r""" + Return log to the base `\pi` of ``self``. + + EXAMPLES:: + + sage: r = RDF(16); r.logpi() + 2.4220462455931204 + sage: r.log() / RDF(log(pi)) + 2.4220462455931204 + sage: r = RDF('39.9'); r.logpi() + 3.2203023346075152 + """ + if self < 0: + from sage.rings.complex_double import CDF + return CDF(self).log(M_PI) + sig_on() + a = self._new_c(gsl_sf_log(self._value) * M_1_LNPI) + sig_off() + return a + + def exp(self): + r""" + Return `e^\mathtt{self}`. + + EXAMPLES:: + + sage: r = RDF(0.0) + sage: r.exp() + 1.0 + + :: + + sage: r = RDF('32.3') + sage: a = r.exp(); a + 106588847274864.47 + sage: a.log() + 32.3 + + :: + + sage: r = RDF('-32.3') + sage: r.exp() + 9.381844588498685e-15 + + :: + + sage: RDF(1000).exp() + +infinity + """ + sig_on() + a = self._new_c(gsl_sf_exp(self._value)) + sig_off() + return a + + def exp2(self): + """ + Return `2^\mathtt{self}`. + + EXAMPLES:: + + sage: r = RDF(0.0) + sage: r.exp2() + 1.0 + + :: + + sage: r = RDF(32.0) + sage: r.exp2() + 4294967295.9999967 + + :: + + sage: r = RDF(-32.3) + sage: r.exp2() + 1.8911724825302065e-10 + """ + sig_on() + a = self._new_c(gsl_sf_exp(self._value * M_LN2)) + sig_off() + return a + + def exp10(self): + r""" + Return `10^\mathtt{self}`. + + EXAMPLES:: + + sage: r = RDF(0.0) + sage: r.exp10() + 1.0 + + :: + + sage: r = RDF(32.0) + sage: r.exp10() + 1.0000000000000069e+32 + + :: + + sage: r = RDF(-32.3) + sage: r.exp10() + 5.011872336272702e-33 + """ + sig_on() + a = self._new_c(gsl_sf_exp(self._value * M_LN10)) + sig_off() + return a + + def cos(self): + """ + Return the cosine of ``self``. + + EXAMPLES:: + + sage: t=RDF.pi()/2 + sage: t.cos() + 6.123233995736757e-17 + """ + return self._new_c(gsl_sf_cos(self._value)) + + def sin(self): + """ + Return the sine of ``self``. + + EXAMPLES:: + + sage: RDF(2).sin() + 0.9092974268256817 + """ + return self._new_c(gsl_sf_sin(self._value)) + + def dilog(self): + r""" + Return the dilogarithm of ``self``. + + This is defined by the + series `\sum_n x^n/n^2` for `|x| \le 1`. When the absolute + value of ``self`` is greater than 1, the returned value is the + real part of (the analytic continuation to `\CC` of) the + dilogarithm of ``self``. + + EXAMPLES:: + + sage: RDF(1).dilog() # rel tol 1.0e-13 + 1.6449340668482264 + sage: RDF(2).dilog() # rel tol 1.0e-13 + 2.46740110027234 + """ + return self._new_c(gsl_sf_dilog(self._value)) + + def restrict_angle(self): + r""" + Return a number congruent to ``self`` mod `2\pi` that lies in + the interval `(-\pi, \pi]`. + + Specifically, it is the unique `x \in (-\pi, \pi]` such + that ```self`` `= x + 2\pi n` for some `n \in \ZZ`. + + EXAMPLES:: + + sage: RDF(pi).restrict_angle() + 3.141592653589793 + sage: RDF(pi + 1e-10).restrict_angle() + -3.1415926534897936 + sage: RDF(1+10^10*pi).restrict_angle() + 0.9999977606... + """ + return self._new_c(gsl_sf_angle_restrict_symm(self._value)) + + def tan(self): + """ + Return the tangent of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/3 + sage: q.tan() + 1.7320508075688767 + sage: q = RDF.pi()/6 + sage: q.tan() + 0.5773502691896256 + """ + cdef double denom + cos = gsl_sf_cos(self._value) + a = self._new_c(gsl_sf_sin(self._value) / cos) + return a + + def sincos(self): + """ + Return a pair consisting of the sine and cosine of ``self``. + + EXAMPLES:: + + sage: t = RDF.pi()/6 + sage: t.sincos() + (0.49999999999999994, 0.8660254037844387) + """ + return self.sin(), self.cos() + + def hypot(self, other): + r""" + Computes the value `\sqrt{s^2 + o^2}` where `s` is ``self`` and `o` + is ``other`` in such a way as to avoid overflow. + + EXAMPLES:: + + sage: x = RDF(4e300); y = RDF(3e300) + sage: x.hypot(y) + 5e+300 + sage: sqrt(x^2+y^2) # overflow + +infinity + """ + sig_on() + a = self._new_c(gsl_sf_hypot(self._value, float(other))) + sig_off() + return a + + def arccos(self): + """ + Return the inverse cosine of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/3 + sage: i = q.cos() + sage: i.arccos() == q + True + """ + return self._new_c(libc.math.acos(self._value)) + + def arcsin(self): + """ + Return the inverse sine of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/5 + sage: i = q.sin() + sage: i.arcsin() == q + True + """ + return self._new_c(libc.math.asin(self._value)) + + def arctan(self): + """ + Return the inverse tangent of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/5 + sage: i = q.tan() + sage: i.arctan() == q + True + """ + return self._new_c(libc.math.atan(self._value)) + + + def cosh(self): + """ + Return the hyperbolic cosine of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/12 + sage: q.cosh() + 1.0344656400955106 + """ + return self._new_c(gsl_ldexp( gsl_sf_exp(self._value) + gsl_sf_exp(-self._value), -1)) # (e^x + e^-x)/2 + + def sinh(self): + """ + Return the hyperbolic sine of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/12 + sage: q.sinh() + 0.26480022760227073 + """ + return self._new_c(gsl_ldexp( gsl_sf_expm1(self._value) - gsl_sf_expm1(-self._value), -1)) # (e^x - e^-x)/2 + + def tanh(self): + """ + Return the hyperbolic tangent of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/12 + sage: q.tanh() + 0.25597778924568454 + """ + return self.sinh() / self.cosh() + + def acosh(self): + """ + Return the hyperbolic inverse cosine of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/2 + sage: i = q.cosh(); i + 2.5091784786580567 + sage: abs(i.acosh()-q) < 1e-15 + True + """ + return self._new_c(gsl_acosh(self._value)) + + def arcsinh(self): + """ + Return the hyperbolic inverse sine of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/2 + sage: i = q.sinh(); i + 2.3012989023072947 + sage: abs(i.arcsinh()-q) < 1e-15 + True + """ + return self._new_c(gsl_asinh(self._value)) + + def arctanh(self): + """ + Return the hyperbolic inverse tangent of ``self``. + + EXAMPLES:: + + sage: q = RDF.pi()/2 + sage: i = q.tanh(); i + 0.9171523356672744 + sage: i.arctanh() - q # rel tol 1 + 4.440892098500626e-16 + """ + return self._new_c(gsl_atanh(self._value)) + + def sech(self): + r""" + Return the hyperbolic secant of ``self``. + + EXAMPLES:: + + sage: RDF(pi).sech() + 0.08626673833405443 + sage: CDF(pi).sech() + 0.08626673833405443 + """ + return 1/self.cosh() + + def csch(self): + r""" + Return the hyperbolic cosecant of ``self``. + + EXAMPLES:: + + sage: RDF(pi).csch() + 0.08658953753004694 + sage: CDF(pi).csch() # rel tol 1e-15 + 0.08658953753004696 + """ + return 1/self.sinh() + + def coth(self): + r""" + Return the hyperbolic cotangent of ``self``. + + EXAMPLES:: + + sage: RDF(pi).coth() + 1.003741873197321 + sage: CDF(pi).coth() + 1.0037418731973213 + """ + return self.cosh() / self.sinh() + + def erf(self): + """ + Return the value of the error function on ``self``. + + EXAMPLES:: + + sage: RDF(6).erf() + 1.0 + """ + return self._new_c(gsl_sf_erf(self._value)) + + @classmethod + def _factorial(cls, int n): + """ + Return the factorial of the integer `n` as a real number. + + EXAMPLES:: + + sage: RDF.factorial(100) + 9.332621544394415e+157 + """ + if n < 0: + raise ArithmeticError("n must be nonnegative") + return cls(gsl_sf_fact(n)) + + def gamma(self): + """ + Return the value of the Euler gamma function on ``self``. + + EXAMPLES:: + + sage: RDF(6).gamma() + 120.0 + sage: RDF(1.5).gamma() # rel tol 1e-15 + 0.8862269254527584 + """ + sig_on() + a = self._new_c(gsl_sf_gamma(self._value)) + sig_off() + return a + + def zeta(self): + r""" + Return the Riemann zeta function evaluated at this real number. + + .. NOTE:: + + PARI is vastly more efficient at computing the Riemann zeta + function. See the example below for how to use it. + + EXAMPLES:: + + sage: RDF(2).zeta() # rel tol 1e-15 + 1.6449340668482269 + sage: RDF.pi()^2/6 + 1.6449340668482264 + sage: RDF(-2).zeta() + 0.0 + sage: RDF(1).zeta() + +infinity + """ + if self._value == 1: + return self._new_c(1)/self._new_c(0) + return self._new_c(gsl_sf_zeta(self._value)) diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 774ab916659..a5bfcc070e8 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -6122,3 +6122,8 @@ def create_RealField(*args, **kwds): deprecation(24511, "Please import create_RealField from sage.rings.real_field") from sage.rings.real_field import create_RealField as cr return cr(*args, **kwds) + + +# Support Python's numbers abstract base class +import numbers +numbers.Real.register(RealNumber) diff --git a/src/sage/rings/valuation/augmented_valuation.py b/src/sage/rings/valuation/augmented_valuation.py index d733851bf7b..863a2c080d6 100644 --- a/src/sage/rings/valuation/augmented_valuation.py +++ b/src/sage/rings/valuation/augmented_valuation.py @@ -157,7 +157,8 @@ from .inductive_valuation import FinalInductiveValuation, NonFinalInductiveValuation, FiniteInductiveValuation, InfiniteInductiveValuation, InductiveValuation from sage.misc.cachefunc import cached_method -from sage.rings.all import infinity, QQ +from sage.rings.infinity import infinity +from sage.rings.rational_field import QQ from sage.structure.factory import UniqueFactory diff --git a/src/sage/rings/valuation/developing_valuation.py b/src/sage/rings/valuation/developing_valuation.py index ab06e85791e..3750d777bd1 100644 --- a/src/sage/rings/valuation/developing_valuation.py +++ b/src/sage/rings/valuation/developing_valuation.py @@ -289,7 +289,7 @@ def _call_(self, f): """ f = self.domain().coerce(f) - from sage.rings.all import infinity + from sage.rings.infinity import infinity if f.is_zero(): return infinity diff --git a/src/sage/rings/valuation/gauss_valuation.py b/src/sage/rings/valuation/gauss_valuation.py index 557edc00149..ef59c605002 100644 --- a/src/sage/rings/valuation/gauss_valuation.py +++ b/src/sage/rings/valuation/gauss_valuation.py @@ -265,7 +265,8 @@ def valuations(self, f, coefficients=None, call_error=False): yield self._base_valuation(f[0]) return - from sage.rings.all import infinity, QQ + from sage.rings.infinity import infinity + from sage.rings.rational_field import QQ if f == self.domain().gen(): yield infinity yield QQ(0) @@ -795,7 +796,7 @@ def lower_bound(self, f): 1 """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity coefficients = f.coefficients(sparse=True) coefficients.reverse() ret = infinity @@ -826,7 +827,7 @@ def upper_bound(self, f): f = self.domain().coerce(f) coefficients = f.coefficients(sparse=True) if not coefficients: - from sage.rings.all import infinity + from sage.rings.infinity import infinity return infinity else: return self._base_valuation.upper_bound(coefficients[-1]) diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index f4b9090f1af..31479167c15 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -413,7 +413,8 @@ def _test_EF(self, **options): tester = self._tester(**options) chain = self.augmentation_chain() for w,v in zip(chain, chain[1:]): - from sage.rings.all import infinity, ZZ + from sage.rings.infinity import infinity + from sage.rings.integer_ring import ZZ if w(w.phi()) is infinity: tester.assertEqual(w.E(), v.E()) tester.assertIn(w.E(), ZZ) @@ -803,7 +804,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a if check and not assume_squarefree and not G.is_squarefree(): raise ValueError("G must be squarefree") - from sage.rings.all import infinity + from sage.rings.infinity import infinity assert self(G) is not infinity # this is a valuation and G is non-zero ret = [] @@ -1105,7 +1106,7 @@ def _equivalence_reduction(self, f, coefficients=None, valuations=None, degree_b R = self.equivalence_unit(-valuation) R = next(self.coefficients(R)) fR_valuations = [vv - valuation for vv in valuations] - from sage.rings.all import infinity + from sage.rings.infinity import infinity fR_coefficients = [next(self.coefficients(c * R)) if vv is not infinity and vv == 0 else 0 for c, vv in zip(coefficients, fR_valuations)] @@ -1566,7 +1567,7 @@ def _test_lift_to_key(self, **options): # check that augmentation produces a valuation with roots of F # in the residue ring - from sage.rings.all import infinity + from sage.rings.infinity import infinity w = self.augmentation(f, infinity) F = F.change_ring(w.residue_ring()) roots = F.roots(multiplicities=False) diff --git a/src/sage/rings/valuation/limit_valuation.py b/src/sage/rings/valuation/limit_valuation.py index f3c89f2b704..1b6e85983de 100644 --- a/src/sage/rings/valuation/limit_valuation.py +++ b/src/sage/rings/valuation/limit_valuation.py @@ -346,7 +346,7 @@ def _repr_(self): [ Gauss valuation induced by 2-adic valuation, v(t + 1) = 1/2 , … ] """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity from .augmented_valuation import AugmentedValuation_base if self._initial_approximation(self._G) is not infinity: if isinstance(self._initial_approximation, AugmentedValuation_base): @@ -489,7 +489,7 @@ def _call_(self, f): """ self._improve_approximation_for_call(f) if self._G.divides(f): - from sage.rings.all import infinity + from sage.rings.infinity import infinity return infinity return self._approximation(f) @@ -519,7 +519,7 @@ def _improve_approximation(self): [ Gauss valuation induced by 2-adic valuation, v(t + 1) = 1/2, v(t^2 + 1) = +Infinity ] """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity if self._approximation(self._G) is infinity: # an infinite valuation can not be improved further return @@ -585,7 +585,7 @@ def _improve_approximation_for_call(self, f): for all future computations.) """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity if self._approximation(self._approximation.phi()) is infinity: # an infinite valuation can not be improved further return diff --git a/src/sage/rings/valuation/scaled_valuation.py b/src/sage/rings/valuation/scaled_valuation.py index 70f6717eed1..6e34d3ce95d 100644 --- a/src/sage/rings/valuation/scaled_valuation.py +++ b/src/sage/rings/valuation/scaled_valuation.py @@ -46,7 +46,8 @@ def create_key(self, base, s): True """ - from sage.rings.all import infinity, QQ + from sage.rings.infinity import infinity + from sage.rings.rational_field import QQ if s is infinity or s not in QQ or s <= 0: # for these values we can not return a TrivialValuation() in # create_object() because that would override that instance's diff --git a/src/sage/rings/valuation/trivial_valuation.py b/src/sage/rings/valuation/trivial_valuation.py index 8d1070bf5cf..abf91cdc025 100644 --- a/src/sage/rings/valuation/trivial_valuation.py +++ b/src/sage/rings/valuation/trivial_valuation.py @@ -174,7 +174,7 @@ def _call_(self, x): +Infinity """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity return infinity def _repr_(self): @@ -302,7 +302,7 @@ def _call_(self, x): 0 """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity return infinity if x == 0 else self.codomain().zero() def _repr_(self): diff --git a/src/sage/rings/valuation/valuation.py b/src/sage/rings/valuation/valuation.py index 3c75e0a22cc..947cc804b28 100644 --- a/src/sage/rings/valuation/valuation.py +++ b/src/sage/rings/valuation/valuation.py @@ -108,7 +108,7 @@ def is_equivalent(self, f, g): True """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity if self(f) is infinity: return self(g) is infinity @@ -879,7 +879,7 @@ def mac_lane_approximant(self, G, valuation, approximants = None): # Check that valuation is an approximant for a valuation # on domain that extends its restriction to the base field. - from sage.rings.all import infinity + from sage.rings.infinity import infinity if valuation(G) is not infinity: v = valuation while not v.is_gauss_valuation(): @@ -982,7 +982,7 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No """ if required_precision is None: - from sage.rings.all import infinity + from sage.rings.infinity import infinity required_precision = infinity R = G.parent() diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index 705e3831799..759d9fc2981 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -161,7 +161,9 @@ def _get_action_(self, S, op, self_on_left): """ from operator import mul - from sage.rings.all import QQ, InfinityRing, ZZ + from sage.rings.infinity import InfinityRing + from sage.rings.rational_field import QQ + from sage.rings.integer_ring import ZZ if op == mul and (S is InfinityRing or S is QQ or S is ZZ): return ScaleAction(S, self, not self_on_left, op) return None @@ -364,7 +366,7 @@ def is_trivial(self): False """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity if self(self.domain().one()) is infinity: # the constant infinity return True @@ -689,7 +691,7 @@ def scale(self, scalar): +Infinity """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity if scalar is infinity: from .trivial_valuation import TrivialPseudoValuation return TrivialPseudoValuation(self.domain()) @@ -796,7 +798,7 @@ def _strictly_separating_element(self, other): 2/3 """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity numerator = self._weakly_separating_element(other) n = self(numerator) @@ -1081,7 +1083,7 @@ def _test_is_negative_pseudo_valuation(self, **options): if not self.is_negative_pseudo_valuation(): X = self.domain().some_elements() for x in tester.some_elements(X): - from sage.rings.all import infinity + from sage.rings.infinity import infinity tester.assertNotEqual(self(x), -infinity) def _test_bounds(self, **options): @@ -1193,7 +1195,8 @@ def _test_scale(self, **options): """ tester = self._tester(**options) - from sage.rings.all import infinity, QQ + from sage.rings.rational_field import QQ + from sage.rings.infinity import infinity from .trivial_valuation import TrivialValuation, TrivialPseudoValuation tester.assertEqual(QQ(0)*self, TrivialValuation(self.domain())) @@ -1246,7 +1249,7 @@ def _test_infinite_zero(self, **options): """ tester = self._tester(**options) - from sage.rings.all import infinity + from sage.rings.infinity import infinity tester.assertEqual(self(self.domain().zero()), infinity) def _test_mul(self, **options): @@ -1263,7 +1266,7 @@ def _test_mul(self, **options): S = self.domain().some_elements() from itertools import product for x,y in tester.some_elements(product(S,S)): - from sage.rings.all import infinity + from sage.rings.infinity import infinity if set([self(x), self(y)]) == set([infinity, -infinity]): continue tester.assertEqual(self(x*y),self(x)+self(y)) @@ -1293,7 +1296,7 @@ def _test_no_infinite_units(self, **options): if self.is_negative_pseudo_valuation(): return - from sage.rings.all import infinity + from sage.rings.infinity import infinity tester = self._tester(**options) for x in tester.some_elements(self.domain().some_elements()): if self(x) is infinity: @@ -1309,7 +1312,7 @@ def _test_value_group(self, **options): sage: v._test_value_group() """ - from sage.rings.all import infinity + from sage.rings.infinity import infinity tester = self._tester(**options) # check consistency of trivial valuations first if self.is_trivial(): @@ -1523,7 +1526,7 @@ def _test_no_infinite_nonzero(self, **options): if not self.is_discrete_valuation(): return - from sage.rings.all import infinity + from sage.rings.infinity import infinity tester = self._tester(**options) for x in tester.some_elements(self.domain().some_elements()): if self(x) is infinity: @@ -1630,7 +1633,7 @@ def _test_inverse(self, **options): tester = self._tester(**options) for x in tester.some_elements(self.domain().some_elements()): - from sage.rings.all import infinity + from sage.rings.infinity import infinity for prec in (0, 1, 42, infinity): try: y = self.inverse(x, prec) diff --git a/src/sage/rings/valuation/value_group.py b/src/sage/rings/valuation/value_group.py index bc5d0840df1..cc0edf113bc 100644 --- a/src/sage/rings/valuation/value_group.py +++ b/src/sage/rings/valuation/value_group.py @@ -28,7 +28,9 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import QQ, ZZ, infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity from sage.misc.cachefunc import cached_method diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index e5b318d8d25..9475fde1562 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -1030,10 +1030,9 @@ def out_degree(self, v=None): sage: s.out_degree(2) 3 """ - if not v is None: + if v is not None: return self._out_degrees[v] - else: - return self._out_degrees + return self._out_degrees def _set_in_degrees(self): """ @@ -1070,10 +1069,9 @@ def in_degree(self, v=None): sage: s.in_degree(2) 3 """ - if not v is None: + if v is not None: return self._in_degrees[v] - else: - return self._in_degrees + return self._in_degrees def _set_burning_config(self): r""" diff --git a/src/sage/schemes/berkovich/berkovich_cp_element.py b/src/sage/schemes/berkovich/berkovich_cp_element.py index ef419c0b50a..1f868be527d 100644 --- a/src/sage/schemes/berkovich/berkovich_cp_element.py +++ b/src/sage/schemes/berkovich/berkovich_cp_element.py @@ -35,10 +35,10 @@ from sage.structure.element import Element from sage.structure.element import Expression +import sage.rings.abc from sage.rings.real_mpfr import RR, is_RealNumber from sage.rings.padics.padic_generic_element import pAdicGenericElement from sage.rings.padics.padic_base_generic import pAdicBaseGeneric -from sage.rings.padics.generic_nodes import is_pAdicField from sage.schemes.projective.projective_space import ProjectiveSpace from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_field from sage.rings.rational_field import QQ @@ -187,7 +187,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= except (TypeError, ValueError): raise TypeError('could not convert %s to %s' % (center, self._base_space)) if self._base_type == 'padic field': - if not is_pAdicField(center.scheme().base_ring()): + if not isinstance(center.scheme().base_ring(), sage.rings.abc.pAdicField): if not isinstance(center.scheme().base_ring(), pAdicBaseGeneric): try: center = (self._base_space)(center) @@ -245,7 +245,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= center = (self._base_space)(center) except (TypeError, ValueError): raise TypeError("could not convert %s to %s" % (center, self._base_space)) - elif not is_pAdicField(center.parent()): + elif not isinstance(center.parent(), sage.rings.abc.pAdicField): # center is padic, not but an element of a padic field. we convert to padic field center = (center.parent().fraction_field())(center) if (center.parent()).prime() != self._p: @@ -291,7 +291,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= except (ValueError, TypeError): raise TypeError("could not convert %s to %s" % (center, self._base_space)) if self._base_type == 'padic field': - if not is_pAdicField(center.scheme().base_ring()): + if not isinstance(center.scheme().base_ring(), sage.rings.abc.pAdicField): if not isinstance(center.scheme().base_ring(), pAdicBaseGeneric): try: center = (self._base_space)(center) @@ -327,7 +327,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= center = (self._base_space)(center) except (TypeError, ValueError): raise TypeError("could not convert %s to %s" % (center, self._base_space)) - elif not is_pAdicField(center.parent()): + elif not isinstance(center.parent(), sage.rings.abc.pAdicField): # center is padic, not but an element of a padic field. we convert to padic field center = (center.parent().fraction_field())(center) if (center.parent()).prime() != self._p: diff --git a/src/sage/schemes/berkovich/berkovich_space.py b/src/sage/schemes/berkovich/berkovich_space.py index 51a0df0a14a..35c6dd05688 100644 --- a/src/sage/schemes/berkovich/berkovich_space.py +++ b/src/sage/schemes/berkovich/berkovich_space.py @@ -38,11 +38,11 @@ from sage.schemes.projective.projective_space import is_ProjectiveSpace, ProjectiveSpace from sage.structure.unique_representation import UniqueRepresentation from sage.categories.number_fields import NumberFields +import sage.rings.abc from sage.rings.integer_ring import ZZ from sage.rings.padics.factory import Qp from sage.rings.rational_field import QQ from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal -from sage.rings.padics.generic_nodes import is_pAdicField from sage.categories.topological_spaces import TopologicalSpaces def is_Berkovich(space): @@ -440,7 +440,7 @@ def __init__(self, base, ideal=None): if not ideal.is_prime(): raise ValueError('passed non prime ideal') self._base_type = 'number field' - elif is_pAdicField(base): # change base to Qpbar + elif isinstance(base, sage.rings.abc.pAdicField): # change base to Qpbar prime = base.prime() ideal = None self._base_type = 'padic field' @@ -614,14 +614,14 @@ def __init__(self, base, ideal=None): base = ProjectiveSpace(Qp(base), 1) else: raise ValueError("non-prime passed into Berkovich space") - if base in NumberFields() or is_pAdicField(base): + if base in NumberFields() or isinstance(base, sage.rings.abc.pAdicField): base = ProjectiveSpace(base, 1) if not is_ProjectiveSpace(base): try: base = ProjectiveSpace(base) except: raise ValueError("base of projective Berkovich space must be projective space") - if not (is_pAdicField(base.base_ring())): + if not isinstance(base.base_ring(), sage.rings.abc.pAdicField): if base.base_ring() not in NumberFields(): raise ValueError("base of projective Berkovich space must be " + \ "projective space over Qp or a number field") diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index bd7cfc8239d..c98c4cbb51b 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -476,7 +476,7 @@ def create_object(self, version, key, **kwds): elif is_NumberField(R): from .ell_number_field import EllipticCurve_number_field return EllipticCurve_number_field(R, x) - elif rings.is_pAdicField(R): + elif isinstance(R, sage.rings.abc.pAdicField): from .ell_padic_field import EllipticCurve_padic_field return EllipticCurve_padic_field(R, x) elif is_FiniteField(R) or (isinstance(R, sage.rings.abc.IntegerModRing) and R.characteristic().is_prime()): diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index de9455a782e..f8c0b5880fd 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -30,9 +30,13 @@ import math import bisect -from sage.rings.all import (ZZ, QQ, RR, RDF, RIF, CC, CDF, CIF, infinity) +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity +from sage.rings.all import RR, RDF, RIF, CC, CDF, CIF -from sage.misc.all import cached_method, cartesian_product_iterator +from sage.misc.cachefunc import cached_method +from sage.misc.all import cartesian_product_iterator from sage.arith.all import lcm, factorial from sage.ext.fast_callable import fast_callable from sage.misc.lazy_import import lazy_import diff --git a/src/sage/schemes/hyperelliptic_curves/constructor.py b/src/sage/schemes/hyperelliptic_curves/constructor.py index d634c9a1001..f5478623bdf 100644 --- a/src/sage/schemes/hyperelliptic_curves/constructor.py +++ b/src/sage/schemes/hyperelliptic_curves/constructor.py @@ -24,7 +24,7 @@ from .hyperelliptic_padic_field import HyperellipticCurve_padic_field from .hyperelliptic_g2 import HyperellipticCurve_g2 -from sage.rings.padics.all import is_pAdicField +import sage.rings.abc from sage.rings.rational_field import is_RationalField from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.polynomial.polynomial_element import is_Polynomial @@ -251,6 +251,8 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): genus_classes = { 2 : HyperellipticCurve_g2} + is_pAdicField = lambda x: isinstance(x, sage.rings.abc.pAdicField) + fields = [ ("FiniteField", is_FiniteField, HyperellipticCurve_finite_field), ("RationalField", is_RationalField, HyperellipticCurve_rational_field), diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py index 2267edfdb1f..1e2991ee51b 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py @@ -7,7 +7,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.padics.all import is_pAdicField, is_pAdicRing, pAdicField +import sage.rings.abc + +from sage.rings.padics.all import pAdicField from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field @@ -28,7 +30,7 @@ def my_chage_ring(self, R): return HyperellipticCurve(f.change_ring(R), h, "%s,%s"%(x,y)) import sage.schemes.hyperelliptic_curves.monsky_washnitzer as monsky_washnitzer - if is_pAdicField(p) or is_pAdicRing(p): + if isinstance(p, (sage.rings.abc.pAdicField, sage.rings.abc.pAdicRing)): K = p else: K = pAdicField(p, prec) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 19234c22264..dcabbaf420a 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -75,6 +75,7 @@ from sage.misc.lazy_import import lazy_import lazy_import("sage.calculus.functions", "jacobian") +import sage.rings.abc from sage.rings.integer import Integer from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic from sage.rings.complex_mpfr import ComplexField_class @@ -988,14 +989,13 @@ def normalize_coordinates(self, **kwds): self.scale_by(R(1) / GCD) # scales by 1/gcd of the coefficients. - from sage.rings.padics.generic_nodes import is_pAdicField if R in _NumberFields: O = R.maximal_order() elif is_FiniteField(R): O = R elif isinstance(R, QuotientRing_generic): O = R.ring() - elif is_pAdicField(R): + elif isinstance(R, sage.rings.abc.pAdicField): O = R.integer_ring() else: O = R @@ -1606,9 +1606,8 @@ def rational_preimages(self, Q, k=1): raise TypeError("must be an endomorphism of projective space") if Q not in self.codomain(): raise TypeError("point must be in codomain of self") - if isinstance(BR.base_ring(), (ComplexField_class, RealField_class, - RealIntervalField_class, - ComplexIntervalField_class)): + if isinstance(BR.base_ring(), (sage.rings.abc.ComplexField, sage.rings.abc.RealField, + sage.rings.abc.RealIntervalField, sage.rings.abc.ComplexIntervalField)): raise NotImplementedError("not implemented over precision fields") PS = self.domain().ambient_space() N = PS.dimension_relative() diff --git a/src/sage/sets/integer_range.py b/src/sage/sets/integer_range.py index 62138a9ecfb..fe61d24d623 100644 --- a/src/sage/sets/integer_range.py +++ b/src/sage/sets/integer_range.py @@ -696,7 +696,7 @@ def __init__(self, begin, end, step=Integer(1), middle_point=Integer(1)): self._end = end self._step = step self._middle_point = middle_point - if not middle_point in self: + if middle_point not in self: raise ValueError("middle_point is not in the interval") if (begin != Infinity and begin != -Infinity) and \ @@ -764,8 +764,8 @@ def next(self, elt): ... LookupError: 1 not in Integer progression containing 0 with increment 10 and bounded with -Infinity and +Infinity """ - if not elt in self: - raise LookupError('%r not in %r' % (elt,self)) + if elt not in self: + raise LookupError('%r not in %r' % (elt, self)) n = self._middle_point if (elt <= n and self._step > 0) or (elt >= n and self._step < 0): right = 2*n-elt+self._step diff --git a/src/sage/structure/gens_py.py b/src/sage/structure/gens_py.py index 2ff623adfad..c5a4bca56ec 100644 --- a/src/sage/structure/gens_py.py +++ b/src/sage/structure/gens_py.py @@ -19,7 +19,7 @@ def multiplicative_iterator(M): - from sage.rings.all import infinity + from sage.rings.infinity import infinity G = M.gens() if len(G) == 0: yield M(1) @@ -46,7 +46,7 @@ def multiplicative_iterator(M): def abelian_iterator(M): - from sage.rings.all import infinity + from sage.rings.infinity import infinity G = M.gens() if len(G) == 0: yield M(0) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 506946bf5f4..30590b1ba77 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2812,9 +2812,16 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: [R._is_numerical() for R in [RIF, RBF, CIF, CBF]] [False, False, False, False] """ - from sage.rings.complex_mpfr import ComplexField - from sage.rings.real_mpfr import mpfr_prec_min - return ComplexField(mpfr_prec_min()).has_coerce_map_from(self) + try: + from sage.rings.complex_mpfr import ComplexField + from sage.rings.real_mpfr import mpfr_prec_min + except ImportError: + pass + else: + return ComplexField(mpfr_prec_min()).has_coerce_map_from(self) + + from sage.rings.real_double import CDF + return CDF.has_coerce_map_from(self) @cached_method def _is_real_numerical(self): @@ -2833,8 +2840,15 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: [R._is_real_numerical() for R in [RIF, RBF, CIF, CBF]] [False, False, False, False] """ - from sage.rings.real_mpfr import RealField, mpfr_prec_min - return RealField(mpfr_prec_min()).has_coerce_map_from(self) + try: + from sage.rings.real_mpfr import RealField, mpfr_prec_min + except ImportError: + pass + else: + return RealField(mpfr_prec_min()).has_coerce_map_from(self) + + from sage.rings.real_double import RDF + return RDF.has_coerce_map_from(self) ############################################################################ # Set base class -- diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 026ceba5220..8c29b6c6657 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1698,7 +1698,7 @@ cdef class Expression(Expression_abc): sage: SR(CBF(1))._convert({'parent':RDF}) 1.0 sage: type(_.pyobject()) - + """ cdef GEx res = self._gobj.evalf(0, kwds) return new_Expression_from_GEx(self._parent, res) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 2d3a8e51f28..7c245e0e6c3 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -1311,7 +1311,7 @@ def the_SymbolicRing(): def is_SymbolicExpressionRing(R): """ - Returns True if ``R`` is the symbolic expression ring. + Return True if ``R`` is the symbolic expression ring. This function is deprecated. Instead, either use ``R is SR`` (to test whether ``R`` is the unique symbolic ring ``SR``); or diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py index 2a834741f4e..9dc4f6e430a 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py @@ -288,13 +288,6 @@ [[[], [1, 2, 4], [1, 3], [1, 3, 4], [1, 4], [2], [2, 3], [2, 4], [4]], [[], [1, 2, 4], [1, 3], [2, 4], [3, 4]]] -Sage example in ./combinat.tex, line 1203:: - - sage: len(S) # py2 - Traceback (most recent call last): - ... - OverflowError: Python int too large to convert to C long - Sage example in ./combinat.tex, line 1237:: sage: P5 = Partitions(5); P5 diff --git a/src/sage/version.py b/src/sage/version.py index a0bf87ed037..7785a1ebba4 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.5.beta5' -date = '2021-10-28' -banner = 'SageMath version 9.5.beta5, Release Date: 2021-10-28' +version = '9.5.beta6' +date = '2021-11-12' +banner = 'SageMath version 9.5.beta6, Release Date: 2021-11-12' diff --git a/src/sage_setup/optional_extension.py b/src/sage_setup/optional_extension.py index 06586f1d393..f2528493846 100644 --- a/src/sage_setup/optional_extension.py +++ b/src/sage_setup/optional_extension.py @@ -48,7 +48,7 @@ def is_package_installed_and_updated(pkg): # Might be an installed old-style package condition = is_package_installed(pkg) else: - condition = (pkginfo["installed_version"] == pkginfo["remote_version"]) + condition = (pkginfo.installed_version == pkginfo.remote_version) return condition diff --git a/tox.ini b/tox.ini index 8c5301eb28e..540ddd20be1 100644 --- a/tox.ini +++ b/tox.ini @@ -117,6 +117,7 @@ passenv = local: SKIP_SYSTEM_PKG_INSTALL local: SKIP_BOOTSTRAP local: SKIP_CONFIGURE + local: OPENBLAS_CONFIGURE local-direct: * setenv =